예제 #1
0
    def split(data):
        length = len(data)

        len_withdrawn = unpack('!H', data[0:2])[0]
        withdrawn = data[2:len_withdrawn + 2]

        if len(withdrawn) != len_withdrawn:
            raise Notify(
                3, 1,
                'invalid withdrawn routes length, not enough data available')

        start_attributes = len_withdrawn + 4
        len_attributes = unpack('!H',
                                data[len_withdrawn + 2:start_attributes])[0]
        start_announced = len_withdrawn + len_attributes + 4
        attributes = data[start_attributes:start_announced]
        announced = data[start_announced:]

        if len(attributes) != len_attributes:
            raise Notify(
                3, 1,
                'invalid total path attribute length, not enough data available'
            )

        if 2 + len_withdrawn + 2 + len_attributes + len(announced) != length:
            raise Notify(
                3, 1,
                'error in BGP message length, not enough data for the size announced'
            )

        return withdrawn, attributes, announced
예제 #2
0
    def read_message(self):
        for length, msg, header, body, notify in self.connection.reader():
            if notify:
                if self.neighbor.api['receive-packets']:
                    self.peer.reactor.processes.receive(
                        self.peer, msg, header, body)
                if self.neighbor.api[Message.ID.NOTIFICATION]:
                    self.peer.reactor.processes.notification(
                        self.peer, notify.code, notify.subcode, str(notify))
                # XXX: is notify not already Notify class ?
                raise Notify(notify.code, notify.subcode, str(notify))
            if not length:
                yield _NOP

        if self.neighbor.api[
                'receive-packets'] and not self.neighbor.api['consolidate']:
            self.peer.reactor.processes.receive(self.peer, msg, header, body)

        if msg == Message.ID.UPDATE and not self.neighbor.api[
                'receive-parsed'] and not self.log_routes:
            yield _UPDATE
            return

        self.logger.message(self.me('<< %s' % Message.ID.name(msg)))
        try:
            message = Message.unpack_message(msg, body, self.negotiated)
        except (KeyboardInterrupt, SystemExit, Notify):
            raise
        except Exception, e:
            self.logger.message(
                self.me('Could not decode message %s' % Capability.hex(msg)))
            self.logger.message(self.me('%s' % str(e)))
            raise Notify(
                2, 0, 'can not decode update message %s' % Capability.hex(msg))
예제 #3
0
파일: mpurnlri.py 프로젝트: pierky/exabgp
    def packed_attributes(self, negotiated, maximum=Negotiated.FREE_SIZE):
        if not self.nlris:
            return

        # we changed the API to nrli.pack from addpath to negotiated but not pack itself

        mpurnlri = []
        for nlri in self.nlris:
            if nlri.family() != self.family(
            ):  # nlri is not part of specified family
                continue
            mpurnlri.append(nlri.pack(negotiated))

        payload = self.afi.pack() + self.safi.pack()
        header_length = len(payload)
        for nlri in mpurnlri:
            if self._len(payload + nlri) > maximum:
                if len(payload) == header_length or len(payload) > maximum:
                    raise Notify(
                        6, 0,
                        'attributes size is so large we can not even pack on MPURNLRI'
                    )
                yield self._attribute(payload)
                payload = self.afi.pack() + self.safi.pack() + nlri
                continue
            payload = payload + nlri
        if len(payload) == header_length or len(payload) > maximum:
            raise Notify(
                6, 0,
                'attributes size is so large we can not even pack on MPURNLRI')
        yield self._attribute(payload)
