diff options
Diffstat (limited to 'dhcpv4/dhcpv4.go')
-rw-r--r-- | dhcpv4/dhcpv4.go | 115 |
1 files changed, 61 insertions, 54 deletions
diff --git a/dhcpv4/dhcpv4.go b/dhcpv4/dhcpv4.go index bbb2f37..d94c58a 100644 --- a/dhcpv4/dhcpv4.go +++ b/dhcpv4/dhcpv4.go @@ -1,3 +1,18 @@ +// Package dhcpv4 provides encoding and decoding of DHCPv4 packets and options. +// +// Example Usage: +// +// p, err := dhcpv4.New( +// dhcpv4.WithClientIP(net.IP{192, 168, 0, 1}), +// dhcpv4.WithMessageType(dhcpv4.MessageTypeInform), +// ) +// p.UpdateOption(dhcpv4.OptServerIdentifier(net.IP{192, 110, 110, 110})) +// +// // Retrieve the DHCP Message Type option. +// m := dhcpv4.GetMessageType(p.Options) +// +// bytesOnTheWire := p.ToBytes() +// longSummary := p.Summary() package dhcpv4 import ( @@ -121,7 +136,7 @@ func New(modifiers ...Modifier) (*DHCPv4, error) { YourIPAddr: net.IPv4zero, ServerIPAddr: net.IPv4zero, GatewayIPAddr: net.IPv4zero, - Options: make([]Option, 0, 10), + Options: make(Options), } for _, mod := range modifiers { mod(&d) @@ -203,11 +218,7 @@ func NewInform(hwaddr net.HardwareAddr, localIP net.IP, modifiers ...Modifier) ( // NewRequestFromOffer builds a DHCPv4 request from an offer. func NewRequestFromOffer(offer *DHCPv4, modifiers ...Modifier) (*DHCPv4, error) { // find server IP address - var serverIP net.IP - serverID := offer.GetOneOption(OptionServerIdentifier) - if serverID != nil { - serverIP = serverID.(*OptServerIdentifier).ServerID - } + serverIP := GetServerIdentifier(offer.Options) if serverIP == nil { return nil, errors.New("Missing Server IP Address in DHCP Offer") } @@ -216,8 +227,8 @@ func NewRequestFromOffer(offer *DHCPv4, modifiers ...Modifier) (*DHCPv4, error) WithReply(offer), WithMessageType(MessageTypeRequest), WithServerIP(serverIP), - WithOption(&OptRequestedIPAddress{RequestedAddr: offer.YourIPAddr}), - WithOption(&OptServerIdentifier{ServerID: serverIP}), + WithOption(OptRequestedIPAddress(offer.YourIPAddr)), + WithOption(OptServerIdentifier(serverIP)), )...) } @@ -281,11 +292,10 @@ func FromBytes(q []byte) (*DHCPv4, error) { return nil, fmt.Errorf("malformed DHCP packet: got magic cookie %v, want %v", cookie[:], magicCookie[:]) } - opts, err := OptionsFromBytes(buf.Data()) - if err != nil { + p.Options = make(Options) + if err := p.Options.fromBytesCheckEnd(buf.Data(), true); err != nil { return nil, err } - p.Options = opts return &p, nil } @@ -325,25 +335,25 @@ func (d *DHCPv4) SetUnicast() { // GetOneOption returns the option that matches the given option code. // -// If no matching option is found, nil is returned. -func (d *DHCPv4) GetOneOption(code OptionCode) Option { - return d.Options.GetOne(code) +// According to RFC 3396, options that are specified more than once are +// concatenated, and hence this should always just return one option. +func (d *DHCPv4) GetOneOption(code OptionCode) []byte { + return d.Options.Get(code) } // UpdateOption replaces an existing option with the same option code with the // given one, adding it if not already present. -func (d *DHCPv4) UpdateOption(option Option) { - d.Options.Update(option) +func (d *DHCPv4) UpdateOption(opt Option) { + if d.Options == nil { + d.Options = make(Options) + } + d.Options.Update(opt) } // MessageType returns the message type, trying to extract it from the // OptMessageType option. It returns nil if the message type cannot be extracted func (d *DHCPv4) MessageType() MessageType { - opt := d.GetOneOption(OptionDHCPMessageType) - if opt == nil { - return MessageTypeNone - } - return opt.(*OptMessageType).MessageType + return GetMessageType(d.Options) } // String implements fmt.Stringer. @@ -352,23 +362,24 @@ func (d *DHCPv4) String() string { d.OpCode, d.TransactionID, d.HWType, d.ClientHWAddr) } -// Summary prints detailed information about the packet. -func (d *DHCPv4) Summary() string { +// SummaryWithVendor prints a summary of the packet, interpreting the +// vendor-specific info option using the given parser (can be nil). +func (d *DHCPv4) SummaryWithVendor(vendorDecoder OptionDecoder) string { ret := fmt.Sprintf( - "DHCPv4\n"+ - " opcode=%s\n"+ - " hwtype=%s\n"+ - " hopcount=%v\n"+ - " transactionid=%s\n"+ - " numseconds=%v\n"+ - " flags=%v (0x%02x)\n"+ - " clientipaddr=%s\n"+ - " youripaddr=%s\n"+ - " serveripaddr=%s\n"+ - " gatewayipaddr=%s\n"+ - " clienthwaddr=%s\n"+ - " serverhostname=%s\n"+ - " bootfilename=%s\n", + "DHCPv4 Message\n"+ + " opcode: %s\n"+ + " hwtype: %s\n"+ + " hopcount: %v\n"+ + " transaction ID: %s\n"+ + " num seconds: %v\n"+ + " flags: %v (0x%02x)\n"+ + " client IP: %s\n"+ + " your IP: %s\n"+ + " server IP: %s\n"+ + " gateway IP: %s\n"+ + " client MAC: %s\n"+ + " server hostname: %s\n"+ + " bootfile name: %s\n", d.OpCode, d.HWType, d.HopCount, @@ -384,29 +395,20 @@ func (d *DHCPv4) Summary() string { d.ServerHostName, d.BootFileName, ) - ret += " options=\n" - for _, opt := range d.Options { - optString := opt.String() - // If this option has sub structures, offset them accordingly. - if strings.Contains(optString, "\n") { - optString = strings.Replace(optString, "\n ", "\n ", -1) - } - ret += fmt.Sprintf(" %v\n", optString) - if opt.Code() == OptionEnd { - break - } - } + ret += " options:\n" + ret += d.Options.Summary(vendorDecoder) return ret } +// Summary prints detailed information about the packet. +func (d *DHCPv4) Summary() string { + return d.SummaryWithVendor(nil) +} + // IsOptionRequested returns true if that option is within the requested // options of the DHCPv4 message. func (d *DHCPv4) IsOptionRequested(requested OptionCode) bool { - optprl := d.GetOneOption(OptionParameterRequestList) - if optprl == nil { - return false - } - for _, o := range optprl.(*OptParameterRequestList).RequestedOpts { + for _, o := range GetParameterRequestList(d.Options) { if o == requested { return true } @@ -459,7 +461,12 @@ func (d *DHCPv4) ToBytes() []byte { // The magic cookie. buf.WriteBytes(magicCookie[:]) + + // Write all options. d.Options.Marshal(buf) + + // Finish the packet. buf.Write8(uint8(OptionEnd)) + return buf.Data() } |