diff options
Diffstat (limited to 'dhcpv6/dhcpv6message.go')
-rw-r--r-- | dhcpv6/dhcpv6message.go | 192 |
1 files changed, 73 insertions, 119 deletions
diff --git a/dhcpv6/dhcpv6message.go b/dhcpv6/dhcpv6message.go index 795e9fc..c367d36 100644 --- a/dhcpv6/dhcpv6message.go +++ b/dhcpv6/dhcpv6message.go @@ -4,7 +4,6 @@ import ( "crypto/rand" "errors" "fmt" - "log" "net" "time" @@ -16,9 +15,9 @@ const MessageHeaderSize = 4 // Message represents a DHCPv6 Message as defined by RFC 3315 Section 6. type Message struct { - messageType MessageType - transactionID TransactionID - options Options + MessageType MessageType + TransactionID TransactionID + Options Options } var randomRead = rand.Read @@ -44,36 +43,36 @@ func GetTime() uint32 { } // NewSolicitWithCID creates a new SOLICIT message with CID. -func NewSolicitWithCID(duid Duid, modifiers ...Modifier) (DHCPv6, error) { - d, err := NewMessage() +func NewSolicitWithCID(duid Duid, modifiers ...Modifier) (*Message, error) { + m, err := NewMessage() if err != nil { return nil, err } - d.(*Message).SetMessage(MessageTypeSolicit) - d.AddOption(&OptClientId{Cid: duid}) + m.MessageType = MessageTypeSolicit + m.AddOption(&OptClientId{Cid: duid}) oro := new(OptRequestedOption) oro.SetRequestedOptions([]OptionCode{ OptionDNSRecursiveNameServer, OptionDomainSearchList, }) - d.AddOption(oro) - d.AddOption(&OptElapsedTime{}) + m.AddOption(oro) + m.AddOption(&OptElapsedTime{}) // FIXME use real values for IA_NA iaNa := &OptIANA{} iaNa.IaId = [4]byte{0xfa, 0xce, 0xb0, 0x0c} iaNa.T1 = 0xe10 iaNa.T2 = 0x1518 - d.AddOption(iaNa) + m.AddOption(iaNa) // Apply modifiers for _, mod := range modifiers { - d = mod(d) + mod(m) } - return d, nil + return m, nil } // NewSolicitForInterface creates a new SOLICIT message with DUID-LLT, using the // given network interface's hardware address and current time -func NewSolicitForInterface(ifname string, modifiers ...Modifier) (DHCPv6, error) { +func NewSolicitForInterface(ifname string, modifiers ...Modifier) (*Message, error) { iface, err := net.InterfaceByName(ifname) if err != nil { return nil, err @@ -88,21 +87,18 @@ func NewSolicitForInterface(ifname string, modifiers ...Modifier) (DHCPv6, error } // NewAdvertiseFromSolicit creates a new ADVERTISE packet based on an SOLICIT packet. -func NewAdvertiseFromSolicit(solicit DHCPv6, modifiers ...Modifier) (DHCPv6, error) { - if solicit == nil { +func NewAdvertiseFromSolicit(sol *Message, modifiers ...Modifier) (*Message, error) { + if sol == nil { return nil, errors.New("SOLICIT cannot be nil") } - if solicit.Type() != MessageTypeSolicit { + if sol.Type() != MessageTypeSolicit { return nil, errors.New("The passed SOLICIT must have SOLICIT type set") } - sol, ok := solicit.(*Message) - if !ok { - return nil, errors.New("The passed SOLICIT must be of Message type") - } // build ADVERTISE from SOLICIT - adv := Message{} - adv.SetMessage(MessageTypeAdvertise) - adv.SetTransactionID(sol.TransactionID()) + adv := &Message{ + MessageType: MessageTypeAdvertise, + TransactionID: sol.TransactionID, + } // add Client ID cid := sol.GetOneOption(OptionClientID) if cid == nil { @@ -111,30 +107,26 @@ func NewAdvertiseFromSolicit(solicit DHCPv6, modifiers ...Modifier) (DHCPv6, err adv.AddOption(cid) // apply modifiers - d := DHCPv6(&adv) for _, mod := range modifiers { - d = mod(d) + mod(adv) } - return d, nil + return adv, nil } // NewRequestFromAdvertise creates a new REQUEST packet based on an ADVERTISE // packet options. -func NewRequestFromAdvertise(advertise DHCPv6, modifiers ...Modifier) (DHCPv6, error) { - if advertise == nil { - return nil, fmt.Errorf("ADVERTISE cannot be nil") +func NewRequestFromAdvertise(adv *Message, modifiers ...Modifier) (*Message, error) { + if adv == nil { + return nil, errors.New("ADVERTISE cannot be nil") } - if advertise.Type() != MessageTypeAdvertise { + if adv.MessageType != MessageTypeAdvertise { return nil, fmt.Errorf("The passed ADVERTISE must have ADVERTISE type set") } - adv, ok := advertise.(*Message) - if !ok { - return nil, fmt.Errorf("The passed ADVERTISE must be of Message type") - } // build REQUEST from ADVERTISE - req := Message{} - req.SetMessage(MessageTypeRequest) - req.SetTransactionID(adv.TransactionID()) + req := &Message{ + MessageType: MessageTypeRequest, + TransactionID: adv.TransactionID, + } // add Client ID cid := adv.GetOneOption(OptionClientID) if cid == nil { @@ -170,102 +162,70 @@ func NewRequestFromAdvertise(advertise DHCPv6, modifiers ...Modifier) (DHCPv6, e } // apply modifiers - d := DHCPv6(&req) for _, mod := range modifiers { - d = mod(d) + mod(req) } - return d, nil + return req, nil } // NewReplyFromMessage creates a new REPLY packet based on a // Message. The function is to be used when generating a reply to // REQUEST, CONFIRM, RENEW, REBIND, RELEASE and INFORMATION-REQUEST packets. -func NewReplyFromMessage(message DHCPv6, modifiers ...Modifier) (DHCPv6, error) { - if message == nil { +func NewReplyFromMessage(msg *Message, modifiers ...Modifier) (*Message, error) { + if msg == nil { return nil, errors.New("Message cannot be nil") } - switch message.Type() { + switch msg.Type() { case MessageTypeRequest, MessageTypeConfirm, MessageTypeRenew, MessageTypeRebind, MessageTypeRelease, MessageTypeInformationRequest: default: return nil, errors.New("Cannot create REPLY from the passed message type set") } - msg, ok := message.(*Message) - if !ok { - return nil, errors.New("The passed MESSAGE must be of Message type") - } + // build REPLY from MESSAGE - rep := Message{} - rep.SetMessage(MessageTypeReply) - rep.SetTransactionID(msg.TransactionID()) + rep := &Message{ + MessageType: MessageTypeReply, + TransactionID: msg.TransactionID, + } // add Client ID - cid := message.GetOneOption(OptionClientID) + cid := msg.GetOneOption(OptionClientID) if cid == nil { return nil, errors.New("Client ID cannot be nil when building REPLY") } rep.AddOption(cid) // apply modifiers - d := DHCPv6(&rep) for _, mod := range modifiers { - d = mod(d) - } - return d, nil -} - -// Type is the DHCPv6 message type. -func (d *Message) Type() MessageType { - return d.messageType -} - -// SetMessage sets the DHCP message type. -func (d *Message) SetMessage(messageType MessageType) { - msgString := messageType.String() - if msgString == "" { - log.Printf("Warning: unknown DHCPv6 message type: %v", messageType) - } - if messageType == MessageTypeRelayForward || messageType == MessageTypeRelayReply { - log.Printf("Warning: using a RELAY message type with a non-relay message: %v (%v)", - msgString, messageType) + mod(rep) } - d.messageType = messageType -} - -// TransactionID returns this message's transaction id. -func (d *Message) TransactionID() TransactionID { - return d.transactionID + return rep, nil } -// SetTransactionID sets this message's transaction id. -func (d *Message) SetTransactionID(tid TransactionID) { - d.transactionID = tid -} - -// SetOptions replaces this message's options. -func (d *Message) SetOptions(options []Option) { - d.options = options +// Type returns this message's message type. +func (m Message) Type() MessageType { + return m.MessageType } // AddOption adds an option to this message. -func (d *Message) AddOption(option Option) { - d.options.Add(option) +func (m *Message) AddOption(option Option) { + m.Options.Add(option) } // UpdateOption updates the existing options with the passed option, adding it // at the end if not present already -func (d *Message) UpdateOption(option Option) { - d.options.Update(option) +func (m *Message) UpdateOption(option Option) { + m.Options.Update(option) } // IsNetboot returns true if the machine is trying to netboot. It checks if // "boot file" is one of the requested options, which is useful for // SOLICIT/REQUEST packet types, it also checks if the "boot file" option is // included in the packet, which is useful for ADVERTISE/REPLY packet. -func (d *Message) IsNetboot() bool { - if d.IsOptionRequested(OptionBootfileURL) { +func (m *Message) IsNetboot() bool { + if m.IsOptionRequested(OptionBootfileURL) { return true } - if optbf := d.GetOneOption(OptionBootfileURL); optbf != nil { + if optbf := m.GetOneOption(OptionBootfileURL); optbf != nil { return true } return false @@ -273,8 +233,8 @@ func (d *Message) IsNetboot() bool { // IsOptionRequested takes an OptionCode and returns true if that option is // within the requested options of the DHCPv6 message. -func (d *Message) IsOptionRequested(requested OptionCode) bool { - for _, optoro := range d.GetOption(OptionORO) { +func (m *Message) IsOptionRequested(requested OptionCode) bool { + for _, optoro := range m.GetOption(OptionORO) { for _, o := range optoro.(*OptRequestedOption).RequestedOptions() { if o == requested { return true @@ -285,26 +245,25 @@ func (d *Message) IsOptionRequested(requested OptionCode) bool { } // String returns a short human-readable string for this message. -func (d *Message) String() string { - return fmt.Sprintf("Message(messageType=%v transactionID=%s, %d options)", - d.Type().String(), d.TransactionID(), len(d.options), - ) +func (m *Message) String() string { + return fmt.Sprintf("Message(messageType=%s transactionID=%s, %d options)", + m.MessageType, m.TransactionID, len(m.Options)) } // Summary prints all options associated with this message. -func (d *Message) Summary() string { +func (m *Message) Summary() string { ret := fmt.Sprintf( "Message\n"+ - " messageType=%v\n"+ + " messageType=%s\n"+ " transactionid=%s\n", - d.Type().String(), - d.TransactionID(), + m.MessageType, + m.TransactionID, ) ret += " options=[" - if len(d.options) > 0 { + if len(m.Options) > 0 { ret += "\n" } - for _, opt := range d.options { + for _, opt := range m.Options { ret += fmt.Sprintf(" %v\n", opt.String()) } ret += " ]\n" @@ -313,31 +272,26 @@ func (d *Message) Summary() string { // ToBytes returns the serialized version of this message as defined by RFC // 3315, Section 5. -func (d *Message) ToBytes() []byte { +func (m *Message) ToBytes() []byte { buf := uio.NewBigEndianBuffer(nil) - buf.Write8(uint8(d.messageType)) - buf.WriteBytes(d.transactionID[:]) - buf.WriteBytes(d.options.ToBytes()) + buf.Write8(uint8(m.MessageType)) + buf.WriteBytes(m.TransactionID[:]) + buf.WriteBytes(m.Options.ToBytes()) return buf.Data() } -// Options returns the current set of options associated with this message. -func (d *Message) Options() []Option { - return d.options -} - // GetOption returns the options associated with the code. -func (d *Message) GetOption(code OptionCode) []Option { - return d.options.Get(code) +func (m *Message) GetOption(code OptionCode) []Option { + return m.Options.Get(code) } // GetOneOption returns the first associated option with the code from this // message. -func (d *Message) GetOneOption(code OptionCode) Option { - return d.options.GetOne(code) +func (m *Message) GetOneOption(code OptionCode) Option { + return m.Options.GetOne(code) } // IsRelay returns whether this is a relay message or not. -func (d *Message) IsRelay() bool { +func (m *Message) IsRelay() bool { return false } |