123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389 |
- """
- Border Gateway Protocol.
- """
- from pypacker import pypacker, triggerlist
- import logging
- logger = logging.getLogger("pypacker")
- # Border Gateway Protocol 4 - RFC 4271
- # Communities Attribute - RFC 1997
- # Capabilities - RFC 3392
- # Route Refresh - RFC 2918
- # Route Reflection - RFC 4456
- # Confederations - RFC 3065
- # Cease Subcodes - RFC 4486
- # NOPEER Community - RFC 3765
- # Multiprotocol Extensions - 2858
- # Message Types
- OPEN = 1
- UPDATE = 2
- NOTIFICATION = 3
- KEEPALIVE = 4
- ROUTE_REFRESH = 5
- # Attribute Types
- ORIGIN = 1
- AS_PATH = 2
- NEXT_HOP = 3
- MULTI_EXIT_DISC = 4
- LOCAL_PREF = 5
- ATOMIC_AGGREGATE = 6
- AGGREGATOR = 7
- COMMUNITIES = 8
- ORIGINATOR_ID = 9
- CLUSTER_LIST = 10
- MP_REACH_NLRI = 14
- MP_UNREACH_NLRI = 15
- # Origin Types
- ORIGIN_IGP = 0
- ORIGIN_EGP = 1
- INCOMPLETE = 2
- # AS Path Types
- AS_SET = 1
- AS_SEQUENCE = 2
- AS_CONFED_SEQUENCE = 3
- AS_CONFED_SET = 4
- # Reserved Communities Types
- NO_EXPORT = 0xffffff01
- NO_ADVERTISE = 0xffffff02
- NO_EXPORT_SUBCONFED = 0xffffff03
- NO_PEER = 0xffffff04
- # Common AFI types
- AFI_IPV4 = 1
- AFI_IPV6 = 2
- # Multiprotocol SAFI types
- SAFI_UNICAST = 1
- SAFI_MULTICAST = 2
- SAFI_UNICAST_MULTICAST = 3
- # OPEN Message Optional Parameters
- AUTHENTICATION = 1
- CAPABILITY = 2
- # Capability Types
- CAP_MULTIPROTOCOL = 1
- CAP_ROUTE_REFRESH = 2
- # NOTIFICATION Error Codes
- MESSAGE_HEADER_ERROR = 1
- OPEN_MESSAGE_ERROR = 2
- UPDATE_MESSAGE_ERROR = 3
- HOLD_TIMER_EXPIRED = 4
- FSM_ERROR = 5
- CEASE = 6
- # Message Header Error Subcodes
- CONNECTION_NOT_SYNCHRONIZED = 1
- BAD_MESSAGE_LENGTH = 2
- BAD_MESSAGE_TYPE = 3
- # OPEN Message Error Subcodes
- UNSUPPORTED_VERSION_NUMBER = 1
- BAD_PEER_AS = 2
- BAD_BGP_IDENTIFIER = 3
- UNSUPPORTED_OPTIONAL_PARAMETER = 4
- AUTHENTICATION_FAILURE = 5
- UNACCEPTABLE_HOLD_TIME = 6
- UNSUPPORTED_CAPABILITY = 7
- # UPDATE Message Error Subcodes
- MALFORMED_ATTRIBUTE_LIST = 1
- UNRECOGNIZED_ATTRIBUTE = 2
- MISSING_ATTRIBUTE = 3
- ATTRIBUTE_FLAGS_ERROR = 4
- ATTRIBUTE_LENGTH_ERROR = 5
- INVALID_ORIGIN_ATTRIBUTE = 6
- AS_ROUTING_LOOP = 7
- INVALID_NEXT_HOP_ATTRIBUTE = 8
- OPTIONAL_ATTRIBUTE_ERROR = 9
- INVALID_NETWORK_FIELD = 10
- MALFORMED_AS_PATH = 11
- # Cease Error Subcodes
- MAX_NUMBER_OF_PREFIXES_REACHED = 1
- ADMINISTRATIVE_SHUTDOWN = 2
- PEER_DECONFIGURED = 3
- ADMINISTRATIVE_RESET = 4
- CONNECTION_REJECTED = 5
- OTHER_CONFIGURATION_CHANGE = 6
- CONNECTION_COLLISION_RESOLUTION = 7
- OUT_OF_RESOURCES = 8
- class BGP(pypacker.Packet):
- __hdr__ = (
- ("marker", "16s", b"\xff" * 16),
- ("len", "H", 0),
- ("type", "B", OPEN)
- )
- def _dissect(self, buf):
- htype = buf[18]
- self._init_handler(htype, buf[19:])
- return 19
- class Open(pypacker.Packet):
- __hdr__ = (
- ("v", "B", 4),
- ("asn", "H", 0),
- ("holdtime", "H", 0),
- ("identifier", "I", 0),
- ("param_len", "B", 0),
- ("params", None, triggerlist.TriggerList)
- )
- def _dissect(self, buf):
- # logger.debug("parsing Parameter")
- pcount = buf[9]
- off = 10
- while pcount > 0:
- plen = buf[off + 2]
- param = self.Parameter(buf[off:off + plen])
- self.params.append(param)
- pcount -= 1
- # TODO: check if len-value is UNCLUSIVE type/len field
- off += plen
- return off
- class Parameter(pypacker.Packet):
- __hdr__ = (
- ("type", "B", 0),
- ("len", "B", 0)
- )
- class Update(pypacker.Packet):
- __hdr__ = (
- ("unflen", "H", 0),
- ("pathlen", "H", 0),
- ("wroutes", None, triggerlist.TriggerList),
- ("pathattrs", None, triggerlist.TriggerList),
- ("anncroutes", None, triggerlist.TriggerList),
- )
- def _dissect(self, buf):
- # temporary unpack to parse flags
- pypacker.Packet._unpack(self, buf[:4])
- # Withdrawn Routes
- # TODO: update
- off = 4
- off_end = off + self.unflen
- while off < off_end:
- rlen = 3 + 0
- route = Route(buf[off:])
- self.wroutes.append(route)
- off += rlen
- # Path Attributes
- off_end = off + self.pathlen
- while off < off_end:
- alen = 3 + buf[3 + off]
- attr = BGP.Update.Attribute(buf[off:off + alen])
- self.pathattrs.append(attr)
- off += alen
- # Announced Routes
- annc = []
- off_end = len(buf)
- while off < off_end:
- rlen = 3 + 0
- route = Route(buf[off:off + rlen])
- annc.append(route)
- off += rlen
- return off
- class Attribute(pypacker.Packet):
- __hdr__ = (
- ("flags", "B", 0),
- ("type", "B", 0),
- ("len", "B", 0)
- )
- def __get_o(self):
- return (self.flags >> 7) & 0x1
- def __set_o(self, o):
- self.flags = (self.flags & ~0x80) | ((o & 0x1) << 7)
- optional = property(__get_o, __set_o)
- def __get_t(self):
- return (self.flags >> 6) & 0x1
- def __set_t(self, t):
- self.flags = (self.flags & ~0x40) | ((t & 0x1) << 6)
- transitive = property(__get_t, __set_t)
- def __get_p(self):
- return (self.flags >> 5) & 0x1
- def __set_p(self, p):
- self.flags = (self.flags & ~0x20) | ((p & 0x1) << 5)
- partial = property(__get_p, __set_p)
- def __get_e(self):
- return (self.flags >> 4) & 0x1
- def __set_e(self, e):
- # handle different header length types, what moron defined this shit?
- if hasattr(self, "len"):
- self._del_headerfield(2, True)
- if e > 0:
- self._add_headerfield("len", "H", 0)
- else:
- self._add_headerfield("len", "B", 0)
- self.flags = (self.flags & ~0x10) | ((e & 0x1) << 4)
- extended_length = property(__get_e, __set_e)
- def _dissect(self, buf):
- # temporary unpack to parse flags
- pypacker.Packet._unpack(self, buf[:2])
- if self.extended_length:
- self.e = 1
- try:
- # TODO: update
- type_instance = BGP.Update.Attribute._switch_type_attribute[type](buf[3:])
- self._set_bodyhandler(type_instance)
- # any exception will lead to: body = raw bytes
- except Exception:
- # logger.debug("BGP > Update > Attribute failed to set handler: %s" % e)
- pass
- return 3
- class Origin(pypacker.Packet):
- __hdr__ = (
- ("type", "B", ORIGIN_IGP),
- )
- class ASPath(pypacker.Packet):
- __hdr__ = (
- ("segments", None, triggerlist.TriggerList),
- )
- def _dissect(self, buf):
- off = 1
- buflen = len(buf)
- while off < buflen:
- seglen = buf[off + 2]
- seg = self.ASPathSegment(buf[off + 1:seglen])
- self.segments.append(seg)
- off += seglen
- return off
- class ASPathSegment(pypacker.Packet):
- __hdr__ = (
- ("type", "B", 0),
- ("len", "B", 0)
- )
- # TODO: auto-set length
- class NextHop(pypacker.Packet):
- __hdr__ = (
- ("ip", "I", 0),
- )
- class MultiExitDisc(pypacker.Packet):
- __hdr__ = (
- ("value", "I", 0),
- )
- class LocalPref(pypacker.Packet):
- __hdr__ = (
- ("value", "I", 0),
- )
- class AtomicAggregate(pypacker.Packet):
- pass
- class Aggregator(pypacker.Packet):
- __hdr__ = (
- ("asn", "H", 0),
- ("ip", "I", 0)
- )
- class OriginatorID(pypacker.Packet):
- __hdr__ = (
- ("value", "I", 0),
- )
- class ClusterList(pypacker.Packet):
- pass
- class MPReachNLRI(pypacker.Packet):
- __hdr__ = (
- ("afi", "H", AFI_IPV4),
- ("safi", "B", SAFI_UNICAST),
- )
- class MPUnreachNLRI(pypacker.Packet):
- __hdr__ = (
- ("afi", "H", AFI_IPV4),
- ("safi", "B", SAFI_UNICAST),
- )
- class Communitie(pypacker.Packet):
- pass
- _switch_type_attribute = {
- ORIGIN : Origin,
- AS_PATH : ASPath,
- NEXT_HOP : NextHop,
- MULTI_EXIT_DISC : MultiExitDisc,
- LOCAL_PREF : LocalPref,
- ATOMIC_AGGREGATE : AtomicAggregate,
- AGGREGATOR : Aggregator,
- COMMUNITIES : Communitie,
- ORIGINATOR_ID : OriginatorID,
- CLUSTER_LIST : ClusterList,
- MP_REACH_NLRI : MPReachNLRI,
- MP_UNREACH_NLRI : MPUnreachNLRI
- }
- class Notification(pypacker.Packet):
- __hdr__ = (
- ("code", "B", 0),
- ("subcode", "B", 0),
- )
- class Keepalive(pypacker.Packet):
- pass
- class RouteRefresh(pypacker.Packet):
- __hdr__ = (
- ("afi", "H", AFI_IPV4),
- ("rsvd", "B", 0),
- ("safi", "B", SAFI_UNICAST)
- )
- class Route(pypacker.Packet):
- __hdr__ = (
- ("len", "B", 0),
- )
- # load handler
- pypacker.Packet.load_handler(BGP,
- {
- OPEN: BGP.Open,
- UPDATE: BGP.Update,
- NOTIFICATION: BGP.Notification,
- KEEPALIVE: BGP.Keepalive,
- ROUTE_REFRESH: BGP.RouteRefresh
- }
- )
|