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

Problem with UDP when binding to IP/interface (while TCP is fine) #6960

Closed
p0358 opened this issue Jul 12, 2022 · 3 comments
Closed

Problem with UDP when binding to IP/interface (while TCP is fine) #6960

p0358 opened this issue Jul 12, 2022 · 3 comments
Labels

Comments

@p0358
Copy link

p0358 commented Jul 12, 2022

Please provide the following information

libtorrent version (or branch): 2.0.6.0, 2.0.5.0

[ qBittorrent 4.4.3.1_11.0.8, Deluge 2.0.5_11.0.7 ]

platform/architecture: Linux x64 (on TrueNAS Scale apps platform (TrueCharts repo), so running under k8s and Docker)

compiler and compiler version: unknown


please describe what symptom you see

So I tried setting up a torrent client with TrueNAS Scale, on a box with second internet card that's connected to a second internet connection, with appropriate routing. I know I DID set it up properly, because:

  1. I can bind properly to interface/IP address using any HTTP client like curl, and it connects via TCP from expected external IP source
  2. I can use netcat bound to an IP to send and receive UDP echo packets, all working as expected (both 1. and 2. from within the container in which the torrent app ran with bridged external network card)
  3. Transmission, which doesn't use libtorrent-rasterbar, does work 100% properly with TCP and UDP

I tried setting it up with qBittorrent and Deluge, however, and it failed.

The problem was that binding to IP interface in both of these programs resulted in TCP-based connections working (HTTP trackers + TCP peers), but all UDP connections would fail (DHT + UDP trackers + uTP peers). DHT would display 0 peers, UDP trackers would not respond, which was a problem for torrents with no HTTP trackers. However adding a peer manually in qBittorrent to such torrents would start download over TCP immediately.

I am pretty sure the issue lies somewhere in libtorrent, as it didn't work in the two torrent clients that use this library, but worked flawlessly in Transmission and when tried in the container shell with any other utility. This issue sadly prevents me from being able to use any torrent client based on this otherwise great library, since most torrents are undownloadable with this issue.


what you would expect to see instead

I should be able to bind to IP/interface and both TCP and UDP should work like in other torrent libraries and programs, instead of having just TCP work.


how to reproduce it

Probably by having two ethernet cards, the primary gateway one, and a second one. Try to bind to the second one. Primary connection is added with default Docker networking, while the second one is bridged, with default route 0.0.0.0 added to its gateway in the config.

Also on the host I use this config for source-based routing (as I said works fine for literally every other app both under container and outside):

echo 101 isp2 >> /etc/iproute2/rt_tables
ip rule add prio 100 from 192.168.10.0/24 lookup isp2
ip route add 0.0.0.0/0 via 192.168.10.1 dev enp1s5 table isp2

where enp1s5 is the second ethernet card, and 192.168.10.0 is its network

@arvidn
Copy link
Owner

arvidn commented Aug 21, 2022

to make sure I understand your scenario; you have two network interfaces, each with a separate IP address. You configure libtorrent to bind to exactly one of them.

Do they have different metrics for routing purposes? If so, are you binding to the one with lower metric?

Would you expect I could reproduce this by using a VPN connection and bind to the regular NIC rather than tun0?

Do you get any error messages in the log that might give a hint of what's failing?

@stale
Copy link

stale bot commented Nov 23, 2022

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale label Nov 23, 2022
@stale stale bot closed this as completed Jan 7, 2023
@p0358
Copy link
Author

p0358 commented Mar 3, 2023

Sorry for late response, I come with some new clues about this issue. So I tried a different approach with setting up routing rules within the container itself.

So I ran:

cat /etc/resolv.conf | sed 's/nameserver 172\.17\.0\.10/nameserver 1.1.1.1/g' | tee /etc/resolv.conf
ip route add 192.168.1.0/24 via 172.16.0.1 dev eth0
ip route replace default via 192.168.0.1

Second line is just to access the container from my main LAN. Most relevant line is the 3rd one. Apparently now it was enough to make it so that by default all the programs within the container use the other network card for internet access. But... UDP doesn't work in qBittorrent again!

This time I didn't need to bind the network or IP in either curl or qBittorrent, so the problem must not be inherently related to that or source-based routing in Linux.

However the UDP itself appears to also be working, since I can run on an external VPS: ncat -e /bin/cat -k -u -l 1234, and then from within my container I can run echo abc | nc -u <my VPS IP> 1234, and I get abc back in response (I wouldn't get it back without the server running).

So the UDP works within the container, and even without interface binding, qBittorrent cannot contact working UDP trackers or any DHT peers, only TCP works in it.

As a last meaningful test, I added -v option to the ncat server, so that it logs into console each time something attempts to connect to it. Then I added that VPS as tracker as udp://<my VPS IP>:1234/announce. That didn't work with skipping tracker announce (unreachable), just as other UDP trackers. This somewhat suggests the issue is with packet sending/socket bind rather than receiving maybe?

EDIT: after binding things in settings to an interface+IP and unbinding again, UDP stuff started working and I got a log line in logs. Perhaps the issue was just the socket binding being outdated after route rules got changed. So this might actually be a separate issue from what I reported initially (and TCP would work immediately since its connections are always new sockets?)

However something still seems to be wrong with UDP binding in general, because previously when I changed the settings, I would get 0 DHT peers even if I came back to previously working "any" bind, and had to restart qBittorrent for it to work again...

But the above might be qBittorrent's issue at this point rather than this library's...


In the end it seems I kinda solved my issue by mounting and replacing entrypoint script in my container to set the ip rules BEFORE qBittorrent even starts, and not using source-based routing and interface binding, but rather changing the main gateway within the container itself.

HOWEVER on the account of original issue, I do think something might be wrong with UDP binding to IP in this library, since that didn't work only in qBittorrent and Deluge, but worked in Transmission. It's worth noting that CURL binding to just interface would not work either, I had to explicitly bind it to the IP. So I'd just glance over if UDP socket doesn't ignore IP setting for binding, and if that setting isn't rather only used for just TCP sockets...

Would you expect I could reproduce this by using a VPN connection and bind to the regular NIC rather than tun0?

On that note, I think it could be reproduced by setting some even junk non-existent primary gateway (for instance when using NAT network in VirtualBox). Then adding second network in VirtualBox as bridged, and executing the commands as in the original post, replacing the 192.168.10.0/24 with your real LAN network, 192.168.10.1 with your real router gateway, and enp1s5 with the name of the bridged card. The result should be that curl myip.wtf/text does not work at all (in case of fake default gateway), but curl --interface 192.168.10.100 works (assuming that's the IP you got assigned to VM), but curl --interface enp1s5 can be broken. If these three behaviors occur, then it's likely the reproduction environment is the same, and probably UDP won't work in qBittorrent if you bind it to either the IP/interface or both.


TL;DR it seems I found a workaround for myself around the original issue, possibly found out that UDP socket binding at least in qBittorrent generally has possibly other issues, but that the original issue might still exist (well a few days ago I tested it again in original configuration and so was the case), and laid out my untested repro idea at the very end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants