Beispiel #1
0
 def unpack(data, negotiated=None):
     # 30/02/12 Quagga communities for soo and rt are not transitive when 4360 says they must be, hence the & 0x0FFF
     community = (ordinal(data[0]) & 0x0F, ordinal(data[1]))
     if community in ExtendedCommunity.registered_extended:
         return ExtendedCommunity.registered_extended[community].unpack(
             data)
     return ExtendedCommunity(data)
Beispiel #2
0
	def unpack_message (cls, data, negotiated):  # pylint: disable=W0613
		what = Type(unpack('!H',data[0:2])[0])
		length = unpack('!H',data[2:4])[0]

		decode,klass = cls.registered_operational.get(what,('unknown',None))

		if decode == 'advisory':
			afi = unpack('!H',data[4:6])[0]
			safi = ordinal(data[6])
			data = data[7:length+4]
			return klass(afi,safi,data)
		elif decode == 'query':
			afi = unpack('!H',data[4:6])[0]
			safi = ordinal(data[6])
			routerid = RouterID.unpack(data[7:11])
			sequence = unpack('!L',data[11:15])[0]
			return klass(afi,safi,routerid,sequence)
		elif decode == 'counter':
			afi = unpack('!H',data[4:6])[0]
			safi = ordinal(data[6])
			routerid = RouterID.unpack(data[7:11])
			sequence = unpack('!L',data[11:15])[0]
			counter = unpack('!L',data[15:19])[0]
			return klass(afi,safi,routerid,sequence,counter)
		else:
			print('ignoring ATM this kind of message')
Beispiel #3
0
    def unpack_nlri(cls, afi, safi, bgp, action, addpath):
        length, bgp = ordinal(bgp[0]), bgp[1:]

        if length & 0xF0 == 0xF0:  # bigger than 240
            extra, bgp = ordinal(bgp[0]), bgp[1:]
            length = ((length & 0x0F) << 16) + extra

        if length > len(bgp):
            raise Notify(3, 10, 'invalid length at the start of the the flow')

        over = bgp[length:]
        bgp = bgp[:length]

        nlri = cls(afi, safi, action)

        if safi == SAFI.flow_vpn:
            nlri.rd = RouteDistinguisher(bgp[:8])
            bgp = bgp[8:]

        seen = []

        while bgp:
            what, bgp = ordinal(bgp[0]), bgp[1:]

            if what not in decode.get(afi, {}):
                raise Notify(
                    3, 10,
                    'unknown flowspec component received for address family %d'
                    % what)

            seen.append(what)
            if sorted(seen) != seen:
                raise Notify(
                    3, 10,
                    'components are not sent in the right order %s' % seen)

            decoded = decode[afi][what]
            klass = factory[afi][what]

            if decoded == 'prefix':
                adding, bgp = klass.make(bgp)
                if not nlri.add(adding):
                    raise Notify(
                        3, 10,
                        'components are incompatible (two sources, two destinations, mix ipv4/ipv6) %s'
                        % seen)
                # logger.parser(LazyFormat("added flow %s (%s) payload " % (klass.NAME,adding),bgp[:-len(left)]))
            else:
                end = False
                while not end:
                    byte, bgp = ordinal(bgp[0]), bgp[1:]
                    end = CommonOperator.eol(byte)
                    operator = CommonOperator.operator(byte)
                    length = CommonOperator.length(byte)
                    value, bgp = bgp[:length], bgp[length:]
                    adding = klass.decoder(value)
                    nlri.add(klass(operator, adding))
                    # logger.parser(LazyFormat("added flow %s (%s) operator %d len %d payload " % (klass.NAME,adding,byte,length),value))

        return nlri, bgp + over
Beispiel #4
0
    def test_nlri(self):
        components = {
            'destination': Flow4Destination(IPv4.pton("192.0.2.0"), 24),
            'source': Flow4Source(IPv4.pton("10.1.2.0"), 24),
            'anyport_1': FlowAnyPort(NumericOperator.EQ | NumericOperator.GT,
                                     25),
            'anyport_2': FlowAnyPort(NumericOperator.EQ | NumericOperator.LT,
                                     80),
        }
        messages = {
            'destination': [0x01, 0x18, 0xc0, 0x00, 0x02],
            'source': [0x02, 0x18, 0x0a, 0x01, 0x02],
            'anyport_1': [0x04, 0x43, 0x19],
            'anyport_2': [0x85, 0x50],
        }

        flow = Flow()
        message = b""
        for key in ['destination', 'source', 'anyport_1', 'anyport_2']:
            flow.add(components[key])
            message += data_from_body(messages[key])
        message = character(len(message)) + message
        # policy.add(to_FlowAction(65000,False,False))
        flow = flow.pack()
        if message[0] != flow[0]:
            self.fail('size mismatch %s %s\n' %
                      (ordinal(flow[0]), ordinal(message[0])))
        if len(flow) != ordinal(flow[0]) + 1:
            self.fail('invalid size for message')
