Skip to content

Fix/linux lan address detection - #1

Merged
noteMASTER11 merged 9 commits into
noteMASTER11:mainfrom
JamDaBam:fix/linux-lan-address-detection
Jul 29, 2026
Merged

Fix/linux lan address detection#1
noteMASTER11 merged 9 commits into
noteMASTER11:mainfrom
JamDaBam:fix/linux-lan-address-detection

Conversation

@JamDaBam

@JamDaBam JamDaBam commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Disclaimer: Parts of the analysis and implementation for this fix were developed with the assistance of Claude Code. The resulting changes were reviewed and tested manually. The Connected Phone functionality has been verified end-to-end on native Linux by connecting to it from a phone on the same local network.

Summary

Fixes "Connected Phone" / LAN sharing failing on native Linux BeamNG.drive with:

No bindable LAN IPv4 address was found after server initialization

Adds an optional manual LAN IP override for the platforms where automatic discovery is provably impossible.

Root cause

lanBridge.lua's selectLanAddress() gathers LAN IPv4 candidates from four sources — BeamNG's native server address, BNGWebWSServer.getNetworkAdapterAddresses(), hostname DNS resolution, and a UDP connect()/getsockname() "route trick" — and hands them to networkAddress.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:

  • Native server address returns 127.0.0.1 even 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).
  • Hostname resolution resolves the machine's hostname to 127.0.1.1, the standard Linux /etc/hosts loopback convention.
  • The UDP route trick fails with "connect restricted" — not a standard OS/LuaSocket error string, but BeamNG's own Lua sandbox deliberately blocking outbound socket: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)

  • New "Manual LAN IP (optional)" field in the Connected Phone settings section (ui/modules/apps/TaxiDriverHUD/app.html/app.js/locales.json), shown when LAN sharing is enabled.
  • Persisted as lanManualAddress 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), via the existing persistence.lua sanitize-on-load path.
  • Flows through taxiDriver.luaoptionalLanBridge.lualanBridge.M.setManualAddress()networkAddress.select() as a new "manual" source with a +1000 score bonus, guaranteeing it outranks every automatic source.
  • Still goes through the same validation as every other candidate — normalized, rejected if not a private LAN IPv4 (loopback/public/malformed excluded), and bind-tested via the existing canBindAddress(). An invalid or unbindable override is rejected, not blindly trusted, and selection falls back to automatic discovery.
  • Automatic discovery is completely unchanged when no manual address is configured.

Bug fixed during implementation

  • optionalLanBridge.lua is a lazy-loading wrapper around lanBridge.lua that only forwards a fixed whitelist of functions. The first cut of the manual-override feature added lanBridge.setManualAddress but forgot to add it to this wrapper, which crashed the entire mod on load with a fatal, uncaught Lua error. Fixed by mirroring the existing pendingPerformance/setPerformanceOptions queue-until-loaded pattern.

Tests

Added to tests/lua/combinatorics.lua (all additive, no existing assertions changed):

  • A valid, bindable manual override outranks every automatic source (native/route/saved/adapter).
  • An invalid override (loopback) is ignored in favor of a valid automatic candidate.
  • An unbindable override is rejected entirely, falling back to nil when 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

  • Automatic LAN IP discovery does not work on this native Linux BeamNG build under Steam Linux Runtime, due to engine-level Lua sandboxing (blocked connect()) rather than anything fixable from mod code. The manual override is the practical workaround.
  • If BeamNG ever fixes 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.

JamDaBam and others added 8 commits July 25, 2026 00:19
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>
@JamDaBam

Copy link
Copy Markdown
Contributor Author

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.

@noteMASTER11
noteMASTER11 merged commit e9cb87a into noteMASTER11:main Jul 29, 2026
@noteMASTER11

Copy link
Copy Markdown
Owner

@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.

@JamDaBam
JamDaBam deleted the fix/linux-lan-address-detection branch August 1, 2026 10:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants