Projekt

Obecné

Profil

Stáhnout (10 KB) Statistiky
| Větev: | Revize:
1
'use strict';
2

    
3
var ip = exports;
4
var Buffer = require('buffer').Buffer;
5
var os = require('os');
6

    
7
ip.toBuffer = function(ip, buff, offset) {
8
  offset = ~~offset;
9

    
10
  var result;
11

    
12
  if (this.isV4Format(ip)) {
13
    result = buff || new Buffer(offset + 4);
14
    ip.split(/\./g).map(function(byte) {
15
      result[offset++] = parseInt(byte, 10) & 0xff;
16
    });
17
  } else if (this.isV6Format(ip)) {
18
    var sections = ip.split(':', 8);
19

    
20
    var i;
21
    for (i = 0; i < sections.length; i++) {
22
      var isv4 = this.isV4Format(sections[i]);
23
      var v4Buffer;
24

    
25
      if (isv4) {
26
        v4Buffer = this.toBuffer(sections[i]);
27
        sections[i] = v4Buffer.slice(0, 2).toString('hex');
28
      }
29

    
30
      if (v4Buffer && ++i < 8) {
31
        sections.splice(i, 0, v4Buffer.slice(2, 4).toString('hex'));
32
      }
33
    }
34

    
35
    if (sections[0] === '') {
36
      while (sections.length < 8) sections.unshift('0');
37
    } else if (sections[sections.length - 1] === '') {
38
      while (sections.length < 8) sections.push('0');
39
    } else if (sections.length < 8) {
40
      for (i = 0; i < sections.length && sections[i] !== ''; i++);
41
      var argv = [ i, 1 ];
42
      for (i = 9 - sections.length; i > 0; i--) {
43
        argv.push('0');
44
      }
45
      sections.splice.apply(sections, argv);
46
    }
47

    
48
    result = buff || new Buffer(offset + 16);
49
    for (i = 0; i < sections.length; i++) {
50
      var word = parseInt(sections[i], 16);
51
      result[offset++] = (word >> 8) & 0xff;
52
      result[offset++] = word & 0xff;
53
    }
54
  }
55

    
56
  if (!result) {
57
    throw Error('Invalid ip address: ' + ip);
58
  }
59

    
60
  return result;
61
};
62

    
63
ip.toString = function(buff, offset, length) {
64
  offset = ~~offset;
65
  length = length || (buff.length - offset);
66

    
67
  var result = [];
68
  if (length === 4) {
69
    // IPv4
70
    for (var i = 0; i < length; i++) {
71
      result.push(buff[offset + i]);
72
    }
73
    result = result.join('.');
74
  } else if (length === 16) {
75
    // IPv6
76
    for (var i = 0; i < length; i += 2) {
77
      result.push(buff.readUInt16BE(offset + i).toString(16));
78
    }
79
    result = result.join(':');
80
    result = result.replace(/(^|:)0(:0)*:0(:|$)/, '$1::$3');
81
    result = result.replace(/:{3,4}/, '::');
82
  }
83

    
84
  return result;
85
};
86

    
87
var ipv4Regex = /^(\d{1,3}\.){3,3}\d{1,3}$/;
88
var ipv6Regex =
89
    /^(::)?(((\d{1,3}\.){3}(\d{1,3}){1})?([0-9a-f]){0,4}:{0,2}){1,8}(::)?$/i;
