From 2a50d0ebb393d6446fc64bf20c0f93c5a367e06c Mon Sep 17 00:00:00 2001 From: "Ivan Kuchin (ikuchin)" Date: Wed, 26 Apr 2023 17:15:52 -0400 Subject: [PATCH] Feature: added fqdn, added object type protocol --- .vscode/launch.json | 2 +- .../cisco-asa-access-entry/address_object.go | 86 +++++++++++++------ .../address_object_test.go | 69 ++++++++++----- .../cisco-asa-access-entry/sh_run_test.txt | 4 + internal/network_entities/init.go | 1 + 5 files changed, 112 insertions(+), 50 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 1e99d48..002ea9b 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -28,7 +28,7 @@ "request": "launch", "mode": "auto", "program": "${workspaceFolder}/main.go", - "args": ["-r", "examples/sh_run", "-s", "examples/syslog"], + "args": ["-r", "examples/sh_run.prod", "-s", "examples/syslog"], } ] } \ No newline at end of file diff --git a/internal/cisco-asa-access-list/cisco-asa-access-entry/address_object.go b/internal/cisco-asa-access-list/cisco-asa-access-entry/address_object.go index e3de56a..6e0f0ed 100644 --- a/internal/cisco-asa-access-list/cisco-asa-access-entry/address_object.go +++ b/internal/cisco-asa-access-list/cisco-asa-access-entry/address_object.go @@ -1,9 +1,11 @@ package ciscoasaaccessentry import ( + "encoding/binary" "errors" "fmt" "log" + "net" "net/netip" "strconv" "strings" @@ -130,82 +132,112 @@ func parseSubnet(parsing_pos uint, fields []string) (uint, addressObject, error) return parsing_pos + 2, _address_object, nil } -func parseAddressObjectContent(fields []string) (addressObject, error) { - var _address_object addressObject +func parseFQDN(fqdn string) ([]addressObject, error) { + var _address_objects []addressObject + + ips, err := net.LookupIP(fqdn) + if err != nil { + error_string := "ERROR: failed to resolve " + fqdn + log.Print(error_string) + return nil, errors.New(error_string) + } + + for _, ip := range ips { + if ip.To4() == nil { + fmt.Printf("Skipping IPv6 address: %s in %s name resolution\n", ip.String(), fqdn) + continue + } + _address_object := addressObject{start: binary.BigEndian.Uint32(ip.To4()), finish: binary.BigEndian.Uint32(ip.To4())} + _address_objects = append(_address_objects, _address_object) + } + + return _address_objects, nil +} + +func parseAddressObjectContent(fields []string) ([]addressObject, error) { + var _address_objects []addressObject switch fields[0] { + case "fqdn": + if len(fields) < 2 { + error_string := "ERROR: not enough fields to parse fqdn in address object" + log.Print(error_string, "(", fields, ")") + return nil, errors.New(error_string) + } + + _ao, err := parseFQDN(fields[1]) + if err != nil { + return nil, err + } + _address_objects = append(_address_objects, _ao...) + return _address_objects, nil case "host": if len(fields) < 2 { error_string := "ERROR: not enough fields to parse host in address object" log.Print(error_string, "(", fields, ")") - return _address_object, errors.New(error_string) + return nil, errors.New(error_string) } ip, err := parseIP(fields[1]) if err != nil { - return _address_object, err + return nil, err } + _address_objects = append(_address_objects, addressObject{start: ip, finish: ip}) - _address_object.start = ip - _address_object.finish = ip - - return _address_object, nil + return _address_objects, nil case "subnet": if len(fields) < 3 { error_string := "ERROR: not enough fields to parse subnet in address object" log.Print(error_string, "(", fields, ")") - return _address_object, errors.New(error_string) + return nil, errors.New(error_string) } _, _address_object, err := parseSubnet(1, fields) if err != nil { - return _address_object, err + return nil, err } + _address_objects = append(_address_objects, _address_object) - return _address_object, nil + return _address_objects, nil case "range": if len(fields) < 3 { error_string := "ERROR: not enough fields to parse range in address object" log.Print(error_string, "(", fields, ")") - return _address_object, errors.New(error_string) + return nil, errors.New(error_string) } start, err := parseIP(fields[1]) if err != nil { - return _address_object, err + return nil, err } finish, err := parseIP(fields[2]) if err != nil { - return _address_object, err + return nil, err } - _address_object.start = start - _address_object.finish = finish + _address_objects = append(_address_objects, addressObject{start: start, finish: finish}) - return _address_object, nil + return _address_objects, nil default: error_string := "ERROR: failed to parse address object" log.Print(error_string, "(", fields, ")") - return _address_object, errors.New(error_string) + return nil, errors.New(error_string) } } -func parseAddressObject(name string) (addressObject, error) { - var _address_object addressObject - +func parseAddressObject(name string) ([]addressObject, error) { address_object_text := sh_run_pipe.SectionExact("object network " + name).Exclude("object network " + name).Exclude("description ").Exclude(" nat ") if address_object_text.Len() != 1 { error_message := "object network must have only 1 line in it. object network " + name + " is " + strconv.Itoa(int(address_object_text.Len())) + " lines." log.Printf("ERROR: %s", error_message) - return _address_object, errors.New(error_message) + return nil, errors.New(error_message) } address_object_line, err := address_object_text.Get(0) if err != nil { - return _address_object, err + return nil, err } - fields := strings.Fields(address_object_line) return parseAddressObjectContent(fields) @@ -244,7 +276,7 @@ func parseAddressObjectGroup(name string) ([]addressObject, error) { if err != nil { return nil, err } - address_object_group = append(address_object_group, _ao) + address_object_group = append(address_object_group, _ao...) case "host": if len(fields) != 3 { error_message := "address-object host must have 3 fields in it. address-object host " + name + " is " + strconv.Itoa(len(fields)) + " fields." @@ -256,7 +288,7 @@ func parseAddressObjectGroup(name string) ([]addressObject, error) { if err != nil { return nil, err } - address_object_group = append(address_object_group, _ao) + address_object_group = append(address_object_group, _ao...) default: if len(fields) < 3 { error_string := "ERROR: not enough fields to parse subnet in address object" @@ -309,7 +341,7 @@ func getAddressObjects(parsing_pos uint, fields []string) (uint, []addressObject if err != nil { return 0, nil, err } - address_objects = append(address_objects, _address_object) + address_objects = append(address_objects, _address_object...) // --- set parsing position to a next block parsing_pos += 2 diff --git a/internal/cisco-asa-access-list/cisco-asa-access-entry/address_object_test.go b/internal/cisco-asa-access-list/cisco-asa-access-entry/address_object_test.go index 11874af..3f64b11 100644 --- a/internal/cisco-asa-access-list/cisco-asa-access-entry/address_object_test.go +++ b/internal/cisco-asa-access-list/cisco-asa-access-entry/address_object_test.go @@ -268,7 +268,7 @@ func Test_parseAddressObjectContent(t *testing.T) { tests := []struct { name string args args - want addressObject + want []addressObject wantErr bool }{ { @@ -276,9 +276,11 @@ func Test_parseAddressObjectContent(t *testing.T) { args: args{ fields: []string{"host", "1.2.3.4"}, }, - want: addressObject{ - uint32(1)<<24 + uint32(2)<<16 + uint32(3)<<8 + uint32(4), - uint32(1)<<24 + uint32(2)<<16 + uint32(3)<<8 + uint32(4), + want: []addressObject{ + { + uint32(1)<<24 + uint32(2)<<16 + uint32(3)<<8 + uint32(4), + uint32(1)<<24 + uint32(2)<<16 + uint32(3)<<8 + uint32(4), + }, }, wantErr: false, }, @@ -287,9 +289,11 @@ func Test_parseAddressObjectContent(t *testing.T) { args: args{ fields: []string{"subnet", "10.11.12.0", "255.255.255.0"}, }, - want: addressObject{ - uint32(10)<<24 + uint32(11)<<16 + uint32(12)<<8 + uint32(0), - uint32(10)<<24 + uint32(11)<<16 + uint32(12)<<8 + uint32(0) | ^(uint32(255)<<24 + uint32(255)<<16 + uint32(255)<<8 + uint32(0)), + want: []addressObject{ + { + uint32(10)<<24 + uint32(11)<<16 + uint32(12)<<8 + uint32(0), + uint32(10)<<24 + uint32(11)<<16 + uint32(12)<<8 + uint32(0) | ^(uint32(255)<<24 + uint32(255)<<16 + uint32(255)<<8 + uint32(0)), + }, }, wantErr: false, }, @@ -298,9 +302,11 @@ func Test_parseAddressObjectContent(t *testing.T) { args: args{ fields: []string{"range", "172.16.17.18", "172.16.17.99"}, }, - want: addressObject{ - uint32(172)<<24 + uint32(16)<<16 + uint32(17)<<8 + uint32(18), - uint32(172)<<24 + uint32(16)<<16 + uint32(17)<<8 + uint32(99), + want: []addressObject{ + { + uint32(172)<<24 + uint32(16)<<16 + uint32(17)<<8 + uint32(18), + uint32(172)<<24 + uint32(16)<<16 + uint32(17)<<8 + uint32(99), + }, }, wantErr: false, }, @@ -309,7 +315,7 @@ func Test_parseAddressObjectContent(t *testing.T) { args: args{ fields: []string{"unknown"}, }, - want: addressObject{}, + want: nil, wantErr: true, }, } @@ -334,7 +340,7 @@ func Test_parseAddressObject(t *testing.T) { tests := []struct { name string args args - want addressObject + want []addressObject wantErr bool }{ { @@ -342,9 +348,11 @@ func Test_parseAddressObject(t *testing.T) { args: args{ name: "SMALL-DC-RI", }, - want: addressObject{ - uint32(192)<<24 + uint32(168)<<16 + uint32(50)<<8 + uint32(50), - uint32(192)<<24 + uint32(168)<<16 + uint32(50)<<8 + uint32(50), + want: []addressObject{ + { + uint32(192)<<24 + uint32(168)<<16 + uint32(50)<<8 + uint32(50), + uint32(192)<<24 + uint32(168)<<16 + uint32(50)<<8 + uint32(50), + }, }, wantErr: false, }, @@ -353,9 +361,11 @@ func Test_parseAddressObject(t *testing.T) { args: args{ name: "SMALL-DC-NH", }, - want: addressObject{ - uint32(192)<<24 + uint32(168)<<16 + uint32(170)<<8 + uint32(0), - uint32(192)<<24 + uint32(168)<<16 + uint32(170)<<8 + uint32(0) | ^(uint32(255)<<24 + uint32(255)<<16 + uint32(255)<<8 + uint32(0)), + want: []addressObject{ + { + uint32(192)<<24 + uint32(168)<<16 + uint32(170)<<8 + uint32(0), + uint32(192)<<24 + uint32(168)<<16 + uint32(170)<<8 + uint32(0) | ^(uint32(255)<<24 + uint32(255)<<16 + uint32(255)<<8 + uint32(0)), + }, }, wantErr: false, }, @@ -364,9 +374,11 @@ func Test_parseAddressObject(t *testing.T) { args: args{ name: "SMALL-DC-MA", }, - want: addressObject{ - uint32(192)<<24 + uint32(168)<<16 + uint32(100)<<8 + uint32(50), - uint32(192)<<24 + uint32(168)<<16 + uint32(100)<<8 + uint32(89), + want: []addressObject{ + { + uint32(192)<<24 + uint32(168)<<16 + uint32(100)<<8 + uint32(50), + uint32(192)<<24 + uint32(168)<<16 + uint32(100)<<8 + uint32(89), + }, }, wantErr: false, }, @@ -375,9 +387,22 @@ func Test_parseAddressObject(t *testing.T) { args: args{ name: "unknown", }, - want: addressObject{}, + want: nil, wantErr: true, }, + { + name: "fqdn", + args: args{ + name: "test.com_fqdn", + }, + want: []addressObject{ + { + uint32(67)<<24 + uint32(225)<<16 + uint32(146)<<8 + uint32(248), + uint32(67)<<24 + uint32(225)<<16 + uint32(146)<<8 + uint32(248), + }, + }, + wantErr: false, + }, } sh_run_pipe.Load("sh_run_test.txt") for _, tt := range tests { diff --git a/internal/cisco-asa-access-list/cisco-asa-access-entry/sh_run_test.txt b/internal/cisco-asa-access-list/cisco-asa-access-entry/sh_run_test.txt index 0b9e8ce..0bf302e 100644 --- a/internal/cisco-asa-access-list/cisco-asa-access-entry/sh_run_test.txt +++ b/internal/cisco-asa-access-list/cisco-asa-access-entry/sh_run_test.txt @@ -105,6 +105,10 @@ object-group protocol TCPUDP protocol-object udp protocol-object tcp +object network test.com_fqdn + description expected IP 67.225.146.248 + fqdn test.com + access-list inside_in extended permit object-group OMNI-PORTS object-group OMNI-INET any4 log access-list inside_in extended permit object NTP object-group OMNI-INET any4 log access-list inside_in extended permit ip object-group MY-NETS object-group RFC1918 diff --git a/internal/network_entities/init.go b/internal/network_entities/init.go index ce41eda..8ddf667 100644 --- a/internal/network_entities/init.go +++ b/internal/network_entities/init.go @@ -153,6 +153,7 @@ func init() { } tcp_ports = []TcpPorts{ + {2049, "nfs"}, {500, "isakmp"}, {554, "rtsp"}, {67, "bootps"},