From 7319b8f8a1a601b5e69c5bcaa33914c0f85b92e6 Mon Sep 17 00:00:00 2001 From: Sean Karlage Date: Sun, 29 Jul 2018 17:54:30 -0700 Subject: DHCPv6: Rename Option constants to CamelCase To appease linters --- dhcpv4/option_userclass_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'dhcpv4/option_userclass_test.go') diff --git a/dhcpv4/option_userclass_test.go b/dhcpv4/option_userclass_test.go index 5b71ea5..492cabd 100644 --- a/dhcpv4/option_userclass_test.go +++ b/dhcpv4/option_userclass_test.go @@ -12,7 +12,7 @@ func TestOptUserClassToBytes(t *testing.T) { } data := opt.ToBytes() expected := []byte{ - 77, // OPTION_USER_CLASS + 77, // OptionUserClass 10, // length 9, 'l', 'i', 'n', 'u', 'x', 'b', 'o', 'o', 't', } @@ -57,7 +57,7 @@ func TestOptUserClassToBytesMultiple(t *testing.T) { } data := opt.ToBytes() expected := []byte{ - 77, // OPTION_USER_CLASS + 77, // OptionUserClass 15, // length 9, 'l', 'i', 'n', 'u', 'x', 'b', 'o', 'o', 't', 4, 't', 'e', 's', 't', -- cgit v1.2.3 From 40474d58d9e4302b97e535e199e79ad1c63ade06 Mon Sep 17 00:00:00 2001 From: Owen Mooney Date: Wed, 1 Aug 2018 20:42:28 +0100 Subject: Parse non-RFC compliant user class (#114) --- dhcpv4/option_userclass.go | 17 +++++++++++++++++ dhcpv4/option_userclass_test.go | 28 ++++++++++++++++++++-------- 2 files changed, 37 insertions(+), 8 deletions(-) (limited to 'dhcpv4/option_userclass_test.go') diff --git a/dhcpv4/option_userclass.go b/dhcpv4/option_userclass.go index 307a128..fc088fa 100644 --- a/dhcpv4/option_userclass.go +++ b/dhcpv4/option_userclass.go @@ -66,6 +66,23 @@ func ParseOptUserClass(data []byte) (*OptUserClass, error) { totalLength, len(data)) } + // Check if option is Microsoft style instead of RFC compliant, issue #113 + + // User-class options are, according to RFC3004, supposed to contain a set + // of strings each with length UC_Len_i. Here we check that this is so, + // by seeing if all the UC_Len_i lengths are consistent with the overall + // option length. If the lengths don't add up, we assume that the option + // is a single string and non RFC3004 compliant + var counting int + for counting < totalLength { + // UC_Len_i does not include itself so add 1 + counting += int(data[counting]) + 1 + } + if counting != totalLength { + opt.UserClasses = append(opt.UserClasses, data[:totalLength]) + return &opt, nil + } + for i := 0; i < totalLength; { ucLen := int(data[i]) if ucLen == 0 { diff --git a/dhcpv4/option_userclass_test.go b/dhcpv4/option_userclass_test.go index 492cabd..02b6f94 100644 --- a/dhcpv4/option_userclass_test.go +++ b/dhcpv4/option_userclass_test.go @@ -38,6 +38,26 @@ func TestParseOptUserClassNone(t *testing.T) { require.Error(t, err) } +func TestParseOptUserClassMicrosoft(t *testing.T) { + expected := []byte{ + 77, 9, 'l', 'i', 'n', 'u', 'x', 'b', 'o', 'o', 't', + } + opt, err := ParseOptUserClass(expected) + require.NoError(t, err) + require.Equal(t, 1, len(opt.UserClasses)) + require.Equal(t, []byte("linuxboot"), opt.UserClasses[0]) +} + +func TestParseOptUserClassMicrosoftLongerThanLength(t *testing.T) { + expected := []byte{ + 77, 9, 'l', 'i', 'n', 'u', 'x', 'b', 'o', 'o', 't', 'X', + } + opt, err := ParseOptUserClass(expected) + require.NoError(t, err) + require.Equal(t, 1, len(opt.UserClasses)) + require.Equal(t, []byte("linuxboot"), opt.UserClasses[0]) +} + func TestParseOptUserClass(t *testing.T) { expected := []byte{ 77, 10, 9, 'l', 'i', 'n', 'u', 'x', 'b', 'o', 'o', 't', @@ -75,14 +95,6 @@ func TestParseOptUserClassLongerThanLength(t *testing.T) { require.Equal(t, []byte("linuxboot"), opt.UserClasses[0]) } -func TestParseOptUserClassShorterThanLength(t *testing.T) { - expected := []byte{ - 77, 10, 10, 'l', 'i', 'n', 'u', 'x', 'b', 'o', 'o', 't', - } - _, err := ParseOptUserClass(expected) - require.Error(t, err) -} - func TestParseOptUserClassShorterTotalLength(t *testing.T) { expected := []byte{ 77, 11, 10, 'l', 'i', 'n', 'u', 'x', 'b', 'o', 'o', 't', -- cgit v1.2.3 From 5fd3f4fea8d73e29d931c0fabb4179b9e98ad275 Mon Sep 17 00:00:00 2001 From: Pablo Mazzini Date: Thu, 2 Aug 2018 11:01:48 +0200 Subject: fix OptUserClass --- dhcpv4/option_userclass.go | 9 ++++++++- dhcpv4/option_userclass_test.go | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) (limited to 'dhcpv4/option_userclass_test.go') diff --git a/dhcpv4/option_userclass.go b/dhcpv4/option_userclass.go index fc088fa..f7e4d7f 100644 --- a/dhcpv4/option_userclass.go +++ b/dhcpv4/option_userclass.go @@ -12,6 +12,7 @@ import ( // OptUserClass represents an option encapsulating User Classes. type OptUserClass struct { UserClasses [][]byte + Rfc3004 bool } // Code returns the option code @@ -22,6 +23,9 @@ func (op *OptUserClass) Code() OptionCode { // ToBytes serializes the option and returns it as a sequence of bytes func (op *OptUserClass) ToBytes() []byte { buf := []byte{byte(op.Code()), byte(op.Length())} + if !op.Rfc3004 && len(op.UserClasses) == 1 { + return append(buf, op.UserClasses[0]...) + } for _, uc := range op.UserClasses { buf = append(buf, byte(len(uc))) buf = append(buf, uc...) @@ -32,6 +36,9 @@ func (op *OptUserClass) ToBytes() []byte { // Length returns the option length func (op *OptUserClass) Length() int { ret := 0 + if !op.Rfc3004 && len(op.UserClasses) == 1 { + return len(op.UserClasses[0]) + } for _, uc := range op.UserClasses { ret += 1 + len(uc) } @@ -82,7 +89,7 @@ func ParseOptUserClass(data []byte) (*OptUserClass, error) { opt.UserClasses = append(opt.UserClasses, data[:totalLength]) return &opt, nil } - + opt.Rfc3004 = true for i := 0; i < totalLength; { ucLen := int(data[i]) if ucLen == 0 { diff --git a/dhcpv4/option_userclass_test.go b/dhcpv4/option_userclass_test.go index 02b6f94..0e74ee1 100644 --- a/dhcpv4/option_userclass_test.go +++ b/dhcpv4/option_userclass_test.go @@ -9,6 +9,7 @@ import ( func TestOptUserClassToBytes(t *testing.T) { opt := OptUserClass{ UserClasses: [][]byte{[]byte("linuxboot")}, + Rfc3004: true, } data := opt.ToBytes() expected := []byte{ @@ -19,6 +20,19 @@ func TestOptUserClassToBytes(t *testing.T) { require.Equal(t, expected, data) } +func TestOptUserClassMicrosoftToBytes(t *testing.T) { + opt := OptUserClass{ + UserClasses: [][]byte{[]byte("linuxboot")}, + } + data := opt.ToBytes() + expected := []byte{ + 77, // OptionUserClass + 9, // length + 'l', 'i', 'n', 'u', 'x', 'b', 'o', 'o', 't', + } + require.Equal(t, expected, data) +} + func TestParseOptUserClassMultiple(t *testing.T) { expected := []byte{ 77, 15, -- cgit v1.2.3 From 4ceb1c8174876a7564bca419ab971cd63c10327f Mon Sep 17 00:00:00 2001 From: Pablo Mazzini Date: Thu, 2 Aug 2018 11:13:54 +0200 Subject: OptUserClass: fix short length --- dhcpv4/option_userclass.go | 2 +- dhcpv4/option_userclass_test.go | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'dhcpv4/option_userclass_test.go') diff --git a/dhcpv4/option_userclass.go b/dhcpv4/option_userclass.go index f7e4d7f..f8a081f 100644 --- a/dhcpv4/option_userclass.go +++ b/dhcpv4/option_userclass.go @@ -58,7 +58,7 @@ func (op *OptUserClass) String() string { func ParseOptUserClass(data []byte) (*OptUserClass, error) { opt := OptUserClass{} - if len(data) < 4 { + if len(data) < 3 { return nil, ErrShortByteStream } code := OptionCode(data[0]) diff --git a/dhcpv4/option_userclass_test.go b/dhcpv4/option_userclass_test.go index 0e74ee1..72cf131 100644 --- a/dhcpv4/option_userclass_test.go +++ b/dhcpv4/option_userclass_test.go @@ -62,6 +62,16 @@ func TestParseOptUserClassMicrosoft(t *testing.T) { require.Equal(t, []byte("linuxboot"), opt.UserClasses[0]) } +func TestParseOptUserClassMicrosoftShort(t *testing.T) { + expected := []byte{ + 77, 1, 'l', + } + opt, err := ParseOptUserClass(expected) + require.NoError(t, err) + require.Equal(t, 1, len(opt.UserClasses)) + require.Equal(t, []byte("l"), opt.UserClasses[0]) +} + func TestParseOptUserClassMicrosoftLongerThanLength(t *testing.T) { expected := []byte{ 77, 9, 'l', 'i', 'n', 'u', 'x', 'b', 'o', 'o', 't', 'X', -- cgit v1.2.3 From 5e00177fe0c35379c9e83da496d6527d932854ae Mon Sep 17 00:00:00 2001 From: Pablo Mazzini Date: Thu, 2 Aug 2018 18:24:24 +0200 Subject: OptUserClass: use only the flag as authoritative --- dhcpv4/dhcpv4_test.go | 4 ++-- dhcpv4/modifiers_test.go | 4 ++-- dhcpv4/option_userclass.go | 14 +++++++++----- dhcpv4/option_userclass_test.go | 1 + 4 files changed, 14 insertions(+), 9 deletions(-) (limited to 'dhcpv4/option_userclass_test.go') diff --git a/dhcpv4/dhcpv4_test.go b/dhcpv4/dhcpv4_test.go index 7e5f083..217c801 100644 --- a/dhcpv4/dhcpv4_test.go +++ b/dhcpv4/dhcpv4_test.go @@ -363,7 +363,7 @@ func TestDHCPv4RequestFromOfferWithModifier(t *testing.T) { require.NoError(t, err) require.NotEqual(t, (*MessageType)(nil), *req.MessageType()) require.Equal(t, MessageTypeRequest, *req.MessageType()) - require.Equal(t, "OptUserClass{userclass=[linuxboot]}", req.options[3].String()) + require.Equal(t, "User Class Information -> linuxboot", req.options[3].String()) } func TestNewReplyFromRequest(t *testing.T) { @@ -385,7 +385,7 @@ func TestNewReplyFromRequestWithModifier(t *testing.T) { require.NoError(t, err) require.Equal(t, discover.TransactionID(), reply.TransactionID()) require.Equal(t, discover.GatewayIPAddr(), reply.GatewayIPAddr()) - require.Equal(t, "OptUserClass{userclass=[linuxboot]}", reply.options[0].String()) + require.Equal(t, "User Class Information -> linuxboot", reply.options[0].String()) } func TestDHCPv4MessageTypeNil(t *testing.T) { diff --git a/dhcpv4/modifiers_test.go b/dhcpv4/modifiers_test.go index 415a4ea..2e249ee 100644 --- a/dhcpv4/modifiers_test.go +++ b/dhcpv4/modifiers_test.go @@ -10,5 +10,5 @@ func TestUserClassModifier(t *testing.T) { d, _ := New() userClass := WithUserClass([]byte("linuxboot")) d = userClass(d) - require.Equal(t, "OptUserClass{userclass=[linuxboot]}", d.options[0].String()) -} \ No newline at end of file + require.Equal(t, "User Class Information -> linuxboot", d.options[0].String()) +} diff --git a/dhcpv4/option_userclass.go b/dhcpv4/option_userclass.go index f8a081f..d6ddabc 100644 --- a/dhcpv4/option_userclass.go +++ b/dhcpv4/option_userclass.go @@ -23,7 +23,7 @@ func (op *OptUserClass) Code() OptionCode { // ToBytes serializes the option and returns it as a sequence of bytes func (op *OptUserClass) ToBytes() []byte { buf := []byte{byte(op.Code()), byte(op.Length())} - if !op.Rfc3004 && len(op.UserClasses) == 1 { + if !op.Rfc3004 { return append(buf, op.UserClasses[0]...) } for _, uc := range op.UserClasses { @@ -36,7 +36,7 @@ func (op *OptUserClass) ToBytes() []byte { // Length returns the option length func (op *OptUserClass) Length() int { ret := 0 - if !op.Rfc3004 && len(op.UserClasses) == 1 { + if !op.Rfc3004 { return len(op.UserClasses[0]) } for _, uc := range op.UserClasses { @@ -47,10 +47,14 @@ func (op *OptUserClass) Length() int { func (op *OptUserClass) String() string { ucStrings := make([]string, 0, len(op.UserClasses)) - for _, uc := range op.UserClasses { - ucStrings = append(ucStrings, string(uc)) + if !op.Rfc3004 { + ucStrings = append(ucStrings, string(op.UserClasses[0])) + } else { + for _, uc := range op.UserClasses { + ucStrings = append(ucStrings, string(uc)) + } } - return fmt.Sprintf("OptUserClass{userclass=[%s]}", strings.Join(ucStrings, ", ")) + return fmt.Sprintf("User Class Information -> %v", strings.Join(ucStrings, ", ")) } // ParseOptUserClass returns a new OptUserClass from a byte stream or diff --git a/dhcpv4/option_userclass_test.go b/dhcpv4/option_userclass_test.go index 72cf131..f6039df 100644 --- a/dhcpv4/option_userclass_test.go +++ b/dhcpv4/option_userclass_test.go @@ -98,6 +98,7 @@ func TestOptUserClassToBytesMultiple(t *testing.T) { []byte("linuxboot"), []byte("test"), }, + Rfc3004: true, } data := opt.ToBytes() expected := []byte{ -- cgit v1.2.3