19a18283aSMarcin Smoczynski#!/usr/bin/env python3 2*1dc48bceSStephen Hemminger# SPDX-License-Identifier: BSD-3-Clause 39a18283aSMarcin Smoczynski 49a18283aSMarcin Smoczynskiimport fcntl 59a18283aSMarcin Smoczynskiimport pkg_resources 69a18283aSMarcin Smoczynskiimport socket 79a18283aSMarcin Smoczynskiimport struct 89a18283aSMarcin Smoczynskiimport sys 99a18283aSMarcin Smoczynskiimport unittest 109a18283aSMarcin Smoczynski 119a18283aSMarcin Smoczynski 129a18283aSMarcin Smoczynskiif sys.version_info < (3, 0): 139a18283aSMarcin Smoczynski print("Python3 is required to run this script") 149a18283aSMarcin Smoczynski sys.exit(1) 159a18283aSMarcin Smoczynski 169a18283aSMarcin Smoczynski 179a18283aSMarcin Smoczynskitry: 189a18283aSMarcin Smoczynski from scapy.all import Ether 199a18283aSMarcin Smoczynskiexcept ImportError: 209a18283aSMarcin Smoczynski print("Scapy module is required") 219a18283aSMarcin Smoczynski sys.exit(1) 229a18283aSMarcin Smoczynski 239a18283aSMarcin Smoczynski 249a18283aSMarcin SmoczynskiPKTTEST_REQ = [ 25f9ee2da6SMarcin Smoczynski "scapy>=2.4.3", 269a18283aSMarcin Smoczynski] 279a18283aSMarcin Smoczynski 289a18283aSMarcin Smoczynski 299a18283aSMarcin Smoczynskidef assert_requirements(req): 309a18283aSMarcin Smoczynski """ 319a18283aSMarcin Smoczynski assert requirement is met 329a18283aSMarcin Smoczynski req can hold a string or a list of strings 339a18283aSMarcin Smoczynski """ 349a18283aSMarcin Smoczynski try: 359a18283aSMarcin Smoczynski pkg_resources.require(req) 369a18283aSMarcin Smoczynski except (pkg_resources.DistributionNotFound, pkg_resources.VersionConflict) as e: 379a18283aSMarcin Smoczynski print("Requirement assertion: " + str(e)) 389a18283aSMarcin Smoczynski sys.exit(1) 399a18283aSMarcin Smoczynski 409a18283aSMarcin Smoczynski 419a18283aSMarcin SmoczynskiTAP_UNPROTECTED = "dtap1" 429a18283aSMarcin SmoczynskiTAP_PROTECTED = "dtap0" 439a18283aSMarcin Smoczynski 449a18283aSMarcin Smoczynski 459a18283aSMarcin Smoczynskiclass Interface(object): 469a18283aSMarcin Smoczynski ETH_P_ALL = 3 479a18283aSMarcin Smoczynski MAX_PACKET_SIZE = 1280 489a18283aSMarcin Smoczynski IOCTL_GET_INFO = 0x8927 499a18283aSMarcin Smoczynski SOCKET_TIMEOUT = 0.5 509a18283aSMarcin Smoczynski def __init__(self, ifname): 519a18283aSMarcin Smoczynski self.name = ifname 529a18283aSMarcin Smoczynski 539a18283aSMarcin Smoczynski # create and bind socket to specified interface 549a18283aSMarcin Smoczynski self.s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(Interface.ETH_P_ALL)) 559a18283aSMarcin Smoczynski self.s.settimeout(Interface.SOCKET_TIMEOUT) 569a18283aSMarcin Smoczynski self.s.bind((self.name, 0, socket.PACKET_OTHERHOST)) 579a18283aSMarcin Smoczynski 589a18283aSMarcin Smoczynski # get interface MAC address 599a18283aSMarcin Smoczynski info = fcntl.ioctl(self.s.fileno(), Interface.IOCTL_GET_INFO, struct.pack('256s', bytes(ifname[:15], encoding='ascii'))) 609a18283aSMarcin Smoczynski self.mac = ':'.join(['%02x' % i for i in info[18:24]]) 619a18283aSMarcin Smoczynski 629a18283aSMarcin Smoczynski def __del__(self): 639a18283aSMarcin Smoczynski self.s.close() 649a18283aSMarcin Smoczynski 659a18283aSMarcin Smoczynski def send_l3packet(self, pkt, mac): 669a18283aSMarcin Smoczynski e = Ether(src=self.mac, dst=mac) 679a18283aSMarcin Smoczynski self.send_packet(e/pkt) 689a18283aSMarcin Smoczynski 699a18283aSMarcin Smoczynski def send_packet(self, pkt): 709a18283aSMarcin Smoczynski self.send_bytes(bytes(pkt)) 719a18283aSMarcin Smoczynski 729a18283aSMarcin Smoczynski def send_bytes(self, bytedata): 739a18283aSMarcin Smoczynski self.s.send(bytedata) 749a18283aSMarcin Smoczynski 759a18283aSMarcin Smoczynski def recv_packet(self): 769a18283aSMarcin Smoczynski return Ether(self.recv_bytes()) 779a18283aSMarcin Smoczynski 789a18283aSMarcin Smoczynski def recv_bytes(self): 799a18283aSMarcin Smoczynski return self.s.recv(Interface.MAX_PACKET_SIZE) 809a18283aSMarcin Smoczynski 819a18283aSMarcin Smoczynski def get_mac(self): 829a18283aSMarcin Smoczynski return self.mac 839a18283aSMarcin Smoczynski 849a18283aSMarcin Smoczynski 859a18283aSMarcin Smoczynskiclass PacketXfer(object): 869a18283aSMarcin Smoczynski def __init__(self, protected_iface=TAP_PROTECTED, unprotected_iface=TAP_UNPROTECTED): 879a18283aSMarcin Smoczynski self.protected_port = Interface(protected_iface) 889a18283aSMarcin Smoczynski self.unprotected_port = Interface(unprotected_iface) 899a18283aSMarcin Smoczynski 909a18283aSMarcin Smoczynski def send_to_protected_port(self, pkt, remote_mac=None): 919a18283aSMarcin Smoczynski if remote_mac is None: 929a18283aSMarcin Smoczynski remote_mac = self.unprotected_port.get_mac() 939a18283aSMarcin Smoczynski self.protected_port.send_l3packet(pkt, remote_mac) 949a18283aSMarcin Smoczynski 959a18283aSMarcin Smoczynski def send_to_unprotected_port(self, pkt, remote_mac=None): 969a18283aSMarcin Smoczynski if remote_mac is None: 979a18283aSMarcin Smoczynski remote_mac = self.protected_port.get_mac() 989a18283aSMarcin Smoczynski self.unprotected_port.send_l3packet(pkt, remote_mac) 999a18283aSMarcin Smoczynski 1009a18283aSMarcin Smoczynski def xfer_unprotected(self, pkt): 1019a18283aSMarcin Smoczynski self.send_to_unprotected_port(pkt) 1029a18283aSMarcin Smoczynski return self.protected_port.recv_packet() 1039a18283aSMarcin Smoczynski 1049a18283aSMarcin Smoczynski def xfer_protected(self, pkt): 1059a18283aSMarcin Smoczynski self.send_to_protected_port(pkt) 1069a18283aSMarcin Smoczynski return self.unprotected_port.recv_packet() 1079a18283aSMarcin Smoczynski 1089a18283aSMarcin Smoczynski 1099a18283aSMarcin Smoczynskidef pkttest(): 1109a18283aSMarcin Smoczynski if len(sys.argv) == 1: 1119a18283aSMarcin Smoczynski sys.exit(unittest.main(verbosity=2)) 1129a18283aSMarcin Smoczynski elif len(sys.argv) == 2: 1139a18283aSMarcin Smoczynski if sys.argv[1] == "config": 1149a18283aSMarcin Smoczynski module = __import__('__main__') 1159a18283aSMarcin Smoczynski try: 1169a18283aSMarcin Smoczynski print(module.config()) 1179a18283aSMarcin Smoczynski except AttributeError: 1189a18283aSMarcin Smoczynski sys.stderr.write("Cannot find \"config()\" in a test") 1199a18283aSMarcin Smoczynski sys.exit(1) 1209a18283aSMarcin Smoczynski else: 1219a18283aSMarcin Smoczynski sys.exit(1) 1229a18283aSMarcin Smoczynski 1239a18283aSMarcin Smoczynski 1249a18283aSMarcin Smoczynskiif __name__ == "__main__": 1259a18283aSMarcin Smoczynski if len(sys.argv) == 2 and sys.argv[1] == "check_reqs": 1269a18283aSMarcin Smoczynski assert_requirements(PKTTEST_REQ) 1279a18283aSMarcin Smoczynski else: 1289a18283aSMarcin Smoczynski print("Usage: " + sys.argv[0] + " check_reqs") 129