Beispiel #5
0
    def unpack_message(cls, data, negotiated):  # pylint: disable=W0613
        what = Type(unpack('!H', data[0:2])[0])
        length = unpack('!H', data[2:4])[0]

        decode, klass = cls.registered_operational.get(what, ('unknown', None))

        if decode == 'advisory':
            afi = unpack('!H', data[4:6])[0]
            safi = ordinal(data[6])
            data = data[7:length + 4]
            return klass(afi, safi, data)
        elif decode == 'query':
            afi = unpack('!H', data[4:6])[0]
            safi = ordinal(data[6])
            routerid = RouterID.unpack(data[7:11])
            sequence = unpack('!L', data[11:15])[0]
            return klass(afi, safi, routerid, sequence)
        elif decode == 'counter':
            afi = unpack('!H', data[4:6])[0]
            safi = ordinal(data[6])
            routerid = RouterID.unpack(data[7:11])
            sequence = unpack('!L', data[11:15])[0]
            counter = unpack('!L', data[15:19])[0]
            return klass(afi, safi, routerid, sequence, counter)
        else:
            print('ignoring ATM this kind of message')
Beispiel #6
0
    def _new_aspaths(cls, data, asn4, klass=None):
        as_set = []
        as_seq = []
        as_cset = []
        as_cseq = []

        backup = data

        unpacker = {
            False: '!H',
            True: '!L',
        }
        size = {
            False: 2,
            True: 4,
        }
        as_choice = {
            ASPath.AS_SEQUENCE: as_seq,
            ASPath.AS_SET: as_set,
            ASPath.AS_CONFED_SEQUENCE: as_cseq,
            ASPath.AS_CONFED_SET: as_cset,
        }

        upr = unpacker[asn4]
        length = size[asn4]

        try:

            while data:
                stype = ordinal(data[0])
                slen = ordinal(data[1])

                if stype not in (ASPath.AS_SET, ASPath.AS_SEQUENCE,
                                 ASPath.AS_CONFED_SEQUENCE,
                                 ASPath.AS_CONFED_SET):
                    raise Notify(3, 11, 'invalid AS Path type sent %d' % stype)

                end = 2 + (slen * length)
                sdata = data[2:end]
                data = data[end:]
                # Eat the data and ignore it if the ASPath attribute is know known
                asns = as_choice.get(stype, [])

                for _ in range(slen):
                    asn = unpack(upr, sdata[:length])[0]
                    asns.append(ASN(asn))
                    sdata = sdata[length:]

        except IndexError:
            raise Notify(3, 11,
                         'not enough data to decode AS_PATH or AS4_PATH')
        except error:  # struct
            raise Notify(3, 11,
                         'not enough data to decode AS_PATH or AS4_PATH')

        if klass:
            return klass(as_seq, as_set, as_cseq, as_cset, backup)
        return cls(as_seq, as_set, as_cseq, as_cset, backup)
Beispiel #7
0
	def unpack (data, negotiated=None):
		# 30/02/12 Quagga communities for soo and rt are not transitive when 4360 says they must be, hence the & 0x0FFF
		community = (ordinal(data[0]) & 0x0F,ordinal(data[1]))
		if community in ExtendedCommunity.registered_extended:
			klass = ExtendedCommunity.registered_extended[community]
			instance = klass.unpack(data)
			instance.klass = klass
			return instance
		return ExtendedCommunity(data)
Beispiel #8
0
	def flag_attribute_content (data):
		flag = Attribute.Flag(ordinal(data[0]))
		attr = Attribute.CODE(ordinal(data[1]))

		if flag & Attribute.Flag.EXTENDED_LENGTH:
			length = unpack('!H',data[2:4])[0]
			return flag, attr, data[4:length+4]
		else:
			length = ordinal(data[2])
			return flag, attr, data[3:length+3]
Beispiel #9
0
    def flag_attribute_content(data):
        flag = Attribute.Flag(ordinal(data[0]))
        attr = Attribute.CODE(ordinal(data[1]))

        if flag & Attribute.Flag.EXTENDED_LENGTH:
            length = unpack('!H', data[2:4])[0]
            return flag, attr, data[4:length + 4]
        else:
            length = ordinal(data[2])
            return flag, attr, data[3:length + 3]
Beispiel #10
0
		def _key_values (name, data):
			if len(data) < 2:
				raise Notify(2,0,"Bad length for OPEN %s (<2) %s" % (name,Capability.hex(data)))
			ld = ordinal(data[1])
			boundary = ld+2
			if len(data) < boundary:
				raise Notify(2,0,"Bad length for OPEN %s (buffer underrun) %s" % (name,Capability.hex(data)))
			key = ordinal(data[0])
			value = data[2:boundary]
			rest = data[boundary:]
			return key,value,rest
Beispiel #11
0
	def _new_aspaths (cls, data, asn4, klass=None):
		as_set = []
		as_seq = []
		as_cset = []
		as_cseq = []

		backup = data

		unpacker = {
			False: '!H',
			True:  '!L',
		}
		size = {
			False: 2,
			True:  4,
		}
		as_choice = {
			ASPath.AS_SEQUENCE: as_seq,
			ASPath.AS_SET:      as_set,
			ASPath.AS_CONFED_SEQUENCE: as_cseq,
			ASPath.AS_CONFED_SET:      as_cset,
		}

		upr = unpacker[asn4]
		length = size[asn4]

		try:

			while data:
				stype = ordinal(data[0])
				slen  = ordinal(data[1])

				if stype not in (ASPath.AS_SET, ASPath.AS_SEQUENCE, ASPath.AS_CONFED_SEQUENCE, ASPath.AS_CONFED_SET):
					raise Notify(3,11,'invalid AS Path type sent %d' % stype)

				end = 2+(slen*length)
				sdata = data[2:end]
				data = data[end:]
				# Eat the data and ignore it if the ASPath attribute is know known
				asns = as_choice.get(stype,[])

				for _ in range(slen):
					asn = unpack(upr,sdata[:length])[0]
					asns.append(ASN(asn))
					sdata = sdata[length:]

		except IndexError:
			raise Notify(3,11,'not enough data to decode AS_PATH or AS4_PATH')
		except error:  # struct
			raise Notify(3,11,'not enough data to decode AS_PATH or AS4_PATH')

		if klass:
			return klass(as_seq,as_set,as_cseq,as_cset,backup)
		return cls(as_seq,as_set,as_cseq,as_cset,backup)
