long2ip = (long) -> a = (long & (0xff << 24)) >>> 24; b = (long & (0xff << 16)) >>> 16; c = (long & (0xff << 8)) >>> 8; d = long & 0xff; return [a, b, c, d].join('.') ip2long = (ip) -> b = (ip + '').split('.'); if b.length is 0 or b.length > 4 then throw new Error('Invalid IP') for byte, i in b if isNaN parseInt(byte, 10) then throw new Error("Invalid byte: #{byte}") if byte < 0 or byte > 255 then throw new Error("Invalid byte: #{byte}") return ((b[0] or 0) << 24 | (b[1] or 0) << 16 | (b[2] or 0) << 8 | (b[3] or 0)) >>> 0 class Netmask constructor: (net, mask) -> throw new Error("Missing `net' parameter") unless typeof net is 'string' unless mask # 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}") 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 @maskLong = ip2long(mask) catch error throw new Error("Invalid mask: #{mask}") for i in [32..0] if @maskLong == (0xffffffff << (32 - i)) >>> 0 @bitmask = i break else if mask # The mask was passed as bitmask, compute the mask as long from it @bitmask = parseInt(mask, 10) @maskLong = 0 if @bitmask > 0 @maskLong = (0xffffffff << (32 - @bitmask)) >>> 0 else throw new Error("Invalid mask: empty") try @netLong = (ip2long(net) & @maskLong) >>> 0 catch error throw new Error("Invalid net address: #{net}") throw new Error("Invalid mask for ip4: #{mask}") unless @bitmask <= 32 # The number of IP address in the block (eg.: 254) @size = Math.pow(2, 32 - @bitmask) # The address of the network block as a string (eg.: 216.240.32.0) @base = long2ip(@netLong) # The netmask as a string (eg.: 255.255.255.0) @mask = long2ip(@maskLong) # The host mask, the opposite of the netmask (eg.: 0.0.0.255) @hostmask = long2ip(~@maskLong) # The first usable address of the block @first = if @bitmask <= 30 then long2ip(@netLong + 1) else @base # The last usable address of the block @last = if @bitmask <= 30 then long2ip(@netLong + @size - 2) else long2ip(@netLong + @size - 1) # The block's broadcast address: the last address of the block (eg.: 192.168.1.255) @broadcast = if @bitmask <= 30 then long2ip(@netLong + @size - 1) # Returns true if the given ip or netmask is contained in the block contains: (ip) -> if typeof ip is 'string' and (ip.indexOf('/') > 0 or ip.split('.').length isnt 4) ip = new Netmask(ip) if ip instanceof Netmask return @contains(ip.base) and @contains((ip.broadcast || ip.last)) else return (ip2long(ip) & @maskLong) >>> 0 == ((@netLong & @maskLong)) >>> 0 # Returns the Netmask object for the block which follow this one next: (count=1) -> return new Netmask(long2ip(@netLong + (@size * count)), @mask) forEach: (fn) -> range = [ip2long(@first)..ip2long(@last)] fn long2ip(long), long, index for long, index in range # Returns the complete netmask formatted as `base/bitmask` toString: -> return @base + "/" + @bitmask exports.ip2long = ip2long exports.long2ip = long2ip exports.Netmask = Netmask