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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@sammachin/node-red-dhcp

v0.1.0

Published

Node-RED nodes for building a DHCP server: receive DHCP requests, construct the reply in a flow, and send it

Readme

node-red-contrib-dhcp

Node-RED nodes for building a DHCP server, where the flow decides what every reply contains.

[dhcp request] → [dhcp options] → [dhcp options] → … → [dhcp response]
   emits MAC        append params      append params      format + send

Built on node-dhcp, used purely as a protocol codec: its own server answers packets from a static, synchronous config, which a Node-RED flow can never drive. Here nothing is answered automatically — a request comes into the flow, the flow builds the reply, and the response node puts it on the wire.

Install

cd ~/.node-red
npm install node-red-contrib-dhcp

The nodes

dhcp request

Listens for DHCP messages and emits one message per packet. Configure the bind address and port (67 by default).

msg.topic   // 'DISCOVER' | 'REQUEST' | 'INFORM' | 'RELEASE' | 'DECLINE'
msg.payload // { mac, xid, hostname, requestedIp, clientId, vendorClassId,
            //   requestedParams, ciaddr, giaddr, broadcastFlag, options }
msg.dhcp    // handle for the downstream nodes - keep it on the message

msg.payload.mac is normalised to aa:bb:cc:dd:ee:ff, so it can be compared against a reservation table directly.

Several request nodes may bind the same address and port; they share one socket.

dhcp options

Appends parameters to the reply being built. Each node holds a list of rows — a parameter and a value — and you can chain as many nodes as you like; a later one wins for anything already set.

The dropdown lists every option node-dhcp knows about (netmask, router, dns, leaseTime, domainName, bootFile, …) plus the four packet header fields:

| field | meaning | | --- | --- | | yiaddr | the address being offered — required for an OFFER or ACK | | siaddr | next server / TFTP address | | sname | server host name | | file | boot file name |

Values are typed inputs, so they can come from the message, flow or global context, an environment variable, or a JSONata expression. Each is converted to the parameter's DHCP type — dns accepts 8.8.8.8, 8.8.4.4, leaseTime accepts 3600, nbNodeType accepts H-node — and an unconvertible value raises an error a catch node can handle rather than producing a malformed packet.

There is no address pool and no lease store. What to hand out is the flow's decision.

Vendor sub-options (option 43)

Option 43 is a container rather than a value: it holds a run of sub-options, each one a code, a length and that many bytes, and what goes in it is the vendor's business. Selecting vendor reveals a second line on the row for the sub-option code and how to encode the value — text, an IPv4 address or list, an 8/16/32-bit number, or hex bytes.

| use | sub-option | encode as | value | | --- | --- | --- | --- | | UniFi controller | 1 | IPv4 address | 192.168.1.10 | | PXE discovery control | 6 | 8-bit number | 11 | | PXE boot server list | 8 | hex bytes | 80 00 01 c0 a8 01 0a |

Unlike other parameters, vendor rows accumulate rather than overwrite, so a block is built from as many rows — and as many nodes — as it needs. Leave the sub-option code blank to drop the encoded bytes into the block verbatim, and a value that is already an array of numbers is taken as raw bytes whatever the encoding, so a function node can build anything the encodings don't cover.

The example above puts 43 = 01 04 c0 a8 01 0a on the wire.

Options by numeric code

Any option, by numeric code sets any option at all — typically something in the 224–254 site-specific range, or one a vendor invented that has no name here. Give the code and the same choice of encoding as vendor sub-options:

| option code | encode as | value | on the wire | | --- | --- | --- | --- | | 224 | text | site-specific | e0 0d 73 69 74 65 … | | 240 | IPv4 address | 10.0.0.1 | f0 04 0a 00 00 01 | | 251 | hex bytes | de:ad:be:ef | fb 04 de ad be ef |

Codes that already have a name are refused, naming it — option 6 is 'dns' - select it by name instead — since the value would otherwise be encoded two different ways.

Custom codes are registered with the protocol layer the first time they are sent, which also means incoming packets carrying them are decoded rather than skipped. Anything else reading the reply needs to do the same: node-dhcp's parser silently drops codes it doesn't know, as test/send-discover.js does for the site-specific range.

dhcp response

Formats everything accumulated and sends it from the request node's socket.

  • Reply — automatic (DISCOVER → OFFER, REQUEST/INFORM → ACK), or a fixed OFFER, ACK or NAK. A NAK carries no address; give a reason with the message option.
  • Server ID — option 54. Defaults to the bind address, or the host's first non-internal IPv4 address.
  • Send to — automatic follows RFC 2131 §4.1: the relay agent if giaddr is set, otherwise unicast to ciaddr if the client already has an address, otherwise broadcast. Unicasting to the offered address would need a raw socket to prime the ARP cache, which Node cannot do. back to sender replies to the source address and port, which is what a real client sees anyway (clients always send from port 68) and lets a test client on an ephemeral port get the reply without root.

Trying it out

Import DHCP server from the Node-RED examples menu (Import → Examples → node-red-contrib-dhcp). It listens on 127.0.0.1:6767, so no privileges are needed:

node test/send-discover.js --port 6767 --mac aa:bb:cc:dd:ee:ff

The script sends a DISCOVER and prints the parsed OFFER.

For real clients, set the request node to port 67 and the response node's Send to back to automatic. Port 67 is privileged: run Node-RED as root, or grant the capability once:

sudo setcap 'cap_net_bind_service=+ep' $(readlink -f $(which node))

Watch the exchange with:

sudo tcpdump -i eth0 -n port 67 or port 68 -vv

Do this on an isolated network. A second DHCP server on a live LAN will hand out addresses to anything that asks.

Tests

npm test

Covers the option catalogue and coercion, reply construction (including a round trip through node-dhcp's parser), destination selection, and a real DISCOVER → OFFER exchange over loopback.

Licence

MIT