예제 #4
0
	def packed_attributes (self, negotiated, maximum=Negotiated.FREE_SIZE):
		if not self.nlris:
			return

		# addpath = negotiated.addpath.send(self.afi,self.safi)
		# nexthopself = negotiated.nexthopself(self.afi)
		mpnlri = {}
		for nlri in self.nlris:
			if nlri.family() != self.family():  # nlri is not part of specified family
				continue
			if nlri.nexthop is NoNextHop:
				# EOR and Flow may not have any next_hop
				nexthop = b''
			else:
				_,rd_size = Family.size.get(self.family(),(0,0))
				nh_rd = character(0)*rd_size if rd_size else b''
				nexthop = nh_rd + nlri.nexthop.ton(negotiated,nlri.afi)

			# mpunli[nexthop] = nlri
			mpnlri.setdefault(nexthop,[]).append(nlri.pack(negotiated))

		for nexthop,nlris in six.iteritems(mpnlri):
			payload = concat_bytes(self.afi.pack(), self.safi.pack(), character(len(nexthop)), nexthop, character(0))
			header_length = len(payload)
			for nlri in nlris:
				if self._len(payload + nlri) > maximum:
					if len(payload) == header_length or len(payload) > maximum:
						raise Notify(6, 0, 'attributes size is so large we can not even pack on MPRNLRI')
					yield self._attribute(payload)
					payload = concat_bytes(self.afi.pack(), self.safi.pack(), character(len(nexthop)), nexthop, character(0), nlri)
					continue
				payload  = concat_bytes(payload, nlri)
			if len(payload) == header_length or len(payload) > maximum:
				raise Notify(6, 0, 'attributes size is so large we can not even pack on MPRNLRI')
			yield self._attribute(payload)
예제 #5
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)))
			l = ord(data[1])
			boundary = l+2
			if len(data) < boundary:
				raise Notify(2,0,"Bad length for OPEN %s (buffer underrun) %s" % (name,Capability.hex(data)))
			key = ord(data[0])
			value = data[2:boundary]
			rest = data[boundary:]
			return key,value,rest

		capabilities = Capabilities()

		option_len = ord(data[0])
		# XXX: FIXME: check the length of data
		if option_len:
			data = data[1:]
			while data:
				key,value,data = _key_values('parameter',data)
				# Paramaters 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