90

    
91
ip.isV4Format = function(ip) {
92
  return ipv4Regex.test(ip);
93
};
94

    
95
ip.isV6Format = function(ip) {
96
  return ipv6Regex.test(ip);
97
};
98
function _normalizeFamily(family) {
99
  return family ? family.toLowerCase() : 'ipv4';
100
}
101

    
102
ip.fromPrefixLen = function(prefixlen, family) {
103
  if (prefixlen > 32) {
104
    family = 'ipv6';
105
  } else {
106
    family = _normalizeFamily(family);
107
  }
108

    
109
  var len = 4;
110
  if (family === 'ipv6') {
111
    len = 16;
112
  }
113
  var buff = new Buffer(len);
114

    
115
  for (var i = 0, n = buff.length; i < n; ++i) {
116
    var bits = 8;
117
    if (prefixlen < 8) {
118
      bits = prefixlen;
119
    }
120
    prefixlen -= bits;
121

    
122
    buff[i] = ~(0xff >> bits) & 0xff;
123
  }
124

    
125
  return ip.toString(buff);
126
};
127

    
128
ip.mask = function(addr, mask) {
129
  addr = ip.toBuffer(addr);
130
  mask = ip.toBuffer(mask);
131

    
132
  var result = new Buffer(Math.max(addr.length, mask.length));
133

    
134
  var i = 0;
135
  // Same protocol - do bitwise and
136
  if (addr.length === mask.length) {
137
    for (i = 0; i < addr.length; i++) {
138
      result[i] = addr[i] & mask[i];
139
    }
140
  } else if (mask.length === 4) {
141
    // IPv6 address and IPv4 mask
142
    // (Mask low bits)
143
    for (i = 0; i < mask.length; i++) {
144
      result[i] = addr[addr.length - 4  + i] & mask[i];
145
    }
146
  } else {
147
    // IPv6 mask and IPv4 addr
148
    for (var i = 0; i < result.length - 6; i++) {
149
      result[i] = 0;
150
    }
151

    
152
    // ::ffff:ipv4
153
    result[10] = 0xff;
154
    result[11] = 0xff;
155
    for (i = 0; i < addr.length; i++) {
156
      result[i + 12] = addr[i] & mask[i + 12];
157
    }
158
    i = i + 12;
159
  }
160
  for (; i < result.length; i++)
161
    result[i] = 0;
162

    
163
  return ip.toString(result);
164
};
165

    
166
ip.cidr = function(cidrString) {
167
  var cidrParts = cidrString.split('/');
168

    
169
  var addr = cidrParts[0];
170
  if (cidrParts.length !== 2)
171
    throw new Error('invalid CIDR subnet: ' + addr);
172

    
173
  var mask = ip.fromPrefixLen(parseInt(cidrParts[1], 10));
174

    
175
  return ip.mask(addr, mask);
176
};
177

    
178
ip.subnet = function(addr, mask) {
179
  var networkAddress = ip.toLong(ip.mask(addr, mask));
180

    
181
  // Calculate the mask's length.
182
  var maskBuffer = ip.toBuffer(mask);
183
  var maskLength = 0;
184

    
185
  for (var i = 0; i < maskBuffer.length; i++) {
186
    if (maskBuffer[i] === 0xff) {
187
      maskLength += 8;
188
    } else {
189
      var octet = maskBuffer[i] & 0xff;
190
      while (octet) {
191
        octet = (octet << 1) & 0xff;
192
        maskLength++;
193
      }
194
    }
195
  }
196

    
197
  var numberOfAddresses = Math.pow(2, 32 - maskLength);
198

    
199
  return {
200
    networkAddress: ip.fromLong(networkAddress),
201
    firstAddress: numberOfAddresses <= 2 ?
202
                    ip.fromLong(networkAddress) :
203
                    ip.fromLong(networkAddress + 1),
204
    lastAddress: numberOfAddresses <= 2 ?
205
                    ip.fromLong(networkAddress + numberOfAddresses - 1) :
206
                    ip.fromLong(networkAddress + numberOfAddresses - 2),
207
    broadcastAddress: ip.fromLong(networkAddress + numberOfAddresses - 1),
208
    subnetMask: mask,
209
    subnetMaskLength: maskLength,
210
    numHosts: numberOfAddresses <= 2 ?
211
                numberOfAddresses : numberOfAddresses - 2,
212
    length: numberOfAddresses,
213
    contains: function(other) {
214
      return networkAddress === ip.toLong(ip.mask(other, mask));
215
    }
216
  };
217
};
218

    
219
ip.cidrSubnet = function(cidrString) {
220
  var cidrParts = cidrString.split('/');
221

    
222
  var addr = cidrParts[0];
223
  if (cidrParts.length !== 2)
224
    throw new Error('invalid CIDR subnet: ' + addr);
225

    
226
  var mask = ip.fromPrefixLen(parseInt(cidrParts[1], 10));
227

    
228
  return ip.subnet(addr, mask);
229
};
230

    
231
ip.not = function(addr) {
232
  var buff = ip.toBuffer(addr);
233
  for (var i = 0; i < buff.length; i++) {
234
    buff[i] = 0xff ^ buff[i];
235
  }
236
  return ip.toString(buff);
237
};
238

    
239
ip.or = function(a, b) {
240
  a = ip.toBuffer(a);
241
  b = ip.toBuffer(b);
242

    
243
  // same protocol
244
  if (a.length === b.length) {
245
    for (var i = 0; i < a.length; ++i) {
246
      a[i] |= b[i];
247
    }
248
    return ip.toString(a);
249

    
250
  // mixed protocols
251
  } else {
252
    var buff = a;
253
    var other = b;
254
    if (b.length > a.length) {
255
      buff = b;
256
      other = a;
257
    }
258

    
259
    var offset = buff.length - other.length;
260
    for (var i = offset; i < buff.length; ++i) {
261
      buff[i] |= other[i - offset];
262
    }
263

    
264
    return ip.toString(buff);
265
  }
266
};
267

    
268
ip.isEqual = function(a, b) {
269
  a = ip.toBuffer(a);
270
  b = ip.toBuffer(b);
271

    
272
  // Same protocol
273
  if (a.length === b.length) {
274
    for (var i = 0; i < a.length; i++) {
275
      if (a[i] !== b[i]) return false;
276
    }
277
    return true;
278
  }
279

    
280
  // Swap
281
  if (b.length === 4) {
282
    var t = b;
283
    b = a;
284
    a = t;
285
  }
286

    
287
  // a - IPv4, b - IPv6
288
  for (var i = 0; i < 10; i++) {
289
    if (b[i] !== 0) return false;
290
  }
291

    
292
  var word = b.readUInt16BE(10);
293
  if (word !== 0 && word !== 0xffff) return false;
294

    
295
  for (var i = 0; i < 4; i++) {
296
    if (a[i] !== b[i + 12]) return false;
297
  }
298

    
299
  return true;
300
};
301

    
302
ip.isPrivate = function(addr) {
303
  return /^(::f{4}:)?10\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i
304
      .test(addr) ||
305
    /^(::f{4}:)?192\.168\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) ||
