diff options
author | Pablo Mazzini <pmazzini@gmail.com> | 2018-08-10 16:00:59 +0200 |
---|---|---|
committer | Pablo Mazzini <pmazzini@gmail.com> | 2018-08-10 16:00:59 +0200 |
commit | f55d67dc49bee6d6aa20913f070ed771b9ff725a (patch) | |
tree | 2e96a2f52ab0bac9f06e0560208ab21bb2c4bb51 /dhcpv6 | |
parent | cff664d4ac7fe61377195a9d439e17259ce5899e (diff) |
rename IsRequested to IsRequestedOption
Diffstat (limited to 'dhcpv6')
-rw-r--r-- | dhcpv6/dhcpv6.go | 83 | ||||
-rw-r--r-- | dhcpv6/dhcpv6_test.go | 133 | ||||
-rw-r--r-- | dhcpv6/dhcpv6message_test.go | 98 | ||||
-rw-r--r-- | dhcpv6/utils.go | 86 | ||||
-rw-r--r-- | dhcpv6/utils_test.go | 80 |
5 files changed, 239 insertions, 241 deletions
diff --git a/dhcpv6/dhcpv6.go b/dhcpv6/dhcpv6.go index 0dabca5..adc52c5 100644 --- a/dhcpv6/dhcpv6.go +++ b/dhcpv6/dhcpv6.go @@ -1,8 +1,10 @@ package dhcpv6 import ( + "errors" "fmt" "net" + "strings" ) type DHCPv6 interface { @@ -199,3 +201,84 @@ func EncapsulateRelay(d DHCPv6, mType MessageType, linkAddr, peerAddr net.IP) (D outer.AddOption(&orm) return &outer, nil } + +// IsNetboot function takes a DHCPv6 message and 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 IsNetboot(msg DHCPv6) bool { + if IsOptionRequested(msg, OptionBootfileURL) { + return true + } + if optbf := msg.GetOneOption(OptionBootfileURL); optbf != nil { + return true + } + return false +} + +// IsOptionRequested function takes a DHCPv6 message and an OptionCode, and +// returns true if that option is within the requested options of the DHCPv6 +// message. +func IsOptionRequested(msg DHCPv6, requested OptionCode) bool { + for _, optoro := range msg.GetOption(OptionORO) { + for _, o := range optoro.(*OptRequestedOption).RequestedOptions() { + if o == requested { + return true + } + } + } + return false +} + +// IsUsingUEFI function takes a DHCPv6 message and returns true if +// the machine trying to netboot is using UEFI of false if it is not. +func IsUsingUEFI(msg DHCPv6) bool { + // RFC 4578 says: + // As of the writing of this document, the following pre-boot + // architecture types have been requested. + // Type Architecture Name + // ---- ----------------- + // 0 Intel x86PC + // 1 NEC/PC98 + // 2 EFI Itanium + // 3 DEC Alpha + // 4 Arc x86 + // 5 Intel Lean Client + // 6 EFI IA32 + // 7 EFI BC + // 8 EFI Xscale + // 9 EFI x86-64 + if opt := msg.GetOneOption(OptionClientArchType); opt != nil { + optat := opt.(*OptClientArchType) + // TODO investigate if other types are appropriate + if optat.ArchType == EFI_BC || optat.ArchType == EFI_X86_64 { + return true + } + } + if opt := msg.GetOneOption(OptionUserClass); opt != nil { + optuc := opt.(*OptUserClass) + for _, uc := range optuc.UserClasses { + if strings.Contains(string(uc), "EFI") { + return true + } + } + } + return false +} + +// GetTransactionID returns a transactionID of a message or its inner message +// in case of relay +func GetTransactionID(packet DHCPv6) (uint32, error) { + if message, ok := packet.(*DHCPv6Message); ok { + return message.TransactionID(), nil + } + if relay, ok := packet.(*DHCPv6Relay); ok { + message, err := relay.GetInnerMessage() + if err != nil { + return 0, err + } + return GetTransactionID(message) + } + return 0, errors.New("Invalid DHCPv6 packet") +} diff --git a/dhcpv6/dhcpv6_test.go b/dhcpv6/dhcpv6_test.go index 4a44e0e..c48df24 100644 --- a/dhcpv6/dhcpv6_test.go +++ b/dhcpv6/dhcpv6_test.go @@ -4,7 +4,6 @@ import ( "net" "testing" - "github.com/insomniacslk/dhcp/iana" "github.com/stretchr/testify/require" ) @@ -126,93 +125,77 @@ func TestFromAndToBytes(t *testing.T) { require.Equal(t, expected, toBytes) } -func TestNewAdvertiseFromSolicit(t *testing.T) { - s := DHCPv6Message{} - s.SetMessage(MessageTypeSolicit) - s.SetTransactionID(0xabcdef) - cid := OptClientId{} - s.AddOption(&cid) - duid := Duid{} +func TestIsNetboot(t *testing.T) { + msg1 := DHCPv6Message{} + require.False(t, IsNetboot(&msg1)) - a, err := NewAdvertiseFromSolicit(&s, WithServerID(duid)) - require.NoError(t, err) - require.Equal(t, a.(*DHCPv6Message).TransactionID(), s.TransactionID()) - require.Equal(t, a.Type(), MessageTypeAdvertise) + msg2 := DHCPv6Message{} + optro := OptRequestedOption{} + optro.AddRequestedOption(OptionBootfileURL) + msg2.AddOption(&optro) + require.True(t, IsNetboot(&msg2)) + + msg3 := DHCPv6Message{} + optbf := OptBootFileURL{} + msg3.AddOption(&optbf) + require.True(t, IsNetboot(&msg3)) } -func TestNewReplyFromDHCPv6Message(t *testing.T) { - msg := DHCPv6Message{} - msg.SetTransactionID(0xabcdef) - cid := OptClientId{} - msg.AddOption(&cid) - sid := OptServerId{} - duid := Duid{} - sid.Sid = duid - msg.AddOption(&sid) +func TestIsOptionRequested(t *testing.T) { + msg1 := DHCPv6Message{} + require.False(t, IsOptionRequested(&msg1, OptionDNSRecursiveNameServer)) - msg.SetMessage(MessageTypeConfirm) - rep, err := NewReplyFromDHCPv6Message(&msg, WithServerID(duid)) - require.NoError(t, err) - require.Equal(t, rep.(*DHCPv6Message).TransactionID(), msg.TransactionID()) - require.Equal(t, rep.Type(), MessageTypeReply) - - msg.SetMessage(MessageTypeRenew) - rep, err = NewReplyFromDHCPv6Message(&msg, WithServerID(duid)) - require.NoError(t, err) - require.Equal(t, rep.(*DHCPv6Message).TransactionID(), msg.TransactionID()) - require.Equal(t, rep.Type(), MessageTypeReply) + msg2 := DHCPv6Message{} + optro := OptRequestedOption{} + optro.AddRequestedOption(OptionDNSRecursiveNameServer) + msg2.AddOption(&optro) + require.True(t, IsOptionRequested(&msg2, OptionDNSRecursiveNameServer)) +} - msg.SetMessage(MessageTypeRebind) - rep, err = NewReplyFromDHCPv6Message(&msg, WithServerID(duid)) - require.NoError(t, err) - require.Equal(t, rep.(*DHCPv6Message).TransactionID(), msg.TransactionID()) - require.Equal(t, rep.Type(), MessageTypeReply) +func TestIsUsingUEFIArchTypeTrue(t *testing.T) { + msg := DHCPv6Message{} + opt := OptClientArchType{ArchType: EFI_BC} + msg.AddOption(&opt) + require.True(t, IsUsingUEFI(&msg)) +} - msg.SetMessage(MessageTypeRelease) - rep, err = NewReplyFromDHCPv6Message(&msg, WithServerID(duid)) - require.NoError(t, err) - require.Equal(t, rep.(*DHCPv6Message).TransactionID(), msg.TransactionID()) - require.Equal(t, rep.Type(), MessageTypeReply) +func TestIsUsingUEFIArchTypeFalse(t *testing.T) { + msg := DHCPv6Message{} + opt := OptClientArchType{ArchType: INTEL_X86PC} + msg.AddOption(&opt) + require.False(t, IsUsingUEFI(&msg)) +} - msg.SetMessage(MessageTypeSolicit) - rep, err = NewReplyFromDHCPv6Message(&msg) - require.Error(t, err) +func TestIsUsingUEFIUserClassTrue(t *testing.T) { + msg := DHCPv6Message{} + opt := OptUserClass{UserClasses: [][]byte{[]byte("ipxeUEFI")}} + msg.AddOption(&opt) + require.True(t, IsUsingUEFI(&msg)) +} - relay := DHCPv6Relay{} - rep, err = NewReplyFromDHCPv6Message(&relay) - require.Error(t, err) +func TestIsUsingUEFIUserClassFalse(t *testing.T) { + msg := DHCPv6Message{} + opt := OptUserClass{UserClasses: [][]byte{[]byte("ipxeLegacy")}} + msg.AddOption(&opt) + require.False(t, IsUsingUEFI(&msg)) } -func TestNewMessageTypeSolicitWithCID(t *testing.T) { - hwAddr, err := net.ParseMAC("24:0A:9E:9F:EB:2B") +func TestGetTransactionIDMessage(t *testing.T) { + message, err := NewMessage() require.NoError(t, err) - - duid := Duid{ - Type: DUID_LL, - HwType: iana.HwTypeEthernet, - LinkLayerAddr: hwAddr, - } - - s, err := NewSolicitWithCID(duid) + transactionID, err := GetTransactionID(message) require.NoError(t, err) + require.Equal(t, transactionID, message.(*DHCPv6Message).TransactionID()) +} - require.Equal(t, s.Type(), MessageTypeSolicit) - // Check CID - cidOption := s.GetOneOption(OptionClientID) - require.NotNil(t, cidOption) - cid, ok := cidOption.(*OptClientId) - require.True(t, ok) - require.Equal(t, cid.Cid, duid) - - // Check ORO - oroOption := s.GetOneOption(OptionORO) - require.NotNil(t, oroOption) - oro, ok := oroOption.(*OptRequestedOption) - require.True(t, ok) - opts := oro.RequestedOptions() - require.Contains(t, opts, OptionDNSRecursiveNameServer) - require.Contains(t, opts, OptionDomainSearchList) - require.Equal(t, len(opts), 2) +func TestGetTransactionIDRelay(t *testing.T) { + message, err := NewMessage() + require.NoError(t, err) + relay, err := EncapsulateRelay(message, MessageTypeRelayForward, nil, nil) + require.NoError(t, err) + transactionID, err := GetTransactionID(relay) + require.NoError(t, err) + require.Equal(t, transactionID, message.(*DHCPv6Message).TransactionID()) } // TODO test NewMessageTypeSolicit diff --git a/dhcpv6/dhcpv6message_test.go b/dhcpv6/dhcpv6message_test.go new file mode 100644 index 0000000..ad90be6 --- /dev/null +++ b/dhcpv6/dhcpv6message_test.go @@ -0,0 +1,98 @@ +package dhcpv6 + +import ( + "net" + "testing" + + "github.com/insomniacslk/dhcp/iana" + "github.com/stretchr/testify/require" +) + +func TestNewAdvertiseFromSolicit(t *testing.T) { + s := DHCPv6Message{} + s.SetMessage(MessageTypeSolicit) + s.SetTransactionID(0xabcdef) + cid := OptClientId{} + s.AddOption(&cid) + duid := Duid{} + + a, err := NewAdvertiseFromSolicit(&s, WithServerID(duid)) + require.NoError(t, err) + require.Equal(t, a.(*DHCPv6Message).TransactionID(), s.TransactionID()) + require.Equal(t, a.Type(), MessageTypeAdvertise) +} + +func TestNewReplyFromDHCPv6Message(t *testing.T) { + msg := DHCPv6Message{} + msg.SetTransactionID(0xabcdef) + cid := OptClientId{} + msg.AddOption(&cid) + sid := OptServerId{} + duid := Duid{} + sid.Sid = duid + msg.AddOption(&sid) + + msg.SetMessage(MessageTypeConfirm) + rep, err := NewReplyFromDHCPv6Message(&msg, WithServerID(duid)) + require.NoError(t, err) + require.Equal(t, rep.(*DHCPv6Message).TransactionID(), msg.TransactionID()) + require.Equal(t, rep.Type(), MessageTypeReply) + + msg.SetMessage(MessageTypeRenew) + rep, err = NewReplyFromDHCPv6Message(&msg, WithServerID(duid)) + require.NoError(t, err) + require.Equal(t, rep.(*DHCPv6Message).TransactionID(), msg.TransactionID()) + require.Equal(t, rep.Type(), MessageTypeReply) + + msg.SetMessage(MessageTypeRebind) + rep, err = NewReplyFromDHCPv6Message(&msg, WithServerID(duid)) + require.NoError(t, err) + require.Equal(t, rep.(*DHCPv6Message).TransactionID(), msg.TransactionID()) + require.Equal(t, rep.Type(), MessageTypeReply) + + msg.SetMessage(MessageTypeRelease) + rep, err = NewReplyFromDHCPv6Message(&msg, WithServerID(duid)) + require.NoError(t, err) + require.Equal(t, rep.(*DHCPv6Message).TransactionID(), msg.TransactionID()) + require.Equal(t, rep.Type(), MessageTypeReply) + + msg.SetMessage(MessageTypeSolicit) + rep, err = NewReplyFromDHCPv6Message(&msg) + require.Error(t, err) + + relay := DHCPv6Relay{} + rep, err = NewReplyFromDHCPv6Message(&relay) + require.Error(t, err) +} + +func TestNewMessageTypeSolicitWithCID(t *testing.T) { + hwAddr, err := net.ParseMAC("24:0A:9E:9F:EB:2B") + require.NoError(t, err) + + duid := Duid{ + Type: DUID_LL, + HwType: iana.HwTypeEthernet, + LinkLayerAddr: hwAddr, + } + + s, err := NewSolicitWithCID(duid) + require.NoError(t, err) + + require.Equal(t, s.Type(), MessageTypeSolicit) + // Check CID + cidOption := s.GetOneOption(OptionClientID) + require.NotNil(t, cidOption) + cid, ok := cidOption.(*OptClientId) + require.True(t, ok) + require.Equal(t, cid.Cid, duid) + + // Check ORO + oroOption := s.GetOneOption(OptionORO) + require.NotNil(t, oroOption) + oro, ok := oroOption.(*OptRequestedOption) + require.True(t, ok) + opts := oro.RequestedOptions() + require.Contains(t, opts, OptionDNSRecursiveNameServer) + require.Contains(t, opts, OptionDomainSearchList) + require.Equal(t, len(opts), 2) +} diff --git a/dhcpv6/utils.go b/dhcpv6/utils.go deleted file mode 100644 index d1715da..0000000 --- a/dhcpv6/utils.go +++ /dev/null @@ -1,86 +0,0 @@ -package dhcpv6 - -import ( - "errors" - "strings" -) - -// IsNetboot function takes a DHCPv6 message and 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 IsNetboot(msg DHCPv6) bool { - if IsRequested(msg, OptionBootfileURL) { - return true - } - if optbf := msg.GetOneOption(OptionBootfileURL); optbf != nil { - return true - } - return false -} - -// IsRequested function takes a DHCPv6 message and an OptionCode, and returns -// true if that option is within the requested options of the DHCPv6 message. -func IsRequested(msg DHCPv6, requested OptionCode) bool { - for _, optoro := range msg.GetOption(OptionORO) { - for _, o := range optoro.(*OptRequestedOption).RequestedOptions() { - if o == requested { - return true - } - } - } - return false -} - -// IsUsingUEFI function takes a DHCPv6 message and returns true if -// the machine trying to netboot is using UEFI of false if it is not. -func IsUsingUEFI(msg DHCPv6) bool { - // RFC 4578 says: - // As of the writing of this document, the following pre-boot - // architecture types have been requested. - // Type Architecture Name - // ---- ----------------- - // 0 Intel x86PC - // 1 NEC/PC98 - // 2 EFI Itanium - // 3 DEC Alpha - // 4 Arc x86 - // 5 Intel Lean Client - // 6 EFI IA32 - // 7 EFI BC - // 8 EFI Xscale - // 9 EFI x86-64 - if opt := msg.GetOneOption(OptionClientArchType); opt != nil { - optat := opt.(*OptClientArchType) - // TODO investigate if other types are appropriate - if optat.ArchType == EFI_BC || optat.ArchType == EFI_X86_64 { - return true - } - } - if opt := msg.GetOneOption(OptionUserClass); opt != nil { - optuc := opt.(*OptUserClass) - for _, uc := range optuc.UserClasses { - if strings.Contains(string(uc), "EFI") { - return true - } - } - } - return false -} - -// GetTransactionID returns a transactionID of a message or its inner message -// in case of relay -func GetTransactionID(packet DHCPv6) (uint32, error) { - if message, ok := packet.(*DHCPv6Message); ok { - return message.TransactionID(), nil - } - if relay, ok := packet.(*DHCPv6Relay); ok { - message, err := relay.GetInnerMessage() - if err != nil { - return 0, err - } - return GetTransactionID(message) - } - return 0, errors.New("Invalid DHCPv6 packet") -} diff --git a/dhcpv6/utils_test.go b/dhcpv6/utils_test.go deleted file mode 100644 index 779d55c..0000000 --- a/dhcpv6/utils_test.go +++ /dev/null @@ -1,80 +0,0 @@ -package dhcpv6 - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -func TestIsNetboot(t *testing.T) { - msg1 := DHCPv6Message{} - require.False(t, IsNetboot(&msg1)) - - msg2 := DHCPv6Message{} - optro := OptRequestedOption{} - optro.AddRequestedOption(OptionBootfileURL) - msg2.AddOption(&optro) - require.True(t, IsNetboot(&msg2)) - - msg3 := DHCPv6Message{} - optbf := OptBootFileURL{} - msg3.AddOption(&optbf) - require.True(t, IsNetboot(&msg3)) -} - -func TestIsRequetsed(t *testing.T) { - msg1 := DHCPv6Message{} - require.False(t, IsRequested(&msg1, OptionDNSRecursiveNameServer)) - - msg2 := DHCPv6Message{} - optro := OptRequestedOption{} - optro.AddRequestedOption(OptionDNSRecursiveNameServer) - msg2.AddOption(&optro) - require.True(t, IsRequested(&msg2, OptionDNSRecursiveNameServer)) -} - -func TestIsUsingUEFIArchTypeTrue(t *testing.T) { - msg := DHCPv6Message{} - opt := OptClientArchType{ArchType: EFI_BC} - msg.AddOption(&opt) - require.True(t, IsUsingUEFI(&msg)) -} - -func TestIsUsingUEFIArchTypeFalse(t *testing.T) { - msg := DHCPv6Message{} - opt := OptClientArchType{ArchType: INTEL_X86PC} - msg.AddOption(&opt) - require.False(t, IsUsingUEFI(&msg)) -} - -func TestIsUsingUEFIUserClassTrue(t *testing.T) { - msg := DHCPv6Message{} - opt := OptUserClass{UserClasses: [][]byte{[]byte("ipxeUEFI")}} - msg.AddOption(&opt) - require.True(t, IsUsingUEFI(&msg)) -} - -func TestIsUsingUEFIUserClassFalse(t *testing.T) { - msg := DHCPv6Message{} - opt := OptUserClass{UserClasses: [][]byte{[]byte("ipxeLegacy")}} - msg.AddOption(&opt) - require.False(t, IsUsingUEFI(&msg)) -} - -func TestGetTransactionIDMessage(t *testing.T) { - message, err := NewMessage() - require.NoError(t, err) - transactionID, err := GetTransactionID(message) - require.NoError(t, err) - require.Equal(t, transactionID, message.(*DHCPv6Message).TransactionID()) -} - -func TestGetTransactionIDRelay(t *testing.T) { - message, err := NewMessage() - require.NoError(t, err) - relay, err := EncapsulateRelay(message, MessageTypeRelayForward, nil, nil) - require.NoError(t, err) - transactionID, err := GetTransactionID(relay) - require.NoError(t, err) - require.Equal(t, transactionID, message.(*DHCPv6Message).TransactionID()) -} |