bgp.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. """
  2. Border Gateway Protocol.
  3. """
  4. from pypacker import pypacker, triggerlist
  5. import logging
  6. logger = logging.getLogger("pypacker")
  7. # Border Gateway Protocol 4 - RFC 4271
  8. # Communities Attribute - RFC 1997
  9. # Capabilities - RFC 3392
  10. # Route Refresh - RFC 2918
  11. # Route Reflection - RFC 4456
  12. # Confederations - RFC 3065
  13. # Cease Subcodes - RFC 4486
  14. # NOPEER Community - RFC 3765
  15. # Multiprotocol Extensions - 2858
  16. # Message Types
  17. OPEN = 1
  18. UPDATE = 2
  19. NOTIFICATION = 3
  20. KEEPALIVE = 4
  21. ROUTE_REFRESH = 5
  22. # Attribute Types
  23. ORIGIN = 1
  24. AS_PATH = 2
  25. NEXT_HOP = 3
  26. MULTI_EXIT_DISC = 4
  27. LOCAL_PREF = 5
  28. ATOMIC_AGGREGATE = 6
  29. AGGREGATOR = 7
  30. COMMUNITIES = 8
  31. ORIGINATOR_ID = 9
  32. CLUSTER_LIST = 10
  33. MP_REACH_NLRI = 14
  34. MP_UNREACH_NLRI = 15
  35. # Origin Types
  36. ORIGIN_IGP = 0
  37. ORIGIN_EGP = 1
  38. INCOMPLETE = 2
  39. # AS Path Types
  40. AS_SET = 1
  41. AS_SEQUENCE = 2
  42. AS_CONFED_SEQUENCE = 3
  43. AS_CONFED_SET = 4
  44. # Reserved Communities Types
  45. NO_EXPORT = 0xffffff01
  46. NO_ADVERTISE = 0xffffff02
  47. NO_EXPORT_SUBCONFED = 0xffffff03
  48. NO_PEER = 0xffffff04
  49. # Common AFI types
  50. AFI_IPV4 = 1
  51. AFI_IPV6 = 2
  52. # Multiprotocol SAFI types
  53. SAFI_UNICAST = 1
  54. SAFI_MULTICAST = 2
  55. SAFI_UNICAST_MULTICAST = 3
  56. # OPEN Message Optional Parameters
  57. AUTHENTICATION = 1
  58. CAPABILITY = 2
  59. # Capability Types
  60. CAP_MULTIPROTOCOL = 1
  61. CAP_ROUTE_REFRESH = 2
  62. # NOTIFICATION Error Codes
  63. MESSAGE_HEADER_ERROR = 1
  64. OPEN_MESSAGE_ERROR = 2
  65. UPDATE_MESSAGE_ERROR = 3
  66. HOLD_TIMER_EXPIRED = 4
  67. FSM_ERROR = 5
  68. CEASE = 6
  69. # Message Header Error Subcodes
  70. CONNECTION_NOT_SYNCHRONIZED = 1
  71. BAD_MESSAGE_LENGTH = 2
  72. BAD_MESSAGE_TYPE = 3
  73. # OPEN Message Error Subcodes
  74. UNSUPPORTED_VERSION_NUMBER = 1
  75. BAD_PEER_AS = 2
  76. BAD_BGP_IDENTIFIER = 3
  77. UNSUPPORTED_OPTIONAL_PARAMETER = 4
  78. AUTHENTICATION_FAILURE = 5
  79. UNACCEPTABLE_HOLD_TIME = 6
  80. UNSUPPORTED_CAPABILITY = 7
  81. # UPDATE Message Error Subcodes
  82. MALFORMED_ATTRIBUTE_LIST = 1
  83. UNRECOGNIZED_ATTRIBUTE = 2
  84. MISSING_ATTRIBUTE = 3
  85. ATTRIBUTE_FLAGS_ERROR = 4
  86. ATTRIBUTE_LENGTH_ERROR = 5
  87. INVALID_ORIGIN_ATTRIBUTE = 6
  88. AS_ROUTING_LOOP = 7
  89. INVALID_NEXT_HOP_ATTRIBUTE = 8
  90. OPTIONAL_ATTRIBUTE_ERROR = 9
  91. INVALID_NETWORK_FIELD = 10
  92. MALFORMED_AS_PATH = 11
  93. # Cease Error Subcodes
  94. MAX_NUMBER_OF_PREFIXES_REACHED = 1
  95. ADMINISTRATIVE_SHUTDOWN = 2
  96. PEER_DECONFIGURED = 3
  97. ADMINISTRATIVE_RESET = 4
  98. CONNECTION_REJECTED = 5
  99. OTHER_CONFIGURATION_CHANGE = 6
  100. CONNECTION_COLLISION_RESOLUTION = 7
  101. OUT_OF_RESOURCES = 8
  102. class BGP(pypacker.Packet):
  103. __hdr__ = (
  104. ("marker", "16s", b"\xff" * 16),
  105. ("len", "H", 0),
  106. ("type", "B", OPEN)
  107. )
  108. def _dissect(self, buf):
  109. htype = buf[18]
  110. self._init_handler(htype, buf[19:])
  111. return 19
  112. class Open(pypacker.Packet):
  113. __hdr__ = (
  114. ("v", "B", 4),
  115. ("asn", "H", 0),
  116. ("holdtime", "H", 0),
  117. ("identifier", "I", 0),
  118. ("param_len", "B", 0),
  119. ("params", None, triggerlist.TriggerList)
  120. )
  121. def _dissect(self, buf):
  122. # logger.debug("parsing Parameter")
  123. pcount = buf[9]
  124. off = 10
  125. while pcount > 0:
  126. plen = buf[off + 2]
  127. param = self.Parameter(buf[off:off + plen])
  128. self.params.append(param)
  129. pcount -= 1
  130. # TODO: check if len-value is UNCLUSIVE type/len field
  131. off += plen
  132. return off
  133. class Parameter(pypacker.Packet):
  134. __hdr__ = (
  135. ("type", "B", 0),
  136. ("len", "B", 0)
  137. )
  138. class Update(pypacker.Packet):
  139. __hdr__ = (
  140. ("unflen", "H", 0),
  141. ("pathlen", "H", 0),
  142. ("wroutes", None, triggerlist.TriggerList),
  143. ("pathattrs", None, triggerlist.TriggerList),
  144. ("anncroutes", None, triggerlist.TriggerList),
  145. )
  146. def _dissect(self, buf):
  147. # temporary unpack to parse flags
  148. pypacker.Packet._unpack(self, buf[:4])
  149. # Withdrawn Routes
  150. # TODO: update
  151. off = 4
  152. off_end = off + self.unflen
  153. while off < off_end:
  154. rlen = 3 + 0
  155. route = Route(buf[off:])
  156. self.wroutes.append(route)
  157. off += rlen
  158. # Path Attributes
  159. off_end = off + self.pathlen
  160. while off < off_end:
  161. alen = 3 + buf[3 + off]
  162. attr = BGP.Update.Attribute(buf[off:off + alen])
  163. self.pathattrs.append(attr)
  164. off += alen
  165. # Announced Routes
  166. annc = []
  167. off_end = len(buf)
  168. while off < off_end:
  169. rlen = 3 + 0
  170. route = Route(buf[off:off + rlen])
  171. annc.append(route)
  172. off += rlen
  173. return off
  174. class Attribute(pypacker.Packet):
  175. __hdr__ = (
  176. ("flags", "B", 0),
  177. ("type", "B", 0),
  178. ("len", "B", 0)
  179. )
  180. def __get_o(self):
  181. return (self.flags >> 7) & 0x1
  182. def __set_o(self, o):
  183. self.flags = (self.flags & ~0x80) | ((o & 0x1) << 7)
  184. optional = property(__get_o, __set_o)
  185. def __get_t(self):
  186. return (self.flags >> 6) & 0x1
  187. def __set_t(self, t):
  188. self.flags = (self.flags & ~0x40) | ((t & 0x1) << 6)
  189. transitive = property(__get_t, __set_t)
  190. def __get_p(self):
  191. return (self.flags >> 5) & 0x1
  192. def __set_p(self, p):
  193. self.flags = (self.flags & ~0x20) | ((p & 0x1) << 5)
  194. partial = property(__get_p, __set_p)
  195. def __get_e(self):
  196. return (self.flags >> 4) & 0x1
  197. def __set_e(self, e):
  198. # handle different header length types, what moron defined this shit?
  199. if hasattr(self, "len"):
  200. self._del_headerfield(2, True)
  201. if e > 0:
  202. self._add_headerfield("len", "H", 0)
  203. else:
  204. self._add_headerfield("len", "B", 0)
  205. self.flags = (self.flags & ~0x10) | ((e & 0x1) << 4)
  206. extended_length = property(__get_e, __set_e)
  207. def _dissect(self, buf):
  208. # temporary unpack to parse flags
  209. pypacker.Packet._unpack(self, buf[:2])
  210. if self.extended_length:
  211. self.e = 1
  212. try:
  213. # TODO: update
  214. type_instance = BGP.Update.Attribute._switch_type_attribute[type](buf[3:])
  215. self._set_bodyhandler(type_instance)
  216. # any exception will lead to: body = raw bytes
  217. except Exception:
  218. # logger.debug("BGP > Update > Attribute failed to set handler: %s" % e)
  219. pass
  220. return 3
  221. class Origin(pypacker.Packet):
  222. __hdr__ = (
  223. ("type", "B", ORIGIN_IGP),
  224. )
  225. class ASPath(pypacker.Packet):
  226. __hdr__ = (
  227. ("segments", None, triggerlist.TriggerList),
  228. )
  229. def _dissect(self, buf):
  230. off = 1
  231. buflen = len(buf)
  232. while off < buflen:
  233. seglen = buf[off + 2]
  234. seg = self.ASPathSegment(buf[off + 1:seglen])
  235. self.segments.append(seg)
  236. off += seglen
  237. return off
  238. class ASPathSegment(pypacker.Packet):
  239. __hdr__ = (
  240. ("type", "B", 0),
  241. ("len", "B", 0)
  242. )
  243. # TODO: auto-set length
  244. class NextHop(pypacker.Packet):
  245. __hdr__ = (
  246. ("ip", "I", 0),
  247. )
  248. class MultiExitDisc(pypacker.Packet):
  249. __hdr__ = (
  250. ("value", "I", 0),
  251. )
  252. class LocalPref(pypacker.Packet):
  253. __hdr__ = (
  254. ("value", "I", 0),
  255. )
  256. class AtomicAggregate(pypacker.Packet):
  257. pass
  258. class Aggregator(pypacker.Packet):
  259. __hdr__ = (
  260. ("asn", "H", 0),
  261. ("ip", "I", 0)
  262. )
  263. class OriginatorID(pypacker.Packet):
  264. __hdr__ = (
  265. ("value", "I", 0),
  266. )
  267. class ClusterList(pypacker.Packet):
  268. pass
  269. class MPReachNLRI(pypacker.Packet):
  270. __hdr__ = (
  271. ("afi", "H", AFI_IPV4),
  272. ("safi", "B", SAFI_UNICAST),
  273. )
  274. class MPUnreachNLRI(pypacker.Packet):
  275. __hdr__ = (
  276. ("afi", "H", AFI_IPV4),
  277. ("safi", "B", SAFI_UNICAST),
  278. )
  279. class Communitie(pypacker.Packet):
  280. pass
  281. _switch_type_attribute = {
  282. ORIGIN : Origin,
  283. AS_PATH : ASPath,
  284. NEXT_HOP : NextHop,
  285. MULTI_EXIT_DISC : MultiExitDisc,
  286. LOCAL_PREF : LocalPref,
  287. ATOMIC_AGGREGATE : AtomicAggregate,
  288. AGGREGATOR : Aggregator,
  289. COMMUNITIES : Communitie,
  290. ORIGINATOR_ID : OriginatorID,
  291. CLUSTER_LIST : ClusterList,
  292. MP_REACH_NLRI : MPReachNLRI,
  293. MP_UNREACH_NLRI : MPUnreachNLRI
  294. }
  295. class Notification(pypacker.Packet):
  296. __hdr__ = (
  297. ("code", "B", 0),
  298. ("subcode", "B", 0),
  299. )
  300. class Keepalive(pypacker.Packet):
  301. pass
  302. class RouteRefresh(pypacker.Packet):
  303. __hdr__ = (
  304. ("afi", "H", AFI_IPV4),
  305. ("rsvd", "B", 0),
  306. ("safi", "B", SAFI_UNICAST)
  307. )
  308. class Route(pypacker.Packet):
  309. __hdr__ = (
  310. ("len", "B", 0),
  311. )
  312. # load handler
  313. pypacker.Packet.load_handler(BGP,
  314. {
  315. OPEN: BGP.Open,
  316. UPDATE: BGP.Update,
  317. NOTIFICATION: BGP.Notification,
  318. KEEPALIVE: BGP.Keepalive,
  319. ROUTE_REFRESH: BGP.RouteRefresh
  320. }
  321. )