306
    /^(::f{4}:)?172\.(1[6-9]|2\d|30|31)\.([0-9]{1,3})\.([0-9]{1,3})$/i
307
      .test(addr) ||
308
    /^(::f{4}:)?127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) ||
309
    /^(::f{4}:)?169\.254\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) ||
310
    /^f[cd][0-9a-f]{2}:/i.test(addr) ||
311
    /^fe80:/i.test(addr) ||
312
    /^::1$/.test(addr) ||
313
    /^::$/.test(addr);
314
};
315

    
316
ip.isPublic = function(addr) {
317
  return !ip.isPrivate(addr);
318
};
319

    
320
ip.isLoopback = function(addr) {
321
  return /^(::f{4}:)?127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/
322
      .test(addr) ||
323
    /^fe80::1$/.test(addr) ||
324
    /^::1$/.test(addr) ||
325
    /^::$/.test(addr);
326
};
327

    
328
ip.loopback = function(family) {
329
  //
330
  // Default to `ipv4`
331
  //
332
  family = _normalizeFamily(family);
333

    
334
  if (family !== 'ipv4' && family !== 'ipv6') {
335
    throw new Error('family must be ipv4 or ipv6');
336
  }
337

    
338
  return family === 'ipv4' ? '127.0.0.1' : 'fe80::1';
339
};
340

    
341
//
342
// ### function address (name, family)
343
// #### @name {string|'public'|'private'} **Optional** Name or security
344
//      of the network interface.
345
// #### @family {ipv4|ipv6} **Optional** IP family of the address (defaults
346
//      to ipv4).
347
//
348
// Returns the address for the network interface on the current system with
349
// the specified `name`:
350
//   * String: First `family` address of the interface.
351
//             If not found see `undefined`.
352
//   * 'public': the first public ip address of family.
353
//   * 'private': the first private ip address of family.
354
//   * undefined: First address with `ipv4` or loopback address `127.0.0.1`.
355
//
356
ip.address = function(name, family) {
357
  var interfaces = os.networkInterfaces();
358
  var all;
359

    
360
  //
361
  // Default to `ipv4`
362
  //
363
  family = _normalizeFamily(family);
364

    
365
  //
366
  // If a specific network interface has been named,
367
  // return the address.
368
  //
369
  if (name && name !== 'private' && name !== 'public') {
370
    var res = interfaces[name].filter(function(details) {
371
      var itemFamily = details.family.toLowerCase();
372
      return itemFamily === family;
373
    });
374
    if (res.length === 0)
375
      return undefined;
376
    return res[0].address;
377
  }
378

    
379
  var all = Object.keys(interfaces).map(function (nic) {
380
    //
381
    // Note: name will only be `public` or `private`
382
    // when this is called.
383
    //
384
    var addresses = interfaces[nic].filter(function (details) {
385
      details.family = details.family.toLowerCase();
386
      if (details.family !== family || ip.isLoopback(details.address)) {
387
        return false;
388
      } else if (!name) {
389
        return true;
390
      }
391

    
392
      return name === 'public' ? ip.isPrivate(details.address) :
393
          ip.isPublic(details.address);
394
    });
395

    
396
    return addresses.length ? addresses[0].address : undefined;
397
  }).filter(Boolean);
398

    
399
  return !all.length ? ip.loopback(family) : all[0];
400
};
401

    
402
ip.toLong = function(ip) {
403
  var ipl = 0;
404
  ip.split('.').forEach(function(octet) {
405
    ipl <<= 8;
406
    ipl += parseInt(octet);
407
  });
408
  return(ipl >>> 0);
409
};
410

    
411
ip.fromLong = function(ipl) {
412
  return ((ipl >>> 24) + '.' +
413
      (ipl >> 16 & 255) + '.' +
414
      (ipl >> 8 & 255) + '.' +
415
      (ipl & 255) );
416
};
    (1-1/1)