diff options
Diffstat (limited to 'dhcpv4/option_userclass.go')
-rw-r--r-- | dhcpv4/option_userclass.go | 38 |
1 files changed, 33 insertions, 5 deletions
diff --git a/dhcpv4/option_userclass.go b/dhcpv4/option_userclass.go index 1505dbb..d6ddabc 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 { + 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 { + return len(op.UserClasses[0]) + } for _, uc := range op.UserClasses { ret += 1 + len(uc) } @@ -39,11 +46,15 @@ func (op *OptUserClass) Length() int { } func (op *OptUserClass) String() string { - ucStrings := make([]string, len(op.UserClasses)) - for _, uc := range op.UserClasses { - ucStrings = append(ucStrings, string(uc)) + ucStrings := make([]string, 0, len(op.UserClasses)) + 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 @@ -51,7 +62,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]) @@ -66,6 +77,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 + } + opt.Rfc3004 = true for i := 0; i < totalLength; { ucLen := int(data[i]) if ucLen == 0 { |