def __send_encrypted_ack(self): ack = AckNotificationPacket() conf.L3socket = L3RawSocket ack.setfieldval( 'CID', string_to_ascii(SessionInstance.get_instance().connection_id)) next_packet_number_int = PacketNumberInstance.get_instance( ).get_next_packet_number() next_packet_number_byte = int(next_packet_number_int).to_bytes( 8, byteorder='little') next_packet_number_nonce = int(next_packet_number_int).to_bytes( 2, byteorder='big') # print("Sending encrypted ack for packet number {}".format(next_packet_number_int)) ack.setfieldval("Packet Number", next_packet_number_int) highest_received = PacketNumberInstance.get_instance( ).get_highest_received_packet_number() # print("Higheste {}".format(highest_received)) highest_received_packet_number = format(int(highest_received, 16), 'x') ack_body = "40" ack_body += str(highest_received_packet_number).zfill(2) ack_body += "0062" ack_body += str(highest_received_packet_number).zfill(2) ack_body += "00" # not sure yet if we can remove this? # if SessionInstance.get_instance().nr_ack_send == 0: # ack_body += str(highest_received_packet_number).zfill(2) # ack_body += "00" # ack_body += "01" keys = SessionInstance.get_instance().keys if keys: request = { 'mode': 'encryption', 'input': ack_body, 'key': keys['key1'].hex(), # For encryption, we use my key 'additionalData': "18" + SessionInstance.get_instance().connection_id + next_packet_number_byte.hex() [:4], # Fixed public flags 18 || fixed connection Id || packet number 'nonce': keys['iv1'].hex() + next_packet_number_nonce.hex().ljust(16, '0') } else: request = { 'mode': 'encryption', 'input': ack_body, 'key': "d309c2ddf54fdb0c34e9ae8f2aa5d0a4", # Just use a fixed, invalid key 'additionalData': "18" + SessionInstance.get_instance().connection_id + next_packet_number_byte.hex()[:4], # Fixed public flags 18 || fixed connection Id || packet number 'nonce': "7a40a2e70600000000000000" # Just use a fixed, invalid nonce. } # print("Ack request for encryption {}".format(request)) ciphertext = CryptoConnectionManager.send_message( ConnectionEndpoint.CRYPTO_ORACLE, json.dumps(request).encode('utf-8'), True) ciphertext = ciphertext['data'] # print("Ciphertext in ack {}".format(ciphertext)) ack.setfieldval("Message Authentication Hash", string_to_ascii(ciphertext[:24])) SessionInstance.get_instance().nr_ack_send += 1 p = IP(dst=SessionInstance.get_instance().destination_ip) / UDP( dport=6121, sport=61250) / ack / Raw(load=string_to_ascii(ciphertext[24:])) send(p)
def inject(self, vicmac, rtrmac, dstmac, vicip, svrip, vicport, svrport, acknum, seqnum, injection, TSVal, TSecr): """Send the injection using Scapy This method is where the actual packet is created for sending Things such as payload and associated flags are genned here FIN/ACK flag is sent to the victim with this method """ print('lib.injector.inject() called !!') global npackets npackets += 1 sys.stdout.write(Bcolors.OKBLUE + '[*] Injecting Packet to victim ' + Bcolors.WARNING + vicmac + Bcolors.OKBLUE + ' (TOTAL: ' + str(npackets) + ' injected packets)\r' + Bcolors.ENDC) sys.stdout.flush() ## Injection using Monitor Mode if self.args.inj == 'mon': hdr = Headers() headers = hdr.default(injection) ## WEP/WPA if self.args.wep or self.args.wpa: packet = self.rTap\ /Dot11( FCfield = 'from-DS', addr1 = vicmac, addr2 = rtrmac, addr3 = dstmac, ### DEBUG # subtype = 8L, subtype = 8, type = 2 )\ /Dot11QoS()\ /LLC()\ /SNAP()\ /IP( dst = vicip, src = svrip )\ /TCP( flags = 'FA', sport = int(svrport), dport = int(vicport), seq = int(seqnum), ack = int(acknum) )\ /Raw( load = headers + injection ) ## Open else: packet = RadioTap()\ /Dot11( FCfield = 'from-DS', addr1 = vicmac, addr2 = rtrmac, addr3 = dstmac )\ /LLC()\ /SNAP()\ /IP( dst = vicip, src = svrip )\ /TCP( flags = 'FA', sport = int(svrport), dport = int(vicport), seq = int(seqnum), ack = int(acknum) )\ /Raw( load = headers + injection ) if TSVal is not None and TSecr is not None: packet[TCP].options = [ ('NOP', None), ('NOP', None), ('Timestamp', ((round(time.time()), TSVal))) ] else: packet[TCP].options = [ ('NOP', None), ('NOP', None), ('Timestamp', ((round(time.time()), 0))) ] ## WPA Injection if self.args.wpa is not None: if self.shake.encDict.get(vicmac) == 'ccmp': ### Why are we incrementing here? Been done before in wpaEncrypt(), verify this. try: self.shake.PN[5] += 1 except: self.shake.PN[4] += 1 try: packet = wpaEncrypt(self.shake.tgtInfo.get(vicmac)[1], self.shake.origPkt, packet, self.shake.PN, True) except: sys.stdout.write(Bcolors.FAIL + '\n[!] pyDot11 did not work\n[!] Injection failed\n ' + Bcolors.ENDC) sys.stdout.flush() else: sys.stdout.write(Bcolors.FAIL + '\n[!] airpwn-ng cannot inject TKIP natively\n[!] Injection failed\n ' + Bcolors.ENDC) sys.stdout.flush() #packet = wpaEncrypt(self.shake.tgtInfo.get(vicmac)[0], #self.shake.origPkt, #packet, #self.shake.PN, #True) if self.args.v is False: sendp(packet, iface = self.interface, verbose = 0) else: sendp(packet, iface = self.interface, verbose = 1) if self.args.pcap is True: wrpcap('outbound.pcap', packet) ## WEP Injection elif self.args.wep is not None: try: packet = wepEncrypt(packet, self.args.wep) except: sys.stdout.write(Bcolors.FAIL + '\n[!] pyDot11 did not work\n[!] Injection failed\n ' + Bcolors.ENDC) sys.stdout.flush() if self.args.v is False: sendp(packet, iface = self.interface, verbose = 0) else: sendp(packet, iface = self.interface, verbose = 1) if self.args.pcap is True: wrpcap('outbound.pcap', packet) ## Open WiFi Injection else: if self.args.v is False: sendp(packet, iface = self.interface, verbose = 0) else: sendp(packet, iface = self.interface, verbose = 1) if self.args.pcap is True: wrpcap('outbound.pcap', packet) ### Single packet exit point ### Used for BeEF hook examples and such if self.args.single is True: sys.stdout.write(Bcolors.OKBLUE + '[*] Injecting Packet to victim ' + Bcolors.WARNING + vicmac + Bcolors.OKBLUE + ' (TOTAL: ' + str(npackets) + ' injected packets)\r' + Bcolors.ENDC) sys.exit(0) ## Injection using Managed Mode else: hdr = Headers() headers = hdr.default(injection) packet = Ether(\ src = self.getHwAddr(self.interface),\ dst = vicmac\ )\ /IP( dst = vicip, src = svrip )\ /TCP( flags = 'FA', sport = int(svrport), dport = int(vicport), seq = int(seqnum), ack = int(acknum) )\ /Raw( load = headers + injection ) if TSVal is not None: packet[TCP].options = [\ ('NOP', None),\ ('NOP', None),\ ('Timestamp', ((round(time.time()), TSVal)))\ ] else: packet[TCP].options = [\ ('NOP', None),\ ('NOP', None),\ ('Timestamp', ((round(time.time()), 0)))\ ] if self.args.v is False: sendp(packet, iface = self.interface, verbose = 0) else: sendp(packet, iface = self.interface, verbose = 1) if self.args.pcap is True: wrpcap('outbound.pcap', packet)
def client_mode(options): """"Implements the niping client running mode :param options: option set from the command line :type options: Values """ times = [] p = Raw("EYECATCHER" + "\x00" * (options.buffer_size - 10)) try: # Establish the connection conn = SAPRoutedStreamSocket.get_nisocket(options.host, options.port, options.route_string) logging.info("") logging.info(datetime.today().ctime()) logging.info("connect to server o.k.") # Send the messages for i in range(options.loops): # Send the packet and grab the response start_time = datetime.now() r = conn.sr(p) end_time = datetime.now() # Check the response if str(r.payload) != str(p): logging.info("[-] Response on message {} differs".format(i)) # Calculate and record the elapsed time times.append(end_time - start_time) # Close the connection properly conn.send(Raw()) conn.close() except SocketError: logging.error("[*] Connection error") except KeyboardInterrupt: logging.error("[*] Cancelled by the user") if times: logging.info("") logging.info(datetime.today().ctime()) logging.info("send and receive {} messages (len {})".format( len(times), options.buffer_size)) # Calculate the stats times = [x.total_seconds() * 1000 for x in times] times_min = min(times) times_max = max(times) times_avg = float(sum(times)) / max(len(times), 1) times_tr = float(options.buffer_size * len(times)) / float(sum(times)) times2 = [x for x in times if x not in [times_min, times_max]] times2_avg = float(sum(times2)) / max(len(times2), 1) times2_tr = float(options.buffer_size * len(times2)) / float( sum(times2)) # Print the stats logging.info("") logging.info("------- times -----") logging.info("avg {:8.3f} ms".format(times_avg)) logging.info("max {:8.3f} ms".format(times_max)) logging.info("min {:8.3f} ms".format(times_min)) logging.info("tr {:8.3f} kB/s".format(times_tr)) logging.info("excluding max and min:") logging.info("av2 {:8.3f} ms".format(times2_avg)) logging.info("tr2 {:8.3f} kB/s".format(times2_tr)) logging.info("")
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.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 self._packet_infos.iteritems() 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)
def test_abf6(self): """ IPv6 ACL Based Forwarding """ # # Simple test for matching IPv6 packets # # # Rule 1 # rule_1 = ({'is_permit': 1, 'is_ipv6': 1, 'proto': 17, 'srcport_or_icmptype_first': 1234, 'srcport_or_icmptype_last': 1234, 'src_ip_prefix_len': 128, 'src_ip_addr': inet_pton(AF_INET6, "2001::2"), 'dstport_or_icmpcode_first': 1234, 'dstport_or_icmpcode_last': 1234, 'dst_ip_prefix_len': 128, 'dst_ip_addr': inet_pton(AF_INET6, "2001::1")}) acl_1 = self.vapi.acl_add_replace(acl_index=4294967295, r=[rule_1]) # # ABF policy for ACL 1 - path via interface 1 # abf_1 = VppAbfPolicy(self, 10, acl_1, [VppRoutePath("3001::1", 0xffffffff, proto=DpoProto.DPO_PROTO_IP6)]) abf_1.add_vpp_config() attach_1 = VppAbfAttach(self, 10, self.pg0.sw_if_index, 45, is_ipv6=True) attach_1.add_vpp_config() # # a packet matching the rule # p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IPv6(src="2001::2", dst="2001::1") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) # # packets are dropped because there is no route to the policy's # next hop # self.send_and_assert_no_replies(self.pg1, p * 65, "no route") # # add a route resolving the next-hop # route = VppIpRoute(self, "3001::1", 32, [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index, proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) route.add_vpp_config() # # now expect packets forwarded. # self.send_and_expect(self.pg0, p * 65, self.pg1)
def create_stream(self, src_if, packet_sizes, traffic_type=0, ipv6=0, proto=-1, ports=0, fragments=False, pkt_raw=True, etype=-1): """ Create input packet stream for defined interface using hosts or deleted_hosts list. :param object src_if: Interface to create packet stream for. :param list packet_sizes: List of required packet sizes. :param traffic_type: 1: ICMP packet, 2: IPv6 with EH, 0: otherwise. :return: Stream of packets. """ pkts = [] if self.flows.__contains__(src_if): src_hosts = self.hosts_by_pg_idx[src_if.sw_if_index] for dst_if in self.flows[src_if]: dst_hosts = self.hosts_by_pg_idx[dst_if.sw_if_index] n_int = len(dst_hosts) * len(src_hosts) for i in range(0, n_int): dst_host = dst_hosts[i / len(src_hosts)] src_host = src_hosts[i % len(src_hosts)] pkt_info = self.create_packet_info(src_if, dst_if) if ipv6 == 1: pkt_info.ip = 1 elif ipv6 == 0: pkt_info.ip = 0 else: pkt_info.ip = random.choice([0, 1]) if proto == -1: pkt_info.proto = random.choice(self.proto[self.IP]) else: pkt_info.proto = proto payload = self.info_to_payload(pkt_info) p = Ether(dst=dst_host.mac, src=src_host.mac) if etype > 0: p = Ether(dst=dst_host.mac, src=src_host.mac, type=etype) if pkt_info.ip: p /= IPv6(dst=dst_host.ip6, src=src_host.ip6) if fragments: p /= IPv6ExtHdrFragment(offset=64, m=1) else: if fragments: p /= IP(src=src_host.ip4, dst=dst_host.ip4, flags=1, frag=64) else: p /= IP(src=src_host.ip4, dst=dst_host.ip4) if traffic_type == self.ICMP: if pkt_info.ip: p /= ICMPv6EchoRequest(type=self.icmp6_type, code=self.icmp6_code) else: p /= ICMP(type=self.icmp4_type, code=self.icmp4_code) else: p /= self.create_upper_layer(i, pkt_info.proto, ports) if pkt_raw: p /= Raw(payload) pkt_info.data = p.copy() if pkt_raw: size = random.choice(packet_sizes) self.extend_packet(p, size) pkts.append(p) return pkts
def test_udp_encap(self): """ UDP Encap test """ # # construct a UDP encap object through each of the peers # v4 through the first two peears, v6 through the second. # udp_encap_0 = VppUdpEncap(self, 0, self.pg0.local_ip4, self.pg0.remote_ip4, 330, 440) udp_encap_1 = VppUdpEncap(self, 1, self.pg1.local_ip4, self.pg1.remote_ip4, 331, 441, table_id=1) udp_encap_2 = VppUdpEncap(self, 2, self.pg2.local_ip6, self.pg2.remote_ip6, 332, 442, table_id=2, is_ip6=1) udp_encap_3 = VppUdpEncap(self, 3, self.pg3.local_ip6, self.pg3.remote_ip6, 333, 443, table_id=3, is_ip6=1) udp_encap_0.add_vpp_config() udp_encap_1.add_vpp_config() udp_encap_2.add_vpp_config() udp_encap_3.add_vpp_config() # # Routes via each UDP encap object - all combinations of v4 and v6. # route_4o4 = VppIpRoute(self, "1.1.0.1", 32, [ VppRoutePath("0.0.0.0", 0xFFFFFFFF, is_udp_encap=1, next_hop_id=0) ]) route_4o6 = VppIpRoute(self, "1.1.2.1", 32, [ VppRoutePath("0.0.0.0", 0xFFFFFFFF, is_udp_encap=1, next_hop_id=2) ]) route_6o4 = VppIpRoute( self, "2001::1", 128, [ VppRoutePath( "0.0.0.0", 0xFFFFFFFF, is_udp_encap=1, next_hop_id=1) ], is_ip6=1) route_6o6 = VppIpRoute( self, "2001::3", 128, [ VppRoutePath( "0.0.0.0", 0xFFFFFFFF, is_udp_encap=1, next_hop_id=3) ], is_ip6=1) route_4o4.add_vpp_config() route_4o6.add_vpp_config() route_6o6.add_vpp_config() route_6o4.add_vpp_config() # # 4o4 encap # p_4o4 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src="2.2.2.2", dst="1.1.0.1") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) rx = self.send_and_expect(self.pg0, p_4o4 * 65, self.pg0) for p in rx: self.validate_outer4(p, udp_encap_0) p = IP(p["UDP"].payload.load) self.validate_inner4(p, p_4o4) # # 4o6 encap # p_4o6 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src="2.2.2.2", dst="1.1.2.1") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) rx = self.send_and_expect(self.pg0, p_4o6 * 65, self.pg2) for p in rx: self.validate_outer6(p, udp_encap_2) p = IP(p["UDP"].payload.load) self.validate_inner4(p, p_4o6) # # 6o4 encap # p_6o4 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IPv6(src="2001::100", dst="2001::1") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) rx = self.send_and_expect(self.pg0, p_6o4 * 65, self.pg1) for p in rx: self.validate_outer4(p, udp_encap_1) p = IPv6(p["UDP"].payload.load) self.validate_inner6(p, p_6o4) # # 6o6 encap # p_6o6 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IPv6(src="2001::100", dst="2001::3") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) rx = self.send_and_expect(self.pg0, p_6o6 * 65, self.pg3) for p in rx: self.validate_outer6(p, udp_encap_3) p = IPv6(p["UDP"].payload.load) self.validate_inner6(p, p_6o6) # # A route with an output label # the TTL of the inner packet is decremented on LSP ingress # route_4oMPLSo4 = VppIpRoute(self, "1.1.2.22", 32, [ VppRoutePath("0.0.0.0", 0xFFFFFFFF, is_udp_encap=1, next_hop_id=1, labels=[66]) ]) route_4oMPLSo4.add_vpp_config() p_4omo4 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src="2.2.2.2", dst="1.1.2.22") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) rx = self.send_and_expect(self.pg0, p_4omo4 * 65, self.pg1) for p in rx: self.validate_outer4(p, udp_encap_1) p = MPLS(p["UDP"].payload.load) self.validate_inner4(p, p_4omo4, ttl=63)
def cnat_translation(self, vips, isV6=False): """ CNat Translation """ ip_class = IPv6 if isV6 else IP ip_v = "ip6" if isV6 else "ip4" sports = [1234, 1233] # # turn the scanner off whilst testing otherwise sessions # will time out # self.vapi.cli("test cnat scanner off") sessions = self.vapi.cnat_session_dump() trs = [] for nbr, vip in enumerate(vips): trs.append(self.cnat_create_translation(vip, nbr, isV6=isV6)) self.logger.info(self.vapi.cli("sh cnat client")) self.logger.info(self.vapi.cli("sh cnat translation")) # # translations # for nbr, vip in enumerate(vips): self.cnat_test_translation(trs[nbr], nbr, sports, isV6=isV6) self.cnat_test_translation_update(trs[nbr], sports, isV6=isV6) if isV6: self.logger.info( self.vapi.cli("sh ip6 fib %s" % self.pg0.remote_ip6)) else: self.logger.info( self.vapi.cli("sh ip fib %s" % self.pg0.remote_ip4)) self.logger.info(self.vapi.cli("sh cnat session verbose")) # # turn the scanner back on and wait untill the sessions # all disapper # self.vapi.cli("test cnat scanner on") n_tries = 0 sessions = self.vapi.cnat_session_dump() while (len(sessions) and n_tries < 100): n_tries += 1 sessions = self.vapi.cnat_session_dump() self.sleep(2) self.assertTrue(n_tries < 100) # # load some flows again and purge # for vip in vips: for src in self.pg0.remote_hosts: for sport in sports: # from client to vip p1 = (Ether(dst=self.pg0.local_mac, src=src.mac) / ip_class(src=getattr(src, ip_v), dst=vip.ip) / vip.l4p(sport=sport, dport=vip.port) / Raw()) self.send_and_expect(self.pg0, p1 * N_PKTS, self.pg2) for tr in trs: tr.delete() self.assertTrue(self.vapi.cnat_session_dump()) self.vapi.cnat_session_purge() self.assertFalse(self.vapi.cnat_session_dump())
def cnat_test_sourcenat(self, srcNatAddr, l4p=TCP, isV6=False): ip_v = "ip6" if isV6 else "ip4" ip_class = IPv6 if isV6 else IP sports = [1234, 1235, 1236] dports = [6661, 6662, 6663] self.pg0.generate_remote_hosts(1) self.pg0.configure_ipv4_neighbors() self.pg0.configure_ipv6_neighbors() self.pg1.generate_remote_hosts(len(sports)) self.pg1.configure_ipv4_neighbors() self.pg1.configure_ipv6_neighbors() self.vapi.cli("test cnat scanner on") t1 = self.cnat_create_translation(srcNatAddr, self.pg0) for nbr, remote_host in enumerate(self.pg1.remote_hosts): # from pods to outside network p1 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_hosts[0].mac) / ip_class(src=getattr(self.pg0.remote_hosts[0], ip_v), dst=getattr(remote_host, ip_v)) / l4p(sport=sports[nbr], dport=dports[nbr]) / Raw()) rxs = self.send_and_expect(self.pg0, p1 * N_PKTS, self.pg1) for rx in rxs: self.assert_packet_checksums_valid(rx) self.assertEqual(rx[ip_class].dst, getattr(remote_host, ip_v)) self.assertEqual(rx[l4p].dport, dports[nbr]) self.assertEqual(rx[ip_class].src, srcNatAddr) sport = rx[l4p].sport # from outside to pods p2 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_hosts[nbr].mac) / ip_class(src=getattr(remote_host, ip_v), dst=srcNatAddr) / l4p(sport=dports[nbr], dport=sport) / Raw()) rxs = self.send_and_expect(self.pg1, p2 * N_PKTS, self.pg0) for rx in rxs: self.assert_packet_checksums_valid(rx) self.assertEqual(rx[ip_class].dst, getattr(self.pg0.remote_hosts[0], ip_v)) self.assertEqual(rx[l4p].dport, sports[nbr]) self.assertEqual(rx[l4p].sport, dports[nbr]) self.assertEqual(rx[ip_class].src, getattr(remote_host, ip_v)) # add remote host to exclude list subnet_mask = 100 if isV6 else 16 subnet = getattr(remote_host, ip_v) + "/" + str(subnet_mask) exclude_subnet = ip_network(subnet, strict=False) t1.cnat_exclude_subnet(exclude_subnet) self.vapi.cnat_session_purge() rxs = self.send_and_expect(self.pg0, p1 * N_PKTS, self.pg1) for rx in rxs: self.assert_packet_checksums_valid(rx) self.assertEqual(rx[ip_class].dst, getattr(remote_host, ip_v)) self.assertEqual(rx[l4p].dport, dports[nbr]) self.assertEqual(rx[ip_class].src, getattr(self.pg0.remote_hosts[0], ip_v)) # remove remote host from exclude list t1.cnat_exclude_subnet(exclude_subnet, isAdd=False) self.vapi.cnat_session_purge() rxs = self.send_and_expect(self.pg0, p1 * N_PKTS, self.pg1) for rx in rxs: self.assert_packet_checksums_valid(rx) self.assertEqual(rx[ip_class].dst, getattr(remote_host, ip_v)) self.assertEqual(rx[l4p].dport, dports[nbr]) self.assertEqual(rx[ip_class].src, srcNatAddr)
def test_pipe(self): """ Pipes """ pipes = [VppPipe(self), VppPipe(self, 10)] for p in pipes: p.add_vpp_config() p.admin_up() # # L2 cross-connect pipe0 east with pg0 and west with pg1 # self.vapi.sw_interface_set_l2_xconnect(self.pg0.sw_if_index, pipes[0].east, enable=1) self.vapi.sw_interface_set_l2_xconnect(pipes[0].east, self.pg0.sw_if_index, enable=1) self.vapi.sw_interface_set_l2_xconnect(self.pg1.sw_if_index, pipes[0].west, enable=1) self.vapi.sw_interface_set_l2_xconnect(pipes[0].west, self.pg1.sw_if_index, enable=1) # test bi-drectional L2 flow pg0<->pg1 p = (Ether(src=self.pg0.remote_mac, dst=self.pg1.remote_mac) / IP(src="1.1.1.1", dst="1.1.1.2") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_expect(self.pg0, p * 65, self.pg1) self.send_and_expect(self.pg1, p * 65, self.pg0) # # Attach ACL to ensure features are run on the pipe # rule_1 = ({ 'is_permit': 0, 'is_ipv6': 0, 'proto': 17, 'srcport_or_icmptype_first': 1234, 'srcport_or_icmptype_last': 1234, 'src_ip_prefix_len': 32, 'src_ip_addr': inet_pton(AF_INET, "1.1.1.1"), 'dstport_or_icmpcode_first': 1234, 'dstport_or_icmpcode_last': 1234, 'dst_ip_prefix_len': 32, 'dst_ip_addr': inet_pton(AF_INET, "1.1.1.2") }) acl = self.vapi.acl_add_replace(acl_index=4294967295, r=[rule_1]) # Apply the ACL on the pipe on output self.vapi.acl_interface_set_acl_list(pipes[0].east, 0, [acl.acl_index]) self.send_and_assert_no_replies(self.pg0, p * 65) self.send_and_expect(self.pg1, p * 65, self.pg0) # remove from output and apply on input self.vapi.acl_interface_set_acl_list(pipes[0].east, 0, []) self.vapi.acl_interface_set_acl_list(pipes[0].west, 1, [acl.acl_index]) self.send_and_assert_no_replies(self.pg0, p * 65) self.send_and_expect(self.pg1, p * 65, self.pg0) self.vapi.acl_interface_set_acl_list(pipes[0].west, 0, []) self.send_and_expect(self.pg0, p * 65, self.pg1) self.send_and_expect(self.pg1, p * 65, self.pg0) # # L3 routes in two separate tables so a pipe can be used to L3 # x-connect # tables = [] tables.append(VppIpTable(self, 1)) tables.append(VppIpTable(self, 2)) for t in tables: t.add_vpp_config() self.pg2.set_table_ip4(1) self.pg2.config_ip4() self.pg2.resolve_arp() self.pg3.set_table_ip4(2) self.pg3.config_ip4() self.pg3.resolve_arp() routes = [] routes.append( VppIpRoute( self, "1.1.1.1", 32, [VppRoutePath(self.pg3.remote_ip4, self.pg3.sw_if_index)], table_id=2)) routes.append( VppIpRoute(self, "1.1.1.1", 32, [VppRoutePath("0.0.0.0", pipes[1].east)], table_id=1)) routes.append( VppIpRoute(self, "1.1.1.2", 32, [VppRoutePath("0.0.0.0", pipes[1].west)], table_id=2)) routes.append( VppIpRoute( self, "1.1.1.2", 32, [VppRoutePath(self.pg2.remote_ip4, self.pg2.sw_if_index)], table_id=1)) for r in routes: r.add_vpp_config() p_east = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IP(src="1.1.1.2", dst="1.1.1.1") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) # bind the pipe ends to the correct tables self.vapi.sw_interface_set_table(pipes[1].west, 0, 2) self.vapi.sw_interface_set_table(pipes[1].east, 0, 1) # IP is not enabled on the pipes at this point self.send_and_assert_no_replies(self.pg2, p_east * 65) # IP enable the Pipes by making them unnumbered pipes[0].set_unnumbered(self.pg2.sw_if_index) pipes[1].set_unnumbered(self.pg3.sw_if_index) self.send_and_expect(self.pg2, p_east * 65, self.pg3) # and the return path p_west = (Ether(src=self.pg3.remote_mac, dst=self.pg3.local_mac) / IP(src="1.1.1.1", dst="1.1.1.2") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_expect(self.pg3, p_west * 65, self.pg2) # # Use ACLs to test features run on the Pipes # self.vapi.acl_interface_set_acl_list(pipes[1].east, 0, [acl.acl_index]) self.send_and_assert_no_replies(self.pg2, p_east * 65) self.send_and_expect(self.pg3, p_west * 65, self.pg2) # remove from output and apply on input self.vapi.acl_interface_set_acl_list(pipes[1].east, 0, []) self.vapi.acl_interface_set_acl_list(pipes[1].west, 1, [acl.acl_index]) self.send_and_assert_no_replies(self.pg2, p_east * 65) self.send_and_expect(self.pg3, p_west * 65, self.pg2) self.vapi.acl_interface_set_acl_list(pipes[1].west, 0, []) self.send_and_expect(self.pg2, p_east * 65, self.pg3) self.send_and_expect(self.pg3, p_west * 65, self.pg2) # cleanup (so the tables delete) self.pg2.unconfig_ip4() self.pg2.set_table_ip4(0) self.pg3.unconfig_ip4() self.pg3.set_table_ip4(0) self.vapi.sw_interface_set_table(pipes[1].west, 0, 0) self.vapi.sw_interface_set_table(pipes[1].east, 0, 0)
def cnat_test_translation(self, t1, nbr, sports, isV6=False): ip_v = "ip6" if isV6 else "ip4" ip_class = IPv6 if isV6 else IP vip = t1.vip # # Flows # for src in self.pg0.remote_hosts: for sport in sports: # from client to vip p1 = (Ether(dst=self.pg0.local_mac, src=src.mac) / ip_class(src=getattr(src, ip_v), dst=vip.ip) / vip.l4p(sport=sport, dport=vip.port) / Raw()) self.vapi.cli("trace add pg-input 1") rxs = self.send_and_expect(self.pg0, p1 * N_PKTS, self.pg1) for rx in rxs: self.assert_packet_checksums_valid(rx) self.assertEqual(rx[ip_class].dst, getattr(self.pg1.remote_hosts[nbr], ip_v)) self.assertEqual(rx[vip.l4p].dport, 4000 + nbr) self.assertEqual(rx[ip_class].src, getattr(src, ip_v)) self.assertEqual(rx[vip.l4p].sport, sport) # from vip to client p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / ip_class(src=getattr(self.pg1.remote_hosts[nbr], ip_v), dst=getattr(src, ip_v)) / vip.l4p(sport=4000 + nbr, dport=sport) / Raw()) rxs = self.send_and_expect(self.pg1, p1 * N_PKTS, self.pg0) for rx in rxs: self.assert_packet_checksums_valid(rx) self.assertEqual(rx[ip_class].dst, getattr(src, ip_v)) self.assertEqual(rx[vip.l4p].dport, sport) self.assertEqual(rx[ip_class].src, vip.ip) self.assertEqual(rx[vip.l4p].sport, vip.port) # # packets to the VIP that do not match a # translation are dropped # p1 = (Ether(dst=self.pg0.local_mac, src=src.mac) / ip_class(src=getattr(src, ip_v), dst=vip.ip) / vip.l4p(sport=sport, dport=6666) / Raw()) self.send_and_assert_no_replies(self.pg0, p1 * N_PKTS, self.pg1) # # packets from the VIP that do not match a # session are forwarded # p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / ip_class(src=getattr(self.pg1.remote_hosts[nbr], ip_v), dst=getattr(src, ip_v)) / vip.l4p(sport=6666, dport=sport) / Raw()) rxs = self.send_and_expect(self.pg1, p1 * N_PKTS, self.pg0) self.assertEqual(t1.get_stats()['packets'], N_PKTS * len(sports) * len(self.pg0.remote_hosts))
def test_ip_load_balance(self): """ IP Load-Balancing """ # # An array of packets that differ only in the destination port # port_ip_pkts = [] port_mpls_pkts = [] # # An array of packets that differ only in the source address # src_ip_pkts = [] src_mpls_pkts = [] for ii in range(65): port_ip_hdr = (IP(dst="10.0.0.1", src="20.0.0.1") / UDP(sport=1234, dport=1234 + ii) / Raw('\xa5' * 100)) port_ip_pkts.append( (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / port_ip_hdr)) port_mpls_pkts.append( (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / MPLS(label=66, ttl=2) / port_ip_hdr)) src_ip_hdr = (IP(dst="10.0.0.1", src="20.0.0.%d" % ii) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) src_ip_pkts.append( (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / src_ip_hdr)) src_mpls_pkts.append( (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / MPLS(label=66, ttl=2) / src_ip_hdr)) route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32, [ VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index), VppRoutePath(self.pg2.remote_ip4, self.pg2.sw_if_index) ]) route_10_0_0_1.add_vpp_config() binding = VppMplsIpBind(self, 66, "10.0.0.1", 32) binding.add_vpp_config() # # inject the packet on pg0 - expect load-balancing across the 2 paths # - since the default hash config is to use IP src,dst and port # src,dst # We are not going to ensure equal amounts of packets across each link, # since the hash algorithm is statistical and therefore this can never # be guaranteed. But wuth 64 different packets we do expect some # balancing. So instead just ensure there is traffic on each link. # self.send_and_expect_load_balancing(self.pg0, port_ip_pkts, [self.pg1, self.pg2]) self.send_and_expect_load_balancing(self.pg0, src_ip_pkts, [self.pg1, self.pg2]) self.send_and_expect_load_balancing(self.pg0, port_mpls_pkts, [self.pg1, self.pg2]) self.send_and_expect_load_balancing(self.pg0, src_mpls_pkts, [self.pg1, self.pg2]) # # change the flow hash config so it's only IP src,dst # - now only the stream with differing source address will # load-balance # self.vapi.set_ip_flow_hash(0, src=1, dst=1, sport=0, dport=0) self.send_and_expect_load_balancing(self.pg0, src_ip_pkts, [self.pg1, self.pg2]) self.send_and_expect_load_balancing(self.pg0, src_mpls_pkts, [self.pg1, self.pg2]) self.send_and_expect_one_itf(self.pg0, port_ip_pkts, self.pg2) # # change the flow hash config back to defaults # self.vapi.set_ip_flow_hash(0, src=1, dst=1, sport=1, dport=1) # # Recursive prefixes # - testing that 2 stages of load-balancing occurs and there is no # polarisation (i.e. only 2 of 4 paths are used) # port_pkts = [] src_pkts = [] for ii in range(257): port_pkts.append( (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(dst="1.1.1.1", src="20.0.0.1") / UDP(sport=1234, dport=1234 + ii) / Raw('\xa5' * 100))) src_pkts.append( (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(dst="1.1.1.1", src="20.0.0.%d" % ii) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100))) route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32, [ VppRoutePath(self.pg3.remote_ip4, self.pg3.sw_if_index), VppRoutePath(self.pg4.remote_ip4, self.pg4.sw_if_index) ]) route_10_0_0_2.add_vpp_config() route_1_1_1_1 = VppIpRoute(self, "1.1.1.1", 32, [ VppRoutePath("10.0.0.2", 0xffffffff), VppRoutePath("10.0.0.1", 0xffffffff) ]) route_1_1_1_1.add_vpp_config() # # inject the packet on pg0 - expect load-balancing across all 4 paths # self.vapi.cli("clear trace") self.send_and_expect_load_balancing( self.pg0, port_pkts, [self.pg1, self.pg2, self.pg3, self.pg4]) self.send_and_expect_load_balancing( self.pg0, src_pkts, [self.pg1, self.pg2, self.pg3, self.pg4]) # # Recursive prefixes # - testing that 2 stages of load-balancing, no choices # port_pkts = [] for ii in range(257): port_pkts.append( (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(dst="1.1.1.2", src="20.0.0.2") / UDP(sport=1234, dport=1234 + ii) / Raw('\xa5' * 100))) route_10_0_0_3 = VppIpRoute( self, "10.0.0.3", 32, [VppRoutePath(self.pg3.remote_ip4, self.pg3.sw_if_index)]) route_10_0_0_3.add_vpp_config() route_1_1_1_2 = VppIpRoute(self, "1.1.1.2", 32, [VppRoutePath("10.0.0.3", 0xffffffff)]) route_1_1_1_2.add_vpp_config() # # inject the packet on pg0 - expect load-balancing across all 4 paths # self.vapi.cli("clear trace") self.send_and_expect_one_itf(self.pg0, port_pkts, self.pg3)
def test_ip_sub_nets(self): """ IP Sub Nets """ # # Configure a covering route to forward so we know # when we are dropping # cover_route = VppIpRoute( self, "10.0.0.0", 8, [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)]) cover_route.add_vpp_config() p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IP(dst="10.10.10.10", src=self.pg0.local_ip4) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.pg1.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) # # Configure some non-/24 subnets on an IP interface # ip_addr_n = socket.inet_pton(socket.AF_INET, "10.10.10.10") self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index, ip_addr_n, 16) pn = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IP(dst="10.10.0.0", src=self.pg0.local_ip4) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) pb = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IP(dst="10.10.255.255", src=self.pg0.local_ip4) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_assert_no_replies(self.pg1, pn, "IP Network address") self.send_and_assert_no_replies(self.pg1, pb, "IP Broadcast address") # remove the sub-net and we are forwarding via the cover again self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index, ip_addr_n, 16, is_add=0) self.pg1.add_stream(pn) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.pg1.add_stream(pb) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) # # A /31 is a special case where the 'other-side' is an attached host # packets to that peer generate ARP requests # ip_addr_n = socket.inet_pton(socket.AF_INET, "10.10.10.10") self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index, ip_addr_n, 31) pn = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IP(dst="10.10.10.11", src=self.pg0.local_ip4) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.pg1.add_stream(pn) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture(1) rx[ARP] # remove the sub-net and we are forwarding via the cover again self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index, ip_addr_n, 31, is_add=0) self.pg1.add_stream(pn) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1)
def test_sapdiag_items_lookup(self): """Test lookup and filtering of SAPDiagItems inside a SAPDiag packet""" sapdiag = SAPDiag() sapdiag_ses_item = SAPDiagItem(item_type="SES") sapdiag.message.append(sapdiag_ses_item) sapdiag_appl_item = SAPDiagItem(item_type="APPL", item_id="ST_USER", item_sid="RFC_PARENT_UUID") sapdiag.message.append(sapdiag_appl_item) self.assertIn(sapdiag_ses_item, sapdiag.get_item(0x1)) self.assertIn(sapdiag_ses_item, sapdiag.get_item("SES")) self.assertNotIn(sapdiag_ses_item, sapdiag.get_item(0x10)) self.assertNotIn(sapdiag_ses_item, sapdiag.get_item("APPL")) self.assertIn(sapdiag_appl_item, sapdiag.get_item(0x10)) self.assertIn(sapdiag_appl_item, sapdiag.get_item("APPL")) self.assertIn(sapdiag_appl_item, sapdiag.get_item("APPL", 0x04)) self.assertIn(sapdiag_appl_item, sapdiag.get_item("APPL", "ST_USER")) self.assertIn(sapdiag_appl_item, sapdiag.get_item("APPL", 0x04, 0x10)) self.assertIn(sapdiag_appl_item, sapdiag.get_item("APPL", "ST_USER", 0x10)) self.assertIn(sapdiag_appl_item, sapdiag.get_item("APPL", "ST_USER", "RFC_PARENT_UUID")) self.assertNotIn(sapdiag_appl_item, sapdiag.get_item(0x1)) self.assertNotIn(sapdiag_appl_item, sapdiag.get_item("APPL4")) self.assertNotIn(sapdiag_appl_item, sapdiag.get_item("APPL", 0x06)) self.assertNotIn(sapdiag_appl_item, sapdiag.get_item("APPL", "ST_R3INFO")) self.assertNotIn(sapdiag_appl_item, sapdiag.get_item("APPL", 0x04, 0x02)) self.assertNotIn(sapdiag_appl_item, sapdiag.get_item("APPL", "ST_USER", 0x02)) self.assertNotIn(sapdiag_appl_item, sapdiag.get_item("APPL", "ST_USER", "CONNECT")) self.assertListEqual([sapdiag_ses_item, sapdiag_appl_item], sapdiag.get_item([0x01, 0x10])) self.assertListEqual([sapdiag_ses_item, sapdiag_appl_item], sapdiag.get_item(["SES", "APPL"])) self.assertIn(sapdiag_appl_item, sapdiag.get_item(["APPL"], [0x04, 0x06])) self.assertIn(sapdiag_appl_item, sapdiag.get_item(["APPL"], ["ST_USER", "ST_R3INFO"])) self.assertIn(sapdiag_appl_item, sapdiag.get_item(["APPL"], 0x04, [0x02, 0x10])) self.assertIn( sapdiag_appl_item, sapdiag.get_item(["APPL"], "ST_USER", ["RFC_PARENT_UUID", "CONNECT"])) self.assertNotIn(sapdiag_appl_item, sapdiag.get_item(["SES", "APPL4"])) self.assertNotIn(sapdiag_appl_item, sapdiag.get_item(["APPL"], ["ST_R3INFO"])) self.assertNotIn(sapdiag_appl_item, sapdiag.get_item(["APPL"], ["ST_USER"], ["CONNECT"])) # Insert a wrong item and observe that the lookup still works sapdiag.message.append(Raw("\x00" * 10)) self.assertIn(sapdiag_ses_item, sapdiag.get_item("SES")) self.assertIn( sapdiag_appl_item, sapdiag.get_item(["APPL"], "ST_USER", ["RFC_PARENT_UUID", "CONNECT"]))
def zero_mutable_fields(pkt, sending=False): """ When using AH, all "mutable" fields must be "zeroed" before calculating the ICV. See RFC 4302, Section 3.3.3.1. Handling Mutable Fields. @param pkt: an IP(v6) packet containing an AH layer. NOTE: The packet will be modified @param sending: if true, ipv6 routing headers will not be reordered """ if pkt.haslayer(AH): pkt[AH].icv = chr(0) * len(pkt[AH].icv) else: raise TypeError('no AH layer found') if pkt.version == 4: # the tos field has been replaced by DSCP and ECN # Routers may rewrite the DS field as needed to provide a # desired local or end-to-end service pkt.tos = 0 # an intermediate router might set the DF bit, even if the source # did not select it. pkt.flags = 0 # changed en route as a normal course of processing by routers pkt.ttl = 0 # will change if any of these other fields change pkt.chksum = 0 immutable_opts = [] for opt in pkt.options: if opt.option in IMMUTABLE_IPV4_OPTIONS: immutable_opts.append(opt) else: immutable_opts.append(Raw(chr(0) * len(opt))) pkt.options = immutable_opts else: # holds DSCP and ECN pkt.tc = 0 # The flow label described in AHv1 was mutable, and in RFC 2460 [DH98] # was potentially mutable. To retain compatibility with existing AH # implementations, the flow label is not included in the ICV in AHv2. pkt.fl = 0 # same as ttl pkt.hlim = 0 next_hdr = pkt.payload while isinstance(next_hdr, (IPv6ExtHdrHopByHop, IPv6ExtHdrRouting, IPv6ExtHdrDestOpt)): if isinstance(next_hdr, (IPv6ExtHdrHopByHop, IPv6ExtHdrDestOpt)): for opt in next_hdr.options: if opt.otype & 0x20: # option data can change en-route and must be zeroed opt.optdata = chr(0) * opt.optlen elif isinstance(next_hdr, IPv6ExtHdrRouting) and sending: # The sender must order the field so that it appears as it # will at the receiver, prior to performing the ICV computation. next_hdr.segleft = 0 if next_hdr.addresses: final = next_hdr.addresses.pop() next_hdr.addresses.insert(0, pkt.dst) pkt.dst = final else: break next_hdr = next_hdr.payload return pkt
# The fields used to identify a version being fingerprinted version_info_fields = [ "version", "release", "patch_number", "source_id", "update_level", "file_version", "platform", "submitted_by", "comment" ] # This is the list of target packets that we use during the fingerprinting. Basically it consist of a dict with the # key being the name of the target packet and the value the construction of it. fingerprint_targets = { # Connect to the SAP Route but not send any packet to trigger a timeout "Timeout": None, # Send a large packet "Network packet too big": Raw("X" * 10025), # Use an invalid opcode "Invalid control opcode": SAPRouter(type=SAPRouter.SAPROUTER_CONTROL, version=38, opcode=3), # Do not send a route "No route": SAPRouter(type=SAPRouter.SAPROUTER_ROUTE), # Set one entry but do no provide a route "No route one entry": SAPRouter(type=SAPRouter.SAPROUTER_ROUTE, route_entries=1), # Set one entry with an invalid length but do no provide it "No route invalid length": SAPRouter(type=SAPRouter.SAPROUTER_ROUTE, route_entries=2, route_rest_nodes=1, route_length=1,
def main(): """Send, receive and check IPv6 and IPv6ExtHdrSegmentRouting packets.""" args = TrafficScriptArg([ u"tx_src_mac", u"tx_dst_mac", u"rx_src_mac", u"rx_dst_mac", u"src_ip", u"dst_ip", u"dir0_srcsid", u"dir0_dstsid1", u"dir0_dstsid2", u"dir1_srcsid", u"dir1_dstsid1", u"dir1_dstsid2", u"decap", u"dir0_dstsid3", u"dir1_dstsid3", u"static_proxy" ]) tx_txq = TxQueue(args.get_arg(u"tx_if")) tx_rxq = RxQueue(args.get_arg(u"tx_if")) rx_txq = TxQueue(args.get_arg(u"rx_if")) rx_rxq = RxQueue(args.get_arg(u"rx_if")) tx_src_mac = args.get_arg(u"tx_src_mac") tx_dst_mac = args.get_arg(u"tx_dst_mac") rx_src_mac = args.get_arg(u"rx_src_mac") rx_dst_mac = args.get_arg(u"rx_dst_mac") src_ip = args.get_arg(u"src_ip") dst_ip = args.get_arg(u"dst_ip") dir0_srcsid = args.get_arg(u"dir0_srcsid") dir0_dstsid1 = args.get_arg(u"dir0_dstsid1") dir0_dstsid2 = args.get_arg(u"dir0_dstsid2") dir1_srcsid = args.get_arg(u"dir1_srcsid") dir1_dstsid1 = args.get_arg(u"dir1_dstsid1") dir1_dstsid2 = args.get_arg(u"dir1_dstsid2") decap = args.get_arg(u"decap") dir0_dstsid3 = args.get_arg(u"dir0_dstsid3") dir1_dstsid3 = args.get_arg(u"dir1_dstsid3") static_proxy = args.get_arg(u"static_proxy") ip_pkt = IPv6(src=src_ip, dst=dst_ip) sent_packets = list() tx_pkt_send = (Ether(src=tx_src_mac, dst=tx_dst_mac) / ip_pkt) tx_pkt_send /= Raw() size_limit = 78 if len(tx_pkt_send) < size_limit: tx_pkt_send[Raw].load += (b"\0" * (size_limit - len(tx_pkt_send))) sent_packets.append(tx_pkt_send) tx_txq.send(tx_pkt_send) while True: rx_pkt_recv = rx_rxq.recv(2) if rx_pkt_recv is None: raise RuntimeError(f"{IPv6.name} packet Rx timeout") if rx_pkt_recv.haslayer(ICMPv6ND_NS): # read another packet in the queue if the current one is ICMPv6ND_NS continue else: # otherwise process the current packet break check_srv6(rx_pkt_recv, rx_src_mac, rx_dst_mac, src_ip, dst_ip, dir0_srcsid, dir0_dstsid1, dir0_dstsid2, dir0_dstsid3, 1) ip_pkt = IPv6(src=dst_ip, dst=src_ip) ip_pkt /= Raw() if len(ip_pkt) < (size_limit - 14): ip_pkt[Raw].load += (b"\0" * (size_limit - 14 - len(ip_pkt))) rx_pkt_send = ( Ether(src=rx_dst_mac, dst=rx_src_mac) / IPv6(src=dir1_srcsid, dst=dir1_dstsid1) / IPv6ExtHdrSegmentRouting( segleft=1 if dir1_dstsid3 == u"None" else 2, lastentry=1 if dir1_dstsid3 == u"None" else 2, addresses=[dir1_dstsid2, dir1_dstsid1] if dir1_dstsid3 == u"None" else [dir1_dstsid3, dir1_dstsid2, dir1_dstsid1]) / ip_pkt) if dir1_dstsid2 != u"None" else ( Ether(src=rx_dst_mac, dst=rx_src_mac) / IPv6(src=dir1_srcsid, dst=dir1_dstsid1) / ip_pkt) rx_txq.send(rx_pkt_send) while True: tx_pkt_recv = tx_rxq.recv(2, ignore=sent_packets) if tx_pkt_recv is None: raise RuntimeError(f"{IPv6.name} packet Rx timeout") if tx_pkt_recv.haslayer(ICMPv6ND_NS): # read another packet in the queue if the current one is ICMPv6ND_NS continue else: # otherwise process the current packet break if decap == u"True": check_ip(tx_pkt_recv, tx_dst_mac, tx_src_mac, dst_ip, src_ip) else: check_srv6(tx_pkt_recv, tx_dst_mac, tx_src_mac, dst_ip, src_ip, dir1_srcsid, dir1_dstsid1, dir1_dstsid2, dir1_dstsid3, 2, bool(static_proxy == u"True")) sys.exit(0)
def test_wg_peer_resp(self): """ Send handshake response """ wg_output_node_name = '/err/wg-output-tun/' wg_input_node_name = '/err/wg-input/' port = 12323 # Create interfaces wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config() wg0.admin_up() wg0.config_ip4() self.pg_enable_capture(self.pg_interfaces) self.pg_start() peer_1 = VppWgPeer(self, wg0, self.pg1.remote_ip4, port+1, ["10.11.2.0/24", "10.11.3.0/24"]).add_vpp_config() self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1) # wait for the peer to send a handshake rx = self.pg1.get_capture(1, timeout=2) # consume the handshake in the noise protocol and # generate the response resp = peer_1.consume_init(rx[0], self.pg1) # send the response, get keepalive rxs = self.send_and_expect(self.pg1, [resp], self.pg1) for rx in rxs: b = peer_1.decrypt_transport(rx) self.assertEqual(0, len(b)) # send a packets that are routed into the tunnel p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst="10.11.3.2") / UDP(sport=555, dport=556) / Raw(b'\x00' * 80)) rxs = self.send_and_expect(self.pg0, p * 255, self.pg1) peer_1.validate_encapped(rxs, p) # send packets into the tunnel, expect to receive them on # the other side p = [(peer_1.mk_tunnel_header(self.pg1) / Wireguard(message_type=4, reserved_zero=0) / WireguardTransport( receiver_index=peer_1.sender, counter=ii, encrypted_encapsulated_packet=peer_1.encrypt_transport( (IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20) / UDP(sport=222, dport=223) / Raw())))) for ii in range(255)] rxs = self.send_and_expect(self.pg1, p, self.pg0) for rx in rxs: self.assertEqual(rx[IP].dst, self.pg0.remote_ip4) self.assertEqual(rx[IP].ttl, 19)
def test_cflow_packet(self): """verify cflow packet fields""" self.logger.info("FFP_TEST_START_0000") self.pg_enable_capture(self.pg_interfaces) self.pkts = [] ipfix = VppCFLOW(test=self, intf='pg8', datapath="ip4", layer='l2 l3 l4', active=2) ipfix.add_vpp_config() route_9001 = VppIpRoute(self, "9.0.0.0", 24, [VppRoutePath(self.pg8._remote_hosts[0].ip4, self.pg8.sw_if_index)]) route_9001.add_vpp_config() ipfix_decoder = IPFIXDecoder() templates = ipfix.verify_templates(ipfix_decoder, count=1) self.pkts = [(Ether(dst=self.pg7.local_mac, src=self.pg7.remote_mac) / IP(src=self.pg7.remote_ip4, dst="9.0.0.100") / TCP(sport=1234, dport=4321, flags=80) / Raw(b'\xa5' * 100))] nowUTC = int(time.time()) nowUNIX = nowUTC+2208988800 self.send_packets(src_if=self.pg7, dst_if=self.pg8) cflow = self.wait_for_cflow_packet(self.collector, templates[0], 10) self.collector.get_capture(2) if cflow[0].haslayer(IPFIX): self.assertEqual(cflow[IPFIX].version, 10) self.assertEqual(cflow[IPFIX].observationDomainID, 1) self.assertEqual(cflow[IPFIX].sequenceNumber, 0) self.assertAlmostEqual(cflow[IPFIX].exportTime, nowUTC, delta=5) if cflow.haslayer(Data): record = ipfix_decoder.decode_data_set(cflow[0].getlayer(Set))[0] # ingress interface self.assertEqual(int(binascii.hexlify(record[10]), 16), 8) # egress interface self.assertEqual(int(binascii.hexlify(record[14]), 16), 9) # packets self.assertEqual(int(binascii.hexlify(record[2]), 16), 1) # src mac self.assertEqual(mac_ntop(record[56]), self.pg8.local_mac) # dst mac self.assertEqual(mac_ntop(record[80]), self.pg8.remote_mac) flowTimestamp = int(binascii.hexlify(record[156]), 16) >> 32 # flow start timestamp self.assertAlmostEqual(flowTimestamp, nowUNIX, delta=1) flowTimestamp = int(binascii.hexlify(record[157]), 16) >> 32 # flow end timestamp self.assertAlmostEqual(flowTimestamp, nowUNIX, delta=1) # ethernet type self.assertEqual(int(binascii.hexlify(record[256]), 16), 8) # src ip self.assertEqual(inet_ntop(socket.AF_INET, record[8]), self.pg7.remote_ip4) # dst ip self.assertEqual(inet_ntop(socket.AF_INET, record[12]), "9.0.0.100") # protocol (TCP) self.assertEqual(int(binascii.hexlify(record[4]), 16), 6) # src port self.assertEqual(int(binascii.hexlify(record[7]), 16), 1234) # dst port self.assertEqual(int(binascii.hexlify(record[11]), 16), 4321) # tcp flags self.assertEqual(int(binascii.hexlify(record[6]), 16), 80) ipfix.remove_vpp_config() self.logger.info("FFP_TEST_FINISH_0000")
def test_wg_peer_init(self): """ Send handshake init """ wg_output_node_name = '/err/wg-output-tun/' wg_input_node_name = '/err/wg-input/' port = 12333 # Create interfaces wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config() wg0.admin_up() wg0.config_ip4() peer_1 = VppWgPeer(self, wg0, self.pg1.remote_ip4, port+1, ["10.11.2.0/24", "10.11.3.0/24"]).add_vpp_config() self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1) # route a packet into the wg interface # use the allowed-ip prefix # this is dropped because the peer is not initiated p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst="10.11.3.2") / UDP(sport=555, dport=556) / Raw()) self.send_and_assert_no_replies(self.pg0, [p]) kp_error = wg_output_node_name + "Keypair error" self.assertEqual(1, self.statistics.get_err_counter(kp_error)) # send a handsake from the peer with an invalid MAC p = peer_1.mk_handshake(self.pg1) p[WireguardInitiation].mac1 = b'foobar' self.send_and_assert_no_replies(self.pg1, [p]) self.assertEqual(1, self.statistics.get_err_counter( wg_input_node_name + "Invalid MAC handshake")) # send a handsake from the peer but signed by the wrong key. p = peer_1.mk_handshake(self.pg1, X25519PrivateKey.generate().public_key()) self.send_and_assert_no_replies(self.pg1, [p]) self.assertEqual(1, self.statistics.get_err_counter( wg_input_node_name + "Peer error")) # send a valid handsake init for which we expect a response p = peer_1.mk_handshake(self.pg1) rx = self.send_and_expect(self.pg1, [p], self.pg1) peer_1.consume_response(rx[0]) # route a packet into the wg interface # this is dropped because the peer is still not initiated p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst="10.11.3.2") / UDP(sport=555, dport=556) / Raw()) self.send_and_assert_no_replies(self.pg0, [p]) self.assertEqual(2, self.statistics.get_err_counter(kp_error)) # send a data packet from the peer through the tunnel # this completes the handshake p = (IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20) / UDP(sport=222, dport=223) / Raw()) d = peer_1.encrypt_transport(p) p = (peer_1.mk_tunnel_header(self.pg1) / (Wireguard(message_type=4, reserved_zero=0) / WireguardTransport(receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d))) rxs = self.send_and_expect(self.pg1, [p], self.pg0) for rx in rxs: self.assertEqual(rx[IP].dst, self.pg0.remote_ip4) self.assertEqual(rx[IP].ttl, 19) # send a packets that are routed into the tunnel p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst="10.11.3.2") / UDP(sport=555, dport=556) / Raw(b'\x00' * 80)) rxs = self.send_and_expect(self.pg0, p * 255, self.pg1) for rx in rxs: rx = IP(peer_1.decrypt_transport(rx)) # chech the oringial packet is present self.assertEqual(rx[IP].dst, p[IP].dst) self.assertEqual(rx[IP].ttl, p[IP].ttl-1) # send packets into the tunnel, expect to receive them on # the other side p = [(peer_1.mk_tunnel_header(self.pg1) / Wireguard(message_type=4, reserved_zero=0) / WireguardTransport( receiver_index=peer_1.sender, counter=ii+1, encrypted_encapsulated_packet=peer_1.encrypt_transport( (IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20) / UDP(sport=222, dport=223) / Raw())))) for ii in range(255)] rxs = self.send_and_expect(self.pg1, p, self.pg0) for rx in rxs: self.assertEqual(rx[IP].dst, self.pg0.remote_ip4) self.assertEqual(rx[IP].ttl, 19) peer_1.remove_vpp_config() wg0.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 self._packet_infos.iteritems() 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_wg_peer_init(self): """ Handoff """ wg_output_node_name = '/err/wg-output-tun/' wg_input_node_name = '/err/wg-input/' port = 12353 # Create interfaces wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config() wg0.admin_up() wg0.config_ip4() peer_1 = VppWgPeer(self, wg0, self.pg1.remote_ip4, port+1, ["10.11.2.0/24", "10.11.3.0/24"]).add_vpp_config() self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1) # send a valid handsake init for which we expect a response p = peer_1.mk_handshake(self.pg1) rx = self.send_and_expect(self.pg1, [p], self.pg1) peer_1.consume_response(rx[0]) # send a data packet from the peer through the tunnel # this completes the handshake and pins the peer to worker 0 p = (IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20) / UDP(sport=222, dport=223) / Raw()) d = peer_1.encrypt_transport(p) p = (peer_1.mk_tunnel_header(self.pg1) / (Wireguard(message_type=4, reserved_zero=0) / WireguardTransport(receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d))) rxs = self.send_and_expect(self.pg1, [p], self.pg0, worker=0) for rx in rxs: self.assertEqual(rx[IP].dst, self.pg0.remote_ip4) self.assertEqual(rx[IP].ttl, 19) # send a packets that are routed into the tunnel # and pins the peer tp worker 1 pe = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst="10.11.3.2") / UDP(sport=555, dport=556) / Raw(b'\x00' * 80)) rxs = self.send_and_expect(self.pg0, pe * 255, self.pg1, worker=1) peer_1.validate_encapped(rxs, pe) # send packets into the tunnel, from the other worker p = [(peer_1.mk_tunnel_header(self.pg1) / Wireguard(message_type=4, reserved_zero=0) / WireguardTransport( receiver_index=peer_1.sender, counter=ii+1, encrypted_encapsulated_packet=peer_1.encrypt_transport( (IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20) / UDP(sport=222, dport=223) / Raw())))) for ii in range(255)] rxs = self.send_and_expect(self.pg1, p, self.pg0, worker=1) for rx in rxs: self.assertEqual(rx[IP].dst, self.pg0.remote_ip4) self.assertEqual(rx[IP].ttl, 19) # send a packets that are routed into the tunnel # from owrker 0 rxs = self.send_and_expect(self.pg0, pe * 255, self.pg1, worker=0) peer_1.validate_encapped(rxs, pe) peer_1.remove_vpp_config() wg0.remove_vpp_config()
def test_abf4(self): """ IPv4 ACL Based Forwarding """ # # We are not testing the various matching capabilities # of ACLs, that's done elsewhere. Here ware are testing # the application of ACLs to a forwarding path to achieve # ABF # So we construct just a few ACLs to ensure the ABF policies # are correclty constructed and used. And a few path types # to test the API path decoding. # # # Rule 1 # rule_1 = ({'is_permit': 1, 'is_ipv6': 0, 'proto': 17, 'srcport_or_icmptype_first': 1234, 'srcport_or_icmptype_last': 1234, 'src_ip_prefix_len': 32, 'src_ip_addr': inet_pton(AF_INET, "1.1.1.1"), 'dstport_or_icmpcode_first': 1234, 'dstport_or_icmpcode_last': 1234, 'dst_ip_prefix_len': 32, 'dst_ip_addr': inet_pton(AF_INET, "1.1.1.2")}) acl_1 = self.vapi.acl_add_replace(acl_index=4294967295, r=[rule_1]) # # ABF policy for ACL 1 - path via interface 1 # abf_1 = VppAbfPolicy(self, 10, acl_1, [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)]) abf_1.add_vpp_config() # # Attach the policy to input interface Pg0 # attach_1 = VppAbfAttach(self, 10, self.pg0.sw_if_index, 50) attach_1.add_vpp_config() # # fire in packet matching the ACL src,dst. If it's forwarded # then the ABF was successful, since default routing will drop it # p_1 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src="1.1.1.1", dst="1.1.1.2") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_expect(self.pg0, p_1*65, self.pg1) # # Attach a 'better' priority policy to the same interface # abf_2 = VppAbfPolicy(self, 11, acl_1, [VppRoutePath(self.pg2.remote_ip4, self.pg2.sw_if_index)]) abf_2.add_vpp_config() attach_2 = VppAbfAttach(self, 11, self.pg0.sw_if_index, 40) attach_2.add_vpp_config() self.send_and_expect(self.pg0, p_1*65, self.pg2) # # Attach a policy with priority in the middle # abf_3 = VppAbfPolicy(self, 12, acl_1, [VppRoutePath(self.pg3.remote_ip4, self.pg3.sw_if_index)]) abf_3.add_vpp_config() attach_3 = VppAbfAttach(self, 12, self.pg0.sw_if_index, 45) attach_3.add_vpp_config() self.send_and_expect(self.pg0, p_1*65, self.pg2) # # remove the best priority # attach_2.remove_vpp_config() self.send_and_expect(self.pg0, p_1*65, self.pg3) # # Attach one of the same policies to Pg1 # attach_4 = VppAbfAttach(self, 12, self.pg1.sw_if_index, 45) attach_4.add_vpp_config() p_2 = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IP(src="1.1.1.1", dst="1.1.1.2") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_expect(self.pg1, p_2 * 65, self.pg3) # # detach the policy from PG1, now expect traffic to be dropped # attach_4.remove_vpp_config() self.send_and_assert_no_replies(self.pg1, p_2 * 65, "Detached")
def inject(self, tgtmac, rtrmac, dstmac, tgtip, svrip, tgtport, svrport, acknum, seqnum, injection, TSVal, TSecr): """Send the injection using Scapy This method is where the actual packet is created for sending things such as the payload and associated flags. FIN/ACK flag is sent to the target with this method. """ ## Headers headers = self.hdr.default(injection) if self.args.tun is False: ## Monitor injection if self.args.inj == 'mon': packet = RadioTap()\ /Dot11( FCfield = 'from-DS', addr1 = tgtmac, addr2 = rtrmac, addr3 = dstmac )\ /LLC()\ /SNAP()\ /IP( dst = tgtip, src = svrip )\ /TCP( flags = 'FA', sport = int(svrport), dport = int(tgtport), seq = int(seqnum), ack = int(acknum) )\ /Raw( load = headers + injection ) if TSVal is not None and TSecr is not None: packet[TCP].options = [('NOP', None), ('NOP', None), ('Timestamp', ((round(time.time()), TSVal)))] else: packet[TCP].options = [('NOP', None), ('NOP', None), ('Timestamp', ((round(time.time()), 0)))] ## Managed injection else: headers = self.hdr.default(injection) packet = Ether( src = self.injMac,\ dst = tgtmac\ )\ /IP( dst = tgtip, src = svrip )\ /TCP( flags = 'FA', sport = int(svrport), dport = int(tgtport), seq = int(seqnum), ack = int(acknum) )\ /Raw( load = headers + injection ) if TSVal is not None: packet[TCP].options = [\ ('NOP', None),\ ('NOP', None),\ ('Timestamp', ((round(time.time()), TSVal)))\ ] else: packet[TCP].options = [\ ('NOP', None),\ ('NOP', None),\ ('Timestamp', ((round(time.time()), 0)))\ ] ## Managed else: try: headers = self.hdr.default(injection) packet = Ether( src = self.injMac,\ dst = tgtmac\ )\ /IP( dst = tgtip, src = svrip )\ /TCP( flags = 'FA', sport = int(svrport), dport = int(tgtport), seq = int(seqnum), ack = int(acknum) )\ /Raw( load = headers + injection ) if TSVal is not None: packet[TCP].options = [ ('NOP', None),\ ('NOP', None),\ ('Timestamp', ((round(time.time()), TSVal)))\ ] else: packet[TCP].options = [ ('NOP', None),\ ('NOP', None),\ ('Timestamp', ((round(time.time()), 0)))\ ] except Exception as E: print(E) ## Inject try: gs(self.injSocket, packet, verbose=False) print('[*] Packet injected to {0}'.format(tgtmac)) except Exception as E: print(E)
def test_gbp(self): """ Group Based Policy """ nat_table = VppIpTable(self, 20) 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 kbsrp(pkt, channel=None, inter=0, count=0, iface=None, store=1, prn=None, lfilter=None, timeout=None, verbose=None, realtime=None): """ Send and receive packets with KillerBee @param channel: 802.15.4 channel to transmit/receive on @param inter: time to wait between tranmissions @param count: number of packets to capture. 0 means infinity @param iface: KillerBee interface to use, or KillerBee() class instance @param store: wether to store sniffed packets or discard them @param prn: function to apply to each packet. If something is returned, it is displayed. Ex: ex: prn = lambda x: x.summary() @param lfilter: python function applied to each packet to determine if further action may be done ex: lfilter = lambda x: x.haslayer(Padding) @param timeout: stop sniffing after a given time (default: None) @param verbose: set verbosity level @param realtime: use packet's timestamp, bending time with realtime value """ if verbose is None: verbose = conf.verb if channel == None: channel = conf.killerbee_channel if not isinstance(iface, KillerBee): if iface is not None: kb = KillerBee(device=iface) else: kb = KillerBee(device=conf.killerbee_device) kb.set_channel(channel) else: kb = iface # Make sure the packet has an FCS layer before TX if not pkt.haslayer(Dot15d4FCS): pkt /= Raw("\x00\x00") pkts_out = __kb_send(kb, pkt, inter=inter, loop=0, count=None, verbose=verbose, realtime=realtime) if verbose: print "\nSent %i packets." % pkts_out pkts_in = __kb_recv(kb, count=count, store=store, prn=prn, lfilter=lfilter, verbose=verbose, timeout=timeout) if verbose: print "\nReceived %i packets." % len(pkts_in) return plist.PacketList(pkts_in, 'Results')
def create_stream(self, src_ip_if, dst_ip_if, reverse, packet_sizes, is_ip6, expect_blocked, expect_established, add_extension_header, icmp_stateful=False): pkts = [] rules = [] permit_rules = [] permit_and_reflect_rules = [] total_packet_count = 8 for i in range(0, total_packet_count): modulo = (i//2) % 2 icmp_type_delta = i % 2 icmp_code = i is_udp_packet = (modulo == 0) if is_udp_packet and icmp_stateful: continue is_reflectable_icmp = (icmp_stateful and icmp_type_delta == 0 and not is_udp_packet) is_reflected_icmp = is_reflectable_icmp and expect_established can_reflect_this_packet = is_udp_packet or is_reflectable_icmp is_permit = i % 2 remote_dst_index = i % len(dst_ip_if.remote_hosts) remote_dst_host = dst_ip_if.remote_hosts[remote_dst_index] if is_permit == 1: info = self.create_packet_info(src_ip_if, dst_ip_if) payload = self.info_to_payload(info) else: to_be_blocked = False if (expect_blocked and not expect_established): to_be_blocked = True if (not can_reflect_this_packet): to_be_blocked = True if to_be_blocked: payload = "to be blocked" else: info = self.create_packet_info(src_ip_if, dst_ip_if) payload = self.info_to_payload(info) if reverse: dst_mac = 'de:ad:00:00:00:00' src_mac = remote_dst_host._mac dst_ip6 = src_ip_if.remote_ip6 src_ip6 = remote_dst_host.ip6 dst_ip4 = src_ip_if.remote_ip4 src_ip4 = remote_dst_host.ip4 dst_l4 = 1234 + i src_l4 = 4321 + i else: dst_mac = src_ip_if.local_mac src_mac = src_ip_if.remote_mac src_ip6 = src_ip_if.remote_ip6 dst_ip6 = remote_dst_host.ip6 src_ip4 = src_ip_if.remote_ip4 dst_ip4 = remote_dst_host.ip4 src_l4 = 1234 + i dst_l4 = 4321 + i if is_reflected_icmp: icmp_type_delta = 1 # default ULP should be something we do not use in tests ulp_l4 = TCP(sport=src_l4, dport=dst_l4) # potentially a chain of protocols leading to ULP ulp = ulp_l4 if is_udp_packet: if is_ip6: ulp_l4 = UDP(sport=src_l4, dport=dst_l4) if add_extension_header: # prepend some extension headers ulp = (IPv6ExtHdrRouting() / IPv6ExtHdrRouting() / IPv6ExtHdrFragment(offset=0, m=1) / ulp_l4) # uncomment below to test invalid ones # ulp = IPv6ExtHdrRouting(len = 200) / ulp_l4 else: ulp = ulp_l4 p = (Ether(dst=dst_mac, src=src_mac) / IPv6(src=src_ip6, dst=dst_ip6) / ulp / Raw(payload)) else: ulp_l4 = UDP(sport=src_l4, dport=dst_l4) # IPv4 does not allow extension headers, # but we rather make it a first fragment flags = 1 if add_extension_header else 0 ulp = ulp_l4 p = (Ether(dst=dst_mac, src=src_mac) / IP(src=src_ip4, dst=dst_ip4, frag=0, flags=flags) / ulp / Raw(payload)) elif modulo == 1: if is_ip6: ulp_l4 = ICMPv6Unknown(type=128 + icmp_type_delta, code=icmp_code) ulp = ulp_l4 p = (Ether(dst=dst_mac, src=src_mac) / IPv6(src=src_ip6, dst=dst_ip6) / ulp / Raw(payload)) else: ulp_l4 = ICMP(type=8 - 8*icmp_type_delta, code=icmp_code) ulp = ulp_l4 p = (Ether(dst=dst_mac, src=src_mac) / IP(src=src_ip4, dst=dst_ip4) / ulp / Raw(payload)) if i % 2 == 1: info.data = p.copy() size = packet_sizes[(i // 2) % len(packet_sizes)] self.extend_packet(p, size) pkts.append(p) rule_family = AF_INET6 if p.haslayer(IPv6) else AF_INET rule_prefix_len = 128 if p.haslayer(IPv6) else 32 rule_l3_layer = IPv6 if p.haslayer(IPv6) else IP if p.haslayer(UDP): rule_l4_sport = p[UDP].sport rule_l4_dport = p[UDP].dport else: if p.haslayer(ICMP): rule_l4_sport = p[ICMP].type rule_l4_dport = p[ICMP].code else: rule_l4_sport = p[ICMPv6Unknown].type rule_l4_dport = p[ICMPv6Unknown].code if p.haslayer(IPv6): rule_l4_proto = ulp_l4.overload_fields[IPv6]['nh'] else: rule_l4_proto = p[IP].proto new_rule = { 'is_permit': is_permit, 'is_ipv6': p.haslayer(IPv6), 'src_ip_addr': inet_pton(rule_family, p[rule_l3_layer].src), 'src_ip_prefix_len': rule_prefix_len, 'dst_ip_addr': inet_pton(rule_family, p[rule_l3_layer].dst), 'dst_ip_prefix_len': rule_prefix_len, 'srcport_or_icmptype_first': rule_l4_sport, 'srcport_or_icmptype_last': rule_l4_sport, 'dstport_or_icmpcode_first': rule_l4_dport, 'dstport_or_icmpcode_last': rule_l4_dport, 'proto': rule_l4_proto, } rules.append(new_rule) new_rule_permit = new_rule.copy() new_rule_permit['is_permit'] = 1 permit_rules.append(new_rule_permit) new_rule_permit_and_reflect = new_rule.copy() if can_reflect_this_packet: new_rule_permit_and_reflect['is_permit'] = 2 else: new_rule_permit_and_reflect['is_permit'] = is_permit permit_and_reflect_rules.append(new_rule_permit_and_reflect) self.logger.info("create_stream pkt#%d: %s" % (i, payload)) return {'stream': pkts, 'rules': rules, 'permit_rules': permit_rules, 'permit_and_reflect_rules': permit_and_reflect_rules}
def kbdecrypt(pkt, key=None, verbose=None, doMicCheck=False): """Decrypt Zigbee frames using AES CCM* with 32-bit MIC""" if verbose is None: verbose = conf.verb if key == None: if conf.killerbee_nkey == None: log_killerbee.error( "Cannot find decryption key. (Set conf.killerbee_nkey)") return None key = conf.killerbee_nkey if len(key) != 16: log_killerbee.error( "Invalid decryption key, must be a 16 byte string.") return None elif not pkt.haslayer(ZigbeeSecurityHeader) or not pkt.haslayer(ZigbeeNWK): log_killerbee.error( "Cannot decrypt frame without a ZigbeeSecurityHeader.") return None try: import zigbee_crypt except ImportError: log_killerbee.error( "Could not import zigbee_crypt extension, cryptographic functionality is not available." ) return None #TODO: Investigate and issue a different fix: # https://code.google.com/p/killerbee/issues/detail?id=30 # This function destroys the packet, therefore work on a copy - @cutaway pkt = pkt.copy() #this is hack to fix the below line pkt.nwk_seclevel = 5 #the issue appears to be when this is set # Now recreate 'pkt' by rebuilding the raw data and creating a new scapy Packet, because # scapy splits the data/mic according to the nwk_seclevel in the ZigbeeSecurityHeader when # the scapy Packet is created. The value of nwk_seclevel in the ZigbeeSecurityHeader does # not have to be accurate in the transmitted frame: the Zigbee NWK standard states that # the nwk_seclevel should be overwritten in the received frame with the value that is being # used by all nodes in the Zigbee network - this is to ensure that unencrypted frames can't be # maliciously injected. i.e. the receiver shouldn't trust the received nwk_seclevel. newpkt = pkt.build() if pkt.haslayer(Dot15d4FCS): pkt = Dot15d4FCS(newpkt) else: pkt = Dot15d4(newpkt) #mic = struct.unpack(">I", f['mic']) mic = pkt.mic f = pkt.getlayer(ZigbeeSecurityHeader).fields encrypted = f['data'] sec_ctrl_byte = str(pkt.getlayer(ZigbeeSecurityHeader))[0] # Bug fix thanks to cutaway (https://code.google.com/p/killerbee/issues/detail?id=25): #nonce = struct.pack('L',f['ext_source'])+struct.pack('I',f['fc']) + sec_ctrl_byte nonce = struct.pack('L', f['source']) + struct.pack( 'I', f['fc']) + sec_ctrl_byte #nonce = "" # build the nonce #nonce += struct.pack(">Q", f['ext_source']) #nonce += struct.pack(">I", f['fc']) #fc = (f['reserved1'] << 6) | (f['extended_nonce'] << 5) | (f['key_type'] << 3) | f['reserved2'] #nonce += chr(fc | 0x05) if verbose > 2: print "Decrypt Details:" print "\tKey: " + key.encode('hex') print "\tNonce: " + nonce.encode('hex') print "\tMic: " + mic.encode('hex') print "\tEncrypted Data: " + encrypted.encode('hex') # For zigbeeData, we need the entire zigbee packet, minus the encrypted data and mic (4 bytes). # So calculate an amount to crop, equal to the size of the encrypted data and mic. Note that # if there was an FCS, scapy will have already stripped it, so it will not returned by the # do_build() call below (and hence doesn't need to be taken into account in crop_size). crop_size = 4 + len(pkt.getlayer(ZigbeeSecurityHeader).fields['data']) # the Security Control Field flags have to be adjusted before this is calculated, so we store their original values so we can reset them later #reserved2 = pkt.getlayer(ZigbeeSecurityHeader).fields['reserved2'] #pkt.getlayer(ZigbeeSecurityHeader).fields['reserved2'] = (pkt.getlayer(ZigbeeSecurityHeader).fields['reserved2'] | 0x05) zigbeeData = pkt.getlayer(ZigbeeNWK).do_build() zigbeeData = zigbeeData[:-crop_size] #pkt.getlayer(ZigbeeSecurityHeader).fields['reserved2'] = reserved2 (payload, micCheck) = zigbee_crypt.decrypt_ccm(key, nonce, mic, encrypted, zigbeeData) if verbose > 2: print "\tDecrypted Data: " + payload.encode('hex') frametype = pkt.getlayer(ZigbeeNWK).fields['frametype'] if frametype == 0 and micCheck == 1: payload = ZigbeeAppDataPayload(payload) elif frametype == 1 and micCheck == 1: payload = ZigbeeNWKCommandPayload(payload) else: payload = Raw(payload) if doMicCheck == False: return payload else: if micCheck == 1: return (payload, True) else: return (payload, False)
from scapy.layers.inet import Ether from scapy.layers.inet import IP from scapy.layers.inet import UDP from scapy.packet import Raw from scapy.sendrecv import sendp DESTINATION_MAC_ADDR = "11:22:33:44:55:66" SOURCE_MAC_ADDR = "aa:bb:cc:dd:ee:ff" DESTINATION_IP_ADDR = "192.168.0.100" SOURCE_IP_ADDR = "192.168.0.123" DESTINATION_PORT = 8080 SOURCE_PORT = 10430 RAW_DATA = "68656c6c6f20776f726c64" # hello world NETWORK_INTERFACE = "Wi-Fi" ether_frame = Ether(src=SOURCE_MAC_ADDR, dst=DESTINATION_MAC_ADDR) ip_setting = IP(src=SOURCE_IP_ADDR, dst=DESTINATION_IP_ADDR) udp_setting = UDP(dport=DESTINATION_PORT, sport=SOURCE_PORT) udp_data = Raw(load=bytes.fromhex(RAW_DATA)) packet = ether_frame / ip_setting / udp_setting / udp_data sendp(packet, iface=NETWORK_INTERFACE)
def test_punt(self): """ Excpetion Path testing """ # # Using the test CLI we will hook in a exception path to # send ACL deny packets out of pg0 and pg1. # the ACL is src,dst = 1.1.1.1,1.1.1.2 # ip_1_1_1_2 = VppIpRoute(self, "1.1.1.2", 32, [VppRoutePath(self.pg3.remote_ip4, self.pg3.sw_if_index)]) ip_1_1_1_2.add_vpp_config() ip_1_2 = VppIpRoute(self, "1::2", 128, [VppRoutePath(self.pg3.remote_ip6, self.pg3.sw_if_index, proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) ip_1_2.add_vpp_config() p4 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IP(src="1.1.1.1", dst="1.1.1.2") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) p6 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IPv6(src="1::1", dst="1::2") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_expect(self.pg2, p4*1, self.pg3) self.send_and_expect(self.pg2, p6*1, self.pg3) # # apply the punting features # self.vapi.cli("test punt pg2") # # pkts now dropped # self.send_and_assert_no_replies(self.pg2, p4*NUM_PKTS) self.send_and_assert_no_replies(self.pg2, p6*NUM_PKTS) # # Check state: # 1 - node error counters # 2 - per-reason counters # 2, 3 are the index of the assigned punt reason # stats = self.statistics.get_counter( "/err/punt-dispatch/No registrations") self.assertEqual(stats, 2*NUM_PKTS) stats = self.statistics.get_counter("/net/punt") self.assertEqual(stats[0][7]['packets'], NUM_PKTS) self.assertEqual(stats[0][8]['packets'], NUM_PKTS) # # use the test CLI to test a client that punts exception # packets out of pg0 # self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip4) self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip6) rx4s = self.send_and_expect(self.pg2, p4*NUM_PKTS, self.pg0) rx6s = self.send_and_expect(self.pg2, p6*NUM_PKTS, self.pg0) # # check the packets come out IP unmodified but destined to pg0 host # for rx in rx4s: self.assertEqual(rx[Ether].dst, self.pg0.remote_mac) self.assertEqual(rx[Ether].src, self.pg0.local_mac) self.assertEqual(p4[IP].dst, rx[IP].dst) self.assertEqual(p4[IP].ttl, rx[IP].ttl) for rx in rx6s: self.assertEqual(rx[Ether].dst, self.pg0.remote_mac) self.assertEqual(rx[Ether].src, self.pg0.local_mac) self.assertEqual(p6[IPv6].dst, rx[IPv6].dst) self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim) stats = self.statistics.get_counter("/net/punt") self.assertEqual(stats[0][7]['packets'], 2*NUM_PKTS) self.assertEqual(stats[0][8]['packets'], 2*NUM_PKTS) # # add another registration for the same reason to send packets # out of pg1 # self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip4) self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip6) self.vapi.cli("clear trace") self.pg2.add_stream(p4 * NUM_PKTS) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rxd = self.pg0.get_capture(NUM_PKTS) for rx in rxd: self.assertEqual(rx[Ether].dst, self.pg0.remote_mac) self.assertEqual(rx[Ether].src, self.pg0.local_mac) self.assertEqual(p4[IP].dst, rx[IP].dst) self.assertEqual(p4[IP].ttl, rx[IP].ttl) rxd = self.pg1.get_capture(NUM_PKTS) for rx in rxd: self.assertEqual(rx[Ether].dst, self.pg1.remote_mac) self.assertEqual(rx[Ether].src, self.pg1.local_mac) self.assertEqual(p4[IP].dst, rx[IP].dst) self.assertEqual(p4[IP].ttl, rx[IP].ttl) self.vapi.cli("clear trace") self.pg2.add_stream(p6 * NUM_PKTS) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rxd = self.pg0.get_capture(NUM_PKTS) for rx in rxd: self.assertEqual(rx[Ether].dst, self.pg0.remote_mac) self.assertEqual(rx[Ether].src, self.pg0.local_mac) self.assertEqual(p6[IPv6].dst, rx[IPv6].dst) self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim) rxd = self.pg1.get_capture(NUM_PKTS) for rx in rxd: self.assertEqual(rx[Ether].dst, self.pg1.remote_mac) self.assertEqual(rx[Ether].src, self.pg1.local_mac) self.assertEqual(p6[IPv6].dst, rx[IPv6].dst) self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim) stats = self.statistics.get_counter("/net/punt") self.assertEqual(stats[0][7]['packets'], 3*NUM_PKTS) self.assertEqual(stats[0][8]['packets'], 3*NUM_PKTS) self.logger.info(self.vapi.cli("show vlib graph punt-dispatch")) self.logger.info(self.vapi.cli("show punt client")) self.logger.info(self.vapi.cli("show punt reason")) self.logger.info(self.vapi.cli("show punt stats")) self.logger.info(self.vapi.cli("show punt db"))