Comparing version 1.9.1 to 2.0.0
@@ -1,1 +0,1 @@ | ||
(function(){var r,t,n,e,i,o,a,s;t={},s=this,"undefined"!=typeof module&&null!==module&&module.exports?module.exports=t:s.ipaddr=t,a=function(r,t,n,e){var i,o;if(r.length!==t.length)throw new Error("ipaddr: cannot match CIDR for objects with different lengths");for(i=0;e>0;){if((o=n-e)<0&&(o=0),r[i]>>o!=t[i]>>o)return!1;e-=n,i+=1}return!0},t.subnetMatch=function(r,t,n){var e,i,o,a,s;null==n&&(n="unicast");for(o in t)for(!(a=t[o])[0]||a[0]instanceof Array||(a=[a]),e=0,i=a.length;e<i;e++)if(s=a[e],r.kind()===s[0].kind()&&r.match.apply(r,s))return o;return n},t.IPv4=function(){function r(r){var t,n,e;if(4!==r.length)throw new Error("ipaddr: ipv4 octet count should be 4");for(t=0,n=r.length;t<n;t++)if(!(0<=(e=r[t])&&e<=255))throw new Error("ipaddr: ipv4 octet should fit in 8 bits");this.octets=r}return r.prototype.kind=function(){return"ipv4"},r.prototype.toString=function(){return this.octets.join(".")},r.prototype.toNormalizedString=function(){return this.toString()},r.prototype.toByteArray=function(){return this.octets.slice(0)},r.prototype.match=function(r,t){var n;if(void 0===t&&(r=(n=r)[0],t=n[1]),"ipv4"!==r.kind())throw new Error("ipaddr: cannot match ipv4 address with non-ipv4 one");return a(this.octets,r.octets,8,t)},r.prototype.SpecialRanges={unspecified:[[new r([0,0,0,0]),8]],broadcast:[[new r([255,255,255,255]),32]],multicast:[[new r([224,0,0,0]),4]],linkLocal:[[new r([169,254,0,0]),16]],loopback:[[new r([127,0,0,0]),8]],carrierGradeNat:[[new r([100,64,0,0]),10]],private:[[new r([10,0,0,0]),8],[new r([172,16,0,0]),12],[new r([192,168,0,0]),16]],reserved:[[new r([192,0,0,0]),24],[new r([192,0,2,0]),24],[new r([192,88,99,0]),24],[new r([198,51,100,0]),24],[new r([203,0,113,0]),24],[new r([240,0,0,0]),4]]},r.prototype.range=function(){return t.subnetMatch(this,this.SpecialRanges)},r.prototype.toIPv4MappedAddress=function(){return t.IPv6.parse("::ffff:"+this.toString())},r.prototype.prefixLengthFromSubnetMask=function(){var r,t,n,e,i,o,a;for(a={0:8,128:7,192:6,224:5,240:4,248:3,252:2,254:1,255:0},r=0,i=!1,t=n=3;n>=0;t=n+=-1){if(!((e=this.octets[t])in a))return null;if(o=a[e],i&&0!==o)return null;8!==o&&(i=!0),r+=o}return 32-r},r}(),n="(0?\\d+|0x[a-f0-9]+)",e={fourOctet:new RegExp("^"+n+"\\."+n+"\\."+n+"\\."+n+"$","i"),longValue:new RegExp("^"+n+"$","i")},t.IPv4.parser=function(r){var t,n,i,o,a;if(n=function(r){return"0"===r[0]&&"x"!==r[1]?parseInt(r,8):parseInt(r)},t=r.match(e.fourOctet))return function(){var r,e,o,a;for(a=[],r=0,e=(o=t.slice(1,6)).length;r<e;r++)i=o[r],a.push(n(i));return a}();if(t=r.match(e.longValue)){if((a=n(t[1]))>4294967295||a<0)throw new Error("ipaddr: address outside defined range");return function(){var r,t;for(t=[],o=r=0;r<=24;o=r+=8)t.push(a>>o&255);return t}().reverse()}return null},t.IPv6=function(){function r(r,t){var n,e,i,o,a,s;if(16===r.length)for(this.parts=[],n=e=0;e<=14;n=e+=2)this.parts.push(r[n]<<8|r[n+1]);else{if(8!==r.length)throw new Error("ipaddr: ipv6 part count should be 8 or 16");this.parts=r}for(i=0,o=(s=this.parts).length;i<o;i++)if(!(0<=(a=s[i])&&a<=65535))throw new Error("ipaddr: ipv6 part should fit in 16 bits");t&&(this.zoneId=t)}return r.prototype.kind=function(){return"ipv6"},r.prototype.toString=function(){return this.toNormalizedString().replace(/((^|:)(0(:|$))+)/,"::")},r.prototype.toRFC5952String=function(){var r,t,n,e,i;for(e=/((^|:)(0(:|$)){2,})/g,i=this.toNormalizedString(),r=0,t=-1;n=e.exec(i);)n[0].length>t&&(r=n.index,t=n[0].length);return t<0?i:i.substring(0,r)+"::"+i.substring(r+t)},r.prototype.toByteArray=function(){var r,t,n,e,i;for(r=[],t=0,n=(i=this.parts).length;t<n;t++)e=i[t],r.push(e>>8),r.push(255&e);return r},r.prototype.toNormalizedString=function(){var r,t,n;return r=function(){var r,n,e,i;for(i=[],r=0,n=(e=this.parts).length;r<n;r++)t=e[r],i.push(t.toString(16));return i}.call(this).join(":"),n="",this.zoneId&&(n="%"+this.zoneId),r+n},r.prototype.toFixedLengthString=function(){var r,t,n;return r=function(){var r,n,e,i;for(i=[],r=0,n=(e=this.parts).length;r<n;r++)t=e[r],i.push(t.toString(16).padStart(4,"0"));return i}.call(this).join(":"),n="",this.zoneId&&(n="%"+this.zoneId),r+n},r.prototype.match=function(r,t){var n;if(void 0===t&&(r=(n=r)[0],t=n[1]),"ipv6"!==r.kind())throw new Error("ipaddr: cannot match ipv6 address with non-ipv6 one");return a(this.parts,r.parts,16,t)},r.prototype.SpecialRanges={unspecified:[new r([0,0,0,0,0,0,0,0]),128],linkLocal:[new r([65152,0,0,0,0,0,0,0]),10],multicast:[new r([65280,0,0,0,0,0,0,0]),8],loopback:[new r([0,0,0,0,0,0,0,1]),128],uniqueLocal:[new r([64512,0,0,0,0,0,0,0]),7],ipv4Mapped:[new r([0,0,0,0,0,65535,0,0]),96],rfc6145:[new r([0,0,0,0,65535,0,0,0]),96],rfc6052:[new r([100,65435,0,0,0,0,0,0]),96],"6to4":[new r([8194,0,0,0,0,0,0,0]),16],teredo:[new r([8193,0,0,0,0,0,0,0]),32],reserved:[[new r([8193,3512,0,0,0,0,0,0]),32]]},r.prototype.range=function(){return t.subnetMatch(this,this.SpecialRanges)},r.prototype.isIPv4MappedAddress=function(){return"ipv4Mapped"===this.range()},r.prototype.toIPv4Address=function(){var r,n,e;if(!this.isIPv4MappedAddress())throw new Error("ipaddr: trying to convert a generic ipv6 address to ipv4");return e=this.parts.slice(-2),r=e[0],n=e[1],new t.IPv4([r>>8,255&r,n>>8,255&n])},r.prototype.prefixLengthFromSubnetMask=function(){var r,t,n,e,i,o,a;for(a={0:16,32768:15,49152:14,57344:13,61440:12,63488:11,64512:10,65024:9,65280:8,65408:7,65472:6,65504:5,65520:4,65528:3,65532:2,65534:1,65535:0},r=0,i=!1,t=n=7;n>=0;t=n+=-1){if(!((e=this.parts[t])in a))return null;if(o=a[e],i&&0!==o)return null;16!==o&&(i=!0),r+=o}return 128-r},r}(),i="(?:[0-9a-f]+::?)+",o={zoneIndex:new RegExp("%[0-9a-z]{1,}","i"),native:new RegExp("^(::)?("+i+")?([0-9a-f]+)?(::)?(%[0-9a-z]{1,})?$","i"),transitional:new RegExp("^((?:"+i+")|(?:::)(?:"+i+")?)"+n+"\\."+n+"\\."+n+"\\."+n+"(%[0-9a-z]{1,})?$","i")},r=function(r,t){var n,e,i,a,s,p;if(r.indexOf("::")!==r.lastIndexOf("::"))return null;for((p=(r.match(o.zoneIndex)||[])[0])&&(p=p.substring(1),r=r.replace(/%.+$/,"")),n=0,e=-1;(e=r.indexOf(":",e+1))>=0;)n++;if("::"===r.substr(0,2)&&n--,"::"===r.substr(-2,2)&&n--,n>t)return null;for(s=t-n,a=":";s--;)a+="0:";return":"===(r=r.replace("::",a))[0]&&(r=r.slice(1)),":"===r[r.length-1]&&(r=r.slice(0,-1)),t=function(){var t,n,e,o;for(o=[],t=0,n=(e=r.split(":")).length;t<n;t++)i=e[t],o.push(parseInt(i,16));return o}(),{parts:t,zoneId:p}},t.IPv6.parser=function(t){var n,e,i,a,s,p,u;if(o.native.test(t))return r(t,8);if((a=t.match(o.transitional))&&(u=a[6]||"",(n=r(a[1].slice(0,-1)+u,6)).parts)){for(e=0,i=(p=[parseInt(a[2]),parseInt(a[3]),parseInt(a[4]),parseInt(a[5])]).length;e<i;e++)if(!(0<=(s=p[e])&&s<=255))return null;return n.parts.push(p[0]<<8|p[1]),n.parts.push(p[2]<<8|p[3]),{parts:n.parts,zoneId:n.zoneId}}return null},t.IPv4.isIPv4=t.IPv6.isIPv6=function(r){return null!==this.parser(r)},t.IPv4.isValid=function(r){try{return new this(this.parser(r)),!0}catch(r){return r,!1}},t.IPv4.isValidFourPartDecimal=function(r){return!(!t.IPv4.isValid(r)||!r.match(/^(0|[1-9]\d*)(\.(0|[1-9]\d*)){3}$/))},t.IPv6.isValid=function(r){var t;if("string"==typeof r&&-1===r.indexOf(":"))return!1;try{return t=this.parser(r),new this(t.parts,t.zoneId),!0}catch(r){return r,!1}},t.IPv4.parse=function(r){var t;if(null===(t=this.parser(r)))throw new Error("ipaddr: string is not formatted like ip address");return new this(t)},t.IPv6.parse=function(r){var t;if(null===(t=this.parser(r)).parts)throw new Error("ipaddr: string is not formatted like ip address");return new this(t.parts,t.zoneId)},t.IPv4.parseCIDR=function(r){var t,n,e;if((n=r.match(/^(.+)\/(\d+)$/))&&(t=parseInt(n[2]))>=0&&t<=32)return e=[this.parse(n[1]),t],Object.defineProperty(e,"toString",{value:function(){return this.join("/")}}),e;throw new Error("ipaddr: string is not formatted like an IPv4 CIDR range")},t.IPv4.subnetMaskFromPrefixLength=function(r){var t,n,e;if((r=parseInt(r))<0||r>32)throw new Error("ipaddr: invalid IPv4 prefix length");for(e=[0,0,0,0],n=0,t=Math.floor(r/8);n<t;)e[n]=255,n++;return t<4&&(e[t]=Math.pow(2,r%8)-1<<8-r%8),new this(e)},t.IPv4.broadcastAddressFromCIDR=function(r){var t,n,e,i,o;try{for(e=(t=this.parseCIDR(r))[0].toByteArray(),o=this.subnetMaskFromPrefixLength(t[1]).toByteArray(),i=[],n=0;n<4;)i.push(parseInt(e[n],10)|255^parseInt(o[n],10)),n++;return new this(i)}catch(r){throw r,new Error("ipaddr: the address does not have IPv4 CIDR format")}},t.IPv4.networkAddressFromCIDR=function(r){var t,n,e,i,o;try{for(e=(t=this.parseCIDR(r))[0].toByteArray(),o=this.subnetMaskFromPrefixLength(t[1]).toByteArray(),i=[],n=0;n<4;)i.push(parseInt(e[n],10)&parseInt(o[n],10)),n++;return new this(i)}catch(r){throw r,new Error("ipaddr: the address does not have IPv4 CIDR format")}},t.IPv6.parseCIDR=function(r){var t,n,e;if((n=r.match(/^(.+)\/(\d+)$/))&&(t=parseInt(n[2]))>=0&&t<=128)return e=[this.parse(n[1]),t],Object.defineProperty(e,"toString",{value:function(){return this.join("/")}}),e;throw new Error("ipaddr: string is not formatted like an IPv6 CIDR range")},t.isValid=function(r){return t.IPv6.isValid(r)||t.IPv4.isValid(r)},t.parse=function(r){if(t.IPv6.isValid(r))return t.IPv6.parse(r);if(t.IPv4.isValid(r))return t.IPv4.parse(r);throw new Error("ipaddr: the address has neither IPv6 nor IPv4 format")},t.parseCIDR=function(r){try{return t.IPv6.parseCIDR(r)}catch(n){n;try{return t.IPv4.parseCIDR(r)}catch(r){throw r,new Error("ipaddr: the address has neither IPv6 nor IPv4 CIDR format")}}},t.fromByteArray=function(r){var n;if(4===(n=r.length))return new t.IPv4(r);if(16===n)return new t.IPv6(r);throw new Error("ipaddr: the binary input is neither an IPv6 nor IPv4 address")},t.process=function(r){var t;return t=this.parse(r),"ipv6"===t.kind()&&t.isIPv4MappedAddress()?t.toIPv4Address():t}}).call(this); | ||
!function(t){!function(t){"use strict";const r="(0?\\d+|0x[a-f0-9]+)",e={fourOctet:new RegExp(`^${r}\\.${r}\\.${r}\\.${r}$`,"i"),threeOctet:new RegExp(`^${r}\\.${r}\\.${r}$`,"i"),twoOctet:new RegExp(`^${r}\\.${r}$`,"i"),longValue:new RegExp(`^${r}$`,"i")},n=new RegExp("^0[0-7]+$","i"),i=new RegExp("^0x[a-f0-9]+$","i"),o="(?:[0-9a-f]+::?)+",s={zoneIndex:new RegExp("%[0-9a-z]{1,}","i"),native:new RegExp(`^(::)?(${o})?([0-9a-f]+)?(::)?(%[0-9a-z]{1,})?$`,"i"),deprecatedTransitional:new RegExp(`^(?:::)(${r}\\.${r}\\.${r}\\.${r}(%[0-9a-z]{1,})?)$`,"i"),transitional:new RegExp(`^((?:${o})|(?:::)(?:${o})?)${r}\\.${r}\\.${r}\\.${r}(%[0-9a-z]{1,})?$`,"i")};function a(t,r){if(t.indexOf("::")!==t.lastIndexOf("::"))return null;let e,n,i=0,o=-1,a=(t.match(s.zoneIndex)||[])[0];for(a&&(a=a.substring(1),t=t.replace(/%.+$/,""));(o=t.indexOf(":",o+1))>=0;)i++;if("::"===t.substr(0,2)&&i--,"::"===t.substr(-2,2)&&i--,i>r)return null;for(n=r-i,e=":";n--;)e+="0:";return":"===(t=t.replace("::",e))[0]&&(t=t.slice(1)),":"===t[t.length-1]&&(t=t.slice(0,-1)),{parts:r=function(){const r=t.split(":"),e=[];for(let t=0;t<r.length;t++)e.push(parseInt(r[t],16));return e}(),zoneId:a}}function p(t,r,e,n){if(t.length!==r.length)throw new Error("ipaddr: cannot match CIDR for objects with different lengths");let i,o=0;for(;n>0;){if((i=e-n)<0&&(i=0),t[o]>>i!=r[o]>>i)return!1;n-=e,o+=1}return!0}function u(t){if(i.test(t))return parseInt(t,16);if("0"===t[0]&&!isNaN(parseInt(t[1],10))){if(n.test(t))return parseInt(t,8);throw new Error(`ipaddr: cannot parse ${t} as octal`)}return parseInt(t,10)}function d(t,r){for(;t.length<r;)t=`0${t}`;return t}const c={};c.IPv4=function(){function t(t){if(4!==t.length)throw new Error("ipaddr: ipv4 octet count should be 4");let r,e;for(r=0;r<t.length;r++)if(!(0<=(e=t[r])&&e<=255))throw new Error("ipaddr: ipv4 octet should fit in 8 bits");this.octets=t}return t.prototype.SpecialRanges={unspecified:[[new t([0,0,0,0]),8]],broadcast:[[new t([255,255,255,255]),32]],multicast:[[new t([224,0,0,0]),4]],linkLocal:[[new t([169,254,0,0]),16]],loopback:[[new t([127,0,0,0]),8]],carrierGradeNat:[[new t([100,64,0,0]),10]],private:[[new t([10,0,0,0]),8],[new t([172,16,0,0]),12],[new t([192,168,0,0]),16]],reserved:[[new t([192,0,0,0]),24],[new t([192,0,2,0]),24],[new t([192,88,99,0]),24],[new t([198,51,100,0]),24],[new t([203,0,113,0]),24],[new t([240,0,0,0]),4]]},t.prototype.kind=function(){return"ipv4"},t.prototype.match=function(t,r){let e;if(void 0===r&&(t=(e=t)[0],r=e[1]),"ipv4"!==t.kind())throw new Error("ipaddr: cannot match ipv4 address with non-ipv4 one");return p(this.octets,t.octets,8,r)},t.prototype.prefixLengthFromSubnetMask=function(){let t=0,r=!1;const e={0:8,128:7,192:6,224:5,240:4,248:3,252:2,254:1,255:0};let n,i,o;for(n=3;n>=0;n-=1){if(!((i=this.octets[n])in e))return null;if(o=e[i],r&&0!==o)return null;8!==o&&(r=!0),t+=o}return 32-t},t.prototype.range=function(){return c.subnetMatch(this,this.SpecialRanges)},t.prototype.toByteArray=function(){return this.octets.slice(0)},t.prototype.toIPv4MappedAddress=function(){return c.IPv6.parse(`::ffff:${this.toString()}`)},t.prototype.toNormalizedString=function(){return this.toString()},t.prototype.toString=function(){return this.octets.join(".")},t}(),c.IPv4.broadcastAddressFromCIDR=function(t){try{const r=this.parseCIDR(t),e=r[0].toByteArray(),n=this.subnetMaskFromPrefixLength(r[1]).toByteArray(),i=[];let o=0;for(;o<4;)i.push(parseInt(e[o],10)|255^parseInt(n[o],10)),o++;return new this(i)}catch(t){throw new Error("ipaddr: the address does not have IPv4 CIDR format")}},c.IPv4.isIPv4=function(t){return null!==this.parser(t)},c.IPv4.isValid=function(t){try{return new this(this.parser(t)),!0}catch(t){return!1}},c.IPv4.isValidFourPartDecimal=function(t){return!(!c.IPv4.isValid(t)||!t.match(/^(0|[1-9]\d*)(\.(0|[1-9]\d*)){3}$/))},c.IPv4.networkAddressFromCIDR=function(t){let r,e,n,i,o;try{for(n=(r=this.parseCIDR(t))[0].toByteArray(),o=this.subnetMaskFromPrefixLength(r[1]).toByteArray(),i=[],e=0;e<4;)i.push(parseInt(n[e],10)&parseInt(o[e],10)),e++;return new this(i)}catch(t){throw new Error("ipaddr: the address does not have IPv4 CIDR format")}},c.IPv4.parse=function(t){const r=this.parser(t);if(null===r)throw new Error("ipaddr: string is not formatted like an IPv4 Address");return new this(r)},c.IPv4.parseCIDR=function(t){let r;if(r=t.match(/^(.+)\/(\d+)$/)){const t=parseInt(r[2]);if(t>=0&&t<=32){const e=[this.parse(r[1]),t];return Object.defineProperty(e,"toString",{value:function(){return this.join("/")}}),e}}throw new Error("ipaddr: string is not formatted like an IPv4 CIDR range")},c.IPv4.parser=function(t){let r,n,i;if(r=t.match(e.fourOctet))return function(){const t=r.slice(1,6),e=[];for(let r=0;r<t.length;r++)n=t[r],e.push(u(n));return e}();if(r=t.match(e.longValue)){if((i=u(r[1]))>4294967295||i<0)throw new Error("ipaddr: address outside defined range");return function(){const t=[];let r;for(r=0;r<=24;r+=8)t.push(i>>r&255);return t}().reverse()}return(r=t.match(e.twoOctet))?function(){const t=r.slice(1,4),e=[];if((i=u(t[1]))>16777215||i<0)throw new Error("ipaddr: address outside defined range");return e.push(u(t[0])),e.push(i>>16&255),e.push(i>>8&255),e.push(255&i),e}():(r=t.match(e.threeOctet))?function(){const t=r.slice(1,5),e=[];if((i=u(t[2]))>65535||i<0)throw new Error("ipaddr: address outside defined range");return e.push(u(t[0])),e.push(u(t[1])),e.push(i>>8&255),e.push(255&i),e}():null},c.IPv4.subnetMaskFromPrefixLength=function(t){if((t=parseInt(t))<0||t>32)throw new Error("ipaddr: invalid IPv4 prefix length");const r=[0,0,0,0];let e=0;const n=Math.floor(t/8);for(;e<n;)r[e]=255,e++;return n<4&&(r[n]=Math.pow(2,t%8)-1<<8-t%8),new this(r)},c.IPv6=function(){function t(t,r){let e,n;if(16===t.length)for(this.parts=[],e=0;e<=14;e+=2)this.parts.push(t[e]<<8|t[e+1]);else{if(8!==t.length)throw new Error("ipaddr: ipv6 part count should be 8 or 16");this.parts=t}for(e=0;e<this.parts.length;e++)if(!(0<=(n=this.parts[e])&&n<=65535))throw new Error("ipaddr: ipv6 part should fit in 16 bits");r&&(this.zoneId=r)}return t.prototype.SpecialRanges={unspecified:[new t([0,0,0,0,0,0,0,0]),128],linkLocal:[new t([65152,0,0,0,0,0,0,0]),10],multicast:[new t([65280,0,0,0,0,0,0,0]),8],loopback:[new t([0,0,0,0,0,0,0,1]),128],uniqueLocal:[new t([64512,0,0,0,0,0,0,0]),7],ipv4Mapped:[new t([0,0,0,0,0,65535,0,0]),96],rfc6145:[new t([0,0,0,0,65535,0,0,0]),96],rfc6052:[new t([100,65435,0,0,0,0,0,0]),96],"6to4":[new t([8194,0,0,0,0,0,0,0]),16],teredo:[new t([8193,0,0,0,0,0,0,0]),32],reserved:[[new t([8193,3512,0,0,0,0,0,0]),32]]},t.prototype.isIPv4MappedAddress=function(){return"ipv4Mapped"===this.range()},t.prototype.kind=function(){return"ipv6"},t.prototype.match=function(t,r){let e;if(void 0===r&&(t=(e=t)[0],r=e[1]),"ipv6"!==t.kind())throw new Error("ipaddr: cannot match ipv6 address with non-ipv6 one");return p(this.parts,t.parts,16,r)},t.prototype.prefixLengthFromSubnetMask=function(){let t=0,r=!1;const e={0:16,32768:15,49152:14,57344:13,61440:12,63488:11,64512:10,65024:9,65280:8,65408:7,65472:6,65504:5,65520:4,65528:3,65532:2,65534:1,65535:0};let n,i;for(let o=7;o>=0;o-=1){if(!((n=this.parts[o])in e))return null;if(i=e[n],r&&0!==i)return null;16!==i&&(r=!0),t+=i}return 128-t},t.prototype.range=function(){return c.subnetMatch(this,this.SpecialRanges)},t.prototype.toByteArray=function(){let t;const r=[],e=this.parts;for(let n=0;n<e.length;n++)t=e[n],r.push(t>>8),r.push(255&t);return r},t.prototype.toFixedLengthString=function(){const t=function(){const t=[];for(let r=0;r<this.parts.length;r++)t.push(d(this.parts[r].toString(16),4));return t}.call(this).join(":");let r="";return this.zoneId&&(r=`%${this.zoneId}`),t+r},t.prototype.toIPv4Address=function(){if(!this.isIPv4MappedAddress())throw new Error("ipaddr: trying to convert a generic ipv6 address to ipv4");const t=this.parts.slice(-2),r=t[0],e=t[1];return new c.IPv4([r>>8,255&r,e>>8,255&e])},t.prototype.toNormalizedString=function(){const t=function(){const t=[];for(let r=0;r<this.parts.length;r++)t.push(this.parts[r].toString(16));return t}.call(this).join(":");let r="";return this.zoneId&&(r=`%${this.zoneId}`),t+r},t.prototype.toRFC5952String=function(){const t=/((^|:)(0(:|$)){2,})/g,r=this.toNormalizedString();let e,n=0,i=-1;for(;e=t.exec(r);)e[0].length>i&&(n=e.index,i=e[0].length);return i<0?r:`${r.substring(0,n)}::${r.substring(n+i)}`},t.prototype.toString=function(){return this.toNormalizedString().replace(/((^|:)(0(:|$))+)/,"::")},t}(),c.IPv6.isIPv6=function(t){return null!==this.parser(t)},c.IPv6.isValid=function(t){if("string"==typeof t&&-1===t.indexOf(":"))return!1;try{const r=this.parser(t);return new this(r.parts,r.zoneId),!0}catch(t){return!1}},c.IPv6.parse=function(t){const r=this.parser(t);if(null===r.parts)throw new Error("ipaddr: string is not formatted like an IPv6 Address");return new this(r.parts,r.zoneId)},c.IPv6.parseCIDR=function(t){let r,e,n;if((e=t.match(/^(.+)\/(\d+)$/))&&(r=parseInt(e[2]))>=0&&r<=128)return n=[this.parse(e[1]),r],Object.defineProperty(n,"toString",{value:function(){return this.join("/")}}),n;throw new Error("ipaddr: string is not formatted like an IPv6 CIDR range")},c.IPv6.parser=function(t){let r,e,n,i,o,p;if(n=t.match(s.deprecatedTransitional))return this.parser(`::ffff:${n[1]}`);if(s.native.test(t))return a(t,8);if((n=t.match(s.transitional))&&(p=n[6]||"",(r=a(n[1].slice(0,-1)+p,6)).parts)){for(o=[parseInt(n[2]),parseInt(n[3]),parseInt(n[4]),parseInt(n[5])],e=0;e<o.length;e++)if(!(0<=(i=o[e])&&i<=255))return null;return r.parts.push(o[0]<<8|o[1]),r.parts.push(o[2]<<8|o[3]),{parts:r.parts,zoneId:r.zoneId}}return null},c.fromByteArray=function(t){const r=t.length;if(4===r)return new c.IPv4(t);if(16===r)return new c.IPv6(t);throw new Error("ipaddr: the binary input is neither an IPv6 nor IPv4 address")},c.isValid=function(t){return c.IPv6.isValid(t)||c.IPv4.isValid(t)},c.parse=function(t){if(c.IPv6.isValid(t))return c.IPv6.parse(t);if(c.IPv4.isValid(t))return c.IPv4.parse(t);throw new Error("ipaddr: the address has neither IPv6 nor IPv4 format")},c.parseCIDR=function(t){try{return c.IPv6.parseCIDR(t)}catch(r){try{return c.IPv4.parseCIDR(t)}catch(t){throw new Error("ipaddr: the address has neither IPv6 nor IPv4 CIDR format")}}},c.process=function(t){const r=this.parse(t);return"ipv6"===r.kind()&&r.isIPv4MappedAddress()?r.toIPv4Address():r},c.subnetMatch=function(t,r,e){let n,i,o,s;for(i in void 0!==e&&null!==e||(e="unicast"),r)if(Object.prototype.hasOwnProperty.call(r,i))for(!(o=r[i])[0]||o[0]instanceof Array||(o=[o]),n=0;n<o.length;n++)if(s=o[n],t.kind()===s[0].kind()&&t.match.apply(t,s))return i;return e},"undefined"!=typeof module&&module.exports?module.exports=c:t.ipaddr=c}(this)}("undefined"==typeof window?window={}:window); |
1435
lib/ipaddr.js
@@ -1,673 +0,930 @@ | ||
(function() { | ||
var expandIPv6, ipaddr, ipv4Part, ipv4Regexes, ipv6Part, ipv6Regexes, matchCIDR, root, zoneIndex; | ||
(function (root) { | ||
'use strict'; | ||
// A list of regular expressions that match arbitrary IPv4 addresses, | ||
// for which a number of weird notations exist. | ||
// Note that an address like 0010.0xa5.1.1 is considered legal. | ||
const ipv4Part = '(0?\\d+|0x[a-f0-9]+)'; | ||
const ipv4Regexes = { | ||
fourOctet: new RegExp(`^${ipv4Part}\\.${ipv4Part}\\.${ipv4Part}\\.${ipv4Part}$`, 'i'), | ||
threeOctet: new RegExp(`^${ipv4Part}\\.${ipv4Part}\\.${ipv4Part}$`, 'i'), | ||
twoOctet: new RegExp(`^${ipv4Part}\\.${ipv4Part}$`, 'i'), | ||
longValue: new RegExp(`^${ipv4Part}$`, 'i') | ||
}; | ||
ipaddr = {}; | ||
// Regular Expression for checking Octal numbers | ||
const octalRegex = new RegExp(`^0[0-7]+$`, 'i'); | ||
const hexRegex = new RegExp(`^0x[a-f0-9]+$`, 'i'); | ||
root = this; | ||
const zoneIndex = '%[0-9a-z]{1,}'; | ||
if ((typeof module !== "undefined" && module !== null) && module.exports) { | ||
module.exports = ipaddr; | ||
} else { | ||
root['ipaddr'] = ipaddr; | ||
} | ||
// IPv6-matching regular expressions. | ||
// For IPv6, the task is simpler: it is enough to match the colon-delimited | ||
// hexadecimal IPv6 and a transitional variant with dotted-decimal IPv4 at | ||
// the end. | ||
const ipv6Part = '(?:[0-9a-f]+::?)+'; | ||
const ipv6Regexes = { | ||
zoneIndex: new RegExp(zoneIndex, 'i'), | ||
'native': new RegExp(`^(::)?(${ipv6Part})?([0-9a-f]+)?(::)?(${zoneIndex})?$`, 'i'), | ||
deprecatedTransitional: new RegExp(`^(?:::)(${ipv4Part}\\.${ipv4Part}\\.${ipv4Part}\\.${ipv4Part}(${zoneIndex})?)$`, 'i'), | ||
transitional: new RegExp(`^((?:${ipv6Part})|(?:::)(?:${ipv6Part})?)${ipv4Part}\\.${ipv4Part}\\.${ipv4Part}\\.${ipv4Part}(${zoneIndex})?$`, 'i') | ||
}; | ||
matchCIDR = function(first, second, partSize, cidrBits) { | ||
var part, shift; | ||
if (first.length !== second.length) { | ||
throw new Error("ipaddr: cannot match CIDR for objects with different lengths"); | ||
} | ||
part = 0; | ||
while (cidrBits > 0) { | ||
shift = partSize - cidrBits; | ||
if (shift < 0) { | ||
shift = 0; | ||
} | ||
if (first[part] >> shift !== second[part] >> shift) { | ||
return false; | ||
} | ||
cidrBits -= partSize; | ||
part += 1; | ||
} | ||
return true; | ||
}; | ||
// Expand :: in an IPv6 address or address part consisting of `parts` groups. | ||
function expandIPv6 (string, parts) { | ||
// More than one '::' means invalid adddress | ||
if (string.indexOf('::') !== string.lastIndexOf('::')) { | ||
return null; | ||
} | ||
ipaddr.subnetMatch = function(address, rangeList, defaultName) { | ||
var k, len, rangeName, rangeSubnets, subnet; | ||
if (defaultName == null) { | ||
defaultName = 'unicast'; | ||
} | ||
for (rangeName in rangeList) { | ||
rangeSubnets = rangeList[rangeName]; | ||
if (rangeSubnets[0] && !(rangeSubnets[0] instanceof Array)) { | ||
rangeSubnets = [rangeSubnets]; | ||
} | ||
for (k = 0, len = rangeSubnets.length; k < len; k++) { | ||
subnet = rangeSubnets[k]; | ||
if (address.kind() === subnet[0].kind()) { | ||
if (address.match.apply(address, subnet)) { | ||
return rangeName; | ||
} | ||
let colonCount = 0; | ||
let lastColon = -1; | ||
let zoneId = (string.match(ipv6Regexes.zoneIndex) || [])[0]; | ||
let replacement, replacementCount; | ||
// Remove zone index and save it for later | ||
if (zoneId) { | ||
zoneId = zoneId.substring(1); | ||
string = string.replace(/%.+$/, ''); | ||
} | ||
} | ||
} | ||
return defaultName; | ||
}; | ||
ipaddr.IPv4 = (function() { | ||
function IPv4(octets) { | ||
var k, len, octet; | ||
if (octets.length !== 4) { | ||
throw new Error("ipaddr: ipv4 octet count should be 4"); | ||
} | ||
for (k = 0, len = octets.length; k < len; k++) { | ||
octet = octets[k]; | ||
if (!((0 <= octet && octet <= 255))) { | ||
throw new Error("ipaddr: ipv4 octet should fit in 8 bits"); | ||
// How many parts do we already have? | ||
while ((lastColon = string.indexOf(':', lastColon + 1)) >= 0) { | ||
colonCount++; | ||
} | ||
} | ||
this.octets = octets; | ||
} | ||
IPv4.prototype.kind = function() { | ||
return 'ipv4'; | ||
}; | ||
// 0::0 is two parts more than :: | ||
if (string.substr(0, 2) === '::') { | ||
colonCount--; | ||
} | ||
IPv4.prototype.toString = function() { | ||
return this.octets.join("."); | ||
}; | ||
if (string.substr(-2, 2) === '::') { | ||
colonCount--; | ||
} | ||
IPv4.prototype.toNormalizedString = function() { | ||
return this.toString(); | ||
}; | ||
// The following loop would hang if colonCount > parts | ||
if (colonCount > parts) { | ||
return null; | ||
} | ||
IPv4.prototype.toByteArray = function() { | ||
return this.octets.slice(0); | ||
}; | ||
// replacement = ':' + '0:' * (parts - colonCount) | ||
replacementCount = parts - colonCount; | ||
replacement = ':'; | ||
while (replacementCount--) { | ||
replacement += '0:'; | ||
} | ||
IPv4.prototype.match = function(other, cidrRange) { | ||
var ref; | ||
if (cidrRange === void 0) { | ||
ref = other, other = ref[0], cidrRange = ref[1]; | ||
} | ||
if (other.kind() !== 'ipv4') { | ||
throw new Error("ipaddr: cannot match ipv4 address with non-ipv4 one"); | ||
} | ||
return matchCIDR(this.octets, other.octets, 8, cidrRange); | ||
}; | ||
// Insert the missing zeroes | ||
string = string.replace('::', replacement); | ||
IPv4.prototype.SpecialRanges = { | ||
unspecified: [[new IPv4([0, 0, 0, 0]), 8]], | ||
broadcast: [[new IPv4([255, 255, 255, 255]), 32]], | ||
multicast: [[new IPv4([224, 0, 0, 0]), 4]], | ||
linkLocal: [[new IPv4([169, 254, 0, 0]), 16]], | ||
loopback: [[new IPv4([127, 0, 0, 0]), 8]], | ||
carrierGradeNat: [[new IPv4([100, 64, 0, 0]), 10]], | ||
"private": [[new IPv4([10, 0, 0, 0]), 8], [new IPv4([172, 16, 0, 0]), 12], [new IPv4([192, 168, 0, 0]), 16]], | ||
reserved: [[new IPv4([192, 0, 0, 0]), 24], [new IPv4([192, 0, 2, 0]), 24], [new IPv4([192, 88, 99, 0]), 24], [new IPv4([198, 51, 100, 0]), 24], [new IPv4([203, 0, 113, 0]), 24], [new IPv4([240, 0, 0, 0]), 4]] | ||
}; | ||
// Trim any garbage which may be hanging around if :: was at the edge in | ||
// the source strin | ||
if (string[0] === ':') { | ||
string = string.slice(1); | ||
} | ||
IPv4.prototype.range = function() { | ||
return ipaddr.subnetMatch(this, this.SpecialRanges); | ||
}; | ||
if (string[string.length - 1] === ':') { | ||
string = string.slice(0, -1); | ||
} | ||
IPv4.prototype.toIPv4MappedAddress = function() { | ||
return ipaddr.IPv6.parse("::ffff:" + (this.toString())); | ||
}; | ||
parts = (function () { | ||
const ref = string.split(':'); | ||
const results = []; | ||
IPv4.prototype.prefixLengthFromSubnetMask = function() { | ||
var cidr, i, k, octet, stop, zeros, zerotable; | ||
zerotable = { | ||
0: 8, | ||
128: 7, | ||
192: 6, | ||
224: 5, | ||
240: 4, | ||
248: 3, | ||
252: 2, | ||
254: 1, | ||
255: 0 | ||
}; | ||
cidr = 0; | ||
stop = false; | ||
for (i = k = 3; k >= 0; i = k += -1) { | ||
octet = this.octets[i]; | ||
if (octet in zerotable) { | ||
zeros = zerotable[octet]; | ||
if (stop && zeros !== 0) { | ||
return null; | ||
} | ||
if (zeros !== 8) { | ||
stop = true; | ||
} | ||
cidr += zeros; | ||
} else { | ||
return null; | ||
for (let i = 0; i < ref.length; i++) { | ||
results.push(parseInt(ref[i], 16)); | ||
} | ||
return results; | ||
})(); | ||
return { | ||
parts: parts, | ||
zoneId: zoneId | ||
}; | ||
} | ||
// A generic CIDR (Classless Inter-Domain Routing) RFC1518 range matcher. | ||
function matchCIDR (first, second, partSize, cidrBits) { | ||
if (first.length !== second.length) { | ||
throw new Error('ipaddr: cannot match CIDR for objects with different lengths'); | ||
} | ||
} | ||
return 32 - cidr; | ||
}; | ||
return IPv4; | ||
let part = 0; | ||
let shift; | ||
})(); | ||
while (cidrBits > 0) { | ||
shift = partSize - cidrBits; | ||
if (shift < 0) { | ||
shift = 0; | ||
} | ||
ipv4Part = "(0?\\d+|0x[a-f0-9]+)"; | ||
if (first[part] >> shift !== second[part] >> shift) { | ||
return false; | ||
} | ||
ipv4Regexes = { | ||
fourOctet: new RegExp("^" + ipv4Part + "\\." + ipv4Part + "\\." + ipv4Part + "\\." + ipv4Part + "$", 'i'), | ||
longValue: new RegExp("^" + ipv4Part + "$", 'i') | ||
}; | ||
cidrBits -= partSize; | ||
part += 1; | ||
} | ||
ipaddr.IPv4.parser = function(string) { | ||
var match, parseIntAuto, part, shift, value; | ||
parseIntAuto = function(string) { | ||
if (string[0] === "0" && string[1] !== "x") { | ||
return parseInt(string, 8); | ||
} else { | ||
return parseInt(string); | ||
} | ||
}; | ||
if (match = string.match(ipv4Regexes.fourOctet)) { | ||
return (function() { | ||
var k, len, ref, results; | ||
ref = match.slice(1, 6); | ||
results = []; | ||
for (k = 0, len = ref.length; k < len; k++) { | ||
part = ref[k]; | ||
results.push(parseIntAuto(part)); | ||
return true; | ||
} | ||
function parseIntAuto (string) { | ||
// Hexadedimal base 16 (0x#) | ||
if (hexRegex.test(string)) { | ||
return parseInt(string, 16); | ||
} | ||
return results; | ||
})(); | ||
} else if (match = string.match(ipv4Regexes.longValue)) { | ||
value = parseIntAuto(match[1]); | ||
if (value > 0xffffffff || value < 0) { | ||
throw new Error("ipaddr: address outside defined range"); | ||
} | ||
return ((function() { | ||
var k, results; | ||
results = []; | ||
for (shift = k = 0; k <= 24; shift = k += 8) { | ||
results.push((value >> shift) & 0xff); | ||
// While octal representation is discouraged by ECMAScript 3 | ||
// and forbidden by ECMAScript 5, we silently allow it to | ||
// work only if the rest of the string has numbers less than 8. | ||
if (string[0] === '0' && !isNaN(parseInt(string[1], 10))) { | ||
if (octalRegex.test(string)) { | ||
return parseInt(string, 8); | ||
} | ||
return results; | ||
})()).reverse(); | ||
} else { | ||
return null; | ||
throw new Error(`ipaddr: cannot parse ${string} as octal`); | ||
} | ||
// Always include the base 10 radix! | ||
return parseInt(string, 10); | ||
} | ||
}; | ||
ipaddr.IPv6 = (function() { | ||
function IPv6(parts, zoneId) { | ||
var i, k, l, len, part, ref; | ||
if (parts.length === 16) { | ||
this.parts = []; | ||
for (i = k = 0; k <= 14; i = k += 2) { | ||
this.parts.push((parts[i] << 8) | parts[i + 1]); | ||
function padPart (part, length) { | ||
while (part.length < length) { | ||
part = `0${part}`; | ||
} | ||
} else if (parts.length === 8) { | ||
this.parts = parts; | ||
} else { | ||
throw new Error("ipaddr: ipv6 part count should be 8 or 16"); | ||
} | ||
ref = this.parts; | ||
for (l = 0, len = ref.length; l < len; l++) { | ||
part = ref[l]; | ||
if (!((0 <= part && part <= 0xffff))) { | ||
throw new Error("ipaddr: ipv6 part should fit in 16 bits"); | ||
} | ||
} | ||
if (zoneId) { | ||
this.zoneId = zoneId; | ||
} | ||
return part; | ||
} | ||
IPv6.prototype.kind = function() { | ||
return 'ipv6'; | ||
const ipaddr = {}; | ||
// An IPv4 address (RFC791). | ||
ipaddr.IPv4 = (function () { | ||
// Constructs a new IPv4 address from an array of four octets | ||
// in network order (MSB first) | ||
// Verifies the input. | ||
function IPv4 (octets) { | ||
if (octets.length !== 4) { | ||
throw new Error('ipaddr: ipv4 octet count should be 4'); | ||
} | ||
let i, octet; | ||
for (i = 0; i < octets.length; i++) { | ||
octet = octets[i]; | ||
if (!((0 <= octet && octet <= 255))) { | ||
throw new Error('ipaddr: ipv4 octet should fit in 8 bits'); | ||
} | ||
} | ||
this.octets = octets; | ||
} | ||
// Special IPv4 address ranges. | ||
// See also https://en.wikipedia.org/wiki/Reserved_IP_addresses | ||
IPv4.prototype.SpecialRanges = { | ||
unspecified: [[new IPv4([0, 0, 0, 0]), 8]], | ||
broadcast: [[new IPv4([255, 255, 255, 255]), 32]], | ||
// RFC3171 | ||
multicast: [[new IPv4([224, 0, 0, 0]), 4]], | ||
// RFC3927 | ||
linkLocal: [[new IPv4([169, 254, 0, 0]), 16]], | ||
// RFC5735 | ||
loopback: [[new IPv4([127, 0, 0, 0]), 8]], | ||
// RFC6598 | ||
carrierGradeNat: [[new IPv4([100, 64, 0, 0]), 10]], | ||
// RFC1918 | ||
'private': [ | ||
[new IPv4([10, 0, 0, 0]), 8], | ||
[new IPv4([172, 16, 0, 0]), 12], | ||
[new IPv4([192, 168, 0, 0]), 16] | ||
], | ||
// Reserved and testing-only ranges; RFCs 5735, 5737, 2544, 1700 | ||
reserved: [ | ||
[new IPv4([192, 0, 0, 0]), 24], | ||
[new IPv4([192, 0, 2, 0]), 24], | ||
[new IPv4([192, 88, 99, 0]), 24], | ||
[new IPv4([198, 51, 100, 0]), 24], | ||
[new IPv4([203, 0, 113, 0]), 24], | ||
[new IPv4([240, 0, 0, 0]), 4] | ||
] | ||
}; | ||
// The 'kind' method exists on both IPv4 and IPv6 classes. | ||
IPv4.prototype.kind = function () { | ||
return 'ipv4'; | ||
}; | ||
// Checks if this address matches other one within given CIDR range. | ||
IPv4.prototype.match = function (other, cidrRange) { | ||
let ref; | ||
if (cidrRange === undefined) { | ||
ref = other; | ||
other = ref[0]; | ||
cidrRange = ref[1]; | ||
} | ||
if (other.kind() !== 'ipv4') { | ||
throw new Error('ipaddr: cannot match ipv4 address with non-ipv4 one'); | ||
} | ||
return matchCIDR(this.octets, other.octets, 8, cidrRange); | ||
}; | ||
// returns a number of leading ones in IPv4 address, making sure that | ||
// the rest is a solid sequence of 0's (valid netmask) | ||
// returns either the CIDR length or null if mask is not valid | ||
IPv4.prototype.prefixLengthFromSubnetMask = function () { | ||
let cidr = 0; | ||
// non-zero encountered stop scanning for zeroes | ||
let stop = false; | ||
// number of zeroes in octet | ||
const zerotable = { | ||
0: 8, | ||
128: 7, | ||
192: 6, | ||
224: 5, | ||
240: 4, | ||
248: 3, | ||
252: 2, | ||
254: 1, | ||
255: 0 | ||
}; | ||
let i, octet, zeros; | ||
for (i = 3; i >= 0; i -= 1) { | ||
octet = this.octets[i]; | ||
if (octet in zerotable) { | ||
zeros = zerotable[octet]; | ||
if (stop && zeros !== 0) { | ||
return null; | ||
} | ||
if (zeros !== 8) { | ||
stop = true; | ||
} | ||
cidr += zeros; | ||
} else { | ||
return null; | ||
} | ||
} | ||
return 32 - cidr; | ||
}; | ||
// Checks if the address corresponds to one of the special ranges. | ||
IPv4.prototype.range = function () { | ||
return ipaddr.subnetMatch(this, this.SpecialRanges); | ||
}; | ||
// Returns an array of byte-sized values in network order (MSB first) | ||
IPv4.prototype.toByteArray = function () { | ||
return this.octets.slice(0); | ||
}; | ||
// Converts this IPv4 address to an IPv4-mapped IPv6 address. | ||
IPv4.prototype.toIPv4MappedAddress = function () { | ||
return ipaddr.IPv6.parse(`::ffff:${this.toString()}`); | ||
}; | ||
// Symmetrical method strictly for aligning with the IPv6 methods. | ||
IPv4.prototype.toNormalizedString = function () { | ||
return this.toString(); | ||
}; | ||
// Returns the address in convenient, decimal-dotted format. | ||
IPv4.prototype.toString = function () { | ||
return this.octets.join('.'); | ||
}; | ||
return IPv4; | ||
})(); | ||
// A utility function to return broadcast address given the IPv4 interface and prefix length in CIDR notation | ||
ipaddr.IPv4.broadcastAddressFromCIDR = function (string) { | ||
try { | ||
const cidr = this.parseCIDR(string); | ||
const ipInterfaceOctets = cidr[0].toByteArray(); | ||
const subnetMaskOctets = this.subnetMaskFromPrefixLength(cidr[1]).toByteArray(); | ||
const octets = []; | ||
let i = 0; | ||
while (i < 4) { | ||
// Broadcast address is bitwise OR between ip interface and inverted mask | ||
octets.push(parseInt(ipInterfaceOctets[i], 10) | parseInt(subnetMaskOctets[i], 10) ^ 255); | ||
i++; | ||
} | ||
return new this(octets); | ||
} catch (e) { | ||
throw new Error('ipaddr: the address does not have IPv4 CIDR format'); | ||
} | ||
}; | ||
IPv6.prototype.toString = function() { | ||
return this.toNormalizedString().replace(/((^|:)(0(:|$))+)/, '::'); | ||
// Checks if a given string is formatted like IPv4 address. | ||
ipaddr.IPv4.isIPv4 = function (string) { | ||
return this.parser(string) !== null; | ||
}; | ||
IPv6.prototype.toRFC5952String = function() { | ||
var bestMatchIndex, bestMatchLength, match, regex, string; | ||
regex = /((^|:)(0(:|$)){2,})/g; | ||
string = this.toNormalizedString(); | ||
bestMatchIndex = 0; | ||
bestMatchLength = -1; | ||
while ((match = regex.exec(string))) { | ||
if (match[0].length > bestMatchLength) { | ||
bestMatchIndex = match.index; | ||
bestMatchLength = match[0].length; | ||
// Checks if a given string is a valid IPv4 address. | ||
ipaddr.IPv4.isValid = function (string) { | ||
try { | ||
new this(this.parser(string)); | ||
return true; | ||
} catch (e) { | ||
return false; | ||
} | ||
} | ||
if (bestMatchLength < 0) { | ||
return string; | ||
} | ||
return string.substring(0, bestMatchIndex) + '::' + string.substring(bestMatchIndex + bestMatchLength); | ||
}; | ||
IPv6.prototype.toByteArray = function() { | ||
var bytes, k, len, part, ref; | ||
bytes = []; | ||
ref = this.parts; | ||
for (k = 0, len = ref.length; k < len; k++) { | ||
part = ref[k]; | ||
bytes.push(part >> 8); | ||
bytes.push(part & 0xff); | ||
} | ||
return bytes; | ||
// Checks if a given string is a full four-part IPv4 Address. | ||
ipaddr.IPv4.isValidFourPartDecimal = function (string) { | ||
if (ipaddr.IPv4.isValid(string) && string.match(/^(0|[1-9]\d*)(\.(0|[1-9]\d*)){3}$/)) { | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
}; | ||
IPv6.prototype.toNormalizedString = function() { | ||
var addr, part, suffix; | ||
addr = ((function() { | ||
var k, len, ref, results; | ||
ref = this.parts; | ||
results = []; | ||
for (k = 0, len = ref.length; k < len; k++) { | ||
part = ref[k]; | ||
results.push(part.toString(16)); | ||
// A utility function to return network address given the IPv4 interface and prefix length in CIDR notation | ||
ipaddr.IPv4.networkAddressFromCIDR = function (string) { | ||
let cidr, i, ipInterfaceOctets, octets, subnetMaskOctets; | ||
try { | ||
cidr = this.parseCIDR(string); | ||
ipInterfaceOctets = cidr[0].toByteArray(); | ||
subnetMaskOctets = this.subnetMaskFromPrefixLength(cidr[1]).toByteArray(); | ||
octets = []; | ||
i = 0; | ||
while (i < 4) { | ||
// Network address is bitwise AND between ip interface and mask | ||
octets.push(parseInt(ipInterfaceOctets[i], 10) & parseInt(subnetMaskOctets[i], 10)); | ||
i++; | ||
} | ||
return new this(octets); | ||
} catch (e) { | ||
throw new Error('ipaddr: the address does not have IPv4 CIDR format'); | ||
} | ||
return results; | ||
}).call(this)).join(":"); | ||
suffix = ''; | ||
if (this.zoneId) { | ||
suffix = '%' + this.zoneId; | ||
} | ||
return addr + suffix; | ||
}; | ||
IPv6.prototype.toFixedLengthString = function() { | ||
var addr, part, suffix; | ||
addr = ((function() { | ||
var k, len, ref, results; | ||
ref = this.parts; | ||
results = []; | ||
for (k = 0, len = ref.length; k < len; k++) { | ||
part = ref[k]; | ||
results.push(part.toString(16).padStart(4, '0')); | ||
// Tries to parse and validate a string with IPv4 address. | ||
// Throws an error if it fails. | ||
ipaddr.IPv4.parse = function (string) { | ||
const parts = this.parser(string); | ||
if (parts === null) { | ||
throw new Error('ipaddr: string is not formatted like an IPv4 Address'); | ||
} | ||
return results; | ||
}).call(this)).join(":"); | ||
suffix = ''; | ||
if (this.zoneId) { | ||
suffix = '%' + this.zoneId; | ||
} | ||
return addr + suffix; | ||
}; | ||
IPv6.prototype.match = function(other, cidrRange) { | ||
var ref; | ||
if (cidrRange === void 0) { | ||
ref = other, other = ref[0], cidrRange = ref[1]; | ||
} | ||
if (other.kind() !== 'ipv6') { | ||
throw new Error("ipaddr: cannot match ipv6 address with non-ipv6 one"); | ||
} | ||
return matchCIDR(this.parts, other.parts, 16, cidrRange); | ||
return new this(parts); | ||
}; | ||
IPv6.prototype.SpecialRanges = { | ||
unspecified: [new IPv6([0, 0, 0, 0, 0, 0, 0, 0]), 128], | ||
linkLocal: [new IPv6([0xfe80, 0, 0, 0, 0, 0, 0, 0]), 10], | ||
multicast: [new IPv6([0xff00, 0, 0, 0, 0, 0, 0, 0]), 8], | ||
loopback: [new IPv6([0, 0, 0, 0, 0, 0, 0, 1]), 128], | ||
uniqueLocal: [new IPv6([0xfc00, 0, 0, 0, 0, 0, 0, 0]), 7], | ||
ipv4Mapped: [new IPv6([0, 0, 0, 0, 0, 0xffff, 0, 0]), 96], | ||
rfc6145: [new IPv6([0, 0, 0, 0, 0xffff, 0, 0, 0]), 96], | ||
rfc6052: [new IPv6([0x64, 0xff9b, 0, 0, 0, 0, 0, 0]), 96], | ||
'6to4': [new IPv6([0x2002, 0, 0, 0, 0, 0, 0, 0]), 16], | ||
teredo: [new IPv6([0x2001, 0, 0, 0, 0, 0, 0, 0]), 32], | ||
reserved: [[new IPv6([0x2001, 0xdb8, 0, 0, 0, 0, 0, 0]), 32]] | ||
// Parses the string as an IPv4 Address with CIDR Notation. | ||
ipaddr.IPv4.parseCIDR = function (string) { | ||
let match; | ||
if ((match = string.match(/^(.+)\/(\d+)$/))) { | ||
const maskLength = parseInt(match[2]); | ||
if (maskLength >= 0 && maskLength <= 32) { | ||
const parsed = [this.parse(match[1]), maskLength]; | ||
Object.defineProperty(parsed, 'toString', { | ||
value: function () { | ||
return this.join('/'); | ||
} | ||
}); | ||
return parsed; | ||
} | ||
} | ||
throw new Error('ipaddr: string is not formatted like an IPv4 CIDR range'); | ||
}; | ||
IPv6.prototype.range = function() { | ||
return ipaddr.subnetMatch(this, this.SpecialRanges); | ||
// Classful variants (like a.b, where a is an octet, and b is a 24-bit | ||
// value representing last three octets; this corresponds to a class C | ||
// address) are omitted due to classless nature of modern Internet. | ||
ipaddr.IPv4.parser = function (string) { | ||
let match, part, value; | ||
// parseInt recognizes all that octal & hexadecimal weirdness for us | ||
if ((match = string.match(ipv4Regexes.fourOctet))) { | ||
return (function () { | ||
const ref = match.slice(1, 6); | ||
const results = []; | ||
for (let i = 0; i < ref.length; i++) { | ||
part = ref[i]; | ||
results.push(parseIntAuto(part)); | ||
} | ||
return results; | ||
})(); | ||
} else if ((match = string.match(ipv4Regexes.longValue))) { | ||
value = parseIntAuto(match[1]); | ||
if (value > 0xffffffff || value < 0) { | ||
throw new Error('ipaddr: address outside defined range'); | ||
} | ||
return ((function () { | ||
const results = []; | ||
let shift; | ||
for (shift = 0; shift <= 24; shift += 8) { | ||
results.push((value >> shift) & 0xff); | ||
} | ||
return results; | ||
})()).reverse(); | ||
} else if ((match = string.match(ipv4Regexes.twoOctet))) { | ||
return (function () { | ||
const ref = match.slice(1, 4); | ||
const results = []; | ||
value = parseIntAuto(ref[1]); | ||
if (value > 0xffffff || value < 0) { | ||
throw new Error('ipaddr: address outside defined range'); | ||
} | ||
results.push(parseIntAuto(ref[0])); | ||
results.push((value >> 16) & 0xff); | ||
results.push((value >> 8) & 0xff); | ||
results.push( value & 0xff); | ||
return results; | ||
})(); | ||
} else if ((match = string.match(ipv4Regexes.threeOctet))) { | ||
return (function () { | ||
const ref = match.slice(1, 5); | ||
const results = []; | ||
value = parseIntAuto(ref[2]); | ||
if (value > 0xffff || value < 0) { | ||
throw new Error('ipaddr: address outside defined range'); | ||
} | ||
results.push(parseIntAuto(ref[0])); | ||
results.push(parseIntAuto(ref[1])); | ||
results.push((value >> 8) & 0xff); | ||
results.push( value & 0xff); | ||
return results; | ||
})(); | ||
} else { | ||
return null; | ||
} | ||
}; | ||
IPv6.prototype.isIPv4MappedAddress = function() { | ||
return this.range() === 'ipv4Mapped'; | ||
// A utility function to return subnet mask in IPv4 format given the prefix length | ||
ipaddr.IPv4.subnetMaskFromPrefixLength = function (prefix) { | ||
prefix = parseInt(prefix); | ||
if (prefix < 0 || prefix > 32) { | ||
throw new Error('ipaddr: invalid IPv4 prefix length'); | ||
} | ||
const octets = [0, 0, 0, 0]; | ||
let j = 0; | ||
const filledOctetCount = Math.floor(prefix / 8); | ||
while (j < filledOctetCount) { | ||
octets[j] = 255; | ||
j++; | ||
} | ||
if (filledOctetCount < 4) { | ||
octets[filledOctetCount] = Math.pow(2, prefix % 8) - 1 << 8 - (prefix % 8); | ||
} | ||
return new this(octets); | ||
}; | ||
IPv6.prototype.toIPv4Address = function() { | ||
var high, low, ref; | ||
if (!this.isIPv4MappedAddress()) { | ||
throw new Error("ipaddr: trying to convert a generic ipv6 address to ipv4"); | ||
} | ||
ref = this.parts.slice(-2), high = ref[0], low = ref[1]; | ||
return new ipaddr.IPv4([high >> 8, high & 0xff, low >> 8, low & 0xff]); | ||
// An IPv6 address (RFC2460) | ||
ipaddr.IPv6 = (function () { | ||
// Constructs an IPv6 address from an array of eight 16 - bit parts | ||
// or sixteen 8 - bit parts in network order(MSB first). | ||
// Throws an error if the input is invalid. | ||
function IPv6 (parts, zoneId) { | ||
let i, part; | ||
if (parts.length === 16) { | ||
this.parts = []; | ||
for (i = 0; i <= 14; i += 2) { | ||
this.parts.push((parts[i] << 8) | parts[i + 1]); | ||
} | ||
} else if (parts.length === 8) { | ||
this.parts = parts; | ||
} else { | ||
throw new Error('ipaddr: ipv6 part count should be 8 or 16'); | ||
} | ||
for (i = 0; i < this.parts.length; i++) { | ||
part = this.parts[i]; | ||
if (!((0 <= part && part <= 0xffff))) { | ||
throw new Error('ipaddr: ipv6 part should fit in 16 bits'); | ||
} | ||
} | ||
if (zoneId) { | ||
this.zoneId = zoneId; | ||
} | ||
} | ||
// Special IPv6 ranges | ||
IPv6.prototype.SpecialRanges = { | ||
// RFC4291, here and after | ||
unspecified: [new IPv6([0, 0, 0, 0, 0, 0, 0, 0]), 128], | ||
linkLocal: [new IPv6([0xfe80, 0, 0, 0, 0, 0, 0, 0]), 10], | ||
multicast: [new IPv6([0xff00, 0, 0, 0, 0, 0, 0, 0]), 8], | ||
loopback: [new IPv6([0, 0, 0, 0, 0, 0, 0, 1]), 128], | ||
uniqueLocal: [new IPv6([0xfc00, 0, 0, 0, 0, 0, 0, 0]), 7], | ||
ipv4Mapped: [new IPv6([0, 0, 0, 0, 0, 0xffff, 0, 0]), 96], | ||
// RFC6145 | ||
rfc6145: [new IPv6([0, 0, 0, 0, 0xffff, 0, 0, 0]), 96], | ||
// RFC6052 | ||
rfc6052: [new IPv6([0x64, 0xff9b, 0, 0, 0, 0, 0, 0]), 96], | ||
// RFC3056 | ||
'6to4': [new IPv6([0x2002, 0, 0, 0, 0, 0, 0, 0]), 16], | ||
// RFC6052, RFC6146 | ||
teredo: [new IPv6([0x2001, 0, 0, 0, 0, 0, 0, 0]), 32], | ||
// RFC4291 | ||
reserved: [[new IPv6([0x2001, 0xdb8, 0, 0, 0, 0, 0, 0]), 32]] | ||
}; | ||
// Checks if this address is an IPv4-mapped IPv6 address. | ||
IPv6.prototype.isIPv4MappedAddress = function () { | ||
return this.range() === 'ipv4Mapped'; | ||
}; | ||
// The 'kind' method exists on both IPv4 and IPv6 classes. | ||
IPv6.prototype.kind = function () { | ||
return 'ipv6'; | ||
}; | ||
// Checks if this address matches other one within given CIDR range. | ||
IPv6.prototype.match = function (other, cidrRange) { | ||
let ref; | ||
if (cidrRange === undefined) { | ||
ref = other; | ||
other = ref[0]; | ||
cidrRange = ref[1]; | ||
} | ||
if (other.kind() !== 'ipv6') { | ||
throw new Error('ipaddr: cannot match ipv6 address with non-ipv6 one'); | ||
} | ||
return matchCIDR(this.parts, other.parts, 16, cidrRange); | ||
}; | ||
// returns a number of leading ones in IPv6 address, making sure that | ||
// the rest is a solid sequence of 0's (valid netmask) | ||
// returns either the CIDR length or null if mask is not valid | ||
IPv6.prototype.prefixLengthFromSubnetMask = function () { | ||
let cidr = 0; | ||
// non-zero encountered stop scanning for zeroes | ||
let stop = false; | ||
// number of zeroes in octet | ||
const zerotable = { | ||
0: 16, | ||
32768: 15, | ||
49152: 14, | ||
57344: 13, | ||
61440: 12, | ||
63488: 11, | ||
64512: 10, | ||
65024: 9, | ||
65280: 8, | ||
65408: 7, | ||
65472: 6, | ||
65504: 5, | ||
65520: 4, | ||
65528: 3, | ||
65532: 2, | ||
65534: 1, | ||
65535: 0 | ||
}; | ||
let part, zeros; | ||
for (let i = 7; i >= 0; i -= 1) { | ||
part = this.parts[i]; | ||
if (part in zerotable) { | ||
zeros = zerotable[part]; | ||
if (stop && zeros !== 0) { | ||
return null; | ||
} | ||
if (zeros !== 16) { | ||
stop = true; | ||
} | ||
cidr += zeros; | ||
} else { | ||
return null; | ||
} | ||
} | ||
return 128 - cidr; | ||
}; | ||
// Checks if the address corresponds to one of the special ranges. | ||
IPv6.prototype.range = function () { | ||
return ipaddr.subnetMatch(this, this.SpecialRanges); | ||
}; | ||
// Returns an array of byte-sized values in network order (MSB first) | ||
IPv6.prototype.toByteArray = function () { | ||
let part; | ||
const bytes = []; | ||
const ref = this.parts; | ||
for (let i = 0; i < ref.length; i++) { | ||
part = ref[i]; | ||
bytes.push(part >> 8); | ||
bytes.push(part & 0xff); | ||
} | ||
return bytes; | ||
}; | ||
// Returns the address in expanded format with all zeroes included, like | ||
// 2001:0db8:0008:0066:0000:0000:0000:0001 | ||
IPv6.prototype.toFixedLengthString = function () { | ||
const addr = ((function () { | ||
const results = []; | ||
for (let i = 0; i < this.parts.length; i++) { | ||
results.push(padPart(this.parts[i].toString(16), 4)); | ||
} | ||
return results; | ||
}).call(this)).join(':'); | ||
let suffix = ''; | ||
if (this.zoneId) { | ||
suffix = `%${this.zoneId}`; | ||
} | ||
return addr + suffix; | ||
}; | ||
// Converts this address to IPv4 address if it is an IPv4-mapped IPv6 address. | ||
// Throws an error otherwise. | ||
IPv6.prototype.toIPv4Address = function () { | ||
if (!this.isIPv4MappedAddress()) { | ||
throw new Error('ipaddr: trying to convert a generic ipv6 address to ipv4'); | ||
} | ||
const ref = this.parts.slice(-2); | ||
const high = ref[0]; | ||
const low = ref[1]; | ||
return new ipaddr.IPv4([high >> 8, high & 0xff, low >> 8, low & 0xff]); | ||
}; | ||
// Returns the address in expanded format with all zeroes included, like | ||
// 2001:db8:8:66:0:0:0:1 | ||
// | ||
// Deprecated: use toFixedLengthString() instead. | ||
IPv6.prototype.toNormalizedString = function () { | ||
const addr = ((function () { | ||
const results = []; | ||
for (let i = 0; i < this.parts.length; i++) { | ||
results.push(this.parts[i].toString(16)); | ||
} | ||
return results; | ||
}).call(this)).join(':'); | ||
let suffix = ''; | ||
if (this.zoneId) { | ||
suffix = `%${this.zoneId}`; | ||
} | ||
return addr + suffix; | ||
}; | ||
// Returns the address in compact, human-readable format like | ||
// 2001:db8:8:66::1 | ||
// in line with RFC 5952 (see https://tools.ietf.org/html/rfc5952#section-4) | ||
IPv6.prototype.toRFC5952String = function () { | ||
const regex = /((^|:)(0(:|$)){2,})/g; | ||
const string = this.toNormalizedString(); | ||
let bestMatchIndex = 0; | ||
let bestMatchLength = -1; | ||
let match; | ||
while ((match = regex.exec(string))) { | ||
if (match[0].length > bestMatchLength) { | ||
bestMatchIndex = match.index; | ||
bestMatchLength = match[0].length; | ||
} | ||
} | ||
if (bestMatchLength < 0) { | ||
return string; | ||
} | ||
return `${string.substring(0, bestMatchIndex)}::${string.substring(bestMatchIndex + bestMatchLength)}`; | ||
}; | ||
// Returns the address in compact, human-readable format like | ||
// 2001:db8:8:66::1 | ||
// | ||
// Deprecated: use toRFC5952String() instead. | ||
IPv6.prototype.toString = function () { | ||
// Replace the first sequence of 1 or more '0' parts with '::' | ||
return this.toNormalizedString().replace(/((^|:)(0(:|$))+)/, '::'); | ||
}; | ||
return IPv6; | ||
})(); | ||
// Checks if a given string is formatted like IPv6 address. | ||
ipaddr.IPv6.isIPv6 = function (string) { | ||
return this.parser(string) !== null; | ||
}; | ||
IPv6.prototype.prefixLengthFromSubnetMask = function() { | ||
var cidr, i, k, part, stop, zeros, zerotable; | ||
zerotable = { | ||
0: 16, | ||
32768: 15, | ||
49152: 14, | ||
57344: 13, | ||
61440: 12, | ||
63488: 11, | ||
64512: 10, | ||
65024: 9, | ||
65280: 8, | ||
65408: 7, | ||
65472: 6, | ||
65504: 5, | ||
65520: 4, | ||
65528: 3, | ||
65532: 2, | ||
65534: 1, | ||
65535: 0 | ||
}; | ||
cidr = 0; | ||
stop = false; | ||
for (i = k = 7; k >= 0; i = k += -1) { | ||
part = this.parts[i]; | ||
if (part in zerotable) { | ||
zeros = zerotable[part]; | ||
if (stop && zeros !== 0) { | ||
return null; | ||
} | ||
if (zeros !== 16) { | ||
stop = true; | ||
} | ||
cidr += zeros; | ||
} else { | ||
return null; | ||
// Checks to see if string is a valid IPv6 Address | ||
ipaddr.IPv6.isValid = function (string) { | ||
// Since IPv6.isValid is always called first, this shortcut | ||
// provides a substantial performance gain. | ||
if (typeof string === 'string' && string.indexOf(':') === -1) { | ||
return false; | ||
} | ||
} | ||
return 128 - cidr; | ||
try { | ||
const addr = this.parser(string); | ||
new this(addr.parts, addr.zoneId); | ||
return true; | ||
} catch (e) { | ||
return false; | ||
} | ||
}; | ||
return IPv6; | ||
// Tries to parse and validate a string with IPv6 address. | ||
// Throws an error if it fails. | ||
ipaddr.IPv6.parse = function (string) { | ||
const addr = this.parser(string); | ||
})(); | ||
if (addr.parts === null) { | ||
throw new Error('ipaddr: string is not formatted like an IPv6 Address'); | ||
} | ||
ipv6Part = "(?:[0-9a-f]+::?)+"; | ||
return new this(addr.parts, addr.zoneId); | ||
}; | ||
zoneIndex = "%[0-9a-z]{1,}"; | ||
ipaddr.IPv6.parseCIDR = function (string) { | ||
let maskLength, match, parsed; | ||
ipv6Regexes = { | ||
zoneIndex: new RegExp(zoneIndex, 'i'), | ||
"native": new RegExp("^(::)?(" + ipv6Part + ")?([0-9a-f]+)?(::)?(" + zoneIndex + ")?$", 'i'), | ||
transitional: new RegExp(("^((?:" + ipv6Part + ")|(?:::)(?:" + ipv6Part + ")?)") + (ipv4Part + "\\." + ipv4Part + "\\." + ipv4Part + "\\." + ipv4Part) + ("(" + zoneIndex + ")?$"), 'i') | ||
}; | ||
if ((match = string.match(/^(.+)\/(\d+)$/))) { | ||
maskLength = parseInt(match[2]); | ||
if (maskLength >= 0 && maskLength <= 128) { | ||
parsed = [this.parse(match[1]), maskLength]; | ||
Object.defineProperty(parsed, 'toString', { | ||
value: function () { | ||
return this.join('/'); | ||
} | ||
}); | ||
return parsed; | ||
} | ||
} | ||
expandIPv6 = function(string, parts) { | ||
var colonCount, lastColon, part, replacement, replacementCount, zoneId; | ||
if (string.indexOf('::') !== string.lastIndexOf('::')) { | ||
return null; | ||
} | ||
zoneId = (string.match(ipv6Regexes['zoneIndex']) || [])[0]; | ||
if (zoneId) { | ||
zoneId = zoneId.substring(1); | ||
string = string.replace(/%.+$/, ''); | ||
} | ||
colonCount = 0; | ||
lastColon = -1; | ||
while ((lastColon = string.indexOf(':', lastColon + 1)) >= 0) { | ||
colonCount++; | ||
} | ||
if (string.substr(0, 2) === '::') { | ||
colonCount--; | ||
} | ||
if (string.substr(-2, 2) === '::') { | ||
colonCount--; | ||
} | ||
if (colonCount > parts) { | ||
return null; | ||
} | ||
replacementCount = parts - colonCount; | ||
replacement = ':'; | ||
while (replacementCount--) { | ||
replacement += '0:'; | ||
} | ||
string = string.replace('::', replacement); | ||
if (string[0] === ':') { | ||
string = string.slice(1); | ||
} | ||
if (string[string.length - 1] === ':') { | ||
string = string.slice(0, -1); | ||
} | ||
parts = (function() { | ||
var k, len, ref, results; | ||
ref = string.split(":"); | ||
results = []; | ||
for (k = 0, len = ref.length; k < len; k++) { | ||
part = ref[k]; | ||
results.push(parseInt(part, 16)); | ||
} | ||
return results; | ||
})(); | ||
return { | ||
parts: parts, | ||
zoneId: zoneId | ||
throw new Error('ipaddr: string is not formatted like an IPv6 CIDR range'); | ||
}; | ||
}; | ||
ipaddr.IPv6.parser = function(string) { | ||
var addr, k, len, match, octet, octets, zoneId; | ||
if (ipv6Regexes['native'].test(string)) { | ||
return expandIPv6(string, 8); | ||
} else if (match = string.match(ipv6Regexes['transitional'])) { | ||
zoneId = match[6] || ''; | ||
addr = expandIPv6(match[1].slice(0, -1) + zoneId, 6); | ||
if (addr.parts) { | ||
octets = [parseInt(match[2]), parseInt(match[3]), parseInt(match[4]), parseInt(match[5])]; | ||
for (k = 0, len = octets.length; k < len; k++) { | ||
octet = octets[k]; | ||
if (!((0 <= octet && octet <= 255))) { | ||
return null; | ||
} | ||
// Parse an IPv6 address. | ||
ipaddr.IPv6.parser = function (string) { | ||
let addr, i, match, octet, octets, zoneId; | ||
if ((match = string.match(ipv6Regexes.deprecatedTransitional))) { | ||
return this.parser(`::ffff:${match[1]}`); | ||
} | ||
addr.parts.push(octets[0] << 8 | octets[1]); | ||
addr.parts.push(octets[2] << 8 | octets[3]); | ||
return { | ||
parts: addr.parts, | ||
zoneId: addr.zoneId | ||
}; | ||
} | ||
} | ||
return null; | ||
}; | ||
if (ipv6Regexes.native.test(string)) { | ||
return expandIPv6(string, 8); | ||
} | ||
if ((match = string.match(ipv6Regexes.transitional))) { | ||
zoneId = match[6] || ''; | ||
addr = expandIPv6(match[1].slice(0, -1) + zoneId, 6); | ||
if (addr.parts) { | ||
octets = [ | ||
parseInt(match[2]), | ||
parseInt(match[3]), | ||
parseInt(match[4]), | ||
parseInt(match[5]) | ||
]; | ||
for (i = 0; i < octets.length; i++) { | ||
octet = octets[i]; | ||
if (!((0 <= octet && octet <= 255))) { | ||
return null; | ||
} | ||
} | ||
ipaddr.IPv4.isIPv4 = ipaddr.IPv6.isIPv6 = function(string) { | ||
return this.parser(string) !== null; | ||
}; | ||
addr.parts.push(octets[0] << 8 | octets[1]); | ||
addr.parts.push(octets[2] << 8 | octets[3]); | ||
return { | ||
parts: addr.parts, | ||
zoneId: addr.zoneId | ||
}; | ||
} | ||
} | ||
ipaddr.IPv4.isValid = function(string) { | ||
var e; | ||
try { | ||
new this(this.parser(string)); | ||
return true; | ||
} catch (error1) { | ||
e = error1; | ||
return false; | ||
} | ||
}; | ||
return null; | ||
}; | ||
ipaddr.IPv4.isValidFourPartDecimal = function(string) { | ||
if (ipaddr.IPv4.isValid(string) && string.match(/^(0|[1-9]\d*)(\.(0|[1-9]\d*)){3}$/)) { | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
}; | ||
// Try to parse an array in network order (MSB first) for IPv4 and IPv6 | ||
ipaddr.fromByteArray = function (bytes) { | ||
const length = bytes.length; | ||
ipaddr.IPv6.isValid = function(string) { | ||
var addr, e; | ||
if (typeof string === "string" && string.indexOf(":") === -1) { | ||
return false; | ||
} | ||
try { | ||
addr = this.parser(string); | ||
new this(addr.parts, addr.zoneId); | ||
return true; | ||
} catch (error1) { | ||
e = error1; | ||
return false; | ||
} | ||
}; | ||
if (length === 4) { | ||
return new ipaddr.IPv4(bytes); | ||
} else if (length === 16) { | ||
return new ipaddr.IPv6(bytes); | ||
} else { | ||
throw new Error('ipaddr: the binary input is neither an IPv6 nor IPv4 address'); | ||
} | ||
}; | ||
ipaddr.IPv4.parse = function(string) { | ||
var parts; | ||
parts = this.parser(string); | ||
if (parts === null) { | ||
throw new Error("ipaddr: string is not formatted like ip address"); | ||
} | ||
return new this(parts); | ||
}; | ||
// Checks if the address is valid IP address | ||
ipaddr.isValid = function (string) { | ||
return ipaddr.IPv6.isValid(string) || ipaddr.IPv4.isValid(string); | ||
}; | ||
ipaddr.IPv6.parse = function(string) { | ||
var addr; | ||
addr = this.parser(string); | ||
if (addr.parts === null) { | ||
throw new Error("ipaddr: string is not formatted like ip address"); | ||
} | ||
return new this(addr.parts, addr.zoneId); | ||
}; | ||
// Attempts to parse an IP Address, first through IPv6 then IPv4. | ||
// Throws an error if it could not be parsed. | ||
ipaddr.parse = function (string) { | ||
if (ipaddr.IPv6.isValid(string)) { | ||
return ipaddr.IPv6.parse(string); | ||
} else if (ipaddr.IPv4.isValid(string)) { | ||
return ipaddr.IPv4.parse(string); | ||
} else { | ||
throw new Error('ipaddr: the address has neither IPv6 nor IPv4 format'); | ||
} | ||
}; | ||
ipaddr.IPv4.parseCIDR = function(string) { | ||
var maskLength, match, parsed; | ||
if (match = string.match(/^(.+)\/(\d+)$/)) { | ||
maskLength = parseInt(match[2]); | ||
if (maskLength >= 0 && maskLength <= 32) { | ||
parsed = [this.parse(match[1]), maskLength]; | ||
Object.defineProperty(parsed, 'toString', { | ||
value: function() { | ||
return this.join('/'); | ||
} | ||
}); | ||
return parsed; | ||
} | ||
} | ||
throw new Error("ipaddr: string is not formatted like an IPv4 CIDR range"); | ||
}; | ||
// Attempt to parse CIDR notation, first through IPv6 then IPv4. | ||
// Throws an error if it could not be parsed. | ||
ipaddr.parseCIDR = function (string) { | ||
try { | ||
return ipaddr.IPv6.parseCIDR(string); | ||
} catch (e) { | ||
try { | ||
return ipaddr.IPv4.parseCIDR(string); | ||
} catch (e2) { | ||
throw new Error('ipaddr: the address has neither IPv6 nor IPv4 CIDR format'); | ||
} | ||
} | ||
}; | ||
ipaddr.IPv4.subnetMaskFromPrefixLength = function(prefix) { | ||
var filledOctetCount, j, octets; | ||
prefix = parseInt(prefix); | ||
if (prefix < 0 || prefix > 32) { | ||
throw new Error('ipaddr: invalid IPv4 prefix length'); | ||
} | ||
octets = [0, 0, 0, 0]; | ||
j = 0; | ||
filledOctetCount = Math.floor(prefix / 8); | ||
while (j < filledOctetCount) { | ||
octets[j] = 255; | ||
j++; | ||
} | ||
if (filledOctetCount < 4) { | ||
octets[filledOctetCount] = Math.pow(2, prefix % 8) - 1 << 8 - (prefix % 8); | ||
} | ||
return new this(octets); | ||
}; | ||
// Parse an address and return plain IPv4 address if it is an IPv4-mapped address | ||
ipaddr.process = function (string) { | ||
const addr = this.parse(string); | ||
ipaddr.IPv4.broadcastAddressFromCIDR = function(string) { | ||
var cidr, error, i, ipInterfaceOctets, octets, subnetMaskOctets; | ||
try { | ||
cidr = this.parseCIDR(string); | ||
ipInterfaceOctets = cidr[0].toByteArray(); | ||
subnetMaskOctets = this.subnetMaskFromPrefixLength(cidr[1]).toByteArray(); | ||
octets = []; | ||
i = 0; | ||
while (i < 4) { | ||
octets.push(parseInt(ipInterfaceOctets[i], 10) | parseInt(subnetMaskOctets[i], 10) ^ 255); | ||
i++; | ||
} | ||
return new this(octets); | ||
} catch (error1) { | ||
error = error1; | ||
throw new Error('ipaddr: the address does not have IPv4 CIDR format'); | ||
} | ||
}; | ||
if (addr.kind() === 'ipv6' && addr.isIPv4MappedAddress()) { | ||
return addr.toIPv4Address(); | ||
} else { | ||
return addr; | ||
} | ||
}; | ||
ipaddr.IPv4.networkAddressFromCIDR = function(string) { | ||
var cidr, error, i, ipInterfaceOctets, octets, subnetMaskOctets; | ||
try { | ||
cidr = this.parseCIDR(string); | ||
ipInterfaceOctets = cidr[0].toByteArray(); | ||
subnetMaskOctets = this.subnetMaskFromPrefixLength(cidr[1]).toByteArray(); | ||
octets = []; | ||
i = 0; | ||
while (i < 4) { | ||
octets.push(parseInt(ipInterfaceOctets[i], 10) & parseInt(subnetMaskOctets[i], 10)); | ||
i++; | ||
} | ||
return new this(octets); | ||
} catch (error1) { | ||
error = error1; | ||
throw new Error('ipaddr: the address does not have IPv4 CIDR format'); | ||
} | ||
}; | ||
// An utility function to ease named range matching. See examples below. | ||
// rangeList can contain both IPv4 and IPv6 subnet entries and will not throw errors | ||
// on matching IPv4 addresses to IPv6 ranges or vice versa. | ||
ipaddr.subnetMatch = function (address, rangeList, defaultName) { | ||
let i, rangeName, rangeSubnets, subnet; | ||
ipaddr.IPv6.parseCIDR = function(string) { | ||
var maskLength, match, parsed; | ||
if (match = string.match(/^(.+)\/(\d+)$/)) { | ||
maskLength = parseInt(match[2]); | ||
if (maskLength >= 0 && maskLength <= 128) { | ||
parsed = [this.parse(match[1]), maskLength]; | ||
Object.defineProperty(parsed, 'toString', { | ||
value: function() { | ||
return this.join('/'); | ||
} | ||
}); | ||
return parsed; | ||
} | ||
} | ||
throw new Error("ipaddr: string is not formatted like an IPv6 CIDR range"); | ||
}; | ||
if (defaultName === undefined || defaultName === null) { | ||
defaultName = 'unicast'; | ||
} | ||
ipaddr.isValid = function(string) { | ||
return ipaddr.IPv6.isValid(string) || ipaddr.IPv4.isValid(string); | ||
}; | ||
for (rangeName in rangeList) { | ||
if (Object.prototype.hasOwnProperty.call(rangeList, rangeName)) { | ||
rangeSubnets = rangeList[rangeName]; | ||
// ECMA5 Array.isArray isn't available everywhere | ||
if (rangeSubnets[0] && !(rangeSubnets[0] instanceof Array)) { | ||
rangeSubnets = [rangeSubnets]; | ||
} | ||
ipaddr.parse = function(string) { | ||
if (ipaddr.IPv6.isValid(string)) { | ||
return ipaddr.IPv6.parse(string); | ||
} else if (ipaddr.IPv4.isValid(string)) { | ||
return ipaddr.IPv4.parse(string); | ||
} else { | ||
throw new Error("ipaddr: the address has neither IPv6 nor IPv4 format"); | ||
} | ||
}; | ||
for (i = 0; i < rangeSubnets.length; i++) { | ||
subnet = rangeSubnets[i]; | ||
if (address.kind() === subnet[0].kind() && address.match.apply(address, subnet)) { | ||
return rangeName; | ||
} | ||
} | ||
} | ||
} | ||
ipaddr.parseCIDR = function(string) { | ||
var e; | ||
try { | ||
return ipaddr.IPv6.parseCIDR(string); | ||
} catch (error1) { | ||
e = error1; | ||
try { | ||
return ipaddr.IPv4.parseCIDR(string); | ||
} catch (error1) { | ||
e = error1; | ||
throw new Error("ipaddr: the address has neither IPv6 nor IPv4 CIDR format"); | ||
} | ||
} | ||
}; | ||
return defaultName; | ||
}; | ||
ipaddr.fromByteArray = function(bytes) { | ||
var length; | ||
length = bytes.length; | ||
if (length === 4) { | ||
return new ipaddr.IPv4(bytes); | ||
} else if (length === 16) { | ||
return new ipaddr.IPv6(bytes); | ||
} else { | ||
throw new Error("ipaddr: the binary input is neither an IPv6 nor IPv4 address"); | ||
} | ||
}; | ||
// Export for both the CommonJS and browser-like environment | ||
if (typeof module !== 'undefined' && module.exports) { | ||
module.exports = ipaddr; | ||
ipaddr.process = function(string) { | ||
var addr; | ||
addr = this.parse(string); | ||
if (addr.kind() === 'ipv6' && addr.isIPv4MappedAddress()) { | ||
return addr.toIPv4Address(); | ||
} else { | ||
return addr; | ||
root.ipaddr = ipaddr; | ||
} | ||
}; | ||
}).call(this); | ||
}(this)); |
declare module "ipaddr.js" { | ||
type IPv4Range = 'unicast' | 'unspecified' | 'broadcast' | 'multicast' | 'linkLocal' | 'loopback' | 'carrierGradeNat' | 'private' | 'reserved'; | ||
type IPv6Range = 'unicast' | 'unspecified' | 'linkLocal' | 'multicast' | 'loopback' | 'uniqueLocal' | 'ipv4Mapped' | 'rfc6145' | 'rfc6052' | '6to4' | 'teredo' | 'reserved'; | ||
type IPvXRangeDefaults = 'unicast' | 'unspecified' | 'multicast' | 'linkLocal' | 'loopback' | 'reserved'; | ||
type IPv4Range = IPvXRangeDefaults | 'broadcast' | 'carrierGradeNat' | 'private'; | ||
type IPv6Range = IPvXRangeDefaults | 'uniqueLocal' | 'ipv4Mapped' | 'rfc6145' | 'rfc6052' | '6to4' | 'teredo'; | ||
@@ -18,9 +19,8 @@ interface RangeList<T> { | ||
namespace Address { | ||
export function fromByteArray(bytes: number[]): IPv4 | IPv6; | ||
export function isValid(addr: string): boolean; | ||
export function fromByteArray(bytes: number[]): IPv4 | IPv6; | ||
export function parse(addr: string): IPv4 | IPv6; | ||
export function parseCIDR(mask: string): [IPv4 | IPv6, number]; | ||
export function process(addr: string): IPv4 | IPv6; | ||
export function subnetMatch(addr: IPv4, rangeList: RangeList<IPv4>, defaultName?: string): string; | ||
export function subnetMatch(addr: IPv6, rangeList: RangeList<IPv6>, defaultName?: string): string; | ||
export function subnetMatch(addr: IPv4 | IPv6, rangeList: RangeList<IPv4 | IPv6>, defaultName?: string): string; | ||
@@ -40,4 +40,3 @@ export class IPv4 extends IP { | ||
kind(): 'ipv4'; | ||
match(addr: IPv4, bits: number): boolean; | ||
match(mask: [IPv4, number]): boolean; | ||
match(what: IPv4 | IPv6 | [IPv4 | IPv6, number], bits?: number): boolean; | ||
range(): IPv4Range; | ||
@@ -61,7 +60,7 @@ subnetMatch(rangeList: RangeList<IPv4>, defaultName?: string): string; | ||
kind(): 'ipv6'; | ||
match(addr: IPv6, bits: number): boolean; | ||
match(mask: [IPv6, number]): boolean; | ||
match(what: IPv4 | IPv6 | [IPv4 | IPv6, number], bits?: number): boolean; | ||
range(): IPv6Range; | ||
subnetMatch(rangeList: RangeList<IPv6>, defaultName?: string): string; | ||
toIPv4Address(): IPv4; | ||
toRFC5952String(): string; | ||
} | ||
@@ -68,0 +67,0 @@ } |
{ | ||
"name": "ipaddr.js", | ||
"description": "A library for manipulating IPv4 and IPv6 addresses in JavaScript.", | ||
"version": "1.9.1", | ||
"version": "2.0.0", | ||
"author": "whitequark <whitequark@whitequark.org>", | ||
@@ -11,8 +11,11 @@ "directories": { | ||
"devDependencies": { | ||
"coffee-script": "~1.12.6", | ||
"nodeunit": "^0.11.3", | ||
"uglify-js": "~3.0.19" | ||
"eslint": "*", | ||
"mocha": "*", | ||
"uglify-es": "*" | ||
}, | ||
"scripts": { | ||
"test": "cake build test" | ||
"lint": "npx eslint lib test", | ||
"lintfix": "npx eslint --fix lib test", | ||
"build": "npx uglifyjs --compress --mangle --wrap=window -o ipaddr.min.js lib/ipaddr.js", | ||
"test": "npx _mocha" | ||
}, | ||
@@ -32,3 +35,3 @@ "files": [ | ||
"engines": { | ||
"node": ">= 0.10" | ||
"node": ">= 10" | ||
}, | ||
@@ -35,0 +38,0 @@ "license": "MIT", |
@@ -22,2 +22,7 @@ # ipaddr.js — an IPv6 and IPv4 address manipulation library [![Build Status](https://travis-ci.org/whitequark/ipaddr.js.svg)](https://travis-ci.org/whitequark/ipaddr.js) | ||
## Older Node support | ||
Use 2.x release for nodejs versions 10+. | ||
Use the 1.x release for versions of nodejs older than 10. | ||
## API | ||
@@ -29,3 +34,3 @@ | ||
```js | ||
var ipaddr = require('ipaddr.js'); | ||
const ipaddr = require('ipaddr.js'); | ||
``` | ||
@@ -72,4 +77,3 @@ | ||
A `match(range, bits)` method can be used to check if the address falls into a | ||
certain CIDR range. | ||
Note that an address can be (obviously) matched only against an address of the same type. | ||
certain CIDR range. Note that an address can be (obviously) matched only against an address of the same type. | ||
@@ -79,4 +83,4 @@ For example: | ||
```js | ||
var addr = ipaddr.parse("2001:db8:1234::1"); | ||
var range = ipaddr.parse("2001:db8::"); | ||
const addr = ipaddr.parse('2001:db8:1234::1'); | ||
const range = ipaddr.parse('2001:db8::'); | ||
@@ -86,5 +90,3 @@ addr.match(range, 32); // => true | ||
Alternatively, `match` can also be called as `match([range, bits])`. In this way, | ||
it can be used together with the `parseCIDR(string)` method, which parses an IP | ||
address together with a CIDR range. | ||
Alternatively, `match` can also be called as `match([range, bits])`. In this way, it can be used together with the `parseCIDR(string)` method, which parses an IP address together with a CIDR range. | ||
@@ -94,11 +96,8 @@ For example: | ||
```js | ||
var addr = ipaddr.parse("2001:db8:1234::1"); | ||
const addr = ipaddr.parse('2001:db8:1234::1'); | ||
addr.match(ipaddr.parseCIDR("2001:db8::/32")); // => true | ||
addr.match(ipaddr.parseCIDR('2001:db8::/32')); // => true | ||
``` | ||
A `range()` method returns one of predefined names for several special ranges defined | ||
by IP protocols. The exact names (and their respective CIDR ranges) can be looked up | ||
in the source: [IPv6 ranges] and [IPv4 ranges]. Some common ones include `"unicast"` | ||
(the default one) and `"reserved"`. | ||
A `range()` method returns one of predefined names for several special ranges defined by IP protocols. The exact names (and their respective CIDR ranges) can be looked up in the source: [IPv6 ranges] and [IPv4 ranges]. Some common ones include `"unicast"` (the default one) and `"reserved"`. | ||
@@ -109,3 +108,3 @@ You can match against your own range list by using | ||
```js | ||
var rangeList = { | ||
const rangeList = { | ||
documentationOnly: [ ipaddr.parse('2001:db8::'), 32 ], | ||
@@ -120,16 +119,12 @@ tunnelProviders: [ | ||
The addresses can be converted to their byte representation with `toByteArray()`. | ||
(Actually, JavaScript mostly does not know about byte buffers. They are emulated with | ||
arrays of numbers, each in range of 0..255.) | ||
The addresses can be converted to their byte representation with `toByteArray()`. (Actually, JavaScript mostly does not know about byte buffers. They are emulated with arrays of numbers, each in range of 0..255.) | ||
```js | ||
var bytes = ipaddr.parse('2a00:1450:8007::68').toByteArray(); // ipv6.google.com | ||
const bytes = ipaddr.parse('2a00:1450:8007::68').toByteArray(); // ipv6.google.com | ||
bytes // => [42, 0x00, 0x14, 0x50, 0x80, 0x07, 0x00, <zeroes...>, 0x00, 0x68 ] | ||
``` | ||
The `ipaddr.IPv4` and `ipaddr.IPv6` objects have some methods defined, too. All of them | ||
have the same interface for both protocols, and are similar to global methods. | ||
The `ipaddr.IPv4` and `ipaddr.IPv6` objects have some methods defined, too. All of them have the same interface for both protocols, and are similar to global methods. | ||
`ipaddr.IPvX.isValid(string)` can be used to check if the string is a valid address | ||
for particular protocol, and `ipaddr.IPvX.parse(string)` is the error-throwing parser. | ||
`ipaddr.IPvX.isValid(string)` can be used to check if the string is a valid address for particular protocol, and `ipaddr.IPvX.parse(string)` is the error-throwing parser. | ||
@@ -143,5 +138,3 @@ `ipaddr.IPvX.isValid(string)` uses the same format for parsing as the POSIX `inet_ntoa` function, which accepts unusual formats like `0xc0.168.1.1` or `0x10000000`. The function `ipaddr.IPv4.isValidFourPartDecimal(string)` validates the IPv4 address and also ensures that it is written in four-part decimal format. | ||
Sometimes you will want to convert IPv6 not to a compact string representation (with | ||
the `::` substitution); the `toNormalizedString()` method will return an address where | ||
all zeroes are explicit. | ||
Sometimes you will want to convert IPv6 not to a compact string representation (with the `::` substitution); the `toNormalizedString()` method will return an address where all zeroes are explicit. | ||
@@ -151,5 +144,5 @@ For example: | ||
```js | ||
var addr = ipaddr.parse("2001:0db8::0001"); | ||
addr.toString(); // => "2001:db8::1" | ||
addr.toNormalizedString(); // => "2001:db8:0:0:0:0:0:1" | ||
const addr = ipaddr.parse('2001:0db8::0001'); | ||
addr.toString(); // => '2001:db8::1' | ||
addr.toNormalizedString(); // => '2001:db8:0:0:0:0:0:1' | ||
``` | ||
@@ -163,3 +156,3 @@ | ||
```js | ||
var addr = ipaddr.parse("2001:db8:10::1234:DEAD"); | ||
const addr = ipaddr.parse('2001:db8:10::1234:DEAD'); | ||
addr.parts // => [0x2001, 0xdb8, 0x10, 0, 0, 0, 0x1234, 0xdead] | ||
@@ -171,3 +164,3 @@ ``` | ||
```js | ||
var addr = ipaddr.parse("2001:db8::%eth0"); | ||
const addr = ipaddr.parse('2001:db8::%eth0'); | ||
addr.zoneId // => 'eth0' | ||
@@ -183,3 +176,3 @@ ``` | ||
```js | ||
var addr = ipaddr.parse("192.168.1.1"); | ||
const addr = ipaddr.parse('192.168.1.1'); | ||
addr.octets // => [192, 168, 1, 1] | ||
@@ -199,4 +192,4 @@ ``` | ||
```js | ||
ipaddr.IPv4.subnetMaskFromPrefixLength(24) == "255.255.255.0" | ||
ipaddr.IPv4.subnetMaskFromPrefixLength(29) == "255.255.255.248" | ||
ipaddr.IPv4.subnetMaskFromPrefixLength(24) == '255.255.255.0' | ||
ipaddr.IPv4.subnetMaskFromPrefixLength(29) == '255.255.255.248' | ||
``` | ||
@@ -206,7 +199,7 @@ | ||
```js | ||
ipaddr.IPv4.broadcastAddressFromCIDR("172.0.0.1/24") == "172.0.0.255" | ||
ipaddr.IPv4.broadcastAddressFromCIDR('172.0.0.1/24') == '172.0.0.255' | ||
``` | ||
`networkAddressFromCIDR()` will return the network address for a given IPv4 interface and netmask in CIDR notation. | ||
```js | ||
ipaddr.IPv4.networkAddressFromCIDR("172.0.0.1/24") == "172.0.0.0" | ||
ipaddr.IPv4.networkAddressFromCIDR('172.0.0.1/24') == '172.0.0.0' | ||
``` | ||
@@ -224,4 +217,4 @@ | ||
```js | ||
var addr = ipaddr.fromByteArray([0x7f, 0, 0, 1]); | ||
addr.toString(); // => "127.0.0.1" | ||
const addr = ipaddr.fromByteArray([0x7f, 0, 0, 1]); | ||
addr.toString(); // => '127.0.0.1' | ||
``` | ||
@@ -232,4 +225,4 @@ | ||
```js | ||
var addr = ipaddr.fromByteArray([0x20, 1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]) | ||
addr.toString(); // => "2001:db8::1" | ||
const addr = ipaddr.fromByteArray([0x20, 1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]) | ||
addr.toString(); // => '2001:db8::1' | ||
``` | ||
@@ -241,3 +234,3 @@ | ||
```js | ||
var addr = ipaddr.parse("127.0.0.1"); | ||
const addr = ipaddr.parse('127.0.0.1'); | ||
addr.toByteArray(); // => [0x7f, 0, 0, 1] | ||
@@ -249,4 +242,4 @@ ``` | ||
```js | ||
var addr = ipaddr.parse("2001:db8::1"); | ||
const addr = ipaddr.parse('2001:db8::1'); | ||
addr.toByteArray(); // => [0x20, 1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] | ||
``` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
55486
838
227
1