def verify_tunneled_6o6(self, src_if, capture, sent, tunnel_src, tunnel_dst, dscp=0, ecn=0): self.assertEqual(len(capture), len(sent)) tc = (dscp << 2) | ecn for i in range(len(capture)): try: tx = sent[i] rx = capture[i] tx_ip = tx[IPv6] rx_ip = rx[IPv6] self.assertEqual(rx_ip.src, tunnel_src) self.assertEqual(rx_ip.dst, tunnel_dst) self.assertEqual(rx_ip.tc, tc) rx_gre = GRE(scapy.compat.raw(rx_ip[IPv6].payload)) self.assertEqual(rx_ip.plen, len(rx_gre)) rx_ip = rx_gre[IPv6] self.assertEqual(rx_ip.src, tx_ip.src) self.assertEqual(rx_ip.dst, tx_ip.dst) except: self.logger.error(ppp("Rx:", rx)) self.logger.error(ppp("Tx:", tx)) raise
def verify_tunneled_6o4(self, src_if, capture, sent, tunnel_src, tunnel_dst): self.assertEqual(len(capture), len(sent)) for i in range(len(capture)): try: tx = sent[i] rx = capture[i] rx_ip = rx[IP] self.assertEqual(rx_ip.src, tunnel_src) self.assertEqual(rx_ip.dst, tunnel_dst) rx_gre = GRE(scapy.compat.raw(rx_ip[IP].payload)) rx_ip = rx_gre[IPv6] tx_ip = tx[IPv6] self.assertEqual(rx_ip.src, tx_ip.src) self.assertEqual(rx_ip.dst, tx_ip.dst) except: self.logger.error(ppp("Rx:", rx)) self.logger.error(ppp("Tx:", tx)) raise
def test_gre_input_node(self): """ GRE gre input nodes not registerd unless configured """ pkt = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / GRE()) self.pg0.add_stream(pkt) self.pg_start() # no tunnel created, gre-input not registered err = self.statistics.get_counter( '/err/ip4-local/unknown ip protocol')[0] self.assertEqual(err, 1) err_count = err # create gre tunnel gre_if = VppGreInterface(self, self.pg0.local_ip4, "1.1.1.2") gre_if.add_vpp_config() self.pg0.add_stream(pkt) self.pg_start() # tunnel created, gre-input registered err = self.statistics.get_counter( '/err/ip4-local/unknown ip protocol')[0] # expect no new errors self.assertEqual(err, err_count)
def checkCapture(self, encap, isv4): self.pg0.assert_nothing_captured() out = self.pg1.get_capture(len(self.packets)) load = [0] * len(self.ass) self.info = None for p in out: try: asid = 0 gre = None if (encap == 'gre4'): ip = p[IP] asid = int(ip.dst.split(".")[3]) self.assertEqual(ip.version, 4) self.assertEqual(ip.flags, 0) self.assertEqual(ip.src, "39.40.41.42") self.assertEqual(ip.dst, "10.0.0.%u" % asid) self.assertEqual(ip.proto, 47) self.assertEqual(len(ip.options), 0) self.assertGreaterEqual(ip.ttl, 64) gre = p[GRE] self.checkInner(gre, isv4) elif (encap == 'gre6'): ip = p[IPv6] asid = ip.dst.split(":") asid = asid[len(asid) - 1] asid = 0 if asid == "" else int(asid) self.assertEqual(ip.version, 6) self.assertEqual(ip.tc, 0) self.assertEqual(ip.fl, 0) self.assertEqual(ip.src, "2004::1") self.assertEqual( socket.inet_pton(socket.AF_INET6, ip.dst), socket.inet_pton(socket.AF_INET6, "2002::%u" % asid)) self.assertEqual(ip.nh, 47) self.assertGreaterEqual(ip.hlim, 64) # self.assertEqual(len(ip.options), 0) gre = GRE(str(p[IPv6].payload)) self.checkInner(gre, isv4) if (encap == 'l3dsr'): ip = p[IP] asid = int(ip.dst.split(".")[3]) self.assertEqual(ip.version, 4) self.assertEqual(ip.flags, 0) self.assertEqual(ip.dst, "10.0.0.%u" % asid) self.assertEqual(ip.tos, 0x1c) self.assertEqual(len(ip.options), 0) load[asid] += 1 except: self.logger.error(ppp("Unexpected or invalid packet:", p)) raise # This is just to roughly check that the balancing algorithm # is not completly biased. for asid in self.ass: if load[asid] < len(self.packets) / (len(self.ass) * 2): self.logger.error("ASS is not balanced: load[%d] = %d" % (asid, load[asid])) raise Exception("Load Balancer algorithm is biased")
def test_fif4(self): """ Fragments in fragments (4o4) """ # TODO this should be ideally in setUpClass, but then we hit a bug # with VppIpRoute incorrectly reporting it's present when it's not # so we need to manually remove the vpp config, thus we cannot have # it shared for multiple test cases self.tun_ip4 = "1.1.1.2" self.gre4 = VppGreInterface(self, self.pg0.local_ip4, self.tun_ip4) self.gre4.add_vpp_config() self.gre4.admin_up() self.gre4.config_ip4() self.route4 = VppIpRoute( self, self.tun_ip4, 32, [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index)]) self.route4.add_vpp_config() self.reset_packet_infos() for i in range(test_packet_count): info = self.create_packet_info(self.pg0, self.pg0) payload = self.info_to_payload(info) p = (IP(id=i, src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / UDP(sport=1234, dport=self.punt_port) / Raw(payload)) size = self.packet_sizes[(i // 2) % len(self.packet_sizes)] self.extend_packet(p, size, self.padding) info.data = p fragments = [ x for _, p in self._packet_infos.iteritems() for x in fragment_rfc791(p.data, 400) ] encapped_fragments = \ [Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.tun_ip4, dst=self.pg0.local_ip4) / GRE() / p for p in fragments] fragmented_encapped_fragments = \ [x for p in encapped_fragments for x in fragment_rfc791(p, 200)] self.pg0.add_stream(fragmented_encapped_fragments) self.pg_enable_capture(self.pg_interfaces) self.pg_start() self.pg0.assert_nothing_captured() packets = self.punt4_socket.wait_for_packets(len(self._packet_infos)) self.verify_capture(packets, IP) # TODO remove gre vpp config by hand until VppIpRoute gets fixed # so that it's query_vpp_config() works as it should self.gre4.remove_vpp_config()
def checkCapture(self, gre4, isv4): out = self.pg0.get_capture() # This check is edited because RA appears in output, maybe disable RA? # self.assertEqual(len(out), 0) self.assertLess(len(out), 20) out = self.pg1.get_capture() self.assertEqual(len(out), len(self.packets)) load = [0] * len(self.ass) self.info = None for p in out: try: asid = 0 gre = None if gre4: ip = p[IP] asid = int(ip.dst.split(".")[3]) self.assertEqual(ip.version, 4) self.assertEqual(ip.flags, 0) self.assertEqual(ip.src, "39.40.41.42") self.assertEqual(ip.dst, "10.0.0.%u" % asid) self.assertEqual(ip.proto, 47) self.assertEqual(len(ip.options), 0) self.assertGreaterEqual(ip.ttl, 64) gre = p[GRE] else: ip = p[IPv6] asid = ip.dst.split(":") asid = asid[len(asid) - 1] asid = 0 if asid == "" else int(asid) self.assertEqual(ip.version, 6) self.assertEqual(ip.tc, 0) self.assertEqual(ip.fl, 0) self.assertEqual(ip.src, "2004::1") self.assertEqual( socket.inet_pton(socket.AF_INET6, ip.dst), socket.inet_pton(socket.AF_INET6, "2002::%u" % asid)) self.assertEqual(ip.nh, 47) self.assertGreaterEqual(ip.hlim, 64) # self.assertEqual(len(ip.options), 0) gre = GRE(str(p[IPv6].payload)) self.checkInner(gre, isv4) load[asid] += 1 except: error("Unexpected or invalid packet:") p.show() raise # This is just to roughly check that the balancing algorithm # is not completly biased. for asid in self.ass: if load[asid] < len(self.packets) / (len(self.ass) * 2): self.log("ASS is not balanced: load[%d] = %d" % (asid, load[asid])) raise Exception("Load Balancer algorithm is biased")
def main(): args = TrafficScriptArg([ 'tx_dst_mac', 'rx_dst_mac', 'inner_src_ip', 'inner_dst_ip', 'outer_src_ip', 'outer_dst_ip' ]) tx_if = args.get_arg('tx_if') rx_if = args.get_arg('rx_if') tx_dst_mac = args.get_arg('tx_dst_mac') rx_dst_mac = args.get_arg('rx_dst_mac') inner_src_ip = args.get_arg('inner_src_ip') inner_dst_ip = args.get_arg('inner_dst_ip') outer_src_ip = args.get_arg('outer_src_ip') outer_dst_ip = args.get_arg('outer_dst_ip') rxq = RxQueue(rx_if) txq = TxQueue(tx_if) sent_packets = [] tx_pkt_raw = Ether(dst=tx_dst_mac) / \ IP(src=outer_src_ip, dst=outer_dst_ip) / \ GRE() / \ IP(src=inner_src_ip, dst=inner_dst_ip) / \ ICMP() sent_packets.append(tx_pkt_raw) txq.send(tx_pkt_raw) ether = rxq.recv(2) if ether is None: raise RuntimeError("ICMP echo Rx timeout") # Check RX headers if ether.dst != rx_dst_mac: raise RuntimeError( "Matching of received destination MAC unsuccessful.") logger.debug("Comparison of received destination MAC: OK.") if ether['IP'].src != inner_src_ip: raise RuntimeError( "Matching of received inner source IP unsuccessful.") logger.debug("Comparison of received outer source IP: OK.") if ether['IP'].dst != inner_dst_ip: raise RuntimeError( "Matching of received inner destination IP unsuccessful.") logger.debug("Comparison of received outer destination IP: OK.") if ether['IP'].proto != IP_PROTOS.icmp: raise RuntimeError("IP protocol is other than ICMP.") logger.debug("Comparison of received ICMP protocol: OK.") sys.exit(0)
def create_tunnel_stream_6o6(self, src_if, tunnel_src, tunnel_dst, src_ip, dst_ip): pkts = [] for i in range(0, 257): info = self.create_packet_info(src_if, src_if) payload = self.info_to_payload(info) p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) / IPv6(src=tunnel_src, dst=tunnel_dst) / GRE() / IPv6(src=src_ip, dst=dst_ip) / UDP(sport=1234, dport=1234) / Raw(payload)) info.data = p.copy() pkts.append(p) return pkts
def create_tunnel_stream_l2o4(self, src_if, tunnel_src, tunnel_dst): pkts = [] for i in range(0, 257): info = self.create_packet_info(src_if, src_if) payload = self.info_to_payload(info) p = ( Ether(dst=src_if.local_mac, src=src_if.remote_mac) / IP(src=tunnel_src, dst=tunnel_dst) / GRE() / Ether(dst=RandMAC('*:*:*:*:*:*'), src=RandMAC('*:*:*:*:*:*')) / IP(src=str(RandIP()), dst=str(RandIP())) / UDP(sport=1234, dport=1234) / Raw(payload)) info.data = p.copy() pkts.append(p) return pkts
def gen_encrypt_pkts(self, sa, sw_intf, src, dst, count=1, payload_size=100): return [ Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) / sa.encrypt( IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / GRE() / IP(src=self.pg1.local_ip4, dst=self.pg1.remote_ip4) / UDP(sport=1144, dport=2233) / Raw('X' * payload_size)) for i in range(count) ]
def test_fif6(self): """ Fragments in fragments (6o6) """ # TODO this should be ideally in setUpClass, but then we hit a bug # with VppIpRoute incorrectly reporting it's present when it's not # so we need to manually remove the vpp config, thus we cannot have # it shared for multiple test cases self.tun_ip6 = "1002::1" self.gre6 = VppGreInterface(self, self.src_if.local_ip6, self.tun_ip6) self.gre6.add_vpp_config() self.gre6.admin_up() self.gre6.config_ip6() self.vapi.ip_reassembly_enable_disable( sw_if_index=self.gre6.sw_if_index, enable_ip6=True) self.route6 = VppIpRoute(self, self.tun_ip6, 128, [ VppRoutePath(self.src_if.remote_ip6, self.src_if.sw_if_index, proto=DpoProto.DPO_PROTO_IP6) ], is_ip6=1) self.route6.add_vpp_config() self.reset_packet_infos() for i in range(test_packet_count): info = self.create_packet_info(self.src_if, self.dst_if) payload = self.info_to_payload(info) # Ethernet header here is only for size calculation, thus it # doesn't matter how it's initialized. This is to ensure that # reassembled packet is not > 9000 bytes, so that it's not dropped p = (Ether() / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) / UDP(sport=1234, dport=5678) / Raw(payload)) size = self.packet_sizes[(i // 2) % len(self.packet_sizes)] self.extend_packet(p, size, self.padding) info.data = p[IPv6] # use only IPv6 part, without ethernet header fragments = [ x for _, i in six.iteritems(self._packet_infos) for x in fragment_rfc8200(i.data, i.index, 400) ] encapped_fragments = \ [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) / IPv6(src=self.tun_ip6, dst=self.src_if.local_ip6) / GRE() / p for p in fragments] fragmented_encapped_fragments = \ [x for p in encapped_fragments for x in ( fragment_rfc8200( p, 2 * len(self._packet_infos) + p[IPv6ExtHdrFragment].id, 200) if IPv6ExtHdrFragment in p else [p] ) ] self.src_if.add_stream(fragmented_encapped_fragments) self.pg_enable_capture(self.pg_interfaces) self.pg_start() self.src_if.assert_nothing_captured() packets = self.dst_if.get_capture(len(self._packet_infos)) self.verify_capture(packets, IPv6) # TODO remove gre vpp config by hand until VppIpRoute gets fixed # so that it's query_vpp_config() works as it should self.gre6.remove_vpp_config()
def test_fif4(self): """ Fragments in fragments (4o4) """ # TODO this should be ideally in setUpClass, but then we hit a bug # with VppIpRoute incorrectly reporting it's present when it's not # so we need to manually remove the vpp config, thus we cannot have # it shared for multiple test cases self.tun_ip4 = "1.1.1.2" self.gre4 = VppGreInterface(self, self.src_if.local_ip4, self.tun_ip4) self.gre4.add_vpp_config() self.gre4.admin_up() self.gre4.config_ip4() self.vapi.ip_reassembly_enable_disable( sw_if_index=self.gre4.sw_if_index, enable_ip4=True) self.route4 = VppIpRoute( self, self.tun_ip4, 32, [VppRoutePath(self.src_if.remote_ip4, self.src_if.sw_if_index)]) self.route4.add_vpp_config() self.reset_packet_infos() for i in range(test_packet_count): info = self.create_packet_info(self.src_if, self.dst_if) payload = self.info_to_payload(info) # Ethernet header here is only for size calculation, thus it # doesn't matter how it's initialized. This is to ensure that # reassembled packet is not > 9000 bytes, so that it's not dropped p = (Ether() / IP( id=i, src=self.src_if.remote_ip4, dst=self.dst_if.remote_ip4) / UDP(sport=1234, dport=5678) / Raw(payload)) size = self.packet_sizes[(i // 2) % len(self.packet_sizes)] self.extend_packet(p, size, self.padding) info.data = p[IP] # use only IP part, without ethernet header fragments = [ x for _, p in six.iteritems(self._packet_infos) for x in fragment_rfc791(p.data, 400) ] encapped_fragments = \ [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) / IP(src=self.tun_ip4, dst=self.src_if.local_ip4) / GRE() / p for p in fragments] fragmented_encapped_fragments = \ [x for p in encapped_fragments for x in fragment_rfc791(p, 200)] self.src_if.add_stream(fragmented_encapped_fragments) self.pg_enable_capture(self.pg_interfaces) self.pg_start() self.src_if.assert_nothing_captured() packets = self.dst_if.get_capture(len(self._packet_infos)) self.verify_capture(packets, IP) # TODO remove gre vpp config by hand until VppIpRoute gets fixed # so that it's query_vpp_config() works as it should self.gre4.remove_vpp_config() self.logger.debug(self.vapi.ppcli("show interface"))
def test_ip_mcast_gre(self): """ IP Multicast Replication over GRE""" gre_if_1 = VppGreInterface(self, self.pg1.local_ip4, self.pg1.remote_ip4).add_vpp_config() gre_if_2 = VppGreInterface(self, self.pg2.local_ip4, self.pg2.remote_ip4).add_vpp_config() gre_if_3 = VppGreInterface(self, self.pg3.local_ip4, self.pg3.remote_ip4).add_vpp_config() gre_if_1.admin_up() gre_if_1.config_ip4() gre_if_2.admin_up() gre_if_2.config_ip4() gre_if_3.admin_up() gre_if_3.config_ip4() # # An (S,G). # one accepting interface, pg0, 2 forwarding interfaces # route_1_1_1_1_232_1_1_1 = VppIpMRoute( self, "1.1.1.1", "232.2.2.2", 64, MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE, [ VppMRoutePath(gre_if_1.sw_if_index, MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT), VppMRoutePath(gre_if_2.sw_if_index, MRouteItfFlags.MFIB_ITF_FLAG_FORWARD), VppMRoutePath(gre_if_3.sw_if_index, MRouteItfFlags.MFIB_ITF_FLAG_FORWARD) ]) route_1_1_1_1_232_1_1_1.add_vpp_config() # # a stream that matches the route for (1.1.1.1,232.2.2.2) # small packets # tx = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IP(src=self.pg1.remote_ip4, dst=self.pg1.local_ip4) / GRE() / IP(src="1.1.1.1", dst="232.2.2.2") / UDP(sport=1234, dport=1234) / Raw('\a5' * 64)) * 63 self.vapi.cli("clear trace") self.pg1.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() # We expect replications on Pg2 & 3 # check the encap headers are as expected based on the egress tunnel rxs = self.pg2.get_capture(len(tx)) for rx in rxs: self.assertEqual(rx[IP].src, gre_if_2.t_src) self.assertEqual(rx[IP].dst, gre_if_2.t_dst) self.assert_packet_checksums_valid(rx) rxs = self.pg3.get_capture(len(tx)) for rx in rxs: self.assertEqual(rx[IP].src, gre_if_3.t_src) self.assertEqual(rx[IP].dst, gre_if_3.t_dst) self.assert_packet_checksums_valid(rx)
class scapy(object): SCAPY_LAYERS = { 'ether': Ether(dst="ff:ff:ff:ff:ff:ff"), 'vlan': Dot1Q(), 'etag': None, '1588': Ether(type=0x88f7), 'arp': ARP(), 'ipv4': IP(), 'ipv4ihl': IP(ihl=10), 'ipv4_ext': IP(frag=5), 'ipv6': IPv6(src="::1"), 'ipv6_ext': IPv6(src="::1", nh=43) / IPv6ExtHdrRouting(), 'ipv6_ext2': IPv6() / IPv6ExtHdrRouting(), 'udp': UDP(), 'tcp': TCP(), 'sctp': SCTP(), 'icmp': ICMP(), 'gre': GRE(), 'raw': Raw(), 'vxlan': Vxlan(), 'inner_mac': Ether(), 'inner_vlan': Dot1Q(), 'inner_ipv4': IP(), 'inner_ipv4_ext': IP(), 'inner_ipv6': IPv6(src="::1"), 'inner_ipv6_ext': IPv6(src="::1"), 'inner_tcp': TCP(), 'inner_udp': UDP(), 'inner_sctp': SCTP(), 'inner_icmp': ICMP(), 'lldp': None, 'ip_frag': IP(frag=5), 'ipv6_frag': IPv6(src="::1") / IPv6ExtHdrFragment(), 'ip_in_ip': IP() / IP(), 'ip_in_ip_frag': IP() / IP(frag=5), 'ipv6_in_ip': IP() / IPv6(src="::1"), 'ipv6_frag_in_ip': IP() / IPv6(src="::1", nh=44) / IPv6ExtHdrFragment(), 'nvgre': None, 'geneve': "Not Implement", } def __init__(self): self.pkt = None pass def assign_pkt(self, pkt): self.pkt = pkt def add_layers(self, layers): self.pkt = None for layer in layers: if self.pkt is not None: self.pkt = self.pkt / self.SCAPY_LAYERS[layer] else: self.pkt = self.SCAPY_LAYERS[layer] def ether(self, pkt_layer, dst="ff:ff:ff:ff:ff:ff", src="00:00:20:00:00:00", type=None): if pkt_layer.name != "Ethernet": return pkt_layer.dst = dst pkt_layer.src = src if type is not None: pkt_layer.type = type def vlan(self, pkt_layer, vlan, prio=0, type=None): if pkt_layer.name != "802.1Q": return pkt_layer.vlan = int(vlan) pkt_layer.prio = prio if type is not None: pkt_layer.type = type def strip_vlan(self, element): value = None if self.pkt.haslayer('Dot1Q') is 0: return None if element == 'vlan': value = int(str(self.pkt[Dot1Q].vlan)) return value def etag(self, pkt_layer, ECIDbase=0, prio=0, type=None): if pkt_layer.name != "802.1BR": return pkt_layer.ECIDbase = int(ECIDbase) pkt_layer.prio = prio if type is not None: pkt_layer.type = type def strip_etag(self, element): value = None if self.pkt.haslayer('Dot1BR') is 0: return None if element == 'ECIDbase': value = int(str(self.pkt[Dot1BR].ECIDbase)) return value def strip_layer2(self, element): value = None layer = self.pkt.getlayer(0) if layer is None: return None if element == 'src': value = layer.src elif element == 'dst': value = layer.dst elif element == 'type': value = layer.type return value def strip_layer3(self, element): value = None layer = self.pkt.getlayer(1) if layer is None: return None if element == 'src': value = layer.src elif element == 'dst': value = layer.dst else: value = layer.getfieldval(element) return value def strip_layer4(self, element): value = None layer = self.pkt.getlayer(2) if layer is None: return None if element == 'src': value = layer.sport elif element == 'dst': value = layer.dport else: value = layer.getfieldval(element) return value def ipv4(self, pkt_layer, frag=0, src="127.0.0.1", proto=None, tos=0, dst="127.0.0.1", chksum=None, len=None, version=4, flags=None, ihl=None, ttl=64, id=1, options=None): pkt_layer.frag = frag pkt_layer.src = src if proto is not None: pkt_layer.proto = proto pkt_layer.tos = tos pkt_layer.dst = dst if chksum is not None: pkt_layer.chksum = chksum if len is not None: pkt_layer.len = len pkt_layer.version = version if flags is not None: pkt_layer.flags = flags if ihl is not None: pkt_layer.ihl = ihl pkt_layer.ttl = ttl pkt_layer.id = id if options is not None: pkt_layer.options = options def ipv6(self, pkt_layer, version=6, tc=0, fl=0, plen=0, nh=0, hlim=64, src="::1", dst="::1"): """ Configure IPv6 protocal. """ pkt_layer.version = version pkt_layer.tc = tc pkt_layer.fl = fl if plen: pkt_layer.plen = plen if nh: pkt_layer.nh = nh pkt_layer.src = src pkt_layer.dst = dst def tcp(self, pkt_layer, src=53, dst=53, flags=None, len=None, chksum=None): pkt_layer.sport = src pkt_layer.dport = dst if flags is not None: pkt_layer.flags = flags if len is not None: pkt_layer.len = len if chksum is not None: pkt_layer.chksum = chksum def udp(self, pkt_layer, src=53, dst=53, len=None, chksum=None): pkt_layer.sport = src pkt_layer.dport = dst if len is not None: pkt_layer.len = len if chksum is not None: pkt_layer.chksum = chksum def sctp(self, pkt_layer, src=53, dst=53, tag=None, len=None, chksum=None): pkt_layer.sport = src pkt_layer.dport = dst if tag is not None: pkt_layer.tag = tag if len is not None: pkt_layer.len = len if chksum is not None: pkt_layer.chksum = chksum def raw(self, pkt_layer, payload=None): if payload is not None: pkt_layer.load = '' for hex1, hex2 in payload: pkt_layer.load += struct.pack("=B", int('%s%s' % (hex1, hex2), 16)) def gre(self, pkt_layer, proto=None): if proto is not None: pkt_layer.proto = proto def vxlan(self, pkt_layer, vni=0): pkt_layer.vni = vni def read_pcap(self, file): pcap_pkts = [] try: pcap_pkts = rdpcap(file) except: pass return pcap_pkts def write_pcap(self, file): try: wrpcap(file, self.pkt) except: pass def send_pcap_pkt(self, crb=None, file='', intf='', count=1): if intf == '' or file == '' or crb is None: print "Invalid option for send packet by scapy" return content = 'pkts=rdpcap(\"%s\");sendp(pkts, iface=\"%s\", count=\"%s\" );exit()' % ( file, intf, count) cmd_file = '/tmp/scapy_%s.cmd' % intf crb.create_file(content, cmd_file) crb.send_expect("scapy -c scapy_%s.cmd &" % intf, "# ") def print_summary(self): print "Send out pkt %s" % self.pkt.summary() def send_pkt(self, intf='', count=1): self.print_summary() if intf != '': # wait few seconds for link ready countdown = 600 while countdown: link_st = subprocess.check_output("ip link show %s" % intf, stderr=subprocess.STDOUT, shell=True) if "LOWER_UP" in link_st: break else: time.sleep(0.01) countdown -= 1 continue # fix fortville can't receive packets with 00:00:00:00:00:00 if self.pkt.getlayer(0).src == "00:00:00:00:00:00": self.pkt.getlayer(0).src = get_if_hwaddr(intf) sendp(self.pkt, iface=intf, count=count)
def test_fif6(self): """ Fragments in fragments (6o6) """ # TODO this should be ideally in setUpClass, but then we hit a bug # with VppIpRoute incorrectly reporting it's present when it's not # so we need to manually remove the vpp config, thus we cannot have # it shared for multiple test cases self.tun_ip6 = "1002::1" self.gre6 = VppGre6Interface(self, self.pg0.local_ip6, self.tun_ip6) self.gre6.add_vpp_config() self.gre6.admin_up() self.gre6.config_ip6() self.route6 = VppIpRoute(self, self.tun_ip6, 128, [ VppRoutePath(self.pg0.remote_ip6, self.pg0.sw_if_index, proto=DpoProto.DPO_PROTO_IP6) ], is_ip6=1) self.route6.add_vpp_config() self.reset_packet_infos() for i in range(test_packet_count): info = self.create_packet_info(self.pg0, self.pg0) payload = self.info_to_payload(info) p = (IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) / UDP(sport=1234, dport=self.punt_port) / Raw(payload)) size = self.packet_sizes[(i // 2) % len(self.packet_sizes)] self.extend_packet(p, size, self.padding) info.data = p fragments = [ x for _, i in self._packet_infos.iteritems() for x in fragment_rfc8200(i.data, i.index, 400) ] encapped_fragments = \ [Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IPv6(src=self.tun_ip6, dst=self.pg0.local_ip6) / GRE() / p for p in fragments] fragmented_encapped_fragments = \ [x for p in encapped_fragments for x in ( fragment_rfc8200( p, 2 * len(self._packet_infos) + p[IPv6ExtHdrFragment].id, 200) if IPv6ExtHdrFragment in p else [p] ) ] self.pg0.add_stream(fragmented_encapped_fragments) self.pg_enable_capture(self.pg_interfaces) self.pg_start() self.pg0.assert_nothing_captured() packets = self.punt6_socket.wait_for_packets(len(self._packet_infos)) self.verify_capture(packets, IPv6) # TODO remove gre vpp config by hand until VppIpRoute gets fixed # so that it's query_vpp_config() works as it should self.gre6.remove_vpp_config()
def checkCapture(self, encap, isv4): self.pg0.assert_nothing_captured() out = self.pg1.get_capture(len(self.packets)) load = [0] * len(self.ass) self.info = None for p in out: try: asid = 0 gre = None if encap == "gre4": ip = p[IP] asid = int(ip.dst.split(".")[3]) self.assertEqual(ip.version, 4) self.assertEqual(ip.flags, 0) self.assertEqual(ip.src, "39.40.41.42") self.assertEqual(ip.dst, "10.0.0.%u" % asid) self.assertEqual(ip.proto, 47) self.assertEqual(len(ip.options), 0) gre = p[GRE] self.checkInner(gre, isv4) elif encap == "gre6": ip = p[IPv6] asid = ip.dst.split(":") asid = asid[len(asid) - 1] asid = 0 if asid == "" else int(asid) self.assertEqual(ip.version, 6) self.assertEqual(ip.tc, 0) self.assertEqual(ip.fl, 0) self.assertEqual(ip.src, "2004::1") self.assertEqual( socket.inet_pton(socket.AF_INET6, ip.dst), socket.inet_pton(socket.AF_INET6, "2002::%u" % asid), ) self.assertEqual(ip.nh, 47) # self.assertEqual(len(ip.options), 0) gre = GRE(scapy.compat.raw(p[IPv6].payload)) self.checkInner(gre, isv4) elif encap == "l3dsr": ip = p[IP] asid = int(ip.dst.split(".")[3]) self.assertEqual(ip.version, 4) self.assertEqual(ip.flags, 0) self.assertEqual(ip.dst, "10.0.0.%u" % asid) self.assertEqual(ip.tos, 0x1C) self.assertEqual(len(ip.options), 0) self.assert_ip_checksum_valid(p) if ip.proto == IP_PROTOS.tcp: self.assert_tcp_checksum_valid(p) elif ip.proto == IP_PROTOS.udp: self.assert_udp_checksum_valid(p) elif encap == "nat4": ip = p[IP] asid = int(ip.dst.split(".")[3]) self.assertEqual(ip.version, 4) self.assertEqual(ip.flags, 0) self.assertEqual(ip.dst, "10.0.0.%u" % asid) self.assertEqual(ip.proto, 17) self.assertEqual(len(ip.options), 0) udp = p[UDP] self.assertEqual(udp.dport, 3307) elif encap == "nat6": ip = p[IPv6] asid = ip.dst.split(":") asid = asid[len(asid) - 1] asid = 0 if asid == "" else int(asid) self.assertEqual(ip.version, 6) self.assertEqual(ip.tc, 0) self.assertEqual(ip.fl, 0) self.assertEqual( socket.inet_pton(socket.AF_INET6, ip.dst), socket.inet_pton(socket.AF_INET6, "2002::%u" % asid), ) self.assertEqual(ip.nh, 17) self.assertGreaterEqual(ip.hlim, 63) udp = UDP(scapy.compat.raw(p[IPv6].payload)) self.assertEqual(udp.dport, 3307) load[asid] += 1 except: self.logger.error(ppp("Unexpected or invalid packet:", p)) raise # This is just to roughly check that the balancing algorithm # is not completely biased. for asid in self.ass: if load[asid] < int(len(self.packets) / (len(self.ass) * 2)): self.logger.error( "ASS is not balanced: load[%d] = %d" % (asid, load[asid]) ) raise Exception("Load Balancer algorithm is biased")
def test_static(self): """1:1 NAT66 test""" flags = self.config_flags.NAT_IS_INSIDE self.vapi.nat66_add_del_interface(is_add=1, flags=flags, sw_if_index=self.pg0.sw_if_index) self.vapi.nat66_add_del_interface(is_add=1, sw_if_index=self.pg1.sw_if_index) self.vapi.nat66_add_del_static_mapping( local_ip_address=self.pg0.remote_ip6, external_ip_address=self.nat_addr, is_add=1, ) # in2out pkts = [] p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) / TCP()) pkts.append(p) p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) / UDP()) pkts.append(p) p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) / ICMPv6EchoRequest()) pkts.append(p) p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) / GRE() / IP() / TCP()) pkts.append(p) self.pg0.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() capture = self.pg1.get_capture(len(pkts)) for packet in capture: try: self.assertEqual(packet[IPv6].src, self.nat_addr) self.assertEqual(packet[IPv6].dst, self.pg1.remote_ip6) self.assert_packet_checksums_valid(packet) except: self.logger.error(ppp("Unexpected or invalid packet:", packet)) raise # out2in pkts = [] p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) / TCP()) pkts.append(p) p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) / UDP()) pkts.append(p) p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) / ICMPv6EchoReply()) pkts.append(p) p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) / GRE() / IP() / TCP()) pkts.append(p) self.pg1.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() capture = self.pg0.get_capture(len(pkts)) for packet in capture: try: self.assertEqual(packet[IPv6].src, self.pg1.remote_ip6) self.assertEqual(packet[IPv6].dst, self.pg0.remote_ip6) self.assert_packet_checksums_valid(packet) except: self.logger.error(ppp("Unexpected or invalid packet:", packet)) raise sm = self.vapi.nat66_static_mapping_dump() self.assertEqual(len(sm), 1) self.assertEqual(sm[0].total_pkts, 8)
def main(): args = TrafficScriptArg([ 'tx_dst_mac', 'tx_src_mac', 'tx_outer_dst_ip', 'tx_outer_src_ip', 'tx_inner_dst_ip', 'tx_inner_src_ip', 'rx_dst_mac', 'rx_src_mac', 'rx_outer_dst_ip', 'rx_outer_src_ip' ]) tx_if = args.get_arg('tx_if') rx_if = args.get_arg('rx_if') tx_dst_mac = args.get_arg('tx_dst_mac') tx_src_mac = args.get_arg('tx_src_mac') tx_outer_dst_ip = args.get_arg('tx_outer_dst_ip') tx_outer_src_ip = args.get_arg('tx_outer_src_ip') tx_inner_dst_ip = args.get_arg('tx_inner_dst_ip') tx_inner_src_ip = args.get_arg('tx_inner_src_ip') rx_dst_mac = args.get_arg('rx_dst_mac') rx_src_mac = args.get_arg('rx_src_mac') rx_outer_dst_ip = args.get_arg('rx_outer_dst_ip') rx_outer_src_ip = args.get_arg('rx_outer_src_ip') udp_src = 1234 udp_dst = 2345 udp_payload = 'udp_payload' rxq = RxQueue(rx_if) txq = TxQueue(tx_if) sent_packets = [] tx_pkt_raw = Ether(dst=tx_dst_mac, src=tx_src_mac) / \ IP(src=tx_outer_src_ip, dst=tx_outer_dst_ip) / \ GRE() / \ IP(src=tx_inner_src_ip, dst=tx_inner_dst_ip) / \ UDP(dport=udp_dst, sport=udp_src) / \ udp_payload sent_packets.append(tx_pkt_raw) txq.send(tx_pkt_raw) ether = rxq.recv(2, ignore=sent_packets) if ether is None: raise RuntimeError("ICMP echo Rx timeout") # Check RX headers if ether.dst != rx_dst_mac: raise RuntimeError( "Matching of received destination MAC unsuccessful.") logger.debug("Comparison of received destination MAC: OK.") if ether.src != rx_src_mac: raise RuntimeError("Matching of received source MAC unsuccessful.") logger.debug("Comparison of received source MAC: OK.") if ether['IP'].src != rx_outer_src_ip: raise RuntimeError( "Matching of received outer source IP unsuccessful.") logger.debug("Comparison of received outer source IP: OK.") if ether['IP'].dst != rx_outer_dst_ip: raise RuntimeError( "Matching of received outer destination IP unsuccessful.") logger.debug("Comparison of received outer destination IP: OK.") if ether['IP'].proto != IP_PROTOS.gre: raise RuntimeError("IP protocol is not GRE.") logger.debug("Comparison of received GRE protocol: OK.") if ether['IP']['GRE']['IP'].src != tx_inner_src_ip: raise RuntimeError( "Matching of received inner source IP unsuccessful.") logger.debug("Comparison of received inner source IP: OK.") if ether['IP']['GRE']['IP'].dst != tx_inner_dst_ip: raise RuntimeError( "Matching of received inner destination IP unsuccessful.") logger.debug("Comparison of received inner destination IP: OK.") # check udp udp = ether['IP']['GRE']['IP']['UDP'] if udp.dport != udp_dst: raise RuntimeError("UDP dport error {} != {}.".format( udp.dport, udp_dst)) print "UDP dport: OK." if udp.sport != udp_src: raise RuntimeError("UDP sport error {} != {}.".format( udp.sport, udp_src)) print "UDP sport: OK." if str(udp.payload) != udp_payload: raise RuntimeError("UDP payload check unsuccessful {} != {}.".format( udp.payload, udp_payload)) print "UDP payload: OK." sys.exit(0)