Documentation ¶
Overview ¶
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/
Index ¶
- func IPAdd(start net.IP, add int) net.IP
- func IPInRange(start, stop, ip net.IP) bool
- func IPLess(a, b net.IP) bool
- func IPRange(start, stop net.IP) int
- func JoinIPs(ips []net.IP) (b []byte)
- func ListenAndServe(handler Handler) error
- func ListenAndServeIf(interfaceName string, handler Handler) error
- func OptionsLeaseTime(d time.Duration) []byte
- func Serve(conn ServeConn, handler Handler) error
- func ServeIf(ifIndex int, pconn net.PacketConn, handler Handler) error
- type Handler
- type MessageType
- type OpCode
- type Option
- type OptionCode
- type Options
- type Packet
- func (p *Packet) AddOption(o OptionCode, value []byte)
- func (p Packet) Broadcast() bool
- func (p Packet) CHAddr() net.HardwareAddr
- func (p Packet) CIAddr() net.IP
- func (p Packet) Cookie() []byte
- func (p Packet) File() []byte
- func (p Packet) Flags() []byte
- func (p Packet) GIAddr() net.IP
- func (p Packet) HLen() byte
- func (p Packet) HType() byte
- func (p Packet) Hops() byte
- func (p Packet) OpCode() OpCode
- func (p Packet) Options() []byte
- func (p *Packet) PadToMinSize()
- func (p Packet) ParseOptions() Options
- func (p Packet) SIAddr() net.IP
- func (p Packet) SName() []byte
- func (p Packet) Secs() []byte
- func (p Packet) SetBroadcast(broadcast bool)
- func (p Packet) SetCHAddr(a net.HardwareAddr)
- func (p Packet) SetCIAddr(ip net.IP)
- func (p Packet) SetCookie(cookie []byte)
- func (p Packet) SetFile(file []byte)
- func (p Packet) SetFlags(flags []byte)
- func (p Packet) SetGIAddr(ip net.IP)
- func (p Packet) SetHType(hType byte)
- func (p Packet) SetHops(hops byte)
- func (p Packet) SetOpCode(c OpCode)
- func (p Packet) SetSIAddr(ip net.IP)
- func (p Packet) SetSName(sName []byte)
- func (p Packet) SetSecs(secs []byte)
- func (p Packet) SetXId(xId []byte)
- func (p Packet) SetYIAddr(ip net.IP)
- func (p *Packet) StripOptions()
- func (p Packet) XId() []byte
- func (p Packet) YIAddr() net.IP
- type ServeConn
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func IPAdd ¶
IPAdd returns a copy of start + add. IPAdd(net.IP{192,168,1,1},30) returns net.IP{192.168.1.31}
func JoinIPs ¶
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 ¶
ListenAndServe listens on the UDP network address addr and then calls Serve with handler to handle requests on incoming packets.
func ListenAndServeIf ¶
Deprecated, use Serve instead with connection from dhcp4/conn or own custom creation
func OptionsLeaseTime ¶
OptionsLeaseTime - converts a time.Duration to a 4 byte slice, compatible with OptionIPAddressLeaseTime.
func Serve ¶
Serve takes a ServeConn (such as a net.PacketConn or dhcp4/conn) for reading and writing DHCP packets. If either ReadFrom or WriteTo error (such as a closed conn, or just time to exit), Serve exits and passes up the error.
Every packet is passed to the Handler's ServeDHCP func.
which processes it and optionally return a response packet for writing back to the network.
To capture limited broadcast packets (sent to 255.255.255.255), you must listen on a socket bound to IP_ADDRANY (0.0.0.0). 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.
Types ¶
type Handler ¶
type Handler interface {
ServeDHCP(req Packet, msgType MessageType, options Options) Packet
}
Example ¶
Example using DHCP with a single network interface device
// Example of minimal DHCP server: package main import ( dhcp "github.com/krolaw/dhcp4" "log" "math/rand" "net" "time" ) // 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.ListenAndServe(handler)) // log.Fatal(dhcp.Serve(dhcp.NewUDP4BoundListener("eth0",":67"), handler)) // Select interface on multi interface device - just linux for now // log.Fatal(dhcp.Serve(dhcp.NewUDP4FilterListener("en0",":67"), handler)) // Work around for other OSes } 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 } reply: return dhcp.ReplyPacket(p, dhcp.Offer, h.ip, dhcp.IPAdd(h.start, free), h.leaseDuration, h.options.SelectOrderOrAll(options[dhcp.OptionParameterRequestList])) 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, h.options.SelectOrderOrAll(options[dhcp.OptionParameterRequestList])) } } } 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) break } } } 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 }
Output:
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 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 OptionDomainSearch OptionCode = 119 OptionClasslessRouteFormat OptionCode = 121 // From RFC3942 - Options Used by PXELINUX OptionPxelinuxMagic OptionCode = 208 OptionPxelinuxConfigfile OptionCode = 209 OptionPxelinuxPathprefix OptionCode = 210 OptionPxelinuxReboottime OptionCode = 211 )
DHCP Options
func (OptionCode) String ¶
func (i OptionCode) String() string
type Options ¶
type Options map[OptionCode][]byte
Map of DHCP options
func (Options) SelectOrder ¶
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 ¶
SelectOrderOrAll has same functionality as SelectOrder, except if the order param is nil, whereby all options are added (in arbitrary order).
type Packet ¶
type Packet []byte
A DHCP 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) CHAddr ¶
func (p Packet) CHAddr() net.HardwareAddr
func (*Packet) PadToMinSize ¶
func (p *Packet) PadToMinSize()
func (Packet) ParseOptions ¶
Parses the packet's options into an Options map
func (Packet) SetBroadcast ¶
func (Packet) SetCHAddr ¶
func (p Packet) SetCHAddr(a net.HardwareAddr)
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.