mirror of https://github.com/secdev/scapy.git
Merge pull request #1037 from gpotter2/win-metrics-fix
[Windows] Guess metrics when InterfaceMetric is not available
This commit is contained in:
commit
7ce1152b25
|
@ -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 = ["(.*)"]
|
||||
|
|
|
@ -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()
|
||||
|
||||
############
|
||||
############
|
||||
|
|
Loading…
Reference in New Issue