github.com/crowdsecurity/crowdsec@v1.6.1/pkg/acquisition/modules/syslog/internal/parser/rfc5424/parse_test.go (about) 1 package rfc5424 2 3 import ( 4 "testing" 5 "time" 6 7 "github.com/crowdsecurity/go-cs-lib/cstest" 8 9 "github.com/stretchr/testify/require" 10 ) 11 12 func TestPri(t *testing.T) { 13 tests := []struct { 14 input string 15 expected int 16 expectedErr string 17 }{ 18 {"<0>", 0, ""}, 19 {"<19>", 19, ""}, 20 {"<200>", 200, ""}, 21 {"<4999>", 0, "PRI must be up to 3 characters long"}, 22 {"<123", 0, "PRI must end with '>'"}, 23 {"123>", 0, "PRI must start with '<'"}, 24 {"<abc>", 0, "PRI must be a number"}, 25 } 26 27 for _, test := range tests { 28 test := test 29 t.Run(test.input, func(t *testing.T) { 30 r := &RFC5424{} 31 r.buf = []byte(test.input) 32 r.len = len(r.buf) 33 err := r.parsePRI() 34 cstest.RequireErrorMessage(t, err, test.expectedErr) 35 }) 36 } 37 } 38 39 func TestHostname(t *testing.T) { 40 tests := []struct { 41 input string 42 expected string 43 expectedErr string 44 strictHostname bool 45 }{ 46 {"127.0.0.1", "127.0.0.1", "", false}, 47 {"::1", "::1", "", false}, 48 {"-", "", "", false}, 49 {"foo.-bar", "", "hostname is not valid", true}, 50 {"foo-.bar", "", "hostname is not valid", true}, 51 {"foo123.bar", "foo123.bar", "", true}, 52 {"a..", "", "hostname is not valid", true}, 53 {"foo.bar", "foo.bar", "", false}, 54 {"foo,bar", "foo,bar", "", false}, 55 {"foo,bar", "", "hostname is not valid", true}, 56 {".", ".", "", true}, 57 {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "", "hostname is not valid", true}, 58 {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.bla", "", "hostname is not valid", true}, 59 {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.bla", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.bla", "", false}, 60 {"a.foo-", "", "hostname is not valid", true}, 61 } 62 63 for _, test := range tests { 64 test := test 65 t.Run(test.input, func(t *testing.T) { 66 opts := []RFC5424Option{} 67 if test.strictHostname { 68 opts = append(opts, WithStrictHostname()) 69 } 70 r := NewRFC5424Parser(opts...) 71 r.buf = []byte(test.input) 72 r.len = len(r.buf) 73 err := r.parseHostname() 74 cstest.RequireErrorMessage(t, err, test.expectedErr) 75 }) 76 } 77 } 78 79 func TestParse(t *testing.T) { 80 type expected struct { 81 Timestamp time.Time 82 Hostname string 83 Tag string 84 PID string 85 Message string 86 PRI int 87 MsgID string 88 } 89 90 tests := []struct { 91 name string 92 input string 93 expected expected 94 expectedErr string 95 opts []RFC5424Option 96 }{ 97 { 98 "valid msg", 99 `<13>1 2021-05-18T11:58:40.828081+02:42 mantis sshd 49340 - [timeQuality isSynced="0" tzKnown="1"] blabla`, expected{ 100 Timestamp: time.Date(2021, 5, 18, 11, 58, 40, 828081000, time.FixedZone("+0242", 9720)), 101 Hostname: "mantis", 102 Tag: "sshd", 103 PID: "49340", 104 MsgID: "", 105 Message: "blabla", 106 PRI: 13, 107 }, "", []RFC5424Option{}, 108 }, 109 { 110 "valid msg with msgid", 111 `<13>1 2021-05-18T11:58:40.828081+02:42 mantis foobar 49340 123123 [timeQuality isSynced="0" tzKnown="1"] blabla`, expected{ 112 Timestamp: time.Date(2021, 5, 18, 11, 58, 40, 828081000, time.FixedZone("+0242", 9720)), 113 Hostname: "mantis", 114 Tag: "foobar", 115 PID: "49340", 116 MsgID: "123123", 117 Message: "blabla", 118 PRI: 13, 119 }, "", []RFC5424Option{}, 120 }, 121 { 122 "valid msg with repeating SD", 123 `<13>1 2021-05-18T11:58:40.828081+02:42 mantis foobar 49340 123123 [timeQuality isSynced="0" tzKnown="1"][foo="bar][a] blabla`, expected{ 124 Timestamp: time.Date(2021, 5, 18, 11, 58, 40, 828081000, time.FixedZone("+0242", 9720)), 125 Hostname: "mantis", 126 Tag: "foobar", 127 PID: "49340", 128 MsgID: "123123", 129 Message: "blabla", 130 PRI: 13, 131 }, "", []RFC5424Option{}, 132 }, 133 { 134 "invalid SD", 135 `<13>1 2021-05-18T11:58:40.828081+02:00 mantis foobar 49340 123123 [timeQuality asd`, expected{}, "structured data must end with ']'", []RFC5424Option{}, 136 }, 137 { 138 "invalid version", 139 `<13>42 2021-05-18T11:58:40.828081+02:00 mantis foobar 49340 123123 [timeQuality isSynced="0" tzKnown="1"] blabla`, expected{}, "version must be 1", []RFC5424Option{}, 140 }, 141 { 142 "invalid message", 143 `<13>1`, expected{}, "version must be followed by a space", []RFC5424Option{}, 144 }, 145 { 146 "valid msg with empty fields", 147 `<13>1 - foo - - - - blabla`, expected{ 148 Timestamp: time.Now().UTC(), 149 Hostname: "foo", 150 PRI: 13, 151 Message: "blabla", 152 }, "", []RFC5424Option{}, 153 }, 154 { 155 "valid msg with empty fields", 156 `<13>1 - - - - - - blabla`, expected{ 157 Timestamp: time.Now().UTC(), 158 PRI: 13, 159 Message: "blabla", 160 }, "", []RFC5424Option{}, 161 }, 162 { 163 "valid msg with escaped SD", 164 `<13>1 2022-05-24T10:57:39Z testhostname unknown - sn="msgid" [foo="\]" bar="a\""][a b="[\]" c] testmessage`, 165 expected{ 166 PRI: 13, 167 Timestamp: time.Date(2022, 5, 24, 10, 57, 39, 0, time.UTC), 168 Tag: "unknown", 169 Hostname: "testhostname", 170 MsgID: `sn="msgid"`, 171 Message: `testmessage`, 172 }, "", []RFC5424Option{}, 173 }, 174 { 175 "valid complex msg", 176 `<13>1 2022-05-24T10:57:39Z myhostname unknown - sn="msgid" [all@0 request="/dist/precache-manifest.58b57debe6bc4f96698da0dc314461e9.js" src_ip_geo_country="DE" MONTH="May" COMMONAPACHELOG="1.1.1.1 - - [24/May/2022:10:57:37 +0200\] \"GET /dist/precache-manifest.58b57debe6bc4f96698da0dc314461e9.js HTTP/2.0\" 304 0" auth="-" HOUR="10" gl2_remote_ip="172.31.32.142" ident="-" gl2_remote_port="43375" BASE10NUM="[2.0, 304, 0\]" pid="-1" program="nginx" gl2_source_input="623ed3440183476d61cff974" INT="+0200" is_private_ip="false" YEAR="2022" src_ip_geo_city="Achern" clientip="1.1.1.1" USERNAME="-" src_ip_geo_location="48.6306,8.0743" gl2_source_node="8620c2bb-dbb7-4535-b1ce-83df223acd8d" MINUTE="57" timestamp="2022-05-24T08:57:37.000Z" src_ip_asn="3320" level="5" IP="1.1.1.1" IPV4="1.1.1.1" verb="GET" gl2_message_id="01G3TMJFAMFS4H60QSF7M029R0" TIME="10:57:37" USER="-" src_ip_asn_owner="Deutsche Telekom AG" response="304" bytes="0" SECOND="37" httpversion="2.0" _id="906ce155-db3f-11ec-b25f-0a189ba2c64e" facility="user" MONTHDAY="24"] source: sn="www.foobar.com" | message: 1.1.1.1 - - [24/May/2022:10:57:37 +0200] "GET /dist/precache-manifest.58b57debe6bc4f96698da0dc314461e9.js HTTP/2.0" 304 0 "https://www.foobar.com/sw.js" "Mozilla/5.0 (Linux; Android 9; ANE-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.61 Mobile Safari/537.36" "-" "www.foobar.com" sn="www.foobar.com" rt=0.000 ua="-" us="-" ut="-" ul="-" cs=HIT { request: /dist/precache-manifest.58b57debe6bc4f96698da0dc314461e9.js | src_ip_geo_country: DE | MONTH: May | COMMONAPACHELOG: 1.1.1.1 - - [24/May/2022:10:57:37 +0200] "GET /dist/precache-manifest.58b57debe6bc4f96698da0dc314461e9.js HTTP/2.0" 304 0 | auth: - | HOUR: 10 | gl2_remote_ip: 172.31.32.142 | ident: - | gl2_remote_port: 43375 | BASE10NUM: [2.0, 304, 0] | pid: -1 | program: nginx | gl2_source_input: 623ed3440183476d61cff974 | INT: +0200 | is_private_ip: false | YEAR: 2022 | src_ip_geo_city: Achern | clientip: 1.1.1.1 | USERNAME:`, 177 expected{ 178 Timestamp: time.Date(2022, 5, 24, 10, 57, 39, 0, time.UTC), 179 Hostname: "myhostname", 180 Tag: "unknown", 181 PRI: 13, 182 MsgID: `sn="msgid"`, 183 Message: `source: sn="www.foobar.com" | message: 1.1.1.1 - - [24/May/2022:10:57:37 +0200] "GET /dist/precache-manifest.58b57debe6bc4f96698da0dc314461e9.js HTTP/2.0" 304 0 "https://www.foobar.com/sw.js" "Mozilla/5.0 (Linux; Android 9; ANE-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.61 Mobile Safari/537.36" "-" "www.foobar.com" sn="www.foobar.com" rt=0.000 ua="-" us="-" ut="-" ul="-" cs=HIT { request: /dist/precache-manifest.58b57debe6bc4f96698da0dc314461e9.js | src_ip_geo_country: DE | MONTH: May | COMMONAPACHELOG: 1.1.1.1 - - [24/May/2022:10:57:37 +0200] "GET /dist/precache-manifest.58b57debe6bc4f96698da0dc314461e9.js HTTP/2.0" 304 0 | auth: - | HOUR: 10 | gl2_remote_ip: 172.31.32.142 | ident: - | gl2_remote_port: 43375 | BASE10NUM: [2.0, 304, 0] | pid: -1 | program: nginx | gl2_source_input: 623ed3440183476d61cff974 | INT: +0200 | is_private_ip: false | YEAR: 2022 | src_ip_geo_city: Achern | clientip: 1.1.1.1 | USERNAME:`, 184 }, "", []RFC5424Option{}, 185 }, 186 { 187 "partial message", 188 `<13>1 2022-05-24T10:57:39Z foo bar -`, 189 expected{}, 190 "EOL after ProcID", 191 []RFC5424Option{}, 192 }, 193 { 194 "partial message", 195 `<13>1 2022-05-24T10:57:39Z foo bar `, 196 expected{}, 197 "EOL after appname", 198 []RFC5424Option{}, 199 }, 200 } 201 202 for _, test := range tests { 203 test := test 204 t.Run(test.name, func(t *testing.T) { 205 r := NewRFC5424Parser(test.opts...) 206 err := r.Parse([]byte(test.input)) 207 cstest.RequireErrorMessage(t, err, test.expectedErr) 208 if test.expectedErr != "" { 209 return 210 } 211 require.WithinDuration(t, test.expected.Timestamp, r.Timestamp, time.Second) 212 if r.Hostname != test.expected.Hostname { 213 t.Errorf("expected hostname '%s', got '%s'", test.expected.Hostname, r.Hostname) 214 } 215 if r.Tag != test.expected.Tag { 216 t.Errorf("expected tag '%s', got '%s'", test.expected.Tag, r.Tag) 217 } 218 if r.PID != test.expected.PID { 219 t.Errorf("expected pid '%s', got '%s'", test.expected.PID, r.PID) 220 } 221 if r.Message != test.expected.Message { 222 t.Errorf("expected message '%s', got '%s'", test.expected.Message, r.Message) 223 } 224 if r.PRI != test.expected.PRI { 225 t.Errorf("expected pri '%d', got '%d'", test.expected.PRI, r.PRI) 226 } 227 if r.MsgID != test.expected.MsgID { 228 t.Errorf("expected msgid '%s', got '%s'", test.expected.MsgID, r.MsgID) 229 } 230 }) 231 } 232 }