viewgit/index.php:465 Only variables should be passed by reference [2048]

viewgit/index.php:466 Non-static method GeSHi::get_language_name_from_extension() should not be called statically [2048]

  1. # IP subnet calculator
  2. # (C) 2007 Wijnand 'tehmaze' Modderman - http://tehmaze.com
  3. # BSD License
  4. #
  5. # ABOUT
  6. # This module allows you to perform network calculations.
  7. #
  8. # CHANGELOG
  9. # 2009-03-23: Added IPv4 short-hand form support, thanks to VeXocide.
  10. # 2007-10-26: Added IPv6 support, as well as a lot of other functions,
  11. # refactored the calculations.
  12. # 2007-10-25: Initial writeup, because I could not find any other workable
  13. # implementation.
  14. #
  15. # TODO
  16. # * add CLI parser
  17. #
  18. # REFERENCES
  19. # * http://www.estoile.com/links/ipv6.pdf
  20. # * http://www.iana.org/assignments/ipv4-address-space
  21. # * http://www.iana.org/assignments/multicast-addresses
  22. # * http://www.iana.org/assignments/ipv6-address-space
  23. # * http://www.iana.org/assignments/ipv6-tla-assignments
  24. # * http://www.iana.org/assignments/ipv6-multicast-addresses
  25. # * http://www.iana.org/assignments/ipv6-anycast-addresses
  26. #
  27. # THANKS (testing, tips)
  28. # * Bastiaan (trbs)
  29. # * Peter van Dijk (Habbie)
  30. # * Hans van Kranenburg (Knorrie)
  31. # * Jeroen Habraken (VeXocide)
  32. #
  33.  
  34. __version__ = '0.3'
  35.  
  36. import types, socket
  37.  
  38. class IP(object):
  39. '''
  40. Represents a single IP address.
  41.  
  42. >>> localhost = IP("127.0.0.1")
  43. >>> print localhost
  44. 127.0.0.1
  45. >>> localhost6 = IP("::1")
  46. >>> print localhost6
  47. 0000:0000:0000:0000:0000:0000:0000:0001
  48. '''
  49.  
  50. # Hex-to-Bin conversion masks
  51. _bitmask = {
  52. '0': '0000', '1': '0001', '2': '0010', '3': '0011',
  53. '4': '0100', '5': '0101', '6': '0110', '7': '0111',
  54. '8': '1000', '9': '1001', 'a': '1010', 'b': '1011',
  55. 'c': '1100', 'd': '1101', 'e': '1110', 'f': '1111'
  56. }
  57.  
  58. # IP range specific information, see IANA allocations.
  59. _range = {
  60. 4: {
  61. '01' : 'CLASS A',
  62. '10' : 'CLASS B',
  63. '110' : 'CLASS C',
  64. '1110' : 'CLASS D MULTICAST',
  65. '11100000' : 'CLASS D LINKLOCAL',
  66. '1111' : 'CLASS E',
  67. '00001010' : 'PRIVATE RFC1918', # 10/8
  68. '101011000001' : 'PRIVATE RFC1918', # 172.16/12
  69. '1100000010101000' : 'PRIVATE RFC1918', # 192.168/16
  70. },
  71. 6: {
  72. '00000000' : 'RESERVED', # ::/8
  73. '00000001' : 'UNASSIGNED', # 100::/8
  74. '0000001' : 'NSAP', # 200::/7
  75. '0000010' : 'IPX', # 400::/7
  76. '0000011' : 'UNASSIGNED', # 600::/7
  77. '00001' : 'UNASSIGNED', # 800::/5
  78. '0001' : 'UNASSIGNED', # 1000::/4
  79. '0010000000000000' : 'RESERVED', # 2000::/16 Reserved
  80. '0010000000000001' : 'ASSIGNABLE', # 2001::/16 Sub-TLA Assignments [RFC2450]
  81. '00100000000000010000000': 'ASSIGNABLE IANA', # 2001:0000::/29 - 2001:01F8::/29 IANA
  82. '00100000000000010000001': 'ASSIGNABLE APNIC', # 2001:0200::/29 - 2001:03F8::/29 APNIC
  83. '00100000000000010000010': 'ASSIGNABLE ARIN', # 2001:0400::/29 - 2001:05F8::/29 ARIN
  84. '00100000000000010000011': 'ASSIGNABLE RIPE', # 2001:0600::/29 - 2001:07F8::/29 RIPE NCC
  85. '0010000000000010' : '6TO4', # 2002::/16 "6to4" [RFC3056]
  86. '0011111111111110' : '6BONE TEST', # 3ffe::/16 6bone Testing [RFC2471]
  87. '0011111111111111' : 'RESERVED', # 3fff::/16 Reserved
  88. '010' : 'GLOBAL-UNICAST', # 4000::/3
  89. '011' : 'UNASSIGNED', # 6000::/3
  90. '100' : 'GEO-UNICAST', # 8000::/3
  91. '101' : 'UNASSIGNED', # a000::/3
  92. '110' : 'UNASSIGNED', # c000::/3
  93. '1110' : 'UNASSIGNED', # e000::/4
  94. '11110' : 'UNASSIGNED', # f000::/5
  95. '111110' : 'UNASSIGNED', # f800::/6
  96. '1111110' : 'UNASSIGNED', # fc00::/7
  97. '111111100' : 'UNASSIGNED', # fe00::/9
  98. '1111111010' : 'LINKLOCAL', # fe80::/10
  99. '1111111011' : 'SITELOCAL', # fec0::/10
  100. '11111111' : 'MULTICAST', # ff00::/8
  101. '0' * 96 : 'IPV4COMP', # ::/96
  102. '0' * 80 + '1' * 16 : 'IPV4MAP', # ::ffff:0:0/96
  103. '0' * 128 : 'UNSPECIFIED', # ::/128
  104. '0' * 127 + '1' : 'LOOPBACK' # ::1/128
  105. }
  106. }
  107.  
  108. def __init__(self, ip, mask=None, version=0):
  109. self.mask = mask
  110. self.v = 0
  111. # Parse input
  112. if isinstance(ip, IP):
  113. self.ip = ip.ip
  114. self.dq = ip.dq
  115. self.v = ip.v
  116. self.mask = ip.mask
  117. elif type(ip) in [types.IntType, types.LongType]:
  118. self.ip = long(ip)
  119. if self.ip <= 0xffffffff:
  120. self.v = version or 4
  121. self.dq = self._itodq(ip)
  122. else:
  123. self.v = version or 4
  124. self.dq = self._itodq(ip)
  125. else:
  126. # If string is in CIDR notation
  127. if '/' in ip:
  128. ip, mask = ip.split('/', 1)
  129. self.mask = int(mask)
  130. self.v = version or 0
  131. self.dq = ip
  132. self.ip = self._dqtoi(ip)
  133. assert self.v != 0, 'Could not parse input'
  134. # Netmask defaults to one ip
  135. if self.mask is None:
  136. self.mask = self.v == 4 and 32 or 128
  137. # Validate subnet size
  138. if self.v == 6:
  139. self.dq = self._itodq(self.ip)
  140. if self.mask < 0 or self.mask > 128:
  141. raise ValueError, "IPv6 subnet size must be between 0 and 128"
  142. elif self.v == 4:
  143. if self.mask < 0 or self.mask > 32:
  144. raise ValueError, "IPv4 subnet size must be between 0 and 32"
  145.  
  146. def bin(self):
  147. '''
  148. Full-length binary representation of the IP address.
  149.  
  150. >>> ip = IP("127.0.0.1")
  151. >>> print ip.bin()
  152. 01111111000000000000000000000001
  153. '''
  154. h = hex(self.ip).lower().rstrip('l')
  155. b = ''.join(self._bitmask[x] for x in h[2:])
  156. l = self.v == 4 and 32 or 128
  157. return ''.join('0' for x in xrange(len(b), l)) + b
  158.  
  159. def hex(self):
  160. '''
  161. Full-length hexadecimal representation of the IP address.
  162.  
  163. >>> ip = IP("127.0.0.1")
  164. >>> print ip.hex()
  165. 7f000001
  166. '''
  167. if self.v == 4:
  168. return '%08x' % self.ip
  169. else:
  170. return '%032x' % self.ip
  171.  
  172. def subnet(self):
  173. return self.mask
  174.  
  175. def version(self):
  176. '''
  177. IP version.
  178.  
  179. >>> ip = IP("127.0.0.1")
  180. >>> print ip.version()
  181. 4
  182. '''
  183. return self.v
  184.  
  185. def info(self):
  186. '''
  187. Show IANA allocation information for the current IP address.
  188.  
  189. >>> ip = IP("127.0.0.1")
  190. >>> print ip.info()
  191. CLASS A
  192. '''
  193. b = self.bin()
  194. l = self.v == 4 and 32 or 128
  195. for i in range(len(b), 0, -1):
  196. if self._range[self.v].has_key(b[:i]):
  197. return self._range[self.v][b[:i]]
  198. return 'UNKNOWN'
  199.  
  200. def _dqtoi(self, dq):
  201. '''
  202. Convert dotquad or hextet to long.
  203. '''
  204. # hex notation
  205. if dq.startswith('0x'):
  206. ip = long(dq[2:], 16)
  207. if ip > 0xffffffffffffffffffffffffffffffffL:
  208. raise ValueError, "%r: IP address is bigger than 2^128" % dq
  209. if ip <= 0xffffffff:
  210. self.v = 4
  211. else:
  212. self.v = 6
  213. return ip
  214.  
  215. # IPv6
  216. if ':' in dq:
  217. hx = dq.split(':') # split hextets
  218. if ':::' in dq:
  219. raise ValueError, "%r: IPv6 address can't contain :::" % dq
  220. # Mixed address (or 4-in-6), ::ffff:192.0.2.42
  221. if '.' in dq:
  222. return self._dqtoi(hx[-1])
  223. if len(hx) > 8:
  224. raise ValueError, "%r: IPv6 address with more than 8 hexletts" % dq
  225. elif len(hx) < 8:
  226. # No :: in address
  227. if not '' in hx:
  228. raise ValueError, "%r: IPv6 address invalid: compressed format malformed" % dq
  229. elif not (dq.startswith('::') or dq.endswith('::')) and len([x for x in hx if x == '']) > 1:
  230. raise ValueError, "%r: IPv6 address invalid: compressed format malformed" % dq
  231. ix = hx.index('')
  232. px = len(hx[ix+1:])
  233. for x in xrange(ix+px+1, 8):
  234. hx.insert(ix, '0')
  235. elif dq.endswith('::'):
  236. pass
  237. elif '' in hx:
  238. raise ValueError, "%r: IPv6 address invalid: compressed format detected in full notation" % dq
  239. ip = ''
  240. hx = [x == '' and '0' or x for x in hx]
  241. for h in hx:
  242. if len(h) < 4:
  243. h = '%04x' % int(h, 16)
  244. if 0 > int(h, 16) > 0xffff:
  245. raise ValueError, "%r: IPv6 address invalid: hextets should be between 0x0000 and 0xffff" % dq
  246. ip += h
  247. self.v = 6
  248. return long(ip, 16)
  249. elif len(dq) == 32:
  250. # Assume full heximal notation
  251. self.v = 6
  252. return long(h, 16)
  253.  
  254. # IPv4
  255. if '.' in dq:
  256. q = dq.split('.')
  257. q.reverse()
  258. if len(q) > 4:
  259. raise ValueError, "%r: IPv4 address invalid: more than 4 bytes" % dq
  260. for x in q:
  261. if 0 > int(x) > 255:
  262. raise ValueError, "%r: IPv4 address invalid: bytes should be between 0 and 255" % dq
  263. while len(q) < 4:
  264. q.insert(1, '0')
  265. self.v = 4
  266. return sum(long(byte) << 8 * index for index, byte in enumerate(q))
  267.  
  268. raise ValueError, "Invalid address input"
  269.  
  270. def _itodq(self, n):
  271. '''
  272. Convert long to dotquad or hextet.
  273. '''
  274. if self.v == 4:
  275. return '.'.join(map(str, [(n>>24) & 0xff, (n>>16) & 0xff, (n>>8) & 0xff, n & 0xff]))
  276. else:
  277. n = '%032x' % n
  278. return ':'.join(n[4*x:4*x+4] for x in xrange(0, 8))
  279.  
  280. def __str__(self):
  281. '''
  282. Return dotquad representation of the IP.
  283.  
  284. >>> ip = IP("::1")
  285. >>> print str(ip)
  286. 0000:0000:0000:0000:0000:0000:0000:0001
  287. '''
  288. return self.dq
  289.  
  290. def __int__(self):
  291. return int(self.ip)
  292.  
  293. def __long__(self):
  294. return self.ip
  295.  
  296. def size(self):
  297. return 1
  298.  
  299. def clone(self):
  300. '''
  301. Return a new <IP> object with a copy of this one.
  302.  
  303. >>> ip = IP('127.0.0.1')
  304. >>> ip.clone()
  305. <ipcalc.IP object at 0xb7d4d18c>
  306. '''
  307. return IP(self)
  308.  
  309. def to_ipv4(self):
  310. '''
  311. Convert (an IPv6) IP address to an IPv4 address, if possible. Only works
  312. for IPv4-compat (::/96) and 6-to-4 (2002::/16) addresses.
  313.  
  314. >>> ip = IP('2002:c000:022a::')
  315. >>> print ip.to_ipv4()
  316. 192.0.2.42
  317. '''
  318. if self.v == 4:
  319. return self
  320. else:
  321. if self.bin().startswith('0' * 96):
  322. return IP(long(self), version=4)
  323. elif long(self) & 0x20020000000000000000000000000000L:
  324. return IP((long(self)-0x20020000000000000000000000000000L)>>80, version=4)
  325. else:
  326. return ValueError, "%r: IPv6 address is not IPv4 compatible, nor a 6-to-4 IP" % self.dq
  327.  
  328. def to_ipv6(self, type='6-to-4'):
  329. '''
  330. Convert (an IPv4) IP address to an IPv6 address.
  331.  
  332. >>> ip = IP('192.0.2.42')
  333. >>> print ip.to_ipv6()
  334. 2002:c000:022a:0000:0000:0000:0000:0000
  335. '''
  336. assert type in ['6-to-4', 'compat'], 'Conversion type not supported'
  337. if self.v == 4:
  338. if type == '6-to-4':
  339. return IP(0x20020000000000000000000000000000L | long(self)<<80, version=6)
  340. elif type == 'compat':
  341. return IP(long(self), version=6)
  342. else:
  343. return self
  344.  
  345. def to_tuple(self):
  346. '''
  347. Used for comparisons.
  348. '''
  349. return (self.dq, self.mask)
  350.  
  351. class Network(IP):
  352. '''
  353. Network slice calculations.
  354.  
  355. >>> localnet = Network('127.0.0.1/8')
  356. >>> print localnet
  357. 127.0.0.1
  358. '''
  359.  
  360. def netmask(self):
  361. '''
  362. Network netmask derived from subnet size.
  363.  
  364. >>> localnet = Network('127.0.0.1/8')
  365. >>> print localnet.netmask()
  366. 255.0.0.0
  367. '''
  368. if self.version() == 4:
  369. return IP((0xffffffffL >> (32-self.mask)) << (32-self.mask), version=self.version())
  370. else:
  371. return IP((0xffffffffffffffffffffffffffffffffL >> (128-self.mask)) << (128-self.mask), version=self.version())
  372.  
  373. def network(self):
  374. '''
  375. Network address.
  376.  
  377. >>> localnet = Network('127.128.99.3/8')
  378. >>> print localnet.network()
  379. 127.0.0.0
  380. '''
  381. return IP(self.ip & long(self.netmask()), version=self.version())
  382.  
  383. def broadcast(self):
  384. '''
  385. Broadcast address.
  386.  
  387. >>> localnet = Network('127.0.0.1/8')
  388. >>> print localnet.broadcast()
  389. 127.255.255.255
  390. '''
  391. # XXX: IPv6 doesn't have a broadcast address, but it's used for other
  392. # calculations such as <Network.host_last>.
  393. if self.version() == 4:
  394. return IP(long(self.network()) | (0xffffffff - long(self.netmask())), version=self.version())
  395. else:
  396. return IP(long(self.network()) | (0xffffffffffffffffffffffffffffffffL - long(self.netmask())), version=self.version())
  397.  
  398. def host_first(self):
  399. '''
  400. First available host in this subnet.
  401. '''
  402. if (self.version() == 4 and self.mask == 32) or (self.version() == 6 and self.mask == 128):
  403. return self
  404. return IP(long(self.network())+1, version=self.version())
  405.  
  406. def host_last(self):
  407. '''
  408. Last available host in this subnet.
  409. '''
  410. if (self.version() == 4 and self.mask == 32) or (self.version() == 6 and self.mask == 128):
  411. return self
  412. return IP(long(self.broadcast())-1, version=self.version())
  413.  
  414. def in_network(self, other):
  415. '''
  416. Check if the given IP address is within this network.
  417. '''
  418. other = Network(other)
  419. return long(other) >= long(self) and long(other) < long(self) + self.size() - other.size() + 1
  420.  
  421. def __contains__(self, ip):
  422. '''
  423. Check if the given ip is part of the network.
  424.  
  425. >>> '192.0.2.42' in Network('192.0.2.0/24')
  426. True
  427. >>> '192.168.2.42' in Network('192.0.2.0/24')
  428. False
  429. '''
  430. return self.in_network(ip)
  431.  
  432. def __lt__(self, other):
  433. return self.size() < IP(other).size()
  434.  
  435. def __le__(self, other):
  436. return self.size() <= IP(other).size()
  437.  
  438. def __gt__(self, other):
  439. return self.size() > IP(other).size()
  440.  
  441. def __ge__(self, other):
  442. return self.size() >= IP(other).size()
  443.  
  444. def __iter__(self):
  445. '''
  446. Generate a range of ip addresses within the network.
  447.  
  448. >>> for ip in Network('192.168.114.0/30'):
  449. ... print str(ip)
  450. ...
  451. 192.168.114.0
  452. 192.168.114.1
  453. 192.168.114.2
  454. 192.168.114.3
  455. '''
  456. for ip in [IP(long(self)+x) for x in xrange(0, self.size())]:
  457. yield ip
  458.  
  459. def has_key(self, ip):
  460. '''
  461. Check if the given ip is part of the network.
  462.  
  463. >>> net = Network('192.0.2.0/24')
  464. >>> net.has_key('192.168.2.0')
  465. False
  466. >>> net.has_key('192.0.2.42')
  467. True
  468. '''
  469. return self.__contains__(ip)
  470.  
  471. def size(self):
  472. '''
  473. Number of ip's within the network.
  474.  
  475. >>> net = Network('192.0.2.0/24')
  476. >>> print net.size()
  477. 256
  478. '''
  479. return 2 ** ((self.version() == 4 and 32 or 128) - self.mask)
  480.  
  481. if __name__ == '__main__':
  482. tests = [
  483. ('192.168.114.42', 23, ['192.168.0.1', '192.168.114.128', '10.0.0.1']),
  484. ('123::', 128, ['123:456::', '::1', '123::456']),
  485. ('::42', 64, ['::1', '1::']),
  486. ('2001:dead:beef:1:c01d:c01a::', 48, ['2001:dead:beef:babe::'])
  487. ]
  488.  
  489. for ip, mask, test_ip in tests:
  490. net = Network(ip, mask)
  491. print '==========='
  492. print 'ip address:', net
  493. print 'to ipv6...:', net.to_ipv6()
  494. print 'ip version:', net.version()
  495. print 'ip info...:', net.info()
  496. print 'subnet....:', net.subnet()
  497. print 'num ip\'s..:', net.size()
  498. print 'integer...:', long(net)
  499. print 'hex.......:', net.hex()
  500. print 'netmask...:', net.netmask()
  501. # Not implemented in IPv6
  502. if net.version() == 4:
  503. print 'network...:', net.network()
  504. print 'broadcast.:', net.broadcast()
  505. print 'first host:', net.host_first()
  506. print 'last host.:', net.host_last()
  507. for ip in test_ip:
  508. print '%s in network: ' % ip, ip in net
  509.