mafintosh / utp-native

Native bindings for libutp
MIT License
103 stars 38 forks source link

clarifications #6

Closed dominictarr closed 3 years ago

dominictarr commented 8 years ago

when the "second api" says it's similar to the net interface, it means it's a reliable stream, right? https://github.com/mafintosh/utp-native#socketonconnection-connection

this doesn't mention how to do NAT hole punching, is there a module for that?

mafintosh commented 8 years ago

Yes the net like api is reliable. https://github.com/mafintosh/discovery-swarm implements hole punching on top using a dns server

dominictarr commented 8 years ago

Hmm, I think I need something a little bit more low level than that (so can control privacy implications, etc)

what is the minimum I need to do hole punching?

mafintosh commented 8 years ago

You need a central known server to distribute the external udp port of two peers to the corresponding peers. Here a quick gist of what this could look like.

// server.js
var dgram = require('dgram')
var server = dgram.createSocket('udp4')
var otherRinfo = null

server.on('message', function (message, rinfo) {
  if (otherRinfo) {
    send(otherRinfo, rinfo)
    send(rinfo, otherRinfo)
  }
  otherRinfo = rinfo
})

server.bind(10000)

function send (rinfo, to) {
  var buf = Buffer(JSON.stringify({host: rinfo.address, port: rinfo.port}))
  server.send(buf, 0, buf.length, to.port, to.address)
}

The clients

var utp = require('utp-native')

var socket = utp()

socket.on('message', function (message) {
  // server send us a peer, try and connect
  var otherPeer = JSON.parse(message)
  var connection = socket.connect(otherPeer.port, otherPeer.host)

  connection.write('hello world')
})

// emitted when a new utp connection is established
socket.on('connection', function (connection) {
  console.log('new peer')
  connection.pipe(process.stdout)
})

// send udp message to known-server.com
socket.bind(0, function () {
  socket.send(Buffer('hello'), 0, 5, 10000, 'known-server.com')
})

This is probably the minimum needed for hole punching

mafintosh commented 8 years ago

Let me know if this works :) I've personally learned a lot about hole punching from reading this blog post from ZeroTier, https://www.zerotier.com/blog/?p=226

dominictarr commented 8 years ago

Awesome. so, once I have that, i'd just bind a utp server (with the second mode where send and receive are the same port) to that port also. I'm guessing this means I could also connect to a server via utp and then ask it my current ip:port? (and then just continue using the utp server? This would have the best privacy implications because utp is reliable and so it could be encrypted via secret-handshake)

mafintosh commented 8 years ago

Yea! You'd basically only use a single utp instance in your entire app. Interesting idea about connecting to the known server using secret-handshake over utp as well. That would work great!

mafintosh commented 8 years ago

This has an added benefit that you only need a single open fd for all your connections

dominictarr commented 8 years ago

that is a pretty good feature for a p2p application!

dominictarr commented 8 years ago

question: will this code create two duplex connections between the peers. I see that the server waits for two messages, then sends the other's info to each. then each peer attempts a connection to the other.

I guess one of them might fail, so you create two and then close the other one? or does utp handle that for you?

mafintosh commented 8 years ago

usually when hole punching only one of the two streams will succeed. utp does not handle picking one of them if both succeed. thats up to you. what i usually do is send a peer id over the wire as the first message and filter out dups that way.

mafintosh commented 8 years ago

btw, a module that did simple 1-to-1 hole punching would be super useful in general

dominictarr commented 8 years ago

yeah. I think the way i'll approach it, (in the secure-scuttlebutt context) is to first create a way to tunnel through a pub to another peer, so you can connect to them that way, and then bootstrap a p2p connection. This can also be pretty private, because peers could also use layered link encryption when tunneling.

(actually, acting as introducers has always been part of the idea with ssb pubs. since running a pub is easy, and useful, quite a few people choose to run them, and then if they act as introducers then we don't have a centralized hub)

robertkowalski commented 6 years ago

btw, a module that did simple 1-to-1 hole punching would be super useful in general

@mafintosh https://github.com/bitfinexcom/boxgloves takes a UTP socket and emits punched events given certain control characters are received. There is also a handshake functionality, where a handshake event is emitted after a certain amount of punches are received and sent.

example:

https://github.com/bitfinexcom/boxgloves/blob/6b6e5da705da5980bb5f0aa9f06059fd8d88536f/examples/simple.js#L30-L49