Patch qBittorrent: Listening on port while using proxy
First things first, to achieve that, we need a proxy where we can set up port forwarding on it, then we modify and compile qbittorrent ourselves. A VPN can work, but that requires UPnP/PMP support of the VPN, which many lacks in. And also, use with caution, if you do not want to expose your IP address accidentally, always use a VPN.
Recently, I came across a situation where I need to do some seeding, but the network I was on requires a proxy to gain access to the Internet. Naively, I set up the proxy settings in qbittorrent, quickly found out that it did not work at all.
After some long nights searching and digging, it turned out that the library qbittorrent (along with several other FOSS torrenting software) depends on, libtorrent, on some recent versions, completely disables port listening while Use proxy for peer connections
is enabled, to avoid network traffic leakage, rendering it impossible to do seeding at all while using a proxy. But the authors never make this clear, and I suspect that qbittorrent authors haven't even realized this behavior. The setting page on qbittorrent doesn't reflect the change in port listening section at all when you enable proxy for peers.
So here come the easier parts. We find the corresponding conditional code, modify, patch, then recompile libtorrent. No changes in qbittorrent are needed, only libtorrent. Check out my patch file listen-when-proxy-on.patch
based on v2.0.7
of libtorrent at end of this article.
Since I'm on archlinux (and yes, BTW, I'm using arch :D), patching software is relatively convenient. Go grab the PKGBUILD
script from arch offical package page https://archlinux.org/packages/extra/x86_64/libtorrent-rasterbar/ (source files link), add our patch into prepare()
section like this:
prepare() {
makedir -p build
cd "$pkgname-$pkgver"
patch --forward --strip=1 --input="${srcdir}/listen-when-proxy-on.patch"
}
and do makepkg -Acs
to compile the package. After it's done, sudo pacman -U libtorrent...
to do a force install. Then we need to do some config stuff.
- Fire up qbittorrent and set a fixed listening port, say
7890
; - Then set up port forwarding on the proxy server we're gonna use. I'm using FRP for port forwarding on my proxy server, so I set up a tcp reverse tunnel with
local_port
as7890
on my computer; - Go to qbittorrent advanced settings page, enable
Allow multiple connections from the same IP address
; - Finally, set proxy server for qbittorrent, and enable proxy for peer connections. Do not turn on UPnP/NAT-PMP. But if you know what you're doing, the patch ensures that they can be turned on along with proxy.
Now we can add a torrent and see, it should start listening for incoming connections from the reverse tunnel we just set on the proxy server. And we can also see all the incoming peers shown as localhost or 127.0.0.1
. No worries, the bittorrent protocol doesn't care about peers' ip addresses, from everyone else's perspective, you're just running qbittorrent on 7890
on the proxy server, everything works fine.
Disclaimer: qBittorrent and libtorrent are FOSS, the patch shared here is also free from restrictions. Please comply with your local regulations, use with caution and at your own risks.
listen-when-proxy-on.patch
:
diff --git a/src/session_impl.cpp b/src/session_impl.cpp
index e25434926..8f38a3344 100644
--- a/src/session_impl.cpp
+++ b/src/session_impl.cpp
@@ -2016,7 +2016,7 @@ namespace {
// if we don't proxy peer connections, don't apply the special logic for
// proxies
- if (m_settings.get_int(settings_pack::proxy_type) != settings_pack::none
+ if (false && m_settings.get_int(settings_pack::proxy_type) != settings_pack::none
&& m_settings.get_bool(settings_pack::proxy_peer_connections))
{
// we will be able to accept incoming connections over UDP. so use
@@ -2774,7 +2774,7 @@ namespace {
// directly.
// This path is only for accepting incoming TCP sockets. The udp_socket
// class also restricts incoming packets based on proxy settings.
- if (m_settings.get_int(settings_pack::proxy_type) != settings_pack::none
+ if (false && m_settings.get_int(settings_pack::proxy_type) != settings_pack::none
&& m_settings.get_bool(settings_pack::proxy_peer_connections))
return;
@@ -5473,7 +5473,7 @@ namespace {
// connections. Not even uTP connections via the port we know about.
// The DHT may use the implied port to make it work, but the port we
// announce here has no relevance for that.
- if (sock->flags & listen_socket_t::proxy)
+ if (false && sock->flags & listen_socket_t::proxy)
return 0;
if (!(sock->flags & listen_socket_t::accept_incoming))
@@ -5513,7 +5513,7 @@ namespace {
return std::uint16_t(sock->tcp_external_port());
}
- if (m_settings.get_int(settings_pack::proxy_type) != settings_pack::none
+ if (false && m_settings.get_int(settings_pack::proxy_type) != settings_pack::none
&& m_settings.get_bool(settings_pack::proxy_peer_connections))
return 0;
@@ -5611,7 +5611,7 @@ namespace {
if (!s->natpmp_mapper
&& !(s->flags & listen_socket_t::local_network)
- && !(s->flags & listen_socket_t::proxy))
+ && !(s->flags & listen_socket_t::proxy && false))
{
// the natpmp constructor may fail and call the callbacks
// into the session_impl.
@@ -6833,8 +6833,9 @@ namespace {
// there's no point in starting the UPnP mapper for a network that isn't
// connected to the internet. The whole point is to forward ports through
// the gateway
+ // Enable UPnP anyway, even when on proxy, we can deal with this ourselves.
if ((s->flags & listen_socket_t::local_network)
- || (s->flags & listen_socket_t::proxy))
+ || (s->flags & listen_socket_t::proxy && false))
return;
if (!s->upnp_mapper)