diff --git a/doc/scapy/usage.rst b/doc/scapy/usage.rst index af2e3a8bbf2..9338c622478 100644 --- a/doc/scapy/usage.rst +++ b/doc/scapy/usage.rst @@ -225,6 +225,9 @@ make\_table() displays a table according to a lambda function Sending packets --------------- +.. note:: + 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. + .. index:: single: Sending packets, send diff --git a/scapy/interfaces.py b/scapy/interfaces.py index f40f529ea8b..3059db2c1d9 100644 --- a/scapy/interfaces.py +++ b/scapy/interfaces.py @@ -372,6 +372,8 @@ def get_if_list(): def get_working_if(): # type: () -> NetworkInterface """Return an interface that works""" + + # IPv4 # return the interface associated with the route with smallest # mask (route by default if it exists) routes = conf.route.routes[:] @@ -383,6 +385,20 @@ def get_working_if(): iface = resolve_iface(ifname) # type: ignore if iface.is_valid(): return iface + + # IPv6 + routes_ipv6 = conf.route6.routes + default_routes_ipv6 = [r for r in routes_ipv6 if r[0] == "::"] + if default_routes_ipv6: + # Sort the default routes using the priority (at index -1) + tmp_routes = sorted(default_routes_ipv6, key=lambda r: r[-1]) + + # Return the interface (at index 2) of the highest priority default + ifname = tmp_routes[-1][2] + iface = resolve_iface(ifname) + if iface.is_valid(): + return iface + # There is no hope left return resolve_iface(conf.loopback_name)