arvidn / libtorrent

an efficient feature complete C++ bittorrent implementation
http://libtorrent.org
Other
5.23k stars 992 forks source link

libtorrent 1.1.x privacy leak - connects directly to peers instead of via interface configured in listen_on() #1605

Closed stewartadam closed 7 years ago

stewartadam commented 7 years ago

libtorrent 1.1.1 ignores its bound interface on start (e.g. 127.0.0.1) and will initiate connections to peers directly on the default interface anyways, causing privacy leaks when using a VPN.

I was able to reproduce this using deluge-daemon (based on Python2 bindings) as well as from the sample client bindings/python/client.py (version from libtorrent-1_1_1 git tag) after modifying its listen_on() call to initialize to use 127.0.0.1.

When binding to 127.0.0.1 or other non-Internet connected interfaces, tracker announces fail and peer connectivity fails as expected but somehow the torrent will have DL/UL traffic anyways.

This issue is NOT present with libtorrent 1.0.9,

OS: Fedora 24 (libtorrent 1.0.9), Fedora 25 (libtorrent 1.1.1) Arch: x86_64 Compiler: gcc-6.x

stewartadam commented 7 years ago

Here is example output from client.py on v1.1.1 (IP addresses redacted):

 peer (a:50449, Unknown) connecting to peer (uTP)
 peer (b:6881, Unknown) connecting to peer (uTP)
 peer (c:19900, Unknown) connecting to peer (uTP)
 peer (d:36780, Unknown) connecting to peer (uTP)
 peer (e:63243, Unknown) connecting to peer (uTP)
 peer (a:50449, Unknown) disconnecting (uTP) [connect] [system]: Invalid argument (reason: 0)
 peer (a:50449, Unknown) connecting to peer (TCP)
 peer (b:6881, Unknown) disconnecting (uTP) [connect] [system]: Invalid argument (reason: 0)
 peer (b:6881, Unknown) connecting to peer (TCP)
 peer (c:19900, Unknown) disconnecting (uTP) [connect] [system]: Invalid argument (reason: 0)
 peer (c:19900, Unknown) connecting to peer (TCP)
 peer (d:36780, Unknown) disconnecting (uTP) [connect] [system]: Invalid argument (reason: 0)
 peer (d:36780, Unknown) connecting to peer (TCP)
 peer (e:63243, Unknown) disconnecting (uTP) [connect] [system]: Invalid argument (reason: 0)
 peer (e:63243, Unknown) connecting to peer (TCP)
 (http://torrent.fedoraproject.org:6969/announce) (-1) Invalid argument "" (1)
 peer (e:63243, Unknown) disconnecting (TCP) [connect] [system]: Connection refused (reason: 0)
 peer (f:63853, Unknown) connecting to peer (uTP)
 peer (f:63853, Unknown) disconnecting (uTP) [connect] [system]: Invalid argument (reason: 0)
 peer (f:63853, Unknown) connecting to peer (TCP)
 peer (d:36780, Unknown) disconnecting (TCP) [sock_read] [system]: Connection reset by peer (reason: 0)
 peer (g:30455, Unknown) connecting to peer (uTP)
 peer (g:30455, Unknown) disconnecting (uTP) [connect] [system]: Invalid argument (reason: 0)
 peer (g:30455, Unknown) connecting to peer (TCP)

You can see that it is connecting to peers anyways:

name: Fedora-Server-dvd-x86_64-25
downloading 29.5600% ##############-----------------------------------
total downloaded: 596673494 Bytes
peers: 4 seeds: 3 distributed copies: 3

download:   57kB/s ( 330kB) upload:    2kB/s (   5kB) info-hash: 62da42b818ebf65c12069f5d1f7b6aa01250a38b
next announce: 0:00:00
tracker:
...
stewartadam commented 7 years ago

On 1.0.9. output is similar:

Fedora-Server-dvd-x86_64-25 peer (a:51413, Unknown) connecting to peer (uTP)
Fedora-Server-dvd-x86_64-25 peer (b:17168, Unknown) connecting to peer (uTP)
Fedora-Server-dvd-x86_64-25 peer (c:58253, Unknown) connecting to peer (uTP)
Fedora-Server-dvd-x86_64-25 peer (a:51413, Unknown) disconnecting: [system] Invalid argument
Fedora-Server-dvd-x86_64-25 peer (b:17168, Unknown) disconnecting: [system] Invalid argument
Fedora-Server-dvd-x86_64-25 peer (c:58253, Unknown) disconnecting: [system] Invalid argument
Fedora-Server-dvd-x86_64-25 peer (a:51413, Unknown) connecting to peer (TCP)
Fedora-Server-dvd-x86_64-25 peer (b:17168, Unknown) connecting to peer (TCP)
Fedora-Server-dvd-x86_64-25 peer (c:58253, Unknown) connecting to peer (TCP)
Fedora-Server-dvd-x86_64-25 peer (a:51413, Unknown) disconnecting: [system] Invalid argument
Fedora-Server-dvd-x86_64-25 peer (b:17168, Unknown) disconnecting: [system] Invalid argument
Fedora-Server-dvd-x86_64-25 peer (c:58253, Unknown) disconnecting: [system] Invalid argument

But no peers are actually connected:

name: Fedora-Server-dvd-x86_64-25
downloading 29.6364% ###############----------------------------------
total downloaded: 598213686 Bytes
peers: 0 seeds: 0 distributed copies: 0

download:     0B/s (    0B) upload:   198B/s (    0B) info-hash: 62da42b818ebf65c12069f5d1f7b6aa01250a38b
next announce: 0:00:08
tracker:
stewartadam commented 7 years ago

If you have a Fedora system and want to repro, you can do so easily simply by switching between these RPMs: 1.0.9: https://koji.fedoraproject.org/koji/buildinfo?buildID=746153 1.1.1: https://koji.fedoraproject.org/koji/buildinfo?buildID=805170

arvidn commented 7 years ago

The listen interface controls which interface the listen socket binds to. That's incoming connections, as far as I know, it has never meant to affect outgoing connections. I don't believe it's been documented as anything other than that.

There's a different setting, in RC_1_1, outgoing_interfaces which it sounds like you're after. In previous versions of libtorrent it was a function call use_interface(). However, binding a socket to an interface does not affect the interface outgoing packets are sent from. The routing table controls that. There's no portable way of indicating that you want an outgoing connection to override your routing table.

In RC_1_1 (and I believe 1.1.1) there is some code to attempt to use (platform specific) bind-to-device, to force a socket to communicate over a specific nic. Would you mind rerunning your test and make sure you set the outgoing_interfaces settings?

stewartadam commented 7 years ago

I noticed that in the docs and was testing it as well -- but I still see my ISP's IP in the external IP received: a.b.c.d message.

Sample I used:

settings = lt.session_settings()
settings.listen_interfaces = "127.0.0.1:46240"
settings.outgoing_interfaces = "tun1"
settings.anonymous_mode = True
settings.enable_upnp = False
settings.enable_dht = False
ses = lt.session(settings.__dict__, flags=0)
ses.set_settings(settings)
ses.listen_on(46240, 46240, '127.0.0.1')
...

edit -- it looks to me like the listen_interfaces and outbound_interfaces settings are not exposed via Python (among many others missing) -- are the bindings out of date?

cas-- commented 7 years ago

You need to use the new settings_pack: http://libtorrent.org/reference-Settings.html#settings_pack

session.get_settings()['outgoing_interfaces']
session.apply_settings({'outgoing_interfaces':''})
stewartadam commented 7 years ago

That works, thanks! Setting it to an lo or a non-existent interface prevents outgoing connections too, which is the behaviour I was after.

Given #1609, would be great to have additional documentation around use of settings_pack from Python and to have client.py updated.

cas-- commented 7 years ago

There is nothing different in the documentation about using the settings_pack in the bindings, that particular ticket is more to do with an edge use-case.

Oh if your issue is resolved could you close this issue.

stewartadam commented 7 years ago

This one can be closed and I see the client.py example was updated recently, thanks.