| | |
| | | 'use strict'; |
| | | |
| | | var ip = exports; |
| | | var Buffer = require('buffer').Buffer; |
| | | var { Buffer } = require('buffer'); |
| | | var os = require('os'); |
| | | |
| | | ip.toBuffer = function(ip, buff, offset) { |
| | | ip.toBuffer = function (ip, buff, offset) { |
| | | offset = ~~offset; |
| | | |
| | | var result; |
| | | |
| | | if (this.isV4Format(ip)) { |
| | | result = buff || new Buffer(offset + 4); |
| | | ip.split(/\./g).map(function(byte) { |
| | | ip.split(/\./g).map((byte) => { |
| | | result[offset++] = parseInt(byte, 10) & 0xff; |
| | | }); |
| | | } else if (this.isV6Format(ip)) { |
| | |
| | | while (sections.length < 8) sections.push('0'); |
| | | } else if (sections.length < 8) { |
| | | for (i = 0; i < sections.length && sections[i] !== ''; i++); |
| | | var argv = [ i, 1 ]; |
| | | var argv = [i, 1]; |
| | | for (i = 9 - sections.length; i > 0; i--) { |
| | | argv.push('0'); |
| | | } |
| | |
| | | } |
| | | |
| | | if (!result) { |
| | | throw Error('Invalid ip address: ' + ip); |
| | | throw Error(`Invalid ip address: ${ip}`); |
| | | } |
| | | |
| | | return result; |
| | | }; |
| | | |
| | | ip.toString = function(buff, offset, length) { |
| | | ip.toString = function (buff, offset, length) { |
| | | offset = ~~offset; |
| | | length = length || (buff.length - offset); |
| | | |
| | | var result = []; |
| | | var i; |
| | | if (length === 4) { |
| | | // IPv4 |
| | | for (var i = 0; i < length; i++) { |
| | | for (i = 0; i < length; i++) { |
| | | result.push(buff[offset + i]); |
| | | } |
| | | result = result.join('.'); |
| | | } else if (length === 16) { |
| | | // IPv6 |
| | | for (var i = 0; i < length; i += 2) { |
| | | for (i = 0; i < length; i += 2) { |
| | | result.push(buff.readUInt16BE(offset + i).toString(16)); |
| | | } |
| | | result = result.join(':'); |
| | |
| | | }; |
| | | |
| | | var ipv4Regex = /^(\d{1,3}\.){3,3}\d{1,3}$/; |
| | | var ipv6Regex = |
| | | /^(::)?(((\d{1,3}\.){3}(\d{1,3}){1})?([0-9a-f]){0,4}:{0,2}){1,8}(::)?$/i; |
| | | var ipv6Regex = /^(::)?(((\d{1,3}\.){3}(\d{1,3}){1})?([0-9a-f]){0,4}:{0,2}){1,8}(::)?$/i; |
| | | |
| | | ip.isV4Format = function(ip) { |
| | | ip.isV4Format = function (ip) { |
| | | return ipv4Regex.test(ip); |
| | | }; |
| | | |
| | | ip.isV6Format = function(ip) { |
| | | ip.isV6Format = function (ip) { |
| | | return ipv6Regex.test(ip); |
| | | }; |
| | | |
| | | function _normalizeFamily(family) { |
| | | if (family === 4) { |
| | | return 'ipv4'; |
| | | } |
| | | if (family === 6) { |
| | | return 'ipv6'; |
| | | } |
| | | return family ? family.toLowerCase() : 'ipv4'; |
| | | } |
| | | |
| | | ip.fromPrefixLen = function(prefixlen, family) { |
| | | ip.fromPrefixLen = function (prefixlen, family) { |
| | | if (prefixlen > 32) { |
| | | family = 'ipv6'; |
| | | } else { |
| | |
| | | return ip.toString(buff); |
| | | }; |
| | | |
| | | ip.mask = function(addr, mask) { |
| | | ip.mask = function (addr, mask) { |
| | | addr = ip.toBuffer(addr); |
| | | mask = ip.toBuffer(mask); |
| | | |
| | | var result = new Buffer(Math.max(addr.length, mask.length)); |
| | | |
| | | var i = 0; |
| | | // Same protocol - do bitwise and |
| | | var i; |
| | | if (addr.length === mask.length) { |
| | | for (i = 0; i < addr.length; i++) { |
| | | result[i] = addr[i] & mask[i]; |
| | |
| | | // IPv6 address and IPv4 mask |
| | | // (Mask low bits) |
| | | for (i = 0; i < mask.length; i++) { |
| | | result[i] = addr[addr.length - 4 + i] & mask[i]; |
| | | result[i] = addr[addr.length - 4 + i] & mask[i]; |
| | | } |
| | | } else { |
| | | // IPv6 mask and IPv4 addr |
| | | for (var i = 0; i < result.length - 6; i++) { |
| | | for (i = 0; i < result.length - 6; i++) { |
| | | result[i] = 0; |
| | | } |
| | | |
| | |
| | | for (i = 0; i < addr.length; i++) { |
| | | result[i + 12] = addr[i] & mask[i + 12]; |
| | | } |
| | | i = i + 12; |
| | | i += 12; |
| | | } |
| | | for (; i < result.length; i++) |
| | | for (; i < result.length; i++) { |
| | | result[i] = 0; |
| | | } |
| | | |
| | | return ip.toString(result); |
| | | }; |
| | | |
| | | ip.cidr = function(cidrString) { |
| | | ip.cidr = function (cidrString) { |
| | | var cidrParts = cidrString.split('/'); |
| | | |
| | | var addr = cidrParts[0]; |
| | | if (cidrParts.length !== 2) |
| | | throw new Error('invalid CIDR subnet: ' + addr); |
| | | if (cidrParts.length !== 2) { |
| | | throw new Error(`invalid CIDR subnet: ${addr}`); |
| | | } |
| | | |
| | | var mask = ip.fromPrefixLen(parseInt(cidrParts[1], 10)); |
| | | |
| | | return ip.mask(addr, mask); |
| | | }; |
| | | |
| | | ip.subnet = function(addr, mask) { |
| | | ip.subnet = function (addr, mask) { |
| | | var networkAddress = ip.toLong(ip.mask(addr, mask)); |
| | | |
| | | // Calculate the mask's length. |
| | |
| | | |
| | | return { |
| | | networkAddress: ip.fromLong(networkAddress), |
| | | firstAddress: numberOfAddresses <= 2 ? |
| | | ip.fromLong(networkAddress) : |
| | | ip.fromLong(networkAddress + 1), |
| | | lastAddress: numberOfAddresses <= 2 ? |
| | | ip.fromLong(networkAddress + numberOfAddresses - 1) : |
| | | ip.fromLong(networkAddress + numberOfAddresses - 2), |
| | | firstAddress: numberOfAddresses <= 2 |
| | | ? ip.fromLong(networkAddress) |
| | | : ip.fromLong(networkAddress + 1), |
| | | lastAddress: numberOfAddresses <= 2 |
| | | ? ip.fromLong(networkAddress + numberOfAddresses - 1) |
| | | : ip.fromLong(networkAddress + numberOfAddresses - 2), |
| | | broadcastAddress: ip.fromLong(networkAddress + numberOfAddresses - 1), |
| | | subnetMask: mask, |
| | | subnetMaskLength: maskLength, |
| | | numHosts: numberOfAddresses <= 2 ? |
| | | numberOfAddresses : numberOfAddresses - 2, |
| | | numHosts: numberOfAddresses <= 2 |
| | | ? numberOfAddresses : numberOfAddresses - 2, |
| | | length: numberOfAddresses, |
| | | contains: function(other) { |
| | | contains(other) { |
| | | return networkAddress === ip.toLong(ip.mask(other, mask)); |
| | | } |
| | | }, |
| | | }; |
| | | }; |
| | | |
| | | ip.cidrSubnet = function(cidrString) { |
| | | ip.cidrSubnet = function (cidrString) { |
| | | var cidrParts = cidrString.split('/'); |
| | | |
| | | var addr = cidrParts[0]; |
| | | if (cidrParts.length !== 2) |
| | | throw new Error('invalid CIDR subnet: ' + addr); |
| | | if (cidrParts.length !== 2) { |
| | | throw new Error(`invalid CIDR subnet: ${addr}`); |
| | | } |
| | | |
| | | var mask = ip.fromPrefixLen(parseInt(cidrParts[1], 10)); |
| | | |
| | | return ip.subnet(addr, mask); |
| | | }; |
| | | |
| | | ip.not = function(addr) { |
| | | ip.not = function (addr) { |
| | | var buff = ip.toBuffer(addr); |
| | | for (var i = 0; i < buff.length; i++) { |
| | | buff[i] = 0xff ^ buff[i]; |
| | |
| | | return ip.toString(buff); |
| | | }; |
| | | |
| | | ip.or = function(a, b) { |
| | | ip.or = function (a, b) { |
| | | var i; |
| | | |
| | | a = ip.toBuffer(a); |
| | | b = ip.toBuffer(b); |
| | | |
| | | // same protocol |
| | | if (a.length === b.length) { |
| | | for (var i = 0; i < a.length; ++i) { |
| | | for (i = 0; i < a.length; ++i) { |
| | | a[i] |= b[i]; |
| | | } |
| | | return ip.toString(a); |
| | | |
| | | // mixed protocols |
| | | } else { |
| | | var buff = a; |
| | | var other = b; |
| | | if (b.length > a.length) { |
| | | buff = b; |
| | | other = a; |
| | | } |
| | | |
| | | var offset = buff.length - other.length; |
| | | for (var i = offset; i < buff.length; ++i) { |
| | | buff[i] |= other[i - offset]; |
| | | } |
| | | |
| | | return ip.toString(buff); |
| | | } |
| | | var buff = a; |
| | | var other = b; |
| | | if (b.length > a.length) { |
| | | buff = b; |
| | | other = a; |
| | | } |
| | | |
| | | var offset = buff.length - other.length; |
| | | for (i = offset; i < buff.length; ++i) { |
| | | buff[i] |= other[i - offset]; |
| | | } |
| | | |
| | | return ip.toString(buff); |
| | | }; |
| | | |
| | | ip.isEqual = function(a, b) { |
| | | ip.isEqual = function (a, b) { |
| | | var i; |
| | | |
| | | a = ip.toBuffer(a); |
| | | b = ip.toBuffer(b); |
| | | |
| | | // Same protocol |
| | | if (a.length === b.length) { |
| | | for (var i = 0; i < a.length; i++) { |
| | | for (i = 0; i < a.length; i++) { |
| | | if (a[i] !== b[i]) return false; |
| | | } |
| | | return true; |
| | |
| | | } |
| | | |
| | | // a - IPv4, b - IPv6 |
| | | for (var i = 0; i < 10; i++) { |
| | | for (i = 0; i < 10; i++) { |
| | | if (b[i] !== 0) return false; |
| | | } |
| | | |
| | | var word = b.readUInt16BE(10); |
| | | if (word !== 0 && word !== 0xffff) return false; |
| | | |
| | | for (var i = 0; i < 4; i++) { |
| | | for (i = 0; i < 4; i++) { |
| | | if (a[i] !== b[i + 12]) return false; |
| | | } |
| | | |
| | | return true; |
| | | }; |
| | | |
| | | ip.isPrivate = function(addr) { |
| | | ip.isPrivate = function (addr) { |
| | | return /^(::f{4}:)?10\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i |
| | | .test(addr) || |
| | | /^(::f{4}:)?192\.168\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) || |
| | | /^(::f{4}:)?172\.(1[6-9]|2\d|30|31)\.([0-9]{1,3})\.([0-9]{1,3})$/i |
| | | .test(addr) || |
| | | /^(::f{4}:)?127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) || |
| | | /^(::f{4}:)?169\.254\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) || |
| | | /^f[cd][0-9a-f]{2}:/i.test(addr) || |
| | | /^fe80:/i.test(addr) || |
| | | /^::1$/.test(addr) || |
| | | /^::$/.test(addr); |
| | | .test(addr) |
| | | || /^(::f{4}:)?192\.168\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) |
| | | || /^(::f{4}:)?172\.(1[6-9]|2\d|30|31)\.([0-9]{1,3})\.([0-9]{1,3})$/i |
| | | .test(addr) |
| | | || /^(::f{4}:)?127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) |
| | | || /^(::f{4}:)?169\.254\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) |
| | | || /^f[cd][0-9a-f]{2}:/i.test(addr) |
| | | || /^fe80:/i.test(addr) |
| | | || /^::1$/.test(addr) |
| | | || /^::$/.test(addr); |
| | | }; |
| | | |
| | | ip.isPublic = function(addr) { |
| | | ip.isPublic = function (addr) { |
| | | return !ip.isPrivate(addr); |
| | | }; |
| | | |
| | | ip.isLoopback = function(addr) { |
| | | ip.isLoopback = function (addr) { |
| | | return /^(::f{4}:)?127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/ |
| | | .test(addr) || |
| | | /^fe80::1$/.test(addr) || |
| | | /^::1$/.test(addr) || |
| | | /^::$/.test(addr); |
| | | .test(addr) |
| | | || /^fe80::1$/.test(addr) |
| | | || /^::1$/.test(addr) |
| | | || /^::$/.test(addr); |
| | | }; |
| | | |
| | | ip.loopback = function(family) { |
| | | ip.loopback = function (family) { |
| | | // |
| | | // Default to `ipv4` |
| | | // |
| | |
| | | // * 'private': the first private ip address of family. |
| | | // * undefined: First address with `ipv4` or loopback address `127.0.0.1`. |
| | | // |
| | | ip.address = function(name, family) { |
| | | ip.address = function (name, family) { |
| | | var interfaces = os.networkInterfaces(); |
| | | var all; |
| | | |
| | | // |
| | | // Default to `ipv4` |
| | |
| | | // return the address. |
| | | // |
| | | if (name && name !== 'private' && name !== 'public') { |
| | | var res = interfaces[name].filter(function(details) { |
| | | var itemFamily = details.family.toLowerCase(); |
| | | var res = interfaces[name].filter((details) => { |
| | | var itemFamily = _normalizeFamily(details.family); |
| | | return itemFamily === family; |
| | | }); |
| | | if (res.length === 0) |
| | | if (res.length === 0) { |
| | | return undefined; |
| | | } |
| | | return res[0].address; |
| | | } |
| | | |
| | | var all = Object.keys(interfaces).map(function (nic) { |
| | | var all = Object.keys(interfaces).map((nic) => { |
| | | // |
| | | // Note: name will only be `public` or `private` |
| | | // when this is called. |
| | | // |
| | | var addresses = interfaces[nic].filter(function (details) { |
| | | details.family = details.family.toLowerCase(); |
| | | var addresses = interfaces[nic].filter((details) => { |
| | | details.family = _normalizeFamily(details.family); |
| | | if (details.family !== family || ip.isLoopback(details.address)) { |
| | | return false; |
| | | } else if (!name) { |
| | | } if (!name) { |
| | | return true; |
| | | } |
| | | |
| | | return name === 'public' ? ip.isPrivate(details.address) : |
| | | ip.isPublic(details.address); |
| | | return name === 'public' ? ip.isPrivate(details.address) |
| | | : ip.isPublic(details.address); |
| | | }); |
| | | |
| | | return addresses.length ? addresses[0].address : undefined; |
| | |
| | | return !all.length ? ip.loopback(family) : all[0]; |
| | | }; |
| | | |
| | | ip.toLong = function(ip) { |
| | | ip.toLong = function (ip) { |
| | | var ipl = 0; |
| | | ip.split('.').forEach(function(octet) { |
| | | ip.split('.').forEach((octet) => { |
| | | ipl <<= 8; |
| | | ipl += parseInt(octet); |
| | | }); |
| | | return(ipl >>> 0); |
| | | return (ipl >>> 0); |
| | | }; |
| | | |
| | | ip.fromLong = function(ipl) { |
| | | return ((ipl >>> 24) + '.' + |
| | | (ipl >> 16 & 255) + '.' + |
| | | (ipl >> 8 & 255) + '.' + |
| | | (ipl & 255) ); |
| | | ip.fromLong = function (ipl) { |
| | | return (`${ipl >>> 24}.${ |
| | | ipl >> 16 & 255}.${ |
| | | ipl >> 8 & 255}.${ |
| | | ipl & 255}`); |
| | | }; |