package module
Version: v0.0.0-...-96a419c Latest Latest

This package is not in the latest version of its module.

Go to latest
Published: Feb 8, 2017 License: BSD-3-Clause Imports: 6 Imported by: 0


DHCP4 - A DHCP library written in Go.



Quick Start

See example_test.go for how to use this library to create a basic server.




Special thanks to https://github.com/pietern for suggesting how to use go.net to be able to listen on a single network interface.


DHCP4 is one of the libraries used by Facebook's DHCP load balancing relay. "Facebook currently uses it in production, and it's deployed at global scale across all of our data centers."



IPv4 DHCP Library for Parsing and Creating DHCP Packets, along with basic DHCP server functionality

Author: http://richard.warburton.it/

Copyright: 2014 Skagerrak Software - http://www.skagerraksoftware.com/




This section is empty.


This section is empty.


func IPAdd

func IPAdd(start net.IP, add int) net.IP

IPAdd returns a copy of start + add. IPAdd(net.IP{192,168,1,1},30) returns net.IP{}

func IPInRange

func IPInRange(start, stop, ip net.IP) bool

IPInRange returns true if ip is between (inclusive) start and stop.

func IPLess

func IPLess(a, b net.IP) bool

IPLess returns where IP a is less than IP b.

func IPRange

func IPRange(start, stop net.IP) int

IPRange returns how many ips in the ip range from start to stop (inclusive)

func JoinIPs

func JoinIPs(ips []net.IP) (b []byte)

JoinIPs returns a byte slice of IP addresses, one immediately after the other This may be useful for creating multiple IP options such as OptionRouter.

func ListenAndServe

func ListenAndServe(handler Handler) error

ListenAndServe listens on the UDP network address addr and then calls Serve with handler to handle requests on incoming packets.

func ListenAndServeIf

func ListenAndServeIf(interfaceName string, handler Handler) error

ListenAndServe listens on the UDP network address addr and then calls Serve with handler to handle requests on incoming packets. i.e. ListenAndServeIf("eth0",handler)

func OptionsLeaseTime

func OptionsLeaseTime(d time.Duration) []byte

OptionsLeaseTime - converts a time.Duration to a 4 byte slice, compatible with OptionIPAddressLeaseTime.

func Serve

func Serve(conn ServeConn, handler Handler) error

Serve takes a ServeConn (such as a net.PacketConn) that it uses for both reading and writing DHCP packets. Every packet is passed to the handler, which processes it and optionally return a response packet for writing back to the network.

