diff options
-rw-r--r-- | dhcpv4/option_archtype.go | 42 | ||||
-rw-r--r-- | dhcpv4/option_archtype_test.go | 9 | ||||
-rw-r--r-- | dhcpv6/dhcpv6.go | 10 | ||||
-rw-r--r-- | dhcpv6/dhcpv6_test.go | 4 | ||||
-rw-r--r-- | dhcpv6/modifiers.go | 6 | ||||
-rw-r--r-- | dhcpv6/option_archtype.go | 62 | ||||
-rw-r--r-- | dhcpv6/option_archtype_test.go | 5 | ||||
-rw-r--r-- | iana/archtype.go | 41 |
8 files changed, 88 insertions, 91 deletions
diff --git a/dhcpv4/option_archtype.go b/dhcpv4/option_archtype.go index 16ca98d..8eafc55 100644 --- a/dhcpv4/option_archtype.go +++ b/dhcpv4/option_archtype.go @@ -6,43 +6,14 @@ package dhcpv4 import ( "encoding/binary" "fmt" -) - -//ArchType encodes an architecture type in an uint16 -type ArchType uint16 -// see rfc4578 -const ( - INTEL_X86PC ArchType = 0 - NEC_PC98 ArchType = 1 - EFI_ITANIUM ArchType = 2 - DEC_ALPHA ArchType = 3 - ARC_X86 ArchType = 4 - INTEL_LEAN_CLIENT ArchType = 5 - EFI_IA32 ArchType = 6 - EFI_BC ArchType = 7 - EFI_XSCALE ArchType = 8 - EFI_X86_64 ArchType = 9 + "github.com/insomniacslk/dhcp/iana" ) -// ArchTypeToStringMap maps an ArchType to a mnemonic name -var ArchTypeToStringMap = map[ArchType]string{ - INTEL_X86PC: "Intel x86PC", - NEC_PC98: "NEC/PC98", - EFI_ITANIUM: "EFI Itanium", - DEC_ALPHA: "DEC Alpha", - ARC_X86: "Arc x86", - INTEL_LEAN_CLIENT: "Intel Lean Client", - EFI_IA32: "EFI IA32", - EFI_BC: "EFI BC", - EFI_XSCALE: "EFI Xscale", - EFI_X86_64: "EFI x86-64", -} - // OptClientArchType represents an option encapsulating the Client System // Architecture Type option Definition. type OptClientArchType struct { - ArchTypes []ArchType + ArchTypes []iana.ArchType } // Code returns the option code. @@ -71,10 +42,7 @@ func (o *OptClientArchType) Length() int { func (o *OptClientArchType) String() string { var archTypes string for idx, at := range o.ArchTypes { - name, ok := ArchTypeToStringMap[at] - if !ok { - name = "Unknown" - } + name := iana.ArchTypeToString(at) archTypes += name if idx < len(o.ArchTypes)-1 { archTypes += ", " @@ -100,10 +68,10 @@ func ParseOptClientArchType(data []byte) (*OptClientArchType, error) { if len(data) < 2+length { return nil, ErrShortByteStream } - archTypes := make([]ArchType, 0, length%2) + archTypes := make([]iana.ArchType, 0, length%2) for idx := 0; idx < length; idx += 2 { b := data[2+idx : 2+idx+2] - archTypes = append(archTypes, ArchType(binary.BigEndian.Uint16(b))) + archTypes = append(archTypes, iana.ArchType(binary.BigEndian.Uint16(b))) } return &OptClientArchType{ArchTypes: archTypes}, nil } diff --git a/dhcpv4/option_archtype_test.go b/dhcpv4/option_archtype_test.go index cb9bc3f..d803328 100644 --- a/dhcpv4/option_archtype_test.go +++ b/dhcpv4/option_archtype_test.go @@ -3,6 +3,7 @@ package dhcpv4 import ( "testing" + "github.com/insomniacslk/dhcp/iana" "github.com/stretchr/testify/require" ) @@ -14,7 +15,7 @@ func TestParseOptClientArchType(t *testing.T) { } opt, err := ParseOptClientArchType(data) require.NoError(t, err) - require.Equal(t, opt.ArchTypes[0], EFI_IA32) + require.Equal(t, opt.ArchTypes[0], iana.EFI_IA32) } func TestParseOptClientArchTypeMultiple(t *testing.T) { @@ -26,8 +27,8 @@ func TestParseOptClientArchTypeMultiple(t *testing.T) { } opt, err := ParseOptClientArchType(data) require.NoError(t, err) - require.Equal(t, opt.ArchTypes[0], EFI_IA32) - require.Equal(t, opt.ArchTypes[1], EFI_ITANIUM) + require.Equal(t, opt.ArchTypes[0], iana.EFI_IA32) + require.Equal(t, opt.ArchTypes[1], iana.EFI_ITANIUM) } func TestParseOptClientArchTypeInvalid(t *testing.T) { @@ -61,7 +62,7 @@ func TestOptClientArchTypeParseAndToBytesMultiple(t *testing.T) { func TestOptClientArchType(t *testing.T) { opt := OptClientArchType{ - ArchTypes: []ArchType{EFI_ITANIUM}, + ArchTypes: []iana.ArchType{iana.EFI_ITANIUM}, } require.Equal(t, opt.Length(), 2) require.Equal(t, opt.Code(), OptionClientSystemArchitectureType) diff --git a/dhcpv6/dhcpv6.go b/dhcpv6/dhcpv6.go index d82ed4a..9382334 100644 --- a/dhcpv6/dhcpv6.go +++ b/dhcpv6/dhcpv6.go @@ -5,6 +5,8 @@ import ( "fmt" "net" "strings" + + "github.com/insomniacslk/dhcp/iana" ) type DHCPv6 interface { @@ -222,9 +224,11 @@ func IsUsingUEFI(msg DHCPv6) bool { // 9 EFI x86-64 if opt := msg.GetOneOption(OptionClientArchType); opt != nil { optat := opt.(*OptClientArchType) - // TODO investigate if other types are appropriate - if optat.ArchType == EFI_BC || optat.ArchType == EFI_X86_64 { - return true + for _, at := range optat.ArchTypes { + // TODO investigate if other types are appropriate + if at == iana.EFI_BC || at == iana.EFI_X86_64 { + return true + } } } if opt := msg.GetOneOption(OptionUserClass); opt != nil { diff --git a/dhcpv6/dhcpv6_test.go b/dhcpv6/dhcpv6_test.go index 812d284..6840252 100644 --- a/dhcpv6/dhcpv6_test.go +++ b/dhcpv6/dhcpv6_test.go @@ -218,14 +218,14 @@ func TestNewMessageTypeSolicitWithCID(t *testing.T) { func TestIsUsingUEFIArchTypeTrue(t *testing.T) { msg := DHCPv6Message{} - opt := OptClientArchType{ArchType: EFI_BC} + opt := OptClientArchType{ArchTypes: []iana.ArchType{iana.EFI_BC}} msg.AddOption(&opt) require.True(t, IsUsingUEFI(&msg)) } func TestIsUsingUEFIArchTypeFalse(t *testing.T) { msg := DHCPv6Message{} - opt := OptClientArchType{ArchType: INTEL_X86PC} + opt := OptClientArchType{ArchTypes: []iana.ArchType{iana.INTEL_X86PC}} msg.AddOption(&opt) require.False(t, IsUsingUEFI(&msg)) } diff --git a/dhcpv6/modifiers.go b/dhcpv6/modifiers.go index 32d11ac..6cd66db 100644 --- a/dhcpv6/modifiers.go +++ b/dhcpv6/modifiers.go @@ -2,6 +2,8 @@ package dhcpv6 import ( "log" + + "github.com/insomniacslk/dhcp/iana" ) // WithClientID adds a client ID option to a DHCPv6 packet @@ -53,9 +55,9 @@ func WithUserClass(uc []byte) Modifier { } // WithArchType adds an arch type option to the packet -func WithArchType(at ArchType) Modifier { +func WithArchType(at iana.ArchType) Modifier { return func(d DHCPv6) DHCPv6 { - ao := OptClientArchType{ArchType: at} + ao := OptClientArchType{ArchTypes: []iana.ArchType{at}} d.AddOption(&ao) return d } diff --git a/dhcpv6/option_archtype.go b/dhcpv6/option_archtype.go index a1b4a9b..231eddd 100644 --- a/dhcpv6/option_archtype.go +++ b/dhcpv6/option_archtype.go @@ -6,42 +6,14 @@ package dhcpv6 import ( "encoding/binary" "fmt" -) - -//ArchType encodes an architecture type in an uint16 -type ArchType uint16 + "strings" -// see rfc4578 -const ( - INTEL_X86PC ArchType = 0 - NEC_PC98 ArchType = 1 - EFI_ITANIUM ArchType = 2 - DEC_ALPHA ArchType = 3 - ARC_X86 ArchType = 4 - INTEL_LEAN_CLIENT ArchType = 5 - EFI_IA32 ArchType = 6 - EFI_BC ArchType = 7 - EFI_XSCALE ArchType = 8 - EFI_X86_64 ArchType = 9 + "github.com/insomniacslk/dhcp/iana" ) -// ArchTypeToStringMap maps an ArchType to a mnemonic name -var ArchTypeToStringMap = map[ArchType]string{ - INTEL_X86PC: "Intel x86PC", - NEC_PC98: "NEC/PC98", - EFI_ITANIUM: "EFI Itanium", - DEC_ALPHA: "DEC Alpha", - ARC_X86: "Arc x86", - INTEL_LEAN_CLIENT: "Intel Lean Client", - EFI_IA32: "EFI IA32", - EFI_BC: "EFI BC", - EFI_XSCALE: "EFI Xscale", - EFI_X86_64: "EFI x86-64", -} - // OptClientArchType represents an option CLIENT_ARCH_TYPE type OptClientArchType struct { - ArchType ArchType + ArchTypes []iana.ArchType } func (op *OptClientArchType) Code() OptionCode { @@ -49,23 +21,28 @@ func (op *OptClientArchType) Code() OptionCode { } func (op *OptClientArchType) ToBytes() []byte { - buf := make([]byte, 6) + buf := make([]byte, 4) binary.BigEndian.PutUint16(buf[0:2], uint16(OptionClientArchType)) binary.BigEndian.PutUint16(buf[2:4], uint16(op.Length())) - binary.BigEndian.PutUint16(buf[4:6], uint16(op.ArchType)) + u16 := make([]byte, 2) + for _, at := range op.ArchTypes { + binary.BigEndian.PutUint16(u16, uint16(at)) + buf = append(buf, u16...) + } return buf } func (op *OptClientArchType) Length() int { - return 2 + return 2*len(op.ArchTypes) } func (op *OptClientArchType) String() string { - name, ok := ArchTypeToStringMap[op.ArchType] - if !ok { - name = "Unknown" + atStrings := make([]string, 0) + for _, at := range op.ArchTypes { + name := iana.ArchTypeToString(at) + atStrings = append(atStrings, name) } - return fmt.Sprintf("OptClientArchType{archtype=%v}", name) + return fmt.Sprintf("OptClientArchType{archtype=%v}", strings.Join(atStrings, ", ")) } // ParseOptClientArchType builds an OptClientArchType structure from @@ -73,9 +50,12 @@ func (op *OptClientArchType) String() string { // length bytes. func ParseOptClientArchType(data []byte) (*OptClientArchType, error) { opt := OptClientArchType{} - if len(data) != 2 { - return nil, fmt.Errorf("Invalid arch type data length. Expected 2 bytes, got %v", len(data)) + if len(data) == 0 || len(data)%2 != 0 { + return nil, fmt.Errorf("Invalid arch type data length. Expected multiple of 2 larger than 2, got %v", len(data)) + } + for idx := 0; idx < len(data); idx += 2 { + b := data[idx : idx+2] + opt.ArchTypes = append(opt.ArchTypes, iana.ArchType(binary.BigEndian.Uint16(b))) } - opt.ArchType = ArchType(binary.BigEndian.Uint16(data)) return &opt, nil } diff --git a/dhcpv6/option_archtype_test.go b/dhcpv6/option_archtype_test.go index 748c8c5..1848e55 100644 --- a/dhcpv6/option_archtype_test.go +++ b/dhcpv6/option_archtype_test.go @@ -3,6 +3,7 @@ package dhcpv6 import ( "testing" + "github.com/insomniacslk/dhcp/iana" "github.com/stretchr/testify/require" ) @@ -12,7 +13,7 @@ func TestParseOptClientArchType(t *testing.T) { } opt, err := ParseOptClientArchType(data) require.NoError(t, err) - require.Equal(t, opt.ArchType, EFI_IA32) + require.Equal(t, opt.ArchTypes[0], iana.EFI_IA32) } func TestParseOptClientArchTypeInvalid(t *testing.T) { @@ -37,7 +38,7 @@ func TestOptClientArchTypeParseAndToBytes(t *testing.T) { func TestOptClientArchType(t *testing.T) { opt := OptClientArchType{ - ArchType: EFI_ITANIUM, + ArchTypes: []iana.ArchType{iana.EFI_ITANIUM}, } require.Equal(t, opt.Length(), 2) require.Equal(t, opt.Code(), OptionClientArchType) diff --git a/iana/archtype.go b/iana/archtype.go new file mode 100644 index 0000000..6b2cc9e --- /dev/null +++ b/iana/archtype.go @@ -0,0 +1,41 @@ +package iana + +//ArchType encodes an architecture type in an uint16 +type ArchType uint16 + +// see rfc4578 +const ( + INTEL_X86PC ArchType = 0 + NEC_PC98 ArchType = 1 + EFI_ITANIUM ArchType = 2 + DEC_ALPHA ArchType = 3 + ARC_X86 ArchType = 4 + INTEL_LEAN_CLIENT ArchType = 5 + EFI_IA32 ArchType = 6 + EFI_BC ArchType = 7 + EFI_XSCALE ArchType = 8 + EFI_X86_64 ArchType = 9 +) + +// ArchTypeToStringMap maps an ArchType to a mnemonic name +var ArchTypeToStringMap = map[ArchType]string{ + INTEL_X86PC: "Intel x86PC", + NEC_PC98: "NEC/PC98", + EFI_ITANIUM: "EFI Itanium", + DEC_ALPHA: "DEC Alpha", + ARC_X86: "Arc x86", + INTEL_LEAN_CLIENT: "Intel Lean Client", + EFI_IA32: "EFI IA32", + EFI_BC: "EFI BC", + EFI_XSCALE: "EFI Xscale", + EFI_X86_64: "EFI x86-64", +} + + +// ArchTypeToString returns a mnemonic name for a given architecture type +func ArchTypeToString(a ArchType) string { + if at := ArchTypeToStringMap[a]; at != "" { + return at + } + return "Unknown" +} |