qbittorrent / qBittorrent

qBittorrent BitTorrent client
https://www.qbittorrent.org
Other
26.87k stars 3.87k forks source link

Inbound DHT connections broken for IPv6 #13461

Open alannz42 opened 3 years ago

alannz42 commented 3 years ago

qBittorrent version and Operating System

qBittorrent v4.2.5, Linux CentOS 8.2

If on linux, libtorrent-rasterbar and Qt version

libtorrent-rasterbar 1.2.10.0 Qt 5.12.5

This is very complicated, please read carefully.

DHT behaviour changes with versions of libtorrent. This discussion focuses on the latest 1.2 version of libtorrent 1.2.10.0.

The GUI allows you to choose a fixed port number for bittorrent which can be opened in the firewall. I will refer to this port as the 'guiport'.

I have used 'wireshark' to analyze the packets/protocols.

1) For each invocation (run) of qBittorrent a port number appears to be advertised for DHT for IPv6. This differs for each invocation. Once chosen the port number may be used for many days. In the firewall log the port is 27506 for this invocation.

2) DHT is working for my node. That is that my node contacts other nodes (by making outbound connections) and exchanges information. The GUI shows over 1000 discovered DHT nodes. qBittorrent makes both IPv4 and IPv6 outbound DHT connections using the guiport and gets successful responses.

3) qBittorrent makes IPv6 outbound DHT get_peers requests on port 27506 (in addition to the guiport). Some of these are answered.

4) My firewall log (example included) shows both TCP and UDP inbound connections to port 27506 which are blocked. They are blocked by the firewall because they appear to be unsolicited inbound connections. For TCP this is obvious as the connection contains the SYN flag. The firewall is statefull and hence can tell the difference between inbound UDP 'connections' and responses to an outbound connection.

5) In addition the ss (show sockets) command shows there are no processes listening on port 27506 so if I opened the firewall port the connections would still be rejected. As a check, 'telnet myhostipv6 27506' is refused showing there is no process listening.

The Problem/Bug

qBittorrent appears to be incorrectly advertising port 27506 for DHT (on this invocation) on IPv6 as there is no process listening for inbound connections.

This is likely to be a side effect of it making outbound DHT requests on 27506.

I have tried to research this and find it in the code but have not be able to find where these parameters are set. I offer two places to look for possible solutions to the problem. I hope this helps.

Possible Solution

The following is an excerpt from the libtorrent documentation:

void dht_announce (sha1_hash const& info_hash, int port = 0, dht::announce_flags_t flags = {});

dht_announce() will issue a DHT announce request to the DHT to the specified info-hash, advertising the specified port. If the port is left at its default, 0, the port will be implied by the DHT message's source port (which may improve connectivity through a NAT).

I suspect somewhere in qBittorrent the DHT port is set to zero rather than the guiport.

Also could be

From the libtorrent documentation:

announce_flags_t

Declared in "libtorrent/kademlia/announce_flags.hpp"

seed announce to DHT as a seed

implied_port announce to DHT with the implied-port flag set. This tells the network to use your source UDP port as your listen port, rather than the one specified in the message. This may improve the chances of traversing NATs when using uTP.

ssl_torrent Specify the port number for the SSL listen socket in the DHT announce.

The flag 'implied_port' could be incorrectly set causing the outbound port to be used rather than the specified port.

Log from firewall show blocked connections:

