summaryrefslogtreecommitdiffhomepage
path: root/dhcpv6
diff options
context:
space:
mode:
authorPablo Mazzini <pmazzini@gmail.com>2020-03-09 17:27:45 +0000
committerGitHub <noreply@github.com>2020-03-09 17:27:45 +0000
commit00901efc824ad5efb860c98ae3cd2e50a3ba610d (patch)
tree8a9626b86dcadf6c206ffd613c99b45d21c714df /dhcpv6
parent19ee83379cf483ab151dd1ad4e36d09483d6a223 (diff)
parent59c22a151d6899aedd143445953e5906b0d11574 (diff)
Merge branch 'master' into feature/dhcp4-o-dhcp6
Diffstat (limited to 'dhcpv6')
-rw-r--r--dhcpv6/dhcpv6message.go24
-rw-r--r--dhcpv6/modifiers.go4
-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
6 files changed, 121 insertions, 48 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",
)
}