npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

mdht

v3.1.3

Published

Mainline DHT

Downloads

15

Readme

mdht -- Mainline DHT implemented in node.js

Dynamic Hash Table customized for the Mainline DHT used by bittorrent to locate torrent peers without using a tracker. Includes BEP44 data storage. IPv4 only. References: BEP5, BEP44. Computes local BEP42 DHT node id from external IP address if provided.

Quick start

$ npm i mdht
$ echo "require('mdht/server')" > server.js
$ node server.js

server.js will connect to the global mainline DHT via default UDP port 6881 (which should be forwarded), by bootstraping from router.bittorrent.com:6881, and then will begin to respond to requests from other nodes. Configuration information and incoming requests are displayed on the console. The routing table and cryptographic seed are saved to disk for future restarts.

server.js interfaces between mdht.js (which in turn interfaces with the DHT network), the user (via the command line) and the disk (to preserve its state between sessions). It also accepts commands from clients to issue outgoing requests to other DHT nodes via HTTP PUTs on the same port.

Navigating to http://localhost:6881 (default port) in a browser loads a web page from server.js via HTTP GET, containing a simple UI for getting and putting BEP44 data and for announcing and getting peers. Alternatively, client/clientLib.js is available to include in custom clients running in a browser or running under Node.js. See client/clientTest.js for examples.

Terminology

Term | Description -----|------------ location | network location (6-byte buffer: 4-byte IPv4 address + 2-byte port); example: Buffer.from('ff0000011ae1', 'hex') represents 127.0.0.1:6881 id | DHT node id, infohash of a torrent, or target of BEP44 data (20-byte buffer) node | a member of the Mainline DHT network which uses UDP peer | a bittorrent client associated with a DHT node which uses TCP, usually on the same port

Usage (API)

const dhtInit = require('mdht')
const dht = dhtInit(options, update) // options is an object, update is a callback function

dhtInit options

Option | Description -------|------------ options.port | local UDP server port (int, default 6881) options.ip | external ip address used to compute DHT node id as per BEP42 (string, default: random id is used) options.seed | seed for generating ed25519 key pair for signing mutable data (32-byte buffer, default random) options.bootLocs | remote node locations to contact at startup (buffer of concatenated locations, default empty)

dhtInit returns an object with the following methods:

dht.announcePeer(ih, impliedPort, ({ numVisited: ..., numStored: ... }) => {}, onV)
dht.getPeers(ih, ({ numVisited: ..., numFound: ..., peers: ... }) => {}, onV)
dht.putData(v, mutableSalt, resetTarget, ({ numVisited: ..., numStored: ..., target: ..., v: ..., salt: ..., seq: ..., k: ..., sig: ... }) => {}, onV)
dht.getData(target, mutableSalt, ({ numVisited: ..., numFound: ..., v: ..., seq: ... }) => {}, onV)
dht.makeMutableTarget(k, mutableSalt)
dht.makeImmutableTarget(v)
dht.stop()
where:

announcePeer, getPeers, putData and getData initiate outgoing DHT queries to remote nodes and return information and/or results in their first callback function after all nodes have responded.

Their first callback function returns a single object with multiple properties pertinent to the method. Object properties that do not apply or were not found are omitted. For example, there will be no .peers or .v property if no peers or values are found; and .salt, .seq, .k and .sig are only returned for mutable data.

Their second callback function, onV, if not null or undefined, is called immediately whenever peer locations or BEP44 data are received from a remote node, with a single argument: an object with .target and .values for getPeers and announcePeer, or .ih and .v for getData and putData, plus .socket in both cases, which is just an object version of a node location { address: (string), port: (int) }.

makeMutableTarget and makeImmutableTarget are utilities for computing targets (node ids) for use with getData or putData, which can be called with the arguments target or resetTarget, respectively, along with mutableSalt, as provided by whomever stored the data. If the target is unknown, it can be computed with makeMutableTarget (if k and mutableSalt are known) or makeImmutableTarget (if v is known).

stop stops timers and closes the udp connection, thus stopping the DHT.

Argument | Description ---------|------------ ih | infohash, id of a torrent (buffer) impliedPort | if 1, ignore local port and use externally visible port (undefined, 0 or 1) target | id of BEP44 data (buffer) v | BEP44 data to be stored in the DHT (object, buffer, string or number) mutableSalt | if immutable BEP44 data then false or ''; if mutable data then true if no salt, or salt (non-empty string or buffer -- string will be converted to buffer, buffer will be truncated to 64 bytes) resetTarget | if not null, a target used to reset the timeout of previously stored mutable data (v is ignored in this case) (buffer) k | public key used to make a mutable target (buffer); if null, local public key is used

Property | Description ---------|------------ values | array of peer locations which have the torrent with infohash ih target | computed id of BEP44 data v | for putData, BEP44 data actually stored (may be a retrieved value if resetTarget is used); for getData, retrieved BEP44 data salt | salt actually used (<= 64-byte buffer) seq | sequence number (int) of mutable data; outgoing/incoming for putData/getData k | public key used to sign and verify mutable data (32-byte buffer) sig | ed25519 signature of salt, v and seq (64-byte buffer)

update is a function which signals the calling program and is called with two arguments (key, value)

Key | Signal | Value ----|--------|------ 'udpFail' | initialization failed | local port (int) that failed to open; calling program should restart using a different port 'id' | initialized | id actually used to create routing table 'publicKey' | initialized | public key (k) actually used for ed25519 signatures 'listening' | local udp socket is listening | local socket 'ready' | bootstrap is complete | number of remote nodes visited during bootstrap 'incoming' | incoming query object | { q: query type (string), socket: remote socket } 'error' | incoming error object | { e: [error code (int), error message (string)], socket: remote socket } 'nodes' | periodic report | buffer packed with node locations from the routing table; may used for disk storage 'closest' | periodic report | array of node ids from the routing table, the closest nodes to the table id 'peers' | periodic report | { numPeers: number of stored peer locations, numInfohashes: number of stored infohashes } 'data' | periodic report | number of BEP44 stored data items 'spam' | detected spammer node, temporarily blocked| 'address:port' 'dropNode' | node dropped from routing table | 'address:port' 'dropPeer' | peer location dropped from storage | 'address:port' 'dropData' | data dropped from BEP44 storage | 'target' (hex string)

BEP42 DHT Security extension

As of v3.1.0, mdht.js contains BEP42 code, partially implemented. The code is used to generate a BEP42 compliant local DHT node id given the externally visible IP address. However, BEP42 is not enforced on remote DHT nodes. On the server.js log output, remote IP addresses are prefixed with an asterix when the corresponding id is not compliant. At this time, only a small percentage of DHT nodes are compliant.