To capture limited broadcast packets (sent to, you must listen on a socket bound to IP_ADDRANY ( This means that broadcast packets sent to any interface on the system may be delivered to this socket. See: https://code.google.com/p/go/issues/detail?id=7106

Additionally, response packets may not return to the same interface that the request was received from. Writing a custom ServeConn, or using ServeIf() can provide a workaround to this problem.

func ServeIf

func ServeIf(ifIndex int, conn net.PacketConn, handler Handler) error

ServeIf does the same job as Serve(), but listens and responds on the specified network interface (by index). It also doubles as an example of how to leverage the dhcp4.ServeConn interface.

If your target only has one interface, use Serve(). ServeIf() requires an import outside the std library. Serving DHCP over multiple interfaces will require your own dhcp4.ServeConn, as listening to broadcasts utilises all interfaces (so you cannot have more than on listener).


type Handler

type Handler interface {
	ServeDHCP(req Packet, msgType MessageType, options Options) Packet

Example using DHCP with a single network interface device

// Example of minimal DHCP server:
package main

import (
	dhcp "github.com/krolaw/dhcp4"


// Example using DHCP with a single network interface device
func main() {
	serverIP := net.IP{172, 30, 0, 1}
	handler := &DHCPHandler{
		ip:            serverIP,
		leaseDuration: 2 * time.Hour,
		start:         net.IP{172, 30, 0, 2},
		leaseRange:    50,
		leases:        make(map[int]lease, 10),
		options: dhcp.Options{
			dhcp.OptionSubnetMask:       []byte{255, 255, 240, 0},
			dhcp.OptionRouter:           []byte(serverIP), // Presuming Server is also your router
			dhcp.OptionDomainNameServer: []byte(serverIP), // Presuming Server is also your DNS server
	// log.Fatal(dhcp.ListenAndServeIf("eth0",handler)) // Select interface on multi interface device

type lease struct {
	nic    string    // Client's CHAddr
	expiry time.Time // When the lease expires

type DHCPHandler struct {
	ip            net.IP        // Server IP to use
	options       dhcp.Options  // Options to send to DHCP Clients
	start         net.IP        // Start of IP range to distribute
	leaseRange    int           // Number of IPs to distribute (starting from start)
	leaseDuration time.Duration // Lease period
	leases        map[int]lease // Map to keep track of leases

func (h *DHCPHandler) ServeDHCP(p dhcp.Packet, msgType dhcp.MessageType, options dhcp.Options) (d dhcp.Packet) {
	switch msgType {

	case dhcp.Discover:
		free, nic := -1, p.CHAddr().String()
		for i, v := range h.leases { // Find previous lease
			if v.nic == nic {
				free = i
				goto reply
		if free = h.freeLease(); free == -1 {
		return dhcp.ReplyPacket(p, dhcp.Offer, h.ip, dhcp.IPAdd(h.start, free), h.leaseDuration,

	case dhcp.Request:
		if server, ok := options[dhcp.OptionServerIdentifier]; ok && !net.IP(server).Equal(h.ip) {
			return nil // Message not for this dhcp server
		reqIP := net.IP(options[dhcp.OptionRequestedIPAddress])
		if reqIP == nil {
			reqIP = net.IP(p.CIAddr())

		if len(reqIP) == 4 && !reqIP.Equal(net.IPv4zero) {
			if leaseNum := dhcp.IPRange(h.start, reqIP) - 1; leaseNum >= 0 && leaseNum < h.leaseRange {
				if l, exists := h.leases[leaseNum]; !exists || l.nic == p.CHAddr().String() {
					h.leases[leaseNum] = lease{nic: p.CHAddr().String(), expiry: time.Now().Add(h.leaseDuration)}
					return dhcp.ReplyPacket(p, dhcp.ACK, h.ip, reqIP, h.leaseDuration,
		return dhcp.ReplyPacket(p, dhcp.NAK, h.ip, nil, 0, nil)

	case dhcp.Release, dhcp.Decline:
		nic := p.CHAddr().String()
		for i, v := range h.leases {
			if v.nic == nic {
				delete(h.leases, i)
	return nil

func (h *DHCPHandler) freeLease() int {
	now := time.Now()
	b := rand.Intn(h.leaseRange) // Try random first
	for _, v := range [][]int{[]int{b, h.leaseRange}, []int{0, b}} {
		for i := v[0]; i < v[1]; i++ {
			if l, ok := h.leases[i]; !ok || l.expiry.Before(now) {
				return i
	return -1

type MessageType

type MessageType byte // Option 53
const (
	Discover MessageType = 1 // Broadcast Packet From Client - Can I have an IP?
	Offer    MessageType = 2 // Broadcast From Server - Here's an IP
	Request  MessageType = 3 // Broadcast From Client - I'll take that IP (Also start for renewals)
	Decline  MessageType = 4 // Broadcast From Client - Sorry I can't use that IP
	ACK      MessageType = 5 // From Server, Yes you can have that IP
	NAK      MessageType = 6 // From Server, No you cannot have that IP
	Release  MessageType = 7 // From Client, I don't need that IP anymore
	Inform   MessageType = 8 // From Client, I have this IP and there's nothing you can do about it

DHCP Message Type 53

func (MessageType) String

func (i MessageType) String() string

type OpCode

type OpCode byte
const (
	BootRequest OpCode = 1 // From Client
	BootReply   OpCode = 2 // From Server


type Option

type Option struct {
	Code  OptionCode
	Value []byte

type OptionCode

type OptionCode byte
const (
	End                          OptionCode = 255
	Pad                          OptionCode = 0
	OptionSubnetMask             OptionCode = 1
	OptionTimeOffset             OptionCode = 2
	OptionRouter                 OptionCode = 3
	OptionTimeServer             OptionCode = 4
	OptionNameServer             OptionCode = 5
	OptionDomainNameServer       OptionCode = 6
	OptionLogServer              OptionCode = 7
	OptionCookieServer           OptionCode = 8
	OptionLPRServer              OptionCode = 9
	OptionImpressServer          OptionCode = 10
	OptionResourceLocationServer OptionCode = 11
	OptionHostName               OptionCode = 12
	OptionBootFileSize           OptionCode = 13
	OptionMeritDumpFile          OptionCode = 14
	OptionDomainName             OptionCode = 15
	OptionSwapServer             OptionCode = 16
	OptionRootPath               OptionCode = 17
	OptionExtensionsPath         OptionCode = 18

	// IP Layer Parameters per Host
	OptionIPForwardingEnableDisable          OptionCode = 19
	OptionNonLocalSourceRoutingEnableDisable OptionCode = 20
	OptionPolicyFilter                       OptionCode = 21
	OptionMaximumDatagramReassemblySize      OptionCode = 22
	OptionDefaultIPTimeToLive                OptionCode = 23
	OptionPathMTUAgingTimeout                OptionCode = 24
	OptionPathMTUPlateauTable                OptionCode = 25

	// IP Layer Parameters per Interface
	OptionInterfaceMTU              OptionCode = 26
	OptionAllSubnetsAreLocal        OptionCode = 27
	OptionBroadcastAddress          OptionCode = 28
	OptionPerformMaskDiscovery      OptionCode = 29
	OptionMaskSupplier              OptionCode = 30
	OptionPerformRouterDiscovery    OptionCode = 31
	OptionRouterSolicitationAddress OptionCode = 32
	OptionStaticRoute               OptionCode = 33

	// Link Layer Parameters per Interface
	OptionTrailerEncapsulation  OptionCode = 34
	OptionARPCacheTimeout       OptionCode = 35
	OptionEthernetEncapsulation OptionCode = 36

	// TCP Parameters
	OptionTCPDefaultTTL        OptionCode = 37
	OptionTCPKeepaliveInterval OptionCode = 38
	OptionTCPKeepaliveGarbage  OptionCode = 39

	// Application and Service Parameters
	OptionNetworkInformationServiceDomain            OptionCode = 40
	OptionNetworkInformationServers                  OptionCode = 41
	OptionNetworkTimeProtocolServers                 OptionCode = 42
	OptionVendorSpecificInformation                  OptionCode = 43
	OptionNetBIOSOverTCPIPNameServer                 OptionCode = 44
	OptionNetBIOSOverTCPIPDatagramDistributionServer OptionCode = 45
	OptionNetBIOSOverTCPIPNodeType                   OptionCode = 46
	OptionNetBIOSOverTCPIPScope                      OptionCode = 47
	OptionXWindowSystemFontServer                    OptionCode = 48
	OptionXWindowSystemDisplayManager                OptionCode = 49
	OptionNetworkInformationServicePlusDomain        OptionCode = 64
	OptionNetworkInformationServicePlusServers       OptionCode = 65
	OptionMobileIPHomeAgent                          OptionCode = 68
	OptionSimpleMailTransportProtocol                OptionCode = 69
	OptionPostOfficeProtocolServer                   OptionCode = 70
	OptionNetworkNewsTransportProtocol               OptionCode = 71
	OptionDefaultWorldWideWebServer                  OptionCode = 72
	OptionDefaultFingerServer                        OptionCode = 73
	OptionDefaultInternetRelayChatServer             OptionCode = 74
	OptionStreetTalkServer                           OptionCode = 75
	OptionStreetTalkDirectoryAssistance              OptionCode = 76

	OptionRelayAgentInformation OptionCode = 82

	// DHCP Extensions
	OptionRequestedIPAddress     OptionCode = 50
	OptionIPAddressLeaseTime     OptionCode = 51
	OptionOverload               OptionCode = 52
	OptionDHCPMessageType        OptionCode = 53
	OptionServerIdentifier       OptionCode = 54
	OptionParameterRequestList   OptionCode = 55
	OptionMessage                OptionCode = 56
	OptionMaximumDHCPMessageSize OptionCode = 57
	OptionRenewalTimeValue       OptionCode = 58
	OptionRebindingTimeValue     OptionCode = 59
	OptionVendorClassIdentifier  OptionCode = 60
	OptionClientIdentifier       OptionCode = 61

	OptionTFTPServerName OptionCode = 66
	OptionBootFileName   OptionCode = 67

	OptionUserClass OptionCode = 77

	OptionClientArchitecture OptionCode = 93

	OptionTZPOSIXString    OptionCode = 100
	OptionTZDatabaseString OptionCode = 101

	OptionClasslessRouteFormat OptionCode = 121

DHCP Options

func (OptionCode) String

func (i OptionCode) String() string

type Options

type Options map[OptionCode][]byte

Map of DHCP options

func (Options) SelectOrder

func (o Options) SelectOrder(order []byte) []Option

SelectOrder returns a slice of options ordered and selected by a byte array usually defined by OptionParameterRequestList. This result is expected to be used in ReplyPacket()'s []Option parameter.

func (Options) SelectOrderOrAll

func (o Options) SelectOrderOrAll(order []byte) []Option

SelectOrderOrAll has same functionality as SelectOrder, except if the order param is nil, whereby all options are added (in arbitary order).

type Packet

type Packet []byte

A DHCP packet

func NewPacket

func NewPacket(opCode OpCode) Packet

func ReplyPacket

func ReplyPacket(req Packet, mt MessageType, serverId, yIAddr net.IP, leaseDuration time.Duration, options []Option) Packet

ReplyPacket creates a reply packet that a Server would send to a client. It uses the req Packet param to copy across common/necessary fields to associate the reply the request.

func RequestPacket

func RequestPacket(mt MessageType, chAddr net.HardwareAddr, cIAddr net.IP, xId []byte, broadcast bool, options []Option) Packet

Creates a request packet that a Client would send to a server.

func (*Packet) AddOption

func (p *Packet) AddOption(o OptionCode, value []byte)

Appends a DHCP option to the end of a packet

func (Packet) Broadcast

func (p Packet) Broadcast() bool

func (Packet) CHAddr

func (p Packet) CHAddr() net.HardwareAddr

func (Packet) CIAddr

func (p Packet) CIAddr() net.IP

func (Packet) Cookie

func (p Packet) Cookie() []byte

func (Packet) File

func (p Packet) File() []byte

BOOTP legacy

func (Packet) Flags

func (p Packet) Flags() []byte

func (Packet) GIAddr

func (p Packet) GIAddr() net.IP

func (Packet) HLen

func (p Packet) HLen() byte

func (Packet) HType

func (p Packet) HType() byte

func (Packet) Hops

func (p Packet) Hops() byte

func (Packet) OpCode

func (p Packet) OpCode() OpCode

func (Packet) Options

func (p Packet) Options() []byte

func (*Packet) PadToMinSize

func (p *Packet) PadToMinSize()

func (Packet) ParseOptions

func (p Packet) ParseOptions() Options

Parses the packet's options into an Options map

func (Packet) SIAddr

func (p Packet) SIAddr() net.IP

func (Packet) SName

func (p Packet) SName() []byte

BOOTP legacy

func (Packet) Secs

func (p Packet) Secs() []byte

func (Packet) SetBroadcast

func (p Packet) SetBroadcast(broadcast bool)

func (Packet) SetCHAddr

func (p Packet) SetCHAddr(a net.HardwareAddr)

func (Packet) SetCIAddr

func (p Packet) SetCIAddr(ip net.IP)

func (Packet) SetCookie

func (p Packet) SetCookie(cookie []byte)

func (Packet) SetFile

func (p Packet) SetFile(file []byte)

BOOTP legacy

func (Packet) SetFlags

func (p Packet) SetFlags(flags []byte)

func (Packet) SetGIAddr

func (p Packet) SetGIAddr(ip net.IP)

func (Packet) SetHType

func (p Packet) SetHType(hType byte)

func (Packet) SetHops

func (p Packet) SetHops(hops byte)

func (Packet) SetOpCode

func (p Packet) SetOpCode(c OpCode)

func (Packet) SetSIAddr

func (p Packet) SetSIAddr(ip net.IP)

func (Packet) SetSName

func (p Packet) SetSName(sName []byte)

BOOTP legacy

func (Packet) SetSecs

func (p Packet) SetSecs(secs []byte)

func (Packet) SetXId

func (p Packet) SetXId(xId []byte)

func (Packet) SetYIAddr

func (p Packet) SetYIAddr(ip net.IP)

func (*Packet) StripOptions

func (p *Packet) StripOptions()

Removes all options from packet.

func (Packet) XId

func (p Packet) XId() []byte

func (Packet) YIAddr

func (p Packet) YIAddr() net.IP

type ServeConn

type ServeConn interface {
	ReadFrom(b []byte) (n int, addr net.Addr, err error)
	WriteTo(b []byte, addr net.Addr) (n int, err error)

ServeConn is the bare minimum connection functions required by Serve() It allows you to create custom connections for greater control, such as ServeIfConn (see serverif.go), which locks to a given interface.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
t or T : Toggle theme light dark auto
y or Y : Canonical URL