Beispiel #12
0
		def _key_values (name, data):
			if len(data) < 2:
				raise Notify(2,0,"Bad length for OPEN %s (<2) %s" % (name,Capability.hex(data)))
			ld = ordinal(data[1])
			boundary = ld+2
			if len(data) < boundary:
				raise Notify(2,0,"Bad length for OPEN %s (buffer underrun) %s" % (name,Capability.hex(data)))
			key = ordinal(data[0])
			value = data[2:boundary]
			rest = data[boundary:]
			return key,value,rest
Beispiel #13
0
    def unpack(cls, data):
        datalen = len(data)
        rd = RouteDistinguisher.unpack(data[:8])
        esi = ESI.unpack(data[8:18])
        etag = EthernetTag.unpack(data[18:22])
        maclength = ordinal(data[22])

        if (maclength > 48 or maclength < 0):
            raise Notify(3, 5, 'invalid MAC Address length in %s' % cls.NAME)
        end = 23 + 6  # MAC length MUST be 6

        mac = MACQUAL.unpack(data[23:end])

        length = ordinal(data[end])
        iplen = length / 8

        if datalen in [33, 36]:  # No IP information (1 or 2 labels)
            iplenUnpack = 0
            if iplen != 0:
                raise Notify(
                    3, 5,
                    "IP length is given as %d, but current MAC route has no IP information"
                    % iplen)
        elif datalen in [37, 40]:  # Using IPv4 addresses (1 or 2 labels)
            iplenUnpack = 4
            if (iplen > 32 or iplen < 0):
                raise Notify(
                    3, 5,
                    "IP field length is given as %d, but current MAC route is IPv4 and valus is out of range"
                    % iplen)
        elif datalen in [49, 52]:  # Using IPv6 addresses (1 or 2 labels)
            iplenUnpack = 16
            if (iplen > 128 or iplen < 0):
                raise Notify(
                    3, 5,
                    "IP field length is given as %d, but current MAC route is IPv6 and valus is out of range"
                    % iplen)
        else:
            raise Notify(
                3, 5,
                "Data field length is given as %d, but does not match one of the expected lengths"
                % datalen)

        payload = data[end + 1:end + 1 + iplenUnpack]
        if payload:
            ip = IP.unpack(data[end + 1:end + 1 + iplenUnpack])
        else:
            ip = None
        label = Labels.unpack(data[end + 1 + iplenUnpack:end + 1 +
                                   iplenUnpack + 3])

        return cls(rd, esi, etag, mac, maclength, label, ip, data)
Beispiel #14
0
    def unpack_nlri(cls, afi, safi, bgp, action, addpath):
        code = ordinal(bgp[0])
        length = ordinal(bgp[1])

        if code in cls.registered_evpn:
            klass = cls.registered_evpn[code].unpack(bgp[2:length + 2])
        else:
            klass = GenericEVPN(code, bgp[2:length + 2])
        klass.CODE = code
        klass.action = action
        klass.addpath = addpath

        return klass, bgp[length + 2:]
Beispiel #15
0
	def unpack_nlri (cls, afi, safi, bgp, action, addpath):
		code = ordinal(bgp[0])
		length = ordinal(bgp[1])

		if code in cls.registered_evpn:
			klass = cls.registered_evpn[code].unpack(bgp[2:length+2])
		else:
			klass = GenericEVPN(code,bgp[2:length+2])
		klass.CODE = code
		klass.action = action
		klass.addpath = addpath

		return klass,bgp[length+2:]
Beispiel #16
0
	def unpack_nlri (cls, afi, safi, bgp, action, addpath):
		length,bgp = ordinal(bgp[0]),bgp[1:]

		if length & 0xF0 == 0xF0:  # bigger than 240
			extra,bgp = ordinal(bgp[0]),bgp[1:]
			length = ((length & 0x0F) << 16) + extra

		if length > len(bgp):
			raise Notify(3,10,'invalid length at the start of the the flow')

		over = bgp[length:]
		bgp = bgp[:length]

		nlri = cls(afi,safi,action)

		if safi == SAFI.flow_vpn:
			nlri.rd = RouteDistinguisher(bgp[:8])
			bgp = bgp[8:]

		seen = []

		while bgp:
			what,bgp = ordinal(bgp[0]),bgp[1:]

			if what not in decode.get(afi,{}):
				raise Notify(3,10,'unknown flowspec component received for address family %d' % what)

			seen.append(what)
			if sorted(seen) != seen:
				raise Notify(3,10,'components are not sent in the right order %s' % seen)

			decoded = decode[afi][what]
			klass = factory[afi][what]

			if decoded == 'prefix':
				adding,bgp = klass.make(bgp)
				if not nlri.add(adding):
					raise Notify(3,10,'components are incompatible (two sources, two destinations, mix ipv4/ipv6) %s' % seen)
			else:
				end = False
				while not end:
					byte,bgp = ordinal(bgp[0]),bgp[1:]
					end = CommonOperator.eol(byte)
					operator = CommonOperator.operator(byte)
					length = CommonOperator.length(byte)
					value,bgp = bgp[:length],bgp[length:]
					adding = klass.decoder(value)
					nlri.add(klass(operator,adding))

		return nlri, bgp+over
