routes.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. """
  4. routines for getting route information
  5. """
  6. # by Benjamin C. Wiley Sittler
  7. __all__ = [
  8. 'getroutes',
  9. 'main',
  10. 'RTF_UP',
  11. 'RTF_GATEWAY',
  12. 'RTF_HOST',
  13. 'RTF_REINSTATE',
  14. 'RTF_DYNAMIC',
  15. 'RTF_MODIFIED',
  16. 'RTF_MTU',
  17. 'RTF_MSS',
  18. 'RTF_WINDOW',
  19. 'RTF_IRTT',
  20. 'RTF_REJECT',
  21. 'RTF_STATIC',
  22. 'RTF_XRESOLVE',
  23. 'RTF_NOFORWARD',
  24. 'RTF_THROW',
  25. 'RTF_NOPMTUDISC',
  26. 'RTF_DEFAULT',
  27. 'RTF_ALLONLINK',
  28. 'RTF_ADDRCONF',
  29. 'RTF_LINKRT',
  30. 'RTF_NONEXTHOP',
  31. 'RTF_CACHE',
  32. 'RTF_FLOW',
  33. 'RTF_POLICY',
  34. 'RTF_LOCAL',
  35. 'RTF_INTERFACE',
  36. 'RTF_MULTICAST',
  37. 'RTF_BROADCAST',
  38. 'RTF_NAT',
  39. 'RTF_ADDRCLASSMASK',
  40. ]
  41. import os
  42. import socket
  43. import struct
  44. from BTL.obsoletepythonsupport import set
  45. class NamedLong(long):
  46. def __new__(self, name, value):
  47. self._long = long.__new__(self, value)
  48. self._long._name = name
  49. return self._long
  50. def __repr__(self):
  51. return self._name
  52. pass
  53. class OrSet(set):
  54. def __repr__(self):
  55. return ' | '.join([ repr(x) for x in self ])
  56. RTF_UP = NamedLong(name = 'RTF_UP', value = 0x0001)
  57. RTF_GATEWAY = NamedLong(name = 'RTF_GATEWAY', value = 0x0002)
  58. RTF_HOST = NamedLong(name = 'RTF_HOST', value = 0x0004)
  59. RTF_REINSTATE = NamedLong(name = 'RTF_REINSTATE', value = 0x0008)
  60. RTF_DYNAMIC = NamedLong(name = 'RTF_DYNAMIC', value = 0x0010)
  61. RTF_MODIFIED = NamedLong(name = 'RTF_MODIFIED', value = 0x0020)
  62. RTF_MTU = NamedLong(name = 'RTF_MTU', value = 0x0040)
  63. RTF_MSS = NamedLong(name = 'RTF_MSS', value = RTF_MTU)
  64. RTF_WINDOW = NamedLong(name = 'RTF_WINDOW', value = 0x0080)
  65. RTF_IRTT = NamedLong(name = 'RTF_IRTT', value = 0x0100)
  66. RTF_REJECT = NamedLong(name = 'RTF_REJECT', value = 0x0200)
  67. RTF_STATIC = NamedLong(name = 'RTF_STATIC', value = 0x0400)
  68. RTF_XRESOLVE = NamedLong(name = 'RTF_XRESOLVE', value = 0x0800)
  69. RTF_NOFORWARD = NamedLong(name = 'RTF_NOFORWARD', value = 0x1000)
  70. RTF_THROW = NamedLong(name = 'RTF_THROW', value = 0x2000)
  71. RTF_NOPMTUDISC = NamedLong(name = 'RTF_NOPMTUDISC', value = 0x4000)
  72. RTF_DEFAULT = NamedLong(name = 'RTF_DEFAULT', value = 0x00010000)
  73. RTF_ALLONLINK = NamedLong(name = 'RTF_ALLONLINK', value = 0x00020000)
  74. RTF_ADDRCONF = NamedLong(name = 'RTF_ADDRCONF', value = 0x00040000)
  75. RTF_LINKRT = NamedLong(name = 'RTF_LINKRT', value = 0x00100000)
  76. RTF_NONEXTHOP = NamedLong(name = 'RTF_NONEXTHOP', value = 0x00200000)
  77. RTF_CACHE = NamedLong(name = 'RTF_CACHE', value = 0x01000000)
  78. RTF_FLOW = NamedLong(name = 'RTF_FLOW', value = 0x02000000)
  79. RTF_POLICY = NamedLong(name = 'RTF_POLICY', value = 0x04000000)
  80. RTF_LOCAL = NamedLong(name = 'RTF_LOCAL', value = 0x80000000)
  81. RTF_INTERFACE = NamedLong(name = 'RTF_INTERFACE', value = 0x40000000)
  82. RTF_MULTICAST = NamedLong(name = 'RTF_MULTICAST', value = 0x20000000)
  83. RTF_BROADCAST = NamedLong(name = 'RTF_BROADCAST', value = 0x10000000)
  84. RTF_NAT = NamedLong(name = 'RTF_NAT', value = 0x08000000)
  85. RTF_ADDRCLASSMASK = NamedLong(name = 'RTF_ADDRCLASSMASK', value = 0xF8000000)
  86. def NamedLongs(x, names):
  87. s = OrSet()
  88. for k in names:
  89. if x & k:
  90. s |= OrSet([k])
  91. x ^= k
  92. k = 1L
  93. while x:
  94. if x & k:
  95. s |= OrSet([k])
  96. x ^= k
  97. k+=k
  98. return s
  99. def flagset(flagbits):
  100. if isinstance(flagbits, set):
  101. return flagbits
  102. return NamedLongs(flagbits,
  103. (RTF_UP,
  104. RTF_GATEWAY,
  105. RTF_HOST,
  106. RTF_REINSTATE,
  107. RTF_DYNAMIC,
  108. RTF_MODIFIED,
  109. RTF_MTU,
  110. RTF_MSS,
  111. RTF_WINDOW,
  112. RTF_IRTT,
  113. RTF_REJECT,
  114. RTF_STATIC,
  115. RTF_XRESOLVE,
  116. RTF_NOFORWARD,
  117. RTF_THROW,
  118. RTF_NOPMTUDISC,
  119. RTF_DEFAULT,
  120. RTF_ALLONLINK,
  121. RTF_ADDRCONF,
  122. RTF_LINKRT,
  123. RTF_NONEXTHOP,
  124. RTF_CACHE,
  125. RTF_FLOW,
  126. RTF_POLICY,
  127. RTF_LOCAL,
  128. RTF_INTERFACE,
  129. RTF_MULTICAST,
  130. RTF_BROADCAST,
  131. RTF_NAT,
  132. RTF_ADDRCLASSMASK,
  133. ))
  134. def addrfamily(family):
  135. return ([ x for x in [ NamedLong(n, getattr(socket, n)) for n in dir(socket) if n[:len('AF_')] == 'AF_' ] if x == family ] + [ family ])[0]
  136. def getroutes(family = None, flags = OrSet([RTF_UP]), name = None):
  137. """
  138. This generator yields matching routes one-by-one. If the optional
  139. family parameter is not None, only routes for the given address
  140. family (AF_INET or AF_INET6) are yielded. If the optional name
  141. parameter is not None, only routes for the given interface are
  142. yielded.
  143. """
  144. uname = os.uname()
  145. assert uname[0] == 'Linux' and [ int(x) for x in uname[2].split('.')[:2] ] >= [ 2, 2 ]
  146. assert family in (None, socket.AF_INET, socket.AF_INET6)
  147. routes = []
  148. if family is None or family == socket.AF_INET:
  149. routes_ipv4 = [ line.rstrip(' ').split() for line in file('/proc/net/route').read().splitlines() ]
  150. routes_ipv4 = [ dict([('family', socket.AF_INET)] + [ (routes_ipv4[0][i].strip().lower(), route[i]) for i in range(len(route)) ]) for route in routes_ipv4[1:] ]
  151. routes = routes + routes_ipv4
  152. if family is None or family == socket.AF_INET6:
  153. routes_ipv6 = [ line.rstrip(' ').split() for line in file('/proc/net/ipv6_route').read().splitlines() ]
  154. routes_ipv6 = [ dict([('family', socket.AF_INET6)] + [ (('destination', 'destination_prefixlen', 'source', 'source_prefixlen', 'gateway', 'metric', 'refcnt', 'use', 'flags', 'iface')[i], route[i]) for i in range(len(route)) ]) for route in routes_ipv6 ]
  155. routes = routes + routes_ipv6
  156. for route in routes:
  157. route['family'] = addrfamily(route['family'])
  158. for field in ('flags', 'refcnt', 'use', 'metric', 'mtu', 'window', 'irtt', 'source_prefixlen', 'destination_prefixlen'):
  159. if field in route:
  160. route[field] = int(route[field], 16)
  161. for field in ('destination', 'gateway', 'mask', 'source'):
  162. if field in route:
  163. route[field] = route[field].decode('hex')
  164. if route['family'] == socket.AF_INET:
  165. route[field] = struct.pack('!I', struct.unpack('I', route[field])[0])
  166. try:
  167. route[field] = socket.inet_ntop(route['family'], route[field])
  168. except:
  169. route[field] = route[field].encode('hex')
  170. if 'flags' in route:
  171. route['flags'] = flagset(route['flags'])
  172. if family is not None and route['family'] != family:
  173. continue
  174. for flag in flagset(flags or 0):
  175. if flag not in flagset(route.get('flags', 0)):
  176. break
  177. else:
  178. if name is not None and route.get('iface') != name:
  179. continue
  180. yield route
  181. def main():
  182. print 'all route details:'
  183. for route in getroutes():
  184. print '\troute' + (
  185. ('destination' in route) and (' to ' + str(route.get('destination')) + (('destination_prefixlen' in route) and ('/' + str(route['destination_prefixlen'])) or (('mask' in route) and ('/' + str(route['mask'])) or ''))) or '') + (
  186. ('source' in route) and (' from ' + str(route['source']) + (('source_prefixlen' in route) and ('/' + str(route['source_prefixlen'])) or '')) or '') + (
  187. ('gateway' in route) and (' via ' + str(route['gateway'])) or '')
  188. rtkeys = route.keys()
  189. rtkeys.sort()
  190. for field in rtkeys:
  191. print '\t\t' + field, `route[field]`
  192. if __name__ == '__main__':
  193. main()