Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Binding to specific interfaces/IPs for outgoing connections #3991

Open
nikitakuklev opened this issue Feb 15, 2017 · 4 comments
Open

Binding to specific interfaces/IPs for outgoing connections #3991

nikitakuklev opened this issue Feb 15, 2017 · 4 comments
Labels
enhancement New features or improvements of some kind, as opposed to a problem (bug)

Comments

@nikitakuklev
Copy link

This issue has been touched upon a couple times, but I thought I should make it a bit clearer with my use case, and ask for comments on feasibility.

Use case: Win10 system with fast (but metered) wired connection (LAN) and slower but essentially unlimited wifi (WF), both behind NAT. There is no port forwarding/UPnP, but remote nodes do have it so direct connections work on both. Interface and gateway (route) metrics are such that everything goes to LAN by default but I want ST to use WF exclusively to save on traffic.

Problem 1: setting listen IP to $WF_IP$ does work but only for listen connections...global discovery/outgoing connections still go out LAN (as expected due to OS routing) and so does all the traffic that follows. (there is also a problem with discovery server not auto-adding source IP anymore, but that is intended as per v3 protocol specs)

Problem 2: even if setting outgoing IP was possible, $WF_IP$ changes frequently - hardcoding it is useless

Desired feature: ability to pick interface and (optionally) specific IP to bind to for all internet traffic (global discovery/relay/direct connections). For example, something like in qBitTorrent:
alt text
alt text

Note that IP binding is useful since single interface can have multiple IPs due to aliases (in my case, main IP is 10.1.1.10 and there is IP alias 10.1.1.11 with 'SkipAsSource=true', such that applications that specifically bind to it are routed over VPN but other traffic only uses 10.1.1.10).

In case both options are not selected, ST should defer to default OS routing as it does now. If only interface is specified, it should follow system routing behavior for that interface (if not known/hard, just pick single IP like libtorrent does). Option to choose fallback strategy in case of interface/IP being unavailable is necessary.

Besides my use case, there are other ways this can be useful. For example, to prevent flip-flopping over intermittent connections (wi-fi or cellular modem/tether), to limit sharing to home IP, or to route ST traffic over VPN interface.

@nikitakuklev
Copy link
Author

Feasibility: (disclaimer - I don't know much Go) It seems that one can obtain a list of interface names and then extract IPs, one of which is then supplied to various Dialers via laddr (such as in here). Since net.Dial used in lib/dialer doesn't have that argument, would need to convert to TCPConn.DialTCP, taking care to separate local UDP stuff.

Concerns I could identify:

  • IP address binding != interface binding (due to routing), and libtorrent for instance solves this via SO_BINDTODEVICE socket if available, with IP binding as fallback. Breaking this down by OS:
    -- Windows has no interface binding but it uses strong ES model, so specifying source IP address is equivalent to specifying interface. This also applies to most *nix OSes.
    -- Linux uses weak ES by default, but can bind interfaces. Doing it with Dialer is hacky and syscall sockets should be used instead. This however would require a major network rewrite unless result can be used with existing Dialer (can PacketConn be swapped in somehow)?
    In the end, it may be simpler to assume a sane routing config and just bind IP on all platforms.
  • Settings need to apply to internet connections but not affect local discovery and traffic - i.e. if LAN is local and WF is internet and only output interface, have to either somehow defer to system routing to reach local peers or keep track of who is on what interface. Also related to Could you please add choosing network interfaces? #1305, Local discovery doesn't work by WiFi network (special problem) #1312. Libtorrent solves this by specifically testing each IP on whether it is local (by checking against mask) before connecting.
  • Need to play nice with proxies (replace underlying proxy Dialer, proxy.Direct, which uses net.Dial?)
  • What happens if connection comes in on interface we listen to, but that is not in outgoing or local lists? Should probably force to listen on all outgoing+local interfaces and ignore anything else.
  • Need to monitor interface and IP status changes (discussed a bit in Syncthing does not take care of network interface priority #2941). This can happen with DHCP renewals or usb wi-fi dongles or on flaky connections. Depending on settings, need to either rescan available IPs and rebind as fallback, revert to OS routing, or wait until interface/IP returns (like current proxy no fallback flag).
  • Dualstack IPv4/IPv6 binding and tracking seems complicated, especially if number and availability of IPs is not homogeneous...scream silently in logs
  • GUI implementation of dynamic multi-selection boxes is not available (could probably get away with string boxes in advanced settings though). Need to refresh options on any network change, or specifically note that restart is required like in above screenshots.

I realize this is hard to implement properly but it does provide an opportunity to resolve at least several open feature requests, especially if local interface selection is also added in. Before valiantly trying and failing to code something, I thought I should ask if anyone has tried it or can see major problems with above approach.


P.S. For those that have this issue and want a temporary fix - you can use a local SOCKS5 proxy that can bind IPs, such as 3proxy. Combined with the no fallback option and a small PS cmdlet to find current IP+set env vars, this effectively imitates interface binding. Works with SyncTrayzor too.

@calmh
Copy link
Member

calmh commented Feb 15, 2017 via email

@calmh calmh added the enhancement New features or improvements of some kind, as opposed to a problem (bug) label Mar 5, 2017
@calmh calmh added this to the Unplanned (Contributions Welcome) milestone Mar 5, 2017
@calmh calmh removed this from the Unplanned (Contributions Welcome) milestone Feb 11, 2018
@xordspar0
Copy link

What's the status of this issue? Are we just waiting for someone to write a patch?

@calmh
Copy link
Member

calmh commented Sep 4, 2018

Yes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New features or improvements of some kind, as opposed to a problem (bug)
Projects
None yet
Development

No branches or pull requests

3 participants