Skip to content

Commit

Permalink
Merge branch 'master' into macos
Browse files Browse the repository at this point in the history
  • Loading branch information
pmazzini committed May 24, 2021
2 parents 4d07145 + 95b2ff6 commit c89f321
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 13 deletions.
3 changes: 1 addition & 2 deletions dhcpv4/dhcpv4.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,7 @@ func GenerateTransactionID() (TransactionID, error) {

// New creates a new DHCPv4 structure and fill it up with default values. It
// won't be a valid DHCPv4 message so you will need to adjust its fields.
// See also NewDiscovery, NewOffer, NewRequest, NewAcknowledge, NewInform and
// NewRelease .
// See also NewDiscovery, NewRequest, NewAcknowledge, NewInform and NewRelease.
func New(modifiers ...Modifier) (*DHCPv4, error) {
xid, err := GenerateTransactionID()
if err != nil {
Expand Down
65 changes: 56 additions & 9 deletions dhcpv4/ztpv4/ztp.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package ztpv4

import (
"bytes"
"errors"
"strings"

"github.com/insomniacslk/dhcp/dhcpv4"
"github.com/insomniacslk/dhcp/iana"
)

// VendorData is optional data a particular vendor may or may not include
Expand All @@ -15,16 +17,10 @@ type VendorData struct {

var errVendorOptionMalformed = errors.New("malformed vendor option")

// ParseVendorData will try to parse dhcp4 options looking for more
// specific vendor data (like model, serial number, etc).
func ParseVendorData(packet *dhcpv4.DHCPv4) (*VendorData, error) {
vc := packet.ClassIdentifier()
if len(vc) == 0 {
return nil, errors.New("vendor options not found")
}
func parseClassIdentifier(packet *dhcpv4.DHCPv4) (*VendorData, error) {
vd := &VendorData{}

switch {
switch vc := packet.ClassIdentifier(); {
// Arista;DCS-7050S-64;01.23;JPE12221671
case strings.HasPrefix(vc, "Arista;"):
p := strings.Split(vc, ";")
Expand Down Expand Up @@ -71,6 +67,57 @@ func ParseVendorData(packet *dhcpv4.DHCPv4) (*VendorData, error) {
return vd, nil
}

// We didn't match anything.
return nil, nil
}

func parseVIVC(packet *dhcpv4.DHCPv4) (*VendorData, error) {
vd := &VendorData{}

for _, id := range packet.VIVC() {
if id.EntID == uint32(iana.EntIDCiscoSystems) {
vd.VendorName = iana.EntIDCiscoSystems.String()
//SN:0;PID:R-IOSXRV9000-CC
for _, f := range bytes.Split(id.Data, []byte(";")) {
p := bytes.Split(f, []byte(":"))
if len(p) != 2 {
return nil, errVendorOptionMalformed
}

switch string(p[0]) {
case "SN":
vd.Serial = string(p[1])
case "PID":
vd.Model = string(p[1])
}
}
return vd, nil
}
}

return nil, nil
}

// ParseVendorData will try to parse dhcp4 options looking for more
// specific vendor data (like model, serial number, etc).
func ParseVendorData(packet *dhcpv4.DHCPv4) (*VendorData, error) {
vd, err := parseClassIdentifier(packet)
if err != nil {
return nil, err
}

// If VendorData is set, return early
if vd != nil {
return vd, nil
}

vd, err = parseVIVC(packet)
if err != nil {
return nil, err
}

if vd != nil {
return vd, nil
}

return nil, errors.New("no known ZTP vendor found")
}
48 changes: 47 additions & 1 deletion dhcpv4/ztpv4/ztp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import (
"testing"

"github.com/insomniacslk/dhcp/dhcpv4"
"github.com/insomniacslk/dhcp/iana"
"github.com/stretchr/testify/require"
)

func TestParseV4VendorClass(t *testing.T) {
func TestParseClassIdentifier(t *testing.T) {
tt := []struct {
name string
vc, hostname string
Expand Down Expand Up @@ -70,3 +71,48 @@ func TestParseV4VendorClass(t *testing.T) {
})
}
}

func TestParseVIVC(t *testing.T) {
tt := []struct {
name string
vivc string
entID iana.EntID
want *VendorData
fail bool
}{
{
name: "cisco",
entID: iana.EntIDCiscoSystems,
vivc: "SN:0;PID:R-IOSXRV9000-CC",
want: &VendorData{VendorName: "Cisco Systems", Model: "R-IOSXRV9000-CC", Serial: "0"},
},
{
name: "ciscoMultipleColonDelimiters",
entID: iana.EntIDCiscoSystems,
vivc: "SN:0:123;PID:R-IOSXRV9000-CC:456",
fail: true,
},
}

for _, tc := range tt {
t.Run(tc.name, func(t *testing.T) {
packet, err := dhcpv4.New()
if err != nil {
t.Fatalf("failed to creat dhcpv4 packet object: %v", err)
}

if tc.vivc != "" {
vivc := dhcpv4.VIVCIdentifier{EntID: uint32(tc.entID), Data: []byte(tc.vivc)}
packet.UpdateOption(dhcpv4.OptVIVC(vivc))
}

vd, err := ParseVendorData(packet)
if tc.fail {
require.Error(t, err)
} else {
require.NoError(t, err)
require.Equal(t, tc.want, vd)
}
})
}
}
21 changes: 21 additions & 0 deletions iana/entid.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package iana

// EntID represents the Enterprise IDs as set by IANA
type EntID int

// See https://www.iana.org/assignments/enterprise-numbers/enterprise-numbers for values
const (
EntIDCiscoSystems EntID = 9
)

var entIDToStringMap = map[EntID]string{
EntIDCiscoSystems: "Cisco Systems",
}

// String returns the vendor name for a given Enterprise ID
func (e EntID) String() string {
if vendor := entIDToStringMap[e]; vendor != "" {
return vendor
}
return "Unknown"
}
2 changes: 1 addition & 1 deletion interfaces/bindtodevice_darwin.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// +build darwin solaris
// +build darwin

package interfaces

Expand Down

0 comments on commit c89f321

Please sign in to comment.