From 7dcaf1830e9e8c30606316bd8b98b4e1ae0cc6d0 Mon Sep 17 00:00:00 2001 From: "James M. Greene" Date: Sat, 19 Aug 2017 16:11:41 -0500 Subject: [PATCH] Allow `ipaddr.IPv4.subnetMaskFromPrefixLength(32)` Fixes #73 Fixes #64 --- README.md | 4 +-- ipaddr.min.js | 2 +- lib/ipaddr.js | 38 +++++++++++--------- src/ipaddr.coffee | 31 ++++++++++------- test/ipaddr.test.coffee | 77 +++++++++++++++++++++-------------------- 5 files changed, 82 insertions(+), 70 deletions(-) diff --git a/README.md b/README.md index 938790e..6876a3b 100644 --- a/README.md +++ b/README.md @@ -183,8 +183,8 @@ ipaddr.IPv4.parse('255.192.164.0').prefixLengthFromSubnetMask() == null `subnetMaskFromPrefixLength()` will return an IPv4 netmask for a valid CIDR prefix length. ```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" ``` `broadcastAddressFromCIDR()` will return the broadcast address for a given IPv4 interface and netmask in CIDR notation. diff --git a/ipaddr.min.js b/ipaddr.min.js index 4967da1..4931324 100644 --- a/ipaddr.min.js +++ b/ipaddr.min.js @@ -1 +1 @@ -(function(){var r,t,n,e,i,o,a,s,p;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=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;r4294967295||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>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>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]+::?)+",p="%[0-9a-z]{1,}",o={zoneIndex:new RegExp(p,"i"),native:new RegExp("^(::)?("+i+")?([0-9a-f]+)?(::)?("+p+")?$","i"),transitional:new RegExp("^((?:"+i+")|(?:::)(?:"+i+")?)"+n+"\\."+n+"\\."+n+"\\."+n+"(%[0-9a-z]{1,})?$","i")},r=function(r,t){var n,e,i,o,a,s;if(r.indexOf("::")!==r.lastIndexOf("::"))return null;for((s=(r.match(p)||[])[0])&&(s=s.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(a=t-n,o=":";a--;)o+="0:";return":"===(r=r.replace("::",o))[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=0&&t<=32)return[this.parse(n[1]),t];throw new Error("ipaddr: string is not formatted like an IPv4 CIDR range")},t.IPv4.subnetMaskFromPrefixLength=function(r){var n,e;if(r<0||r>32)throw new Error("ipaddr: invalid prefix length");for(e=Array(4).fill(0),n=0;n=0&&t<=128)return[this.parse(n[1]),t];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"ipv6"===(t=this.parse(r)).kind()&&t.isIPv4MappedAddress()?t.toIPv4Address():t}}).call(this); \ No newline at end of file +(function(){var r,t,n,e,i,o,a,s,p;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=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;r4294967295||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>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>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]+::?)+",p="%[0-9a-z]{1,}",o={zoneIndex:new RegExp(p,"i"),native:new RegExp("^(::)?("+i+")?([0-9a-f]+)?(::)?("+p+")?$","i"),transitional:new RegExp("^((?:"+i+")|(?:::)(?:"+i+")?)"+n+"\\."+n+"\\."+n+"\\."+n+"(%[0-9a-z]{1,})?$","i")},r=function(r,t){var n,e,i,o,a,s;if(r.indexOf("::")!==r.lastIndexOf("::"))return null;for((s=(r.match(p)||[])[0])&&(s=s.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(a=t-n,o=":";a--;)o+="0:";return":"===(r=r.replace("::",o))[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=0&&t<=32)return[this.parse(n[1]),t];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=0&&t<=128)return[this.parse(n[1]),t];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"ipv6"===(t=this.parse(r)).kind()&&t.isIPv4MappedAddress()?t.toIPv4Address():t}}).call(this); \ No newline at end of file diff --git a/lib/ipaddr.js b/lib/ipaddr.js index c6132ad..c464209 100644 --- a/lib/ipaddr.js +++ b/lib/ipaddr.js @@ -556,32 +556,37 @@ }; ipaddr.IPv4.subnetMaskFromPrefixLength = function(prefix) { - var j, octets; + var filledOctetCount, j, octets; + prefix = parseInt(prefix); if (prefix < 0 || prefix > 32) { - throw new Error('ipaddr: invalid prefix length'); + throw new Error('ipaddr: invalid IPv4 prefix length'); } - octets = Array(4).fill(0); + octets = [0, 0, 0, 0]; j = 0; - while (j < Math.floor(prefix / 8)) { + filledOctetCount = Math.floor(prefix / 8); + while (j < filledOctetCount) { octets[j] = 255; j++; } - octets[Math.floor(prefix / 8)] = Math.pow(2, prefix % 8) - 1 << 8 - (prefix % 8); - return new ipaddr.IPv4(octets); + if (filledOctetCount < 4) { + octets[filledOctetCount] = Math.pow(2, prefix % 8) - 1 << 8 - (prefix % 8); + } + return new this(octets); }; ipaddr.IPv4.broadcastAddressFromCIDR = function(string) { - var error, i, ipInterface, octets, subnetMask; + var cidr, error, i, ipInterfaceOctets, octets, subnetMaskOctets; try { - ipInterface = ipaddr.IPv4.parseCIDR(string)[0]; - subnetMask = this.subnetMaskFromPrefixLength([ipaddr.IPv4.parseCIDR(string)[1]]); + cidr = this.parseCIDR(string); + ipInterfaceOctets = cidr[0].toByteArray(); + subnetMaskOctets = this.subnetMaskFromPrefixLength(cidr[1]).toByteArray(); octets = []; i = 0; while (i < 4) { - octets.push(parseInt(ipInterface.octets[i], 10) | parseInt(subnetMask.octets[i], 10) ^ 255); + octets.push(parseInt(ipInterfaceOctets[i], 10) | parseInt(subnetMaskOctets[i], 10) ^ 255); i++; } - return new ipaddr.IPv4(octets); + return new this(octets); } catch (error1) { error = error1; throw new Error('ipaddr: the address does not have IPv4 CIDR format'); @@ -589,17 +594,18 @@ }; ipaddr.IPv4.networkAddressFromCIDR = function(string) { - var error, i, ipInterface, octets, subnetMask; + var cidr, error, i, ipInterfaceOctets, octets, subnetMaskOctets; try { - ipInterface = ipaddr.IPv4.parseCIDR(string)[0]; - subnetMask = this.subnetMaskFromPrefixLength([ipaddr.IPv4.parseCIDR(string)[1]]); + cidr = this.parseCIDR(string); + ipInterfaceOctets = cidr[0].toByteArray(); + subnetMaskOctets = this.subnetMaskFromPrefixLength(cidr[1]).toByteArray(); octets = []; i = 0; while (i < 4) { - octets.push(parseInt(ipInterface.octets[i], 10) & parseInt(subnetMask.octets[i], 10)); + octets.push(parseInt(ipInterfaceOctets[i], 10) & parseInt(subnetMaskOctets[i], 10)); i++; } - return new ipaddr.IPv4(octets); + return new this(octets); } catch (error1) { error = error1; throw new Error('ipaddr: the address does not have IPv4 CIDR format'); diff --git a/src/ipaddr.coffee b/src/ipaddr.coffee index c62847b..f03a98b 100644 --- a/src/ipaddr.coffee +++ b/src/ipaddr.coffee @@ -494,28 +494,32 @@ ipaddr.IPv4.parseCIDR = (string) -> # A utility function to return subnet mask in IPv4 format given the prefix length ipaddr.IPv4.subnetMaskFromPrefixLength = (prefix) -> + prefix = parseInt(prefix) if prefix < 0 or prefix > 32 - throw new Error('ipaddr: invalid prefix length') - octets = Array(4).fill(0) + throw new Error('ipaddr: invalid IPv4 prefix length') + octets = [0, 0, 0, 0] j = 0 - while j < Math.floor(prefix / 8) + filledOctetCount = Math.floor(prefix / 8) + while j < filledOctetCount octets[j] = 255 j++ - octets[Math.floor(prefix / 8)] = Math.pow(2, (prefix % 8)) - 1 << 8 - (prefix % 8) - new (ipaddr.IPv4)(octets) + if filledOctetCount < 4 + octets[filledOctetCount] = Math.pow(2, (prefix % 8)) - 1 << 8 - (prefix % 8) + new @(octets) # A utility function to return broadcast address given the IPv4 interface and prefix length in CIDR notation ipaddr.IPv4.broadcastAddressFromCIDR = (string) -> try - ipInterface = ipaddr.IPv4.parseCIDR(string)[0] - subnetMask = @subnetMaskFromPrefixLength([ ipaddr.IPv4.parseCIDR(string)[1] ]) + cidr = @parseCIDR(string) + ipInterfaceOctets = cidr[0].toByteArray() + subnetMaskOctets = @subnetMaskFromPrefixLength(cidr[1]).toByteArray() octets = [] i = 0 while i < 4 # Broadcast address is bitwise OR between ip interface and inverted mask - octets.push parseInt(ipInterface.octets[i], 10) | parseInt(subnetMask.octets[i], 10) ^ 255 + octets.push parseInt(ipInterfaceOctets[i], 10) | parseInt(subnetMaskOctets[i], 10) ^ 255 i++ - return new (ipaddr.IPv4)(octets) + return new @(octets) catch error throw new Error('ipaddr: the address does not have IPv4 CIDR format') return @@ -523,15 +527,16 @@ ipaddr.IPv4.broadcastAddressFromCIDR = (string) -> # A utility function to return network address given the IPv4 interface and prefix length in CIDR notation ipaddr.IPv4.networkAddressFromCIDR = (string) -> try - ipInterface = ipaddr.IPv4.parseCIDR(string)[0] - subnetMask = @subnetMaskFromPrefixLength([ ipaddr.IPv4.parseCIDR(string)[1] ]) + cidr = @parseCIDR(string) + ipInterfaceOctets = cidr[0].toByteArray() + subnetMaskOctets = @subnetMaskFromPrefixLength(cidr[1]).toByteArray() octets = [] i = 0 while i < 4 # Network address is bitwise AND between ip interface and mask - octets.push parseInt(ipInterface.octets[i], 10) & parseInt(subnetMask.octets[i], 10) + octets.push parseInt(ipInterfaceOctets[i], 10) & parseInt(subnetMaskOctets[i], 10) i++ - return new (ipaddr.IPv4)(octets) + return new @(octets) catch error throw new Error('ipaddr: the address does not have IPv4 CIDR format') return diff --git a/test/ipaddr.test.coffee b/test/ipaddr.test.coffee index 839480d..b42387d 100644 --- a/test/ipaddr.test.coffee +++ b/test/ipaddr.test.coffee @@ -401,48 +401,49 @@ module.exports = test.equal(ipaddr.IPv6.parse('ffff:0:0:ffff::%z').prefixLengthFromSubnetMask(), null) test.done() - 'subnetMaskFromPrefixLength returns correct subnet mask given prefix length': (test) -> - - test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength("0"), "0.0.0.0"); - test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength("1"), "128.0.0.0") - test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength("2"), "192.0.0.0") - test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength("3"), "224.0.0.0") - test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength("4"), "240.0.0.0") - test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength("5"), "248.0.0.0") - test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength("6"), "252.0.0.0") - test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength("7"), "254.0.0.0") - test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength("8"), "255.0.0.0"); - test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength("9"), "255.128.0.0") - test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength("10"), "255.192.0.0") - test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength("11"), "255.224.0.0") - test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength("12"), "255.240.0.0") - test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength("13"), "255.248.0.0") - test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength("14"), "255.252.0.0") - test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength("15"), "255.254.0.0") - test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength("16"), "255.255.0.0") - test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength("17"), "255.255.128.0") - test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength("18"), "255.255.192.0") - test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength("19"), "255.255.224.0") - test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength("20"), "255.255.240.0") - test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength("21"), "255.255.248.0") - test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength("22"), "255.255.252.0") - test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength("23"), "255.255.254.0") - test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength("24"), "255.255.255.0") - test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength("25"), "255.255.255.128") - test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength("26"), "255.255.255.192") - test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength("27"), "255.255.255.224") - test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength("28"), "255.255.255.240") - test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength("29"), "255.255.255.248") - test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength("30"), "255.255.255.252") - test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength("31"), "255.255.255.254") - test.done() - - 'broadcastAddressFromCIDR returns correct broadcast address': (test) -> + 'subnetMaskFromPrefixLength returns correct IPv4 subnet mask given prefix length': (test) -> + + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(0), "0.0.0.0"); + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(1), "128.0.0.0") + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(2), "192.0.0.0") + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(3), "224.0.0.0") + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(4), "240.0.0.0") + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(5), "248.0.0.0") + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(6), "252.0.0.0") + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(7), "254.0.0.0") + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(8), "255.0.0.0"); + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(9), "255.128.0.0") + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(10), "255.192.0.0") + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(11), "255.224.0.0") + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(12), "255.240.0.0") + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(13), "255.248.0.0") + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(14), "255.252.0.0") + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(15), "255.254.0.0") + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(16), "255.255.0.0") + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(17), "255.255.128.0") + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(18), "255.255.192.0") + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(19), "255.255.224.0") + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(20), "255.255.240.0") + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(21), "255.255.248.0") + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(22), "255.255.252.0") + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(23), "255.255.254.0") + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(24), "255.255.255.0") + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(25), "255.255.255.128") + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(26), "255.255.255.192") + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(27), "255.255.255.224") + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(28), "255.255.255.240") + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(29), "255.255.255.248") + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(30), "255.255.255.252") + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(31), "255.255.255.254") + test.equal(ipaddr.IPv4.subnetMaskFromPrefixLength(32), "255.255.255.255") + test.done() + + 'broadcastAddressFromCIDR returns correct IPv4 broadcast address': (test) -> test.equal(ipaddr.IPv4.broadcastAddressFromCIDR("172.0.0.1/24"), "172.0.0.255") test.equal(ipaddr.IPv4.broadcastAddressFromCIDR("172.0.0.1/26"), "172.0.0.63") test.done() - 'networkAddressFromCIDR returns correct network address': (test) -> + 'networkAddressFromCIDR returns correct IPv4 network address': (test) -> test.equal(ipaddr.IPv4.networkAddressFromCIDR("172.0.0.1/24"), "172.0.0.0") test.equal(ipaddr.IPv4.networkAddressFromCIDR("172.0.0.1/5"), "168.0.0.0") test.done()