def pack (self): rs = [] for k,capabilities in six.iteritems(self): for capability in capabilities.extract(): rs.append(concat_bytes(character(k),character(len(capability)),capability)) parameters = concat_bytes_i(concat_bytes(character(2),character(len(r)),r) for r in rs) return concat_bytes(character(len(parameters)),parameters)
def _segment (self, seg_type, values, asn4): length = len(values) if length: if length > 255: return self._segment(seg_type,values[:255],asn4) + self._segment(seg_type,values[255:],asn4) return concat_bytes(character(seg_type),character(len(values)),concat_bytes_i(v.pack(asn4) for v in values)) return b""
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)
def pack_nlri(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(character(ID)) ordered_rules.append(concat_bytes_i(rule.pack() for rule in rules)) components = self.rd.pack() + concat_bytes_i(ordered_rules) lc = len(components) if lc < 0xF0: return concat_bytes(character(lc), components) if lc < 0x0FFF: return concat_bytes(pack('!H', lc | 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" )
def extract(self): rs = [ character(0), ] for v in self: rs.append(character(v)) return rs
def extract (self): return [concat_bytes( character(len(self.host_name)), self.host_name, character(len(self.domain_name)), self.domain_name, )]
def __init__ (self, packed=None, integer=None, ip=None): if packed: self.path_info = packed elif ip: self.path_info = concat_bytes_i(character(int(_)) for _ in ip.split('.')) elif integer: self.path_info = concat_bytes_i(character((integer >> offset) & 0xff) for offset in [24,16,8,0]) else: self.path_info = b''
def extract(self): return [ concat_bytes( character(len(self.host_name)), self.host_name, character(len(self.domain_name)), self.domain_name, ) ]
def pack (self, negotiated=None): flag = self.FLAG length = len(self.data) if length > 0xFF: flag |= Attribute.Flag.EXTENDED_LENGTH if flag & Attribute.Flag.EXTENDED_LENGTH: len_value = pack('!H',length) else: len_value = character(length) return concat_bytes(character(flag),character(self.ID),len_value,self.data)
def _segment(self, seg_type, values, asn4): length = len(values) if length: if length > 255: return self._segment(seg_type, values[:255], asn4) + self._segment( seg_type, values[255:], asn4) return concat_bytes(character(seg_type), character(len(values)), concat_bytes_i(v.pack(asn4) for v in values)) return b""
def route_distinguisher(tokeniser): data = tokeniser() separator = data.find(':') if separator > 0: prefix = data[:separator] suffix = int(data[separator + 1:]) if '.' in prefix: data = [character(0), character(1)] data.extend([character(int(_)) for _ in prefix.split('.')]) data.extend([character(suffix >> 8), character(suffix & 0xFF)]) rtd = concat_bytes_i(data) else: number = int(prefix) if number < pow(2, 16) and suffix < pow(2, 32): rtd = character(0) + character(0) + pack('!H', number) + pack( '!L', suffix) elif number < pow(2, 32) and suffix < pow(2, 16): rtd = character(0) + character(2) + pack('!L', number) + pack( '!H', suffix) else: raise ValueError('invalid route-distinguisher %s' % data) return RouteDistinguisher(rtd)
class ESI(object): DEFAULT = concat_bytes_i(character(0) for _ in range(0, 10)) MAX = concat_bytes_i(character(0xFF) for _ in range(0, 10)) __slots__ = ['esi'] def __init__(self, esi=None): self.esi = self.DEFAULT if esi is None else esi if len(self.esi) != 10: raise Exception("incorrect ESI, len %d instead of 10" % len(esi)) def __eq__(self, other): return self.esi == other.esi def __neq__(self, other): return self.esi != other.esi def __lt__(self, other): raise RuntimeError('comparing ESI for ordering does not make sense') def __le__(self, other): raise RuntimeError('comparing ESI for ordering does not make sense') def __gt__(self, other): raise RuntimeError('comparing ESI for ordering does not make sense') def __ge__(self, other): raise RuntimeError('comparing ESI for ordering does not make sense') def __str__(self): if self.esi == self.DEFAULT: return "-" return ":".join('%02x' % ordinal(_) for _ in self.esi) def __repr__(self): return self.__str__() def pack(self): return self.esi def __len__(self): return 10 def __hash__(self): return hash(self.esi) @classmethod def unpack(cls, data): return cls(data[:10]) def json(self, compact=None): return '"esi": "%s"' % str(self)
def _attribute(self, value): flag = self.FLAG if flag & Attribute.Flag.OPTIONAL and not value: return b'' length = len(value) if length > 0xFF: flag |= Attribute.Flag.EXTENDED_LENGTH if flag & Attribute.Flag.EXTENDED_LENGTH: len_value = pack('!H', length) else: len_value = character(length) return concat_bytes(character(flag), character(self.ID), len_value, value)
def attribute(tokeniser): start = tokeniser() if start != '[': raise ValueError('invalid attribute, does not starts with [') code = tokeniser().lower() if not code.startswith('0x'): raise ValueError('invalid attribute, code is not 0x hexadecimal') try: code = int(code, 16) except ValueError: raise ValueError('invalid attribute, code is not 0x hexadecimal') flag = tokeniser().lower() if not flag.startswith('0x'): raise ValueError('invalid attribute, flag is not 0x hexadecimal') try: flag = int(flag, 16) except ValueError: raise ValueError('invalid attribute, flag is not 0x hexadecimal') data = tokeniser().lower() if not data.startswith('0x'): raise ValueError('invalid attribute, data is not 0x hexadecimal') if len(data) % 2: raise ValueError('invalid attribute, data is not 0x hexadecimal') data = concat_bytes_i( character(int(data[_:_ + 2], 16)) for _ in range(2, len(data), 2)) end = tokeniser() if end != ']': raise ValueError('invalid attribute, does not ends with ]') return GenericAttribute(code, flag, data)
def unescape (string): start = 0 while start < len(string): pos = string.find('\\', start) if pos == -1: yield string[start:] break yield string[start:pos] pos += 1 esc = string[pos] if esc == 'b': yield '\b' elif esc == 'f': yield '\f' elif esc == 'n': yield '\n' elif esc == 'r': yield '\r' elif esc == 't': yield '\t' elif esc == 'u': yield character(int(string[pos + 1:pos + 5], 16)) pos += 4 else: yield esc start = pos + 1
def attribute (tokeniser): start = tokeniser() if start != '[': raise ValueError('invalid attribute, does not starts with [') code = tokeniser().lower() if not code.startswith('0x'): raise ValueError('invalid attribute, code is not 0x hexadecimal') try: code = int(code,16) except ValueError: raise ValueError('invalid attribute, code is not 0x hexadecimal') flag = tokeniser().lower() if not flag.startswith('0x'): raise ValueError('invalid attribute, flag is not 0x hexadecimal') try: flag = int(flag,16) except ValueError: raise ValueError('invalid attribute, flag is not 0x hexadecimal') data = tokeniser().lower() if not data.startswith('0x'): raise ValueError('invalid attribute, data is not 0x hexadecimal') if len(data) % 2: raise ValueError('invalid attribute, data is not 0x hexadecimal') data = concat_bytes_i(character(int(data[_:_+2],16)) for _ in range(2,len(data),2)) end = tokeniser() if end != ']': raise ValueError('invalid attribute, does not ends with ]') return GenericAttribute(code,flag,data)
def _signature_segment (self, asns=None, skis=None): sig_segment = [] if not skis or not asns: skis = copy.deepcopy(self.all_skis) #skis.reverse() # split SKI string into 2 letters step = 2 #for ski in reversed(skis): for ski in skis: #self.ski_str = self.negotiated.neighbor.ski[0] self.ski_str = ski splitSKI = [ski[i:i+step] for i in range(0, len(ski), step) ] # convert hexstring into integer result = [ character( int(splitSKI[i], 16)) for i in range (0, len(splitSKI))] sig_segment.extend(result) # processing signatures # dict-asn-ski.keys(): list of keys, dict.values(): list of values list.index(n): index number if self.dict_asn_ski and ski in self.dict_asn_ski.values() : host_asn = list(self.dict_asn_ski.keys())[list(self.dict_asn_ski.values()).index(ski)] else : # TODO: need default action host_asn = None sig_segment_value = self._signature(host_asn, ski) if not sig_segment_value : return None sig_segment.append(sig_segment_value) self.signature_block_len += self.SIG_LEN + self.SKI_LEN return sig_segment
def unescape(string): start = 0 while start < len(string): pos = string.find('\\', start) if pos == -1: yield string[start:] break yield string[start:pos] pos += 1 esc = string[pos] if esc == 'b': yield '\b' elif esc == 'f': yield '\f' elif esc == 'n': yield '\n' elif esc == 'r': yield '\r' elif esc == 't': yield '\t' elif esc == 'u': yield character(int(string[pos + 1:pos + 5], 16)) pos += 4 else: yield esc start = pos + 1
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')
def pack(self, negotiated=None): addpath = self.path_info.pack( ) if negotiated and negotiated.addpath.send(self.afi, self.safi) else b'' mask = character( len(self.labels) * 8 + len(self.rd) * 8 + self.cidr.mask) return addpath + mask + self.labels.pack() + self.rd.pack( ) + self.cidr.pack_ip()
class EOR(Message): ID = Message.CODE.UPDATE TYPE = character(Message.CODE.UPDATE) class NLRI(_NLRI): PREFIX = b'\x00\x00\x00\x07\x90\x0F\x00\x03' MP_LENGTH = len(PREFIX) + 1 + 2 # len(AFI) and len(SAFI) EOR = True nexthop = None def __init__(self, afi, safi, action): _NLRI.__init__(self, afi, safi, action) self.action = action self.afi = afi self.safi = safi def pack_nlri(self, negotiated=None): if self.afi == AFI.ipv4 and self.safi == SAFI.unicast: return b'\x00\x00\x00\x00' return self.PREFIX + self.afi.pack() + self.safi.pack() def __repr__(self): return self.extensive() def extensive(self): return 'eor %ld/%ld (%s %s)' % (long(self.afi), long( self.safi), self.afi, self.safi) def json(self, announced=True, compact=None): return '"eor": { "afi" : "%s", "safi" : "%s" }' % (self.afi, self.safi) def __len__(self): if self.afi == AFI.ipv4 and self.safi == SAFI.unicast: # May not have been the size read on the wire if MP was used for IPv4 unicast return 4 else: return self.MP_LENGTH def __init__(self, afi, safi, action=None): Message.__init__(self) self.nlris = [ EOR.NLRI(afi, safi, action), ] self.attributes = Attributes() def message(self, negotiated=None): return self._message(self.nlris[0].pack()) def __repr__(self): return 'EOR' @classmethod def unpack_message(cls, data, negotiated): header_length = len(EOR.NLRI.PREFIX) return cls(AFI.unpack(data[header_length:header_length + 2]), SAFI.unpack(data[header_length + 2]))
def test101_EVPNHashEqual_somefieldsvary(self): ''' Two EVPN MAC NLRIs differing by their ESI or label or RD, or nexthop, but otherwise identical should hash to the same value, and be equal ''' nlri0 = EVPNMAC(RouteDistinguisher.fromElements("42.42.42.42", 5), ESI(), EthernetTag(111), MAC("01:02:03:04:05:06"), 6 * 8, Labels([42], True), IP.create("1.1.1.1")) # ESI nlri1 = EVPNMAC(RouteDistinguisher.fromElements("42.42.42.42", 5), ESI(b''.join(character(1) for _ in range(0, 10))), EthernetTag(111), MAC("01:02:03:04:05:06"), 6 * 8, Labels([42], True), IP.create("1.1.1.1")) # label nlri2 = EVPNMAC(RouteDistinguisher.fromElements("42.42.42.42", 5), ESI(), EthernetTag(111), MAC("01:02:03:04:05:06"), 6 * 8, Labels([4444], True), IP.create("1.1.1.1")) # IP: different IPs, but same MACs: different route nlri3 = EVPNMAC(RouteDistinguisher.fromElements("42.42.42.42", 5), ESI(), EthernetTag(111), MAC("01:02:03:04:05:06"), 6 * 8, Labels([42], True), IP.create("2.2.2.2")) # with a next hop... nlri4 = EVPNMAC(RouteDistinguisher.fromElements("42.42.42.42", 5), ESI(), EthernetTag(111), MAC("01:02:03:04:05:06"), 6 * 8, Labels([42], True), IP.create("1.1.1.1"), IP.pton("10.10.10.10")) nlri5 = EVPNMAC(RouteDistinguisher.fromElements("42.42.42.42", 5), ESI(), EthernetTag(111), MAC("01:02:03:04:05:06"), 6 * 8, Labels([42], True), IP.create("1.1.1.1"), IP.pton("11.11.11.11")) self.assertEqual(hash(nlri0), hash(nlri1)) self.assertEqual(hash(nlri0), hash(nlri2)) self.assertEqual(hash(nlri0), hash(nlri4)) self.assertEqual(nlri0, nlri1) self.assertEqual(nlri0, nlri2) self.assertEqual(nlri0, nlri4) self.assertEqual(nlri1, nlri2) self.assertEqual(nlri1, nlri4) self.assertEqual(nlri2, nlri4) self.assertEqual(nlri4, nlri5) self.assertNotEqual(hash(nlri0), hash(nlri3)) self.assertNotEqual(nlri0, nlri3) self.assertNotEqual(nlri1, nlri3) self.assertNotEqual(nlri2, nlri3) self.assertNotEqual(nlri3, nlri4)
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
def _pack(self, packed=None): if self._packed: return self._packed if packed: self._packed = packed return packed self._packed = concat_bytes( self.rd.pack(), self.esi.pack(), self.etag.pack(), character(self.maclen), # only 48 supported by the draft self.mac.pack(), character(len(self.ip) * 8 if self.ip else 0), self.ip.pack() if self.ip else b'', self.label.pack()) return self._packed
def extract(self): restart = pack('!H', ((self.restart_flag << 12) | (self.restart_time & Graceful.TIME_MASK))) families = [(afi.pack(), safi.pack(), character(self[(afi, safi)])) for (afi, safi) in self.keys()] sfamilies = concat_bytes_i( concat_bytes(pafi, psafi, family) for (pafi, psafi, family) in families) return [concat_bytes(restart, sfamilies)]
def unpack (cls, data): labels = [] while len(data): label = unpack('!L',character(0)+data[:3])[0] data = data[3:] labels.append(label >> 4) if label & 0x001: break return cls(labels)
def _pack (self, packed=None): if self._packed: return self._packed if packed: self._packed = packed return packed self._packed = concat_bytes( self.rd.pack(), self.esi.pack(), self.etag.pack(), character(self.maclen), # only 48 supported by the draft self.mac.pack(), character(len(self.ip)*8 if self.ip else 0), self.ip.pack() if self.ip else b'', self.label.pack() ) return self._packed
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
def _pack(self, packed=None): if self._packed: return self._packed if packed: self._packed = packed return packed self._packed = concat_bytes(self.rd.pack(), self.etag.pack(), character(len(self.ip) * 8), self.ip.pack()) return self._packed
def destination(tokeniser): data = tokeniser() if data.count('.') == 3 and data.count(':') == 0: ip, netmask = data.split('/') raw = concat_bytes_i(character(int(_)) for _ in ip.split('.')) yield Flow4Destination(raw, int(netmask)) elif data.count('/') == 1: ip, netmask = data.split('/') offset = 0 yield Flow6Destination(IP.pton(ip), int(netmask), int(offset)) else: ip, netmask, offset = data.split('/') yield Flow6Destination(IP.pton(ip), int(netmask), int(offset))
class NOP (Message): ID = Message.CODE.NOP TYPE = character(Message.CODE.NOP) def message (self,negotiated=None): raise RuntimeError('NOP messages can not be sent on the wire') def __str__ (self): return "NOP" @classmethod def unpack_message (cls, data, negotiated): # pylint: disable=W0613 return NOP()
def _pack(self, packed=None): if self._packed: return self._packed if packed: self._packed = packed return packed self._packed = concat_bytes( self.rd.pack(), self.esi.pack(), character(len(self.ip) * 8 if self.ip else 0), self.ip.pack() if self.ip else b'') return self._packed
def destination (tokeniser): data = tokeniser() if data.count('.') == 3 and data.count(':') == 0: ip,netmask = data.split('/') raw = concat_bytes_i(character(int(_)) for _ in ip.split('.')) yield Flow4Destination(raw,int(netmask)) elif data.count('/') == 1: ip,netmask = data.split('/') offset = 0 yield Flow6Destination(IP.pton(ip),int(netmask),int(offset)) else: ip,netmask,offset = data.split('/') yield Flow6Destination(IP.pton(ip),int(netmask),int(offset))
class RouteRefresh(Message): ID = Message.CODE.ROUTE_REFRESH TYPE = character(Message.CODE.ROUTE_REFRESH) request = 0 start = 1 end = 2 def __init__(self, afi, safi, reserved=0): self.afi = AFI.create(afi) self.safi = SAFI.create(safi) self.reserved = Reserved(reserved) def message(self, negotiated=None): return self._message( concat_bytes(self.afi.pack(), character(self.reserved), self.safi.pack())) def __str__(self): return "REFRESH" def extensive(self): return 'route refresh %s/%d/%s' % (self.afi, self.reserved, self.safi) # XXX: Check how we get this data into the RR def families(self): return self._families[:] @classmethod 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) def __eq__(self, other): if not isinstance(other, RouteRefresh): return False if self.afi != other.afi: return False if self.safi != other.safi: return False if self.reserved != other.reserved: return False return True def __ne__(self, other): return not self.__eq__(other)
def fromElements (cls, prefix, suffix): try: if '.' in prefix: data = [character(0),character(1)] data.extend([character(int(_)) for _ in prefix.split('.')]) data.extend([character(suffix >> 8),character(suffix & 0xFF)]) distinguisher = concat_bytes_i(data) else: number = int(prefix) if number < pow(2,16) and suffix < pow(2,32): distinguisher = character(0) + character(0) + pack('!H',number) + pack('!L',suffix) elif number < pow(2,32) and suffix < pow(2,16): distinguisher = character(0) + character(2) + pack('!L',number) + pack('!H',suffix) else: raise ValueError('invalid route-distinguisher %s' % number) return cls(distinguisher) except ValueError: raise ValueError('invalid route-distinguisher %s:%s' % (prefix,suffix))
def pack_nlri (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(character(ID)) ordered_rules.append(concat_bytes_i(rule.pack() for rule in rules)) components = self.rd.pack() + concat_bytes_i(ordered_rules) lc = len(components) if lc < 0xF0: return concat_bytes(character(lc),components) if lc < 0x0FFF: return concat_bytes(pack('!H',lc | 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")
def _pack (self, packed=None): if self._packed: return self._packed if packed: self._packed = packed return packed self._packed = concat_bytes( self.rd.pack(), self.etag.pack(), character(len(self.ip)*8), self.ip.pack() ) return self._packed
def _pack (self, packed=None): if self._packed: return self._packed if packed: self._packed = packed return packed self._packed = concat_bytes( self.rd.pack(), self.esi.pack(), character(len(self.ip)*8 if self.ip else 0), self.ip.pack() if self.ip else b'' ) return self._packed
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)
class KeepAlive (Message): ID = Message.CODE.KEEPALIVE TYPE = character(Message.CODE.KEEPALIVE) def message (self,negotiated=None): return self._message(b'') def __str__ (self): return "KEEPALIVE" @classmethod def unpack_message (cls, data, negotiated): # pylint: disable=W0613 # This can not happen at decode time as we check the length of the KEEPALIVE message # But could happen when calling the function programmatically if data: raise Notify('Keepalive can not have any payload but contains %s', hexstring(data)) return cls()
def route_distinguisher (tokeniser): data = tokeniser() separator = data.find(':') if separator > 0: prefix = data[:separator] suffix = int(data[separator+1:]) if '.' in prefix: data = [character(0),character(1)] data.extend([character(int(_)) for _ in prefix.split('.')]) data.extend([character(suffix >> 8),character(suffix & 0xFF)]) rtd = concat_bytes_i(data) else: number = int(prefix) if number < pow(2,16) and suffix < pow(2,32): rtd = character(0) + character(0) + pack('!H',number) + pack('!L',suffix) elif number < pow(2,32) and suffix < pow(2,16): rtd = character(0) + character(2) + pack('!L',number) + pack('!H',suffix) else: raise ValueError('invalid route-distinguisher %s' % data) return RouteDistinguisher(rtd)
def _pack (self, packed=None): if self._packed: return self._packed if packed: self._packed = packed return packed self._packed = concat_bytes( self.rd.pack(), self.esi.pack(), self.etag.pack(), character(self.iplen), self.ip.pack(), self.gwip.pack(), self.label.pack(), ) return self._packed
def pack_nlri (self): return character(self.mask) + self._packed[:CIDR.size(self.mask)]
def pack_int (afi, integer): return concat_bytes_i(character((integer >> (offset * 8)) & 0xff) for offset in range(IP.length(afi)-1,-1,-1))
def resetFlags(char): return character(ordinal(char) & ~(Attribute.Flag.TRANSITIVE | Attribute.Flag.OPTIONAL))
def __init__ (self, origin, packed=None): self.origin = origin self._packed = self._attribute(packed if packed else character(origin))
def from_rt(cls, route_target): packed = route_target.pack() return cls.unpack(concat_bytes(packed[0:1], character(cls.COMMUNITY_SUBTYPE), packed[2:]))
def extract (self): restart = pack('!H',((self.restart_flag << 12) | (self.restart_time & Graceful.TIME_MASK))) families = [(afi.pack(),safi.pack(),character(self[(afi,safi)])) for (afi,safi) in self.keys()] sfamilies = concat_bytes_i(concat_bytes(pafi,psafi,family) for (pafi,psafi,family) in families) return [concat_bytes(restart,sfamilies)]
def pack (self): l,v = self.encode(self.value) op = self.operations | _len_to_bit(l) return concat_bytes(character(op),v)
def encode (self, value): return 1,character(value)
def __hash__ (self): return hash(character(self.mask)+self._packed)
def encode (self, value): if value < (1 << 8): return 1,character(value) if value < (1 << 16): return 2,pack('!H',value) return 4,pack('!L',value)
def pack (self, negotiated=None): addpath = self.path_info.pack() if negotiated and negotiated.addpath.send(self.afi,self.safi) else b'' mask = character(len(self.labels)*8 + len(self.rd)*8 + self.cidr.mask) return addpath + mask + self.labels.pack() + self.rd.pack() + self.cidr.pack_ip()