From 4d26b5e0b42f27fa41d872b15a7d2bc867787975 Mon Sep 17 00:00:00 2001 From: Chris Koch Date: Sat, 28 Dec 2019 04:05:29 -0800 Subject: v6: rename IAPD option to be shorter Also removes superfluous GetOne/Del proxy functions. Signed-off-by: Chris Koch --- dhcpv6/dhcpv6message.go | 8 +- dhcpv6/option_iapd.go | 61 ++++++++++++ dhcpv6/option_iapd_test.go | 111 ++++++++++++++++++++++ dhcpv6/option_prefixdelegation.go | 72 --------------- dhcpv6/option_prefixdelegation_test.go | 164 --------------------------------- dhcpv6/options.go | 2 +- 6 files changed, 177 insertions(+), 241 deletions(-) create mode 100644 dhcpv6/option_iapd.go create mode 100644 dhcpv6/option_iapd_test.go delete mode 100644 dhcpv6/option_prefixdelegation.go delete mode 100644 dhcpv6/option_prefixdelegation_test.go (limited to 'dhcpv6') diff --git a/dhcpv6/dhcpv6message.go b/dhcpv6/dhcpv6message.go index cb0503f..7d96ce3 100644 --- a/dhcpv6/dhcpv6message.go +++ b/dhcpv6/dhcpv6message.go @@ -68,17 +68,17 @@ func (mo MessageOptions) OneIANA() *OptIANA { } // IAPD returns all Identity Association for Prefix Delegation options. -func (mo MessageOptions) IAPD() []*OptIAForPrefixDelegation { +func (mo MessageOptions) IAPD() []*OptIAPD { opts := mo.Get(OptionIAPD) - var ianas []*OptIAForPrefixDelegation + var ianas []*OptIAPD for _, o := range opts { - ianas = append(ianas, o.(*OptIAForPrefixDelegation)) + ianas = append(ianas, o.(*OptIAPD)) } return ianas } // OneIAPD returns the first IAPD option. -func (mo MessageOptions) OneIAPD() *OptIAForPrefixDelegation { +func (mo MessageOptions) OneIAPD() *OptIAPD { iapds := mo.IAPD() if len(iapds) == 0 { return nil diff --git a/dhcpv6/option_iapd.go b/dhcpv6/option_iapd.go new file mode 100644 index 0000000..03f3744 --- /dev/null +++ b/dhcpv6/option_iapd.go @@ -0,0 +1,61 @@ +package dhcpv6 + +import ( + "fmt" + "time" + + "github.com/u-root/u-root/pkg/uio" +) + +// OptIAPD implements the identity association for prefix +// delegation option defined by RFC 3633, Section 9. +type OptIAPD struct { + IaId [4]byte + T1 time.Duration + T2 time.Duration + Options Options +} + +// Code returns the option code +func (op *OptIAPD) Code() OptionCode { + return OptionIAPD +} + +// ToBytes serializes the option and returns it as a sequence of bytes +func (op *OptIAPD) ToBytes() []byte { + buf := uio.NewBigEndianBuffer(nil) + buf.WriteBytes(op.IaId[:]) + + t1 := Duration{op.T1} + t1.Marshal(buf) + t2 := Duration{op.T2} + t2.Marshal(buf) + + buf.WriteBytes(op.Options.ToBytes()) + return buf.Data() +} + +// String returns a string representation of the OptIAPD data +func (op *OptIAPD) String() string { + return fmt.Sprintf("OptIAPD{IAID=%v, t1=%v, t2=%v, options=%v}", + op.IaId, op.T1, op.T2, op.Options) +} + +// ParseOptIAPD builds an OptIAPD structure from a sequence of bytes. +// The input data does not include option code and length bytes. +func ParseOptIAPD(data []byte) (*OptIAPD, error) { + var opt OptIAPD + buf := uio.NewBigEndianBuffer(data) + buf.ReadBytes(opt.IaId[:]) + + var t1, t2 Duration + t1.Unmarshal(buf) + t2.Unmarshal(buf) + opt.T1 = t1.Duration + opt.T2 = t2.Duration + + if err := opt.Options.FromBytes(buf.ReadAll()); err != nil { + return nil, err + } + return &opt, buf.FinError() +} diff --git a/dhcpv6/option_iapd_test.go b/dhcpv6/option_iapd_test.go new file mode 100644 index 0000000..babb5a7 --- /dev/null +++ b/dhcpv6/option_iapd_test.go @@ -0,0 +1,111 @@ +package dhcpv6 + +import ( + "net" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +func TestOptIAPDParseOptIAPD(t *testing.T) { + data := []byte{ + 1, 0, 0, 0, // IAID + 0, 0, 0, 1, // T1 + 0, 0, 0, 2, // T2 + 0, 26, 0, 25, // 26 = IAPrefix Option, 25 = length + 0xaa, 0xbb, 0xcc, 0xdd, // IAPrefix preferredLifetime + 0xee, 0xff, 0x00, 0x11, // IAPrefix validLifetime + 36, // IAPrefix prefixLength + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // IAPrefix ipv6Prefix + } + opt, err := ParseOptIAPD(data) + require.NoError(t, err) + require.Equal(t, OptionIAPD, opt.Code()) + require.Equal(t, [4]byte{1, 0, 0, 0}, opt.IaId) + require.Equal(t, time.Second, opt.T1) + require.Equal(t, 2*time.Second, opt.T2) +} + +func TestOptIAPDParseOptIAPDInvalidLength(t *testing.T) { + data := []byte{ + 1, 0, 0, 0, // IAID + 0, 0, 0, 1, // T1 + // truncated from here + } + _, err := ParseOptIAPD(data) + require.Error(t, err) +} + +func TestOptIAPDParseOptIAPDInvalidOptions(t *testing.T) { + data := []byte{ + 1, 0, 0, 0, // IAID + 0, 0, 0, 1, // T1 + 0, 0, 0, 2, // T2 + 0, 26, 0, 25, // 26 = IAPrefix Option, 25 = length + 0xaa, 0xbb, 0xcc, 0xdd, // IAPrefix preferredLifetime + 0xee, 0xff, 0x00, 0x11, // IAPrefix validLifetime + 36, // IAPrefix prefixLength + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // IAPrefix ipv6Prefix missing last byte + } + _, err := ParseOptIAPD(data) + require.Error(t, err) +} + +func TestOptIAPDToBytes(t *testing.T) { + oaddr := OptIAPrefix{} + oaddr.PreferredLifetime = 0xaabbccdd * time.Second + oaddr.ValidLifetime = 0xeeff0011 * time.Second + oaddr.SetPrefixLength(36) + oaddr.SetIPv6Prefix(net.IPv6loopback) + + opt := OptIAPD{} + opt.IaId = [4]byte{1, 2, 3, 4} + opt.T1 = 12345 * time.Second + opt.T2 = 54321 * time.Second + opt.Options = append(opt.Options, &oaddr) + + expected := []byte{ + 1, 2, 3, 4, // IA ID + 0, 0, 0x30, 0x39, // T1 = 12345 + 0, 0, 0xd4, 0x31, // T2 = 54321 + 0, 26, 0, 25, // 26 = IAPrefix Option, 25 = length + 0xaa, 0xbb, 0xcc, 0xdd, // IAPrefix preferredLifetime + 0xee, 0xff, 0x00, 0x11, // IAPrefix validLifetime + 36, // IAPrefix prefixLength + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // IAPrefix ipv6Prefix + } + require.Equal(t, expected, opt.ToBytes()) +} + +func TestOptIAPDString(t *testing.T) { + data := []byte{ + 1, 0, 0, 0, // IAID + 0, 0, 0, 1, // T1 + 0, 0, 0, 2, // T2 + 0, 26, 0, 25, // 26 = IAPrefix Option, 25 = length + 0xaa, 0xbb, 0xcc, 0xdd, // IAPrefix preferredLifetime + 0xee, 0xff, 0x00, 0x11, // IAPrefix validLifetime + 36, // IAPrefix prefixLength + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // IAPrefix ipv6Prefix + } + opt, err := ParseOptIAPD(data) + require.NoError(t, err) + + str := opt.String() + require.Contains( + t, str, + "IAID=[1 0 0 0]", + "String() should return the IAID", + ) + require.Contains( + t, str, + "t1=1s, t2=2s", + "String() should return the T1/T2 options", + ) + require.Contains( + t, str, + "options=[", + "String() should return a list of options", + ) +} diff --git a/dhcpv6/option_prefixdelegation.go b/dhcpv6/option_prefixdelegation.go deleted file mode 100644 index fe72936..0000000 --- a/dhcpv6/option_prefixdelegation.go +++ /dev/null @@ -1,72 +0,0 @@ -package dhcpv6 - -import ( - "fmt" - "time" - - "github.com/u-root/u-root/pkg/uio" -) - -// OptIAForPrefixDelegation implements the identity association for prefix -// delegation option defined by RFC 3633, Section 9. -type OptIAForPrefixDelegation struct { - IaId [4]byte - T1 time.Duration - T2 time.Duration - Options Options -} - -// Code returns the option code -func (op *OptIAForPrefixDelegation) Code() OptionCode { - return OptionIAPD -} - -// ToBytes serializes the option and returns it as a sequence of bytes -func (op *OptIAForPrefixDelegation) ToBytes() []byte { - buf := uio.NewBigEndianBuffer(nil) - buf.WriteBytes(op.IaId[:]) - - t1 := Duration{op.T1} - t1.Marshal(buf) - t2 := Duration{op.T2} - t2.Marshal(buf) - - buf.WriteBytes(op.Options.ToBytes()) - return buf.Data() -} - -// String returns a string representation of the OptIAForPrefixDelegation data -func (op *OptIAForPrefixDelegation) String() string { - return fmt.Sprintf("OptIAForPrefixDelegation{IAID=%v, t1=%v, t2=%v, options=%v}", - op.IaId, op.T1, op.T2, op.Options) -} - -// GetOneOption will get an option of the give type from the Options field, if -// it is present. It will return `nil` otherwise -func (op *OptIAForPrefixDelegation) GetOneOption(code OptionCode) Option { - return op.Options.GetOne(code) -} - -// DelOption will remove all the options that match a Option code. -func (op *OptIAForPrefixDelegation) DelOption(code OptionCode) { - op.Options.Del(code) -} - -// build an OptIAForPrefixDelegation structure from a sequence of bytes. -// The input data does not include option code and length bytes. -func ParseOptIAForPrefixDelegation(data []byte) (*OptIAForPrefixDelegation, error) { - var opt OptIAForPrefixDelegation - buf := uio.NewBigEndianBuffer(data) - buf.ReadBytes(opt.IaId[:]) - - var t1, t2 Duration - t1.Unmarshal(buf) - t2.Unmarshal(buf) - opt.T1 = t1.Duration - opt.T2 = t2.Duration - - if err := opt.Options.FromBytes(buf.ReadAll()); err != nil { - return nil, err - } - return &opt, buf.FinError() -} diff --git a/dhcpv6/option_prefixdelegation_test.go b/dhcpv6/option_prefixdelegation_test.go deleted file mode 100644 index 1fff283..0000000 --- a/dhcpv6/option_prefixdelegation_test.go +++ /dev/null @@ -1,164 +0,0 @@ -package dhcpv6 - -import ( - "net" - "testing" - "time" - - "github.com/stretchr/testify/require" -) - -func TestOptIAForPrefixDelegationParseOptIAForPrefixDelegation(t *testing.T) { - data := []byte{ - 1, 0, 0, 0, // IAID - 0, 0, 0, 1, // T1 - 0, 0, 0, 2, // T2 - 0, 26, 0, 25, // 26 = IAPrefix Option, 25 = length - 0xaa, 0xbb, 0xcc, 0xdd, // IAPrefix preferredLifetime - 0xee, 0xff, 0x00, 0x11, // IAPrefix validLifetime - 36, // IAPrefix prefixLength - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // IAPrefix ipv6Prefix - } - opt, err := ParseOptIAForPrefixDelegation(data) - require.NoError(t, err) - require.Equal(t, OptionIAPD, opt.Code()) - require.Equal(t, [4]byte{1, 0, 0, 0}, opt.IaId) - require.Equal(t, time.Second, opt.T1) - require.Equal(t, 2*time.Second, opt.T2) -} - -func TestOptIAForPrefixDelegationParseOptIAForPrefixDelegationInvalidLength(t *testing.T) { - data := []byte{ - 1, 0, 0, 0, // IAID - 0, 0, 0, 1, // T1 - // truncated from here - } - _, err := ParseOptIAForPrefixDelegation(data) - require.Error(t, err) -} - -func TestOptIAForPrefixDelegationParseOptIAForPrefixDelegationInvalidOptions(t *testing.T) { - data := []byte{ - 1, 0, 0, 0, // IAID - 0, 0, 0, 1, // T1 - 0, 0, 0, 2, // T2 - 0, 26, 0, 25, // 26 = IAPrefix Option, 25 = length - 0xaa, 0xbb, 0xcc, 0xdd, // IAPrefix preferredLifetime - 0xee, 0xff, 0x00, 0x11, // IAPrefix validLifetime - 36, // IAPrefix prefixLength - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // IAPrefix ipv6Prefix missing last byte - } - _, err := ParseOptIAForPrefixDelegation(data) - require.Error(t, err) -} - -func TestOptIAForPrefixDelegationGetOneOption(t *testing.T) { - buf := []byte{ - 0xaa, 0xbb, 0xcc, 0xdd, // preferredLifetime - 0xee, 0xff, 0x00, 0x11, // validLifetime - 36, // prefixLength - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // ipv6Prefix - } - oaddr, err := ParseOptIAPrefix(buf) - if err != nil { - t.Fatal(err) - } - opt := OptIAForPrefixDelegation{} - opt.Options = append(opt.Options, oaddr) - require.Equal(t, oaddr, opt.GetOneOption(OptionIAPrefix)) -} - -func TestOptIAForPrefixDelegationGetOneOptionMissingOpt(t *testing.T) { - buf := []byte{ - 0xaa, 0xbb, 0xcc, 0xdd, // preferredLifetime - 0xee, 0xff, 0x00, 0x11, // validLifetime - 36, // prefixLength - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // ipv6Prefix - } - oaddr, err := ParseOptIAPrefix(buf) - if err != nil { - t.Fatal(err) - } - opt := OptIAForPrefixDelegation{} - opt.Options = append(opt.Options, oaddr) - require.Equal(t, nil, opt.GetOneOption(OptionDNSRecursiveNameServer)) -} - -func TestOptIAForPrefixDelegationDelOption(t *testing.T) { - optiana1 := OptIAForPrefixDelegation{} - optiana2 := OptIAForPrefixDelegation{} - optiaaddr := OptIAPrefix{} - optsc := OptStatusCode{} - - optiana1.Options = append(optiana1.Options, &optsc) - optiana1.Options = append(optiana1.Options, &optiaaddr) - optiana1.Options = append(optiana1.Options, &optiaaddr) - optiana1.DelOption(OptionIAPrefix) - require.Equal(t, len(optiana1.Options), 1) - require.Equal(t, optiana1.Options[0], &optsc) - - optiana2.Options = append(optiana2.Options, &optiaaddr) - optiana2.Options = append(optiana2.Options, &optsc) - optiana2.Options = append(optiana2.Options, &optiaaddr) - optiana2.DelOption(OptionIAPrefix) - require.Equal(t, len(optiana2.Options), 1) - require.Equal(t, optiana2.Options[0], &optsc) -} - -func TestOptIAForPrefixDelegationToBytes(t *testing.T) { - oaddr := OptIAPrefix{} - oaddr.PreferredLifetime = 0xaabbccdd * time.Second - oaddr.ValidLifetime = 0xeeff0011 * time.Second - oaddr.SetPrefixLength(36) - oaddr.SetIPv6Prefix(net.IPv6loopback) - - opt := OptIAForPrefixDelegation{} - opt.IaId = [4]byte{1, 2, 3, 4} - opt.T1 = 12345 * time.Second - opt.T2 = 54321 * time.Second - opt.Options = append(opt.Options, &oaddr) - - expected := []byte{ - 1, 2, 3, 4, // IA ID - 0, 0, 0x30, 0x39, // T1 = 12345 - 0, 0, 0xd4, 0x31, // T2 = 54321 - 0, 26, 0, 25, // 26 = IAPrefix Option, 25 = length - 0xaa, 0xbb, 0xcc, 0xdd, // IAPrefix preferredLifetime - 0xee, 0xff, 0x00, 0x11, // IAPrefix validLifetime - 36, // IAPrefix prefixLength - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // IAPrefix ipv6Prefix - } - require.Equal(t, expected, opt.ToBytes()) -} - -func TestOptIAForPrefixDelegationString(t *testing.T) { - data := []byte{ - 1, 0, 0, 0, // IAID - 0, 0, 0, 1, // T1 - 0, 0, 0, 2, // T2 - 0, 26, 0, 25, // 26 = IAPrefix Option, 25 = length - 0xaa, 0xbb, 0xcc, 0xdd, // IAPrefix preferredLifetime - 0xee, 0xff, 0x00, 0x11, // IAPrefix validLifetime - 36, // IAPrefix prefixLength - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // IAPrefix ipv6Prefix - } - opt, err := ParseOptIAForPrefixDelegation(data) - require.NoError(t, err) - - str := opt.String() - require.Contains( - t, str, - "IAID=[1 0 0 0]", - "String() should return the IAID", - ) - require.Contains( - t, str, - "t1=1s, t2=2s", - "String() should return the T1/T2 options", - ) - require.Contains( - t, str, - "options=[", - "String() should return a list of options", - ) -} diff --git a/dhcpv6/options.go b/dhcpv6/options.go index 752ca2c..aefdfc8 100644 --- a/dhcpv6/options.go +++ b/dhcpv6/options.go @@ -70,7 +70,7 @@ func ParseOption(code OptionCode, optData []byte) (Option, error) { case OptionDomainSearchList: opt, err = parseOptDomainSearchList(optData) case OptionIAPD: - opt, err = ParseOptIAForPrefixDelegation(optData) + opt, err = ParseOptIAPD(optData) case OptionIAPrefix: opt, err = ParseOptIAPrefix(optData) case OptionRemoteID: -- cgit v1.2.3