Skip to content

Commit

Permalink
BREAKING CHANGE: fix parsing of IPs with less than 4 bytes
Browse files Browse the repository at this point in the history
Previous API was treating IPs with less than for bytes as IP with a
netmask of the size of the provided bytes (1=8, 2=16, 3=24) and was
interpreting the IP as if it was completed with 0s on the right side.

Propre IP parsing for these is to consider missing bytes as being 0s on
the left side.

Mask size is no longer infered by the number of bytes provided.
  • Loading branch information
rs committed Mar 19, 2021
1 parent ec1b5b5 commit 9f9fc38
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 24 deletions.
10 changes: 4 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,9 @@ Netmask objects are created with an IP address and optionally a mask. There are
'216.240.32.0', '255.255.255.0'
'216.240.32.0', 0xffffff00
'216.240.32.4' // A /32 block.
'216.240.32' // A /24 block.
'216.240' // A /16 block.
'140' // A /8 block.
'216.240.32/24'
'216.240/16'
'0330.0360.040.04' // Octal form
'0xd8.0xf0.0x20.0x4' // Hex form


API
---
Expand All @@ -67,7 +65,7 @@ License

(The MIT License)

Copyright (c) 2011 Olivier Poitrey <rs@dailymotion.com>
Copyright (c) 2011 Olivier Poitrey <rs@rhapsodyk.net>

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

Expand Down
14 changes: 5 additions & 9 deletions lib/netmask.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ ip2long = (ip) ->
if isNaN(byte) then throw new Error("Invalid byte: #{byte}")
if byte < 0 or byte > 255 then throw new Error("Invalid byte: #{byte}")
b[i] = byte
return ((b[0] or 0) << 24 | (b[1] or 0) << 16 | (b[2] or 0) << 8 | (b[3] or 0)) >>> 0
while b.length < 4
b.unshift(0)
return (b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3]) >>> 0


class Netmask
Expand All @@ -31,13 +33,7 @@ class Netmask
# try to find the mask in the net (i.e.: 1.2.3.4/24 or 1.2.3.4/255.255.255.0)
[net, mask] = net.split('/', 2)
unless mask
switch net.split('.').length
when 1 then mask = 8
when 2 then mask = 16
when 3 then mask = 24
when 4 then mask = 32
else throw new Error("Invalid net address: #{net}")

mask = 32
if typeof mask is 'string' and mask.indexOf('.') > -1
# Compute bitmask, the netmask as a number of bits in the network portion of the address for this block (eg.: 24)
try
Expand All @@ -48,7 +44,7 @@ class Netmask
if @maskLong == (0xffffffff << (32 - i)) >>> 0
@bitmask = i
break
else if mask
else if mask or mask == 0
# The mask was passed as bitmask, compute the mask as long from it
@bitmask = parseInt(mask, 10)
@maskLong = 0
Expand Down
29 changes: 20 additions & 9 deletions test/netmasks.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ fixtures =
['209.157.68.22', '255.255.224.0', '209.157.64.0', '255.255.224.0', 19]
['209.157.70.33/19', null, '209.157.64.0', '255.255.224.0', 19]
['209.157.70.33', null, '209.157.70.33', '255.255.255.255', 32]
['140.174.82', null, '140.174.82.0', '255.255.255.0', 24]
['140.174', null, '140.174.0.0', '255.255.0.0', 16]
['10', null, '10.0.0.0', '255.0.0.0', 8]
['10/8', null, '10.0.0.0', '255.0.0.0', 8]
['209.157.64/19', null, '209.157.64.0', '255.255.224.0', 19]
['140.174.82', null, '0.140.174.82', '255.255.255.255', 32]
['140.174', null, '0.0.140.174', '255.255.255.255', 32]
['10', null, '0.0.0.10', '255.255.255.255', 32]
['10/8', null, '0.0.0.0', '255.0.0.0', 8]
['209.157.64/19', null, '0.209.128.0', '255.255.224.0', 19]
['216.140.48.16/32', null, '216.140.48.16', '255.255.255.255', 32]
['209.157/17', null, '209.157.0.0', '255.255.128.0', 17]
['209.157/17', null, '0.0.128.0', '255.255.128.0', 17]
['0.0.0.0/0', null, '0.0.0.0', '0.0.0.0', 0]
]

Expand Down Expand Up @@ -45,14 +45,15 @@ vows.describe('Netmask contains IP')
'does not contain IP 10.168.2.0': (block) -> assert.ok not block.contains('10.168.2.0')
'does not contain IP 209.168.2.0': (block) -> assert.ok not block.contains('209.168.2.0')
'contains block 192.168.1.0/24': (block) -> assert.ok block.contains('192.168.1.0/24')
'contains block 192.168.1': (block) -> assert.ok block.contains('192.168.1')
'contains block 192.168.1.128/25': (block) -> assert.ok block.contains('192.168.1.128/25')
'contains block 192.168.1 (0.192.168.10)': (block) -> assert.ok not block.contains('192.168.1')
'does not contains block 192.168.1.128/25': (block) -> assert.ok block.contains('192.168.1.128/25')
'does not contain block 192.168.1.0/23': (block) -> assert.ok not block.contains('192.168.1.0/23')
'does not contain block 192.168.2.0/24': (block) -> assert.ok not block.contains('192.168.2.0/24')
'toString equals 192.168.1.0/24': (block) -> assert.equal block.toString(), '192.168.1.0/24'
'block 192.168.0.0/24':
topic: -> new Netmask('192.168.0.0/24')
'does not contain block 192.168': (block) -> assert.ok not block.contains('192.168')
'does not contain block 192.168 (0.0.192.168)': (block) -> assert.ok not block.contains('192.168')
'does not contain block 192.168.0.0/16': (block) -> assert.ok not block.contains('192.168.0.0/16')
'block 31.0.0.0/8':
topic: -> new Netmask('31.0.0.0/8')
'contains IP 31.5.5.5': (block) -> assert.ok block.contains('31.5.5.5')
Expand All @@ -64,6 +65,16 @@ vows.describe('Netmask contains IP')
'contains IP 127.0.0.2': (block) -> assert.ok block.contains('127.0.0.2')
'contains IP 0177.0.0.2 (127.0.0.2)': (block) -> assert.ok block.contains('0177.0.0.2')
'contains IP 0x7f.0.0.2 (127.0.0.2)': (block) -> assert.ok block.contains('0x7f.0.0.2')
'does not contains IP 127 (0.0.0.127)': (block) -> assert.ok not block.contains('127')
'does not contains IP 0177 (0.0.0.127)': (block) -> assert.ok not block.contains('0177')
'block 0.0.0.0/24':
topic: -> new Netmask('0.0.0.0/0')
'contains IP 0.0.0.0': (block) -> assert.ok block.contains('0.0.0.0')
'contains IP 0': (block) -> assert.ok block.contains('0')
'contains IP 10 (0.0.0.10)': (block) -> assert.ok block.contains('10')
'contains IP 010 (0.0.0.8)': (block) -> assert.ok block.contains('010')
'contains IP 0x10 (0.0.0.16)': (block) -> assert.ok block.contains('0x10')

.export(module)

vows.describe('Netmask forEach')
Expand Down

0 comments on commit 9f9fc38

Please sign in to comment.