From c063ce388b0632ce267a0ff9af24e186504ebcaa Mon Sep 17 00:00:00 2001 From: Chris Koch Date: Fri, 24 Feb 2023 21:39:24 -0800 Subject: New tests for ClientID & ServerID Signed-off-by: Chris Koch --- dhcpv6/duid.go | 17 ++++- dhcpv6/option_clientid_test.go | 160 +++++++++++++++++++++------------------- dhcpv6/option_serverid_test.go | 164 ++++++++++++++++++++++------------------- dhcpv6/options.go | 4 +- go.mod | 3 +- go.sum | 5 ++ 6 files changed, 198 insertions(+), 155 deletions(-) diff --git a/dhcpv6/duid.go b/dhcpv6/duid.go index 027c6b0..0470f9f 100644 --- a/dhcpv6/duid.go +++ b/dhcpv6/duid.go @@ -61,6 +61,9 @@ func (d *DUIDLLT) Equal(e DUID) bool { if !ok { return false } + if d == nil { + return d == ellt + } return d.HWType == ellt.HWType && d.Time == ellt.Time && bytes.Equal(d.LinkLayerAddr, ellt.LinkLayerAddr) } @@ -103,6 +106,9 @@ func (d *DUIDLL) Equal(e DUID) bool { if !ok { return false } + if d == nil { + return d == ell + } return d.HWType == ell.HWType && bytes.Equal(d.LinkLayerAddr, ell.LinkLayerAddr) } @@ -145,6 +151,9 @@ func (d *DUIDEN) Equal(e DUID) bool { if !ok { return false } + if d == nil { + return d == en + } return d.EnterpriseNumber == en.EnterpriseNumber && bytes.Equal(d.EnterpriseIdentifier, en.EnterpriseIdentifier) } @@ -187,6 +196,9 @@ func (d *DUIDUUID) Equal(e DUID) bool { if !ok { return false } + if d == nil { + return d == euuid + } return d.UUID == euuid.UUID } @@ -226,6 +238,9 @@ func (d *DUIDOpaque) Equal(e DUID) bool { if !ok { return false } + if d == nil { + return d == eopaque + } return d.Type == eopaque.Type && bytes.Equal(d.Data, eopaque.Data) } @@ -259,7 +274,7 @@ func (d DUIDType) String() string { func DUIDFromBytes(data []byte) (DUID, error) { buf := uio.NewBigEndianBuffer(data) if !buf.Has(2) { - return nil, fmt.Errorf("buffer too short: have %d bytes, want 2 bytes", buf.Len()) + return nil, fmt.Errorf("%w: have %d bytes, want 2 bytes", uio.ErrBufferTooShort, buf.Len()) } typ := DUIDType(buf.Read16()) diff --git a/dhcpv6/option_clientid_test.go b/dhcpv6/option_clientid_test.go index dd637ae..a80403a 100644 --- a/dhcpv6/option_clientid_test.go +++ b/dhcpv6/option_clientid_test.go @@ -1,78 +1,108 @@ package dhcpv6 import ( + "errors" + "fmt" "net" "reflect" "testing" + "github.com/google/go-cmp/cmp" "github.com/insomniacslk/dhcp/iana" "github.com/stretchr/testify/require" + "github.com/u-root/uio/uio" ) -func TestParseMessageOptionsWithClientID(t *testing.T) { - buf := []byte{ - 0, 1, // Client ID option - 0, 10, // length - 0, 3, // DUID_LL - 0, 1, // hwtype ethernet - 0, 1, 2, 3, 4, 5, // HW addr - } - - want := &DUIDLL{HWType: iana.HWTypeEthernet, LinkLayerAddr: net.HardwareAddr{0, 1, 2, 3, 4, 5}} - var mo MessageOptions - if err := mo.FromBytes(buf); err != nil { - t.Errorf("FromBytes = %v", err) - } else if got := mo.ClientID(); !reflect.DeepEqual(got, want) { - t.Errorf("ClientID = %v, want %v", got, want) +func TestClientIDParseAndGetter(t *testing.T) { + for i, tt := range []struct { + buf []byte + err error + want DUID + }{ + { + buf: []byte{ + 0, 1, // Client ID option + 0, 10, // length + 0, 3, // DUID_LL + 0, 1, // hwtype ethernet + 0, 1, 2, 3, 4, 5, // HW addr + }, + want: &DUIDLL{HWType: iana.HWTypeEthernet, LinkLayerAddr: net.HardwareAddr{0, 1, 2, 3, 4, 5}}, + }, + { + buf: nil, + want: nil, + }, + { + buf: []byte{0, 1, 0, 1, 0}, + want: nil, + err: uio.ErrBufferTooShort, + }, + } { + t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { + var mo MessageOptions + if err := mo.FromBytes(tt.buf); !errors.Is(err, tt.err) { + t.Errorf("FromBytes = %v, want %v", err, tt.err) + } + if got := mo.ClientID(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("ClientID = %v, want %v", got, tt.want) + } + }) } } -func TestParseOptClientID(t *testing.T) { - data := []byte{ - 0, 3, // DUID_LL - 0, 1, // hwtype ethernet - 0, 1, 2, 3, 4, 5, // hw addr - } - var opt optClientID - err := opt.FromBytes(data) - require.NoError(t, err) - want := OptClientID( - &DUIDLL{ - HWType: iana.HWTypeEthernet, - LinkLayerAddr: net.HardwareAddr([]byte{0, 1, 2, 3, 4, 5}), +func TestClientID(t *testing.T) { + for i, tt := range []struct { + buf []byte + want optClientID + err error + }{ + { + buf: []byte{ + 0, 3, // DUID_LL + 0, 1, // hwtype ethernet + 0, 1, 2, 3, 4, 5, // hw addr + }, + want: optClientID{ + &DUIDLL{ + HWType: iana.HWTypeEthernet, + LinkLayerAddr: net.HardwareAddr([]byte{0, 1, 2, 3, 4, 5}), + }, + }, }, - ) - require.Equal(t, want, &opt) -} - -func TestOptClientIdToBytes(t *testing.T) { - opt := OptClientID( - &DUIDLL{ - HWType: iana.HWTypeEthernet, - LinkLayerAddr: net.HardwareAddr([]byte{5, 4, 3, 2, 1, 0}), + { + buf: []byte{0}, + err: uio.ErrBufferTooShort, }, - ) - expected := []byte{ - 0, 3, // DUID_LL - 0, 1, // hwtype ethernet - 5, 4, 3, 2, 1, 0, // hw addr - } - require.Equal(t, expected, opt.ToBytes()) -} + { + buf: []byte{0, 3, 0}, + err: uio.ErrBufferTooShort, + }, + { + buf: nil, + err: uio.ErrBufferTooShort, + }, + } { + t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { + var opt optClientID + if err := opt.FromBytes(tt.buf); !errors.Is(err, tt.err) { + t.Errorf("FromBytes = %v, want %v", err, tt.err) + } + if tt.err == nil { + if !reflect.DeepEqual(tt.want, opt) { + t.Errorf("FromBytes = %v, want %v", opt, tt.want) + } -func TestOptClientIdDecodeEncode(t *testing.T) { - data := []byte{ - 0, 3, // DUID_LL - 0, 1, // hwtype ethernet - 5, 4, 3, 2, 1, 0, // hw addr + out := tt.want.ToBytes() + if diff := cmp.Diff(tt.buf, out); diff != "" { + t.Errorf("ToBytes mismatch: (-want, +got):\n%s", diff) + } + } + }) } - var opt optClientID - err := opt.FromBytes(data) - require.NoError(t, err) - require.Equal(t, data, opt.ToBytes()) } -func TestOptionClientId(t *testing.T) { +func TestOptionClientIDString(t *testing.T) { opt := OptClientID( &DUIDLL{ HWType: iana.HWTypeEthernet, @@ -87,23 +117,3 @@ func TestOptionClientId(t *testing.T) { "String() should contain the correct cid output", ) } - -func TestOptClientIdparseOptClientIDBogusDUID(t *testing.T) { - data := []byte{ - 0, 4, // DUID_UUID - 1, 2, 3, 4, 5, 6, 7, 8, 9, // a UUID should be 18 bytes not 17 - 10, 11, 12, 13, 14, 15, 16, 17, - } - var opt optClientID - err := opt.FromBytes(data) - require.Error(t, err, "A truncated OptClientId DUID should return an error") -} - -func TestOptClientIdparseOptClientIDInvalidTooShort(t *testing.T) { - data := []byte{ - 0, // truncated: DUIDs are at least 2 bytes - } - var opt optClientID - err := opt.FromBytes(data) - require.Error(t, err, "A truncated OptClientId should return an error") -} diff --git a/dhcpv6/option_serverid_test.go b/dhcpv6/option_serverid_test.go index b0250c2..bb4a928 100644 --- a/dhcpv6/option_serverid_test.go +++ b/dhcpv6/option_serverid_test.go @@ -1,82 +1,112 @@ package dhcpv6 import ( + "errors" + "fmt" "net" "reflect" "testing" + "github.com/google/go-cmp/cmp" "github.com/insomniacslk/dhcp/iana" "github.com/stretchr/testify/require" + "github.com/u-root/uio/uio" ) -func TestParseMessageOptionsWithServerID(t *testing.T) { - buf := []byte{ - 0, 2, // Server ID option - 0, 10, // length - 0, 3, // DUID_LL - 0, 1, // hwtype ethernet - 0, 1, 2, 3, 4, 5, // HW addr - } - - want := &DUIDLL{HWType: iana.HWTypeEthernet, LinkLayerAddr: net.HardwareAddr{0, 1, 2, 3, 4, 5}} - var mo MessageOptions - if err := mo.FromBytes(buf); err != nil { - t.Errorf("FromBytes = %v", err) - } else if got := mo.ServerID(); !reflect.DeepEqual(got, want) { - t.Errorf("ServerID = %v, want %v", got, want) +func TestServerIDParseAndGetter(t *testing.T) { + for i, tt := range []struct { + buf []byte + err error + want DUID + }{ + { + buf: []byte{ + 0, 2, // Server ID option + 0, 10, // length + 0, 3, // DUID_LL + 0, 1, // hwtype ethernet + 0, 1, 2, 3, 4, 5, // HW addr + }, + want: &DUIDLL{HWType: iana.HWTypeEthernet, LinkLayerAddr: net.HardwareAddr{0, 1, 2, 3, 4, 5}}, + }, + { + buf: nil, + want: nil, + }, + { + buf: []byte{0, 1, 0, 1, 0}, + want: nil, + err: uio.ErrBufferTooShort, + }, + } { + t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { + var mo MessageOptions + if err := mo.FromBytes(tt.buf); !errors.Is(err, tt.err) { + t.Errorf("FromBytes = %v, want %v", err, tt.err) + } + if got := mo.ServerID(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("ServerID = %v, want %v", got, tt.want) + } + }) } } -func TestParseOptServerID(t *testing.T) { - data := []byte{ - 0, 3, // DUID_LL - 0, 1, // hwtype ethernet - 0, 1, 2, 3, 4, 5, // hw addr - } - var opt optServerID - err := opt.FromBytes(data) - require.NoError(t, err) - want := OptServerID( - &DUIDLL{ - HWType: iana.HWTypeEthernet, - LinkLayerAddr: net.HardwareAddr{0, 1, 2, 3, 4, 5}, +func TestServerID(t *testing.T) { + for i, tt := range []struct { + buf []byte + want optServerID + err error + }{ + { + buf: []byte{ + 0, 3, // DUID_LL + 0, 1, // hwtype ethernet + 0, 1, 2, 3, 4, 5, // hw addr + }, + want: optServerID{ + &DUIDLL{ + HWType: iana.HWTypeEthernet, + LinkLayerAddr: net.HardwareAddr([]byte{0, 1, 2, 3, 4, 5}), + }, + }, }, - ) - require.Equal(t, &opt, want) -} - -func TestOptServerIdToBytes(t *testing.T) { - opt := OptServerID( - &DUIDLL{ - HWType: iana.HWTypeEthernet, - LinkLayerAddr: net.HardwareAddr{5, 4, 3, 2, 1, 0}, + { + buf: []byte{0}, + err: uio.ErrBufferTooShort, }, - ) - expected := []byte{ - 0, 3, // DUID_LL - 0, 1, // hwtype ethernet - 5, 4, 3, 2, 1, 0, // hw addr - } - require.Equal(t, expected, opt.ToBytes()) -} + { + buf: []byte{0, 3, 0}, + err: uio.ErrBufferTooShort, + }, + { + buf: nil, + err: uio.ErrBufferTooShort, + }, + } { + t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { + var opt optServerID + if err := opt.FromBytes(tt.buf); !errors.Is(err, tt.err) { + t.Errorf("FromBytes = %v, want %v", err, tt.err) + } + if tt.err == nil { + if !reflect.DeepEqual(tt.want, opt) { + t.Errorf("FromBytes = %v, want %v", opt, tt.want) + } -func TestOptServerIdDecodeEncode(t *testing.T) { - data := []byte{ - 0, 3, // DUID_LL - 0, 1, // hwtype ethernet - 5, 4, 3, 2, 1, 0, // hw addr + out := tt.want.ToBytes() + if diff := cmp.Diff(tt.buf, out); diff != "" { + t.Errorf("ToBytes mismatch: (-want, +got):\n%s", diff) + } + } + }) } - var opt optServerID - err := opt.FromBytes(data) - require.NoError(t, err) - require.Equal(t, data, opt.ToBytes()) } -func TestOptionServerId(t *testing.T) { +func TestOptionServerIDString(t *testing.T) { opt := OptServerID( &DUIDLL{ HWType: iana.HWTypeEthernet, - LinkLayerAddr: net.HardwareAddr{0xde, 0xad, 0, 0, 0xbe, 0xef}, + LinkLayerAddr: net.HardwareAddr([]byte{0xde, 0xad, 0, 0, 0xbe, 0xef}), }, ) require.Equal(t, OptionServerID, opt.Code()) @@ -84,26 +114,6 @@ func TestOptionServerId(t *testing.T) { t, opt.String(), "Server ID: DUID-LL{HWType=Ethernet HWAddr=de:ad:00:00:be:ef}", - "String() should contain the correct sid output", + "String() should contain the correct cid output", ) } - -func TestOptServerIdparseOptServerIDBogusDUID(t *testing.T) { - data := []byte{ - 0, 4, // DUID_UUID - 1, 2, 3, 4, 5, 6, 7, 8, 9, // a UUID should be 18 bytes not 17 - 10, 11, 12, 13, 14, 15, 16, 17, - } - var opt optServerID - err := opt.FromBytes(data) - require.Error(t, err, "A truncated OptServerId DUID should return an error") -} - -func TestOptServerIdparseOptServerIDInvalidTooShort(t *testing.T) { - data := []byte{ - 0, // truncated: DUIDs are at least 2 bytes - } - var opt optServerID - err := opt.FromBytes(data) - require.Error(t, err, "A truncated OptServerId should return an error") -} diff --git a/dhcpv6/options.go b/dhcpv6/options.go index 6a55082..552abd0 100644 --- a/dhcpv6/options.go +++ b/dhcpv6/options.go @@ -224,7 +224,9 @@ type OptionParser func(code OptionCode, data []byte) (Option, error) // FromBytesWithParser parses Options from byte sequences using the parsing // function that is passed in as a paremeter func (o *Options) FromBytesWithParser(data []byte, parser OptionParser) error { - *o = make(Options, 0, 10) + if *o == nil { + *o = make(Options, 0, 10) + } if len(data) == 0 { // no options, no party return nil diff --git a/go.mod b/go.mod index e484f33..90b005a 100644 --- a/go.mod +++ b/go.mod @@ -4,13 +4,14 @@ go 1.18 require ( github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72 + github.com/google/go-cmp v0.5.9 github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7 github.com/mdlayher/netlink v1.1.1 github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065 github.com/stretchr/testify v1.6.1 - github.com/u-root/uio v0.0.0-20230215032506-9aa6f7e2d72c + github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 golang.org/x/net v0.0.0-20201110031124-69a78807bb2b golang.org/x/sys v0.5.0 ) diff --git a/go.sum b/go.sum index 52bea58..43f0b87 100644 --- a/go.sum +++ b/go.sum @@ -8,6 +8,8 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 h1:/jC7qQFrv8CrSJVmaolDVOxTfS9kc36uB6H40kdbQq8= @@ -46,6 +48,8 @@ github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/u-root/uio v0.0.0-20230215032506-9aa6f7e2d72c h1:PHoGTnweZP+KIg/8Zc6+iOesrIF5yHkpb4GBDxHm7yE= github.com/u-root/uio v0.0.0-20230215032506-9aa6f7e2d72c/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264= +github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 h1:tHNk7XK9GkmKUR6Gh8gVBKXc2MVSZ4G/NnWLtzw4gNA= +github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -77,6 +81,7 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -- cgit v1.2.3