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
						
					
					
				| 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
 |