Oct 1 11:28:55 SRC=2804:014c:da96:51d4:a47c:04f5:9a3e:10e8 DST=LOCALNET:1000:0000:0000:0011 P=UDP SPT=15184 DPT=27506 Oct 1 11:28:55 SRC=2804:014c:da96:51d4:9473:fe6e:3c45:ce33 DST=LOCALNET:1000:0000:0000:0011 P=UDP SPT=15184 DPT=27506 Oct 1 11:28:55 SRC=2804:014c:da96:51d4:a47c:04f5:9a3e:10e8 DST=LOCALNET:1000:0000:0000:0011 P=UDP SPT=15184 DPT=27506 Oct 1 11:28:59 SRC=2600:1700:5050:2820:0000:0000:0000:0017 DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=42102 DPT=27506 SYN
Oct 1 11:29:01 SRC=2600:8806:0400:014d:5838:8292:d16d:2374 DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=60995 DPT=27506 SYN
Oct 1 11:29:02 SRC=2600:8806:0400:014d:5838:8292:d16d:2374 DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=60995 DPT=27506 SYN
Oct 1 11:29:04 SRC=2600:8806:0400:014d:5838:8292:d16d:2374 DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=60995 DPT=27506 SYN
Oct 1 11:29:08 SRC=2600:1700:5050:2820:0000:0000:0000:0017 DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=42102 DPT=27506 SYN
Oct 1 11:29:08 SRC=2600:8806:0400:014d:5838:8292:d16d:2374 DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=60995 DPT=27506 SYN
Oct 1 11:29:14 SRC=2001:0470:c9bf:0001:0000:0000:0000:0002 DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=15597 DPT=27506 SYN
Oct 1 11:29:16 SRC=2600:8806:0400:014d:5838:8292:d16d:2374 DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=60995 DPT=27506 SYN
Oct 1 11:29:17 SRC=2001:0470:c9bf:0001:0000:0000:0000:0002 DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=15597 DPT=27506 SYN
Oct 1 11:29:20 SRC=2001:0470:c9bf:0001:0000:0000:0000:0002 DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=15597 DPT=27506 SYN
Oct 1 11:29:23 SRC=2001:0470:c9bf:0001:0000:0000:0000:0002 DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=15597 DPT=27506 SYN
Oct 1 11:29:26 SRC=2001:0470:c9bf:0001:0000:0000:0000:0002 DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=15597 DPT=27506 SYN
Oct 1 11:29:28 SRC=2a01:0e0a:02a6:b770:0211:32ff:fe2c:a603 DST=LOCALNET:1000:0000:0000:0011 P=UDP SPT=51413 DPT=27506 Oct 1 11:29:30 SRC=2001:0470:c9bf:0001:0000:0000:0000:0002 DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=15597 DPT=27506 SYN
Oct 1 11:29:31 SRC=2a01:0e0a:02a6:b770:0211:32ff:fe2c:a603 DST=LOCALNET:1000:0000:0000:0011 P=UDP SPT=51413 DPT=27506 Oct 1 11:29:37 SRC=2a01:0e0a:02a6:b770:0211:32ff:fe2c:a603 DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=59039 DPT=27506 SYN
Oct 1 11:29:42 SRC=2001:0981:5cf5:0001:19d9:c594:724a:2a27 DST=LOCALNET:1000:0000:0000:0011 P=UDP SPT=51413 DPT=27506 Oct 1 11:29:44 SRC=2605:a601:ad82:0e00:0211:32ff:fe97:6fed DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=47023 DPT=27506 SYN
Oct 1 11:29:45 SRC=2001:0981:5cf5:0001:19d9:c594:724a:2a27 DST=LOCALNET:1000:0000:0000:0011 P=UDP SPT=51413 DPT=27506 Oct 1 11:29:45 SRC=2605:a601:ad82:0e00:0211:32ff:fe97:6fed DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=47023 DPT=27506 SYN
Oct 1 11:29:47 SRC=2605:a601:ad82:0e00:0211:32ff:fe97:6fed DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=47023 DPT=27506 SYN
Oct 1 11:29:51 SRC=2001:0981:5cf5:0001:19d9:c594:724a:2a27 DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=48551 DPT=27506 SYN
Oct 1 11:29:51 SRC=2605:a601:ad82:0e00:0211:32ff:fe97:6fed DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=47023 DPT=27506 SYN
Oct 1 11:29:59 SRC=2605:a601:ad82:0e00:0211:32ff:fe97:6fed DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=47023 DPT=27506 SYN
Oct 1 11:30:32 SRC=2600:1700:5050:2820:0000:0000:0000:0017 DST=LOCALNET:1000:0000:0000:0011 P=UDP SPT=6881 DPT=27506 Oct 1 11:30:40 SRC=2600:1700:4570:3200:3968:3131:fc0a:9a7f DST=LOCALNET:1000:0000:0000:0011 P=UDP SPT=51413 DPT=27506 Oct 1 11:30:41 SRC=2601:008b:8500:004a:0211:32ff:feac:52b0 DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=48533 DPT=27506 SYN
Oct 1 11:30:41 SRC=2a02:a03f:e591:4000:3c04:a5a6:109d:f8f2 DST=LOCALNET:1000:0000:0000:0011 P=UDP SPT=33500 DPT=27506 Oct 1 11:30:42 SRC=2601:008b:8500:004a:0211:32ff:feac:52b0 DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=48533 DPT=27506 SYN
Oct 1 11:30:44 SRC=2601:008b:8500:004a:0211:32ff:feac:52b0 DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=48533 DPT=27506 SYN
Oct 1 11:30:48 SRC=2601:008b:8500:004a:0211:32ff:feac:52b0 DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=48533 DPT=27506 SYN
Oct 1 11:30:55 SRC=2001:0470:c9bf:0001:0000:0000:0000:0002 DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=20010 DPT=27506 SYN
Oct 1 11:30:56 SRC=2601:008b:8500:004a:0211:32ff:feac:52b0 DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=48533 DPT=27506 SYN
Oct 1 11:30:58 SRC=2001:0470:c9bf:0001:0000:0000:0000:0002 DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=20010 DPT=27506 SYN
Oct 1 11:31:02 SRC=2001:0470:c9bf:0001:0000:0000:0000:0002 DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=20010 DPT=27506 SYN
Oct 1 11:31:05 SRC=2001:0470:c9bf:0001:0000:0000:0000:0002 DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=20010 DPT=27506 SYN
Oct 1 11:31:06 SRC=2804:01b2:a985:5bb8:21a3:acf8:6e33:3976 DST=LOCALNET:1000:0000:0000:0011 P=UDP SPT=6881 DPT=27506 Oct 1 11:31:08 SRC=2001:0470:c9bf:0001:0000:0000:0000:0002 DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=20010 DPT=27506 SYN
Oct 1 11:31:11 SRC=2001:0470:c9bf:0001:0000:0000:0000:0002 DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=20010 DPT=27506 SYN
Oct 1 11:31:22 SRC=2600:1700:4570:3200:3968:3131:fc0a:9a7f DST=LOCALNET:1000:0000:0000:0011 P=UDP SPT=51413 DPT=27506 Oct 1 11:31:38 SRC=2605:a000:123e:015a:0dc6:c65b:99b0:bcea DST=LOCALNET:1000:0000:0000:0011 P=UDP SPT=25829 DPT=27506 Oct 1 11:31:41 SRC=2605:a000:123e:015a:8981:f85c:00e6:cc9a DST=LOCALNET:1000:0000:0000:0011 P=UDP SPT=25829 DPT=27506 Oct 1 11:31:56 SRC=2a00:0dd0:bbbb:7539:0000:0000:0000:0178 DST=LOCALNET:1000:0000:0000:0011 P=UDP SPT=62733 DPT=27506 Oct 1 11:31:59 SRC=2a00:0dd0:bbbb:7539:0000:0000:0000:0178 DST=LOCALNET:1000:0000:0000:0011 P=UDP SPT=62733 DPT=27506 Oct 1 11:31:59 SRC=2a03:4000:0027:0192:0024:0012:1984:0003 DST=LOCALNET:1000:0000:0000:0011 P=UDP SPT=51413 DPT=27506 Oct 1 11:32:02 SRC=2a03:4000:0027:0192:0024:0012:1984:0003 DST=LOCALNET:1000:0000:0000:0011 P=UDP SPT=51413 DPT=27506 Oct 1 11:32:03 SRC=2804:014d:688d:182a:0000:0000:0000:1003 DST=LOCALNET:1000:0000:0000:0011 P=UDP SPT=6881 DPT=27506 Oct 1 11:32:05 SRC=2a00:0dd0:bbbb:7539:0000:0000:0000:0178 DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=39587 DPT=27506 SYN
Oct 1 11:32:08 SRC=2a03:4000:0027:0192:0024:0012:1984:0003 DST=LOCALNET:1000:0000:0000:0011 P=TCP SPT=59067 DPT=27506 SYN
Oct 1 11:32:55 SRC=2001:0b07:0a11:9f50:d43f:5110:0438:30bf DST=LOCALNET:1000:0000:0000:0011 P=UDP SPT=55677 DPT=27506 Oct 1 11:32:57 SRC=2001:0b07:0a11:9f50:f58d:835a:d0aa:b3e2 DST=LOCALNET:1000:0000:0000:0011 P=UDP SPT=55677 DPT=27506 Oct 1 11:33:03 SRC=2600:1700:4570:3200:3968:3131:fc0a:9a7f DST=LOCALNET:1000:0000:0000:0011 P=UDP SPT=51413 DPT=27506