예제 #6
0
    def unpack_nlri(cls, afi, safi, bgp, action, addpath):
        length, bgp = ord(bgp[0]), bgp[1:]

        if length & 0xF0 == 0xF0:  # bigger than 240
            extra, bgp = ord(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 = Flow(afi, safi, action)

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

        seen = []

        while bgp:
            what, bgp = ord(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 = ord(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
예제 #7
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 = 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', bytes([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 family %s (AFI %d) %s (SAFI %d)' %
                (AFI(afi), int(afi), SAFI(safi), int(safi)))

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

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

        return nlri, bgp
예제 #8
0
    def packed_attributes(self, negotiated, maximum=Negotiated.FREE_SIZE):
        if not self.nlris:
            return

        # addpath = negotiated.addpath.send(self.afi,self.safi)
        # nexthopself = negotiated.nexthopself(self.afi)
        mpnlri = {}
        for nlri in self.nlris:
            if nlri.family() != self.family(
            ):  # nlri is not part of specified family
                continue
            if nlri.nexthop is NoNextHop:
                # EOR and Flow may not have any next_hop
                nexthop = b''
            else:
                _, rd_size = Family.size.get(self.family(), (0, 0))
                nh_rd = bytes([0]) * rd_size if rd_size else b''
                try:
                    nexthop = nh_rd + nlri.nexthop.ton(negotiated, nlri.afi)
                except TypeError:
                    # we could not match "next-hop self" with the BGP AFI of the BGP sesion
                    # attempting invalid IPv4 next-hop (0.0.0.0) to try to not kill the session
                    # and preserve some form of backward compatibility (for some vendors)
                    # the next-hop may have been IPv6 but not valided as the RFC says
                    #
                    # An UPDATE message that carries no NLRI, other than the one encoded in
                    # the MP_REACH_NLRI attribute, SHOULD NOT carry the NEXT_HOP attribute.
                    # If such a message contains the NEXT_HOP attribute, the BGP speaker
                    # that receives the message SHOULD ignore this attribute.
                    #
                    # Some vendors may have therefore not valided the next-hop
                    # and accepted invalid IPv6 next-hop in the past
                    nexthop = bytes([0]) * 4

            # mpunli[nexthop] = nlri
            mpnlri.setdefault(nexthop, []).append(nlri.pack(negotiated))

        for nexthop, nlris in mpnlri.items():
            payload = self.afi.pack() + self.safi.pack() + bytes(
                [len(nexthop)]) + nexthop + bytes([0])
            header_length = len(payload)
            for nlri in nlris:
                if self._len(payload + nlri) > maximum:
                    if len(payload) == header_length or len(payload) > maximum:
                        raise Notify(
                            6, 0,
                            'attributes size is so large we can not even pack on MPRNLRI'
                        )
                    yield self._attribute(payload)
                    payload = self.afi.pack() + self.safi.pack() + bytes(
                        [len(nexthop)]) + nexthop + bytes([0]) + nlri
                    continue
                payload = payload + nlri
            if len(payload) == header_length or len(payload) > maximum:
                raise Notify(
                    6, 0,
                    'attributes size is so large we can not even pack on MPRNLRI'
                )
            yield self._attribute(payload)
예제 #9
0
 def unpack_message(cls, data, _):
     try:
         afi, reserved, safi = unpack('!HBB', data)
     except error:
         raise Notify(7, 1, 'invalid route-refresh message')
     if reserved not in (0, 1, 2):
         raise Notify(7, 2, 'invalid route-refresh message subtype')
     return RouteRefresh(afi, safi, reserved)
예제 #10
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 = data[0]
                slen = 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)
예제 #11
0
    def packed_attributes(self, negotiated, maximum=Negotiated.FREE_SIZE):
        if not self.nlris:
            return

        # addpath = negotiated.addpath.send(self.afi,self.safi)
        # nexthopself = negotiated.nexthopself(self.afi)
        mpnlri = {}
        for nlri in self.nlris:
            if nlri.family() != self.family(
            ):  # nlri is not part of specified family
                continue
            if nlri.nexthop is NoNextHop:
                # EOR and Flow may not have any next_hop
                nexthop = ''
            else:
                # we do not want a next_hop attribute packed (with the _attribute()) but just the next_hop itself
                if nlri.safi.has_rd():
                    # .packed and not .pack()
                    nexthop = chr(0) * 8 + nlri.nexthop.ton(
                        negotiated, nlri.afi)
                else:
                    # .packed and not .pack()
                    nexthop = nlri.nexthop.ton(negotiated, nlri.afi)

            # mpunli[nexthop] = nlri
            mpnlri.setdefault(nexthop, []).append(nlri.pack(negotiated))

        for nexthop, nlris in mpnlri.iteritems():
            payload = ''.join([
                self.afi.pack(),
                self.safi.pack(),
                chr(len(nexthop)), nexthop,
                chr(0)
            ])
            header_length = len(payload)
            for nlri in nlris:
                if self._len(payload + nlri) > maximum:
                    if len(payload) == header_length or len(payload) > maximum:
                        raise Notify(
                            6, 0,
                            'attributes size is so large we can not even pack on MPRNLRI'
                        )
                    yield self._attribute(payload)
                    payload = ''.join([
                        self.afi.pack(),
                        self.safi.pack(),
                        chr(len(nexthop)), nexthop,
                        chr(0), nlri
                    ])
                    continue
                payload = ''.join([payload, nlri])
            if len(payload) == header_length or len(payload) > maximum:
                raise Notify(
                    6, 0,
                    'attributes size is so large we can not even pack on MPRNLRI'
                )
            yield self._attribute(payload)
예제 #12
0
파일: inet.py 프로젝트: doddt/exabgp
    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 = ord(bgp[0])
        bgp = bgp[1:]

        if cls.has_label():
            labels = []
            while bgp and mask >= 8:
                label = int(unpack('!L', chr(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 cls.has_rd():
            mask -= 8 * 8  # the 8 bytes of the route distinguisher
            rd = bgp[:8]
            bgp = bgp[8:]
            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 sand SAFI %d' %
                (afi, safi))

        network, bgp = bgp[:size], bgp[size:]
        padding = '\0' * (IP.length(afi) - size)

        nlri.cidr = CIDR(network + padding, mask)

        return nlri, bgp
예제 #13
0
파일: mac.py 프로젝트: bopopescu/exabgp-1
    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 = 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 = 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)
예제 #14
0
    def _nlri(afi, safi, bgp, action, addpath):
        labels = []
        rd = ''

        if addpath:
            path_identifier = bgp[:4]
            bgp = bgp[4:]
        else:
            path_identifier = None

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

        if SAFI(safi).has_label():
            while bgp and mask >= 8:
                label = int(unpack('!L', chr(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

        if SAFI(safi).has_rd():
            mask -= 8 * 8  # the 8 bytes of the route distinguisher
            rd = bgp[:8]
            bgp = bgp[8:]

        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 sand SAFI %d' %
                (afi, safi))

        network, bgp = bgp[:size], bgp[size:]
        padding = '\0' * (IP.length(afi) - size)
        prefix = network + padding

        return labels, rd, path_identifier, mask, size, prefix, bgp
예제 #15
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)))
			l = ord(data[1])
			boundary = l+2
			if len(data) < boundary:
				raise Notify(2,0,"Bad length for OPEN %s (buffer underrun) %s" % (name,Capability.hex(data)))
			key = ord(data[0])
			value = data[2:boundary]
			rest = data[boundary:]
			return key,value,rest
예제 #16
0
 def tick(self, message=_NOP, ignore=_NOP.TYPE):
     if message.TYPE != ignore:
         self.last_read = time.time()
     if self.holdtime:
         left = int(self.last_read + self.holdtime - time.time())
         self.logger.timers(
             self.me('Receive Timer %d second(s) left' % left))
         if left <= 0:
             raise Notify(self.code, self.subcode, self.message)
     elif message.TYPE == KeepAlive.TYPE:
         raise Notify(2, 6,
                      'Holdtime is zero and we got a keepalive message')
예제 #17
0
def _nlrifactory(afi, safi, bgp, action):
    labels = []
    rd = ''

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

    if SAFI(safi).has_label():
        while bgp and mask >= 8:
            label = int(unpack('!L', chr(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

    if SAFI(safi).has_rd():
        mask -= 8 * 8  # the 8 bytes of the route distinguisher
        rd = bgp[:8]
        bgp = bgp[8:]

    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 = mask_to_bytes.get(mask, None)
    if size is None:
        raise Notify(3, 10, 'invalid netmask found when decoding NLRI')

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

    network, bgp = bgp[:size], bgp[size:]
    padding = '\0' * (NLRI.length[afi] - size)
    prefix = network + padding

    return labels, rd, mask, size, prefix, bgp
예제 #18
0
파일: timer.py 프로젝트: andychenzy/exabgp
 def check_ka(self, message=_NOP, ignore=_NOP.TYPE):
     if message.TYPE != ignore:
         self.last_read = time.time()
     if self.holdtime:
         left = int(self.last_read + self.holdtime - time.time())
         self.logger.timers(
             self.me('Receive Timer %d second(s) left' % left))
         if left <= 0:
             raise Notify(self.code, self.subcode, self.message)
     elif message.TYPE == KeepAlive.TYPE:
         raise Notify(
             2, 6,
             'Negotiated holdtime was zero, it was invalid to send us a keepalive messages'
         )
예제 #19
0
    def __new_aspaths(cls, data, asn4, klass=None):
        as_set = []
        as_seq = []
        backup = data

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

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

        try:

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

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

                end = 2 + (slen * length)
                sdata = data[2:end]
                data = data[end:]
                asns = as_choice[stype]

                for i 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, backup)
        return cls(as_seq, as_set, backup)
예제 #20
0
    def read_message(self):
        # This will always be defined by the loop but scope leaking upset scrutinizer/pylint
        msg_id = None

        packets = self.neighbor.api['receive-packets']
        consolidate = self.neighbor.api['receive-consolidate']
        parsed = self.neighbor.api['receive-parsed']

        for length, msg_id, header, body, notify in self.connection.reader():
            if notify:
                if self.neighbor.api['receive-%d' % Message.CODE.NOTIFICATION]:
                    if packets and not consolidate:
                        self.peer.reactor.processes.packets(
                            self.peer.neighbor, 'receive', msg_id, header,
                            body)

                    if not packets or consolidate:
                        header = ''
                        body = ''

                    self.peer.reactor.processes.notification(
                        self.peer.neighbor, 'receive', notify.code,
                        notify.subcode, str(notify), header, body)
                # XXX: is notify not already Notify class ?
                raise Notify(notify.code, notify.subcode, str(notify))
            if not length:
                yield _NOP

        if packets and not consolidate:
            self.peer.reactor.processes.packets(self.peer.neighbor, 'receive',
                                                msg_id, header, body)

        if msg_id == Message.CODE.UPDATE:
            if not parsed and not self.log_routes:
                yield _UPDATE
                return

        self.logger.message(self.me('<< %s' % Message.CODE.name(msg_id)))
        try:
            message = Message.unpack(msg_id, body, self.negotiated)
        except (KeyboardInterrupt, SystemExit, Notify):
            raise
        except Exception, exc:
            self.logger.message(
                self.me('Could not decode message "%d"' % msg_id))
            self.logger.message(self.me('%s' % str(exc)))
            self.logger.message(traceback.format_exc())
            raise Notify(1, 0,
                         'can not decode update message of type "%d"' % msg_id)
예제 #21
0
파일: igpflags.py 프로젝트: x11us/exabgp
	def unpack (cls,data,length):
		igpflags = ['D', 'N', 'L', 'P']
		if length > 1:
			raise Notify(3,5, "IGP Flags TLV length too large")
		else:
			flag_array = binascii.b2a_hex(data[0])
			hex_rep = hex(int(flag_array, 16))
			bit_array = BitArray(hex_rep)
			valid_flags = [''.join(item)+'0000' for item in itertools.product('01', repeat=4)]
 			valid_flags.append('0000')
 			if bit_array.bin in valid_flags:
				flags = dict(zip(igpflags, bit_array.bin))
				return cls(igpflags=flags)
			else:
    				raise Notify(3,5, "Invalid IGP flags mask")
예제 #22
0
파일: mplsmask.py 프로젝트: leleobhz/exabgp
	def unpack (cls,data,length):
		mpls_mask = ['LDP', 'RSVP-TE', 'RSV', 'RSV', 'RSV', 'RSV', 'RSV', 'RSV']
		if length > 1:
			raise Notify(3,5, "LINK TLV length too large")
		else:
			flag_array = binascii.b2a_hex(data[0])
			hex_rep = hex(int(flag_array, 16))
			bit_array = BitArray(hex_rep)
			valid_flags = [''.join(item)+'000000' for item in itertools.product('01', repeat=2)]
			valid_flags.append('0000')
			if bit_array.bin in valid_flags:
				flags = dict(zip(mpls_mask, bit_array.bin))
				return cls(mplsflags=flags)
			else:
				raise Notify(3,5, "Invalid MPLS flags mask")
예제 #23
0
	def __call__ (self):
		#  True  if we need or are trying
		#  False if we do not need to send one
		try:
			return self._generator.next()
		except StopIteration:
			raise Notify(4,0,'could not send keepalive')
예제 #24
0
	def _keepalive (self, proto):
		need_ka   = False
		generator = None

		while True:
			# SEND KEEPALIVES
			need_ka |= self.send_timer.need_ka()

			if need_ka:
				if not generator:
					generator = proto.new_keepalive()
					need_ka = False

			if not generator:
				yield False
				continue

			try:
				# try to close the generator and raise a StopIteration in one call
				generator.next()
				generator.next()
				# still running
				yield True
			except NetworkError:
				raise Notify(4,0,'problem with network while trying to send keepalive')
			except StopIteration:
				generator = None
				yield False
예제 #25
0
파일: srcap.py 프로젝트: gklinich/exabgp
    def unpack(cls, data):
        # Extract node capability flags
        flags = cls.unpack_flags(data[0:1])
        # Move pointer past flags and reserved bytes
        data = data[2:]
        sids = []

        while data:
            # Range Size: 3 octet value indicating the number of labels in
            # the range.
            range_size = unpack('!L', bytes([0]) + data[:3])[0]

            # SID/Label: If length is set to 3, then the 20 rightmost bits
            # represent a label.  If length is set to 4, then the value
            # represents a 32 bit SID.
            t, l = unpack('!HH', data[3:7])
            if t != 1161:
                raise Notify(3, 5, "Invalid sub-TLV type: {}".format(t))
            if l == 3:
                sids.append([
                    range_size,
                    unpack('!I',
                           bytes([0]) + data[7:l + 7])[0] & 0xfffff
                ])
            elif l == 4:
                # XXX: really we are reading 7+ but then re-parsing it again ??
                sids.append([range_size, unpack('!I', data[7:l + 7])[0]])
            data = data[l + 7:]

        return cls(flags, sids)
예제 #26
0
파일: flow.py 프로젝트: tempbottle/exabgp
    def pack(self, negotiated=None):
        ordered_rules = []
        # the order is a RFC requirement
        for ID in sorted(self.rules.keys()):
            rules = self.rules[ID]
            # for each component get all the operation to do
            # the format use does not prevent two opposing rules meaning that no packet can ever match
            for rule in rules:
                rule.operations &= (CommonOperator.EOL ^ 0xFF)
            rules[-1].operations |= CommonOperator.EOL
            # and add it to the last rule
            if ID not in (FlowDestination.ID, FlowSource.ID):
                ordered_rules.append(chr(ID))
            ordered_rules.append(''.join(rule.pack() for rule in rules))

        components = self.rd.pack() + ''.join(ordered_rules)

        l = len(components)
        if l < 0xF0:
            return "%s%s" % (chr(l), components)
        if l < 0x0FFF:
            return "%s%s" % (pack('!H', l | 0xF000), components)
        raise Notify(
            3, 0,
            "my administrator attempted to announce a Flow Spec rule larger than encoding allows, protecting the innocent the only way I can"
        )
예제 #27
0
 def unpack(cls, data, length):
     if length != 4:
         raise Notify(3, 5, "Unable to decode attribute. Incorrect Size")
     else:
         b = BitArray(bytes=data)
         colormask = b.unpack('uintbe:32')
         return cls(colormask=colormask)
예제 #28
0
    def pack(self, addpath=None):
        ordered_rules = []
        # the order is a RFC requirement
        for ID in sorted(self.rules.keys()):
            rules = self.rules[ID]
            # for each component get all the operation to do
            # the format use does not prevent two opposing rules meaning that no packet can ever match
            for rule in rules:
                rule.operations &= (CommonOperator.EOL ^ 0xFF)
            rules[-1].operations |= CommonOperator.EOL
            # and add it to the last rule
            if ID not in (FlowDestination.ID, FlowSource.ID):
                ordered_rules.append(chr(ID))
            ordered_rules.append(''.join(rule.pack() for rule in rules))

        components = ''.join(ordered_rules)

        if self.safi == SAFI.flow_vpn:
            components = self.rd.pack() + components

        l = len(components)
        if l < 0xF0:
            data = "%s%s" % (chr(l), components)
        elif l < 0x0FFF:
            data = "%s%s" % (pack('!H', l | 0xF000), components)
        else:
            raise Notify(
                3, 0,
                "rule too big for NLRI - how to handle this - does this work ?"
            )
            # data = "%s" % chr(0)

        return data
예제 #29
0
    def unpack(cls, data, negotiated):
        try:
            if cls.cached:
                if data == cls.previous:
                    return cls.cached
                # # This code may mess with the cached data
                # elif cls.previous and data.startswith(cls.previous):
                # 	attributes = Attributes()
                # 	for key in cls.cached:
                # 		attributes[key] = cls.cached[key]
                # 	attributes.parse(data[len(cls.previous):],negotiated)
                else:
                    attributes = cls().parse(data, negotiated)
            else:
                attributes = cls().parse(data, negotiated)

            if Attribute.CODE.AS_PATH in attributes and Attribute.CODE.AS4_PATH in attributes:
                attributes.merge_attributes()

            if Attribute.CODE.MP_REACH_NLRI not in attributes and Attribute.CODE.MP_UNREACH_NLRI not in attributes:
                cls.previous = data
                cls.cached = attributes
            else:
                cls.previous = ''
                cls.cached = None

            return attributes
        except IndexError:
            raise Notify(3, 2, data)
예제 #30
0
    def add(self, attribute, _=None):
        # we return None as attribute if the unpack code must not generate them
        if attribute is None:
            return

        self._str = ''
        self._json = ''

        # XXX: FIXME: I am not sure anymore that more than one of each is possible
        if attribute.ID in Attributes.MULTIPLE:
            # deadcode: setdefault does not seem to exist anywhere ? (TM)
            self.setdefault(attribute.ID, []).append(attribute)
        # elif attribute.ID in (Attribute.CODE.COMMUNITY, Attribute.CODE.EXTENDED_COMMUNITY):
        # 	if attribute.ID not in self:
        # 		self[attribute.ID] = Attribute.klass(attribute.ID,attribute.FLAG)()
        # 	self[attribute.ID].add(attribute)
        elif attribute.ID in self:
            # For flows we can add extended-communities using special keywords and extended-community
            # This allows this trick
            if attribute.ID != Attribute.CODE.EXTENDED_COMMUNITY:
                raise Notify(
                    3, 0, 'multiple attribute for %s' %
                    str(Attribute.CODE(attribute.ID)))
            for community in attribute.communities:
                self[attribute.ID].add(community)
        else:
            self[attribute.ID] = attribute