From f655438469d576a76314791633c35bdcbf5c140b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Caletka?= Date: Tue, 7 May 2024 10:43:05 +0200 Subject: [PATCH] Fix interface selection for IPv6-only hosts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of considering the full IPv4 routing table, we only look for IPv4 default route and IPv6 routes shorter or equal /8 (for instance `2000::/3`). Since the `conf.route6` is not ready yet when we first run, we reload `conf.ifaces` after loading `route6.py`. This fixes #4304 Signed-off-by: Ondřej Caletka --- scapy/interfaces.py | 19 ++++++++++++++----- scapy/route6.py | 2 ++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/scapy/interfaces.py b/scapy/interfaces.py index f40f529ea8b..42ed2cbe4a8 100644 --- a/scapy/interfaces.py +++ b/scapy/interfaces.py @@ -372,11 +372,20 @@ def get_if_list(): def get_working_if(): # type: () -> NetworkInterface """Return an interface that works""" - # return the interface associated with the route with smallest - # mask (route by default if it exists) - routes = conf.route.routes[:] - routes.sort(key=lambda x: x[1]) - ifaces = (x[3] for x in routes) + # return the interface associated with the default route + # IPv4 default route is preferred, then IPv6 route + # shorter or equal than /8 or any interface as a fallback + default_routes_v4 = (x for x in conf.route.routes if x[1] == 0) + if conf.route6: + default_routes_v6 = (x for x in conf.route6.routes if x[1] <= 8) + default_routes_v6 = sorted(default_routes_v6, key=lambda x: x[1]) + else: + default_routes_v6 = [] + + ifaces = (x[3] for x in itertools.chain( + default_routes_v4, + default_routes_v6) + ) # First check the routing ifaces from best to worse, # then check all the available ifaces as backup. for ifname in itertools.chain(ifaces, conf.ifaces.values()): diff --git a/scapy/route6.py b/scapy/route6.py index dd86b26ca6b..4826fcd5a5b 100644 --- a/scapy/route6.py +++ b/scapy/route6.py @@ -360,3 +360,5 @@ def route(self, dst="", dev=None, verbose=conf.verb): conf.route6 = Route6() +# IPv6 routing table can influence default interface selection +conf.ifaces.reload()