mrambossek commented 2 years ago

im confused, how exactly does this supersede #12553? i have exactly the problem stated there; lots of inbound DHT connections on tcp and udp port 1.

alannz42 commented 2 years ago

The problem changes with the versions of qBittorrent and especially the libtorrent-rasterbar library version. I no longer have the port 1 problem.

alannz42 commented 2 years ago

In case anyone reads this the problem is still there with the current version:

qBittorrent 4.4.0 rc1 libtorrent 2.0.4

For each invocation of qBittorrent it creates a random port and advertises DHT services on this port. Any attempt to access these services remotely is blocked by the firewall.

The port number ought to both be fixed and set in the GUI so it can be added to the firewall.

This bug is many years old. It does not affect you at all, everything works. It does affect your peers though.

Come on - there must be some network people out there.

Chocobo1 commented 2 years ago

@arvidn You might be interested in this issue.

arvidn commented 2 years ago

qBittorrent appears to be incorrectly advertising port 27506 for DHT (on this invocation) on IPv6 as there is no process listening for inbound connections.

It took me a while to get this. Do I understand correctly that what you're referring to as advertising a port is: your listen port that you're announcing the the DHT? ("announce" being a bittorrent term-of-art of telling a tracker or similar about your participation in a swarm, and what your listen socket is).

