diff options
-rw-r--r-- | dhcpv6/modifiers.go | 4 | ||||
-rw-r--r-- | dhcpv6/option_nontemporaryaddress.go | 57 | ||||
-rw-r--r-- | dhcpv6/option_nontemporaryaddress_test.go | 50 |
3 files changed, 70 insertions, 41 deletions
diff --git a/dhcpv6/modifiers.go b/dhcpv6/modifiers.go index 14bfe51..ce5ce97 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_nontemporaryaddress.go b/dhcpv6/option_nontemporaryaddress.go index 3ea46fe..01971f8 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 +} + +// Address returns the addresses assigned to the identity. +func (io IdentityOptions) Address() []*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.Address() + 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", ) } |