DNS Encoder, Decoder, and Server
hbo-dnsd (also known as dnsd) is a Node.js package providing functionalities for encoding and decoding DNS messages, as well as an API to run custom authoritative DNS servers. Currently at version 0.9.8, its development appears to have ceased around 2012, judging by the provided examples and the specified Node.js engine compatibility (>= 0.8). The package differentiates itself by offering direct programmatic control over DNS message structures as JavaScript objects, allowing developers to implement highly customized DNS resolution logic. It enables the creation of dynamic DNS responses based on request parameters, unlike static DNS server configurations. Due to its age, it relies solely on CommonJS modules and is not actively maintained, making it potentially incompatible with modern Node.js versions or ESM-first projects.
Common errors
-
ReferenceError: require is not defined
cause Attempting to use `require('dnsd')` in an ES Module context (e.g., in a `.mjs` file or a project with `"type": "module"` in `package.json`).fixEnsure the file where `require('dnsd')` is used is treated as a CommonJS module. This can involve changing the file extension to `.cjs` or ensuring `"type": "commonjs"` is set in the nearest `package.json` for that file's scope. -
Error: listen EACCES: permission denied 0.0.0.0:53
cause The Node.js process attempted to bind to a privileged network port (like port 53) without sufficient operating system permissions (e.g., not running as root).fixRun the Node.js process with `sudo` (not recommended for production due to security implications) or configure system capabilities to allow non-root processes to bind to privileged ports. Alternatively, use a higher, unprivileged port (e.g., 5353) and configure network traffic redirection (e.g., `iptables` on Linux, or similar tools on other OS) from port 53 to the chosen unprivileged port. -
TypeError: Cannot read properties of undefined (reading 'listen') (or similar runtime errors related to Node.js core APIs)
cause `hbo-dnsd` was developed for Node.js 0.8, and its internal implementation might rely on Node.js core APIs that have changed, been deprecated, or removed in much newer Node.js versions.fixThis issue indicates deep incompatibility. The most effective fix is to migrate to a modern, actively maintained DNS library that supports current Node.js versions, as retrofitting this package for modern Node.js is impractical and risky.
Warnings
- breaking Outdated Node.js compatibility: The package specifies compatibility with Node.js >= 0.8. Running it on modern Node.js versions (e.g., Node.js 16, 18, 20+) is highly likely to lead to unexpected behavior, runtime errors, or security vulnerabilities due to significant API changes and deprecations in the Node.js core over the last decade.
- gotcha CommonJS-only Module: `hbo-dnsd` is written exclusively in CommonJS (`require()`) and does not provide an ES Module (ESM) export. Developers in modern Node.js projects configured for ESM (`"type": "module"` in `package.json` or `.mjs` files) will encounter issues.
- breaking Lack of Maintenance & Security: The package has not been updated since 2014 and is considered abandoned. This implies a critical lack of security patches for potential DNS-related vulnerabilities (e.g., DNS amplification, cache poisoning) or compatibility fixes for evolving network standards and operating system changes.
- gotcha Port 53 requires elevated privileges: Running a DNS server on the standard UDP port 53 typically requires root/administrator privileges on most operating systems. The examples provided use port 5353, which is unprivileged, but for an actual public DNS service, port 53 is necessary.
- gotcha No TypeScript definitions: The package does not ship with TypeScript type definitions (`.d.ts` files). This means users in TypeScript projects will lack type safety and autocompletion, potentially leading to runtime errors that would otherwise be caught at compile time.
Install
-
npm install hbo-dnsd -
yarn add hbo-dnsd -
pnpm add hbo-dnsd
Imports
- dnsd
import dnsd from 'dnsd'
const dnsd = require('dnsd') - createServer
import { createServer } from 'dnsd'const server = dnsd.createServer(...)
Quickstart
const dnsd = require('dnsd')
const server = dnsd.createServer(handler)
server.zone('example.com', 'ns1.example.com', 'us@example.com', 'now', '2h', '30m', '2w', '10m')
.listen(5353, '127.0.0.1')
console.log('Server running at 127.0.0.1:5353')
function handler(req, res) {
console.log('%s:%s/%s %j', req.connection.remoteAddress, req.connection.remotePort, req.connection.type, req)
const question = res.question[0]
, hostname = question.name
, length = hostname.length
, ttl = Math.floor(Math.random() * 3600)
if(question.type == 'A') {
res.answer.push({name:hostname, type:'A', data:"1.1.1."+length, 'ttl':ttl})
res.answer.push({name:hostname, type:'A', data:"2.2.2."+length, 'ttl':ttl})
}
res.end()
}
// To test, run this script and then in your terminal:
// $ dig @localhost -p 5353 example.com soa
// $ dig @localhost -p 5353 example.com a