Furthermore, the title: "Inbound DHT connections broken for IPv6", doesn't refer to the DHT traffic itself, not incoming DHT messages. It's referring to incoming peer connections, from peers that learned about you from the DHT.

In short, you're saying that libtorrent is announcing an incorrect listen port to the DHT.

As you discovered in libtorrent, a DHT announce message can omit the listen port to have the receiver use the source port of the UDP packet, rather than a port specified by the sender. This improves the situation for a peer behind a NAT that doesn't know its own listen port. Assuming the NAT is full-cone, this will allow incoming uTP connections. This is because uTP also runs over UDP and in fact the same local socket that's used for DHT (and UDP trackers).

However, in the case where you manually forward ports, and you do know your listen port, and it's different than your DHT socket port, then using the implied-port feature won't work for you.

One thing I don't understand is what IPv6 have to do with it. I would expect IPv4 to be affected the same way.

arvidn commented 2 years ago

Here's a patch that adds a setting that can disable the "implied port" feature: https://github.com/arvidn/libtorrent/pull/6573

arvidn commented 2 years ago

@alannz42 by default, libtorrent will open its UDP socket and TCP listen socket bound to the same port number. And the UPnP/PCP port mapping will also attempt to forward the same external port numbers for those sockets. In that case, the implied-port feature would give you the correct behavior, right?

Do you have a setup where you end up with different external ports for UDP and TCP traffic?

ghost commented 2 years ago

He describes the problem to be affecting only the IPv6 protocol. qBit is listening on one IPv6 port for TCP/UDP but annoucing a different port to DHT for IPv6. I suspect this has something to do with the multi homing changes to DHT that were introduced in RC1_2.

ghost commented 2 years ago

Also it doesn’t make sense to use implied port for IPv6 as it doesn’t even use NAT.

arvidn commented 2 years ago

libtorrent (virtually) always use the "implied-port" feature when announcing to the DHT. I suspect that ends up being the incorrect one in OPs setup.

@alannz42 in your example tcpdump, where you receive incoming connection attempts on port 27506, what port is your DHT socket bound to? I assume it's 27506, or it's assigned that as the external port in your NAT.

