Fix/linux lan address detection - #1
Conversation
Native Linux BeamNG reports "No bindable LAN IPv4 address was found" for Connected Phone. canBindAddress discarded the real LuaSocket bind error, and several address-discovery paths carried Windows-only assumptions (adapter description matching, a hardcoded "Windows hostname" label), so there was no way to see which of the four candidate sources was actually failing on Linux. - canBindAddress and networkAddress.select now propagate the actual bind failure reason instead of a bare boolean. - Log raw adapter/hostname discovery entries and per-destination route-probe results, plus a full per-candidate score breakdown, to make the next Linux log capture diagnostic. - Recognize Linux predictable interface names (eno/enp/ens/eth/wlp) in the adapter-type scoring bonus, and penalize Docker/Podman/veth/bridge interfaces like other virtual adapters. - Add test coverage for the above plus loopback/0.0.0.0/multicast rejection and saved-address-vs-live-candidate precedence. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The first diagnostics pass silently dropped the second pcall return value (LuaSocket's actual error string) from both setpeername and getsockname, so route_probe logs showed error="nil" even when the UDP route trick failed. Live Nobara logs confirmed native/adapter/hostname discovery all only surface loopback (127.0.0.1 / 127.0.1.1) on this Linux build, making the route trick the only source that could still find a real LAN IP -- so seeing why it fails is now the critical missing diagnostic. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…time
Live Nobara logs revealed the real root cause: BeamNG's Lua sandbox blocks
outbound socket connect() entirely ("connect restricted"), so the UDP route
trick can never work, regardless of platform. Combined with native/adapter/
hostname discovery all returning loopback-only on this Linux build, every
existing candidate source was structurally dead, not just mis-scored.
/proc/net/fib_trie is a plain kernel-exposed pseudo-file (read via io.open,
not a shelled-out command) listing every IPv4 address assigned to a local
interface under its "Local:" section, marked "host LOCAL". Parsing it gives
a genuine platform-native way to discover real LAN addresses without relying
on a blocked connect() call or broken adapter enumeration.
Known limitation: fib_trie has no interface-name field, so candidates from
this source can't get the Wi-Fi/Ethernet description bonus or the Docker/
libvirt bridge penalty -- only subnet-based scoring applies. Sufficient for
a typical single-NIC desktop; a machine with both a real LAN adapter and a
container bridge in RFC1918 space may need a follow-up disambiguation pass.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ssible
Live testing on native Linux BeamNG confirmed the engine's own Lua sandbox
blocks both outbound socket connect() ("connect restricted") and io.open()
on arbitrary paths (confirmed via /proc/net/fib_trie, which exists and is
readable at the OS level but still returns nil from inside the sandbox).
Combined with native/adapter/hostname discovery all being loopback-only on
this build, there is no remaining Lua-level way to discover the real LAN
address automatically on this platform.
Add a "Manual LAN IP" settings field (TaxiDriverHUD connectivity section)
that lets the user type their address once. It flows through the same
validation pipeline as every other source -- normalized, rejected if not a
private LAN IPv4 (loopback/public/malformed all excluded), and bind-tested
-- it just outranks every automatic source (+1000) when valid, rather than
being trusted blindly. Automatic discovery keeps working unchanged on
platforms where it already does (e.g. Windows).
Persisted in the regular settings file (unlike the session-only lanEnabled
flag), since it's a static per-machine value, not a security-sensitive
per-session toggle.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
taxiDriver.lua requires "taxiDriver/optionalLanBridge" as lanBridge, a lazy
wrapper that only forwards a fixed set of functions to the real lanBridge
module. The previous commit added lanBridge.setManualAddress but never added
it to this wrapper's whitelist, so calling it crashed extension load with a
fatal, uncaught Lua error ("attempt to call field 'setManualAddress' (a nil
value)") -- breaking the entire mod, not just LAN sharing.
Mirrors the existing pendingPerformance/setPerformanceOptions pattern: the
value is queued if the real module hasn't loaded yet and flushed once it
does.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
procNetAddresses() never actually works on this engine -- io.open() is blocked by the same Lua sandbox that blocks socket connect(), confirmed via live testing -- so it was dead complexity with no benefit. Removed it along with the per-entry diagnostic dumps (adapter_entry, hostname_entry, route_probe) added during investigation: useful for finding the root cause, not worth keeping as permanent log noise now that it's understood. Kept: bind-error propagation (bindReason), the route-trick error capture (fixing a real bug where a second pcall return value was dropped), the Linux interface-name scoring patterns, the Docker/podman penalty markers, and the manual LAN IP override -- all the changes that actually matter going forward. networkAddress.lua's scoring loop reverted to a single combined score local instead of three separate candidate fields, since the breakdown was only ever needed for the now-removed verbose logging. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… override Reduce the branch to the minimum required for the manual LAN IP override: drop the route/bind diagnostic logging, hostname rename, and Linux interface-name/Docker-Podman scoring added during investigation, along with their tests, restoring that logic to match main. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
The original issue no longer appears to be reproducible. Connected Phone / LAN sharing is now able to detect and use the correct LAN address automatically on the tested native Linux setup. However, I still think keeping the optional manual LAN IP override could be useful. It provides a fallback for systems where automatic address discovery fails, returns the wrong interface, or behaves differently depending on the network configuration. Since the override is optional and the existing automatic discovery remains unchanged when no manual address is configured, it could still be a useful addition even though it is no longer required to solve the original issue on the tested setup. |
|
@JamDaBam In the future make the skill 'localization-manager' which will always check the locales.json files please. :) Because this PR missed both "lanManualAddress" and "lanManualAddressHelp" values in all languages except English. |
Summary
Fixes "Connected Phone" / LAN sharing failing on native Linux BeamNG.drive with:
Adds an optional manual LAN IP override for the platforms where automatic discovery is provably impossible.
Root cause
lanBridge.lua'sselectLanAddress()gathers LAN IPv4 candidates from four sources — BeamNG's native server address,BNGWebWSServer.getNetworkAdapterAddresses(), hostname DNS resolution, and a UDPconnect()/getsockname()"route trick" — and hands them tonetworkAddress.select()for scoring and a bind test. On native Linux (confirmed via live testing on Nobara 44, BeamNG 0.38.6, native Steam build under Steam Linux Runtime), all four sources are dead ends:127.0.0.1even when bound to"any".BNGWebWSServer.getNetworkAdapterAddresses()returns exactly one entry:127.0.0.1. This engine API appears to have an incomplete Linux implementation (it works correctly on Windows, returning real adapters).127.0.1.1, the standard Linux/etc/hostsloopback convention."connect restricted"— not a standard OS/LuaSocket error string, but BeamNG's own Lua sandbox deliberately blocking outboundsocket:connect()/setpeername()calls from mod code.Conclusion: BeamNG's Lua engine sandbox blocks outbound socket
connect()on native Linux, by design. Windows was never affected because its native adapter enumeration (a legitimate engine-side C++ API, not raw Lua I/O) actually returns real interfaces there. There is no remaining pure-Lua way to discover the real LAN IPv4 address automatically inside this sandbox on this native Linux build.Changes
Manual LAN IP override (the fix that unblocks affected users)
ui/modules/apps/TaxiDriverHUD/app.html/app.js/locales.json), shown when LAN sharing is enabled.lanManualAddressin the regular settings file (unlike the session-onlylanEnabledflag, since it's a static per-machine value, not a security-sensitive per-session toggle), via the existingpersistence.luasanitize-on-load path.taxiDriver.lua→optionalLanBridge.lua→lanBridge.M.setManualAddress()→networkAddress.select()as a new"manual"source with a +1000 score bonus, guaranteeing it outranks every automatic source.canBindAddress(). An invalid or unbindable override is rejected, not blindly trusted, and selection falls back to automatic discovery.Bug fixed during implementation
optionalLanBridge.luais a lazy-loading wrapper aroundlanBridge.luathat only forwards a fixed whitelist of functions. The first cut of the manual-override feature addedlanBridge.setManualAddressbut forgot to add it to this wrapper, which crashed the entire mod on load with a fatal, uncaught Lua error. Fixed by mirroring the existingpendingPerformance/setPerformanceOptionsqueue-until-loaded pattern.Tests
Added to
tests/lua/combinatorics.lua(all additive, no existing assertions changed):nilwhen no automatic candidate is usable.Manual verification
Confirmed working end-to-end on Nobara 44 / BeamNG.drive 0.38.6 (native Linux, Steam Linux Runtime): entering the machine's real LAN IP into the new settings field allows Connected Phone to start successfully where automatic detection could not.
Remaining limitations
connect()) rather than anything fixable from mod code. The manual override is the practical workaround.BNGWebWSServer.getNetworkAdapterAddresses()on Linux (or relaxes the sandbox), the existing automatic sources would start working again unchanged — no code here assumes they're permanently broken.