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, conn 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 ¶
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 ¶
OptionsLeaseTime - converts a time.Duration to a 4 byte slice, compatible with OptionIPAddressLeaseTime.
func Serve ¶
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 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.
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).
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/onesimus-systems/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.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 } 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, net.IP(options[dhcp.OptionRequestedIPAddress]), 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 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 ¶
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 arbitary 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.