Beispiel #17
0
	def json (self):
		h = 0x00
		for byte in self.community:
			h <<= 8
			h += ordinal(byte)
		s = self.klass.__repr__(self) if self.klass else ''
		return '{ "value": %s, "string": "%s" }' % (h,s)
Beispiel #18
0
 def spaced(value):
     even = None
     for v in value:
         if even is False:
             yield ' '
         yield '%02X' % ordinal(v)
         even = not even
Beispiel #19
0
 def json(self):
     h = 0x00
     for byte in self.community:
         h <<= 8
         h += ordinal(byte)
     s = self.klass.__repr__(self) if self.klass else ''
     return '{ "value": %ld, "string": "%s" }' % (h, s)
Beispiel #20
0
	def unpack (data):
		def _key_values (name, data):
			if len(data) < 2:
				raise Notify(2,0,"Bad length for OPEN %s (<2) %s" % (name,Capability.hex(data)))
			ld = ordinal(data[1])
			boundary = ld+2
			if len(data) < boundary:
				raise Notify(2,0,"Bad length for OPEN %s (buffer underrun) %s" % (name,Capability.hex(data)))
			key = ordinal(data[0])
			value = data[2:boundary]
			rest = data[boundary:]
			return key,value,rest

		capabilities = Capabilities()

		option_len = ordinal(data[0])
		if not option_len:
			return capabilities

		data = data[1:option_len+1]
		while data:
			key,value,data = _key_values('parameter',data)
			# Parameters must only be sent once.
			if key == Parameter.AUTHENTIFICATION_INFORMATION:
				raise Notify(2,5)

			if key == Parameter.CAPABILITIES:
				while value:
					capability,capv,value = _key_values('capability',value)
					capabilities[capability] = Capability.unpack(capability,capabilities,capv)
			else:
				raise Notify(2,0,'Unknow OPEN parameter %s' % hex(key))
		return capabilities
Beispiel #21
0
	def unpack (data):
		def _key_values (name, data):
			if len(data) < 2:
				raise Notify(2,0,"Bad length for OPEN %s (<2) %s" % (name,Capability.hex(data)))
			ld = ordinal(data[1])
			boundary = ld+2
			if len(data) < boundary:
				raise Notify(2,0,"Bad length for OPEN %s (buffer underrun) %s" % (name,Capability.hex(data)))
			key = ordinal(data[0])
			value = data[2:boundary]
			rest = data[boundary:]
			return key,value,rest

		capabilities = Capabilities()

		option_len = ordinal(data[0])
		if not option_len:
			return capabilities

		data = data[1:option_len+1]
		while data:
			key,value,data = _key_values('parameter',data)
			# Parameters must only be sent once.
			if key == Parameter.AUTHENTIFICATION_INFORMATION:
				raise Notify(2,5)

			if key == Parameter.CAPABILITIES:
				while value:
					capability,capv,value = _key_values('capability',value)
					capabilities[capability] = Capability.unpack(capability,capabilities,capv)
			else:
				raise Notify(2,0,'Unknow OPEN parameter %s' % hex(key))
		return capabilities
Beispiel #22
0
	def unpack (cls, exdata):
		data = exdata

		# Get the data length to understand if addresses are IPv4 or IPv6
		datalen = len(data)

		rd = RouteDistinguisher.unpack(data[:8])
		data = data[8:]

		esi = ESI.unpack(data[:10])
		data = data[10:]

		etag = EthernetTag.unpack(data[:4])
		data = data[4:]

		iplen = ordinal(data[0])
		data = data[1:]

		if datalen == (26 + 8):  # Using IPv4 addresses
			ip = IP.unpack(data[:4])
			data = data[4:]
			gwip = IP.unpack(data[:4])
			data = data[4:]
		elif datalen == (26 + 32):  # Using IPv6 addresses
			ip = IP.unpack(data[:16])
			data = data[16:]
			gwip = IP.unpack(data[:16])
			data = data[16:]
		else:
			raise Notify(3,5,"Data field length is given as %d, but EVPN route currently support only IPv4 or IPv6(34 or 58)" % datalen)

		label = Labels.unpack(data[:3])

		return cls(rd,esi,etag,label,ip,iplen,gwip,exdata)
Beispiel #23
0
	def spaced (value):
		even = None
		for v in value:
			if even is False:
				yield ' '
			yield '%02X' % ordinal(v)
			even = not even
Beispiel #24
0
	def decode (afi,bgp):
		mask = ordinal(bgp[0])
		size = CIDR.size(mask)

		if len(bgp) < size+1:
			raise Notify(3,10,'could not decode CIDR')

		return bgp[1:size+1] + padding(IP.length(afi)-size), mask
Beispiel #25
0
	def pack_nlri (self, negotiated=None):
		# XXX: no support for addpath yet
		# We reset ext com flag bits from the first byte in the packed RT
		# because in an RTC route these flags never appear.
		if self.rt:
			packedRT = self.rt.pack()
			return pack("!BLB", len(self), self.origin, ordinal(RTC.resetFlags(packedRT[0]))) + packedRT[1:]
		return pack("!B",0)
Beispiel #26
0
	def unpack (data, negotiated):
		communities = ExtendedCommunities()
		while data:
			if data and len(data) < 8:
				raise Notify(3,1,'could not decode extended community %s' % str([hex(ordinal(_)) for _ in data]))
			communities.add(ExtendedCommunity.unpack(data[:8],negotiated))
			data = data[8:]
		return communities
