pyke369 / pdhcp

an efficient programmable BOOTP/DHCP client/server/relay
MIT License
20 stars 3 forks source link

PDHCP

An efficient programmable BOOTP/DHCP client/server/relay (re-)written in Go.

Presentation

pdhcp is a DHCP toolbox, which can be used to implement client, server or relay roles in a standard DHCP infrastructure. Contrary to most DHCP packages, pdhcp does not directly implement the business logic of a standard DHCP system, but relies on external helpers (or backends) for that.

The communication protocol between pdhcp and these external helpers is based on JSONL: each DHCP request or response is translated into its JSON object equivalent, serialized, and sent to/received from the external backends. For instance in client mode (see documentation below), this backend is basically the shell script starting pdhcp, and DHCP responses from servers are simply emitted on the standard output (gron makes JSON grepable):

$ pdhcp -i eth0 |gron |gron -u
{
  "address-lease-time": 604800,
  "bootp-assigned-address": "192.168.40.150",
  "bootp-broadcast": true,
  "bootp-filename": "undionly.kpxe",
  "bootp-hardware-length": 6,
  "bootp-hardware-type": "ethernet",
  "bootp-opcode": "reply",
  "bootp-relay-hops": 0,
  "bootp-server-address": "192.168.40.1",
  "bootp-start-time": 0,
  "bootp-transaction-id": "9acb0442",
  "client-hardware-address": "aa:ff:19:93:8d:a6",
  "dhcp-message-type": "offer",
  "domain-name": "domain.com",
  "domain-name-servers": [
     "192.168.40.1"
  ],
  "hostname": "server",
  "routers": [
     "192.168.40.1"
  ],
  "server-identifier": "192.168.40.1",
  "subnet-mask": "255.255.255.0"
}

The wrapper script calling pdhcp is then responsible for chaining the necessary calls, for instance to perform a DHCP lease allocation (known as a DORA cycle). It may seem like a lot of extra work compared to existing DHCP programs, but it's quite easy to implement in practice and brings a lot of flexibility in your DHCP infrastructure workflows (especially for large datacenters servers provisioning scenarii, which is one of the cases pdhcp was originally designed for).

pdhcp implements RFC2131 / RFC2132 and most of their subsequent updates.

Build & Packaging

You may need to install a recent version of the Golang compiler (>= 1.13) and the GNU make utility to build the pdhcp binaries,. Once these requirements are fulfilled, clone the pdhcp Github repository locally:

$ git clone https://github.com/pyke369/pdhcp

and type:

$ make

This will take care of building everything. You may optionally produce a Debian package by typing:

$ make deb

(the devscripts package needs to be installed for this last command)

Usage

A basic help screen is displayed by using the -h command-line parameter:

$ pdhcp -h
usage: pdhcp [OPTIONS...]

options are:
  -6    run in IPv6 mode
  -R string
        add/modify DHCP attributes in the default client request
  -a string
        use an alternate listen address (default "0.0.0.0")
  -b string
        specify the backend command path or URL
  -f string
        provide an alternate logging configuration
  -h    show this help screen
  -i string
        specify a comma-separated list of interfaces to use
  -j    list all available DHCP options (JSON format)
  -l    list all available DHCP options (human format)
  -p int
        use an alternate DHCP port (default 67)
  -r string
        specify the remote DHCP server address in relay mode
  -s string
        use an alternate local relay address
  -v    show the program version
  -w int
        change the backend workers count (default 1)

The command-line options not specific to a particular running mode are described here:

Client Mode

The following options can be used in client mode (in addition to the general options above):

Server Mode

The following options can be used in server mode (in addition to the general options above):


- `-w`: when the associated backend is a local executable (CGI mode), specify the number of forked processes (a.k.a "workers");
DHCP requests from clients will be load-balanced among all available workers:

$ pdhcp ... -w 8 ...


## Relay Mode
The following options can be used in relay mode (in addition to the general options above):

- `-i`: specify the network interfaces the `pdhcp` relay will listen on to receive DHCP requests from clients; any number
of interfaces may be specified, and this parameter is mandatory in relay mode. `pdhcp` is capable of listening on non-broadcast
interfaces in relay mode, which may prove useful to receive remote DHCP server responses on tunnel or virtual interfaces:

$ pdhcp ... -i eth3,br2,eth0.321 ...


- `-r`: specify the remote server to relay DHCP requests to; this parameter is mandatory in relay mode and a custom port may
be specified if needed (67 by default):

$ pdhcp ... -r dhcp-server.domain.com:6767 ...


- `-s`: the giaddr field (gateway IP address) of the relayed BOOTP packets contains by default the first IP address detected
on the interface receiving the DHCP client requests; using this parameter provide a way to overload this value (note it should
never be used in a regular production setup):

$ pdhcp ... -s 192.168.40.10 ...


## Support Programs
Some backend examples are provided in the `support` sub-folder, and briefly described here:

- `local-backend.py`: a very basic (but fully functionnal) backend written in Python, designed to run along the `pdhcp`
server process, with the following minimalist command-line:

$ pdhcp -b support/local-backend.py -w 4 2020-02-27 16:16:38.312 INFO {"event":"start","mode":"backend","pid":21263,"version":"2.0.0"} 2020-02-27 16:16:38.313 INFO {"event":"listen","listen":"-@0.0.0.0:67"} 2020-02-27 16:16:38.313 INFO {"backend":"support/local-backend.py","event":"worker-start","worker":21269} 2020-02-27 16:16:38.313 INFO {"backend":"support/local-backend.py","event":"worker-start","worker":21270} 2020-02-27 16:16:38.314 INFO {"backend":"support/local-backend.py","event":"worker-start","worker":21271} 2020-02-27 16:16:38.315 INFO {"backend":"support/local-backend.py","event":"worker-start","worker":21272}


- `remote-backend.php`: the same backend as above, but written in PHP and supposed to be hosted behind a local or
remote HTTP tiers; an example of invocation from `pdhcp`:

$ pdhcp -b https://some-php-server.com/remote-backend.php 2020-02-27 16:17:48.997 INFO {"event":"start","mode":"backend","pid":21333,"version":"2.0.0"} 2020-02-27 16:17:48.998 INFO {"event":"listen","listen":"-@0.0.0.0:67"}


- `http-backend`: a full-featured HTTP backend written in Go, with static and dynamic (leases management) support;
the configuration is read from a tree of files, which allows for a clean and potentially complex setup:

$ support/http-backend support/http-backend.conf 2020-02-27 16:18:24 INFO {"config":"http-backend.conf","event":"start","pid":21379,"version":"2.0.0"} 2020-02-27 16:18:24 INFO {"event":"listen","listen":"*:8000"}



## Limitations
- DHCPv6 is not supported yet.
- *BSD (incl. Darwin/MacOS) platform-specific code (BPF-based) is also not there yet.

## Similar Projects
- [Internet Systems Consortium Kea](https://www.isc.org/kea/)