I take it your TCP listen socket is bound to some other port then, is that right?

alannz42 commented 2 years ago

qBittorrent appears to be incorrectly advertising port 27506 for DHT (on this invocation) on IPv6 as there is no process listening for inbound connections.

It took me a while to get this. Do I understand correctly that what you're referring to as advertising a port is: your listen port that you're announcing the the DHT? ("announce" being a bittorrent term-of-art of telling a tracker or similar about your participation in a swarm, and what your listen socket is).

Furthermore, the title: "Inbound DHT connections broken for IPv6", doesn't refer to the DHT traffic itself, not incoming DHT messages. It's referring to incoming peer connections, from peers that learned about you from the DHT.

In short, you're saying that libtorrent is announcing an incorrect listen port to the DHT.

As you discovered in libtorrent, a DHT announce message can omit the listen port to have the receiver use the source port of the UDP packet, rather than a port specified by the sender. This improves the situation for a peer behind a NAT that doesn't know its own listen port. Assuming the NAT is full-cone, this will allow incoming uTP connections. This is because uTP also runs over UDP and in fact the same local socket that's used for DHT (and UDP trackers).

However, in the case where you manually forward ports, and you do know your listen port, and it's different than your DHT socket port, then using the implied-port feature won't work for you.

One thing I don't understand is what IPv6 have to do with it. I would expect IPv4 to be affected the same way.

alannz42 commented 2 years ago

Thank you for your responses. I will try to answer some of your questions. I don't fully understand the coding of qBittorrent or the network protocols. The only tools I have are the firewall logs showing rejected packets and wireshark (a network analyzer).

First a more detailed description of my setup. qBittorrent has a real (non-NATed) IPV6 address and a NATed IPV4 address. Both go through the firewall.

One of the problems I am facing is one of nomenclature - which port is being talked about.

There is a port number in the GUI named "Port used for incoming connections" I shall call this the GUI-port or gport.

I am getting blocked inbound connections to another port I shall call the miscreant port or mport.

gport is in the firewall and is allowed to pass through.

mport is never the same as gport. mport is a random port for each invocation of qBittorrent but remains fixed for that run of the program. I suspect this is created by passing a zero to the network socket library so that the OS allocates an unused port.

It would be good to stick with the IPV6 problem as it is easy to identify. The analysis of this problem may lead to highlighting other issues.

My analysis of the traffic on mport is as follows:

I get inbound TCP connections (i.e. with SYN set) which are rejected. I get similar inbound UDP connections. While UDP is stateless the firewall identifies these as 'new' connections.

The data in these connections is identified as 'BitTorrent DHT Protocol', the request is Dictionary/get_peers. These connections are rejected by the firewall.

In addition qBittorrent has successful conversations on mport using the uTP protocol.

I have had an idea as to what could be happening. Please let me know if is nonsense.

I am having successful DHT transactions with other nodes on mport. If these remote nodes share my address/port with third party nodes using DHT then when these third party nodes try to connect to me using DHT they will be rejected as unknown inbound connections by the firewall.

I'll try and answer some of your questions from a number of posts:

Do you have a setup where you end up with different external ports for UDP and TCP traffic?

The only port I know about is gport - torrent file transfer fully works. gport is allowed through the firewall for both TCP and UDP.

_libtorrent (virtually) always use the "implied-port" feature when announcing to the DHT. I suspect that ends up being the incorrect one in OPs setup.

@alannz42 in your example tcpdump, where you receive incoming connection attempts on port 27506, what port is your DHT socket bound to? I assume it's 27506, or it's assigned that as the external port in your NAT.

I take it your TCP listen socket is bound to some other port then, is that right?_

Yes, gport is different to mport.

what port is your DHT socket bound to?

I would assume this is mport. mport has valid DHT traffic on it. If mport is my DHT socket then surely it needs to be a fixed port number and available in the GUI.

I am very happy to help debug this.

arvidn commented 2 years ago

I'm not an expert on qBittorrent, just the libtorrent interface. qBittorrent may expose certain features under other names.

