Skip to content

Linux: keep a USB-tethered phone's name and color across replugs - #174

Open
ysai258 wants to merge 6 commits into
anmolkapil:mainfrom
ysai258:linux-docker-bridges-and-phone-identity
Open

ysai258 wants to merge 6 commits into
anmolkapil:mainfrom
ysai258:linux-docker-bridges-and-phone-identity

Conversation

@ysai258

@ysai258 ysai258 commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Why

On Linux, a phone shared over USB tethering loses its custom name and color every time it's plugged in. Android picks a random MAC for USB tethering on each connection, and systemd names the device from the MAC (enx8e1dfa42a7fe, then enx267c32d5a390, …). Network preferences are keyed by NetworkInterfaceInfo.id, which is the device name, so the name saved for the phone never matches it again.

What changes

In getLinuxAdapters (src/main/network/interfaces.ts), for an adapter it already classifies as usb:

  • It reads the serial of the USB device behind the adapter (/sys/class/net/<dev>/device/../serial; the network function is …/usb1/1-2/1-2:1.0, and its parent 1-2 is the phone).
  • id becomes usb:<serial> (for example usb:RZCX12KDXRY). It stays the same across replugs, cables and ports, so saved names, colors and limits stick.
  • device is still the real device name, so SO_BINDTODEVICE and routing are unchanged.
  • Ids stay unique. If two adapters report the same serial (cheap phones with a placeholder like 0123456789ABCDEF, or one phone with two network functions), neither uses it, and both keep the device name as before.
  • Settings saved under the device name move to the new id. The main process does it before the network is used, so it also happens with no window open, and the window applies the same move to its copy.
  • getLinuxAdapters moves to linuxAdapters.ts and takes the sys root, so it can be tested without Electron.
  • The NetworkInterfaceInfo.id doc comment in src/shared/types.ts says so.

Scope change: this PR first also hid Docker bridges. #32 has since done that in getLinuxAdapters, so I merged main and dropped that part. What's left is only the phone's id.

What it doesn't change

  • macOS and Windows.
  • Linux adapters that aren't USB, and USB adapters without a serial: the id is still the device name.
  • On upgrade, settings saved under an adapter's current device name (name, color, limits, proxy) move to its usb:<serial> id, unless that id already has settings. A phone last saved under an older random enx… name can't be matched and has to be renamed once.
  • network-usage.json isn't moved, so an adapter with a data limit starts its used amount from 0 once after upgrading.

How I checked it

Manually, on Linux (Ubuntu, kernel 6.8), with Wi-Fi and a Samsung phone on USB tethering: before, each replug produced a new enx… network with the default name. With the serial id, listActiveInterfaces() returned { id: 'usb:RZCX12KDXRY', device: 'enx8e1dfa42a7fe', kind: 'usb' }, and the saved name came back after replugging. After merging #32, I re-ran discovery on the same machine with the phone unplugged: Wi-Fi is listed and the Docker bridges are filtered as before.

Tests:

  • npm run lint, npm run typecheck and npm run format:check are clean.
  • npm run test:e2e:smoke: 163 passed, 1 failed. The failure is ui.spec.ts:137 (minimum window keeps download controls…), which passes in CI and fails only on my display setup.
  • e2e/linuxAdapters.spec.ts runs getLinuxAdapters over a fake /sys tree (serial found, no serial, two adapters sharing a serial) and covers the settings carry-over.
  • e2e/liveNetworks.spec.ts checks through the app that a saved name and proxy survive the id change.

🤖 Generated with Claude Code

ysai258 and others added 2 commits October 22, 2026 22:20
Docker's bridges (br-<id>, docker0) and libvirt's virbr0 have addresses, so
they were listed as networks that never carry anything. A bridge is now
skipped when it is virtual and nothing but veths/taps are plugged into it.

Android USB tethering picks a random MAC each time the phone is plugged in,
so systemd names it enx<mac> afresh and its saved name and color were lost.
A USB network device now takes its id from the USB serial (usb:<serial>)
and its label from the device's product name ("SAMSUNG Android"). A serial
two devices share falls back to the device name, so ids stay unique.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ne's USB serial id on top

anmolkapil#32 now hides Docker bridges and veths in getLinuxAdapters, so this branch's
own filtering is dropped. What's left: a USB adapter's id is usb:<serial>,
so a tethered phone keeps its saved name and color across replugs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ysai258 ysai258 changed the title Linux: hide Docker bridges, and know a USB-tethered phone across replugs Linux: keep a USB-tethered phone's name and color across replugs Oct 29, 2026
@ysai258

ysai258 commented Oct 29, 2026

