You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					168 lines
				
				5.6 KiB
			
		
		
			
		
	
	
					168 lines
				
				5.6 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								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 = []
							 | 
						||
| 
								 | 
							
								    for i in [0..3]
							 | 
						||
| 
								 | 
							
								        if ip.length == 0
							 | 
						||
| 
								 | 
							
								            break
							 | 
						||
| 
								 | 
							
								        if i > 0
							 | 
						||
| 
								 | 
							
								            if ip[0] != '.'
							 | 
						||
| 
								 | 
							
								                throw new Error('Invalid IP')
							 | 
						||
| 
								 | 
							
								            ip = ip.substring(1)
							 | 
						||
| 
								 | 
							
								        [n, c] = atob(ip)
							 | 
						||
| 
								 | 
							
								        ip = ip.substring(c)
							 | 
						||
| 
								 | 
							
								        b.push(n)
							 | 
						||
| 
								 | 
							
								    if ip.length != 0
							 | 
						||
| 
								 | 
							
								        throw new Error('Invalid IP')
							 | 
						||
| 
								 | 
							
								    switch b.length
							 | 
						||
| 
								 | 
							
								        when 1
							 | 
						||
| 
								 | 
							
								            # Long input notation
							 | 
						||
| 
								 | 
							
								            if b[0] > 0xFFFFFFFF
							 | 
						||
| 
								 | 
							
								                throw new Error('Invalid IP')
							 | 
						||
| 
								 | 
							
								            return b[0] >>> 0
							 | 
						||
| 
								 | 
							
								        when 2
							 | 
						||
| 
								 | 
							
								            # Class A notation
							 | 
						||
| 
								 | 
							
								            if b[0] > 0xFF or b[1] > 0xFFFFFF
							 | 
						||
| 
								 | 
							
								                throw new Error('Invalid IP')
							 | 
						||
| 
								 | 
							
								            return (b[0] << 24 | b[1]) >>> 0
							 | 
						||
| 
								 | 
							
								        when 3
							 | 
						||
| 
								 | 
							
								            # Class B notation
							 | 
						||
| 
								 | 
							
								            if b[0] > 0xFF or b[1] > 0xFF or b[2] > 0xFFFF
							 | 
						||
| 
								 | 
							
								                throw new Error('Invalid IP')
							 | 
						||
| 
								 | 
							
								            return (b[0] << 24 | b[1] << 16 | b[2]) >>> 0
							 | 
						||
| 
								 | 
							
								        when 4
							 | 
						||
| 
								 | 
							
								            # Dotted quad notation 
							 | 
						||
| 
								 | 
							
								            if b[0] > 0xFF or b[1] > 0xFF or b[2] > 0xFF or b[3] > 0xFF
							 | 
						||
| 
								 | 
							
								                throw new Error('Invalid IP')
							 | 
						||
| 
								 | 
							
								            return (b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3]) >>> 0
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								            throw new Error('Invalid IP')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								chr = (b) ->
							 | 
						||
| 
								 | 
							
								    return b.charCodeAt(0)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								chr0 = chr('0')
							 | 
						||
| 
								 | 
							
								chra = chr('a')
							 | 
						||
| 
								 | 
							
								chrA = chr('A')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								atob = (s) ->
							 | 
						||
| 
								 | 
							
								    n = 0
							 | 
						||
| 
								 | 
							
								    base = 10
							 | 
						||
| 
								 | 
							
								    dmax = '9'
							 | 
						||
| 
								 | 
							
								    i = 0
							 | 
						||
| 
								 | 
							
								    if s.length > 1 and s[i] == '0'
							 | 
						||
| 
								 | 
							
								        if s[i+1] == 'x' or s[i+1] == 'X'
							 | 
						||
| 
								 | 
							
								            i += 2
							 | 
						||
| 
								 | 
							
								            base = 16
							 | 
						||
| 
								 | 
							
								        else if '0' <= s[i+1] and s[i+1] <= '9'
							 | 
						||
| 
								 | 
							
								            i++
							 | 
						||
| 
								 | 
							
								            base = 8
							 | 
						||
| 
								 | 
							
								            dmax = '7'
							 | 
						||
| 
								 | 
							
								    start = i
							 | 
						||
| 
								 | 
							
								    while i < s.length
							 | 
						||
| 
								 | 
							
								        if '0' <= s[i] and s[i] <= dmax
							 | 
						||
| 
								 | 
							
								            n = (n*base + (chr(s[i])-chr0)) >>> 0
							 | 
						||
| 
								 | 
							
								        else if base == 16
							 | 
						||
| 
								 | 
							
								            if 'a' <= s[i] and s[i] <= 'f'
							 | 
						||
| 
								 | 
							
								                n = (n*base + (10+chr(s[i])-chra)) >>> 0
							 | 
						||
| 
								 | 
							
								            else if 'A' <= s[i] and s[i] <= 'F'
							 | 
						||
| 
								 | 
							
								                n = (n*base + (10+chr(s[i])-chrA)) >>> 0
							 | 
						||
| 
								 | 
							
								            else
							 | 
						||
| 
								 | 
							
								                break
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								            break
							 | 
						||
| 
								 | 
							
								        if n > 0xFFFFFFFF
							 | 
						||
| 
								 | 
							
								            throw new Error('too large')
							 | 
						||
| 
								 | 
							
								        i++
							 | 
						||
| 
								 | 
							
								    if i == start
							 | 
						||
| 
								 | 
							
								        throw new Error('empty octet')
							 | 
						||
| 
								 | 
							
								    return [n, i]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								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
							 | 
						||
| 
								 | 
							
								            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
							 | 
						||
| 
								 | 
							
								                @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 or mask == 0
							 | 
						||
| 
								 | 
							
								            # 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) ->
							 | 
						||
| 
								 | 
							
								        # this implementation is not idiomatic but avoids large memory allocations (2 arrays, one for range and one for the results) in cases when then netmask is large
							 | 
						||
| 
								 | 
							
								        long = ip2long(@first)
							 | 
						||
| 
								 | 
							
								        lastLong = ip2long(@last)
							 | 
						||
| 
								 | 
							
								        index = 0
							 | 
						||
| 
								 | 
							
								        while long <= lastLong
							 | 
						||
| 
								 | 
							
								          fn long2ip(long), long, index
							 | 
						||
| 
								 | 
							
								          index++
							 | 
						||
| 
								 | 
							
								          long++
							 | 
						||
| 
								 | 
							
								        return
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Returns the complete netmask formatted as `base/bitmask`
							 | 
						||
| 
								 | 
							
								    toString: ->
							 | 
						||
| 
								 | 
							
								        return @base + "/" + @bitmask
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								exports.ip2long = ip2long
							 | 
						||
| 
								 | 
							
								exports.long2ip = long2ip
							 | 
						||
| 
								 | 
							
								exports.Netmask = Netmask
							 |