Could you look at your qBittorrent log, on startup, to see which ports are actually used? I suspect that perhaps mport is the one the UDP socket is bound to, but you expect it to be bound to gport.

I get the impression that you have set up manual port forwarding of the port you've selected, which means you don't really want any of the retry behavior (described below). You would (presumably) want a clearly visible error message saying the port you selected is busy.

If my theory is correct, qBittorrent might have a setting corresponding to the libtorrent option settings_pack::max_retry_port_bind. If this is set to 0, there will be no retries of binding sockets, it will just fail and be (relatively) obvious that nothing works.

Do you see any incoming connections? If so, do you see both incoming TCP and uTP connections?

explanation

The logic for creating and setting up listen sockets for a libtorrent session can be found here. a listen_socket_t in libtorrent represents both a TCP listen socket and a UDP socket (used for DHT, uTP and UDP trackers). It also contains state for UPnP/PCP forwarding and the resulting external port assigned to those sockets.

The notable part is where, after the TCP listen socket has been created and bound, the UDP socket is created and bound to the same port (here and here).

So, typically the port you specify in the GUI would be the same as both the TCP listen socket and the corresponding UDP socket would be bound to. However, you may also notice that if bind() fails with address_in_use, the port is incremented by 1 and bind() is tried again.

alannz42 commented 2 years ago

In the log all sockets bind successfully to gport.

The TCP listen socket and the UDP socket are the same, they both bind to gport, I get inbound connections on gport. I see uTP on gport. I see DHT on gport.

On the last run mport was 2190, gport was 25000 so it can't be a fail and increment problem.

Somewhere in the code it is doing DHT on another port (mport).

arvidn commented 2 years ago

does netstat -l show you a UDP socket on mport?

arvidn commented 2 years ago
netstat -ulp

Might be the most helpful.

alannz42 commented 2 years ago

netstat -ulpn | grep qbittorrent

shows listeners on gport only for IPV4, IPv6 and localhost