Beispiel #27
0
	def unpack (data, negotiated):
		communities = Communities()
		while data:
			if data and len(data) < 4:
				raise Notify(3,1,'could not decode community %s' % str([hex(ordinal(_)) for _ in data]))
			communities.add(Community.unpack(data[:4],negotiated))
			data = data[4:]
		return communities
Beispiel #28
0
 def __repr__(self):
     if self.klass:
         return self.klass.__repr__(self)
     h = 0x00
     for byte in self.community:
         h <<= 8
         h += ordinal(byte)
     return "0x%016X" % h
Beispiel #29
0
	def __repr__ (self):
		if self.klass:
			return self.klass.__repr__(self)
		h = 0x00
		for byte in self.community:
			h <<= 8
			h += ordinal(byte)
		return "0x%016X" % h
Beispiel #30
0
    def decode(afi, bgp):
        mask = ordinal(bgp[0])
        size = CIDR.size(mask)

        if len(bgp) < size + 1:
            raise Notify(3, 10, 'could not decode CIDR')

        return bgp[1:size + 1] + padding(IP.length(afi) - size), mask
Beispiel #31
0
	def unpack (cls, data):
		rd = RouteDistinguisher.unpack(data[:8])
		etag = EthernetTag.unpack(data[8:12])
		iplen = ordinal(data[12])
		if iplen not in (4*8,16*8):
			raise Exception("IP len is %d, but EVPN route currently support only IPv4" % iplen)
		ip = IP.unpack(data[13:13+iplen//8])
		return cls(rd,etag,ip,data)
Beispiel #32
0
    def send(self, raw):
        if self.neighbor.api.get(
                'send-%s' % Message.CODE.short(ordinal(raw[18])), False):
            message = Update.unpack_message(raw[19:], self.negotiated)
            self._to_api('send', message, raw)

        for boolean in self.connection.writer(raw):
            yield boolean
Beispiel #33
0
	def unpack (data, negotiated):
		communities = ExtendedCommunities()
		while data:
			if data and len(data) < 8:
				raise Notify(3,1,'could not decode extended community %s' % str([hex(ordinal(_)) for _ in data]))
			communities.add(ExtendedCommunity.unpack(data[:8],negotiated))
			data = data[8:]
		return communities
Beispiel #34
0
    def unpack_nlri(cls, afi, safi, bgp, action, addpath):
        nlri = cls(afi, safi, action)

        if addpath:
            nlri.path_info = PathInfo(bgp[:4])
            bgp = bgp[4:]

        mask = ordinal(bgp[0])
        bgp = bgp[1:]

        _, rd_size = Family.size.get((afi, safi), (0, 0))
        rd_mask = rd_size * 8

        if safi.has_label():
            labels = []
            while mask - rd_mask >= 24:
                label = int(unpack('!L', character(0) + bgp[:3])[0])
                bgp = bgp[3:]
                mask -= 24  # 3 bytes
                # The last 4 bits are the bottom of Stack
                # The last bit is set for the last label
                labels.append(label >> 4)
                # This is a route withdrawal
                if label == 0x800000 and action == IN.WITHDRAWN:
                    break
                # This is a next-hop
                if label == 0x000000:
                    break
                if label & 1:
                    break
            nlri.labels = Labels(labels)

        if rd_size:
            mask -= rd_mask  # the route distinguisher
            rd = bgp[:rd_size]
            bgp = bgp[rd_size:]
            nlri.rd = RouteDistinguisher(rd)

        if mask < 0:
            raise Notify(3, 10, 'invalid length in NLRI prefix')

        if not bgp and mask:
            raise Notify(
                3, 10,
                'not enough data for the mask provided to decode the NLRI')

        size = CIDR.size(mask)

        if len(bgp) < size:
            raise Notify(
                3, 10,
                'could not decode route with AFI %d and SAFI %d' % (afi, safi))

        network, bgp = bgp[:size], bgp[size:]

        nlri.cidr = CIDR(network + padding(IP.length(afi) - size), mask)

        return nlri, bgp
Beispiel #35
0
	def send (self, raw):
		code = 'send-%s' % Message.CODE.short(ordinal(raw[18]))
		self.peer.stats[code] = self.peer.stats.get(code,0) + 1
		if self.neighbor.api.get(code,False):
			message = Update.unpack_message(raw[19:],self.negotiated)
			self._to_api('send',message,raw)

		for boolean in self.connection.writer(raw):
			yield boolean
Beispiel #36
0
	def unpack_capability (instance, data, capability=None):  # pylint: disable=W0613
		# XXX: FIXME: should check that we have not yet seen the capability
		while data:
			afi = AFI.unpack(data[:2])
			safi = SAFI.unpack(data[2])
			sr = ordinal(data[3])
			instance.add_path(afi,safi,sr)
			data = data[4:]
		return instance
 def unpack_capability(instance, data, capability=None):  # pylint: disable=W0613
     # XXX: FIXME: should check that we have not yet seen the capability
     while data:
         afi = AFI.unpack(data[:2])
         safi = SAFI.unpack(data[2])
         sr = ordinal(data[3])
         instance.add_path(afi, safi, sr)
         data = data[4:]
     return instance
Beispiel #38
0
 def json(self):
     if self.capability in Capability.CODE.reserved:
         iana = 'reserved'
     elif self.capability in Capability.CODE.unassigned:
         iana = 'unassigned'
     else:
         iana = 'unknown'
     raw = ''.join('%02X' % ordinal(_) for _ in self.data)
     return '{ "name": "unknown", "iana": "%s", "value": %d, "raw": "%s" }' % (
         iana, self.capability, raw)
 def unpack(cls, data):
     rd = RouteDistinguisher.unpack(data[:8])
     etag = EthernetTag.unpack(data[8:12])
     iplen = ordinal(data[12])
     if iplen not in (4 * 8, 16 * 8):
         raise Exception(
             "IP len is %d, but EVPN route currently support only IPv4" %
             iplen)
     ip = IP.unpack(data[13:13 + iplen // 8])
     return cls(rd, etag, ip, data)
Beispiel #40
0
	def split (last):
		if Attribute.CODE.INTERNAL_SPLIT not in last.attributes:
			yield last
			return

		# ignore if the request is for an aggregate, or the same size
		mask = last.nlri.cidr.mask
		cut = last.attributes[Attribute.CODE.INTERNAL_SPLIT]
		if mask >= cut:
			yield last
			return

		# calculate the number of IP in the /<size> of the new route
		increment = pow(2,last.nlri.afi.mask() - cut)
		# how many new routes are we going to create from the initial one
		number = pow(2,cut - last.nlri.cidr.mask)

		# convert the IP into a integer/long
		ip = 0
		for c in last.nlri.cidr.ton():
			ip <<= 8
			ip += ordinal(c)

		afi = last.nlri.afi
		safi = last.nlri.safi

		# Really ugly
		klass = last.nlri.__class__
		nexthop = last.nlri.nexthop
		if safi.has_path():
			path_info = last.nlri.path_info
		if safi.has_label():
			labels = last.nlri.labels
		if safi.has_rd():
			rd = last.nlri.rd

		# XXX: Looks weird to set and then set to None, check
		last.nlri.cidr.mask = cut
		last.nlri = None

		# generate the new routes
		for _ in range(number):
			# update ip to the next route, this recalculate the "ip" field of the Inet class
			nlri = klass(afi,safi,OUT.ANNOUNCE)
			nlri.cidr = CIDR(pack_int(afi,ip),cut)
			nlri.nexthop = nexthop  # nexthop can be NextHopSelf
			if safi.has_path():
				nlri.path_info = path_info
			if safi.has_label():
				nlri.labels = labels
			if safi.has_rd():
				nlri.rd = rd
			# next ip
			ip += increment
			yield Change(nlri,last.attributes)
Beispiel #41
0
	def unpack_nlri (cls, afi, safi, bgp, action, addpath):
		nlri = cls(afi,safi,action)

		if addpath:
			nlri.path_info = PathInfo(bgp[:4])
			bgp = bgp[4:]

		mask = ordinal(bgp[0])
		bgp = bgp[1:]

		_, rd_size = Family.size.get((afi, safi), (0, 0))
		rd_mask = rd_size * 8

		if safi.has_label():
			labels = []
			while mask - rd_mask >= 24:
				label = int(unpack('!L',character(0) + bgp[:3])[0])
				bgp = bgp[3:]
				mask -= 24  	# 3 bytes
				# The last 4 bits are the bottom of Stack
				# The last bit is set for the last label
				labels.append(label >> 4)
				# This is a route withdrawal
				if label == 0x800000 and action == IN.WITHDRAWN:
					break
				# This is a next-hop
				if label == 0x000000:
					break
				if label & 1:
					break
			nlri.labels = Labels(labels)


		if rd_size:
			mask -= rd_mask  # the route distinguisher
			rd = bgp[:rd_size]
			bgp = bgp[rd_size:]
			nlri.rd = RouteDistinguisher(rd)

		if mask < 0:
			raise Notify(3,10,'invalid length in NLRI prefix')

		if not bgp and mask:
			raise Notify(3,10,'not enough data for the mask provided to decode the NLRI')

		size = CIDR.size(mask)

		if len(bgp) < size:
			raise Notify(3,10,'could not decode route with AFI %d and SAFI %d' % (afi,safi))

		network,bgp = bgp[:size],bgp[size:]

		nlri.cidr = CIDR(network + padding(IP.length(afi)-size),mask)

		return nlri,bgp
Beispiel #42
0
	def unpack (cls, data):
		rd = RouteDistinguisher.unpack(data[:8])
		esi = ESI.unpack(data[8:18])
		iplen = ordinal(data[18])

		if iplen not in (32,128):
			raise Notify(3,5,"IP length field is given as %d in current Segment, expecting 32 (IPv4) or 128 (IPv6) bits" % iplen)

		ip = IP.unpack(data[19:19+(iplen//8)])

		return cls(rd,esi,ip,data)
Beispiel #43
0
 def unpack(data, negotiated):
     communities = ExtendedCommunitiesIPv6()
     while data:
         if data and len(data) < 20:
             raise Notify(
                 3, 1, 'could not decode ipv6 extended community %s' %
                 str([hex(ordinal(_)) for _ in data]))
         communities.add(ExtendedCommunityIPv6.unpack(
             data[:20], negotiated))
         data = data[20:]
     return communities
Beispiel #44
0
	def _read_open (self):
		wait = environment.settings().bgp.openwait
		opentimer = ReceiveTimer(self.proto.connection.session,wait,1,1,'waited for open too long, we do not like stuck in active')
		# Only yield if we have not the open, otherwise the reactor can run the other connection
		# which would be bad as we need to do the collission check without going to the other peer
		for message in self.proto.read_open(self.neighbor.peer_address.top()):
			opentimer.check_ka(message)
			# XXX: FIXME: change the whole code to use the ord and not the chr version
			# Only yield if we have not the open, otherwise the reactor can run the other connection
			# which would be bad as we need to do the collission check
			if ordinal(message.TYPE) == Message.CODE.NOP:
				yield ACTION.NOW
		yield message
Beispiel #45
0
	def unpack (cls, data):
		datalen = len(data)
		rd = RouteDistinguisher.unpack(data[:8])
		esi = ESI.unpack(data[8:18])
		etag = EthernetTag.unpack(data[18:22])
		maclength = ordinal(data[22])

		if (maclength > 48 or maclength < 0):
			raise Notify(3,5,'invalid MAC Address length in %s' % cls.NAME)
		end = 23 + 6  # MAC length MUST be 6

		mac = MACQUAL.unpack(data[23:end])

		length = ordinal(data[end])
		iplen = length / 8

		if datalen in [33,36]:  # No IP information (1 or 2 labels)
			iplenUnpack = 0
			if iplen != 0:
				raise Notify(3,5,"IP length is given as %d, but current MAC route has no IP information" % iplen)
		elif datalen in [37, 40]:  # Using IPv4 addresses (1 or 2 labels)
			iplenUnpack = 4
			if (iplen > 32 or iplen < 0):
				raise Notify(3,5,"IP field length is given as %d, but current MAC route is IPv4 and valus is out of range" % iplen)
		elif datalen in [49, 52]:  # Using IPv6 addresses (1 or 2 labels)
			iplenUnpack = 16
			if (iplen > 128 or iplen < 0):
				raise Notify(3,5,"IP field length is given as %d, but current MAC route is IPv6 and valus is out of range" % iplen)
		else:
			raise Notify(3,5,"Data field length is given as %d, but does not match one of the expected lengths" % datalen)

		payload = data[end+1:end+1+iplenUnpack]
		if payload:
			ip = IP.unpack(data[end+1:end+1+iplenUnpack])
		else:
			ip = None
		label = Labels.unpack(data[end+1+iplenUnpack:end+1+iplenUnpack+3])

		return cls(rd,esi,etag,mac,maclength,label,ip,data)
Beispiel #46
0
	def _read_open (self):
		wait = environment.settings().bgp.openwait
		opentimer = ReceiveTimer(self.proto.connection.session,wait,1,1,'waited for open too long, we do not like stuck in active')
		# Only yield if we have not the open, otherwise the reactor can run the other connection
		# which would be bad as we need to do the collission check without going to the other peer
		for message in self.proto.read_open(self.neighbor.peer_address.top()):
			opentimer.check_ka(message)
			# XXX: FIXME: change the whole code to use the ord and not the chr version
			# Only yield if we have not the open, otherwise the reactor can run the other connection
			# which would be bad as we need to do the collission check
			if ordinal(message.TYPE) == Message.CODE.NOP:
				yield ACTION.NOW
		yield message
 def unpack(data, negotiated):
     large_communities = LargeCommunities()
     while data:
         if data and len(data) < 12:
             raise Notify(
                 3, 1, 'could not decode large community %s' %
                 str([hex(ordinal(_)) for _ in data]))
         lc = LargeCommunity.unpack(data[:12], negotiated)
         data = data[12:]
         if lc in large_communities.communities:
             continue
         large_communities.add(lc)
     return large_communities
Beispiel #48
0
	def unpack_capability (instance, data, capability=None):  # pylint: disable=W0613
		# XXX: FIXME: should raise if instance was already setup
		restart = unpack('!H',data[:2])[0]
		restart_flag = restart >> 12
		restart_time = restart & Graceful.TIME_MASK
		data = data[2:]
		families = []
		while data:
			afi = AFI.unpack(data[:2])
			safi = SAFI.unpack(data[2])
			flag_family = ordinal(data[3])
			families.append((afi,safi,flag_family))
			data = data[4:]
		return instance.set(restart_flag,restart_time,families)
Beispiel #49
0
	def unpack_capability (instance, data, capability=None):  # pylint: disable=W0613
		# XXX: FIXME: should raise if instance was already setup
		restart = unpack('!H',data[:2])[0]
		restart_flag = restart >> 12
		restart_time = restart & Graceful.TIME_MASK
		data = data[2:]
		families = []
		while data:
			afi = AFI.unpack(data[:2])
			safi = SAFI.unpack(data[2])
			flag_family = ordinal(data[3])
			families.append((afi,safi,flag_family))
			data = data[4:]
		return instance.set(restart_flag,restart_time,families)
Beispiel #50
0
    def __init__(self, code, subcode, data=b'', parse_data=True):
        self.code = code
        self.subcode = subcode

        if not parse_data:
            self.data = data
            return

        if not (code, subcode) in [(6, 2), (6, 4)]:
            self.data = data if not len(
                [_ for _ in str(data)
                 if _ not in string.printable]) else hexbytes(data)
            return

        if len(data) == 0:
            # shutdown without shutdown communication (the old fashioned way)
            self.data = b''
            return

        # draft-ietf-idr-shutdown or the peer was using 6,2 with data

        shutdown_length = ordinal(data[0])
        data = data[1:]

        if shutdown_length == 0:
            self.data = b"empty Shutdown Communication."
            # move offset past length field
            return

        if len(data) < shutdown_length:
            self.data = b"invalid Shutdown Communication (buffer underrun) length : %i [%s]" % (
                shutdown_length, hexstring(data))
            return

        if shutdown_length > 128:
            self.data = b"invalid Shutdown Communication (too large) length : %i [%s]" % (
                shutdown_length, hexstring(data))
            return

        try:
            self.data = b'Shutdown Communication: "%s"' % \
             data[:shutdown_length].decode('utf-8').replace('\r',' ').replace('\n',' ')
        except UnicodeDecodeError:
            self.data = b"invalid Shutdown Communication (invalid UTF-8) length : %i [%s]" % (
                shutdown_length, hexstring(data))
            return

        trailer = data[shutdown_length:]
        if trailer:
            self.data += b", trailing data: " + hexstring(trailer)
    def unpack(cls, data):
        rd = RouteDistinguisher.unpack(data[:8])
        esi = ESI.unpack(data[8:18])
        iplen = ordinal(data[18])

        if iplen not in (32, 128):
            raise Notify(
                3, 5,
                "IP length field is given as %d in current Segment, expecting 32 (IPv4) or 128 (IPv6) bits"
                % iplen)

        ip = IP.unpack(data[19:19 + (iplen // 8)])

        return cls(rd, esi, ip, data)
	def unpack_message (cls, data, _=None):
		version = ordinal(data[0])
		if version != 4:
			# Only version 4 is supported nowdays..
			raise Notify(2,1,bytes_ascii(data[0]))
		asn = unpack('!H',data[1:3])[0]
		hold_time = unpack('!H',data[3:5])[0]
		numeric = unpack('!L',data[5:9])[0]
		router_id = "%d.%d.%d.%d" % (numeric >> 24,(numeric >> 16) & 0xFF,(numeric >> 8) & 0xFF,numeric & 0xFF)
		return cls(
			Version(version),
			ASN(asn),
			HoldTime(hold_time),
			RouterID(router_id),
			Capabilities.unpack(data[9:])
		)
Beispiel #53
0
	def _read_open (self):
		wait = environment.settings().bgp.openwait
		opentimer = ReceiveTimer(self.proto.connection.session,wait,1,1,'waited for open too long, we do not like stuck in active')
		# Only yield if we have not the open, otherwise the reactor can run the other connection
		# which would be bad as we need to do the collission check without going to the other peer
		for message in self.proto.read_open(self.neighbor.peer_address.top()):
			opentimer.check_ka(message)
			# XXX: FIXME: change the whole code to use the ord and not the chr version
			# Only yield if we have not the open, otherwise the reactor can run the other connection
			# which would be bad as we need to do the collission check
			if ordinal(message.TYPE) == Message.CODE.NOP:
				# If a peer does not reply to OPEN message, or not enough bytes
				# yielding ACTION.NOW can cause ExaBGP to busy spin trying to
				# read from peer. See GH #723 .
				yield ACTION.LATER
		yield message
Beispiel #54
0
def check_message (neighbor, message):
	message = message.replace(':','')
	raw = concat_bytes_i(character(int(_,16)) for _ in (message[i*2:(i*2)+2] for i in range(len(message)//2)))

	if raw.startswith(b'\xff'*16):
		kind = ordinal(raw[18])
		# XXX: FIXME: check size
		# size = (ordinal(raw[16]) << 16) + (ordinal(raw[17]))

		if kind == 1:
			return check_open(neighbor,raw[18:])
		elif kind == 2:
			return check_update(neighbor,raw)
		elif kind == 3:
			return check_notification(raw)
	else:
		return check_update(neighbor,raw)
Beispiel #55
0
	def __init__ (self, code, subcode, data=b'', parse_data=True):
		self.code = code
		self.subcode = subcode

		if not parse_data:
			self.data = data
			return

		if not (code, subcode) in [(6, 2), (6, 4)]:
			self.data = data if not len([_ for _ in str(data) if _ not in string.printable]) else hexbytes(data)
			return

		if len(data) == 0:
			# shutdown without shutdown communication (the old fashioned way)
			self.data = b''
			return

		# draft-ietf-idr-shutdown or the peer was using 6,2 with data

		shutdown_length  = ordinal(data[0])
		data = data[1:]

		if shutdown_length == 0:
			self.data = b"empty Shutdown Communication."
			# move offset past length field
			return

		if len(data) < shutdown_length:
			self.data = b"invalid Shutdown Communication (buffer underrun) length : %i [%s]" % (shutdown_length, hexstring(data))
			return

		if shutdown_length > 128:
			self.data = b"invalid Shutdown Communication (too large) length : %i [%s]" % (shutdown_length, hexstring(data))
			return

		try:
			self.data = b'Shutdown Communication: "%s"' % \
				data[:shutdown_length].decode('utf-8').replace('\r',' ').replace('\n',' ')
		except UnicodeDecodeError:
			self.data = b"invalid Shutdown Communication (invalid UTF-8) length : %i [%s]" % (shutdown_length, hexstring(data))
			return

		trailer = data[shutdown_length:]
		if trailer:
			self.data += b", trailing data: " + hexstring(trailer)
Beispiel #56
0
	def unpack_nlri (cls, afi, safi, bgp, action, addpath):

		length = ordinal(bgp[0])

		if length == 0:
			return cls(afi,safi,action,ASN(0),None),bgp[1:]

		if length < 8*4:
			raise Exception("incorrect RT length: %d (should be >=32,<=96)" % length)

		# We are reseting the flags on the RouteTarget extended
		# community, because they do not make sense for an RTC route

		return cls(
			afi, safi, action,
			ASN(unpack('!L', bgp[1:5])[0]),
			RouteTarget.unpack(
				RTC.resetFlags(bgp[5])+bgp[6:13]
			)
		),bgp[13:]