def delt(self, dst, gw=None): # type: (str, Optional[str]) -> None """ Ex: delt(dst="::/0") delt(dst="2001:db8:cafe:f000::/56") delt(dst="2001:db8:cafe:f000::/56", gw="2001:db8:deca::1") """ tmp = dst + "/128" dst, plen_b = tmp.split('/')[:2] dst = in6_ptop(dst) plen = int(plen_b) to_del = [x for x in self.routes if in6_ptop(x[0]) == dst and x[1] == plen] if gw: gw = in6_ptop(gw) to_del = [x for x in self.routes if in6_ptop(x[2]) == gw] if len(to_del) == 0: warning("No matching route found") elif len(to_del) > 1: warning("Found more than one match. Aborting.") else: i = self.routes.index(to_del[0]) self.invalidate_cache() self.remove_ipv6_iface(self.routes[i][3]) del(self.routes[i])
def na_resp_host(self, src_host, rx): self.assertEqual(rx[Ether].dst, src_host.mac) self.assertEqual(in6_ptop(rx[IPv6].dst), in6_ptop(src_host.ip6)) self.assertTrue(rx.haslayer(ICMPv6ND_NA)) self.assertTrue(rx.haslayer(ICMPv6NDOptDstLLAddr)) na = rx[ICMPv6ND_NA] return Host(mac=na.lladdr, ip6=na.tgt)
def verify_dhcp6_advert(self, pkt, intf, peer): ether = pkt[Ether] self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff") self.assertEqual(ether.src, intf.local_mac) ip = pkt[IPv6] self.assertEqual(in6_ptop(ip.dst), in6_ptop(peer)) self.assertEqual(in6_ptop(ip.src), in6_ptop(intf.local_ip6)) udp = pkt[UDP] self.assertEqual(udp.dport, DHCP6_SERVER_PORT) self.assertEqual(udp.sport, DHCP6_CLIENT_PORT)
def validate_ra(self, intf, rx, dst_ip=None, mtu=9000, pi_opt=None): if not dst_ip: dst_ip = intf.remote_ip6 # unicasted packets must come to the unicast mac self.assertEqual(rx[Ether].dst, intf.remote_mac) # and from the router's MAC self.assertEqual(rx[Ether].src, intf.local_mac) # the rx'd RA should be addressed to the sender's source self.assertTrue(rx.haslayer(ICMPv6ND_RA)) self.assertEqual(in6_ptop(rx[IPv6].dst), in6_ptop(dst_ip)) # and come from the router's link local self.assertTrue(in6_islladdr(rx[IPv6].src)) self.assertEqual(in6_ptop(rx[IPv6].src), in6_ptop(mk_ll_addr(intf.local_mac))) # it should contain the links MTU ra = rx[ICMPv6ND_RA] self.assertEqual(ra[ICMPv6NDOptMTU].mtu, mtu) # it should contain the source's link layer address option sll = ra[ICMPv6NDOptSrcLLAddr] self.assertEqual(sll.lladdr, intf.local_mac) if not pi_opt: # the RA should not contain prefix information self.assertFalse(ra.haslayer(ICMPv6NDOptPrefixInfo)) else: raos = rx.getlayer(ICMPv6NDOptPrefixInfo, 1) # the options are nested in the scapy packet in way that i cannot # decipher how to decode. this 1st layer of option always returns # nested classes, so a direct obj1=obj2 comparison always fails. # however, the getlayer(.., 2) does give one instnace. # so we cheat here and construct a new opt instnace for comparison rd = ICMPv6NDOptPrefixInfo(prefixlen=raos.prefixlen, prefix=raos.prefix, L=raos.L, A=raos.A) if type(pi_opt) is list: for ii in range(len(pi_opt)): self.assertEqual(pi_opt[ii], rd) rd = rx.getlayer(ICMPv6NDOptPrefixInfo, ii + 2) else: self.assertEqual(pi_opt, raos)
def validate_ra(self, intf, rx, dst_ip=None): if not dst_ip: dst_ip = intf.remote_ip6 # unicasted packets must come to the unicast mac self.assertEqual(rx[Ether].dst, intf.remote_mac) # and from the router's MAC self.assertEqual(rx[Ether].src, intf.local_mac) # the rx'd RA should be addressed to the sender's source self.assertTrue(rx.haslayer(ICMPv6ND_RA)) self.assertEqual(in6_ptop(rx[IPv6].dst), in6_ptop(dst_ip)) # and come from the router's link local self.assertTrue(in6_islladdr(rx[IPv6].src)) self.assertEqual(in6_ptop(rx[IPv6].src), in6_ptop(mk_ll_addr(intf.local_mac)))
def validate_na(self, intf, rx, dst_ip=None, tgt_ip=None): if not dst_ip: dst_ip = intf.remote_ip6 if not tgt_ip: dst_ip = intf.local_ip6 # unicasted packets must come to the unicast mac self.assertEqual(rx[Ether].dst, intf.remote_mac) # and from the router's MAC self.assertEqual(rx[Ether].src, intf.local_mac) # the rx'd NA should be addressed to the sender's source self.assertTrue(rx.haslayer(ICMPv6ND_NA)) self.assertEqual(in6_ptop(rx[IPv6].dst), in6_ptop(dst_ip)) # and come from the target address self.assertEqual(in6_ptop(rx[IPv6].src), in6_ptop(tgt_ip)) # Dest link-layer options should have the router's MAC dll = rx[ICMPv6NDOptDstLLAddr] self.assertEqual(dll.lladdr, intf.local_mac)
def delt(self, dst, gw=None): """ Ex: delt(dst="::/0") delt(dst="2001:db8:cafe:f000::/56") delt(dst="2001:db8:cafe:f000::/56", gw="2001:db8:deca::1") """ tmp = dst + "/128" dst, plen = tmp.split('/')[:2] dst = in6_ptop(dst) plen = int(plen) to_del = [x for x in self.routes if in6_ptop(x[0]) == dst and x[1] == plen] if gw: gw = in6_ptop(gw) to_del = [x for x in self.routes if in6_ptop(x[2]) == gw] if len(to_del) == 0: warning("No matching route found") elif len(to_del) > 1: warning("Found more than one match. Aborting.") else: i = self.routes.index(to_del[0]) self.invalidate_cache() del(self.routes[i])
def verify_dhcp6_solicit(self, pkt, intf, peer_ip, peer_mac, fib_id=0, oui=0, dst_mac=None, dst_ip=None): if not dst_mac: dst_mac = intf.remote_mac if not dst_ip: dst_ip = in6_ptop(intf.remote_ip6) ether = pkt[Ether] self.assertEqual(ether.dst, dst_mac) self.assertEqual(ether.src, intf.local_mac) ip = pkt[IPv6] self.assertEqual(in6_ptop(ip.dst), dst_ip) self.assertEqual(in6_ptop(ip.src), in6_ptop(intf.local_ip6)) udp = pkt[UDP] self.assertEqual(udp.dport, DHCP6_CLIENT_PORT) self.assertEqual(udp.sport, DHCP6_SERVER_PORT) relay = pkt[DHCP6_RelayForward] self.assertEqual(in6_ptop(relay.peeraddr), in6_ptop(peer_ip)) oid = pkt[DHCP6OptIfaceId] cll = pkt[DHCP6OptClientLinkLayerAddr] self.assertEqual(cll.optlen, 8) self.assertEqual(cll.lltype, 1) self.assertEqual(cll.clladdr, peer_mac) if fib_id != 0: vss = pkt[DHCP6OptVSS] self.assertEqual(vss.optlen, 8) self.assertEqual(vss.type, 1) # the OUI and FIB-id are really 3 and 4 bytes resp. # but the tested range is small self.assertEqual(ord(vss.data[0]), 0) self.assertEqual(ord(vss.data[1]), 0) self.assertEqual(ord(vss.data[2]), oui) self.assertEqual(ord(vss.data[3]), 0) self.assertEqual(ord(vss.data[4]), 0) self.assertEqual(ord(vss.data[5]), 0) self.assertEqual(ord(vss.data[6]), fib_id) # the relay message should be an encoded Solicit msg = pkt[DHCP6OptRelayMsg] sol = DHCP6_Solicit() self.assertEqual(msg.optlen, len(str(sol))) self.assertEqual(str(sol), (str(msg[1]))[:msg.optlen])
def ifadd(self, iff, addr): """ Add an interface 'iff' with provided address into routing table. Ex: ifadd('eth0', '2001:bd8:cafe:1::1/64') will add following entry into # noqa: E501 Scapy6 internal routing table: Destination Next Hop iface Def src @ Metric 2001:bd8:cafe:1::/64 :: eth0 2001:bd8:cafe:1::1 1 prefix length value can be omitted. In that case, a value of 128 will be used. """ addr, plen = (addr.split("/") + ["128"])[:2] addr = in6_ptop(addr) plen = int(plen) naddr = inet_pton(socket.AF_INET6, addr) nmask = in6_cidr2mask(plen) prefix = inet_ntop(socket.AF_INET6, in6_and(nmask, naddr)) self.invalidate_cache() self.routes.append((prefix, plen, '::', iff, [addr], 1))
def test_nd_mirror_proxy(self): """ Interface (Mirror) Proxy ND """ # # When VPP has an interface whose address is also applied to a TAP # interface on the host, then VPP's TAP interface will be unnumbered # to the 'real' interface and do proxy ND from the host. # the curious aspect of this setup is that ND requests from the host # will come from the VPP's own address. # addr = self.pg0.remote_ip6 nsma = in6_getnsma(inet_pton(socket.AF_INET6, addr)) d = inet_ntop(socket.AF_INET6, nsma) # Make pg1 un-numbered to pg0 # self.pg1.unconfig_ip6() self.pg1.set_unnumbered(self.pg0.sw_if_index) # # Enable ND proxy on pg1 # self.vapi.ip6nd_proxy_enable_disable(sw_if_index=self.pg1.sw_if_index, is_enable=1) # # Send the ND request with an originating address that # is VPP's own address # nd_req_from_host = ( Ether(src=self.pg1.remote_mac, dst=in6_getnsmac(nsma)) / IPv6(dst=d, src=self.pg0.local_ip6) / ICMPv6ND_NS(tgt=addr) / ICMPv6NDOptSrcLLAddr(lladdr=self.pg1.remote_mac)) rx = self.send_and_expect(self.pg1, [nd_req_from_host], self.pg1) self.assertEqual(rx[0][Ether].src, self.pg1.local_mac) self.assertEqual(rx[0][Ether].dst, self.pg1.remote_mac) self.assertEqual(rx[0][IPv6].src, self.pg0.remote_ip6) self.assertEqual(rx[0][IPv6].dst, self.pg0.local_ip6) self.assertEqual(ipv6nh[rx[0][IPv6].nh], "ICMPv6") self.assertEqual(rx[0][ICMPv6ND_NA].tgt, self.pg0.remote_ip6) self.assertTrue(rx[0].haslayer(ICMPv6NDOptDstLLAddr)) self.assertEqual(rx[0][ICMPv6NDOptDstLLAddr].lladdr, self.pg1.local_mac) # # Send the unicast ND request # unicast_nd_req_from_host = ( Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IPv6(dst=self.pg0.remote_ip6, src=self.pg1.remote_ip6_ll) / ICMPv6ND_NS(tgt=self.pg0.remote_ip6) / ICMPv6NDOptSrcLLAddr(lladdr=self.pg1.remote_mac)) rx = self.send_and_expect(self.pg1, [unicast_nd_req_from_host], self.pg0) self.assertEqual(rx[0][Ether].src, self.pg0.local_mac) self.assertEqual(rx[0][Ether].dst, in6_getnsmac(nsma)) self.assertEqual(rx[0][IPv6].src, self.pg0.local_ip6) self.assertEqual(rx[0][IPv6].dst, d) self.assertEqual(ipv6nh[rx[0][IPv6].nh], "ICMPv6") self.assertEqual(rx[0][ICMPv6ND_NS].tgt, self.pg0.remote_ip6) self.assertTrue(rx[0].haslayer(ICMPv6NDOptSrcLLAddr)) self.assertEqual(rx[0][ICMPv6NDOptSrcLLAddr].lladdr, self.pg0.local_mac) # Resolve the NDs on the uplink self.pg0.resolve_ndp() # # Again send the unicast ND request, this time dst address should be # in local cache # rx = self.send_and_expect(self.pg1, [unicast_nd_req_from_host], self.pg1) self.assertEqual(rx[0][Ether].src, self.pg1.local_mac) self.assertEqual(rx[0][Ether].dst, self.pg1.remote_mac) self.assertEqual(rx[0][IPv6].src, self.pg0.remote_ip6) self.assertEqual(in6_ptop(rx[0][IPv6].dst), in6_ptop(self.pg1.remote_ip6_ll)) self.assertEqual(ipv6nh[rx[0][IPv6].nh], "ICMPv6") self.assertEqual(rx[0][ICMPv6ND_NA].tgt, self.pg0.remote_ip6) self.assertTrue(rx[0].haslayer(ICMPv6NDOptDstLLAddr)) self.assertEqual(rx[0][ICMPv6NDOptDstLLAddr].lladdr, self.pg1.local_mac) # # Send the Echo Request from host to remote (of uplink) # id = self.pg1.sw_if_index seq = 0x1 echo_request = ( Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IPv6(dst=self.pg0.remote_ip6, src=self.pg0.local_ip6) / ICMPv6EchoRequest(seq=seq, id=id)) rx = self.send_and_expect(self.pg1, [echo_request], self.pg0) self.assertEqual(rx[0][Ether].src, self.pg0.local_mac) self.assertEqual(rx[0][Ether].dst, self.pg0.remote_mac) self.assertEqual(rx[0][IPv6].src, self.pg0.local_ip6) self.assertEqual(rx[0][IPv6].dst, self.pg0.remote_ip6) self.assertEqual(ipv6nh[rx[0][IPv6].nh], "ICMPv6") self.assertTrue(rx[0].haslayer(ICMPv6EchoRequest)) self.assertEqual(rx[0][ICMPv6EchoRequest].id, id) self.assertEqual(rx[0][ICMPv6EchoRequest].seq, seq) # # setup a punt redirect so packets from the uplink go to the tap # redirect = VppIpPuntRedirect(self, self.pg0.sw_if_index, self.pg1.sw_if_index, self.pg0.local_ip6) redirect.add_vpp_config() echo_reply = (Ether(dst=self.pg0.remote_mac, src=self.pg0.local_mac) / IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) / ICMPv6EchoReply(seq=1, id=id)) rx = self.send_and_expect(self.pg0, [echo_reply], self.pg1) self.assertEqual(rx[0][Ether].src, self.pg1.local_mac) self.assertEqual(rx[0][Ether].dst, self.pg1.remote_mac) self.assertEqual(rx[0][IPv6].src, self.pg0.remote_ip6) self.assertEqual(rx[0][IPv6].dst, self.pg0.local_ip6) self.assertEqual(ipv6nh[rx[0][IPv6].nh], "ICMPv6") self.assertTrue(rx[0].haslayer(ICMPv6EchoReply)) self.assertEqual(rx[0][ICMPv6EchoReply].id, id) self.assertEqual(rx[0][ICMPv6EchoReply].seq, seq) # # cleanup # self.vapi.ip6nd_proxy_enable_disable(sw_if_index=self.pg1.sw_if_index, is_enable=0) redirect.remove_vpp_config()