( I don't want to publish my IP information on this forum ).

alannz42 commented 2 years ago

I have never been able to find a listener for mport.

This means that even if mport was found, made a fixed port, put in the GUI and opened in the firewall it would still fail as there is no code listening for the inbound connections.

These is something seriously wrong somewhere.

alannz42 commented 2 years ago

My suggestion is that qbit learns of other nodes through DHT and wants to learn about them.

It opens a connection to them on mport and has a conversation with them on mport. These nodes take mport as the port qbit is listening on and distributes this information to other nodes. Other nodes make inbound connections on mport to find there is nothing there.

Somewhere in the code qbit is making outbound DHT connections using port zero (which the OS allocates as a random free port). This port is remembered as mport.

This code ought to use gport not zero.

alannz42 commented 2 years ago

Please also read #12553

There is a clue there in the release notes to libtorrent.

alannz42 commented 2 years ago

Re #12553

In previous versions of the software mport was fixed as port 1.

My guess is someone changed it to zero (allocate free port). It probably should have been changed to gport.

arvidn commented 2 years ago

When you stop qBittorrent, do the blocked incoming packets taper off and disappear? It sounds like it. This would establish causation.

If you disabled DHT entirely, do the blocked incoming packets also taper off? If not, it could be an issue with a tracker or tracker announce. However, given that you see blocked DHT packets, it suggests it's related to the DHT.

There's also local peer service, which attempts to multicast an announce. If you happen to have a network where multicast works a hop or two outside of your local network, this could also affect things. For good measure, it would be a good idea to disable LSD and make sure that's not what's causing it too.

Since the "implied port" feature is enabled almost always, I wouldn't expect to find mport in the actual outgoing DHT messages, but it might be worth looking. In an announce packet you would see this string in the body of the packet:

1:q13:announce_peer

and also a string of this form:

4:porti<port-number>e

(where <port-number> is some integer listen port we're announcing). However, I would expect this port to be 0, and:

12:implied_porti1e

to be present.

If that assumption is correct, the more interesting field to look at in these messages would be the source port. Now, presumably the source port is gport. But is there any chance your NAT or firewall may rewrite it to mport? In an ideal case you would be able to look at your outgoing packets on the outside of your firewall.

alannz42 commented 2 years ago

When you stop qBittorrent, do the blocked incoming packets taper off and disappear? It sounds like it. This would establish causation.

Yes, they fade away over an hour.

If you disabled DHT entirely, do the blocked incoming packets also taper off? If not, it could be an issue with a tracker or tracker announce. However, given that you see blocked DHT packets, it suggests it's related to the DHT.

None obvious with DHT disabled. However, since mport changes with each invocation of qbit I can only determine mport statistically. If there are not a lot of unexpected blocked packets I can't tell them from the other thousands of attacks on my firewall.

There's also local peer service, which attempts to multicast an announce. If you happen to have a network where multicast works a hop or two outside of your local network, this could also affect things. For good measure, it would be a good idea to disable LSD and make sure that's not what's causing it too.

I have Enable local peer discovery disabled. Also all multicast and broadcasts are blocked at the firewall.

Since the "implied port" feature is enabled almost always, I wouldn't expect to find mport in the actual outgoing DHT messages, but it might be worth looking. In an announce packet you would see this string in the body of the packet:

1:q13:announce_peer

and also a string of this form:

4:porti<port-number>e

(where <port-number> is some integer listen port we're announcing). However, I would expect this port to be 0, and:

12:implied_porti1e

to be present.

If that assumption is correct, the more interesting field to look at in these messages would be the source port. Now, presumably the source port is gport. But is there any chance your NAT or firewall may rewrite it to mport? In an ideal case you would be able to look at your outgoing packets on the outside of your firewall.

That would be difficult to do since there are millions of packets traversing the firewall.

My IPV6 is not NATed so there are no port rewrites.

I know qbit is making outbound DHT connections from mport. These outbound connections succeed and they get a response from the remote node which correctly passes through the firewall to mport and back to qbit.

The problem is the unsolicited inbound connections to mport.

arvidn commented 2 years ago

I know qbit is making outbound DHT connections from mport. These outbound connections succeed and they get a response from the remote node which correctly passes through the firewall to mport and back to qbit.

ok, great! So we can conclude that libtorrent, for some reason, ends up sending DHT messages from a socket that is unbound (or bound to port 0). And (perhaps the most puzzling part) there is no log entry of this bind() call and whether it succeeds or not.

arvidn commented 2 years ago

There's a chance capturing those DHT packets in wireshark may contain some further clues. straceing the process for send(),sendmsg(),socket(),bind() etc. calls might also contain some clues. I can't make libtorrent do this locally, so there may be some configuration option you have that I don't.

How is IPv6 related to this? Does it only happen on IPv6? i.e. either the socket is bound to an IPv6 address but port 0, or the unbound socket is only used when sending packets to IPv6 destinations.

alannz42 commented 2 years ago

Now we understand the problem if we look at the history it provides an answer.

qbit 4.2.3 with libtorrent 1.2.6

This generated a huge number of unexpected inbound connections on port 1. Here mport was fixed at 1. This was reported a few days ago by another user (above).

If you look at the ChangeLog for libtorrent for the 1.2.5 release it states:

announce port=1 instead of port=0, when there is no listen port

This is EXACTLY the problem.

I guess at some stage it was changed back to port 0 (OS to allocate a random free port).

"when there is no listen port" - this looks like the bug. Somehow the code thinks there is no listen port. It should be gport.

Can you find where in the code this 0 was changed to a 1?

If you look at the logic around there I suspect it is broken - it should be gport.

arvidn commented 2 years ago

you were saying you saw inbound DHT messages to port 1 (earlier) and now to some other port. This cannot be explained simply by the announce port. If it was just the announce port changing you would only see incoming peer connections. i.e. TCP and uTP SYN packets.

Is it the case that you don't have a listen port open on IPv6? So when the IPv6 DHT node announces, it doesn't have a port to announce as your listen port?

You say that you specify gport as your listen port, but if you are reachable over both IPv4 and IPv6, you need to specify that port twice, like this (at the libtorrent level):

0.0.0.0:gport,[::]:gport
luzpaz commented 9 months ago

What's left here to do ?