alanmcgovern / monotorrent

The official repository for MonoTorrent, a bittorrent library for .NET
https://github.com/alanmcgovern/monotorrent
MIT License
1.15k stars 397 forks source link

Connection Authentication Advice #556

Closed borigas closed 2 years ago

borigas commented 2 years ago

Thanks for all your work on a great library!

I'm using monotorrent to distribute software updates across the internet to IoT devices and am looking for a way to authenticate connections to avoid allowing unauthorized devices from downloading my binaries. I'm currently using an IPSec tunnel, but it has had some issues with firewalls so I'm looking for alternatives.

One option appears to be private torrents, but my understanding is that only secures access to the tracker. I think if you know an IP/port for a peer, you can connect directly. Is that accurate?

Another partially formed idea is using web seeds and sticking an http proxy in front of the connection to do authentication. Not sure exactly if/how it'd work yet.

Are there any other authentication options available that would secure the connection to the peers? Do you have any advice? Thanks again for all your help!

alanmcgovern commented 2 years ago

One option appears to be private torrents, but my understanding is that only secures access to the tracker. I think if you know an IP/port for a peer, you can connect directly. Is that accurate?

Yup. The absolute best security for private torrents/trackers is that the infohash will not be announced to DHT so you cannot find peers there, and also 'unauthenticated' peers will get an empty response if they announce to the private tracker. If you could get your hands on the infohash and the ip/port for a single peer, you'd be able to get the data using any bittorrent client.

Another partially formed idea is using web seeds and sticking an http proxy in front of the connection to do authentication. Not sure exactly if/how it'd work yet.

There are two plausible ways to implement something like this but allow standard peer-to-peer connections. If you use webseeds, then you may as well not use bittorrent because a 'web seed' is an overcomplicated HTTP get call, which is useful only to bootstrap a bittorrent swarm when there are no other seeders available :)

Option 1: The essence of what you'd need to do would be to create a custom SocketPeerConnection.

To authenticate outgoing connections, you could tweak the 'ConnectAsync' method to call Socket.Connect, and then send/receive whatever data you need to authorize the connection. If authorization fails, just close the socket. If it succceeds, return the socket and the engine will continue with the standard bittorrent handshaking.

To authenticate incoming connections, you'll need a custom [IPeerConnectionListener](https://github.com/alanmcgovern/monotorrent/blob/master/src/MonoTorrent.Connections/MonoTorrent.Connections.Peer/PeerConnectionListener.cs. Here you'll do the same dance - once an incoming connection is received, you must send/receive your authentication packets, and once things are successful you can pass the Socket to the library (via the ConnectionReceived event) and then monotorrent will continue with the normal bittorrent handshaking process.

Option 2: Instead of a custom IPeerConnection, just create a custom IPeerConnector. It's a simpler API and gives you the control you need.

You will still need a custom IPeerConnectionListener as described in Option 1.

You can find a custom IPeerConnector implementation which addsSOCKS5 support for MonoTorrent 3.x : https://github.com/alanmcgovern/monotorrent.socks5/tree/main/src/MonoTorrent.Socks5 . It sets up a socks5 proxy for web requests as well as peer connections, so it's a bit more complicated :)

borigas commented 2 years ago

Really appreciate the thoughtful answer. I didn't know those hooks existed. They should make this much easier than I was expecting. Thanks again.

alanmcgovern commented 2 years ago

No worries! Do let me know if you have any issues using these APIs and extension points. They're mostly new as part of the 3.0 API and were primarily to help split some dependencies within monotorrent itself, and give some compile-time enforcement that things should be extensible.

I'm always interested to know if the extension points exposed through this library are sufficient to add the capabilities people need, and this looks like a clear case of "The extension points should work... right???" :)

lostmsu commented 7 months ago

BTW, I looked at this, and it seems I should create a new EncryptionType instead. The reason is that at least in my case I need to authenticate the incoming connection in regards to the infohash it is looking for. And to ensure the client does not authenticate for one infohash but then ask for another in the handshake, the authentication has to happen after or during the initial handshake (e.g. peer should send authentication token along with the handshake).

Another issue is ensuring that the client is who they claim to be, otherwise another client could connect to you, take your handshake message and forward it to someone else (this won't work with encryption enabled though, cause they would not be able to decrypt the stream then).

Would appreciate an insight on the best way to do this, also if anyone would be interested in this kind of extension be a part of MonoTorrent.