예제 #1
0
    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('')
예제 #2
0
	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('')
예제 #3
0
    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:])
예제 #4
0
	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:])