package dhcpv4 import ( "errors" "fmt" "strings" ) // This option implements the User Class option // https://tools.ietf.org/html/rfc3004 // OptUserClass represents an option encapsulating User Classes. type OptUserClass struct { UserClasses [][]byte } // Code returns the option code func (op *OptUserClass) Code() OptionCode { return OptionUserClassInformation } // 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())} for _, uc := range op.UserClasses { buf = append(buf, byte(len(uc))) buf = append(buf, uc...) } return buf } // Length returns the option length func (op *OptUserClass) Length() int { ret := 0 for _, uc := range op.UserClasses { ret += 1 + len(uc) } return ret } func (op *OptUserClass) String() string { ucStrings := make([]string, len(op.UserClasses)) for _, uc := range op.UserClasses { ucStrings = append(ucStrings, string(uc)) } return fmt.Sprintf("OptUserClass{userclass=[%s]}", strings.Join(ucStrings, ", ")) } // ParseOptUserClass returns a new OptUserClass from a byte stream or // error if any func ParseOptUserClass(data []byte) (*OptUserClass, error) { opt := OptUserClass{} if len(data) < 4 { return nil, ErrShortByteStream } code := OptionCode(data[0]) if code != OptionUserClassInformation { return nil, fmt.Errorf("expected code %v, got %v", OptionUserClassInformation, code) } totalLength := int(data[1]) data = data[2:] if len(data) < totalLength { return nil, fmt.Errorf("ParseOptUserClass: short data: length is %d but got %d bytes", totalLength, len(data)) } for i := 0; i < totalLength; { ucLen := int(data[i]) if ucLen == 0 { return nil, errors.New("User Class value has invalid length of 0") } base := i + 1 if len(data) < base+ucLen { return nil, fmt.Errorf("ParseOptUserClass: short data: %d bytes; want: %d", len(data), base+ucLen) } opt.UserClasses = append(opt.UserClasses, data[base:base+ucLen]) i += base + ucLen } if len(opt.UserClasses) < 1 { return nil, errors.New("ParseOptUserClass: at least one user class is required") } return &opt, nil }