def test_ns(self): """ IPv6 Neighbour Solicitation Exceptions Test scenario: - Send an NS Sourced from an address not covered by the link sub-net - Send an NS to an mcast address the router has not joined - Send NS for a target address the router does not onn. """ # # An NS from a non link source address # nsma = in6_getnsma(inet_pton(socket.AF_INET6, self.pg0.local_ip6)) d = inet_ntop(socket.AF_INET6, nsma) p = (Ether(dst=in6_getnsmac(nsma)) / IPv6(dst=d, src="2002::2") / ICMPv6ND_NS(tgt=self.pg0.local_ip6) / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)) pkts = [p] self.send_and_assert_no_replies( self.pg0, pkts, "No response to NS source by address not on sub-net") # # An NS for sent to a solicited mcast group the router is # not a member of FAILS # if 0: nsma = in6_getnsma(inet_pton(socket.AF_INET6, "fd::ffff")) d = inet_ntop(socket.AF_INET6, nsma) p = (Ether(dst=in6_getnsmac(nsma)) / IPv6(dst=d, src=self.pg0.remote_ip6) / ICMPv6ND_NS(tgt=self.pg0.local_ip6) / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)) pkts = [p] self.send_and_assert_no_replies( self.pg0, pkts, "No response to NS sent to unjoined mcast address") # # An NS whose target address is one the router does not own # nsma = in6_getnsma(inet_pton(socket.AF_INET6, self.pg0.local_ip6)) d = inet_ntop(socket.AF_INET6, nsma) p = (Ether(dst=in6_getnsmac(nsma)) / IPv6(dst=d, src=self.pg0.remote_ip6) / ICMPv6ND_NS(tgt="fd::ffff") / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)) pkts = [p] self.send_and_assert_no_replies( self.pg0, pkts, "No response to NS for unknown target")
def ns_req(cls, src_host, host): nsma = in6_getnsma(inet_pton(AF_INET6, "fd10::ffff")) d = inet_ntop(AF_INET6, nsma) return (Ether(dst="ff:ff:ff:ff:ff:ff", src=src_host.mac) / IPv6(dst=d, src=src_host.ip6) / ICMPv6ND_NS(tgt=host.ip6) / ICMPv6NDOptSrcLLAddr(lladdr=src_host.mac))
def icmpv6_ns(host, ifname): # 请求特定IPv6地址的MAC地址 ll_mac = get_mac_address(ifname) # 获取本机接口MAC地址 # 构建icmpv6_ns数据包 # -----------IPv6头部 - ----------- # Next Header: 0x3A(ICMPv6) # 原地址: Link Local address # 目的地址: Solicited node multicast address # # ----------ICMPv6头部 - --------- # ICMPv6 Type: 135 # ICMPv6 Code: 0(NS) # 目标地址: 2001:1::129 # # ----Source Link-Layer Address - --- # 源地址: 本地MAC地址 packet = IPv6(src=mac_to_ipv6_linklocal(ll_mac), dst=Solicited_node_multicast_address(host)) / \ ICMPv6ND_NS(tgt=host) / ICMPv6NDOptSrcLLAddr(lladdr=ll_mac) # packet.show() # 发送数据包 result = sr1(packet, timeout=2, verbose=False) # 提取返回的MAC地址 # result.show() return result.getlayer( "ICMPv6 Neighbor Discovery Option - Destination Link-Layer Address" ).fields['lladdr']
def create_ndp_req(self): """Create NDP - NS applicable for this interface""" nsma = in6_getnsma(inet_pton(socket.AF_INET6, self.local_ip6)) d = inet_ntop(socket.AF_INET6, nsma) return (Ether(dst=in6_getnsmac(nsma)) / IPv6(dst=d, src=self.remote_ip6) / ICMPv6ND_NS(tgt=self.local_ip6) / ICMPv6NDOptSrcLLAddr(lladdr=self.remote_mac))
def resolve_icmpv6_nd_on_software_interfaces(cls, args): for i in args: ip = cls.VPP_SOFT_IP6S[i] cls.log("Sending ICMPv6ND_NS request for %s on port %u" % (ip, i)) nd_req = (Ether(dst="ff:ff:ff:ff:ff:ff", src=cls.MY_MACS[i]) / IPv6(src=cls.MY_SOFT_IP6S[i], dst=ip) / ICMPv6ND_NS(tgt=ip) / ICMPv6NDOptSrcLLAddr(lladdr=cls.MY_MACS[i])) cls.pg_add_stream(i, nd_req) cls.pg_enable_capture([i]) cls.cli(2, "trace add pg-input 1") cls.pg_start()
def test_ipv6_flows(self): """ Verify that a UPLINK->UE arp request is properly matched """ ll_addr = get_if_hwaddr('testing_br') pkt_sender = ScapyPacketInjector(self.IFACE) pkt_rs = Ether(dst=self.OTHER_MAC, src=self.UE_MAC) pkt_rs /= IPv6( src='fe80:24c3:d0ff:fef3:9d21:4407:d337:1928', dst='ff02::2', ) pkt_rs /= ICMPv6ND_RS() pkt_rs /= ICMPv6NDOptSrcLLAddr(lladdr=ll_addr) pkt_ns = Ether(dst=self.OTHER_MAC, src=self.UE_MAC) pkt_ns /= IPv6( src='fe80::9d21:4407:d337:1928', dst='ff02::2', ) pkt_ns /= ICMPv6ND_NS(tgt='abcd:87:3::') pkt_ns /= ICMPv6NDOptSrcLLAddr(lladdr=ll_addr) ipv6_addr = 'ab22:5:6c:9:9d21:4407:d337:1928' interface = get_ipv6_interface_id(ipv6_addr) prefix = get_ipv6_prefix(ipv6_addr) self.service_manager.interface_to_prefix_mapper.save_prefix( interface, prefix, ) ulink_args = RyuForwardFlowArgsBuilder(self._tbl_num) \ .set_eth_match(eth_dst=self.OTHER_MAC, eth_src=self.UE_MAC) \ .set_reg_value(DIRECTION_REG, Direction.OUT) \ .build_requests() isolator = RyuDirectTableIsolator(ulink_args, self.testing_controller) snapshot_verifier = SnapshotVerifier( self, self.BRIDGE, self.service_manager, include_stats=False, ) with isolator, snapshot_verifier: pkt_sender.send(pkt_rs) pkt_sender.send(pkt_ns) wait_after_send(self.testing_controller, wait_time=5)
def resolve_icmpv6_nd(cls, args): for i in args: ip = cls.VPP_IP6S[i] cls.log("Sending ICMPv6ND_NS request for %s on port %u" % (ip, i)) nd_req = (Ether(dst="ff:ff:ff:ff:ff:ff", src=cls.MY_MACS[i]) / IPv6(src=cls.MY_IP6S[i], dst=ip) / ICMPv6ND_NS(tgt=ip) / ICMPv6NDOptSrcLLAddr(lladdr=cls.MY_MACS[i])) cls.pg_add_stream(i, nd_req) cls.pg_enable_capture([i]) cls.cli(2, "trace add pg-input 1") cls.pg_start() nd_reply = cls.pg_get_capture(i)[0] icmpv6_na = nd_reply[ 'ICMPv6 Neighbor Discovery - Neighbor Advertisement'] dst_ll_addr = icmpv6_na[ 'ICMPv6 Neighbor Discovery Option - Destination Link-Layer Address'] cls.VPP_MACS[i] = dst_ll_addr.lladdr
def test_vrrp6_backup_nond(self): """ IPv6 Backup VR ignores NDP """ # We need an address for a virtual IP that is not the IP that # ARP requests will originate from vr_id = 100 prio = 100 intvl = self._default_adv intvl_s = intvl * 0.01 vip = self.pg0.remote_hosts[1].ip6 vr = VppVRRPVirtualRouter(self, self.pg0, vr_id, prio=prio, intvl=intvl, flags=self._default_flags, vips=[vip]) vr.add_vpp_config() self._vrs.append(vr) nsma = in6_getnsma(inet_pton(socket.AF_INET6, vip)) dmac = in6_getnsmac(nsma) dst_ip = inet_ntop(socket.AF_INET6, nsma) ndp_req = (Ether(dst=dmac, src=self.pg0.remote_mac) / IPv6(dst=dst_ip, src=self.pg0.remote_ip6) / ICMPv6ND_NS(tgt=vip) / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)) # Before the VR is started make sure no reply to request for VIP self.send_and_assert_no_replies(self.pg0, [ndp_req], timeout=1) # VR should start in backup state and still should not reply to NDP # send a higher priority adv to make sure it does not become master adv = vr.vrrp_adv_packet(prio=prio + 10, src_ip=self.pg0.remote_ip6) pkts = [adv, ndp_req] vr.start_stop(is_start=1) self.send_and_assert_no_replies(self.pg0, pkts, timeout=intvl_s) vr.start_stop(is_start=0)
def test_gbp(self): """ Group Based Policy """ nat_table = VppIpTable(self, 20) nat_table.add_vpp_config() nat_table = VppIpTable(self, 20, is_ip6=True) nat_table.add_vpp_config() # # Bridge Domains # self.vapi.bridge_domain_add_del(1, flood=1, uu_flood=1, forward=1, learn=0, arp_term=1, is_add=1) self.vapi.bridge_domain_add_del(2, flood=1, uu_flood=1, forward=1, learn=0, arp_term=1, is_add=1) self.vapi.bridge_domain_add_del(20, flood=1, uu_flood=1, forward=1, learn=0, arp_term=1, is_add=1) # # 3 EPGs, 2 of which share a BD. # epgs = [] recircs = [] epgs.append( VppGbpEndpointGroup(self, 220, 0, 1, self.pg4, self.loop0, "10.0.0.128", "2001:10::128")) recircs.append(VppGbpRecirc(self, epgs[0], self.loop3)) epgs.append( VppGbpEndpointGroup(self, 221, 0, 1, self.pg5, self.loop0, "10.0.1.128", "2001:10:1::128")) recircs.append(VppGbpRecirc(self, epgs[1], self.loop4)) epgs.append( VppGbpEndpointGroup(self, 222, 0, 2, self.pg6, self.loop1, "10.0.2.128", "2001:10:2::128")) recircs.append(VppGbpRecirc(self, epgs[2], self.loop5)) # # 2 NAT EPGs, one for floating-IP subnets, the other for internet # epgs.append( VppGbpEndpointGroup(self, 333, 20, 20, self.pg7, self.loop2, "11.0.0.128", "3001::128")) recircs.append(VppGbpRecirc(self, epgs[3], self.loop6, is_ext=True)) epgs.append( VppGbpEndpointGroup(self, 444, 20, 20, self.pg8, self.loop2, "11.0.0.129", "3001::129")) recircs.append(VppGbpRecirc(self, epgs[4], self.loop8, is_ext=True)) epg_nat = epgs[3] recirc_nat = recircs[3] # # 4 end-points, 2 in the same subnet, 3 in the same BD # eps = [] eps.append( VppGbpEndpoint(self, self.pg0, epgs[0], recircs[0], "10.0.0.1", "11.0.0.1")) eps.append( VppGbpEndpoint(self, self.pg1, epgs[0], recircs[0], "10.0.0.2", "11.0.0.2")) eps.append( VppGbpEndpoint(self, self.pg2, epgs[1], recircs[1], "10.0.1.1", "11.0.0.3")) eps.append( VppGbpEndpoint(self, self.pg3, epgs[2], recircs[2], "10.0.2.1", "11.0.0.4")) eps.append( VppGbpEndpoint(self, self.pg0, epgs[0], recircs[0], "2001:10::1", "3001::1", is_ip6=True)) eps.append( VppGbpEndpoint(self, self.pg1, epgs[0], recircs[0], "2001:10::2", "3001::2", is_ip6=True)) eps.append( VppGbpEndpoint(self, self.pg2, epgs[1], recircs[1], "2001:10:1::1", "3001::3", is_ip6=True)) eps.append( VppGbpEndpoint(self, self.pg3, epgs[2], recircs[2], "2001:10:2::1", "3001::4", is_ip6=True)) # # Config related to each of the EPGs # for epg in epgs: # IP config on the BVI interfaces if epg != epgs[1] and epg != epgs[4]: epg.bvi.set_table_ip4(epg.rd) epg.bvi.set_table_ip6(epg.rd) # The BVIs are NAT inside interfaces self.vapi.nat44_interface_add_del_feature(epg.bvi.sw_if_index, is_inside=1, is_add=1) self.vapi.nat66_add_del_interface(epg.bvi.sw_if_index, is_inside=1, is_add=1) self.vapi.sw_interface_add_del_address(epg.bvi.sw_if_index, epg.bvi_ip4_n, 32) self.vapi.sw_interface_add_del_address(epg.bvi.sw_if_index, epg.bvi_ip6_n, 128, is_ipv6=True) # EPG uplink interfaces in the BD epg.uplink.set_table_ip4(epg.rd) epg.uplink.set_table_ip6(epg.rd) self.vapi.sw_interface_set_l2_bridge(epg.uplink.sw_if_index, epg.bd) # add the BD ARP termination entry for BVI IP self.vapi.bd_ip_mac_add_del(bd_id=epg.bd, mac=mactobinary(self.router_mac), ip=epg.bvi_ip4_n, is_ipv6=0, is_add=1) self.vapi.bd_ip_mac_add_del(bd_id=epg.bd, mac=mactobinary(self.router_mac), ip=epg.bvi_ip6_n, is_ipv6=1, is_add=1) # epg[1] shares the same BVI to epg[0] if epg != epgs[1] and epg != epgs[4]: # BVI in BD self.vapi.sw_interface_set_l2_bridge(epg.bvi.sw_if_index, epg.bd, bvi=1) # BVI L2 FIB entry self.vapi.l2fib_add_del(self.router_mac, epg.bd, epg.bvi.sw_if_index, is_add=1, bvi_mac=1) # EPG in VPP epg.add_vpp_config() for recirc in recircs: # EPG's ingress recirculation interface maps to its RD recirc.recirc.set_table_ip4(recirc.epg.rd) recirc.recirc.set_table_ip6(recirc.epg.rd) # in the bridge to allow DVR. L2 emulation to punt to L3 self.vapi.sw_interface_set_l2_bridge(recirc.recirc.sw_if_index, recirc.epg.bd) self.vapi.sw_interface_set_l2_emulation(recirc.recirc.sw_if_index) self.vapi.nat44_interface_add_del_feature( recirc.recirc.sw_if_index, is_inside=0, is_add=1) self.vapi.nat66_add_del_interface(recirc.recirc.sw_if_index, is_inside=0, is_add=1) recirc.add_vpp_config() ep_routes = [] ep_arps = [] for ep in eps: self.pg_enable_capture(self.pg_interfaces) self.pg_start() # # routes to the endpoints. We need these since there are no # adj-fibs due to the fact the the BVI address has /32 and # the subnet is not attached. # r = VppIpRoute( self, ep.ip, ep.ip_len, [VppRoutePath(ep.ip, ep.epg.bvi.sw_if_index, proto=ep.proto)], is_ip6=ep.is_ip6) r.add_vpp_config() ep_routes.append(r) # # ARP entries for the endpoints # a = VppNeighbor(self, ep.epg.bvi.sw_if_index, ep.itf.remote_mac, ep.ip, af=ep.af) a.add_vpp_config() ep_arps.append(a) # add each EP itf to the its BD self.vapi.sw_interface_set_l2_bridge(ep.itf.sw_if_index, ep.epg.bd) # add the BD ARP termination entry self.vapi.bd_ip_mac_add_del(bd_id=ep.epg.bd, mac=ep.bin_mac, ip=ep.ip_n, is_ipv6=0, is_add=1) # L2 FIB entry self.vapi.l2fib_add_del(ep.mac, ep.epg.bd, ep.itf.sw_if_index, is_add=1) # Add static mappings for each EP from the 10/8 to 11/8 network if ep.af == AF_INET: self.vapi.nat44_add_del_static_mapping(ep.ip_n, ep.floating_ip_n, vrf_id=0, addr_only=1) else: self.vapi.nat66_add_del_static_mapping(ep.ip_n, ep.floating_ip_n, vrf_id=0) # VPP EP create ... ep.add_vpp_config() # ... results in a Gratuitous ARP/ND on the EPG's uplink rx = ep.epg.uplink.get_capture(1, timeout=0.2) if ep.is_ip6: self.assertTrue(rx[0].haslayer(ICMPv6ND_NA)) self.assertEqual(rx[0][ICMPv6ND_NA].tgt, ep.ip) else: self.assertTrue(rx[0].haslayer(ARP)) self.assertEqual(rx[0][ARP].psrc, ep.ip) self.assertEqual(rx[0][ARP].pdst, ep.ip) # add the BD ARP termination entry for floating IP self.vapi.bd_ip_mac_add_del(bd_id=epg_nat.bd, mac=ep.bin_mac, ip=ep.floating_ip_n, is_ipv6=ep.is_ip6, is_add=1) # floating IPs route via EPG recirc r = VppIpRoute(self, ep.floating_ip, ep.ip_len, [ VppRoutePath(ep.floating_ip, ep.recirc.recirc.sw_if_index, is_dvr=1, proto=ep.proto) ], table_id=20, is_ip6=ep.is_ip6) r.add_vpp_config() ep_routes.append(r) # L2 FIB entries in the NAT EPG BD to bridge the packets from # the outside direct to the internal EPG self.vapi.l2fib_add_del(ep.mac, epg_nat.bd, ep.recirc.recirc.sw_if_index, is_add=1) # # ARP packets for unknown IP are flooded # pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(op="who-has", hwdst="ff:ff:ff:ff:ff:ff", hwsrc=self.pg0.remote_mac, pdst=epgs[0].bvi_ip4, psrc="10.0.0.88")) self.send_and_expect(self.pg0, [pkt_arp], self.pg0) # # ARP/ND packets get a response # pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(op="who-has", hwdst="ff:ff:ff:ff:ff:ff", hwsrc=self.pg0.remote_mac, pdst=epgs[0].bvi_ip4, psrc=eps[0].ip)) self.send_and_expect(self.pg0, [pkt_arp], self.pg0) nsma = in6_getnsma(inet_pton(AF_INET6, eps[4].ip)) d = inet_ntop(AF_INET6, nsma) pkt_nd = (Ether(dst=in6_getnsmac(nsma)) / IPv6(dst=d, src=eps[4].ip) / ICMPv6ND_NS(tgt=epgs[0].bvi_ip6) / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)) self.send_and_expect(self.pg0, [pkt_nd], self.pg0) # # broadcast packets are flooded # pkt_bcast = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / IP(src=eps[0].ip, dst="232.1.1.1") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.vapi.cli("clear trace") self.pg0.add_stream(pkt_bcast) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rxd = eps[1].itf.get_capture(1) self.assertEqual(rxd[0][Ether].dst, pkt_bcast[Ether].dst) rxd = epgs[0].uplink.get_capture(1) self.assertEqual(rxd[0][Ether].dst, pkt_bcast[Ether].dst) # # packets to non-local L3 destinations dropped # pkt_intra_epg_220_ip4 = ( Ether(src=self.pg0.remote_mac, dst=self.router_mac) / IP(src=eps[0].ip, dst="10.0.0.99") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) pkt_inter_epg_222_ip4 = ( Ether(src=self.pg0.remote_mac, dst=self.router_mac) / IP(src=eps[0].ip, dst="10.0.1.99") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_assert_no_replies(self.pg0, pkt_intra_epg_220_ip4 * 65) pkt_inter_epg_222_ip6 = ( Ether(src=self.pg0.remote_mac, dst=self.router_mac) / IPv6(src=eps[4].ip, dst="2001:10::99") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_222_ip6 * 65) # # Add the subnet routes # s41 = VppGbpSubnet(self, 0, "10.0.0.0", 24) s42 = VppGbpSubnet(self, 0, "10.0.1.0", 24) s43 = VppGbpSubnet(self, 0, "10.0.2.0", 24) s41.add_vpp_config() s42.add_vpp_config() s43.add_vpp_config() s61 = VppGbpSubnet(self, 0, "2001:10::1", 64, is_ip6=True) s62 = VppGbpSubnet(self, 0, "2001:10:1::1", 64, is_ip6=True) s63 = VppGbpSubnet(self, 0, "2001:10:2::1", 64, is_ip6=True) s61.add_vpp_config() s62.add_vpp_config() s63.add_vpp_config() self.send_and_expect_bridged(self.pg0, pkt_intra_epg_220_ip4 * 65, self.pg4) self.send_and_expect_bridged(self.pg3, pkt_inter_epg_222_ip4 * 65, self.pg6) self.send_and_expect_bridged6(self.pg3, pkt_inter_epg_222_ip6 * 65, self.pg6) self.logger.info(self.vapi.cli("sh ip fib 11.0.0.2")) self.logger.info(self.vapi.cli("sh gbp endpoint-group")) self.logger.info(self.vapi.cli("sh gbp endpoint")) self.logger.info(self.vapi.cli("sh gbp recirc")) self.logger.info(self.vapi.cli("sh int")) self.logger.info(self.vapi.cli("sh int addr")) self.logger.info(self.vapi.cli("sh int feat loop6")) self.logger.info(self.vapi.cli("sh vlib graph ip4-gbp-src-classify")) self.logger.info(self.vapi.cli("sh int feat loop3")) # # Packet destined to unknown unicast is sent on the epg uplink ... # pkt_intra_epg_220_to_uplink = ( Ether(src=self.pg0.remote_mac, dst="00:00:00:33:44:55") / IP(src=eps[0].ip, dst="10.0.0.99") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_expect_bridged(self.pg0, pkt_intra_epg_220_to_uplink * 65, self.pg4) # ... and nowhere else self.pg1.get_capture(0, timeout=0.1) self.pg1.assert_nothing_captured(remark="Flood onto other VMS") pkt_intra_epg_221_to_uplink = ( Ether(src=self.pg2.remote_mac, dst="00:00:00:33:44:66") / IP(src=eps[0].ip, dst="10.0.0.99") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_expect_bridged(self.pg2, pkt_intra_epg_221_to_uplink * 65, self.pg5) # # Packets from the uplink are forwarded in the absence of a contract # pkt_intra_epg_220_from_uplink = ( Ether(src="00:00:00:33:44:55", dst=self.pg0.remote_mac) / IP(src=eps[0].ip, dst="10.0.0.99") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_expect_bridged(self.pg4, pkt_intra_epg_220_from_uplink * 65, self.pg0) # # in the absence of policy, endpoints in the same EPG # can communicate # pkt_intra_epg = ( Ether(src=self.pg0.remote_mac, dst=self.pg1.remote_mac) / IP(src=eps[0].ip, dst=eps[1].ip) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_expect_bridged(self.pg0, pkt_intra_epg * 65, self.pg1) # # in the abscense of policy, endpoints in the different EPG # cannot communicate # pkt_inter_epg_220_to_221 = ( Ether(src=self.pg0.remote_mac, dst=self.pg2.remote_mac) / IP(src=eps[0].ip, dst=eps[2].ip) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) pkt_inter_epg_221_to_220 = ( Ether(src=self.pg2.remote_mac, dst=self.pg0.remote_mac) / IP(src=eps[2].ip, dst=eps[0].ip) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) pkt_inter_epg_220_to_222 = ( Ether(src=self.pg0.remote_mac, dst=self.router_mac) / IP(src=eps[0].ip, dst=eps[3].ip) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_220_to_221 * 65) self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_220_to_222 * 65) # # A uni-directional contract from EPG 220 -> 221 # c1 = VppGbpContract(self, 220, 221, 0) c1.add_vpp_config() self.send_and_expect_bridged(self.pg0, pkt_inter_epg_220_to_221 * 65, self.pg2) self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_220_to_222 * 65) # # contract for the return direction # c2 = VppGbpContract(self, 221, 220, 0) c2.add_vpp_config() self.send_and_expect_bridged(self.pg0, pkt_inter_epg_220_to_221 * 65, self.pg2) self.send_and_expect_bridged(self.pg2, pkt_inter_epg_221_to_220 * 65, self.pg0) # # check that inter group is still disabled for the groups # not in the contract. # self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_220_to_222 * 65) # # A uni-directional contract from EPG 220 -> 222 'L3 routed' # c3 = VppGbpContract(self, 220, 222, 0) c3.add_vpp_config() self.logger.info(self.vapi.cli("sh gbp contract")) self.send_and_expect_routed(self.pg0, pkt_inter_epg_220_to_222 * 65, self.pg3, self.router_mac) # # remove both contracts, traffic stops in both directions # c2.remove_vpp_config() c1.remove_vpp_config() c3.remove_vpp_config() self.send_and_assert_no_replies(self.pg2, pkt_inter_epg_221_to_220 * 65) self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_220_to_221 * 65) self.send_and_expect_bridged(self.pg0, pkt_intra_epg * 65, self.pg1) # # EPs to the outside world # # in the EP's RD an external subnet via the NAT EPG's recirc se1 = VppGbpSubnet(self, 0, "0.0.0.0", 0, is_internal=False, sw_if_index=recirc_nat.recirc.sw_if_index, epg=epg_nat.epg) se1.add_vpp_config() se2 = VppGbpSubnet(self, 0, "11.0.0.0", 8, is_internal=False, sw_if_index=recirc_nat.recirc.sw_if_index, epg=epg_nat.epg) se2.add_vpp_config() se16 = VppGbpSubnet(self, 0, "::", 0, is_internal=False, sw_if_index=recirc_nat.recirc.sw_if_index, epg=epg_nat.epg, is_ip6=True) se16.add_vpp_config() # in the NAT RD an external subnet via the NAT EPG's uplink se3 = VppGbpSubnet(self, 20, "0.0.0.0", 0, is_internal=False, sw_if_index=epg_nat.uplink.sw_if_index, epg=epg_nat.epg) se36 = VppGbpSubnet(self, 20, "::", 0, is_internal=False, sw_if_index=epg_nat.uplink.sw_if_index, epg=epg_nat.epg, is_ip6=True) se4 = VppGbpSubnet(self, 20, "11.0.0.0", 8, is_internal=False, sw_if_index=epg_nat.uplink.sw_if_index, epg=epg_nat.epg) se3.add_vpp_config() se36.add_vpp_config() se4.add_vpp_config() self.logger.info(self.vapi.cli("sh ip fib 0.0.0.0/0")) self.logger.info(self.vapi.cli("sh ip fib 11.0.0.1")) self.logger.info(self.vapi.cli("sh ip6 fib ::/0")) self.logger.info(self.vapi.cli("sh ip6 fib %s" % eps[4].floating_ip)) # # From an EP to an outside addess: IN2OUT # pkt_inter_epg_220_to_global = ( Ether(src=self.pg0.remote_mac, dst=self.router_mac) / IP(src=eps[0].ip, dst="1.1.1.1") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) # no policy yet self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_220_to_global * 65) c4 = VppGbpContract(self, 220, 333, 0) c4.add_vpp_config() self.send_and_expect_natted(self.pg0, pkt_inter_epg_220_to_global * 65, self.pg7, eps[0].floating_ip) pkt_inter_epg_220_to_global = ( Ether(src=self.pg0.remote_mac, dst=self.router_mac) / IPv6(src=eps[4].ip, dst="6001::1") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_expect_natted6(self.pg0, pkt_inter_epg_220_to_global * 65, self.pg7, eps[4].floating_ip) # # From a global address to an EP: OUT2IN # pkt_inter_epg_220_from_global = ( Ether(src=self.router_mac, dst=self.pg0.remote_mac) / IP(dst=eps[0].floating_ip, src="1.1.1.1") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_assert_no_replies(self.pg7, pkt_inter_epg_220_from_global * 65) c5 = VppGbpContract(self, 333, 220, 0) c5.add_vpp_config() self.send_and_expect_unnatted(self.pg7, pkt_inter_epg_220_from_global * 65, eps[0].itf, eps[0].ip) pkt_inter_epg_220_from_global = ( Ether(src=self.router_mac, dst=self.pg0.remote_mac) / IPv6(dst=eps[4].floating_ip, src="6001::1") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_expect_unnatted6(self.pg7, pkt_inter_epg_220_from_global * 65, eps[4].itf, eps[4].ip) # # From a local VM to another local VM using resp. public addresses: # IN2OUT2IN # pkt_intra_epg_220_global = ( Ether(src=self.pg0.remote_mac, dst=self.router_mac) / IP(src=eps[0].ip, dst=eps[1].floating_ip) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_expect_double_natted(eps[0].itf, pkt_intra_epg_220_global * 65, eps[1].itf, eps[0].floating_ip, eps[1].ip) pkt_intra_epg_220_global = ( Ether(src=self.pg4.remote_mac, dst=self.router_mac) / IPv6(src=eps[4].ip, dst=eps[5].floating_ip) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_expect_double_natted6(eps[4].itf, pkt_intra_epg_220_global * 65, eps[5].itf, eps[4].floating_ip, eps[5].ip) # # cleanup # for ep in eps: # del static mappings for each EP from the 10/8 to 11/8 network if ep.af == AF_INET: self.vapi.nat44_add_del_static_mapping(ep.ip_n, ep.floating_ip_n, vrf_id=0, addr_only=1, is_add=0) else: self.vapi.nat66_add_del_static_mapping(ep.ip_n, ep.floating_ip_n, vrf_id=0, is_add=0) for epg in epgs: # IP config on the BVI interfaces self.vapi.sw_interface_add_del_address(epg.bvi.sw_if_index, epg.bvi_ip4_n, 32, is_add=0) self.vapi.sw_interface_add_del_address(epg.bvi.sw_if_index, epg.bvi_ip6_n, 128, is_add=0, is_ipv6=True) self.logger.info(self.vapi.cli("sh int addr")) epg.uplink.set_table_ip4(0) epg.uplink.set_table_ip6(0) if epg != epgs[0] and epg != epgs[3]: epg.bvi.set_table_ip4(0) epg.bvi.set_table_ip6(0) self.vapi.nat44_interface_add_del_feature(epg.bvi.sw_if_index, is_inside=1, is_add=0) self.vapi.nat66_add_del_interface(epg.bvi.sw_if_index, is_inside=1, is_add=0) for recirc in recircs: recirc.recirc.set_table_ip4(0) recirc.recirc.set_table_ip6(0) self.vapi.nat44_interface_add_del_feature( recirc.recirc.sw_if_index, is_inside=0, is_add=0) self.vapi.nat66_add_del_interface(recirc.recirc.sw_if_index, is_inside=0, is_add=0)
def create_ndp_req(self): """Create NDP - NS applicable for this interface""" return (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.remote_mac) / IPv6(src=self.remote_ip6, dst=self.local_ip6) / ICMPv6ND_NS(tgt=self.local_ip6) / ICMPv6NDOptSrcLLAddr(lladdr=self.remote_mac))
def main(): args = TrafficScriptArg(['src_mac', 'dst_mac', 'src_ip', 'dst_ip']) rxq = RxQueue(args.get_arg('rx_if')) txq = TxQueue(args.get_arg('tx_if')) src_mac = args.get_arg('src_mac') dst_mac = args.get_arg('dst_mac') src_ip = args.get_arg('src_ip') dst_ip = args.get_arg('dst_ip') sent_packets = [] # send ICMPv6 neighbor solicitation message pkt_send = (Ether(src=src_mac, dst='ff:ff:ff:ff:ff:ff') / IPv6(src=src_ip, dst='ff02::1:ff00:2') / ICMPv6ND_NS(tgt=dst_ip) / ICMPv6NDOptSrcLLAddr(lladdr=src_mac)) sent_packets.append(pkt_send) txq.send(pkt_send) # receive ICMPv6 neighbor advertisement message ether = rxq.recv(2, sent_packets) if ether is None: raise RuntimeError('ICMPv6 echo reply Rx timeout') if not ether.haslayer(IPv6): raise RuntimeError( 'Unexpected packet with no IPv6 received {0}'.format( ether.__repr__())) ipv6 = ether['IPv6'] if not ipv6.haslayer(ICMPv6ND_NA): raise RuntimeError( 'Unexpected packet with no ICMPv6 ND-NA received {0}'.format( ipv6.__repr__())) icmpv6_na = ipv6['ICMPv6 Neighbor Discovery - Neighbor Advertisement'] # verify target address if icmpv6_na.tgt != dst_ip: raise RuntimeError('Invalid target address {0} should be {1}'.format( icmpv6_na.tgt, dst_ip)) if not icmpv6_na.haslayer(ICMPv6NDOptDstLLAddr): raise RuntimeError( 'Missing Destination Link-Layer Address option in ICMPv6 ' + 'Neighbor Advertisement {0}'.format(icmpv6_na.__repr__())) option = 'ICMPv6 Neighbor Discovery Option - Destination Link-Layer Address' dst_ll_addr = icmpv6_na[option] # verify destination link-layer address field if dst_ll_addr.lladdr != dst_mac: raise RuntimeError('Invalid lladdr {0} should be {1}'.format( dst_ll_addr.lladdr, dst_mac)) # verify checksum cksum = icmpv6_na.cksum del icmpv6_na.cksum tmp = ICMPv6ND_NA(str(icmpv6_na)) if not checksum_equal(tmp.cksum, cksum): raise RuntimeError('Invalid checksum {0} should be {1}'.format( cksum, tmp.cksum)) sys.exit(0)
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()
def imcpv6nd_solicit(tx_if, src_mac, dst_mac, src_ip, dst_ip): """Send ICMPv6 Neighbor Solicitation packet and expect a response from the proxy. :param tx_if: Interface on TG. :param src_mac: MAC address of TG interface. :param dst_mac: MAC address of proxy interface. :param src_ip: IP address of TG interface. :param dst_ip: IP address of proxied interface. :type tx_if: str :type src_mac: str :type dst_mac: str :type src_ip: str :type dst_ip: str :raises RuntimeError: If the received packet is not correct. """ rxq = RxQueue(tx_if) txq = TxQueue(tx_if) sent_packets = [] icmpv6nd_solicit_pkt = (Ether(src=src_mac, dst=dst_mac) / IPv6(src=src_ip) / ICMPv6ND_NS(tgt=dst_ip)) sent_packets.append(icmpv6nd_solicit_pkt) txq.send(icmpv6nd_solicit_pkt) ether = None for _ in range(5): ether = rxq.recv(3, ignore=sent_packets) if not ether: continue if ether.haslayer(ICMPv6ND_NS): # read another packet in the queue in case of ICMPv6ND_NS packet continue else: # otherwise process the current packet break if ether is None: raise RuntimeError('ICMPv6ND Proxy response timeout.') if ether.src != dst_mac: raise RuntimeError("Source MAC address error: {} != {}".format( ether.src, dst_mac)) print "Source MAC address: OK." if ether.dst != src_mac: raise RuntimeError("Destination MAC address error: {} != {}".format( ether.dst, src_mac)) print "Destination MAC address: OK." if ether[IPv6].src != dst_ip: raise RuntimeError("Source IP address error: {} != {}".format( ether[IPv6].src, dst_ip)) print "Source IP address: OK." if ether[IPv6].dst != src_ip: raise RuntimeError("Destination IP address error: {} != {}".format( ether[IPv6].dst, src_ip)) print "Destination IP address: OK." try: target_addr = ether[IPv6][ICMPv6ND_NA].tgt except (KeyError, AttributeError): raise RuntimeError("Not an ICMPv6ND Neighbor Advertisement packet.") if target_addr != dst_ip: raise RuntimeError( "ICMPv6 field 'Target address' error: {} != {}".format( target_addr, dst_ip)) print "Target address field: OK."
def test_ns(self): """ IPv6 Neighbour Solicitation Exceptions Test scenario: - Send an NS Sourced from an address not covered by the link sub-net - Send an NS to an mcast address the router has not joined - Send NS for a target address the router does not onn. """ # # An NS from a non link source address # nsma = in6_getnsma(inet_pton(AF_INET6, self.pg0.local_ip6)) d = inet_ntop(AF_INET6, nsma) p = (Ether(dst=in6_getnsmac(nsma)) / IPv6(dst=d, src="2002::2") / ICMPv6ND_NS(tgt=self.pg0.local_ip6) / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)) pkts = [p] self.send_and_assert_no_replies( self.pg0, pkts, "No response to NS source by address not on sub-net") # # An NS for sent to a solicited mcast group the router is # not a member of FAILS # if 0: nsma = in6_getnsma(inet_pton(AF_INET6, "fd::ffff")) d = inet_ntop(AF_INET6, nsma) p = (Ether(dst=in6_getnsmac(nsma)) / IPv6(dst=d, src=self.pg0.remote_ip6) / ICMPv6ND_NS(tgt=self.pg0.local_ip6) / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)) pkts = [p] self.send_and_assert_no_replies( self.pg0, pkts, "No response to NS sent to unjoined mcast address") # # An NS whose target address is one the router does not own # nsma = in6_getnsma(inet_pton(AF_INET6, self.pg0.local_ip6)) d = inet_ntop(AF_INET6, nsma) p = (Ether(dst=in6_getnsmac(nsma)) / IPv6(dst=d, src=self.pg0.remote_ip6) / ICMPv6ND_NS(tgt="fd::ffff") / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)) pkts = [p] self.send_and_assert_no_replies( self.pg0, pkts, "No response to NS for unknown target") # # A neighbor entry that has no associated FIB-entry # self.pg0.generate_remote_hosts(4) nd_entry = VppNeighbor(self, self.pg0.sw_if_index, self.pg0.remote_hosts[2].mac, self.pg0.remote_hosts[2].ip6, af=AF_INET6, is_no_fib_entry=1) nd_entry.add_vpp_config() # # check we have the neighbor, but no route # self.assertTrue( find_nbr(self, self.pg0.sw_if_index, self.pg0._remote_hosts[2].ip6, inet=AF_INET6)) self.assertFalse( find_route(self, self.pg0._remote_hosts[2].ip6, 128, inet=AF_INET6))
def create_ndp_req(self): return (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.remote_mac) / IPv6(src=self.remote_ip6, dst=self.local_ip6) / ICMPv6ND_NS(tgt=self.local_ip6) / ICMPv6NDOptSrcLLAddr(lladdr=self.remote_mac))
def run(self, pipe): ''' Will execute IPv6 NS request ''' # re-initialize in case of multiple consecutive runs # (e.g. from console-plugin) self.record.initialize() ns_request = Ether(src=self.src_mac, dst=self.nd_dst_mac)/ \ IPv6(src=self.src_ip, dst=self.nd_dst_ipv6)/ \ ICMPv6ND_NS(tgt=self.dst_ip)/ \ ICMPv6NDOptSrcLLAddr(lladdr=self.src_mac) # add VLAN to the packet if needed if not self.vlan.is_default(): self.vlan.embed(ns_request, fmt=self.fmt) for retry in range(0, (self.retries + 1)): # send neighbor solicitation tx_info = yield pipe.async_tx_pkt(ns_request) self.log("ND: TX NS: {0},{1} -> {2} (retry {3})".format( self.src_ip, self.src_mac, self.dst_ip, retry)) # wait for NA packet pkts = yield pipe.async_wait_for_pkt(time_sec=self.timeout) if not pkts: self.log("ND: timeout for {0},{1} <-- {2} (retry {3})".format( self.src_ip, self.src_mac, self.dst_ip, retry)) continue for p in pkts: # parse record response = Ether(p['pkt']) if ICMPv6NDOptDstLLAddr in response: self.log("ND: RX NA: {0} <- {1}, {2}".format( response[IPv6].dst, response[IPv6].src, response[ICMPv6NDOptDstLLAddr].lladdr)) self.record.update(response) if ICMPv6ND_NS in response: self.handle_ns_request(pipe, response) if self.record.is_resolved() == True: break if not self.record.is_resolved() == True: # ND failed return # # neighbor verification - wait for incoming NS requests from # neighbors to achieve a proper "REACHABLE" state on remote # device # start_time = time.time() while (time.time() - start_time) < self.verify_timeout: pkts = yield pipe.async_wait_for_pkt(time_sec=self.verify_timeout) if not pkts: pass else: for packet in pkts: p = Ether(packet['pkt']) if ICMPv6ND_NA in p: # NAs are not expected anymore... self.log( "ND: late arrival of NA from {0} for {1} discarded" .format(p[IPv6].src, p[IPv6].dst)) elif ICMPv6ND_NS not in p: # everything else should be NS's self.log("ND: got unexpected packet: {0}".format( p.summary())) else: self.handle_ns_request(pipe, p)
def test_nd_proxy(self): """ IPv6 Proxy ND """ # # Generate some hosts in the subnet that we are proxying # self.pg0.generate_remote_hosts(8) nsma = in6_getnsma(inet_pton(AF_INET6, self.pg0.local_ip6)) d = inet_ntop(AF_INET6, nsma) # # Send an NS for one of those remote hosts on one of the proxy links # expect no response since it's from an address that is not # on the link that has the prefix configured # ns_pg1 = (Ether(dst=in6_getnsmac(nsma), src=self.pg1.remote_mac) / IPv6(dst=d, src=self.pg0._remote_hosts[2].ip6) / ICMPv6ND_NS(tgt=self.pg0.local_ip6) / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0._remote_hosts[2].mac)) self.send_and_assert_no_replies(self.pg1, ns_pg1, "Off link NS") # # Add proxy support for the host # self.vapi.ip6_nd_proxy( inet_pton(AF_INET6, self.pg0._remote_hosts[2].ip6), self.pg1.sw_if_index) # # try that NS again. this time we expect an NA back # self.pg1.add_stream(ns_pg1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.validate_na(self.pg1, rx[0], dst_ip=self.pg0._remote_hosts[2].ip6, tgt_ip=self.pg0.local_ip6) # # ... and that we have an entry in the ND cache # self.assertTrue( find_nbr(self, self.pg1.sw_if_index, self.pg0._remote_hosts[2].ip6, inet=AF_INET6)) # # ... and we can route traffic to it # t = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IPv6(dst=self.pg0._remote_hosts[2].ip6, src=self.pg0.remote_ip6) / UDP(sport=10000, dport=20000) / Raw('\xa5' * 100)) self.pg0.add_stream(t) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) rx = rx[0] self.assertEqual(rx[Ether].dst, self.pg0._remote_hosts[2].mac) self.assertEqual(rx[Ether].src, self.pg1.local_mac) self.assertEqual(rx[IPv6].src, t[IPv6].src) self.assertEqual(rx[IPv6].dst, t[IPv6].dst) # # Test we proxy for the host on the main interface # ns_pg0 = (Ether(dst=in6_getnsmac(nsma), src=self.pg0.remote_mac) / IPv6(dst=d, src=self.pg0.remote_ip6) / ICMPv6ND_NS(tgt=self.pg0._remote_hosts[2].ip6) / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)) self.pg0.add_stream(ns_pg0) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture(1) self.validate_na(self.pg0, rx[0], tgt_ip=self.pg0._remote_hosts[2].ip6, dst_ip=self.pg0.remote_ip6) # # Setup and resolve proxy for another host on another interface # ns_pg2 = (Ether(dst=in6_getnsmac(nsma), src=self.pg2.remote_mac) / IPv6(dst=d, src=self.pg0._remote_hosts[3].ip6) / ICMPv6ND_NS(tgt=self.pg0.local_ip6) / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0._remote_hosts[2].mac)) self.vapi.ip6_nd_proxy( inet_pton(AF_INET6, self.pg0._remote_hosts[3].ip6), self.pg2.sw_if_index) self.pg2.add_stream(ns_pg2) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg2.get_capture(1) self.validate_na(self.pg2, rx[0], dst_ip=self.pg0._remote_hosts[3].ip6, tgt_ip=self.pg0.local_ip6) self.assertTrue( find_nbr(self, self.pg2.sw_if_index, self.pg0._remote_hosts[3].ip6, inet=AF_INET6)) # # hosts can communicate. pg2->pg1 # t2 = (Ether(dst=self.pg2.local_mac, src=self.pg0.remote_hosts[3].mac) / IPv6(dst=self.pg0._remote_hosts[2].ip6, src=self.pg0._remote_hosts[3].ip6) / UDP(sport=10000, dport=20000) / Raw('\xa5' * 100)) self.pg2.add_stream(t2) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) rx = rx[0] self.assertEqual(rx[Ether].dst, self.pg0._remote_hosts[2].mac) self.assertEqual(rx[Ether].src, self.pg1.local_mac) self.assertEqual(rx[IPv6].src, t2[IPv6].src) self.assertEqual(rx[IPv6].dst, t2[IPv6].dst) # # remove the proxy configs # self.vapi.ip6_nd_proxy(inet_pton(AF_INET6, self.pg0._remote_hosts[2].ip6), self.pg1.sw_if_index, is_del=1) self.vapi.ip6_nd_proxy(inet_pton(AF_INET6, self.pg0._remote_hosts[3].ip6), self.pg2.sw_if_index, is_del=1) self.assertFalse( find_nbr(self, self.pg2.sw_if_index, self.pg0._remote_hosts[3].ip6, inet=AF_INET6)) self.assertFalse( find_nbr(self, self.pg1.sw_if_index, self.pg0._remote_hosts[2].ip6, inet=AF_INET6)) # # no longer proxy-ing... # self.send_and_assert_no_replies(self.pg0, ns_pg0, "Proxy unconfigured") self.send_and_assert_no_replies(self.pg1, ns_pg1, "Proxy unconfigured") self.send_and_assert_no_replies(self.pg2, ns_pg2, "Proxy unconfigured") # # no longer forwarding. traffic generates NS out of the glean/main # interface # self.pg2.add_stream(t2) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture(1) self.assertTrue(rx[0].haslayer(ICMPv6ND_NS))