def UpdateFactory(self, data): length = len(data) # withdrawn lw, withdrawn, data = defix(data) if len(withdrawn) != lw: raise Notify(3, 1) la, attribute, announced = defix(data) if len(attribute) != la: raise Notify(3, 1) # The RFC check ... #if lw + la + 23 > length: if 2 + lw + 2 + la + len(announced) != length: raise Notify(3, 1) routes = [] while withdrawn: nlri = BGPPrefix(AFI.ipv4, withdrawn) route = ReceivedRoute(nlri, 'withdraw') withdrawn = withdrawn[len(nlri):] routes.append(route) self.mp_routes = [] attributes = self.AttributesFactory(attribute) routes.extend(self.mp_routes) while announced: nlri = BGPPrefix(AFI.ipv4, announced) route = ReceivedRoute(nlri, 'announce') # XXX: Should this be a deep copy route.attributes = attributes announced = announced[len(nlri):] routes.append(route) #logger.info(self.me('Received route %s' % nlri)) #print "routes", routes #print "attributes", attributes if routes: return Update(routes) return NOP('')
def UpdateFactory (self,data): length = len(data) # withdrawn lw,withdrawn,data = defix(data) if len(withdrawn) != lw: raise Notify(3,1) la,attribute,announced = defix(data) if len(attribute) != la: raise Notify(3,1) # The RFC check ... #if lw + la + 23 > length: if 2 + lw + 2+ la + len(announced) != length: raise Notify(3,1) routes = [] while withdrawn: nlri = BGPPrefix(AFI.ipv4,withdrawn) route = ReceivedRoute(nlri,'withdraw') withdrawn = withdrawn[len(nlri):] routes.append(route) self.mp_routes = [] attributes = self.AttributesFactory(attribute) routes.extend(self.mp_routes) while announced: nlri = BGPPrefix(AFI.ipv4,announced) route = ReceivedRoute(nlri,'announce') # XXX: Should this be a deep copy route.attributes = attributes announced = announced[len(nlri):] routes.append(route) #logger.info(self.me('Received route %s' % nlri)) #print "routes", routes #print "attributes", attributes if routes: return Update(routes) return NOP('')
def _AttributesFactory(self, data): if not data: return self # We do not care if the attribute are transitive or not as we do not redistribute flag = Flag(ord(data[0])) code = AttributeID(ord(data[1])) if flag & Flag.EXTENDED_LENGTH: length = unpack('!H', data[2:4])[0] offset = 4 else: length = ord(data[2]) offset = 3 data = data[offset:] # if not length: # return self._AttributesFactory(data[length:]) # XXX: This code does not make sure that attributes are unique - or does it ? if code == AttributeID.ORIGIN: logger.parser('parsing origin') self.attributes.add(Origin(ord(data[0]))) return self._AttributesFactory(data[length:]) if code == AttributeID.AS_PATH: logger.parser('parsing as_path') self.attributes.add(self.__new_ASPath(data[:length], self._asn4)) if not self._asn4 and self.attributes.has(AttributeID.AS4_PATH): self.__merge_attributes() return self._AttributesFactory(data[length:]) if code == AttributeID.AS4_PATH: logger.parser('parsing as_path') self.attributes.add(self.__new_AS4Path(data[:length])) if not self._asn4 and self.attributes.has(AttributeID.AS_PATH): self.__merge_attributes() return self._AttributesFactory(data[length:]) if code == AttributeID.NEXT_HOP: logger.parser('parsing next-hop') self.attributes.add(NextHop(Inet(AFI.ipv4, data[:4]))) return self._AttributesFactory(data[length:]) if code == AttributeID.MED: logger.parser('parsing med') self.attributes.add(MED(unpack('!L', data[:4])[0])) return self._AttributesFactory(data[length:]) if code == AttributeID.LOCAL_PREF: logger.parser('parsing local-preference') self.attributes.add(LocalPreference(unpack('!L', data[:4])[0])) return self._AttributesFactory(data[length:]) if code == AttributeID.ORIGINATOR_ID: logger.parser('parsing originator-id') self.attributes.add(OriginatorId.unpack(data[:4])) return self._AttributesFactory(data[length:]) if code == AttributeID.PMSI_TUNNEL: logger.parser('parsing pmsi-tunnel') self.attributes.add(PMSITunnel.unpack(data[:length])) return self._AttributesFactory(data[length:]) if code == AttributeID.ATOMIC_AGGREGATE: logger.parser('ignoring atomic-aggregate') return self._AttributesFactory(data[length:]) if code == AttributeID.AGGREGATOR: logger.parser('ignoring aggregator') return self._AttributesFactory(data[length:]) if code == AttributeID.AS4_AGGREGATOR: logger.parser('ignoring as4_aggregator') return self._AttributesFactory(data[length:]) if code == AttributeID.COMMUNITY: logger.parser('parsing communities') self.attributes.add(self.__new_communities(data[:length])) return self._AttributesFactory(data[length:]) if code == AttributeID.EXTENDED_COMMUNITY: logger.parser('parsing communities') self.attributes.add(self.__new_extended_communities(data[:length])) return self._AttributesFactory(data[length:]) if code == AttributeID.MP_UNREACH_NLRI: logger.parser('parsing multi-protocol nlri unreacheable') next_attributes = data[length:] data = data[:length] afi, safi = unpack('!HB', data[:3]) offset = 3 # See RFC 5549 for better support if not afi in (AFI.ipv4, AFI.ipv6, AFI.l2vpn) or (not safi in ( SAFI.unicast, SAFI.mpls_vpn, SAFI.rtc, SAFI.evpn)): #self.log.out('we only understand IPv4/IPv6 and should never have received this MP_UNREACH_NLRI (%s %s)' % (afi,safi)) raise Exception( "Unsupported AFI/SAFI received !! not supposed to happen here..." ) return self._AttributesFactory(next_attributes) data = data[offset:] while data: if safi == SAFI.unicast: route = ReceivedRoute(BGPPrefix(afi, data), 'withdraw') elif (afi == AFI.ipv4 and safi == SAFI.mpls_vpn): route = ReceivedRoute( VPNLabelledPrefix.unpack(afi, safi, data), 'withdraw') elif (afi == AFI.ipv4 and safi == SAFI.rtc): route = ReceivedRoute( RouteTargetConstraint.unpack(afi, safi, data), 'withdraw') elif (afi == AFI.l2vpn and safi == SAFI.evpn): route = ReceivedRoute(EVPNNLRI.unpack(data), 'withdraw') else: raise Exception("Unsupported AFI/SAFI combination !!") return self._AttributesFactory(next_attributes) data = data[len(route.nlri):] self.mp_routes.append(route) return self._AttributesFactory(next_attributes) if code == AttributeID.MP_REACH_NLRI: logger.parser('parsing multi-protocol nlri reacheable') next_attributes = data[length:] data = data[:length] afi, safi = unpack('!HB', data[:3]) offset = 3 if not afi in (AFI.ipv4, AFI.ipv6, AFI.l2vpn) or (not safi in ( SAFI.unicast, SAFI.mpls_vpn, SAFI.rtc, SAFI.evpn)): #self.log.out('we only understand IPv4/IPv6 and should never have received this MP_REACH_NLRI (%s %s)' % (afi,safi)) raise Exception( "Unsupported AFI/SAFI received !! not supposed to happen here..." ) return self._AttributesFactory(next_attributes) len_nh = ord(data[offset]) offset += 1 if afi == AFI.ipv4 and safi in ( SAFI.unicast, ) and not len_nh == 4: # We are not following RFC 4760 Section 7 (deleting route and possibly tearing down the session) #self.log.out('bad IPv4 next-hop length (%d)' % len_nh) return self._AttributesFactory(next_attributes) if afi == AFI.ipv6 and safi in ( SAFI.unicast, ) and not len_nh in (16, 32): # We are not following RFC 4760 Section 7 (deleting route and possibly tearing down the session) #self.log.out('bad IPv6 next-hop length (%d)' % len_nh) return self._AttributesFactory(next_attributes) nh = data[offset:offset + len_nh] offset += len_nh if len_nh == 32: # we have a link-local address in the next-hop we ideally need to ignore if nh[0] == chr(0xfe): nh = nh[16:] elif nh[16] == chr(0xfe): nh = nh[:16] # We are not following RFC 4760 Section 7 (deleting route and possibly tearing down the session) else: return self._AttributesFactory(next_attributes) if len_nh >= 16: nh = socket.inet_ntop(socket.AF_INET6, nh) else: if (safi in (SAFI.mpls_vpn, )): # the next-hop is preceded by an rdtype and a 6-byte RD, we don't care about the RD yet nh = socket.inet_ntop(socket.AF_INET, nh[8:]) else: nh = socket.inet_ntop(socket.AF_INET, nh) nb_snpa = ord(data[offset]) offset += 1 snpas = [] for _ in range(nb_snpa): len_snpa = ord(offset) offset += 1 snpas.append(data[offset:offset + len_snpa]) offset += len_snpa data = data[offset:] while data: if safi == SAFI.unicast: route = ReceivedRoute(BGPPrefix(afi, data), 'announce') elif (afi == AFI.ipv4 and safi == SAFI.mpls_vpn): route = ReceivedRoute( VPNLabelledPrefix.unpack(afi, safi, data), 'announce') elif (afi == AFI.ipv4 and safi == SAFI.rtc): route = ReceivedRoute( RouteTargetConstraint.unpack(afi, safi, data), 'announce') elif (afi == AFI.l2vpn and safi == SAFI.evpn): route = ReceivedRoute(EVPNNLRI.unpack(data), 'announce') else: raise Exception("Unsupported AFI/SAFI combination !!") return self._AttributesFactory(next_attributes) data = data[len(route.nlri):] route.attributes = self.attributes route.attributes.add(NextHop(to_IP(nh))) self.mp_routes.append(route) return self._AttributesFactory(next_attributes) logger.warning( "ignoring attributes of type %s %s" % (str(code), [hex(ord(_)) for _ in data]), 'parsing') return self._AttributesFactory(data[length:])
def _AttributesFactory (self,data): if not data: return self # We do not care if the attribute are transitive or not as we do not redistribute flag = Flag(ord(data[0])) code = AttributeID(ord(data[1])) if flag & Flag.EXTENDED_LENGTH: length = unpack('!H',data[2:4])[0] offset = 4 else: length = ord(data[2]) offset = 3 data = data[offset:] # if not length: # return self._AttributesFactory(data[length:]) # XXX: This code does not make sure that attributes are unique - or does it ? if code == AttributeID.ORIGIN: logger.parser('parsing origin') self.attributes.add(Origin(ord(data[0]))) return self._AttributesFactory(data[length:]) if code == AttributeID.AS_PATH: logger.parser('parsing as_path') self.attributes.add(self.__new_ASPath(data[:length],self._asn4)) if not self._asn4 and self.attributes.has(AttributeID.AS4_PATH): self.__merge_attributes() return self._AttributesFactory(data[length:]) if code == AttributeID.AS4_PATH: logger.parser('parsing as_path') self.attributes.add(self.__new_AS4Path(data[:length])) if not self._asn4 and self.attributes.has(AttributeID.AS_PATH): self.__merge_attributes() return self._AttributesFactory(data[length:]) if code == AttributeID.NEXT_HOP: logger.parser('parsing next-hop') self.attributes.add(NextHop(Inet(AFI.ipv4,data[:4]))) return self._AttributesFactory(data[length:]) if code == AttributeID.MED: logger.parser('parsing med') self.attributes.add(MED(unpack('!L',data[:4])[0])) return self._AttributesFactory(data[length:]) if code == AttributeID.LOCAL_PREF: logger.parser('parsing local-preference') self.attributes.add(LocalPreference(unpack('!L',data[:4])[0])) return self._AttributesFactory(data[length:]) if code == AttributeID.ORIGINATOR_ID: logger.parser('parsing originator-id') self.attributes.add(OriginatorId.unpack(data[:4])) return self._AttributesFactory(data[length:]) if code == AttributeID.PMSI_TUNNEL: logger.parser('parsing pmsi-tunnel') self.attributes.add(PMSITunnel.unpack(data[:length])) return self._AttributesFactory(data[length:]) if code == AttributeID.ATOMIC_AGGREGATE: logger.parser('ignoring atomic-aggregate') return self._AttributesFactory(data[length:]) if code == AttributeID.AGGREGATOR: logger.parser('ignoring aggregator') return self._AttributesFactory(data[length:]) if code == AttributeID.AS4_AGGREGATOR: logger.parser('ignoring as4_aggregator') return self._AttributesFactory(data[length:]) if code == AttributeID.COMMUNITY: logger.parser('parsing communities') self.attributes.add(self.__new_communities(data[:length])) return self._AttributesFactory(data[length:]) if code == AttributeID.EXTENDED_COMMUNITY: logger.parser('parsing communities') self.attributes.add(self.__new_extended_communities(data[:length])) return self._AttributesFactory(data[length:]) if code == AttributeID.MP_UNREACH_NLRI: logger.parser('parsing multi-protocol nlri unreacheable') next_attributes = data[length:] data = data[:length] afi,safi = unpack('!HB',data[:3]) offset = 3 # See RFC 5549 for better support if not afi in (AFI.ipv4,AFI.ipv6,AFI.l2vpn) or (not safi in (SAFI.unicast, SAFI.mpls_vpn, SAFI.rtc,SAFI.evpn)): #self.log.out('we only understand IPv4/IPv6 and should never have received this MP_UNREACH_NLRI (%s %s)' % (afi,safi)) raise Exception("Unsupported AFI/SAFI received !! not supposed to happen here...") return self._AttributesFactory(next_attributes) data = data[offset:] while data: if safi == SAFI.unicast: route = ReceivedRoute(BGPPrefix(afi,data),'withdraw') elif (afi == AFI.ipv4 and safi == SAFI.mpls_vpn): route = ReceivedRoute(VPNLabelledPrefix.unpack(afi,safi,data),'withdraw') elif (afi == AFI.ipv4 and safi == SAFI.rtc): route = ReceivedRoute(RouteTargetConstraint.unpack(afi,safi,data),'withdraw') elif (afi == AFI.l2vpn and safi == SAFI.evpn): route = ReceivedRoute(EVPNNLRI.unpack(data) ,'withdraw') else: raise Exception("Unsupported AFI/SAFI combination !!") return self._AttributesFactory(next_attributes) data = data[len(route.nlri):] self.mp_routes.append(route) return self._AttributesFactory(next_attributes) if code == AttributeID.MP_REACH_NLRI: logger.parser('parsing multi-protocol nlri reacheable') next_attributes = data[length:] data = data[:length] afi,safi = unpack('!HB',data[:3]) offset = 3 if not afi in (AFI.ipv4,AFI.ipv6,AFI.l2vpn) or (not safi in (SAFI.unicast,SAFI.mpls_vpn,SAFI.rtc,SAFI.evpn)): #self.log.out('we only understand IPv4/IPv6 and should never have received this MP_REACH_NLRI (%s %s)' % (afi,safi)) raise Exception("Unsupported AFI/SAFI received !! not supposed to happen here...") return self._AttributesFactory(next_attributes) len_nh = ord(data[offset]) offset += 1 if afi == AFI.ipv4 and safi in (SAFI.unicast,) and not len_nh == 4: # We are not following RFC 4760 Section 7 (deleting route and possibly tearing down the session) #self.log.out('bad IPv4 next-hop length (%d)' % len_nh) return self._AttributesFactory(next_attributes) if afi == AFI.ipv6 and safi in (SAFI.unicast,) and not len_nh in (16,32): # We are not following RFC 4760 Section 7 (deleting route and possibly tearing down the session) #self.log.out('bad IPv6 next-hop length (%d)' % len_nh) return self._AttributesFactory(next_attributes) nh = data[offset:offset+len_nh] offset += len_nh if len_nh == 32: # we have a link-local address in the next-hop we ideally need to ignore if nh[0] == chr(0xfe): nh = nh[16:] elif nh[16] == chr(0xfe): nh = nh[:16] # We are not following RFC 4760 Section 7 (deleting route and possibly tearing down the session) else: return self._AttributesFactory(next_attributes) if len_nh >= 16: nh = socket.inet_ntop(socket.AF_INET6,nh) else: if (safi in (SAFI.mpls_vpn,)): # the next-hop is preceded by an rdtype and a 6-byte RD, we don't care about the RD yet nh = socket.inet_ntop(socket.AF_INET,nh[8:]) else: nh = socket.inet_ntop(socket.AF_INET,nh) nb_snpa = ord(data[offset]) offset += 1 snpas = [] for _ in range(nb_snpa): len_snpa = ord(offset) offset += 1 snpas.append(data[offset:offset+len_snpa]) offset += len_snpa data = data[offset:] while data: if safi == SAFI.unicast: route = ReceivedRoute(BGPPrefix(afi,data),'announce') elif (afi == AFI.ipv4 and safi == SAFI.mpls_vpn): route = ReceivedRoute(VPNLabelledPrefix.unpack(afi,safi,data) ,'announce') elif (afi == AFI.ipv4 and safi == SAFI.rtc): route = ReceivedRoute(RouteTargetConstraint.unpack(afi,safi,data) ,'announce') elif (afi == AFI.l2vpn and safi == SAFI.evpn): route = ReceivedRoute(EVPNNLRI.unpack(data) ,'announce') else: raise Exception("Unsupported AFI/SAFI combination !!") return self._AttributesFactory(next_attributes) data = data[len(route.nlri):] route.attributes = self.attributes route.attributes.add(NextHop(to_IP(nh))) self.mp_routes.append(route) return self._AttributesFactory(next_attributes) logger.warning("ignoring attributes of type %s %s" % (str(code),[hex(ord(_)) for _ in data]),'parsing') return self._AttributesFactory(data[length:])