From 4fa6783dbbef98b775a028e6d5056e0fec5577e5 Mon Sep 17 00:00:00 2001 From: Tomas Janousek Date: Thu, 28 Mar 2024 15:01:50 +0000 Subject: [PATCH] NetworkMgr: Use cheaper/simpler hasDefaultRoute in isOnline Device:getDefaultRoute parses /proc/net/route and converts the hex addresses to textual IP addresses, but in `isOnline` we don't care what address the gateway actually has, we only care about whether we have a default route into the Internet. This provides a simpler alternative that does the equivalent of "ip route get 203.0.113.1 || ip route get 2001:db8::1" (note that it does support IPv6-only connectivity as opposed to Device:getDefaultRoute) and returns true if we have a route. Inspired by https://github.com/pavel-odintsov/get_default_outgoing_ip_linux --- frontend/ui/network/manager.lua | 35 ++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/frontend/ui/network/manager.lua b/frontend/ui/network/manager.lua index 04e8018b2..802e6d1db 100644 --- a/frontend/ui/network/manager.lua +++ b/frontend/ui/network/manager.lua @@ -274,6 +274,39 @@ function NetworkMgr:ifHasAnAddress() return ok end +-- The socket API equivalent of "ip route get 203.0.113.1 || ip route get 2001:db8::1". +-- +-- These addresses are from special ranges reserved for documentation +-- (RFC 5737, RFC 3849) and therefore likely to just use the default route. +function NetworkMgr:hasDefaultRoute() + local socket = require("socket") + + local s, ret, err + s, err = socket.udp() + if s == nil then + logger.err("NetworkMgr: socket.udp:", err) + return nil + end + + ret, err = s:setpeername("203.0.113.1", "53") + if ret == nil then + -- Most likely "Network is unreachable", meaning there's no route to that address. + logger.dbg("NetworkMgr: socket.udp.setpeername:", err) + + -- Try IPv6, may still succeed if this is an IPv6-only network. + ret, err = s:setpeername("2001:db8::1", "53") + if ret == nil then + -- Most likely "Network is unreachable", meaning there's no route to that address. + logger.dbg("NetworkMgr: socket.udp.setpeername:", err) + end + end + + s:close() + + -- If setpeername succeeded, we have a default route. + return ret ~= nil +end + -- Wrappers around turnOnWifi & turnOffWifi with proper Event signaling function NetworkMgr:enableWifi(wifi_cb, connectivity_cb, connectivity_widget, interactive) local status = self:requestToTurnOnWifi(wifi_cb, interactive) @@ -534,7 +567,7 @@ function NetworkMgr:isOnline() -- Fail early if we don't even have a default route. -- On PocketBook devices, if the first call to socket.dns.toip(…) fails, it never succeeds again. - if not Device:getDefaultRoute() then + if not self:hasDefaultRoute() then return false end