From 6cb0f30d455b1de222abfb00ca203dad0c1f1754 Mon Sep 17 00:00:00 2001 From: Pablo Mazzini Date: Fri, 9 Nov 2018 11:41:59 +0000 Subject: parse only option 60 --- dhcpv4/ztp/ztp.go | 75 ++++++++++---------------------------------------- dhcpv4/ztp/ztp_test.go | 74 ++++++++++--------------------------------------- 2 files changed, 28 insertions(+), 121 deletions(-) (limited to 'dhcpv4/ztp') diff --git a/dhcpv4/ztp/ztp.go b/dhcpv4/ztp/ztp.go index 7e1009f..a7e5d2f 100644 --- a/dhcpv4/ztp/ztp.go +++ b/dhcpv4/ztp/ztp.go @@ -1,11 +1,9 @@ package ztpv4 import ( - "bytes" "errors" "strings" - "github.com/golang/glog" "github.com/insomniacslk/dhcp/dhcpv4" ) @@ -20,30 +18,22 @@ type VendorData struct { var errVendorOptionMalformed = errors.New("malformed vendor option") -// VendorDataV4 will try to parse dhcp4 options data looking for more specific -// vendor data (like model, serial number, etc). If the options are missing -func VendorDataV4(packet *dhcpv4.DHCPv4) VendorData { - vd := VendorData{} - - if err := parseV4VendorClass(&vd, packet); err != nil { - glog.Errorf("failed to parse vendor data from vendor class: %v", err) - } - - if err := parseV4VIVC(&vd, packet); err != nil { - glog.Errorf("failed to parse vendor data from vendor-idenitifying vendor class: %v", err) - } - - return vd +// 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) { + return parseV4VendorClass(packet); } // parseV4Opt60 will attempt to look at the Vendor Class option (Option 60) on // DHCPv4. The option is formatted as a string with the content being specific // for the vendor, usually using a deliminator to separate the values. // See: https://tools.ietf.org/html/rfc1533#section-9.11 -func parseV4VendorClass(vd *VendorData, packet *dhcpv4.DHCPv4) error { +func parseV4VendorClass(packet *dhcpv4.DHCPv4) (*VendorData, error) { + vd := &VendorData{} + opt := packet.GetOneOption(dhcpv4.OptionClassIdentifier) if opt == nil { - return nil + return vd, nil } vc := opt.(*dhcpv4.OptClassIdentifier).Identifier @@ -52,25 +42,25 @@ func parseV4VendorClass(vd *VendorData, packet *dhcpv4.DHCPv4) error { case strings.HasPrefix(vc, "Arista;"): p := strings.Split(vc, ";") if len(p) < 4 { - return errVendorOptionMalformed + return vd, errVendorOptionMalformed } vd.VendorName = p[0] vd.Model = p[1] vd.Serial = p[3] - return nil + return vd, nil // ZPESystems:NSC:002251623 case strings.HasPrefix(vc, "ZPESystems:"): p := strings.Split(vc, ":") if len(p) < 3 { - return errVendorOptionMalformed + return vd, errVendorOptionMalformed } vd.VendorName = p[0] vd.Model = p[1] vd.Serial = p[2] - return nil + return vd, nil // Juniper option 60 parsing is a bit more nuanced. The following are all // "valid" indetifing stings for Juniper: @@ -94,46 +84,9 @@ func parseV4VendorClass(vd *VendorData, packet *dhcpv4.DHCPv4) error { } vd.Model = vc - return nil + return vd, nil } // We didn't match anything, just return an empty vendor data. - return nil -} - -const entIDCiscoSystems = 0x9 - -// parseV4Opt124 will attempt to read the Vendor-Identifying Vendor Class -// (Option 124) on a DHCPv4 packet. The data is represented in a length/value -// format with an indentifying enterprise number. -// -// See: https://tools.ietf.org/html/rfc3925 -func parseV4VIVC(vd *VendorData, packet *dhcpv4.DHCPv4) error { - opt := packet.GetOneOption(dhcpv4.OptionVendorIdentifyingVendorClass) - if opt == nil { - return nil - } - ids := opt.(*dhcpv4.OptVIVC).Identifiers - - for _, id := range ids { - if id.EntID == entIDCiscoSystems { - vd.VendorName = "Cisco Systems" - - //SN:0;PID:R-IOSXRV9000-CC - for _, f := range bytes.Split(id.Data, []byte(";")) { - p := bytes.SplitN(f, []byte(":"), 2) - if len(p) != 2 { - return errVendorOptionMalformed - } - - switch string(p[0]) { - case "SN": - vd.Serial = string(p[1]) - case "PID": - vd.Model = string(p[1]) - } - } - } - } - return nil + return vd, nil } diff --git a/dhcpv4/ztp/ztp_test.go b/dhcpv4/ztp/ztp_test.go index f46f9d8..ae715b2 100644 --- a/dhcpv4/ztp/ztp_test.go +++ b/dhcpv4/ztp/ztp_test.go @@ -3,15 +3,15 @@ package ztpv4 import ( "testing" - "github.com/google/go-cmp/cmp" "github.com/insomniacslk/dhcp/dhcpv4" + "github.com/stretchr/testify/require" ) func TestParseV4VendorClass(t *testing.T) { tt := []struct { name string vc, hostname string - want VendorData + want *VendorData fail bool }{ {name: "empty", fail: true}, @@ -20,44 +20,44 @@ func TestParseV4VendorClass(t *testing.T) { { name: "arista", vc: "Arista;DCS-7050S-64;01.23;JPE12345678", - want: VendorData{ + want: &VendorData{ VendorName: "Arista", Model: "DCS-7050S-64", Serial: "JPE12345678"}, }, { name: "juniper", vc: "Juniper-ptx1000-DD123", - want: VendorData{VendorName: "Juniper", Model: "ptx1000", Serial: "DD123"}, + want: &VendorData{VendorName: "Juniper", Model: "ptx1000", Serial: "DD123"}, }, { name: "juniperModelDash", vc: "Juniper-qfx10002-36q-DN817", - want: VendorData{VendorName: "Juniper", Model: "qfx10002-36q", Serial: "DN817"}, + want: &VendorData{VendorName: "Juniper", Model: "qfx10002-36q", Serial: "DN817"}, }, { name: "juniperHostnameSerial", vc: "Juniper-qfx10008", hostname: "DE123", - want: VendorData{VendorName: "Juniper", Model: "qfx10008", Serial: "DE123"}, + want: &VendorData{VendorName: "Juniper", Model: "qfx10008", Serial: "DE123"}, }, { name: "juniperNoSerial", vc: "Juniper-qfx10008", - want: VendorData{VendorName: "Juniper", Model: "qfx10008", Serial: ""}, + want: &VendorData{VendorName: "Juniper", Model: "qfx10008", Serial: ""}, }, { name: "juniperInvalid", vc: "Juniper-", - want: VendorData{VendorName: "Juniper", Model: "", Serial: ""}, + want: &VendorData{VendorName: "Juniper", Model: "", Serial: ""}, }, { name: "juniperInvalid2", vc: "Juniper-qfx99999-", - want: VendorData{VendorName: "Juniper", Model: "qfx99999", Serial: ""}, + want: &VendorData{VendorName: "Juniper", Model: "qfx99999", Serial: ""}, }, { name: "zpe", vc: "ZPESystems:NSC:001234567", - want: VendorData{VendorName: "ZPESystems", Model: "NSC", Serial: "001234567"}, + want: &VendorData{VendorName: "ZPESystems", Model: "NSC", Serial: "001234567"}, }, } @@ -78,56 +78,10 @@ func TestParseV4VendorClass(t *testing.T) { }) } - vd := VendorData{} - - if err := parseV4VendorClass(&vd, packet); err != nil && !tc.fail { - t.Errorf("unexpected failure: %v", err) - } - - if !cmp.Equal(tc.want, vd) { - t.Errorf("unexpected VendorData:\n%s", cmp.Diff(tc.want, vd)) - } - }) - } -} - -func TestParseV4VIVC(t *testing.T) { - tt := []struct { - name string - entID uint32 - input []byte - want VendorData - fail bool - }{ - {name: "empty", fail: true}, - { - name: "ciscoIOSXR", - entID: 0x09, - input: []byte("SN:0;PID:R-IOSXRV9000-CC"), - want: VendorData{VendorName: "Cisco Systems", Model: "R-IOSXRV9000-CC", Serial: "0"}, - }, - } - - 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) - } - packet.AddOption(&dhcpv4.OptVIVC{ - Identifiers: []dhcpv4.VIVCIdentifier{ - {EntID: tc.entID, Data: tc.input}, - }, - }) - - vd := VendorData{} - - if err := parseV4VIVC(&vd, packet); err != nil && !tc.fail { - t.Errorf("unexpected failure: %v", err) - } - - if !cmp.Equal(tc.want, vd) { - t.Errorf("unexpected VendorData:\n%s", cmp.Diff(tc.want, vd)) + vd, err := parseV4VendorClass(packet) + if !tc.fail { + require.NoError(t, err) + require.Equal(t, tc.want, vd) } }) } -- cgit v1.2.3