subnetparse.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. # Written by John Hoffman
  2. # see LICENSE.txt for license information
  3. from bisect import bisect, insort
  4. try:
  5. True
  6. except:
  7. True = 1
  8. False = 0
  9. bool = lambda x: not not x
  10. hexbinmap = {
  11. '0': '0000',
  12. '1': '0001',
  13. '2': '0010',
  14. '3': '0011',
  15. '4': '0100',
  16. '5': '0101',
  17. '6': '0110',
  18. '7': '0111',
  19. '8': '1000',
  20. '9': '1001',
  21. 'a': '1010',
  22. 'b': '1011',
  23. 'c': '1100',
  24. 'd': '1101',
  25. 'e': '1110',
  26. 'f': '1111',
  27. 'x': '0000',
  28. }
  29. chrbinmap = {}
  30. for n in xrange(256):
  31. b = []
  32. nn = n
  33. for i in xrange(8):
  34. if nn & 0x80:
  35. b.append('1')
  36. else:
  37. b.append('0')
  38. nn <<= 1
  39. chrbinmap[n] = ''.join(b)
  40. def to_bitfield_ipv4(ip):
  41. ip = ip.split('.')
  42. if len(ip) != 4:
  43. raise ValueError, "bad address"
  44. b = []
  45. for i in ip:
  46. b.append(chrbinmap[int(i)])
  47. return ''.join(b)
  48. def to_bitfield_ipv6(ip):
  49. b = ''
  50. doublecolon = False
  51. if ip == '':
  52. raise ValueError, "bad address"
  53. if ip == '::': # boundary handling
  54. ip = ''
  55. elif ip[:2] == '::':
  56. ip = ip[1:]
  57. elif ip[0] == ':':
  58. raise ValueError, "bad address"
  59. elif ip[-2:] == '::':
  60. ip = ip[:-1]
  61. elif ip[-1] == ':':
  62. raise ValueError, "bad address"
  63. for n in ip.split(':'):
  64. if n == '': # double-colon
  65. if doublecolon:
  66. raise ValueError, "bad address"
  67. doublecolon = True
  68. b += ':'
  69. continue
  70. if n.find('.') >= 0: # IPv4
  71. n = to_bitfield_ipv4(n)
  72. b += n + '0'*(32-len(n))
  73. continue
  74. n = ('x'*(4-len(n))) + n
  75. for i in n:
  76. b += hexbinmap[i]
  77. if doublecolon:
  78. pos = b.find(':')
  79. b = b[:pos]+('0'*(129-len(b)))+b[pos+1:]
  80. if len(b) != 128: # always check size
  81. raise ValueError, "bad address"
  82. return b
  83. ipv4addrmask = to_bitfield_ipv6('::ffff:0:0')[:96]
  84. class IP_List:
  85. def __init__(self, entrylist=None):
  86. self.ipv4list = []
  87. self.ipv6list = []
  88. if entrylist:
  89. for ip, depth in entrylist:
  90. self._append(ip,depth)
  91. self.ipv4list.sort()
  92. self.ipv6list.sort()
  93. def __nonzero__(self):
  94. return bool(self.ipv4list or self.ipv6list)
  95. def _append(self, ip, depth = 256):
  96. if ip.find(':') < 0: # IPv4
  97. self.ipv4list.append(to_bitfield_ipv4(ip)[:depth])
  98. else:
  99. b = to_bitfield_ipv6(ip)
  100. if b.startswith(ipv4addrmask):
  101. self.ipv4list.append(b[96:][:depth-96])
  102. else:
  103. self.ipv6list.append(b[:depth])
  104. def append(self, ip, depth = 256):
  105. if ip.find(':') < 0: # IPv4
  106. insort(self.ipv4list,to_bitfield_ipv4(ip)[:depth])
  107. else:
  108. b = to_bitfield_ipv6(ip)
  109. if b.startswith(ipv4addrmask):
  110. insort(self.ipv4list,b[96:][:depth-96])
  111. else:
  112. insort(self.ipv6list,b[:depth])
  113. def includes(self, ip):
  114. if not (self.ipv4list or self.ipv6list):
  115. return False
  116. if ip.find(':') < 0: # IPv4
  117. b = to_bitfield_ipv4(ip)
  118. else:
  119. b = to_bitfield_ipv6(ip)
  120. if b.startswith(ipv4addrmask):
  121. b = b[96:]
  122. if len(b) > 32:
  123. l = self.ipv6list
  124. else:
  125. l = self.ipv4list
  126. for map in l[bisect(l,b)-1:]:
  127. if b.startswith(map):
  128. return True
  129. if map > b:
  130. return False
  131. return False
  132. def read_fieldlist(self, file): # reads a list from a file in the format 'ip/len <whatever>'
  133. f = open(file, 'r')
  134. while True:
  135. line = f.readline()
  136. if not line:
  137. break
  138. line = line.strip().expandtabs()
  139. if not line or line[0] == '#':
  140. continue
  141. try:
  142. line, garbage = line.split(' ',1)
  143. except:
  144. pass
  145. try:
  146. line, garbage = line.split('#',1)
  147. except:
  148. pass
  149. try:
  150. ip, depth = line.split('/')
  151. except:
  152. ip = line
  153. depth = None
  154. try:
  155. if depth is not None:
  156. depth = int(depth)
  157. self._append(ip,depth)
  158. except:
  159. print '*** WARNING *** could not parse IP range: '+line
  160. f.close()
  161. self.ipv4list.sort()
  162. self.ipv6list.sort()
  163. def set_intranet_addresses(self):
  164. self.append('127.0.0.1',8)
  165. self.append('10.0.0.0',8)
  166. self.append('172.16.0.0',12)
  167. self.append('192.168.0.0',16)
  168. self.append('169.254.0.0',16)
  169. self.append('::1')
  170. self.append('fe80::',16)
  171. self.append('fec0::',16)
  172. def set_ipv4_addresses(self):
  173. self.append('::ffff:0:0',96)
  174. def ipv6_to_ipv4(ip):
  175. ip = to_bitfield_ipv6(ip)
  176. if not ip.startswith(ipv4addrmask):
  177. raise ValueError, "not convertible to IPv4"
  178. ip = ip[-32:]
  179. x = ''
  180. for i in range(4):
  181. x += str(int(ip[:8],2))
  182. if i < 3:
  183. x += '.'
  184. ip = ip[8:]
  185. return x
  186. def to_ipv4(ip):
  187. if is_ipv4(ip):
  188. _valid_ipv4(ip)
  189. return ip
  190. return ipv6_to_ipv4(ip)
  191. def is_ipv4(ip):
  192. return ip.find(':') < 0
  193. def _valid_ipv4(ip):
  194. ip = ip.split('.')
  195. if len(ip) != 4:
  196. raise ValueError
  197. for i in ip:
  198. chr(int(i))
  199. def is_valid_ip(ip):
  200. try:
  201. if not ip:
  202. return False
  203. if is_ipv4(ip):
  204. _valid_ipv4(ip)
  205. return True
  206. to_bitfield_ipv6(ip)
  207. return True
  208. except:
  209. return False