summaryrefslogtreecommitdiffhomepage
path: root/dhcpv6
diff options
context:
space:
mode:
Diffstat (limited to 'dhcpv6')
-rw-r--r--dhcpv6/dhcpv6message.go13
-rw-r--r--dhcpv6/modifiers.go14
-rw-r--r--dhcpv6/modifiers_test.go15
-rw-r--r--dhcpv6/option_dhcpv4_msg.go39
-rw-r--r--dhcpv6/option_dhcpv4_msg_test.go105
-rw-r--r--dhcpv6/option_dhcpv4_o_dhcpv6_server.go46
-rw-r--r--dhcpv6/option_dhcpv4_o_dhcpv6_server_test.go55
-rw-r--r--dhcpv6/option_iaaddress.go24
-rw-r--r--dhcpv6/option_iaaddress_test.go10
-rw-r--r--dhcpv6/option_nontemporaryaddress.go57
-rw-r--r--dhcpv6/option_nontemporaryaddress_test.go50
-rw-r--r--dhcpv6/options.go4
-rw-r--r--dhcpv6/types.go6
13 files changed, 390 insertions, 48 deletions
diff --git a/dhcpv6/dhcpv6message.go b/dhcpv6/dhcpv6message.go
index 0927038..2067fcc 100644
--- a/dhcpv6/dhcpv6message.go
+++ b/dhcpv6/dhcpv6message.go
@@ -241,6 +241,19 @@ func (mo MessageOptions) FQDN() *OptFQDN {
return nil
}
+// DHCP4oDHCP6Server returns the DHCP 4o6 Server Address option as
+// defined by RFC 7341.
+func (mo MessageOptions) DHCP4oDHCP6Server() *OptDHCP4oDHCP6Server {
+ opt := mo.Options.GetOne(OptionDHCP4oDHCP6Server)
+ if opt == nil {
+ return nil
+ }
+ if server, ok := opt.(*OptDHCP4oDHCP6Server); ok {
+ return server
+ }
+ return nil
+}
+
// Message represents a DHCPv6 Message as defined by RFC 3315 Section 6.
type Message struct {
MessageType MessageType
diff --git a/dhcpv6/modifiers.go b/dhcpv6/modifiers.go
index 14bfe51..ffea9ed 100644
--- a/dhcpv6/modifiers.go
+++ b/dhcpv6/modifiers.go
@@ -63,7 +63,7 @@ func WithIANA(addrs ...OptIAAddress) Modifier {
iana = &OptIANA{}
}
for _, addr := range addrs {
- iana.AddOption(&addr)
+ iana.Options.Add(&addr)
}
msg.UpdateOption(iana)
}
@@ -77,7 +77,7 @@ func WithIAID(iaid [4]byte) Modifier {
iana := msg.Options.OneIANA()
if iana == nil {
iana = &OptIANA{
- Options: Options{},
+ Options: IdentityOptions{Options: []Option{}},
}
}
copy(iana.IaId[:], iaid[:])
@@ -119,3 +119,13 @@ func WithRequestedOptions(codes ...OptionCode) Modifier {
}
}
}
+
+// WithDHCP4oDHCP6Server adds or updates an OptDHCP4oDHCP6Server
+func WithDHCP4oDHCP6Server(addrs ...net.IP) Modifier {
+ return func(d DHCPv6) {
+ opt := OptDHCP4oDHCP6Server{
+ DHCP4oDHCP6Servers: addrs,
+ }
+ d.UpdateOption(&opt)
+ }
+}
diff --git a/dhcpv6/modifiers_test.go b/dhcpv6/modifiers_test.go
index b99d4a2..c240067 100644
--- a/dhcpv6/modifiers_test.go
+++ b/dhcpv6/modifiers_test.go
@@ -92,3 +92,18 @@ func TestWithFQDN(t *testing.T) {
require.Equal(t, uint8(4), ofqdn.Flags)
require.Equal(t, "cnos.localhost", ofqdn.DomainName)
}
+
+func TestWithDHCP4oDHCP6Server(t *testing.T) {
+ var d Message
+ WithDHCP4oDHCP6Server([]net.IP{
+ net.ParseIP("fe80::1"),
+ net.ParseIP("fe80::2"),
+ }...)(&d)
+ require.Equal(t, 1, len(d.Options.Options))
+ opt := d.Options.DHCP4oDHCP6Server()
+ require.Equal(t, OptionDHCP4oDHCP6Server, opt.Code())
+ require.Equal(t, 2, len(opt.DHCP4oDHCP6Servers))
+ require.Equal(t, net.ParseIP("fe80::1"), opt.DHCP4oDHCP6Servers[0])
+ require.Equal(t, net.ParseIP("fe80::2"), opt.DHCP4oDHCP6Servers[1])
+ require.NotEqual(t, net.ParseIP("fe80::1"), opt.DHCP4oDHCP6Servers[1])
+}
diff --git a/dhcpv6/option_dhcpv4_msg.go b/dhcpv6/option_dhcpv4_msg.go
new file mode 100644
index 0000000..0a1a2b3
--- /dev/null
+++ b/dhcpv6/option_dhcpv4_msg.go
@@ -0,0 +1,39 @@
+package dhcpv6
+
+import (
+ "fmt"
+
+ "github.com/insomniacslk/dhcp/dhcpv4"
+)
+
+// OptDHCPv4Msg represents a OptionDHCPv4Msg option
+//
+// This module defines the OptDHCPv4Msg structure.
+// https://www.ietf.org/rfc/rfc7341.txt
+type OptDHCPv4Msg struct {
+ Msg *dhcpv4.DHCPv4
+}
+
+// Code returns the option code
+func (op *OptDHCPv4Msg) Code() OptionCode {
+ return OptionDHCPv4Msg
+}
+
+// ToBytes returns the option serialized to bytes.
+func (op *OptDHCPv4Msg) ToBytes() []byte {
+ return op.Msg.ToBytes()
+}
+
+func (op *OptDHCPv4Msg) String() string {
+ return fmt.Sprintf("OptDHCPv4Msg{%v}", op.Msg)
+}
+
+// ParseOptDHCPv4Msg builds an OptDHCPv4Msg structure
+// from a sequence of bytes. The input data does not include option code and length
+// bytes.
+func ParseOptDHCPv4Msg(data []byte) (*OptDHCPv4Msg, error) {
+ var opt OptDHCPv4Msg
+ var err error
+ opt.Msg, err = dhcpv4.FromBytes(data)
+ return &opt, err
+}
diff --git a/dhcpv6/option_dhcpv4_msg_test.go b/dhcpv6/option_dhcpv4_msg_test.go
new file mode 100644
index 0000000..1ffa17a
--- /dev/null
+++ b/dhcpv6/option_dhcpv4_msg_test.go
@@ -0,0 +1,105 @@
+package dhcpv6
+
+import (
+ "bytes"
+ "net"
+ "testing"
+
+ "github.com/insomniacslk/dhcp/dhcpv4"
+ "github.com/insomniacslk/dhcp/iana"
+ "github.com/stretchr/testify/require"
+)
+
+var magicCookie = [4]byte{99, 130, 83, 99}
+
+func TestParseOptDHCPv4Msg(t *testing.T) {
+ data := []byte{
+ 1, // dhcp request
+ 1, // ethernet hw type
+ 6, // hw addr length
+ 3, // hop count
+ 0xaa, 0xbb, 0xcc, 0xdd, // transaction ID, big endian (network)
+ 0, 3, // number of seconds
+ 0, 1, // broadcast
+ 0, 0, 0, 0, // client IP address
+ 0, 0, 0, 0, // your IP address
+ 0, 0, 0, 0, // server IP address
+ 0, 0, 0, 0, // gateway IP address
+ 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // client MAC address + padding
+ }
+
+ // server host name
+ expectedHostname := []byte{}
+ for i := 0; i < 64; i++ {
+ expectedHostname = append(expectedHostname, 0)
+ }
+ data = append(data, expectedHostname...)
+ // boot file name
+ expectedBootfilename := []byte{}
+ for i := 0; i < 128; i++ {
+ expectedBootfilename = append(expectedBootfilename, 0)
+ }
+ data = append(data, expectedBootfilename...)
+ // magic cookie, then no options
+ data = append(data, magicCookie[:]...)
+
+ opt, err := ParseOptDHCPv4Msg(data)
+ d := opt.Msg
+ require.NoError(t, err)
+ require.Equal(t, d.OpCode, dhcpv4.OpcodeBootRequest)
+ require.Equal(t, d.HWType, iana.HWTypeEthernet)
+ require.Equal(t, d.HopCount, byte(3))
+ require.Equal(t, d.TransactionID, dhcpv4.TransactionID{0xaa, 0xbb, 0xcc, 0xdd})
+ require.Equal(t, d.NumSeconds, uint16(3))
+ require.Equal(t, d.Flags, uint16(1))
+ require.True(t, d.ClientIPAddr.Equal(net.IPv4zero))
+ require.True(t, d.YourIPAddr.Equal(net.IPv4zero))
+ require.True(t, d.GatewayIPAddr.Equal(net.IPv4zero))
+ require.Equal(t, d.ClientHWAddr, net.HardwareAddr{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff})
+ require.Equal(t, d.ServerHostName, "")
+ require.Equal(t, d.BootFileName, "")
+ // no need to check Magic Cookie as it is already validated in FromBytes
+ // above
+}
+
+func TestOptDHCPv4MsgToBytes(t *testing.T) {
+ // the following bytes match what dhcpv4.New would create. Keep them in
+ // sync!
+ expected := []byte{
+ 1, // Opcode BootRequest
+ 1, // HwType Ethernet
+ 6, // HwAddrLen
+ 0, // HopCount
+ 0x11, 0x22, 0x33, 0x44, // TransactionID
+ 0, 0, // NumSeconds
+ 0, 0, // Flags
+ 0, 0, 0, 0, // ClientIPAddr
+ 0, 0, 0, 0, // YourIPAddr
+ 0, 0, 0, 0, // ServerIPAddr
+ 0, 0, 0, 0, // GatewayIPAddr
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ClientHwAddr
+ }
+ // ServerHostName
+ expected = append(expected, bytes.Repeat([]byte{0}, 64)...)
+ // BootFileName
+ expected = append(expected, bytes.Repeat([]byte{0}, 128)...)
+
+ // Magic Cookie
+ expected = append(expected, magicCookie[:]...)
+
+ // Minimum message length padding.
+ //
+ // 236 + 4 byte cookie + 59 bytes padding + 1 byte end.
+ expected = append(expected, bytes.Repeat([]byte{0}, 59)...)
+
+ // End
+ expected = append(expected, 0xff)
+
+ d, err := dhcpv4.New()
+ require.NoError(t, err)
+ // fix TransactionID to match the expected one, since it's randomly
+ // generated in New()
+ d.TransactionID = dhcpv4.TransactionID{0x11, 0x22, 0x33, 0x44}
+ opt := OptDHCPv4Msg{Msg: d}
+ require.Equal(t, expected, opt.ToBytes())
+}
diff --git a/dhcpv6/option_dhcpv4_o_dhcpv6_server.go b/dhcpv6/option_dhcpv4_o_dhcpv6_server.go
new file mode 100644
index 0000000..a46ecac
--- /dev/null
+++ b/dhcpv6/option_dhcpv4_o_dhcpv6_server.go
@@ -0,0 +1,46 @@
+package dhcpv6
+
+import (
+ "fmt"
+ "net"
+
+ "github.com/u-root/u-root/pkg/uio"
+)
+
+// OptDHCP4oDHCP6Server represents a OptionDHCP4oDHCP6Server option
+//
+// This module defines the OptDHCP4oDHCP6Server structure.
+// https://www.ietf.org/rfc/rfc7341.txt
+type OptDHCP4oDHCP6Server struct {
+ DHCP4oDHCP6Servers []net.IP
+}
+
+// Code returns the option code
+func (op *OptDHCP4oDHCP6Server) Code() OptionCode {
+ return OptionDHCP4oDHCP6Server
+}
+
+// ToBytes returns the option serialized to bytes.
+func (op *OptDHCP4oDHCP6Server) ToBytes() []byte {
+ buf := uio.NewBigEndianBuffer(nil)
+ for _, addr := range op.DHCP4oDHCP6Servers {
+ buf.WriteBytes(addr.To16())
+ }
+ return buf.Data()
+}
+
+func (op *OptDHCP4oDHCP6Server) String() string {
+ return fmt.Sprintf("OptDHCP4oDHCP6Server{4o6-servers=%v}", op.DHCP4oDHCP6Servers)
+}
+
+// ParseOptDHCP4oDHCP6Server builds an OptDHCP4oDHCP6Server structure
+// from a sequence of bytes. The input data does not include option code and length
+// bytes.
+func ParseOptDHCP4oDHCP6Server(data []byte) (*OptDHCP4oDHCP6Server, error) {
+ var opt OptDHCP4oDHCP6Server
+ buf := uio.NewBigEndianBuffer(data)
+ for buf.Has(net.IPv6len) {
+ opt.DHCP4oDHCP6Servers = append(opt.DHCP4oDHCP6Servers, buf.CopyN(net.IPv6len))
+ }
+ return &opt, buf.FinError()
+}
diff --git a/dhcpv6/option_dhcpv4_o_dhcpv6_server_test.go b/dhcpv6/option_dhcpv4_o_dhcpv6_server_test.go
new file mode 100644
index 0000000..de86594
--- /dev/null
+++ b/dhcpv6/option_dhcpv4_o_dhcpv6_server_test.go
@@ -0,0 +1,55 @@
+package dhcpv6
+
+import (
+ "net"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func TestParseOptDHCP4oDHCP6Server(t *testing.T) {
+ data := []byte{
+ 0x2a, 0x03, 0x28, 0x80, 0xff, 0xfe, 0x00, 0x0c, 0xfa, 0xce, 0xb0, 0x0c, 0x00, 0x00, 0x00, 0x35,
+ }
+ expected := []net.IP{
+ net.IP(data),
+ }
+ opt, err := ParseOptDHCP4oDHCP6Server(data)
+ require.NoError(t, err)
+ require.Equal(t, expected, opt.DHCP4oDHCP6Servers)
+ require.Equal(t, OptionDHCP4oDHCP6Server, opt.Code())
+ require.Contains(t, opt.String(), "4o6-servers=[2a03:2880:fffe:c:face:b00c:0:35]", "String() should contain the correct DHCP4-over-DHCP6 server output")
+}
+
+func TestOptDHCP4oDHCP6ServerToBytes(t *testing.T) {
+ ip1 := net.ParseIP("2a03:2880:fffe:c:face:b00c:0:35")
+ ip2 := net.ParseIP("2001:4860:4860::8888")
+ servers := []net.IP{ip1, ip2}
+ expected := append([]byte{}, []byte(ip1)...)
+ expected = append(expected, []byte(ip2)...)
+ opt := OptDHCP4oDHCP6Server{DHCP4oDHCP6Servers: servers}
+ require.Equal(t, expected, opt.ToBytes())
+}
+
+func TestParseOptDHCP4oDHCP6ServerParseNoAddr(t *testing.T) {
+ data := []byte{
+ }
+ var expected []net.IP
+ opt, err := ParseOptDHCP4oDHCP6Server(data)
+ require.NoError(t, err)
+ require.Equal(t, expected, opt.DHCP4oDHCP6Servers)
+}
+
+func TestOptDHCP4oDHCP6ServerToBytesNoAddr(t *testing.T) {
+ expected := []byte(nil)
+ opt := OptDHCP4oDHCP6Server{}
+ require.Equal(t, expected, opt.ToBytes())
+}
+
+func TestParseOptDHCP4oDHCP6ServerParseBogus(t *testing.T) {
+ data := []byte{
+ 0x2a, 0x03, 0x28, 0x80, 0xff, 0xfe, 0x00, 0x0c, // invalid IPv6 address
+ }
+ _, err := ParseOptDHCP4oDHCP6Server(data)
+ require.Error(t, err, "An invalid IPv6 address should return an error")
+}
diff --git a/dhcpv6/option_iaaddress.go b/dhcpv6/option_iaaddress.go
index c4184e1..9752ee7 100644
--- a/dhcpv6/option_iaaddress.go
+++ b/dhcpv6/option_iaaddress.go
@@ -8,6 +8,26 @@ import (
"github.com/u-root/u-root/pkg/uio"
)
+// AddressOptions are options valid for the IAAddress option field.
+//
+// RFC 8415 Appendix C lists only the Status Code option as valid.
+type AddressOptions struct {
+ Options
+}
+
+// Status returns the status code associated with this option.
+func (ao AddressOptions) Status() *OptStatusCode {
+ opt := ao.Options.GetOne(OptionStatusCode)
+ if opt == nil {
+ return nil
+ }
+ sc, ok := opt.(*OptStatusCode)
+ if !ok {
+ return nil
+ }
+ return sc
+}
+
// OptIAAddress represents an OptionIAAddr.
//
// This module defines the OptIAAddress structure.
@@ -16,7 +36,7 @@ type OptIAAddress struct {
IPv6Addr net.IP
PreferredLifetime time.Duration
ValidLifetime time.Duration
- Options Options
+ Options AddressOptions
}
// Code returns the option's code
@@ -39,7 +59,7 @@ func (op *OptIAAddress) ToBytes() []byte {
}
func (op *OptIAAddress) String() string {
- return fmt.Sprintf("OptIAAddress{ipv6addr=%v, preferredlifetime=%v, validlifetime=%v, options=%v}",
+ return fmt.Sprintf("IAAddress: IP=%v PreferredLifetime=%v ValidLifetime=%v Options=%v",
op.IPv6Addr, op.PreferredLifetime, op.ValidLifetime, op.Options)
}
diff --git a/dhcpv6/option_iaaddress_test.go b/dhcpv6/option_iaaddress_test.go
index 4db999c..900973c 100644
--- a/dhcpv6/option_iaaddress_test.go
+++ b/dhcpv6/option_iaaddress_test.go
@@ -54,9 +54,9 @@ func TestOptIAAddressToBytes(t *testing.T) {
IPv6Addr: net.IP(ipBytes),
PreferredLifetime: 0x0a0b0c0d * time.Second,
ValidLifetime: 0x0e0f0102 * time.Second,
- Options: []Option{
+ Options: AddressOptions{[]Option{
OptElapsedTime(10 * time.Millisecond),
- },
+ }},
}
require.Equal(t, expected, opt.ToBytes())
}
@@ -74,17 +74,17 @@ func TestOptIAAddressString(t *testing.T) {
str := opt.String()
require.Contains(
t, str,
- "ipv6addr=2401:203:405:607:809:a0b:c0d:e0f",
+ "IP=2401:203:405:607:809:a0b:c0d:e0f",
"String() should return the ipv6addr",
)
require.Contains(
t, str,
- "preferredlifetime=1m10s",
+ "PreferredLifetime=1m10s",
"String() should return the preferredlifetime",
)
require.Contains(
t, str,
- "validlifetime=50s",
+ "ValidLifetime=50s",
"String() should return the validlifetime",
)
}
diff --git a/dhcpv6/option_nontemporaryaddress.go b/dhcpv6/option_nontemporaryaddress.go
index 3ea46fe..0b6012e 100644
--- a/dhcpv6/option_nontemporaryaddress.go
+++ b/dhcpv6/option_nontemporaryaddress.go
@@ -25,6 +25,45 @@ func (d *Duration) Unmarshal(buf *uio.Lexer) {
d.Duration = time.Duration(t) * time.Second
}
+// IdentityOptions implement the options allowed for IA_NA and IA_TA messages.
+//
+// The allowed options are identified in RFC 3315 Appendix B.
+type IdentityOptions struct {
+ Options
+}
+
+// Addresses returns the addresses assigned to the identity.
+func (io IdentityOptions) Addresses() []*OptIAAddress {
+ opts := io.Options.Get(OptionIAAddr)
+ var iaAddrs []*OptIAAddress
+ for _, o := range opts {
+ iaAddrs = append(iaAddrs, o.(*OptIAAddress))
+ }
+ return iaAddrs
+}
+
+// OneAddress returns one address (of potentially many) assigned to the identity.
+func (io IdentityOptions) OneAddress() *OptIAAddress {
+ a := io.Addresses()
+ if len(a) == 0 {
+ return nil
+ }
+ return a[0]
+}
+
+// Status returns the status code associated with this option.
+func (io IdentityOptions) Status() *OptStatusCode {
+ opt := io.Options.GetOne(OptionStatusCode)
+ if opt == nil {
+ return nil
+ }
+ sc, ok := opt.(*OptStatusCode)
+ if !ok {
+ return nil
+ }
+ return sc
+}
+
// OptIANA implements the identity association for non-temporary addresses
// option.
//
@@ -34,7 +73,7 @@ type OptIANA struct {
IaId [4]byte
T1 time.Duration
T2 time.Duration
- Options Options
+ Options IdentityOptions
}
func (op *OptIANA) Code() OptionCode {
@@ -58,22 +97,6 @@ func (op *OptIANA) String() string {
op.IaId, op.T1, op.T2, op.Options)
}
-// AddOption adds an option at the end of the IA_NA options
-func (op *OptIANA) AddOption(opt Option) {
- op.Options.Add(opt)
-}
-
-// GetOneOption will get an option of the give type from the Options field, if
-// it is present. It will return `nil` otherwise
-func (op *OptIANA) GetOneOption(code OptionCode) Option {
- return op.Options.GetOne(code)
-}
-
-// DelOption will remove all the options that match a Option code.
-func (op *OptIANA) DelOption(code OptionCode) {
- op.Options.Del(code)
-}
-
// ParseOptIANA builds an OptIANA structure from a sequence of bytes. The
// input data does not include option code and length bytes.
func ParseOptIANA(data []byte) (*OptIANA, error) {
diff --git a/dhcpv6/option_nontemporaryaddress_test.go b/dhcpv6/option_nontemporaryaddress_test.go
index ceee9ec..50cb11b 100644
--- a/dhcpv6/option_nontemporaryaddress_test.go
+++ b/dhcpv6/option_nontemporaryaddress_test.go
@@ -46,16 +46,16 @@ func TestOptIANAGetOneOption(t *testing.T) {
IPv6Addr: net.ParseIP("::1"),
}
opt := OptIANA{
- Options: []Option{OptElapsedTime(0), oaddr},
+ Options: IdentityOptions{[]Option{&OptStatusCode{}, oaddr}},
}
- require.Equal(t, oaddr, opt.GetOneOption(OptionIAAddr))
+ require.Equal(t, oaddr, opt.Options.OneAddress())
}
func TestOptIANAAddOption(t *testing.T) {
opt := OptIANA{}
- opt.AddOption(OptElapsedTime(0))
- require.Equal(t, 1, len(opt.Options))
- require.Equal(t, OptionElapsedTime, opt.Options[0].Code())
+ opt.Options.Add(OptElapsedTime(0))
+ require.Equal(t, 1, len(opt.Options.Options))
+ require.Equal(t, OptionElapsedTime, opt.Options.Options[0].Code())
}
func TestOptIANAGetOneOptionMissingOpt(t *testing.T) {
@@ -63,28 +63,34 @@ func TestOptIANAGetOneOptionMissingOpt(t *testing.T) {
IPv6Addr: net.ParseIP("::1"),
}
opt := OptIANA{
- Options: []Option{OptElapsedTime(0), oaddr},
+ Options: IdentityOptions{[]Option{&OptStatusCode{}, oaddr}},
}
- require.Equal(t, nil, opt.GetOneOption(OptionDNSRecursiveNameServer))
+ require.Equal(t, nil, opt.Options.GetOne(OptionDNSRecursiveNameServer))
}
func TestOptIANADelOption(t *testing.T) {
- optiana1 := OptIANA{}
- optiana2 := OptIANA{}
optiaaddr := OptIAAddress{}
optsc := OptStatusCode{}
- optiana1.Options = append(optiana1.Options, &optsc)
- optiana1.Options = append(optiana1.Options, &optiaaddr)
- optiana1.Options = append(optiana1.Options, &optiaaddr)
- optiana1.DelOption(OptionIAAddr)
- require.Equal(t, optiana1.Options, Options{&optsc})
+ iana1 := OptIANA{
+ Options: IdentityOptions{[]Option{
+ &optsc,
+ &optiaaddr,
+ &optiaaddr,
+ }},
+ }
+ iana1.Options.Del(OptionIAAddr)
+ require.Equal(t, iana1.Options.Options, Options{&optsc})
- optiana2.Options = append(optiana2.Options, &optiaaddr)
- optiana2.Options = append(optiana2.Options, &optsc)
- optiana2.Options = append(optiana2.Options, &optiaaddr)
- optiana2.DelOption(OptionIAAddr)
- require.Equal(t, optiana2.Options, Options{&optsc})
+ iana2 := OptIANA{
+ Options: IdentityOptions{[]Option{
+ &optiaaddr,
+ &optsc,
+ &optiaaddr,
+ }},
+ }
+ iana2.Options.Del(OptionIAAddr)
+ require.Equal(t, iana2.Options.Options, Options{&optsc})
}
func TestOptIANAToBytes(t *testing.T) {
@@ -92,9 +98,9 @@ func TestOptIANAToBytes(t *testing.T) {
IaId: [4]byte{1, 2, 3, 4},
T1: 12345 * time.Second,
T2: 54321 * time.Second,
- Options: []Option{
+ Options: IdentityOptions{[]Option{
OptElapsedTime(10 * time.Millisecond),
- },
+ }},
}
expected := []byte{
1, 2, 3, 4, // IA ID
@@ -128,7 +134,7 @@ func TestOptIANAString(t *testing.T) {
)
require.Contains(
t, str,
- "options=[",
+ "options={",
"String() should return a list of options",
)
}
diff --git a/dhcpv6/options.go b/dhcpv6/options.go
index 9b76f6d..87a33ff 100644
--- a/dhcpv6/options.go
+++ b/dhcpv6/options.go
@@ -87,6 +87,10 @@ func ParseOption(code OptionCode, optData []byte) (Option, error) {
var o OptNetworkInterfaceID
err = o.FromBytes(optData)
opt = &o
+ case OptionDHCPv4Msg:
+ opt, err = ParseOptDHCPv4Msg(optData)
+ case OptionDHCP4oDHCP6Server:
+ opt, err = ParseOptDHCP4oDHCP6Server(optData)
case Option4RD:
opt, err = ParseOpt4RD(optData)
case Option4RDMapRule:
diff --git a/dhcpv6/types.go b/dhcpv6/types.go
index 560581c..7c4052f 100644
--- a/dhcpv6/types.go
+++ b/dhcpv6/types.go
@@ -36,6 +36,10 @@ const (
MessageTypeLeaseQueryReply MessageType = 15
MessageTypeLeaseQueryDone MessageType = 16
MessageTypeLeaseQueryData MessageType = 17
+ _ MessageType = 18
+ _ MessageType = 19
+ MessageTypeDHCPv4Query MessageType = 20
+ MessageTypeDHCPv4Response MessageType = 21
)
// String prints the message type name.
@@ -66,6 +70,8 @@ var messageTypeToStringMap = map[MessageType]string{
MessageTypeLeaseQueryReply: "LEASEQUERY-REPLY",
MessageTypeLeaseQueryDone: "LEASEQUERY-DONE",
MessageTypeLeaseQueryData: "LEASEQUERY-DATA",
+ MessageTypeDHCPv4Query: "DHCPv4-QUERY",
+ MessageTypeDHCPv4Response: "DHCPv4-RESPONSE",
}
// OptionCode is a single byte representing the code for a given Option.