| % Regression tests on Windows only for Scapy |
| |
| # More informations at http://www.secdev.org/projects/UTscapy/ |
| |
| ############ |
| ############ |
| + Networking tests |
| |
| = Automaton - SelectableSelector system timeout |
| |
| class TimeOutSelector(SelectableObject): |
| def check_recv(self): |
| return False |
| |
| assert select_objects([TimeOutSelector()], 0) == [] |
| assert select_objects([TimeOutSelector()], 1) == [] |
| |
| ############ |
| ############ |
| + Windows Networking tests |
| |
| = Mocked read_routes6() calls |
| |
| import mock |
| from scapy.tools.UTscapy import Bunch |
| from scapy.arch.windows import _read_routes6_post2008 |
| |
| def check_mandatory_ipv6_routes(routes6): |
| """Ensure that mandatory IPv6 routes are present.""" |
| if len([r for r in routes6 if r[0] == "::" and r[4] == ["::1"]]) < 1: |
| return False |
| if len([r for r in routes6 if r[0] == "fe80::" and (r[1] == 64 or r[1] == 32)]) < 1: |
| return False |
| if len([r for r in routes6 if in6_islladdr(r[0]) and r[1] == 128]) < 1: |
| return False |
| return True |
| |
| def dev_from_index_custom(if_index): |
| if_list = [{'mac': 'D0:50:99:56:DD:F9', 'win_index': '13', 'guid': '{C56DFFB3-992C-4964-B000-3E7C0F76E8BA}', 'name': 'Killer E2200 Gigabit Ethernet Controller', 'description': 'Ethernet'}, {'mac': '00:FF:0E:C7:25:37', 'win_index': '3', 'guid': '{0EC72537-B662-4F5D-B34E-48BFAE799BBE}', 'name': 'TAP-Windows Adapter V9', 'description': 'Ethernet 2'}] |
| values = {} |
| for i in if_list: |
| try: |
| interface = NetworkInterface(i) |
| values[interface.guid] = interface |
| except (KeyError, PcapNameNotFoundError): |
| pass |
| for devname, iface in values.items(): |
| if iface.win_index == str(if_index): |
| return iface |
| raise ValueError("Unknown network interface index %r" % if_index) |
| |
| @mock.patch("scapy.arch.windows.construct_source_candidate_set") |
| @mock.patch("scapy.arch.windows.get_if_list") |
| @mock.patch("scapy.arch.windows.dev_from_index") |
| @mock.patch("scapy.arch.windows.POWERSHELL_PROCESS.query") |
| def test_read_routes6_windows(mock_comm, mock_dev_from_index, mock_winpcapylist, mock_utils6cset): |
| """Test read_routes6() on Windows""" |
| # 'Get-NetRoute -AddressFamily IPV6 | select ifIndex, DestinationPrefix, NextHop' |
| get_net_route_output = """ |
| ifIndex : 3 |
| DestinationPrefix : ff00::/8 |
| NextHop : :: |
| RouteMetric : 0 |
| InterfaceMetric : 1 |
| |
| ifIndex : 16 |
| DestinationPrefix : ff00::/8 |
| NextHop : :: |
| RouteMetric : 0 |
| InterfaceMetric : 1 |
| |
| ifIndex : 13 |
| DestinationPrefix : ff00::/8 |
| NextHop : :: |
| RouteMetric : 0 |
| InterfaceMetric : 1 |
| |
| ifIndex : 1 |
| DestinationPrefix : ff00::/8 |
| NextHop : :: |
| RouteMetric : 0 |
| InterfaceMetric : 1 |
| |
| ifIndex : 13 |
| DestinationPrefix : fe80::dc1d:24e8:af00:125e/128 |
| NextHop : :: |
| RouteMetric : 20 |
| InterfaceMetric : 256 |
| |
| ifIndex : 3 |
| DestinationPrefix : fe80::9402:5804:cb16:fb3b/128 |
| NextHop : :: |
| RouteMetric : 1 |
| InterfaceMetric : 0 |
| |
| ifIndex : 16 |
| DestinationPrefix : fe80::100:7f:fffe/128 |
| NextHop : :: |
| RouteMetric : 1 |
| InterfaceMetric : 0 |
| |
| ifIndex : 3 |
| DestinationPrefix : fe80::/64 |
| NextHop : :: |
| RouteMetric : 0 |
| InterfaceMetric : 1 |
| |
| ifIndex : 16 |
| DestinationPrefix : fe80::/64 |
| NextHop : :: |
| RouteMetric : 0 |
| InterfaceMetric : 1 |
| |
| ifIndex : 13 |
| DestinationPrefix : fe80::/64 |
| NextHop : :: |
| RouteMetric : 0 |
| InterfaceMetric : 1 |
| |
| ifIndex : 13 |
| DestinationPrefix : 2a01:e35:2f17:fe60:dc1d:24e8:af00:125e/128 |
| NextHop : :: |
| RouteMetric : 20 |
| InterfaceMetric : 256 |
| |
| ifIndex : 13 |
| DestinationPrefix : 2a01:e35:2f17:fe60::/64 |
| NextHop : :: |
| RouteMetric : 30 |
| InterfaceMetric : 256 |
| |
| ifIndex : 1 |
| DestinationPrefix : ::1/128 |
| NextHop : :: |
| RouteMetric : 0 |
| InterfaceMetric : 256 |
| |
| ifIndex : 13 |
| DestinationPrefix : ::/0 |
| NextHop : fe80::224:d4ff:fea0:a6d7 |
| RouteMetric : 0 |
| InterfaceMetric : 256 |
| """ |
| mock_comm.return_value = get_net_route_output.split("\n") |
| mock_winpcapylist.return_value = [u'\\Device\\NPF_{0EC72537-B662-4F5D-B34E-48BFAE799BBE}', u'\\Device\\NPF_{C56DFFB3-992C-4964-B000-3E7C0F76E8BA}'] |
| # Mocked in6_getifaddr() output |
| mock_dev_from_index.side_effect = dev_from_index_custom |
| # Random |
| mock_utils6cset.side_effect = lambda x,y,z: ["::1"] if x=="::" else ["fdbb:d995:ddd8:51fc::"] |
| # Test the function |
| routes = _read_routes6_post2008() |
| for r in routes: |
| print(r) |
| print(len(routes)) |
| assert(len(routes) == 9) |
| assert(check_mandatory_ipv6_routes(routes)) |
| |
| |
| test_read_routes6_windows() |
| |
| = Test _read_routes_post2008 with missing InterfaceMetric |
| |
| from scapy.arch.windows import _read_routes_post2008 |
| |
| @mock.patch("scapy.arch.windows._get_metrics") |
| @mock.patch("scapy.arch.windows.POWERSHELL_PROCESS.query") |
| @mock.patch("scapy.arch.windows.get_if_list") |
| @mock.patch("scapy.arch.windows.dev_from_index") |
| def test_missing_ifacemetric(mock_dev_from_index, mock_winpcapylist, mock_exec_query, mock_get_metrics): |
| exc_query_output = """ifIndex : 3 |
| DestinationPrefix : 255.255.255.255/0 |
| NextHop : 192.168.103.1 |
| RouteMetric : 10 |
| InterfaceMetric : 256 |
| |
| ifIndex : 13 |
| DestinationPrefix : 255.255.255.255/32 |
| NextHop : 0.0.0.0 |
| RouteMetric : 20 |
| InterfaceMetric : |
| """ |
| mock_exec_query.side_effect = lambda *args, **kargs: exc_query_output.split("\n") |
| mock_winpcapylist.return_value = [u'\\Device\\NPF_{0EC72537-B662-4F5D-B34E-48BFAE799BBE}', u'\\Device\\NPF_{C56DFFB3-992C-4964-B000-3E7C0F76E8BA}'] |
| mock_dev_from_index.side_effect = dev_from_index_custom |
| mock_get_metrics.side_effect = lambda: {'16': 0, '13': 123} |
| routes = _read_routes_post2008() |
| for r in routes: |
| print(r) |
| assert len(routes) == 2 |
| # Test if metrics were correctly read/guessed |
| assert routes[0][5] == 266 |
| assert routes[1][5] == 143 |
| |
| test_missing_ifacemetric() |
| |
| = Test _get_metrics with weird netsh length |
| |
| from scapy.arch.windows import _get_metrics |
| |
| @mock.patch("scapy.arch.windows.POWERSHELL_PROCESS.query") |
| def test_get_metrics(mock_exec_query): |
| exc_query_output = """Interface Loopback Pseudo-Interface 1 Parameters |
| ------------------------------- |
| IfLuid : loopback_0 |
| IfIndex : 1 |
| State : connected |
| Metric : 75 |
| Link MTU : 4294967295 byt |
| Reachable Time : 40500 ms |
| Base Reachable Time : 30000 ms |
| Retransmission Interval : 1000 ms |
| DAD Transmits : 0 |
| Site Prefix Length : 64 |
| Site Id : 1 |
| Forwarding : disabled |
| Advertising : disabled |
| Neighbor Discovery : disabled |
| Neighbor Unreachability Detection : disabled |
| Router Discovery : dhcp |
| Managed Address Configuration : enabled |
| Other Stateful Configuration : enabled |
| Weak Host Sends : disabled |
| Weak Host Receives : disabled |
| Use Automatic Metric : enabled |
| Ignore Default Routes : disabled |
| Advertised Router Lifetime : 1800 seconds |
| Advertise Default Route : disabled |
| Current Hop Limit : 0 |
| Force ARPND Wake up patterns : disabled |
| Directed MAC Wake up patterns : disabled |
| ECN capability : application |
| |
| Interface Wi-Fi Parameters |
| ------------------------------- |
| IfLuid : wireless_32768 |
| IfIndex : 7 |
| State : connected |
| Metric : 55 |
| Link MTU : 1500 bytes |
| Reachable Time : 43500 ms |
| Base Reachable Time : 30000 ms |
| Retransmission Interval : 1000 ms |
| DAD Transmits : 3 |
| Site Prefix Length : 64 |
| Site Id : 1 |
| Forwarding : disabled |
| Advertising : disabled |
| Neighbor Discovery : enabled |
| Neighbor Unreachability Detection : enabled |
| Router Discovery : dhcp |
| Managed Address Configuration : enabled |
| Other Stateful Configuration : enabled |
| Weak Host Sends : disabled |
| Weak Host Receives : disabled |
| Use Automatic Metric : enabled |
| Ignore Default Routes : disabled |
| Advertised Router Lifetime : 1800 seconds |
| Advertise Default Route : disabled |
| Current Hop Limit : 0 |
| Force ARPND Wake up patterns : disabled |
| Directed MAC Wake up patterns : disabled |
| ECN capability : application |
| """ |
| mock_exec_query.side_effect = lambda *args, **kargs: exc_query_output.split("\n") |
| metrics = _get_metrics() |
| print(metrics) |
| assert metrics == {'1': 75, '7': 55} |
| |
| test_get_metrics() |
| |
| ############ |
| ############ |
| + Windows arch unit tests |
| |
| = Test PowerShell availability |
| from scapy.config import conf |
| assert conf.prog.powershell != None |
| |
| = Store powershell results |
| import mock |
| from scapy.config import conf |
| |
| ps_ip = get_ip_from_name(conf.iface.name) |
| ps_if_list = get_windows_if_list() |
| ps_read_routes = read_routes() |
| |
| # Turn on VBS mode |
| conf.prog.powershell = None |
| |
| = Test get_ip_from_name with VBS |
| ps_ip |
| |
| assert get_ip_from_name(conf.iface.name) == ps_ip |
| |
| = Test get_windows_if_list with VBS |
| ps_if_list |
| |
| def is_in_if_list(i, list): |
| if not i["mac"]: |
| return True |
| for j in list: |
| if j["guid"] == i["guid"] and j["name"] == i["name"]: |
| return True |
| return False |
| |
| vbs_if_list = get_windows_if_list() |
| vbs_if_list |
| _correct = True |
| for i in vbs_if_list: |
| if not is_in_if_list(i, ps_if_list): |
| _correct = False |
| break |
| |
| assert _correct |
| |
| = Test read_routes with VBS |
| ps_read_routes |
| |
| def is_in_route_list(i, list): |
| # Ignore all empty IP or macs |
| if i[4] == '': |
| return True |
| if i[3].mac == '' or i[3].guid == '' or i[3].ip == '': |
| return True |
| for j in list: |
| if j[2] == i[2] and j[4] == i[4] and j[3].guid == i[3].guid: |
| return True |
| return False |
| |
| vbs_read_routes = read_routes() |
| vbs_if_list |
| _correct = True |
| for i in vbs_read_routes: |
| if not is_in_route_list(i, ps_read_routes): |
| _correct = False |
| break |
| |
| assert _correct |
| |
| conf.prog._reload() |
| |
| = show_interfaces |
| |
| from scapy.arch import show_interfaces |
| |
| with ContextManagerCaptureOutput() as cmco: |
| show_interfaces() |
| lines = cmco.get_output().split("\n")[1:] |
| for l in lines: |
| if not l.strip(): |
| continue |
| int(l[:2]) |
| |
| = dev_from_pcapname |
| |
| from scapy.config import conf |
| |
| assert dev_from_pcapname(conf.iface.pcap_name).guid == conf.iface.guid |
| |
| = test pcap_service_status |
| |
| status = pcap_service_status() |
| status |
| assert status[0] in ["npcap", "npf"] |
| assert status[2] == True |
| |
| = test pcap_service_stop |
| |
| pcap_service_stop() |
| assert pcap_service_status()[2] == False |
| |
| = test pcap_service_start |
| |
| pcap_service_start() |
| assert pcap_service_status()[2] == True |
| |
| = Test auto-pcap start UI |
| |
| old_ifaces = IFACES.data |
| |
| @mock.patch("scapy.arch.windows.get_if_list") |
| def _test_autostart_ui(mocked_getiflist): |
| mocked_getiflist.side_effect = lambda: [] |
| IFACES.reload() |
| assert IFACES.data == {} |
| |
| _test_autostart_ui() |
| |
| IFACES.data = old_ifaces |