def test3_IPVPNHashEqual(self): ''' Two VPN NLRI distinct only by their *action* should hash to the same value, and be equal ''' packedPrefix, mask = prefixToPackedIPMask("1.1.1.1/32") nlri1 = IPVPN.new(AFI(AFI.ipv4), SAFI(SAFI.mpls_vpn), packedPrefix, mask, Labels([42], True), RouteDistinguisher.fromElements("42.42.42.42", 5), IP.pton("45.45.45.45"), OUT.ANNOUNCE) nlri2 = IPVPN.new(AFI(AFI.ipv4), SAFI(SAFI.mpls_vpn), packedPrefix, mask, Labels([42], True), RouteDistinguisher.fromElements("42.42.42.42", 5), IP.pton("45.45.45.45"), OUT.WITHDRAW) self.assertEqual(hash(nlri1), hash(nlri2)) self.assertTrue(nlri1.eq(nlri2)) self.assertEqual(nlri1, nlri2)
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(['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 destination(tokeniser): data = tokeniser() if data.count('.') == 3 and data.count(':') == 0: ip, netmask = data.split('/') raw = b''.join(bytes([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))
def source(tokeniser): data = tokeniser() if data.count('.') == 3 and data.count(':') == 0: ip, netmask = data.split('/') raw = ''.join(chr(int(_)) for _ in ip.split('.')) yield Flow4Source(raw, int(netmask)) elif data.count('/') == 1: ip, netmask = data.split('/') offset = 0 yield Flow6Source(IP.pton(ip), int(netmask), int(offset)) else: ip, netmask, offset = data.split('/') yield Flow6Source(IP.pton(ip), int(netmask), int(offset))
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))
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))
def parse_api_attribute(self, command, peers, action): # This is a quick solution which does not support next-hop self attribute, nlris = command.split('nlri') route = '%s route 0.0.0.0/0 %s' % (action, ' '.join( attribute.split()[2:])) parsed = self.parse_api_route(route, peers, action) if parsed in (True, False, None): return parsed attributes = parsed[0][1].attributes nexthop = parsed[0][1].nlri.nexthop changes = [] for nlri in nlris.split(): ip, mask = nlri.split('/') klass = Prefix if 'path-information' in command else MPLS change = Change( klass(afi=IP.toafi(ip), safi=IP.tosafi(ip), packed=IP.pton(ip), mask=int(mask), nexthop=nexthop.packed, action=action), attributes) if action == 'withdraw': change.nlri.action = OUT.withdraw else: change.nlri.action = OUT.announce changes.append((peers.keys(), change)) return changes
def test200_IPVPNCreatePackUnpack(self): '''Test pack/unpack for IPVPN routes''' nlri = IPVPN.new( AFI.ipv4, SAFI.mpls_vpn, IP.pton("1.2.3.0"), 24, Labels([42], True), RouteDistinguisher.fromElements("42.42.42.42", 5), ) packed = nlri.pack() unpacked, leftover = IPVPN.unpack_nlri(AFI.ipv4, SAFI.mpls_vpn, packed, OUT.UNSET, None) self.assertEqual(0, len(leftover)) # TODO: compare packed with a reference encoding verified # as conformant with RFC4364 self.assertTrue(isinstance(unpacked, IPVPN)) self.assertEqual("1.2.3.0/24", unpacked.cidr.prefix()) self.assertEqual(1, len(unpacked.labels.labels)) self.assertEqual(42, unpacked.labels.labels[0]) self.assertEqual("42.42.42.42:5", unpacked.rd._str())
def api_attribute (self, command, peers, action): # This is a quick solution which does not support next-hop self attribute,nlris = command.split('nlri') route = '%s route 0.0.0.0/0 %s' % (action, ' '.join(attribute.split()[2:])) parsed = self.api_route(peers,route) if parsed in (True,False,None): return parsed attributes = parsed[0][1].attributes nexthop = parsed[0][1].nlri.nexthop changes = [] for nlri in nlris.split(): ip,mask = nlri.split('/') klass = MPLS if 'path-information' in command else INET change = Change( klass( afi=IP.toafi(ip), safi=IP.tosafi(ip), packed=IP.pton(ip), mask=int(mask), nexthop='', # could be NextHopSelf action=action ), attributes ) change.nlri.nexthop = nexthop if action == 'withdraw': change.nlri.action = OUT.WITHDRAW else: change.nlri.action = OUT.ANNOUNCE changes.append((peers.keys(),change)) return changes
def pack(self): t = pack('!B', self.TLV) l = pack('!H', self.LENGTH) r0 = pack('!B', 0) r1 = pack('!H', 0) val = IP.pton(self.v6sid) return concat_bytes(t, l, r0, r1, val)
def parse_api_attribute (self,command,peers,action): # This is a quick solution which does not support next-hop self attribute,nlris = command.split('nlri') route = '%s route 0.0.0.0/0 %s' % (action, ' '.join(attribute.split()[2:])) parsed = self.parse_api_route(route,peers,action) if parsed in (True,False,None): return parsed attributes = parsed[0][1].attributes nexthop = parsed[0][1].nlri.nexthop changes = [] for nlri in nlris.split(): ip,mask = nlri.split('/') klass = Prefix if 'path-information' in command else MPLS change = Change( klass( afi=IP.toafi(ip), safi=IP.tosafi(ip), packed=IP.pton(ip), mask=int(mask), nexthop=nexthop.packed, action=action ) ,attributes ) if action == 'withdraw': change.nlri.action = OUT.withdraw else: change.nlri.action = OUT.announce changes.append((peers.keys(),change)) return changes
def insert_static_route (self, scope, name, command, tokens): try: ip = tokens.pop(0) except IndexError: return self.error.set(self.syntax) try: ip,mask = ip.split('/') mask = int(mask) except ValueError: mask = 32 try: if 'rd' in tokens: klass = MPLS elif 'route-distinguisher' in tokens: klass = MPLS elif 'label' in tokens: klass = MPLS else: klass = INET # nexthop must be false and its str return nothing .. an empty string does that update = Change(klass(afi=IP.toafi(ip),safi=IP.tosafi(ip),packed=IP.pton(ip),mask=mask,nexthop=None,action=OUT.ANNOUNCE),Attributes()) except ValueError: return self.error.set(self.syntax) if 'announce' not in scope[-1]: scope[-1]['announce'] = [] scope[-1]['announce'].append(update) return True
def pack (self): return concat_bytes( pack('!B', self.TLV), pack('!H', self.LENGTH), pack('!B', 0), pack('!H', 0), IP.pton(self.v6sid) )
def source (tokeniser): data = tokeniser() if data.count('/') == 1: ip,netmask = data.split('/') raw = ''.join(chr(int(_)) for _ in ip.split('.')) yield Flow4Source(raw,int(netmask)) else: ip,netmask,offset = data.split('/') yield Flow6Source(IP.pton(ip),int(netmask),int(offset))
def destination(tokeniser): data = tokeniser() if data.count('/') == 1: ip, netmask = data.split('/') raw = ''.join(chr(int(_)) for _ in ip.split('.')) yield Flow4Destination(raw, int(netmask)) return else: ip, netmask, offset = data.split('/') yield Flow6Destination(IP.pton(ip), int(netmask), int(offset))
def pack(self): return ( pack('!B', self.TLV) + pack('!H', self.LENGTH) + pack('!B', 0) + IP.pton(self.l3vpnsid) + pack('!B', 0) + pack('!H', 0xFFFF) + pack('!B', 0) )
def test0_IPVPNHashEqual(self): ''' Two indistinct VPN NLRIs should hash to the same value, and be equal ''' rd = RouteDistinguisher.fromElements("42.42.42.42", 5) packedPrefix, mask = prefixToPackedIPMask("1.1.1.1/32") nlri1 = IPVPN.new(AFI(AFI.ipv4), SAFI(SAFI.mpls_vpn), packedPrefix, mask, Labels([42], True), rd, IP.pton("45.45.45.45"), OUT.ANNOUNCE) nlri2 = IPVPN.new(AFI(AFI.ipv4), SAFI(SAFI.mpls_vpn), packedPrefix, mask, Labels([42], True), rd, IP.pton("45.45.45.45"), OUT.ANNOUNCE) self.assertEqual(hash(nlri1), hash(nlri2)) self.assertEqual(nlri1, nlri2)
def prefix(tokeniser): # XXX: could raise ip = tokeniser() try: ip, mask = ip.split('/') mask = int(mask) except ValueError: mask = 32 return Range(ip, IP.pton(ip), mask)
def pack (self): return concat_bytes( pack('!B', self.TLV), pack('!H', self.LENGTH), pack('!B', 0), IP.pton(self.l3vpnsid), pack('!B', 0), pack('!H', 0xffff), pack('!B', 0), )
def prefix(tokeniser): # XXX: could raise ip = tokeniser() try: ip, mask = ip.split("/") mask = int(mask) except ValueError: mask = 32 return Range(ip, IP.pton(ip), mask)
def destination (tokeniser): data = tokeniser() if data.count('/') == 1: ip,netmask = data.split('/') raw = ''.join(chr(int(_)) for _ in ip.split('.')) yield Flow4Destination(raw,int(netmask)) return else: ip,netmask,offset = data.split('/') yield Flow6Destination(IP.pton(ip),int(netmask),int(offset))
def MD5(io, ip, port, md5): if md5: os = platform.system() if os == 'FreeBSD': if md5 != 'kernel': raise MD5Error( 'FreeBSD requires that you set your MD5 key via ipsec.conf.\n' 'Something like:\n' 'flush;\n' 'add <local ip> <peer ip> tcp 0x1000 -A tcp-md5 "password";' ) try: TCP_MD5SIG = 0x10 io.setsockopt(socket.IPPROTO_TCP, TCP_MD5SIG, 1) except socket.error: raise MD5Error( 'FreeBSD requires that you rebuild your kernel to enable TCP MD5 Signatures:\n' 'options IPSEC\n' 'options TCP_SIGNATURE\n' 'device crypto\n') elif os == 'Linux': try: # __kernel_sockaddr_storage n_af = IP.toaf(ip) n_addr = IP.pton(ip) n_port = socket.htons(port) # pack 'x' is padding, so we want the struct # Do not use '!' for the pack, the network (big) endian switch in # struct.pack is fighting against inet_pton and htons (note the n) if IP.toafi(ip) == AFI.ipv4: # SS_MAXSIZE is 128 but addr_family, port and ipaddr (8 bytes total) are written independently of the padding SS_MAXSIZE_PADDING = 128 - calcsize('HH4s') # 8 sockaddr = pack('HH4s%dx' % SS_MAXSIZE_PADDING, socket.AF_INET, n_port, n_addr) else: SS_MAXSIZE_PADDING = 128 - calcsize('HI16sI') # 28 SIN6_FLOWINFO = 0 SIN6_SCOPE_ID = 0 sockaddr = pack('HHI16sI%dx' % SS_MAXSIZE_PADDING, n_af, n_port, SIN6_FLOWINFO, n_addr, SIN6_SCOPE_ID) TCP_MD5SIG_MAXKEYLEN = 80 key = pack('2xH4x%ds' % TCP_MD5SIG_MAXKEYLEN, len(md5), md5) TCP_MD5SIG = 14 io.setsockopt(socket.IPPROTO_TCP, TCP_MD5SIG, sockaddr + key) except socket.error, exc: raise MD5Error( 'This linux machine does not support TCP_MD5SIG, you can not use MD5 (%s)' % errstr(exc)) else: raise MD5Error('ExaBGP has no MD5 support for %s' % os)
def prefix (tokeniser): # XXX: could raise ip = tokeniser() try: ip,mask = ip.split('/') mask = int(mask) except ValueError: mask = 32 tokeniser.afi = IP.toafi(ip) return Range(ip,IP.pton(ip),mask)
def test2_IPVPNHashEqual(self): ''' Two VPN NLRI distinct only by their *nexthop* should hash to the same value, and be equal ''' packedPrefix, mask = prefixToPackedIPMask("1.1.1.1/32") nlri1 = IPVPN.new(AFI(AFI.ipv4), SAFI(SAFI.mpls_vpn), packedPrefix, mask, Labels([42], True), RouteDistinguisher.fromElements("42.42.42.42", 5), IP.pton("45.45.45.45"), OUT.ANNOUNCE) nlri2 = IPVPN.new(AFI(AFI.ipv4), SAFI(SAFI.mpls_vpn), packedPrefix, mask, Labels([42], True), RouteDistinguisher.fromElements("42.42.42.42", 5), IP.pton("77.77.77.77"), OUT.ANNOUNCE) self.assertEqual(hash(nlri1), hash(nlri2)) self.assertTrue(nlri1.eq(nlri2)) self.assertNotEqual(nlri1, nlri2)
def inet (tokeniser): ipmask = prefix(tokeniser) return Change( INET( afi=IP.toafi(ipmask.string), safi=IP.tosafi(ipmask.string), packed=IP.pton(ipmask.string), mask=ipmask.mask, nexthop=None, action=OUT.UNSET ), Attributes() )
def test0_IPVPNHashEqual(self): ''' Two indistinct VPN NLRIs should hash to the same value, and be equal ''' rd = RouteDistinguisher.fromElements("42.42.42.42", 5) packedPrefix, mask = prefixToPackedIPMask("1.1.1.1/32") nlri1 = IPVPN.new(AFI(AFI.ipv4), SAFI(SAFI.mpls_vpn), packedPrefix, mask, Labels([42], True), rd, IP.pton("45.45.45.45"), OUT.ANNOUNCE) nlri2 = IPVPN.new(AFI(AFI.ipv4), SAFI(SAFI.mpls_vpn), packedPrefix, mask, Labels([42], True), rd, IP.pton("45.45.45.45"), OUT.ANNOUNCE) self.assertEqual(hash(nlri1), hash(nlri2)) self.assertEqual(nlri1, nlri2)
def test2_MPLSVPNHashEqual(self): ''' Two VPN NLRI distinct only by their *nexthop* should hash to the same value, and be equal ''' packedPrefix, mask = prefixToPackedIPMask("1.1.1.1/32") nlri1 = MPLSVPN(AFI(AFI.ipv4), SAFI(SAFI.mpls_vpn), packedPrefix, mask, Labels([42], True), RouteDistinguisher.fromElements("42.42.42.42", 5), IP.pton("45.45.45.45"), OUT.ANNOUNCE) nlri2 = MPLSVPN(AFI(AFI.ipv4), SAFI(SAFI.mpls_vpn), packedPrefix, mask, Labels([42], True), RouteDistinguisher.fromElements("42.42.42.42", 5), IP.pton("77.77.77.77"), OUT.ANNOUNCE) self.assertEqual(hash(nlri1), hash(nlri2)) self.assertEqual(nlri1, nlri2)
def source (self, scope, name, command, tokens): try: data = tokens.pop(0) if data.count('/') == 1: ip,netmask = data.split('/') raw = ''.join(chr(int(_)) for _ in ip.split('.')) if not scope[-1]['announce'][-1].nlri.add(Flow4Source(raw,int(netmask))): return self.error.set('Flow can only have one destination') else: ip,netmask,offset = data.split('/') change = scope[-1]['announce'][-1] change.nlri.afi = AFI(AFI.ipv6) if not change.nlri.add(Flow6Source(IP.pton(ip),int(netmask),int(offset))): return self.error.set('Flow can only have one destination') return True except (IndexError,ValueError): return self.error.set(self.syntax)
def test200_IPVPNCreatePackUnpack(self): '''Test pack/unpack for IPVPN routes''' nlri = IPVPN.new(AFI(AFI.ipv4), SAFI(SAFI.mpls_vpn), IP.pton("1.2.3.0"), 24, Labels([42], True), RouteDistinguisher.fromElements("42.42.42.42", 5)) packed = nlri.pack() unpacked,leftover = IPVPN.unpack_nlri(AFI(AFI.ipv4), SAFI(SAFI.mpls_vpn), packed, OUT.UNSET, None) self.assertEqual(0, len(leftover)) # TODO: compare packed with a reference encoding verified # as conformant with RFC4364 self.assertTrue(isinstance(unpacked, IPVPN)) self.assertEqual("1.2.3.0/24", unpacked.cidr.prefix()) self.assertEqual(1, len(unpacked.labels.labels)) self.assertEqual(42, unpacked.labels.labels[0]) self.assertEqual("42.42.42.42:5", unpacked.rd._str())
def source(self, scope, name, command, tokens): try: data = tokens.pop(0) if data.count('/') == 1: ip, netmask = data.split('/') raw = ''.join(chr(int(_)) for _ in ip.split('.')) if not scope[-1]['announce'][-1].nlri.add( Flow4Source(raw, int(netmask))): return self.error.set('Flow can only have one destination') else: ip, netmask, offset = data.split('/') change = scope[-1]['announce'][-1] change.nlri.afi = AFI(AFI.ipv6) if not change.nlri.add( Flow6Source(IP.pton(ip), int(netmask), int(offset))): return self.error.set('Flow can only have one destination') return True except (IndexError, ValueError): return self.error.set(self.syntax)
def insert_static_route(self, scope, name, command, tokens): try: ip = tokens.pop(0) except IndexError: return self.error.set(self.syntax) try: ip, mask = ip.split('/') mask = int(mask) except ValueError: mask = 32 try: if 'rd' in tokens: klass = MPLS elif 'route-distinguisher' in tokens: klass = MPLS elif 'label' in tokens: klass = MPLS else: klass = INET # nexthop must be false and its str return nothing .. an empty string does that update = Change( klass(afi=IP.toafi(ip), safi=IP.tosafi(ip), packed=IP.pton(ip), mask=mask, nexthop=None, action=OUT.ANNOUNCE), Attributes()) except ValueError: return self.error.set(self.syntax) if 'announce' not in scope[-1]: scope[-1]['announce'] = [] scope[-1]['announce'].append(update) return True
def prefixToPackedIPMask(prefix): ipString, mask = prefix.split("/") return (IP.pton(ipString), int(mask))
def MD5 (io, ip, port, md5, md5_base64): platform_os = platform.system() if platform_os == 'FreeBSD': if md5: if md5 != 'kernel': raise MD5Error( 'FreeBSD requires that you set your MD5 key via ipsec.conf.\n' 'Something like:\n' 'flush;\n' 'add <local ip> <peer ip> tcp 0x1000 -A tcp-md5 "password";' ) try: TCP_MD5SIG = 0x10 io.setsockopt(socket.IPPROTO_TCP, TCP_MD5SIG, 1) except socket.error: raise MD5Error( 'FreeBSD requires that you rebuild your kernel to enable TCP MD5 Signatures:\n' 'options IPSEC\n' 'options TCP_SIGNATURE\n' 'device crypto\n' ) elif platform_os == 'Linux': try: if md5: md5_bytes = None if md5_base64 is True: try: md5_bytes = base64.b64decode(md5) except TypeError: raise MD5Error("Failed to decode base 64 encoded PSK") elif md5_base64 is None and not re.match('.*[^a-f0-9].*', md5): # auto options = [md5+'==', md5+'=', md5] for md5 in options: try: md5_bytes = base64.b64decode(md5) break except TypeError: pass # __kernel_sockaddr_storage n_af = IP.toaf(ip) n_addr = IP.pton(ip) n_port = socket.htons(port) # pack 'x' is padding, so we want the struct # Do not use '!' for the pack, the network (big) endian switch in # struct.pack is fighting against inet_pton and htons (note the n) if IP.toafi(ip) == AFI.ipv4: # SS_MAXSIZE is 128 but addr_family, port and ipaddr (8 bytes total) are written independently of the padding SS_MAXSIZE_PADDING = 128 - calcsize('HH4s') # 8 sockaddr = pack('HH4s%dx' % SS_MAXSIZE_PADDING, socket.AF_INET, n_port, n_addr) else: SS_MAXSIZE_PADDING = 128 - calcsize('HI16sI') # 28 SIN6_FLOWINFO = 0 SIN6_SCOPE_ID = 0 sockaddr = pack('HHI16sI%dx' % SS_MAXSIZE_PADDING, n_af, n_port, SIN6_FLOWINFO, n_addr, SIN6_SCOPE_ID) TCP_MD5SIG_MAXKEYLEN = 80 TCP_MD5SIG = 14 if md5_bytes: key = pack('2xH4x%ds' % TCP_MD5SIG_MAXKEYLEN, len(md5_bytes), md5_bytes) io.setsockopt(socket.IPPROTO_TCP, TCP_MD5SIG, sockaddr + key) elif md5: md5_bytes = bytes_ascii(md5) key = pack('2xH4x%ds' % TCP_MD5SIG_MAXKEYLEN, len(md5_bytes), md5_bytes) io.setsockopt(socket.IPPROTO_TCP, TCP_MD5SIG, sockaddr + key) # else: # key = pack('2xH4x%ds' % TCP_MD5SIG_MAXKEYLEN, 0, b'') # io.setsockopt(socket.IPPROTO_TCP, TCP_MD5SIG, sockaddr + key) except socket.error as exc: if exc.errno != errno.ENOENT: raise MD5Error('This linux machine does not support TCP_MD5SIG, you can not use MD5 (%s)' % errstr(exc)) elif md5: raise MD5Error('ExaBGP has no MD5 support for %s' % platform_os)
def pack(self): return concat_bytes(pack('!B', self.TLV), pack('!H', self.LENGTH), pack('!B', 0), pack('!H', 0), IP.pton(self.v6sid))
def prefixToPackedIPMask(prefix): ipString, mask = prefix.split("/") return (IP.pton(ipString), int(mask))
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(0), 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(1), 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(0), 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(0), 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(0), 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(0), 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 pack(self): return pack('!B', self.TLV) + pack('!H', self.LENGTH) + pack( '!B', 0) + pack('!H', 0) + IP.pton(self.v6sid)
def MD5(io, ip, port, md5, md5_base64): platform_os = platform.system() if platform_os == 'FreeBSD': if md5: if md5 != 'kernel': raise MD5Error( 'FreeBSD requires that you set your MD5 key via ipsec.conf.\n' 'Something like:\n' 'flush;\n' 'add <local ip> <peer ip> tcp 0x1000 -A tcp-md5 "password";' ) try: TCP_MD5SIG = 0x10 io.setsockopt(socket.IPPROTO_TCP, TCP_MD5SIG, 1) except socket.error: raise MD5Error( 'FreeBSD requires that you rebuild your kernel to enable TCP MD5 Signatures:\n' 'options IPSEC\n' 'options TCP_SIGNATURE\n' 'device crypto\n') elif platform_os == 'Linux': try: md5_bytes = None if md5: if md5_base64 is True: try: md5_bytes = base64.b64decode(md5) except TypeError: raise MD5Error("Failed to decode base 64 encoded PSK") elif md5_base64 is None and not re.match('.*[^a-f0-9].*', md5): # auto options = [md5 + '==', md5 + '=', md5] for md5 in options: try: md5_bytes = base64.b64decode(md5) break except TypeError: pass # __kernel_sockaddr_storage n_af = IP.toaf(ip) n_addr = IP.pton(ip) n_port = socket.htons(port) # pack 'x' is padding, so we want the struct # Do not use '!' for the pack, the network (big) endian switch in # struct.pack is fighting against inet_pton and htons (note the n) if IP.toafi(ip) == AFI.ipv4: # SS_MAXSIZE is 128 but addr_family, port and ipaddr (8 bytes total) are written independently of the padding SS_MAXSIZE_PADDING = 128 - calcsize('HH4s') # 8 sockaddr = pack('HH4s%dx' % SS_MAXSIZE_PADDING, socket.AF_INET, n_port, n_addr) else: SS_MAXSIZE_PADDING = 128 - calcsize('HI16sI') # 28 SIN6_FLOWINFO = 0 SIN6_SCOPE_ID = 0 sockaddr = pack('HHI16sI%dx' % SS_MAXSIZE_PADDING, n_af, n_port, SIN6_FLOWINFO, n_addr, SIN6_SCOPE_ID) TCP_MD5SIG_MAXKEYLEN = 80 TCP_MD5SIG = 14 if md5_bytes: key = pack('2xH4x%ds' % TCP_MD5SIG_MAXKEYLEN, len(md5_bytes), md5_bytes) io.setsockopt(socket.IPPROTO_TCP, TCP_MD5SIG, sockaddr + key) elif md5: md5_bytes = bytes(md5, 'ascii') key = pack('2xH4x%ds' % TCP_MD5SIG_MAXKEYLEN, len(md5_bytes), md5_bytes) io.setsockopt(socket.IPPROTO_TCP, TCP_MD5SIG, sockaddr + key) # else: # key = pack('2xH4x%ds' % TCP_MD5SIG_MAXKEYLEN, 0, b'') # io.setsockopt(socket.IPPROTO_TCP, TCP_MD5SIG, sockaddr + key) except socket.error as exc: if exc.errno != errno.ENOENT: raise MD5Error( 'This linux machine does not support TCP_MD5SIG, you can not use MD5 (%s)' % errstr(exc)) elif md5: raise MD5Error('ExaBGP has no MD5 support for %s' % platform_os)