Copy link
Copy Markdown
Contributor Author

Hi @anmolkapil, a gentle ping on this one when you get a chance 🙂

  • Updated for Feat: add per-connection proxy configuration and improve network interface handling #32: it now hides Docker bridges itself, so I dropped that part and merged main. What's left is small: a USB-tethered phone gets the id usb:<serial>, so its custom name and color stick across replugs instead of resetting with every new enx… name.
  • No conflicts with main. CI still needs a maintainer to approve the workflow run.
  • Smoke tests pass locally, apart from ui.spec.ts:137 and ui.spec.ts:288, which fail the same way on unmodified main on my machine.

Happy to add a test over a fake /sys tree, or to rework the approach if you'd prefer something else. Thanks!

anmolkapil#32 named the button after the network ("Edit Office fibre") instead of
"Edit network", so the settings test couldn't find it and failed on main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ysai258

ysai258 commented Oct 29, 2026

Copy link
Copy Markdown
Contributor Author

The E2E (smoke) failure was ui.spec.ts:288 (every choice survives a reload and a restart). It fails on main too, since #32: that PR renamed the network edit button from "Edit network" to "Edit ", and the test still looked for the old name.

I added a small separate commit here that finds the button by its new name (/^Edit /). It's only a test change; the app is unchanged. Locally the smoke suite now passes apart from ui.spec.ts:137, which passes in CI and fails only on my display setup. Happy to move that commit into its own PR if you'd rather keep this one focused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@Arpit-Khandelwal Arpit-Khandelwal left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the clear write-up. Keying a tethered phone by its USB serial is a good idea. I checked readUsbSerial against a fake /sys tree (interface -> device link -> parent folder with serial) under Node, and it returns the serial as expected. Merged with main, typecheck, lint, format, the build and the ui/network/liveNetworks specs pass.

Two things before this can go in:

  1. Keep existing settings on upgrade. Saved names, colors, limits and (since #32) the per-network proxy are all keyed by id. With this change, every Linux USB adapter that reports a serial gets a new id. That includes USB-Ethernet dongles whose name never changed, not only phones. Their saved settings disappear after the update, and a network that had a proxy would quietly go direct. Could you carry the old entry over? For example, when nothing is saved under usb:<serial> but something is saved under the device name, move it to the new id.
  2. A test. Yes, please add the fake /sys test you offered. For example, let getLinuxAdapters / readUsbSerial take the sys root as a parameter, and cover: serial found, no serial, two adapters with the same serial, and the settings carry-over from point 1.

Also, #223 makes the same ui.spec.ts edit-button fix and conflicts with your test commit. Please drop that commit once #223 is merged.

result.push({
id: device,
// A tethered phone keeps its saved name and color across replugs (see readUsbSerial).
id: linuxAdapter?.usbSerial ? `usb:${linuxAdapter.usbSerial}` : device,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changes the id for every Linux USB adapter with a serial, including USB-Ethernet dongles with a stable enx… name. Settings (name, color, limits, the #32 proxy) are keyed by this id, so they'd be lost on upgrade. Please move an entry saved under device to the new usb: id when there's none under the new one.

ysai258 and others added 2 commits November 9, 2026 22:42
…and-phone-identity

# Conflicts:
#	e2e/ui.spec.ts
Names, colors, limits and proxies are keyed by network id, so giving a USB
adapter with a serial the id usb:<serial> would have lost them on upgrade,
and a network with a proxy would have quietly gone direct. What's saved under
the device name now moves to the new id when none is saved there. Main does
it before the network is used, so it also happens with no window open; the
window does the same to its copy, which it saves whole.

getLinuxAdapters takes the sys root and moves out of interfaces.ts, which
loads Electron, so it can be tested over a fake /sys tree.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ysai258

ysai258 commented Nov 9, 2026

Copy link
Copy Markdown
Contributor Author

@Arpit-Khandelwal Thanks for the review! Addressed in 8515c9e:

  1. Settings carry over: an entry saved under the device name moves to usb:<serial> when none exists there. Main does it before the network is used (so it also works with no window open), and the window applies the same move to its copy.
  2. Tests: getLinuxAdapters takes the sys root; e2e/linuxAdapters.spec.ts covers serial found, no serial, a shared serial and the carry-over, and liveNetworks.spec.ts checks through the app that a proxy survives the id change.
  3. ui.spec.ts: test: fix the settings smoke test after the network edit button was renamed #234 landed the same fix, so I merged main and that file now matches it.

One thing left as is: network-usage.json isn't moved, so an adapter with a data limit starts its used amount from 0 once after upgrading. Happy to carry that over too if you'd like.

This branch has not been deployed

No deployments
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