| % Regression tests for Linux only | |
| # More information at http://www.secdev.org/projects/UTscapy/ | |
| ############ | |
| ############ | |
| + Linux only test | |
| = L3RawSocket | |
| ~ netaccess IP ICMP linux needs_root | |
| old_l3socket = conf.L3socket | |
| old_debug_dissector = conf.debug_dissector | |
| conf.debug_dissector = False | |
| conf.L3socket = L3RawSocket | |
| x = sr1(IP(dst="www.google.com")/ICMP(),timeout=3) | |
| conf.debug_dissector = old_debug_dissector | |
| conf.L3socket = old_l3socket | |
| x | |
| assert x[IP].ottl() in [32, 64, 128, 255] | |
| assert 0 <= x[IP].hops() <= 126 | |
| x is not None and ICMP in x and x[ICMP].type == 0 | |
| # TODO: fix this test (randomly stuck) | |
| # ex: https://travis-ci.org/secdev/scapy/jobs/247473497 | |
| #= Supersocket _flush_fd | |
| #~ needs_root linux | |
| # | |
| #import select | |
| # | |
| #from scapy.arch.linux import _flush_fd | |
| #socket = conf.L2listen() | |
| #select.select([socket],[],[],2) | |
| #_flush_fd(socket.ins) | |
| = Interface aliases & sub-interfaces | |
| ~ linux needs_root | |
| import os | |
| exit_status = os.system("ip link add name scapy0 type dummy") | |
| exit_status = os.system("ip addr add 192.0.2.1/24 dev scapy0") | |
| exit_status = os.system("ip link set scapy0 up") | |
| exit_status = os.system("ifconfig scapy0:0 inet 198.51.100.1/24 up") | |
| if exit_status == 0: | |
| exit_status = os.system("ip addr show scapy0") | |
| print(get_if_list()) | |
| conf.route.resync() | |
| print(conf.route.routes) | |
| assert(conf.route.route("198.51.100.254") == ("scapy0", "198.51.100.1", "0.0.0.0")) | |
| route_alias = (3325256704, 4294967040, "0.0.0.0", "scapy0", "198.51.100.1", 0) | |
| assert(route_alias in conf.route.routes) | |
| exit_status = os.system("ip link add link scapy0 name scapy0.42 type vlan id 42") | |
| exit_status = os.system("ip addr add 203.0.113.42/24 dev scapy0.42") | |
| exit_status = os.system("ip link set scapy0.42 up") | |
| exit_status = os.system("ip route add 192.0.2.43/32 via 203.0.113.41") | |
| print(get_if_list()) | |
| conf.route.resync() | |
| print(conf.route.routes) | |
| assert(conf.route.route("192.0.2.43") == ("scapy0.42", "203.0.113.42", "203.0.113.41")) | |
| route_specific = (3221226027, 4294967295, "203.0.113.41", "scapy0.42", "203.0.113.42", 0) | |
| assert(route_specific in conf.route.routes) | |
| exit_status = os.system("ip link del name dev scapy0") | |
| else: | |
| assert True | |
| = catch loopback device missing | |
| ~ linux needs_root | |
| from mock import patch | |
| # can't remove the lo device (or its address without causing trouble) - use some pseudo dummy instead | |
| with patch('scapy.arch.linux.conf.loopback_name', 'scapy_lo_x'): | |
| routes = read_routes() | |
| = catch loopback device no address assigned | |
| ~ linux needs_root | |
| import os, socket | |
| from mock import patch | |
| exit_status = os.system("ip link add name scapy_lo type dummy") | |
| assert(exit_status == 0) | |
| exit_status = os.system("ip link set dev scapy_lo up") | |
| assert(exit_status == 0) | |
| with patch('scapy.arch.linux.conf.loopback_name', 'scapy_lo'): | |
| routes = read_routes() | |
| exit_status = os.system("ip addr add dev scapy_lo 10.10.0.1/24") | |
| assert(exit_status == 0) | |
| with patch('scapy.arch.linux.conf.loopback_name', 'scapy_lo'): | |
| routes = read_routes() | |
| got_lo_device = False | |
| for route in routes: | |
| dst_int, msk_int, gw_str, if_name, if_addr, metric = route | |
| if if_name == 'scapy_lo': | |
| got_lo_device = True | |
| assert(if_addr == '10.10.0.1') | |
| dst_addr = socket.inet_ntoa(struct.pack("!I", dst_int)) | |
| assert(dst_addr == '10.10.0.0') | |
| msk = socket.inet_ntoa(struct.pack("!I", msk_int)) | |
| assert (msk == '255.255.255.0') | |
| break | |
| assert(got_lo_device) | |
| exit_status = os.system("ip link del dev scapy_lo") | |
| assert(exit_status == 0) | |
| = IPv6 link-local address selection | |
| IFACES._add_fake_iface("scapy0") | |
| from mock import patch | |
| conf.route6.routes = [('fe80::', 64, '::', 'scapy0', ['fe80::e039:91ff:fe79:1910'], 256)] | |
| conf.route6.ipv6_ifaces = set(['scapy0']) | |
| bck_conf_iface = conf.iface | |
| conf.iface = "scapy0" | |
| with patch("scapy.layers.l2.get_if_hwaddr") as mgih: | |
| mgih.return_value = 'e2:39:91:79:19:10' | |
| p = Ether()/IPv6(dst="ff02::1")/ICMPv6NIQueryName(data="ff02::1") | |
| print(p.sprintf("%Ether.src% > %Ether.dst%\n%IPv6.src% > %IPv6.dst%")) | |
| ip6_ll_address = 'fe80::e039:91ff:fe79:1910' | |
| print(p[IPv6].src, ip6_ll_address) | |
| assert p[IPv6].src == ip6_ll_address | |
| mac_address = 'e2:39:91:79:19:10' | |
| print(p[Ether].src, mac_address) | |
| assert p[Ether].src == mac_address | |
| conf.iface = bck_conf_iface | |
| conf.route6.resync() | |
| = IPv6 | |
| ~ linux | |
| addrs = in6_getifaddr() | |
| if len(addrs) == 0: | |
| assert True | |
| else: | |
| assert all([in6_isvalid(addr[0]) for addr in in6_getifaddr()]) | |
| assert set([addr[2] for addr in in6_getifaddr()]) == conf.route6.ipv6_ifaces | |
| = veth interface error handling | |
| ~ linux needs_root veth | |
| try: | |
| veth = VEthPair('this_IF_name_is_to_long_and_will_cause_an_error', 'veth_scapy_1') | |
| veth.setup() | |
| assert False | |
| except subprocess.CalledProcessError: | |
| pass | |
| except Exception: | |
| assert False | |
| = veth interface usage - ctx manager | |
| ~ linux needs_root veth | |
| from threading import Condition | |
| cond_started = Condition() | |
| def _sniffer_started(): | |
| global cond_started | |
| cond_started.acquire() | |
| cond_started.notify() | |
| cond_started.release() | |
| cond_started.acquire() | |
| try: | |
| with VEthPair('veth_scapy_0', 'veth_scapy_1') as veth: | |
| if_list = get_if_list() | |
| assert ('veth_scapy_0' in if_list) | |
| assert ('veth_scapy_1' in if_list) | |
| frm_count = 0 | |
| def _sniffer(): | |
| sniffed = sniff(iface='veth_scapy_1', | |
| store=True, | |
| count=2, | |
| lfilter=lambda p: Ether in p and p[Ether].type == 0xbeef, | |
| started_callback=_sniffer_started) | |
| global frm_count | |
| frm_count = 2 | |
| t_sniffer = Thread(target=_sniffer) | |
| t_sniffer.start() | |
| cond_started.wait() | |
| sendp(Ether(type=0xbeef)/Raw(b'0123456789'), | |
| iface='veth_scapy_0', | |
| count=2) | |
| t_sniffer.join(1) | |
| assert(frm_count == 2) | |
| if_list = get_if_list() | |
| assert ('veth_scapy_0' not in if_list) | |
| assert ('veth_scapy_1' not in if_list) | |
| except subprocess.CalledProcessError: | |
| assert False | |
| except Exception: | |
| assert False | |
| = veth interface usage - manual interface handling | |
| ~ linux needs_root veth | |
| from threading import Condition | |
| cond_started = Condition() | |
| def _sniffer_started(): | |
| global cond_started | |
| cond_started.acquire() | |
| cond_started.notify() | |
| cond_started.release() | |
| cond_started.acquire() | |
| veth = VEthPair('veth_scapy_0', 'veth_scapy_1') | |
| try: | |
| veth.setup() | |
| veth.up() | |
| except subprocess.CalledProcessError: | |
| assert False | |
| except Exception: | |
| assert False | |
| conf.ifaces.reload() | |
| if_list = get_if_list() | |
| assert ('veth_scapy_0' in if_list) | |
| assert ('veth_scapy_1' in if_list) | |
| frm_count = 0 | |
| def _sniffer(): | |
| sniffed = sniff(iface='veth_scapy_1', | |
| store=True, | |
| count=2, | |
| lfilter=lambda p: Ether in p and p[Ether].type == 0xbeef, | |
| started_callback=_sniffer_started) | |
| global frm_count | |
| frm_count = 2 | |
| t_sniffer = Thread(target=_sniffer) | |
| t_sniffer.start() | |
| cond_started.wait() | |
| sendp(Ether(type=0xbeef)/Raw(b'0123456789'), | |
| iface='veth_scapy_0', | |
| count=2) | |
| t_sniffer.join(1) | |
| assert(frm_count == 2) | |
| try: | |
| veth.down() | |
| veth.destroy() | |
| conf.ifaces.reload() | |
| if_list = get_if_list() | |
| assert ('veth_scapy_0' not in if_list) | |
| assert ('veth_scapy_1' not in if_list) | |
| except subprocess.CalledProcessError: | |
| assert False | |
| except Exception: | |
| assert False | |
| = Routing table, interface with no names | |
| ~ linux | |
| from mock import patch | |
| @patch("scapy.arch.linux.ioctl") | |
| def test_read_routes(mock_ioctl): | |
| def raise_ioerror(*args, **kwargs): | |
| if args[1] == 0x8912: | |
| return args[2] | |
| raise IOError | |
| mock_ioctl.side_effect = raise_ioerror | |
| read_routes() | |
| test_read_routes() | |
| = L3PacketSocket sendto exception | |
| ~ linux needs_root | |
| if six.PY3: | |
| import mock, six, socket | |
| @mock.patch("scapy.arch.linux.socket.socket.sendto") | |
| def test_L3PacketSocket_sendto_python3(mock_sendto): | |
| mock_sendto.side_effect = OSError(22, 2807) | |
| l3ps = L3PacketSocket() | |
| l3ps.send(IP(dst="8.8.8.8")/ICMP()) | |
| return True | |
| assert test_L3PacketSocket_sendto_python3() | |
| = Test _interface_selection | |
| ~ netaccess linux needs_root | |
| import os | |
| from scapy.sendrecv import _interface_selection | |
| assert _interface_selection(None, IP(dst="8.8.8.8")/UDP()) == conf.iface | |
| exit_status = os.system("ip link add name scapy0 type dummy") | |
| exit_status = os.system("ip addr add 192.0.2.1/24 dev scapy0") | |
| exit_status = os.system("ip link set scapy0 up") | |
| assert _interface_selection(None, IP(dst="192.0.2.42")/UDP()) == "scapy0" | |
| exit_status = os.system("ip link del name dev scapy0") | |
| = Test 802.Q sniffing | |
| ~ linux needs_root python3_only | |
| from threading import Thread, Condition | |
| veth = VEthPair("left0", "right0") | |
| veth.setup() | |
| veth.up() | |
| exit_status = os.system("ip link add link right0 name vlanright0 type vlan id 42") | |
| exit_status = os.system("ip link add link left0 name vlanleft0 type vlan id 42") | |
| exit_status = os.system("ip link set vlanright0 up") | |
| exit_status = os.system("ip link set vlanleft0 up") | |
| exit_status = os.system("ip addr add 198.51.100.1/24 dev vlanleft0") | |
| exit_status = os.system("ip addr add 198.51.100.2/24 dev vlanright0") | |
| cond_started = Condition() | |
| def _sniffer_started(): | |
| global cond_started | |
| cond_started.acquire() | |
| cond_started.notify() | |
| cond_started.release() | |
| cond_started.acquire() | |
| dot1q_count = 0 | |
| def _sniffer(): | |
| sniffed = sniff(iface="right0", | |
| lfilter=lambda p: Dot1Q in p, | |
| count=2, | |
| timeout=5, | |
| started_callback=_sniffer_started) | |
| global dot1q_count | |
| dot1q_count = len(sniffed) | |
| t_sniffer = Thread(target=_sniffer) | |
| t_sniffer.start() | |
| cond_started.wait() | |
| sendp(Ether()/IP(dst="198.51.100.2")/ICMP(), iface='vlanleft0', count=2) | |
| t_sniffer.join(1) | |
| assert(dot1q_count == 2) | |
| veth.destroy() | |
| = Reload interfaces & routes | |
| conf.ifaces.reload() | |
| conf.route.resync() | |
| conf.route6.resync() |