From 3d18640b3de84d56507e2f86a9a88a5798b656de Mon Sep 17 00:00:00 2001 From: Nate Brown Date: Mon, 7 Aug 2017 12:05:46 -0700 Subject: [PATCH] Handle and provide better filter processing errors --- audit.go | 44 +++++++++++------ audit_test.go | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 158 insertions(+), 15 deletions(-) diff --git a/audit.go b/audit.go index 2d85acf..d5a7a77 100644 --- a/audit.go +++ b/audit.go @@ -231,7 +231,7 @@ func createStdOutOutput(config *viper.Viper) (*AuditWriter, error) { return NewAuditWriter(os.Stdout, attempts), nil } -func createFilters(config *viper.Viper) []AuditFilter { +func createFilters(config *viper.Viper) ([]AuditFilter, error) { var err error var ok bool @@ -239,18 +239,18 @@ func createFilters(config *viper.Viper) []AuditFilter { filters := []AuditFilter{} if fs == nil { - return filters + return filters, nil } ft, ok := fs.([]interface{}) if !ok { - return filters + return filters, fmt.Errorf("Could not parse filters object") } for i, f := range ft { f2, ok := f.(map[interface{}]interface{}) if !ok { - el.Fatal("Could not parse filter ", i+1, f) + return filters, fmt.Errorf("Could not parse filter %d; '%+v'", i+1, f) } af := AuditFilter{} @@ -260,28 +260,25 @@ func createFilters(config *viper.Viper) []AuditFilter { if ev, ok := v.(string); ok { fv, err := strconv.ParseUint(ev, 10, 64) if err != nil { - el.Fatal("`message_type` in filter ", i+1, " could not be parsed ", v, " ", err) + return filters, fmt.Errorf("`message_type` in filter %d could not be parsed; Value: `%+v`; Error: %s", i+1, v, err) } af.messageType = uint16(fv) } else if ev, ok := v.(int); ok { - if !ok { - el.Fatal("`message_type` in filter ", i+1, " could not be parsed ", v) - } af.messageType = uint16(ev) } else { - el.Fatal("`message_type` in filter ", i+1, " could not be parsed ", v) + return filters, fmt.Errorf("`message_type` in filter %d could not be parsed; Value: `%+v`", i+1, v) } case "regex": re, ok := v.(string) if !ok { - el.Fatal("`regex` in filter ", i+1, " could not be parsed ", v) + return filters, fmt.Errorf("`regex` in filter %d could not be parsed; Value: `%+v`", i+1, v) } if af.regex, err = regexp.Compile(re); err != nil { - el.Fatal("`regex` in filter ", i+1, " could not be parsed ", v, " ", err) + return filters, fmt.Errorf("`regex` in filter %d could not be parsed; Value: `%+v`; Error: %s", i+1, v, err) } case "syscall": @@ -290,16 +287,28 @@ func createFilters(config *viper.Viper) []AuditFilter { } else if ev, ok := v.(int); ok { af.syscall = strconv.Itoa(ev) } else { - el.Fatal("`syscall` in filter ", i+1, " could not be parsed ", v) + return filters, fmt.Errorf("`syscall` in filter %d could not be parsed; Value: `%+v`", i+1, v) } } } + if af.regex == nil { + return filters, fmt.Errorf("Filter %d is missing the `regex` entry", i+1) + } + + if af.syscall == "" { + return filters, fmt.Errorf("Filter %d is missing the `syscall` entry", i+1) + } + + if af.messageType == 0 { + return filters, fmt.Errorf("Filter %d is missing the `message_type` entry", i+1) + } + filters = append(filters, af) - l.Printf("Ignoring syscall `%v` containing message type `%v` matching string `%s`\n", af.syscall, af.messageType, af.regex.String()) + l.Printf("Ignoring syscall `%v` containing message type `%v` matching string `%s`\n", af.syscall, af.messageType, af.regex.String()) } - return filters + return filters, nil } func main() { @@ -328,6 +337,11 @@ func main() { el.Fatal(err) } + filters, err := createFilters(config) + if err != nil { + el.Fatal(err) + } + nlClient := NewNetlinkClient(config.GetInt("socket_buffer.receive")) marshaller := NewAuditMarshaller( writer, @@ -336,7 +350,7 @@ func main() { config.GetBool("message_tracking.enabled"), config.GetBool("message_tracking.log_out_of_order"), config.GetInt("message_tracking.max_out_of_order"), - createFilters(config), + filters, ) l.Printf("Started processing events in the range [%d, %d]\n", config.GetInt("events.min"), config.GetInt("events.max")) diff --git a/audit_test.go b/audit_test.go index 89c2783..d7b96b9 100644 --- a/audit_test.go +++ b/audit_test.go @@ -328,6 +328,135 @@ func Test_createOutput(t *testing.T) { assert.Nil(t, err) } +func Test_createFilters(t *testing.T) { + lb, elb := hookLogger() + defer resetLogger() + + // no filters + c := viper.New() + f, err := createFilters(c) + assert.Nil(t, err) + assert.Empty(t, f) + + // Bad outer filter value + c = viper.New() + c.Set("filters", 1) + f, err = createFilters(c) + assert.EqualError(t, err, "Could not parse filters object") + assert.Empty(t, f) + + // Bad inner filter value + c = viper.New() + rf := make([]interface{}, 0) + rf = append(rf, "bad filter definition") + c.Set("filters", rf) + f, err = createFilters(c) + assert.EqualError(t, err, "Could not parse filter 1; 'bad filter definition'") + assert.Empty(t, f) + + // Bad message type - string + c = viper.New() + rf = make([]interface{}, 0) + rf = append(rf, map[interface{}]interface{}{"message_type": "bad message type"}) + c.Set("filters", rf) + f, err = createFilters(c) + assert.EqualError(t, err, "`message_type` in filter 1 could not be parsed; Value: `bad message type`; Error: strconv.ParseUint: parsing \"bad message type\": invalid syntax") + assert.Empty(t, f) + + // Bad message type - unknown + c = viper.New() + rf = make([]interface{}, 0) + rf = append(rf, map[interface{}]interface{}{"message_type": false}) + c.Set("filters", rf) + f, err = createFilters(c) + assert.EqualError(t, err, "`message_type` in filter 1 could not be parsed; Value: `false`") + assert.Empty(t, f) + + // Bad regex - not string + c = viper.New() + rf = make([]interface{}, 0) + rf = append(rf, map[interface{}]interface{}{"regex": false}) + c.Set("filters", rf) + f, err = createFilters(c) + assert.EqualError(t, err, "`regex` in filter 1 could not be parsed; Value: `false`") + assert.Empty(t, f) + + // Bad regex - un-parse-able + c = viper.New() + rf = make([]interface{}, 0) + rf = append(rf, map[interface{}]interface{}{"regex": "["}) + c.Set("filters", rf) + f, err = createFilters(c) + assert.EqualError(t, err, "`regex` in filter 1 could not be parsed; Value: `[`; Error: error parsing regexp: missing closing ]: `[`") + assert.Empty(t, f) + + // Bad syscall - not string or int + c = viper.New() + rf = make([]interface{}, 0) + rf = append(rf, map[interface{}]interface{}{"syscall": []string{}}) + c.Set("filters", rf) + f, err = createFilters(c) + assert.EqualError(t, err, "`syscall` in filter 1 could not be parsed; Value: `[]`") + assert.Empty(t, f) + + // Missing regex + c = viper.New() + rf = make([]interface{}, 0) + rf = append(rf, map[interface{}]interface{}{"syscall": "1", "message_type": "1"}) + c.Set("filters", rf) + f, err = createFilters(c) + assert.EqualError(t, err, "Filter 1 is missing the `regex` entry") + assert.Empty(t, f) + + // Missing message_type + c = viper.New() + rf = make([]interface{}, 0) + rf = append(rf, map[interface{}]interface{}{"syscall": "1", "regex": "1"}) + c.Set("filters", rf) + f, err = createFilters(c) + assert.EqualError(t, err, "Filter 1 is missing the `message_type` entry") + assert.Empty(t, f) + + // Missing message_type + c = viper.New() + rf = make([]interface{}, 0) + rf = append(rf, map[interface{}]interface{}{"message_type": "1", "regex": "1"}) + c.Set("filters", rf) + f, err = createFilters(c) + assert.EqualError(t, err, "Filter 1 is missing the `syscall` entry") + assert.Empty(t, f) + + // Good with strings + c = viper.New() + rf = make([]interface{}, 0) + rf = append(rf, map[interface{}]interface{}{"message_type": "1", "regex": "1", "syscall": "1"}) + c.Set("filters", rf) + f, err = createFilters(c) + assert.Nil(t, err) + assert.NotEmpty(t, f) + assert.Equal(t, "1", f[0].syscall) + assert.Equal(t, uint16(1), f[0].messageType) + assert.Equal(t, "1", f[0].regex.String()) + assert.Empty(t, elb.String()) + assert.Equal(t, "Ignoring syscall `1` containing message type `1` matching string `1`\n", lb.String()) + + // Good with ints + lb.Reset() + elb.Reset() + c = viper.New() + rf = make([]interface{}, 0) + rf = append(rf, map[interface{}]interface{}{"message_type": 1, "regex": "1", "syscall": 1}) + c.Set("filters", rf) + f, err = createFilters(c) + assert.Nil(t, err) + assert.NotEmpty(t, f) + assert.Equal(t, "1", f[0].syscall) + assert.Equal(t, uint16(1), f[0].messageType) + assert.Equal(t, "1", f[0].regex.String()) + assert.Empty(t, elb.String()) + assert.Equal(t, "Ignoring syscall `1` containing message type `1` matching string `1`\n", lb.String()) +} + func Benchmark_MultiPacketMessage(b *testing.B) { marshaller := NewAuditMarshaller(NewAuditWriter(&noopWriter{}, 1), uint16(1300), uint16(1399), false, false, 1, []AuditFilter{})