Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Running private DHTs #22

Open
tetsuo opened this issue Oct 7, 2019 · 11 comments
Open

Running private DHTs #22

tetsuo opened this issue Oct 7, 2019 · 11 comments

Comments

@tetsuo
Copy link

tetsuo commented Oct 7, 2019

README says:

To run a fully private DHT, start two or more dht nodes with an empty bootstrap array (dht({bootstrap:[]})) and then use the addresses of those nodes as the bootrstrap option in all other dht nodes.

But dht({ bootstrap: [] }) never fires a listening event.

Can you show an example for running a private bootstrap node?

@davidmarkclements
Copy link
Contributor

You need to call listen:

const dht = require('@hyperswam/dht')

const node = dht({
  ephemeral: true,
  // make ourselves the bootstrap node
  bootstrap: []
})

node.listen()

node.on('listening', () => {
  const { address, port } = node.address()

  console.log(`listening on ${address}:${port}`)
})

@tetsuo
Copy link
Author

tetsuo commented Oct 7, 2019

Thank you @davidmarkclements

It looks like it is not required to call listen when you have a list of bootstrap nodes already.

const node = dht()
node.on('listening', () => {
  console.log('this fires')
})

@davidmarkclements
Copy link
Contributor

Yeah we should address that with either docs or alter behaviour - @mafintosh what do you think?

@tetsuo
Copy link
Author

tetsuo commented Oct 7, 2019

One more thing:

I'm expecting these two to not connect at all, but they do:

import crypto from 'crypto'
import hyperswarm, { Hyperswarm } from 'hyperswarm'

const topic = crypto.randomBytes(32)

const swx = hyperswarm({ bootstrap: [], ephemeral: true })
const swy = hyperswarm({ bootstrap: [], ephemeral: true })

swx.on('connection', socket => {
  socket.write('a')
})

swy.on('connection', socket => {
  socket.on('data', console.log)
})

swx.join(topic, { lookup: false, announce: true })

swy.join(topic, { lookup: true, announce: false })

@RangerMauve
Copy link

Hyperswarm uses MDNS for discovering peers on the local network. That might be how the two are finding each other.

@mafintosh
Copy link
Contributor

We just released local discovery through the DHT yesterday.
If mdns is giving you trouble you can try that using the announceLocalAddress flag.

const swarm = hyperswarm({
  announceLocalAddress: true
})

@tetsuo
Copy link
Author

tetsuo commented Oct 7, 2019

Hyperswarm uses MDNS for discovering peers on the local network. That might be how the two are finding each other.

@RangerMauve

I see now, thanks!! I thought hyperswarm only worked with dht-rpc.

But I guess it's not possible to disable mdns completely:

https://github.com/hyperswarm/discovery/blob/8b41a510b295bbaad1113845f397352545c12fdd/index.js#L152

@mafintosh

Well, if mdns is already working then that means this module acts a little bit differently than its predecessor (discovery-swarm). In discovery-swarm, you receive a connection event for all the different types of connections.

What I'm actually trying to figure out is how to deal with duplicates.

I'm creating a noise-peer socket to authenticate the other end when I receive the connection, but destroying a socket (e.g., throwing 'already connected') starts an infinite reconnection loop.

This of course only happens when a peer has both the announce and lookup flags set.

My workaround is to make a Swarm either an initiator or non-initiator, but not both.

But what I really would love to achieve is:

  • to be able to identify if a connection is an initiator or not (using details.client) and initialize the noise stream that way, so I can have a peer that can announce and lookup at the same.

  • connect to a peer only once regardless of the connection type and gracefully destroy a socket I received via the connection.

  sw.on('connection', socket => {
    const secure = noise(socket, initiator, {
      pattern: 'XX',
      staticKeyPair: keys,
      onstatickey: (remoteKey, done) => {
        const hex = remoteKey.toString('hex')
        if (remoteKeys.has(hex)) {
          return done(new Error('already connected'))
        }
        remoteKeys.add(hex)
        sockets.set(secure, hex)
        if (onconnect) {
          onconnect(hex)
        }
        if (onupdate) {
          onupdate(remoteKeys)
        }
        done(null)
      }
    })

@tetsuo
Copy link
Author

tetsuo commented Oct 7, 2019

Here is my naive attempt to disable multicast completely:

https://github.com/tetsuo/discovery/commit/116c74c846467996f74545253d4965f33059bd12

sadly {bootstrap: [local], multicast: false} doesn't seem to work

@sallespro
Copy link

During V5 exploration, DHT does not seem to fire the listen event when bootstrapped.

const node = new DHT({  ephemeral: true, bootstrap: []});
server.on('listening', () => { console.log(server.address())})

do one need to create two nodes before the first actually listen ?
this is needed to setup the host/post of the second node.

@mafintosh
Copy link
Contributor

@sallespro sorry missed your comment. You need at least one none ephemeral DHT running for a server to announce itself (listen)

@draeder
Copy link

draeder commented Feb 20, 2023

I have been struggling all day today to get my private bootstrap DHT to work. This issue is the only place I can find more detailed documentation about it, but it is still not working.

I have my bootstrap server code, bootstrap.js:

import DHT from "@hyperswarm/dht"

const bootstrap = DHT.bootstrapper(10001, "127.0.0.1", { ephemeral: true, bootstrap: [], announceLocalAddress: true })

bootstrap.on('listening', () => {
  console.log(bootstrap.localAddress())
})

bootstrap.on('connection', () => {
  console.log("Got a connection??") // This never fires
})

Then my server & client code, test.js:

import Hyperswarm from "hyperswarm"

const swarm = new Hyperswarm({ bootstrap: ["127.0.0.1:10001" ], ephemeral: true, announceLocalAddress: true })

swarm.on("connection", ()=> {
  console.log("connected!")
})

const topic = Buffer.alloc(32).fill('hello world')
const discovery = swarm.join(topic)
await discovery.flushed()

test.js works fine when I do not try to point it at my bootstrap server. It does not work when I do.

I'm running two instances of test.js as well as bootstrap.js on the same computer, if that's important.

Any direction is greatly appreciated!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants