diff options
-rw-r--r-- | dhcpv6/dhcpv6message.go | 24 | ||||
-rw-r--r-- | dhcpv6/modifiers.go | 4 | ||||
-rw-r--r-- | dhcpv6/option_iaaddress.go | 24 | ||||
-rw-r--r-- | dhcpv6/option_iaaddress_test.go | 10 | ||||
-rw-r--r-- | dhcpv6/option_nontemporaryaddress.go | 57 | ||||
-rw-r--r-- | dhcpv6/option_nontemporaryaddress_test.go | 50 | ||||
-rw-r--r-- | netboot/netconf.go | 13 |
7 files changed, 123 insertions, 59 deletions
diff --git a/dhcpv6/dhcpv6message.go b/dhcpv6/dhcpv6message.go index 2ec3203..3b850fb 100644 --- a/dhcpv6/dhcpv6message.go +++ b/dhcpv6/dhcpv6message.go @@ -167,6 +167,30 @@ func (mo MessageOptions) BootFileParam() []string { return nil } +// UserClasses returns a list of user classes. +func (mo MessageOptions) UserClasses() [][]byte { + opt := mo.Options.GetOne(OptionUserClass) + if opt == nil { + return nil + } + if t, ok := opt.(*OptUserClass); ok { + return t.UserClasses + } + return nil +} + +// VendorOpts returns the enterprise number and a list of vendor options. +func (mo MessageOptions) VendorOpts() (uint32, Options) { + opt := mo.Options.GetOne(OptionVendorOpts) + if opt == nil { + return 0, nil + } + if t, ok := opt.(*OptVendorOpts); ok { + return t.EnterpriseNumber, t.VendorOpts + } + return 0, nil +} + // ElapsedTime returns the Elapsed Time option as defined by RFC 3315 Section 22.9. // // ElapsedTime returns a duration of 0 if the option is not present. diff --git a/dhcpv6/modifiers.go b/dhcpv6/modifiers.go index 549ec38..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[:]) 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/netboot/netconf.go b/netboot/netconf.go index 78ddff8..60468a7 100644 --- a/netboot/netconf.go +++ b/netboot/netconf.go @@ -41,19 +41,11 @@ func GetNetConfFromPacketv6(d *dhcpv6.Message) (*NetConf, error) { } netconf := NetConf{} - // get IP configuration - iaaddrs := make([]*dhcpv6.OptIAAddress, 0) - for _, o := range iana.Options { - if o.Code() == dhcpv6.OptionIAAddr { - iaaddrs = append(iaaddrs, o.(*dhcpv6.OptIAAddress)) - } - } - netmask := net.IPMask(net.ParseIP("ffff:ffff:ffff:ffff::")) - for _, iaaddr := range iaaddrs { + for _, iaaddr := range iana.Options.Addresses() { netconf.Addresses = append(netconf.Addresses, AddrConf{ IPNet: net.IPNet{ IP: iaaddr.IPv6Addr, - Mask: netmask, + Mask: net.CIDRMask(64, 128), }, PreferredLifetime: iaaddr.PreferredLifetime, ValidLifetime: iaaddr.ValidLifetime, @@ -70,7 +62,6 @@ func GetNetConfFromPacketv6(d *dhcpv6.Message) (*NetConf, error) { if domains != nil { netconf.DNSSearchList = domains.Labels } - return &netconf, nil } |