1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 | "use strict";
|
24 |
|
25 | var fs = require('fs'),
|
26 | EventEmitter = require('events').EventEmitter,
|
27 | os = require('os'),
|
28 | util = require('util');
|
29 |
|
30 | var Platform = function () {
|
31 | this._nsReady = false;
|
32 | this._hostsReady = false;
|
33 |
|
34 | Object.defineProperty(this, 'ready', {
|
35 | get: function () {
|
36 | return this._nsReady && this._hostsReady;
|
37 | },
|
38 | });
|
39 |
|
40 | this._watches = {};
|
41 |
|
42 | Object.defineProperty(this, 'watching', {
|
43 | get: function () {
|
44 | return Object.keys(this._watches).length > 0;
|
45 | },
|
46 | set: function (value) {
|
47 | if (value)
|
48 | this._watchFiles();
|
49 | else {
|
50 | for (k in this._watches) {
|
51 | this._watches[k].close();
|
52 | delete this._watches[k];
|
53 | }
|
54 | }
|
55 | },
|
56 | });
|
57 |
|
58 | this._initNameServers();
|
59 | this._initHostsFile();
|
60 | this._populate();
|
61 | };
|
62 | util.inherits(Platform, EventEmitter);
|
63 |
|
64 | Platform.prototype.realod = function () {
|
65 | this.emit('unready');
|
66 | this._initNameServers();
|
67 | this._initHostsFile();
|
68 | this._populate();
|
69 | };
|
70 |
|
71 | Platform.prototype._initNameServers = function () {
|
72 | this._nsReady = false;
|
73 | this.name_servers = [];
|
74 | this.search_path = [];
|
75 | this.timeout = 5 * 1000;
|
76 | this.attempts = 5;
|
77 | this.edns = false;
|
78 | };
|
79 |
|
80 | Platform.prototype._initHostsFile = function () {
|
81 | this._hostsReady = false;
|
82 | this.hosts = {};
|
83 | };
|
84 |
|
85 | Platform.prototype._populate = function () {
|
86 | var hostsfile, self = this;
|
87 |
|
88 | switch (os.platform()) {
|
89 | case 'win32':
|
90 | this.name_servers = [
|
91 | {
|
92 | address: '8.8.8.8',
|
93 | port: 53,
|
94 | },
|
95 | {
|
96 | address: '8.8.4.4.',
|
97 | port: 53,
|
98 | },
|
99 | ];
|
100 | hosts = path.join(process.env.SystemRoot, '\\System32\\drivers\\etc\\hosts');
|
101 | break;
|
102 | default:
|
103 | this.parseResolv();
|
104 | hostsfile = '/etc/hosts';
|
105 | break;
|
106 | }
|
107 |
|
108 | this._parseHosts(hostsfile);
|
109 | };
|
110 |
|
111 | Platform.prototype._watchFiles = function () {
|
112 | var self = this, watchParams;
|
113 |
|
114 | watchParams = {
|
115 | persistent: false,
|
116 | };
|
117 |
|
118 | switch (os.platform()) {
|
119 | case 'win32':
|
120 |
|
121 | break;
|
122 | default:
|
123 | this._watches.resolve = fs.watch('/etc/resolv.conf', watchParams, function (event, filename) {
|
124 | if (event === 'change') {
|
125 | self.emit('unready');
|
126 | self._initNameServers();
|
127 | self.parseResolv();
|
128 | }
|
129 | });
|
130 | this._watches.hosts = fs.watch('/etc/hosts', watchParams, function (event, filename) {
|
131 | if (event === 'change') {
|
132 | self.emit('unready');
|
133 | self._initHostsFile();
|
134 | self._parseHosts(hostsfile);
|
135 | }
|
136 | });
|
137 | break;
|
138 | }
|
139 | };
|
140 |
|
141 | Platform.prototype._checkReady = function () {
|
142 | if (this.ready) {
|
143 | this.emit('ready');
|
144 | }
|
145 | };
|
146 |
|
147 | Platform.prototype.parseResolv = function () {
|
148 | var self = this;
|
149 |
|
150 | fs.readFile('/etc/resolv.conf', 'ascii', function (err, file) {
|
151 | if (err) {
|
152 | throw err;
|
153 | }
|
154 |
|
155 | file.split(/\n/).forEach(function (line) {
|
156 | var i, parts, subparts;
|
157 | line = line.replace(/^\s+|\s+$/g, '');
|
158 | if (!line.match(/^#/)) {
|
159 | parts = line.split(/\s+/);
|
160 | switch (parts[0]) {
|
161 | case 'nameserver':
|
162 | self.name_servers.push({
|
163 | address: parts[1],
|
164 | port: 53,
|
165 | });
|
166 | break;
|
167 | case 'domain':
|
168 | self.search_path = [parts[1]];
|
169 | break;
|
170 | case 'search':
|
171 | self.search_path = [parts.slice(1)];
|
172 | break;
|
173 | case 'options':
|
174 | for (i = 1; i < parts.length; i++) {
|
175 | subparts = parts[i].split(/:/);
|
176 | switch (subparts[0]) {
|
177 | case 'timeout':
|
178 | self.timeout = parseInt(subparts[1], 10) * 1000;
|
179 | break;
|
180 | case 'attempts':
|
181 | self.attempts = parseInt(subparts[1], 10);
|
182 | break;
|
183 | case 'edns0':
|
184 | self.edns = true;
|
185 | break;
|
186 | }
|
187 | }
|
188 | break;
|
189 | }
|
190 | }
|
191 | });
|
192 |
|
193 | self._nsReady = true;
|
194 | self._checkReady();
|
195 | });
|
196 | };
|
197 |
|
198 | Platform.prototype._parseHosts = function (hostsfile) {
|
199 | var self = this;
|
200 |
|
201 | fs.readFile(hostsfile, 'ascii', function (err, file) {
|
202 | if (err) {
|
203 | throw err;
|
204 | }
|
205 |
|
206 | file.split(/\n/).forEach(function (line) {
|
207 | var i, parts, ip;
|
208 | line = line.replace(/^\s+|\s+$/g, '');
|
209 | if (!line.match(/^#/)) {
|
210 | parts = line.split(/\s+/);
|
211 | ip = parts[0];
|
212 | self.hosts[ip] = parts.slice(1);
|
213 | for (i = 1; i < parts.length; i++) {
|
214 | if (!self.hosts[parts[i]]) {
|
215 | self.hosts[parts[i]] = [];
|
216 | }
|
217 | self.hosts[parts[i]].push(ip);
|
218 | }
|
219 | }
|
220 | });
|
221 |
|
222 | self._hostsReady = true;
|
223 | self._checkReady();
|
224 | });
|
225 | };
|
226 |
|
227 | module.exports = new Platform();
|