ip/netaddress: better ip parsing.
This commit is contained in:
parent
2d49e38580
commit
016d0da096
@ -110,7 +110,7 @@ WSProxy.prototype._handleResolve = function _handleResolve(ws, name, record, cal
|
|||||||
WSProxy.prototype._handleConnect = function _handleConnect(ws, port, host, nonce) {
|
WSProxy.prototype._handleConnect = function _handleConnect(ws, port, host, nonce) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var state = this.sockets.get(ws);
|
var state = this.sockets.get(ws);
|
||||||
var socket, pow;
|
var socket, pow, raw;
|
||||||
|
|
||||||
if (state.socket) {
|
if (state.socket) {
|
||||||
this.log('Client is trying to reconnect (%s).', state.host);
|
this.log('Client is trying to reconnect (%s).', state.host);
|
||||||
@ -149,7 +149,9 @@ WSProxy.prototype._handleConnect = function _handleConnect(ws, port, host, nonce
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IP.version(host) === -1) {
|
try {
|
||||||
|
raw = IP.toBuffer(host);
|
||||||
|
} catch (e) {
|
||||||
this.log('Client gave a bad host: %s (%s).', host, state.host);
|
this.log('Client gave a bad host: %s (%s).', host, state.host);
|
||||||
ws.emit('tcp error', {
|
ws.emit('tcp error', {
|
||||||
message: 'EHOSTUNREACH',
|
message: 'EHOSTUNREACH',
|
||||||
@ -159,8 +161,10 @@ WSProxy.prototype._handleConnect = function _handleConnect(ws, port, host, nonce
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IP.isPrivate(host)) {
|
if (!IP.isRoutable(raw)) {
|
||||||
this.log('Client is trying to connect to a private ip (%s).', state.host);
|
this.log(
|
||||||
|
'Client is trying to connect to a bad ip: %s (%s).',
|
||||||
|
host, state.host);
|
||||||
ws.emit('tcp error', {
|
ws.emit('tcp error', {
|
||||||
message: 'ENETUNREACH',
|
message: 'ENETUNREACH',
|
||||||
code: 'ENETUNREACH'
|
code: 'ENETUNREACH'
|
||||||
|
|||||||
@ -1759,7 +1759,7 @@ HTTPOptions.prototype.fromOptions = function fromOptions(options) {
|
|||||||
|
|
||||||
if (options.host != null) {
|
if (options.host != null) {
|
||||||
assert(typeof options.host === 'string');
|
assert(typeof options.host === 'string');
|
||||||
this.host = options.host;
|
this.host = IP.normalize(options.host);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.port != null) {
|
if (options.port != null) {
|
||||||
@ -1786,7 +1786,7 @@ HTTPOptions.prototype.fromOptions = function fromOptions(options) {
|
|||||||
// Allow no-auth implicitly
|
// Allow no-auth implicitly
|
||||||
// if we're listening locally.
|
// if we're listening locally.
|
||||||
if (!options.apiKey && !options.serviceKey && options.noAuth == null) {
|
if (!options.apiKey && !options.serviceKey && options.noAuth == null) {
|
||||||
if (IP.isLoopback(this.host))
|
if (this.host === '127.0.0.1' || this.host === '::1')
|
||||||
this.noAuth = true;
|
this.noAuth = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3153,10 +3153,13 @@ Pool.prototype.getIP = co(function* getIP() {
|
|||||||
|
|
||||||
ip = res.body.trim();
|
ip = res.body.trim();
|
||||||
|
|
||||||
if (IP.version(ip) === -1)
|
try {
|
||||||
|
ip = IP.normalize(ip);
|
||||||
|
} catch (e) {
|
||||||
return yield this.getIP2();
|
return yield this.getIP2();
|
||||||
|
}
|
||||||
|
|
||||||
return IP.normalize(ip);
|
return ip;
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -3184,9 +3187,6 @@ Pool.prototype.getIP2 = co(function* getIP2() {
|
|||||||
|
|
||||||
ip = match[1];
|
ip = match[1];
|
||||||
|
|
||||||
if (IP.version(ip) === -1)
|
|
||||||
throw new Error('Could not parse IP.');
|
|
||||||
|
|
||||||
return IP.normalize(ip);
|
return IP.normalize(ip);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -3311,10 +3311,10 @@ PoolOptions.prototype.fromOptions = function fromOptions(options) {
|
|||||||
|
|
||||||
if (options.host != null) {
|
if (options.host != null) {
|
||||||
assert(typeof options.host === 'string');
|
assert(typeof options.host === 'string');
|
||||||
assert(IP.version(options.host) !== -1, '`host` must be an IP.');
|
this.host = options.host;
|
||||||
this.host = IP.normalize(options.host);
|
this.address.setHost(this.host);
|
||||||
if (IP.isRoutable(this.host))
|
if (!this.address.isRoutable())
|
||||||
this.address.setHost(this.host);
|
this.address.setNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.port != null) {
|
if (options.port != null) {
|
||||||
|
|||||||
@ -38,6 +38,7 @@ function NetAddress(options) {
|
|||||||
this.services = 0;
|
this.services = 0;
|
||||||
this.ts = 0;
|
this.ts = 0;
|
||||||
this.hostname = '0.0.0.0:0';
|
this.hostname = '0.0.0.0:0';
|
||||||
|
this.raw = IP.ZERO_IP;
|
||||||
|
|
||||||
if (options)
|
if (options)
|
||||||
this.fromOptions(options);
|
this.fromOptions(options);
|
||||||
@ -65,9 +66,8 @@ NetAddress.prototype.fromOptions = function fromOptions(options) {
|
|||||||
assert(typeof options.host === 'string');
|
assert(typeof options.host === 'string');
|
||||||
assert(typeof options.port === 'number');
|
assert(typeof options.port === 'number');
|
||||||
|
|
||||||
assert(IP.version(options.host) !== -1);
|
this.raw = IP.toBuffer(options.host);
|
||||||
|
this.host = IP.toString(this.raw);
|
||||||
this.host = IP.normalize(options.host);
|
|
||||||
this.port = options.port;
|
this.port = options.port;
|
||||||
|
|
||||||
if (options.services) {
|
if (options.services) {
|
||||||
@ -105,22 +105,31 @@ NetAddress.prototype.hasServices = function hasServices(services) {
|
|||||||
return (this.services & services) === services;
|
return (this.services & services) === services;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether the address is IPv4.
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
NetAddress.isIPv4 = function isIPv4() {
|
||||||
|
return IP.isIPv4(this.raw);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether the address is IPv6.
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
NetAddress.isIPv6 = function isIPv6() {
|
||||||
|
return !IP.isIPv6(this.raw);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test whether the host is null.
|
* Test whether the host is null.
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
NetAddress.prototype.isNull = function isNull() {
|
NetAddress.prototype.isNull = function isNull() {
|
||||||
return IP.isNull(this.host);
|
return IP.isNull(this.raw);
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test whether the host is a broadcast address.
|
|
||||||
* @returns {Boolean}
|
|
||||||
*/
|
|
||||||
|
|
||||||
NetAddress.prototype.isBroadcast = function isBroadcast() {
|
|
||||||
return IP.isBroadcast(this.host);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -128,17 +137,8 @@ NetAddress.prototype.isBroadcast = function isBroadcast() {
|
|||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
NetAddress.prototype.isLoopback = function isLoopback() {
|
NetAddress.prototype.isLocal = function isLocal() {
|
||||||
return IP.isLoopback(this.host);
|
return IP.isLocal(this.raw);
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test whether the host is a private address.
|
|
||||||
* @returns {Boolean}
|
|
||||||
*/
|
|
||||||
|
|
||||||
NetAddress.prototype.isPrivate = function isPrivate() {
|
|
||||||
return IP.isPrivate(this.host);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -147,7 +147,7 @@ NetAddress.prototype.isPrivate = function isPrivate() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
NetAddress.prototype.isValid = function isValid() {
|
NetAddress.prototype.isValid = function isValid() {
|
||||||
return IP.isValid(this.host);
|
return IP.isValid(this.raw);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -156,7 +156,26 @@ NetAddress.prototype.isValid = function isValid() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
NetAddress.prototype.isRoutable = function isRoutable() {
|
NetAddress.prototype.isRoutable = function isRoutable() {
|
||||||
return IP.isRoutable(this.host);
|
return IP.isRoutable(this.raw);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether the host is an onion address.
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
NetAddress.prototype.isTor = function isTor() {
|
||||||
|
return IP.isTor(this.raw);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set null host.
|
||||||
|
*/
|
||||||
|
|
||||||
|
NetAddress.prototype.setNull = function setNull() {
|
||||||
|
this.raw = IP.ZERO_IP;
|
||||||
|
this.host = '0.0.0.0';
|
||||||
|
this.hostname = IP.hostname(this.host, this.port);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -165,8 +184,9 @@ NetAddress.prototype.isRoutable = function isRoutable() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
NetAddress.prototype.setHost = function setHost(host) {
|
NetAddress.prototype.setHost = function setHost(host) {
|
||||||
this.host = host;
|
this.raw = IP.toBuffer(host);
|
||||||
this.hostname = IP.hostname(host, this.port);
|
this.host = IP.toString(this.raw);
|
||||||
|
this.hostname = IP.hostname(this.host, this.port);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -190,9 +210,8 @@ NetAddress.prototype.setPort = function setPort(port) {
|
|||||||
NetAddress.prototype.fromHost = function fromHost(host, port, network) {
|
NetAddress.prototype.fromHost = function fromHost(host, port, network) {
|
||||||
network = Network.get(network);
|
network = Network.get(network);
|
||||||
|
|
||||||
assert(IP.version(host) !== -1);
|
this.raw = IP.toBuffer(host);
|
||||||
|
this.host = IP.toString(this.raw);
|
||||||
this.host = host;
|
|
||||||
this.port = port || network.port;
|
this.port = port || network.port;
|
||||||
this.services = NetAddress.DEFAULT_SERVICES;
|
this.services = NetAddress.DEFAULT_SERVICES;
|
||||||
this.ts = network.now();
|
this.ts = network.now();
|
||||||
@ -284,7 +303,8 @@ NetAddress.prototype.fromReader = function fromReader(br, full) {
|
|||||||
// are currently unused.
|
// are currently unused.
|
||||||
br.readU32();
|
br.readU32();
|
||||||
|
|
||||||
this.host = IP.toString(br.readBytes(16, true));
|
this.raw = br.readBytes(16);
|
||||||
|
this.host = IP.toString(this.raw);
|
||||||
this.port = br.readU16BE();
|
this.port = br.readU16BE();
|
||||||
this.hostname = IP.hostname(this.host, this.port);
|
this.hostname = IP.hostname(this.host, this.port);
|
||||||
|
|
||||||
@ -337,7 +357,7 @@ NetAddress.prototype.toWriter = function toWriter(bw, full) {
|
|||||||
|
|
||||||
bw.writeU32(this.services);
|
bw.writeU32(this.services);
|
||||||
bw.writeU32(0);
|
bw.writeU32(0);
|
||||||
bw.writeBytes(IP.toBuffer(this.host));
|
bw.writeBytes(this.raw);
|
||||||
bw.writeU16BE(this.port);
|
bw.writeU16BE(this.port);
|
||||||
|
|
||||||
return bw;
|
return bw;
|
||||||
@ -385,11 +405,11 @@ NetAddress.prototype.toJSON = function toJSON() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
NetAddress.prototype.fromJSON = function fromJSON(json) {
|
NetAddress.prototype.fromJSON = function fromJSON(json) {
|
||||||
assert(IP.version(json.host) !== -1);
|
|
||||||
assert(util.isNumber(json.port));
|
assert(util.isNumber(json.port));
|
||||||
assert(json.port >= 0 && json.port <= 0xffff);
|
assert(json.port >= 0 && json.port <= 0xffff);
|
||||||
assert(util.isNumber(json.services));
|
assert(util.isNumber(json.services));
|
||||||
assert(util.isNumber(json.ts));
|
assert(util.isNumber(json.ts));
|
||||||
|
this.raw = IP.toBuffer(json.host);
|
||||||
this.host = json.host;
|
this.host = json.host;
|
||||||
this.port = json.port;
|
this.port = json.port;
|
||||||
this.services = json.services;
|
this.services = json.services;
|
||||||
|
|||||||
584
lib/utils/ip.js
584
lib/utils/ip.js
@ -18,10 +18,26 @@ var IP = exports;
|
|||||||
* Constants
|
* Constants
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/;
|
var ZERO_IP = new Buffer('00000000000000000000000000000000', 'hex');
|
||||||
var ipv6Regex =
|
var LOCAL_IP = new Buffer('00000000000000000000000000000001', 'hex');
|
||||||
|
var RFC6052 = new Buffer('0064ff9b0000000000000000', 'hex');
|
||||||
|
var RFC4862 = new Buffer('fe80000000000000', 'hex');
|
||||||
|
var RFC6145 = new Buffer('0000000000000000ffff0000', 'hex');
|
||||||
|
var TOR_ONION = new Buffer('fd87d87eeb43', 'hex');
|
||||||
|
var V4MAP = new Buffer('00000000000000000000ffff', 'hex');
|
||||||
|
var SHIFTED = new Buffer('00000000000000ffff', 'hex');
|
||||||
|
|
||||||
|
var IPV4_REGEX = /^(\d{1,3}\.){3}\d{1,3}$/;
|
||||||
|
var IPV6_REGEX =
|
||||||
/^(::)?(((\d{1,3}\.){3}(\d{1,3}){1})?([0-9a-f]){0,4}:{0,2}){1,8}(::)?$/i;
|
/^(::)?(((\d{1,3}\.){3}(\d{1,3}){1})?([0-9a-f]){0,4}:{0,2}){1,8}(::)?$/i;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IP address of all zeroes.
|
||||||
|
* @const {Buffer}
|
||||||
|
*/
|
||||||
|
|
||||||
|
IP.ZERO_IP = ZERO_IP;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a hostname.
|
* Parse a hostname.
|
||||||
* @param {String} addr
|
* @param {String} addr
|
||||||
@ -30,7 +46,7 @@ var ipv6Regex =
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
IP.parseHost = function parseHost(addr, fallback) {
|
IP.parseHost = function parseHost(addr, fallback) {
|
||||||
var parts, host, port, version, hostname;
|
var parts, host, port, version, hostname, raw;
|
||||||
|
|
||||||
assert(typeof addr === 'string');
|
assert(typeof addr === 'string');
|
||||||
|
|
||||||
@ -91,8 +107,10 @@ IP.parseHost = function parseHost(addr, fallback) {
|
|||||||
|
|
||||||
version = IP.version(host);
|
version = IP.version(host);
|
||||||
|
|
||||||
if (version !== -1)
|
if (version !== -1) {
|
||||||
host = IP.normalize(host);
|
raw = IP.toBuffer(host);
|
||||||
|
host = IP.toString(raw);
|
||||||
|
}
|
||||||
|
|
||||||
hostname = host;
|
hostname = host;
|
||||||
|
|
||||||
@ -101,7 +119,7 @@ IP.parseHost = function parseHost(addr, fallback) {
|
|||||||
|
|
||||||
hostname += ':' + port;
|
hostname += ':' + port;
|
||||||
|
|
||||||
return new Address(host, port, version, hostname);
|
return new Address(host, port, version, hostname, raw);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -166,7 +184,7 @@ IP.isV4Format = function isV4Format(str) {
|
|||||||
if (str.length > 15)
|
if (str.length > 15)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return ipv4Regex.test(str);
|
return IPV4_REGEX.test(str);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -184,66 +202,64 @@ IP.isV6Format = function isV6Format(str) {
|
|||||||
if (str.length > 39)
|
if (str.length > 39)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return ipv6Regex.test(str);
|
return IPV6_REGEX.test(str);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test whether a buffer is an ipv4-mapped ipv6 address.
|
* Test whether a buffer is an ipv4-mapped ipv6 address.
|
||||||
* @param {Buffer} buf
|
* @param {Buffer} raw
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
IP.isMapped = function isMapped(buf) {
|
IP.isMapped = function isMapped(raw) {
|
||||||
var i;
|
assert(Buffer.isBuffer(raw));
|
||||||
|
assert(raw.length === 16);
|
||||||
|
|
||||||
assert(Buffer.isBuffer(buf));
|
return raw[0] === 0x00
|
||||||
assert(buf.length === 16);
|
&& raw[1] === 0x00
|
||||||
|
&& raw[2] === 0x00
|
||||||
if (buf[10] !== 0xff || buf[11] !== 0xff)
|
&& raw[3] === 0x00
|
||||||
return false;
|
&& raw[4] === 0x00
|
||||||
|
&& raw[5] === 0x00
|
||||||
for (i = 0; i < 10; i++) {
|
&& raw[6] === 0x00
|
||||||
if (buf[i] !== 0)
|
&& raw[7] === 0x00
|
||||||
return false;
|
&& raw[8] === 0x00
|
||||||
}
|
&& raw[9] === 0x00
|
||||||
|
&& raw[10] === 0xff
|
||||||
return true;
|
&& raw[11] === 0xff;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert an IP string to a buffer.
|
* Parse an IP string and return a buffer.
|
||||||
* @param {String} str
|
* @param {String} str
|
||||||
* @returns {Buffer}
|
* @returns {Buffer}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
IP.toBuffer = function toBuffer(str) {
|
IP.toBuffer = function toBuffer(str) {
|
||||||
var buf = new Buffer(16);
|
var raw = new Buffer(16);
|
||||||
|
|
||||||
assert(typeof str === 'string');
|
assert(typeof str === 'string');
|
||||||
|
|
||||||
if (IP.isV4Format(str)) {
|
if (IP.isV4Format(str)) {
|
||||||
buf.fill(0);
|
raw.fill(0);
|
||||||
buf[10] = 0xff;
|
raw[10] = 0xff;
|
||||||
buf[11] = 0xff;
|
raw[11] = 0xff;
|
||||||
return IP.parseV4(str, buf, 12);
|
return IP.parseV4(str, raw, 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IP.isV6Format(str))
|
return IP.parseV6(str, raw, 0);
|
||||||
return IP.parseV6(str, buf, 0);
|
|
||||||
|
|
||||||
throw Error('Invalid IP address: ' + str);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert an IPv4 string to a buffer.
|
* Convert an IPv4 string to a buffer.
|
||||||
* @private
|
* @private
|
||||||
* @param {String} str
|
* @param {String} str
|
||||||
* @param {Buffer} buf
|
* @param {Buffer} raw
|
||||||
* @param {Number} offset
|
* @param {Number} offset
|
||||||
* @returns {Buffer}
|
* @returns {Buffer}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
IP.parseV4 = function parseV4(str, buf, offset) {
|
IP.parseV4 = function parseV4(str, raw, offset) {
|
||||||
var parts = str.split('.');
|
var parts = str.split('.');
|
||||||
var i, ch;
|
var i, ch;
|
||||||
|
|
||||||
@ -255,29 +271,28 @@ IP.parseV4 = function parseV4(str, buf, offset) {
|
|||||||
assert(ch.length <= 3);
|
assert(ch.length <= 3);
|
||||||
ch = parseInt(ch, 10);
|
ch = parseInt(ch, 10);
|
||||||
assert(ch >= 0 && ch <= 255);
|
assert(ch >= 0 && ch <= 255);
|
||||||
buf[offset++] = ch;
|
raw[offset++] = ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
return buf;
|
return raw;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert an IPv6 string to a buffer.
|
* Convert an IPv6 string to a buffer.
|
||||||
* @private
|
* @private
|
||||||
* @param {String} str
|
* @param {String} str
|
||||||
* @param {Buffer} buf
|
* @param {Buffer} raw
|
||||||
* @param {Number} offset
|
* @param {Number} offset
|
||||||
* @returns {Buffer}
|
* @returns {Buffer}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
IP.parseV6 = function parseV6(str, buf, offset) {
|
IP.parseV6 = function parseV6(str, raw, offset) {
|
||||||
var parts = str.split(':');
|
var parts = str.split(':');
|
||||||
var missing = 8 - parts.length;
|
var missing = 8 - parts.length;
|
||||||
var start = offset;
|
var start = offset;
|
||||||
var colon = false;
|
var colon = false;
|
||||||
var i, word;
|
var i, word;
|
||||||
|
|
||||||
assert(missing >= 0, 'IPv6 address is too long.');
|
|
||||||
assert(parts.length >= 2, 'Not an IPv6 address.');
|
assert(parts.length >= 2, 'Not an IPv6 address.');
|
||||||
|
|
||||||
for (i = 0; i < parts.length; i++) {
|
for (i = 0; i < parts.length; i++) {
|
||||||
@ -286,8 +301,6 @@ IP.parseV6 = function parseV6(str, buf, offset) {
|
|||||||
missing--;
|
missing--;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(missing >= 0, 'IPv6 address is too long.');
|
|
||||||
|
|
||||||
for (i = 0; i < parts.length; i++) {
|
for (i = 0; i < parts.length; i++) {
|
||||||
word = parts[i];
|
word = parts[i];
|
||||||
|
|
||||||
@ -308,8 +321,8 @@ IP.parseV6 = function parseV6(str, buf, offset) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (missing > 0) {
|
while (missing > 0) {
|
||||||
buf[offset++] = 0;
|
raw[offset++] = 0;
|
||||||
buf[offset++] = 0;
|
raw[offset++] = 0;
|
||||||
missing--;
|
missing--;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,7 +330,7 @@ IP.parseV6 = function parseV6(str, buf, offset) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (IP.isV4Format(word)) {
|
if (IP.isV4Format(word)) {
|
||||||
IP.parseV4(word, buf, offset);
|
IP.parseV4(word, raw, offset);
|
||||||
offset += 4;
|
offset += 4;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -328,50 +341,50 @@ IP.parseV6 = function parseV6(str, buf, offset) {
|
|||||||
|
|
||||||
assert(word === word, 'Non-number in IPv6 address.');
|
assert(word === word, 'Non-number in IPv6 address.');
|
||||||
|
|
||||||
buf[offset++] = (word >> 8) & 0xff;
|
raw[offset++] = (word >> 8) & 0xff;
|
||||||
buf[offset++] = word & 0xff;
|
raw[offset++] = word & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(missing === 0, 'IPv6 address has missing sections.');
|
assert(missing === 0, 'IPv6 address has missing sections.');
|
||||||
assert.equal(offset, start + 16);
|
assert.equal(offset, start + 16);
|
||||||
|
|
||||||
return buf;
|
return raw;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a buffer to an ip string.
|
* Convert a buffer to an ip string.
|
||||||
* @param {Buffer} buf
|
* @param {Buffer} raw
|
||||||
* @returns {String}
|
* @returns {String}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
IP.toString = function toString(buf) {
|
IP.toString = function toString(raw) {
|
||||||
var str = '';
|
var str = '';
|
||||||
var i;
|
var i;
|
||||||
|
|
||||||
assert(Buffer.isBuffer(buf));
|
assert(Buffer.isBuffer(raw));
|
||||||
|
|
||||||
if (buf.length === 4) {
|
if (raw.length === 4) {
|
||||||
str += buf[0];
|
str += raw[0];
|
||||||
str += '.' + buf[1];
|
str += '.' + raw[1];
|
||||||
str += '.' + buf[2];
|
str += '.' + raw[2];
|
||||||
str += '.' + buf[3];
|
str += '.' + raw[3];
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buf.length === 16) {
|
if (raw.length === 16) {
|
||||||
if (IP.isMapped(buf)) {
|
if (IP.isMapped(raw)) {
|
||||||
str += buf[12];
|
str += raw[12];
|
||||||
str += '.' + buf[13];
|
str += '.' + raw[13];
|
||||||
str += '.' + buf[14];
|
str += '.' + raw[14];
|
||||||
str += '.' + buf[15];
|
str += '.' + raw[15];
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
str += buf.readUInt16BE(0, true).toString(16);
|
str += raw.readUInt16BE(0, true).toString(16);
|
||||||
|
|
||||||
for (i = 2; i < 16; i += 2) {
|
for (i = 2; i < 16; i += 2) {
|
||||||
str += ':';
|
str += ':';
|
||||||
str += buf.readUInt16BE(i, true).toString(16);
|
str += raw.readUInt16BE(i, true).toString(16);
|
||||||
}
|
}
|
||||||
|
|
||||||
str = str.replace(/(^|:)0(:0)*:0(:|$)/, '$1::$3');
|
str = str.replace(/(^|:)0(:0)*:0(:|$)/, '$1::$3');
|
||||||
@ -380,7 +393,31 @@ IP.toString = function toString(buf) {
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw Error('Invalid IP address: ' + buf.toString('hex'));
|
throw Error('Invalid IP address: ' + raw.toString('hex'));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a buffer to an ip string or .onion.
|
||||||
|
* @param {Buffer} raw
|
||||||
|
* @returns {String}
|
||||||
|
*/
|
||||||
|
|
||||||
|
IP.toHost = function toHost(raw) {
|
||||||
|
var i, ch, host;
|
||||||
|
|
||||||
|
if (IP.isTor(raw)) {
|
||||||
|
host = '';
|
||||||
|
for (i = 6; i < raw.length; i += 2) {
|
||||||
|
ch = raw[i];
|
||||||
|
ch = ch.toString(32);
|
||||||
|
while (ch.length < 4)
|
||||||
|
ch = '0' + ch;
|
||||||
|
host += ch;
|
||||||
|
}
|
||||||
|
return host + '.onion';
|
||||||
|
}
|
||||||
|
|
||||||
|
return IP.toString(raw);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -394,116 +431,421 @@ IP.normalize = function normalize(str) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test whether an IP is null.
|
* Test whether the address is IPv4.
|
||||||
* @param {String} str - Normalized ip.
|
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
IP.isNull = function isNull(str) {
|
IP.isIPv4 = function isIPv4(raw) {
|
||||||
return str === '0.0.0.0' || str === '::';
|
return IP.isMapped(raw);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test whether the IP is a broadcast address.
|
* Test whether the address is IPv6.
|
||||||
* @param {String} str - Normalized ip.
|
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
IP.isBroadcast = function isBroadcast(str) {
|
IP.isIPv6 = function isIPv6(raw) {
|
||||||
return str === '255.255.255.255'
|
return !IP.isMapped(raw) && !IP.isTor(raw);
|
||||||
|| str === '::ffff:ffff:ffff';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test whether the IP is valid.
|
* Test whether the host is null.
|
||||||
* @param {String} str - Normalized ip.
|
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
IP.isValid = function isValid(str) {
|
IP.isNull = function isNull(raw) {
|
||||||
return !IP.isNull(str) && !IP.isBroadcast(str);
|
if (IP.isIPv4(raw)) {
|
||||||
|
// 0.0.0.0
|
||||||
|
return raw[12] === 0
|
||||||
|
&& raw[13] === 0
|
||||||
|
&& raw[14] === 0
|
||||||
|
&& raw[15] === 0;
|
||||||
|
}
|
||||||
|
// ::
|
||||||
|
return IP.isEqual(raw, ZERO_IP);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test whether the IP is routable.
|
* Test whether the host is a broadcast address.
|
||||||
* @param {String} str - Normalized ip.
|
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
IP.isRoutable = function isRoutable(str) {
|
IP.isBroadcast = function isBroadcast(raw) {
|
||||||
return IP.isValid(str) && !IP.isLoopback(str);
|
if (IP.isIPv4(raw)) {
|
||||||
|
// 255.255.255.255
|
||||||
|
return raw[12] === 255
|
||||||
|
&& raw[13] === 255
|
||||||
|
&& raw[14] === 255
|
||||||
|
&& raw[15] === 255;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test whether a string is a private address.
|
* Test whether the ip is RFC 1918.
|
||||||
* @param {String} str
|
* @param {Buffer} raw
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
IP.isPrivate = function isPrivate(str) {
|
IP.isRFC1918 = function isRFC1918(raw) {
|
||||||
assert(typeof str === 'string');
|
if (!IP.isIPv4(raw))
|
||||||
|
return false;
|
||||||
|
|
||||||
return /^(::f{4}:)?10\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(str)
|
if (raw[12] === 10)
|
||||||
|| /^(::f{4}:)?192\.168\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(str)
|
return true;
|
||||||
|| /^(::f{4}:)?172\.(1[6-9]|2\d|30|31)\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(str)
|
|
||||||
|| /^(::f{4}:)?127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(str)
|
if (raw[12] === 192 && raw[13] === 168)
|
||||||
|| /^(::f{4}:)?169\.254\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(str)
|
return true;
|
||||||
|| /^f[cd][0-9a-f]{2}:/i.test(str)
|
|
||||||
|| /^fe80:/i.test(str)
|
if (raw[12] === 172 && (raw[13] >= 16 && raw[13] <= 31))
|
||||||
|| /^::1$/.test(str)
|
return true;
|
||||||
|| /^::$/.test(str);
|
|
||||||
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test whether a string is a public address.
|
* Test whether the ip is RFC 2544.
|
||||||
* @param {String} str
|
* @param {Buffer} raw
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
IP.isPublic = function isPublic(str) {
|
IP.isRFC2544 = function isRFC2544(raw) {
|
||||||
return !IP.isPrivate(str);
|
if (!IP.isIPv4(raw))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (raw[12] === 198 && (raw[13] === 18 || raw[13] === 19))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (raw[12] === 169 && raw[13] === 254)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test whether a string is a loopback address.
|
* Test whether the ip is RFC 3927.
|
||||||
* @param {String} str
|
* @param {Buffer} raw
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
IP.isLoopback = function isLoopback(str) {
|
IP.isRFC3927 = function isRFC3927(raw) {
|
||||||
assert(typeof str === 'string');
|
if (!IP.isIPv4(raw))
|
||||||
|
return false;
|
||||||
|
|
||||||
return /^(::f{4}:)?127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/.test(str)
|
if (raw[12] === 169 && raw[13] === 254)
|
||||||
|| /^fe80::1$/.test(str)
|
return true;
|
||||||
|| /^::1$/.test(str)
|
|
||||||
|| /^::$/.test(str);
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get loopback address for ip family.
|
* Test whether the ip is RFC 6598.
|
||||||
* @param {String} family - ipv4 or ipv6.
|
* @param {Buffer} raw
|
||||||
* @returns {String}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
IP.loopback = function loopback(family) {
|
IP.isRFC6598 = function isRFC6598(raw) {
|
||||||
if (!family)
|
if (!IP.isIPv4(raw))
|
||||||
family = 'ipv4';
|
return false;
|
||||||
|
|
||||||
family = family.toLowerCase();
|
if (raw[12] === 100
|
||||||
|
&& (raw[13] >= 64 && raw[13] <= 127)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (family !== 'ipv4' && family !== 'ipv6')
|
return false;
|
||||||
throw new Error('Family must be ipv4 or ipv6.');
|
|
||||||
|
|
||||||
return family === 'ipv4' ? '127.0.0.1' : 'fe80::1';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Helpers
|
* Test whether the ip is RFC 5737.
|
||||||
|
* @param {Buffer} raw
|
||||||
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function Address(host, port, version, hostname) {
|
IP.isRFC5737 = function isRFC5737(raw) {
|
||||||
|
if (!IP.isIPv4(raw))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (raw[12] === 192
|
||||||
|
&& (raw[13] === 0 && raw[14] === 2)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (raw[12] === 198 && raw[13] === 51 && raw[14] === 100)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (raw[12] === 203 && raw[13] === 0 && raw[14] === 113)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether the ip is RFC 3849.
|
||||||
|
* @param {Buffer} raw
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
IP.isRFC3849 = function isRFC3849(raw) {
|
||||||
|
if (raw[0] === 0x20 && raw[1] === 0x01
|
||||||
|
&& raw[2] === 0x0d && raw[3] === 0xb8) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether the ip is RFC 3964.
|
||||||
|
* @param {Buffer} raw
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
IP.isRFC3964 = function isRFC3964(raw) {
|
||||||
|
if (raw[0] === 0x20 && raw[1] === 0x02)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether the ip is RFC 6052.
|
||||||
|
* @param {Buffer} raw
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
IP.isRFC6052 = function isRFC6052(raw) {
|
||||||
|
return IP.hasPrefix(raw, RFC6052);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether the ip is RFC 4380.
|
||||||
|
* @param {Buffer} raw
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
IP.isRFC4380 = function isRFC4380(raw) {
|
||||||
|
if (raw[0] === 0x20 && raw[1] === 0x01
|
||||||
|
&& raw[2] === 0x00 && raw[3] === 0x00) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether the ip is RFC 4862.
|
||||||
|
* @param {Buffer} raw
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
IP.isRFC4862 = function isRFC4862(raw) {
|
||||||
|
return IP.hasPrefix(raw, RFC4862);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether the ip is RFC 4193.
|
||||||
|
* @param {Buffer} raw
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
IP.isRFC4193 = function isRFC4193(raw) {
|
||||||
|
if ((raw[0] & 0xfe) === 0xfc)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether the ip is RFC 6145.
|
||||||
|
* @param {Buffer} raw
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
IP.isRFC6145 = function isRFC6145(raw) {
|
||||||
|
return IP.hasPrefix(raw, RFC6145);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether the ip is RFC 4843.
|
||||||
|
* @param {Buffer} raw
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
IP.isRFC4843 = function isRFC4843(raw) {
|
||||||
|
if (raw[0] === 0x20 && raw[1] === 0x01
|
||||||
|
&& raw[2] === 0x00 && (raw[3] & 0xf0) === 0x10) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether the ip has a tor onion prefix.
|
||||||
|
* @param {Buffer} raw
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
IP.isTor = function isTor(raw) {
|
||||||
|
return IP.hasPrefix(raw, TOR_ONION);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether the ip is local.
|
||||||
|
* @param {Buffer} raw
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
IP.isLocal = function isLocal(raw) {
|
||||||
|
if (IP.isIPv4(raw)) {
|
||||||
|
if (raw[12] === 127 && raw[13] === 0)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IP.isEqual(raw, LOCAL_IP))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether the ip is a multicast address.
|
||||||
|
* @param {Buffer} raw
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
IP.isMulticast = function isMulticast(raw) {
|
||||||
|
if (IP.isIPv4(raw)) {
|
||||||
|
if ((raw[12] & 0xf0) === 0xe0)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return raw[0] === 0xff;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether the ip is valid.
|
||||||
|
* @param {Buffer} raw
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
IP.isValid = function isValid(raw) {
|
||||||
|
if (IP.hasPrefix(raw, SHIFTED))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (IP.isNull(raw))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (IP.isBroadcast(raw))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (IP.isRFC3849(raw))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether the ip is routable.
|
||||||
|
* @param {Buffer} raw
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
IP.isRoutable = function isRoutable(raw) {
|
||||||
|
if (!IP.isValid(raw))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (IP.isRFC1918(raw))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (IP.isRFC2544(raw))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (IP.isRFC3927(raw))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (IP.isRFC4862(raw))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (IP.isRFC6598(raw))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (IP.isRFC5737(raw))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (IP.isRFC4193(raw) && !IP.isTor(raw))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (IP.isRFC4843(raw))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (IP.isLocal(raw))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether an IP has a prefix.
|
||||||
|
* @param {Buffer} raw
|
||||||
|
* @param {Buffer} prefix
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
IP.hasPrefix = function hasPrefix(raw, prefix) {
|
||||||
|
var i;
|
||||||
|
|
||||||
|
assert(Buffer.isBuffer(raw));
|
||||||
|
assert(Buffer.isBuffer(prefix));
|
||||||
|
assert(raw.length >= prefix.length);
|
||||||
|
|
||||||
|
for (i = 0; i < prefix.length; i++) {
|
||||||
|
if (raw[i] !== prefix[i])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether two IPs are equal.
|
||||||
|
* @param {Buffer} a
|
||||||
|
* @param {Buffer} b
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
IP.isEqual = function isEqual(a, b) {
|
||||||
|
var i;
|
||||||
|
|
||||||
|
assert(a.length === 16);
|
||||||
|
assert(b.length === 16);
|
||||||
|
|
||||||
|
if (a.compare)
|
||||||
|
return a.compare(b) === 0;
|
||||||
|
|
||||||
|
for (i = 0; i < a.length; i++) {
|
||||||
|
if (a[i] !== b[i])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a parsed address.
|
||||||
|
* @param {String} host
|
||||||
|
* @param {Number} port
|
||||||
|
* @param {Number} version
|
||||||
|
* @param {String} hostname
|
||||||
|
* @param {Buffer} raw
|
||||||
|
*/
|
||||||
|
|
||||||
|
function Address(host, port, version, hostname, raw) {
|
||||||
this.host = host;
|
this.host = host;
|
||||||
this.port = port;
|
this.port = port;
|
||||||
this.version = version;
|
this.version = version;
|
||||||
this.hostname = hostname;
|
this.hostname = hostname;
|
||||||
|
this.raw = raw || ZERO_IP;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user