Repository navigation
feat: bind peer traffic to one interface, with fixed ports and a /network API - #210
Merged
Merged
Conversation
…work API (#164) webtorrent binds nothing to any interface, so a VPN that drops hands the swarm and the search sites the real address. Instead of polling an adapter and hoping to pause in time, every socket the process opens is bound to the interface's address through Node's own net/dgram prototypes (and utp-native's bind, which opens its socket natively): peers, trackers, DHT, web seeds and the search fetches. While the interface is gone, new sockets get an unroutable address and fail closed. A 2 s watch tears the engine down when the interface disappears and re-attaches every torrent when it is back, on its new address if that changed; the queue's items never change state, so the TUI needs nothing new and a stalled download simply reads as stalled. --interface <name|ip>, --peer-port and --dht-port ride on the environment (TORLINK_INTERFACE, TORLINK_PEER_PORT, TORLINK_DHT_PORT), the way TORLINK_NO_UTP does, so the TUI, a --daemon child and search all see them, and a restart after `torlnk update` replays the flags. The DHT may never share the peer port, where uTP already listens. Bound, LSD, UPnP, NAT-PMP and WebRTC peers stay off: each would use another interface, and a mapping request would fight the one the interface's owner keeps alive. serve gains GET /network (address, online, listen port, and the count of peers that dialed in, which is the proof a forwarded port works) and POST /network to change the interface or ports in place, so a script that reads a forwarded port from a VPN client can hand it over without a restart. Nothing is tied to a particular VPN: torlink only knows the interface. IPv4 only for now, since webtorrent and the DHT open udp4 sockets.
…lient errors Re-attaching after a drop re-verifies every seed on disk, so a link that bounces for a few seconds would have re-hashed a seedbox each time; the return now settles for 3 s first, and anything added meanwhile waits with the rest. The fail-closed address was a fixed 192.0.2.1, and containers do hand out that range (the sandbox this was built in sat on 192.0.2.2/24). It is now whichever RFC 5737 range this host does not hold at the moment the interface goes down. webtorrent's own errors (a fixed port already taken, uTP that would not start) were swallowed, leaving torrents at zero peers with nothing in the log. They are reported on /network and by the daemons, a destroyed client is dropped so the next add or a POST /network with a free port builds a fresh one.
vu1nz Security Review0 finding(s) in PR #? No security issues found. |
ThreatCrush Security Scan0 finding(s) No findings. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What and why
Closes #164.
webtorrent binds nothing to any interface, so a VPN that drops hands the swarm and the search sites the real address. This binds every socket the process opens to one interface's address and fails closed when that interface is gone, with no TUI changes and nothing tied to a particular VPN.
--interface <name|ip>(TORLINK_INTERFACE) binds peers, trackers, DHT, web seeds and the search fetches to the interface's IPv4 address. webtorrent has no option for this, sosrc/util/bind.tsinjects the address at the one place every library passes through: Node'snet/dgramprototypes, plus utp-native's own bind. Installed only when an interface is configured; inert otherwise.EADDRNOTAVAILinstead of leaving through the default route. A 2 s watch tears the engine down on a drop and re-attaches every torrent when the interface is back, on its new address if that changed, after a 3 s settle so a bouncing link does not re-hash a seedbox each time. Queue items never change state, so the TUI needs nothing new: a stalled download reads as stalled.--peer-portfixes the TCP/uTP listen port (the one to forward),--dht-portthe DHT port; the two may never be equal, since uTP already holds the peer port's UDP side. Bound, LSD, UPnP, NAT-PMP and WebRTC peers stay off: each would use another interface, and a mapping request would fight the one the interface's gateway keeps alive.TORLINK_NO_UTP, so the TUI, a--daemonchild andsearchall see them, and a restart aftertorlnk updatereplays argv.search --interfaceexits 1 with a message when the interface is down.servegainsGET /network(address, online, listen port, incoming peer count as proof a forwarded port works, and the client's own last error) andPOST /networkto change interface or ports in place, so an external driver that reads a forwarded port from its VPN client can hand it over without a restart./downloadscarries the same status.Verified on Linux beyond the suite:
serve --interface lo --peer-port 51413puts every peer socket on 127.0.0.1 and moves the port throughPOST /network; on a veth interface, all sockets sit on its address, vanish on link down while the download stays listed, and come back on a new address with the fixed port; an unknown interface boots paused with a hint listing the real ones.Limits stated in the README: IPv4 only (webtorrent and the DHT open
udp4sockets), DNS through the OS resolver, and the git/npm children oftorlnk updateunbound.Checklist
npm run typecheckis cleannpm testpassesHELP_GROUPSandfooterHintsinsrc/ui/keymap.ts(no key added; no TUI changes)Storefield, I updatedmakeStoreinscripts/render-previews-impl.tsx(noStorefield added)feat:/fix:/docs:/chore:)Generated by Claude Code