package syslogacquisition import ( "fmt" "net" "runtime" "testing" "time" "github.com/crowdsecurity/crowdsec/pkg/cstest" "github.com/crowdsecurity/crowdsec/pkg/types" log "github.com/sirupsen/logrus" "gopkg.in/tomb.v2" "github.com/stretchr/testify/assert" ) func TestConfigure(t *testing.T) { tests := []struct { config string expectedErr string }{ { config: ` foobar: bla source: syslog`, expectedErr: "line 2: field foobar not found in type syslogacquisition.SyslogConfiguration", }, { config: `source: syslog`, expectedErr: "", }, { config: ` source: syslog listen_port: asd`, expectedErr: "cannot unmarshal !!str `asd` into int", }, { config: ` source: syslog listen_port: 424242`, expectedErr: "invalid port 424242", }, { config: ` source: syslog listen_addr: 10.0.0`, expectedErr: "invalid listen IP 10.0.0", }, } subLogger := log.WithFields(log.Fields{ "type": "syslog", }) for _, test := range tests { s := SyslogSource{} err := s.Configure([]byte(test.config), subLogger) cstest.AssertErrorContains(t, err, test.expectedErr) } } func writeToSyslog(logs []string) { conn, err := net.Dial("udp", "127.0.0.1:4242") if err != nil { fmt.Printf("could not establish connection to syslog server : %s", err) return } for _, log := range logs { n, err := fmt.Fprint(conn, log) if err != nil { fmt.Printf("could not write to syslog server : %s", err) return } if n != len(log) { fmt.Printf("could not write to syslog server : %s", err) return } } } func TestStreamingAcquisition(t *testing.T) { tests := []struct { name string config string expectedErr string logs []string expectedLines int }{ { name: "invalid msgs", config: `source: syslog listen_port: 4242 listen_addr: 127.0.0.1`, logs: []string{"foobar", "bla", "pouet"}, }, { name: "RFC5424", config: `source: syslog listen_port: 4242 listen_addr: 127.0.0.1`, expectedLines: 2, logs: []string{`<13>1 2021-05-18T11:58:40.828081+02:00 mantis sshd 49340 - [timeQuality isSynced="0" tzKnown="1"] blabla`, `<13>1 2021-05-18T12:12:37.560695+02:00 mantis sshd 49340 - [timeQuality isSynced="0" tzKnown="1"] blabla2[foobar]`}, }, { name: "RFC3164", config: `source: syslog listen_port: 4242 listen_addr: 127.0.0.1`, expectedLines: 3, logs: []string{`<13>May 18 12:37:56 mantis sshd[49340]: blabla2[foobar]`, `<13>May 18 12:37:56 mantis sshd[49340]: blabla2`, `<13>May 18 12:37:56 mantis sshd: blabla2`, `<13>May 18 12:37:56 mantis sshd`}, }, } if runtime.GOOS != "windows" { tests = append(tests, struct { name string config string expectedErr string logs []string expectedLines int }{ name: "privileged port", config: `source: syslog`, expectedErr: "could not start syslog server: could not listen on port 514: listen udp 127.0.0.1:514: bind: permission denied", }) } for _, ts := range tests { ts := ts t.Run(ts.name, func(t *testing.T) { subLogger := log.WithFields(log.Fields{ "type": "syslog", }) s := SyslogSource{} err := s.Configure([]byte(ts.config), subLogger) if err != nil { t.Fatalf("could not configure syslog source : %s", err) } tomb := tomb.Tomb{} out := make(chan types.Event) err = s.StreamingAcquisition(out, &tomb) cstest.AssertErrorContains(t, err, ts.expectedErr) if ts.expectedErr != "" { return } if err != nil && ts.expectedErr == "" { t.Fatalf("unexpected error while starting syslog server: %s", err) return } actualLines := 0 go writeToSyslog(ts.logs) READLOOP: for { select { case <-out: actualLines++ case <-time.After(2 * time.Second): break READLOOP } } assert.Equal(t, ts.expectedLines, actualLines) tomb.Kill(nil) tomb.Wait() }) } }