diff --git a/scapy/arch/windows/__init__.py b/scapy/arch/windows/__init__.py index 9c40ec76b..664197086 100755 --- a/scapy/arch/windows/__init__.py +++ b/scapy/arch/windows/__init__.py @@ -843,8 +843,29 @@ def read_routes(): warning("No default IPv4 routes found. Your Windows release may no be supported and you have to enter your routes manually", onlyOnce=True) return routes +def _get_metrics(ipv6=False): + """Returns a dict containing all IPv4 or IPv6 interfaces' metric, + ordered by their interface index. + """ + query_cmd = "netsh interface " + ("ipv6" if ipv6 else "ipv4") + " show interfaces level=verbose" + stdout = POWERSHELL_PROCESS.query([query_cmd]) + res = {} + _buffer = [] + _pattern = re.compile(".*:\s+(\d+)") + for _line in stdout: + if not _line.strip(): + continue + _buffer.append(_line) + if len(_buffer) == 32: # An interface, with all its parameters, is 32 lines long + if_index = re.search(_pattern, _buffer[3]).group(1) + if_metric = int(re.search(_pattern, _buffer[5]).group(1)) + res[if_index] = if_metric + _buffer = [] + return res + def _read_routes_post2008(): routes = [] + if4_metrics = None # This works only starting from Windows 8/2012 and up. For older Windows another solution is needed # Get-NetRoute -AddressFamily IPV4 | select ifIndex, DestinationPrefix, NextHop, RouteMetric, InterfaceMetric | fl for line in exec_query(['Get-NetRoute', '-AddressFamily IPV4'], ['ifIndex', 'DestinationPrefix', 'NextHop', 'RouteMetric', 'InterfaceMetric']): @@ -861,8 +882,14 @@ def _read_routes_post2008(): # continue dest, mask = line[1].split('/') ip = "127.0.0.1" if line[0] == "1" else iface.ip # Force loopback on iface 1 + if not line[4].strip(): # InterfaceMetric is not available. Load it from netsh + if not if4_metrics: + if4_metrics = _get_metrics() + metric = int(line[3]) + if4_metrics.get(iface.win_index, 0) # RouteMetric + InterfaceMetric + else: + metric = int(line[3]) + int(line[4]) # RouteMetric + InterfaceMetric routes.append((atol(dest), itom(int(mask)), - line[2], iface, ip, int(line[3])+int(line[4]))) + line[2], iface, ip, metric)) return routes ############ @@ -918,33 +945,13 @@ def _read_routes6_post2008(): _append_route6(routes6, dpref, dp, nh, iface, lifaddr, metric) return routes6 -def _get_i6_metric(): - """Returns a dict containing all IPv6 interfaces' metric, - ordered by their interface index. - """ - query_cmd = "netsh interface ipv6 show interfaces level=verbose" - stdout = POWERSHELL_PROCESS.query([query_cmd]) - res = {} - _buffer = [] - _pattern = re.compile(".*:\s+(\d+)") - for _line in stdout: - if not _line.strip(): - continue - _buffer.append(_line) - if len(_buffer) == 32: # An interface, with all its parameters, is 32 lines long - if_index = re.search(_pattern, _buffer[3]).group(1) - if_metric = int(re.search(_pattern, _buffer[5]).group(1)) - res[if_index] = if_metric - _buffer = [] - return res - def _read_routes6_7(): # Not supported in powershell, we have to use netsh routes = [] query_cmd = "netsh interface ipv6 show route level=verbose" stdout = POWERSHELL_PROCESS.query([query_cmd]) lifaddr = in6_getifaddr() - if6_metrics = _get_i6_metric() + if6_metrics = _get_metrics(ipv6=True) # Define regexes r_int = [".*:\s+(\d+)"] r_all = ["(.*)"] diff --git a/test/mock_windows.uts b/test/mock_windows.uts index bd24a226c..b016294bc 100644 --- a/test/mock_windows.uts +++ b/test/mock_windows.uts @@ -158,6 +158,40 @@ InterfaceMetric : 256 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() ############ ############