Skip to content

Commit c21e446

Browse files
committed
Use IPv6 default route when no IPv4 is available
1 parent 58519e5 commit c21e446

File tree

3 files changed

+33
-0
lines changed

3 files changed

+33
-0
lines changed

doc/scapy/usage.rst

+3
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,9 @@ make\_table() displays a table according to a lambda function
226226
Sending packets
227227
---------------
228228

229+
.. note::
230+
Scapy automatically detects the network interface to be used by default, and stores this result in ``conf.iface``. Packets built by Scapy uses this variable to set relevant fields such as Ethernet source addresses. When sending packets, with functions such as ``send()``, Scapy will use the network interface stored in ``conf.iface``. This behavior can be changed using the ``iface=`` argument. With IPv6 and link-local addresses, it is mandatory to setup both ``conf.iface`` and ``iface=`` the same value to get the desired result, as Scapy cannot find which interface to use for link-local communications.
231+
229232
.. index::
230233
single: Sending packets, send
231234

scapy/interfaces.py

+16
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,8 @@ def get_if_list():
372372
def get_working_if():
373373
# type: () -> NetworkInterface
374374
"""Return an interface that works"""
375+
376+
# IPv4
375377
# return the interface associated with the route with smallest
376378
# mask (route by default if it exists)
377379
routes = conf.route.routes[:]
@@ -383,6 +385,20 @@ def get_working_if():
383385
iface = resolve_iface(ifname) # type: ignore
384386
if iface.is_valid():
385387
return iface
388+
389+
# IPv6
390+
routes_ipv6 = conf.route6.routes
391+
default_routes_ipv6 = [r for r in routes_ipv6 if r[0] == "::"]
392+
if default_routes_ipv6:
393+
# Sort the default routes using the priority (at index -1)
394+
tmp_routes = sorted(default_routes_ipv6, key=lambda r: r[-1])
395+
396+
# Return the interface (at index 2) of the highest priority default
397+
ifname = tmp_routes[-1][2]
398+
iface = resolve_iface(ifname)
399+
if iface.is_valid():
400+
return iface
401+
386402
# There is no hope left
387403
return resolve_iface(conf.loopback_name)
388404

test/regression.uts

+14
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,20 @@ assert "cuz you know the way to go" + conf.iface # right +
334334

335335
_test_get_working_if()
336336

337+
# Test IPv6 default route interface selection
338+
ni = NetworkInterface(InterfaceProvider(), {"name": "scapy0", "ips": ["::1"], "mac": "aa:aa:aa:aa:aa:aa"})
339+
340+
import mock
341+
@mock.patch("scapy.interfaces.conf.route.routes")
342+
@mock.patch("scapy.interfaces.conf.route6.routes")
343+
def _test_get_working_if_v6(rou6, rou):
344+
rou = []
345+
rou6 = [("::", 0, "", ni, [""], 0)]
346+
print(get_working_if())
347+
assert get_working_if() == ni
348+
349+
_test_get_working_if_v6()
350+
337351
= Test conf.ifaces
338352

339353
conf.iface

0 commit comments

Comments
 (0)