logstash-patterns-core 4.2.0 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +98 -0
  3. data/Gemfile +3 -0
  4. data/README.md +11 -18
  5. data/lib/logstash/patterns/core.rb +11 -3
  6. data/logstash-patterns-core.gemspec +1 -1
  7. data/patterns/ecs-v1/aws +28 -0
  8. data/patterns/ecs-v1/bacula +53 -0
  9. data/patterns/ecs-v1/bind +13 -0
  10. data/patterns/ecs-v1/bro +30 -0
  11. data/patterns/ecs-v1/exim +26 -0
  12. data/patterns/ecs-v1/firewalls +111 -0
  13. data/patterns/ecs-v1/grok-patterns +95 -0
  14. data/patterns/ecs-v1/haproxy +40 -0
  15. data/patterns/ecs-v1/httpd +17 -0
  16. data/patterns/ecs-v1/java +34 -0
  17. data/patterns/ecs-v1/junos +13 -0
  18. data/patterns/ecs-v1/linux-syslog +16 -0
  19. data/patterns/{maven → ecs-v1/maven} +0 -0
  20. data/patterns/ecs-v1/mcollective +4 -0
  21. data/patterns/ecs-v1/mongodb +7 -0
  22. data/patterns/ecs-v1/nagios +124 -0
  23. data/patterns/ecs-v1/postgresql +2 -0
  24. data/patterns/ecs-v1/rails +13 -0
  25. data/patterns/ecs-v1/redis +3 -0
  26. data/patterns/ecs-v1/ruby +2 -0
  27. data/patterns/ecs-v1/squid +6 -0
  28. data/patterns/ecs-v1/zeek +33 -0
  29. data/patterns/{aws → legacy/aws} +1 -1
  30. data/patterns/{bacula → legacy/bacula} +5 -5
  31. data/patterns/legacy/bind +3 -0
  32. data/patterns/{bro → legacy/bro} +0 -0
  33. data/patterns/{exim → legacy/exim} +8 -2
  34. data/patterns/{firewalls → legacy/firewalls} +2 -2
  35. data/patterns/{grok-patterns → legacy/grok-patterns} +0 -0
  36. data/patterns/{haproxy → legacy/haproxy} +0 -0
  37. data/patterns/{httpd → legacy/httpd} +1 -1
  38. data/patterns/{java → legacy/java} +0 -0
  39. data/patterns/{junos → legacy/junos} +0 -0
  40. data/patterns/{linux-syslog → legacy/linux-syslog} +0 -0
  41. data/patterns/legacy/maven +1 -0
  42. data/patterns/{mcollective → legacy/mcollective} +0 -0
  43. data/patterns/{mcollective-patterns → legacy/mcollective-patterns} +0 -0
  44. data/patterns/{mongodb → legacy/mongodb} +0 -0
  45. data/patterns/{nagios → legacy/nagios} +0 -0
  46. data/patterns/{postgresql → legacy/postgresql} +0 -0
  47. data/patterns/{rails → legacy/rails} +0 -0
  48. data/patterns/{redis → legacy/redis} +0 -0
  49. data/patterns/{ruby → legacy/ruby} +0 -0
  50. data/patterns/legacy/squid +4 -0
  51. data/spec/patterns/aws_spec.rb +395 -0
  52. data/spec/patterns/bacula_spec.rb +367 -0
  53. data/spec/patterns/bind_spec.rb +78 -0
  54. data/spec/patterns/bro_spec.rb +613 -0
  55. data/spec/patterns/core_spec.rb +51 -9
  56. data/spec/patterns/exim_spec.rb +201 -0
  57. data/spec/patterns/firewalls_spec.rb +669 -66
  58. data/spec/patterns/haproxy_spec.rb +246 -38
  59. data/spec/patterns/httpd_spec.rb +215 -94
  60. data/spec/patterns/java_spec.rb +357 -27
  61. data/spec/patterns/junos_spec.rb +101 -0
  62. data/spec/patterns/mcollective_spec.rb +35 -0
  63. data/spec/patterns/mongodb_spec.rb +170 -33
  64. data/spec/patterns/nagios_spec.rb +296 -79
  65. data/spec/patterns/netscreen_spec.rb +123 -0
  66. data/spec/patterns/rails3_spec.rb +87 -29
  67. data/spec/patterns/redis_spec.rb +157 -121
  68. data/spec/patterns/shorewall_spec.rb +85 -74
  69. data/spec/patterns/squid_spec.rb +139 -0
  70. data/spec/patterns/syslog_spec.rb +266 -22
  71. data/spec/spec_helper.rb +80 -6
  72. metadata +64 -28
  73. data/patterns/bind +0 -3
  74. data/patterns/squid +0 -4
  75. data/spec/patterns/bro.rb +0 -126
  76. data/spec/patterns/s3_spec.rb +0 -173
@@ -54,15 +54,6 @@ describe "HTTP DATE parsing" do
54
54
 
55
55
  end
56
56
 
57
- describe "TOMCATLOG" do
58
-
59
- let(:value) { '2014-01-09 20:03:28,269 -0800 | ERROR | com.example.service.ExampleService - something compeletely unexpected happened...'}
60
-
61
- it "generates the logmessage field" do
62
- expect(grok_match(subject, value)).to include("logmessage" => "something compeletely unexpected happened...")
63
- end
64
- end
65
-
66
57
  describe 'LOGLEVEL' do
67
58
  it 'matches info label' do
68
59
  expect(grok_match(subject, 'INFO')).to pass
@@ -495,3 +486,54 @@ describe "URN" do
495
486
  end
496
487
  end
497
488
  end
489
+
490
+ describe_pattern "EMAILADDRESS", ['legacy', 'ecs-v1'] do
491
+
492
+ # NOTE: EMAILLOCALPART was only updated in ECS mode, as following the RFC is
493
+ # actually a breaking change -> legacy does match incorrect e-mail addresses.
494
+
495
+ it "matches 'hello.world@123.net' address" do
496
+ expect(grok_exact_match(pattern, 'hello.world@123.net')).to pass
497
+ end
498
+
499
+ [
500
+ 'a@example.com',
501
+ 'a{b}@example.com',
502
+ 'Foo+Bar@x.exposed',
503
+ ].each do |valid_email|
504
+ it "matches #{valid_email.inspect} address" do
505
+ expect(grok_exact_match(pattern, valid_email)).to pass if ecs_compatibility?
506
+ end
507
+ end
508
+
509
+ it "does not match 'x y@example.com' address" do
510
+ expect(grok_exact_match(pattern, 'hello.world@123.net')).to pass
511
+ end
512
+
513
+ [
514
+ 'a:b@example.com',
515
+ 'a..b@example.com',
516
+ ].each do |invalid_email|
517
+ it "does not match #{invalid_email.inspect} address" do
518
+ expect(grok_exact_match(pattern, invalid_email)).to_not pass if ecs_compatibility?
519
+ end
520
+ end
521
+
522
+ it "matches e-mail with digits only local-part" do
523
+ expect(grok_exact_match(pattern, '00@q.ro')).to pass if ecs_compatibility?
524
+ end
525
+
526
+ it "matches e-mail with 64 chars in local-part" do
527
+ expect(grok_exact_match(pattern, ('ab' * 32) + '@root.cz')).to pass
528
+ expect(grok_exact_match(pattern, ('a.bc' * 16) + '@00.cz')).to pass
529
+ end
530
+
531
+ it "does not match e-mail with more than 64 char length local-part" do
532
+ if ecs_compatibility?
533
+ expect(grok_exact_match(pattern, ('ab' * 32) + 'a' + '@root.cz')).to_not pass
534
+ # NOTE: we allow longer with '.' but at least we limit "too long" :
535
+ expect(grok_exact_match(pattern, ('a.bc' * 64) + '@00.cz')).to_not pass
536
+ end
537
+ end
538
+
539
+ end
@@ -0,0 +1,201 @@
1
+ # encoding: utf-8
2
+ require "spec_helper"
3
+ require "logstash/patterns/core"
4
+
5
+ describe_pattern 'EXIM', ['legacy', 'ecs-v1'] do
6
+
7
+ context 'message arrival (old)' do
8
+
9
+ let(:message) do
10
+ "1995-10-31 08:57:53 0tACW1-0005MB-00 <= kryten@dwarf.fict.example H=mailer.fict.example [192.168.123.123] " +
11
+ "U=exim P=smtp S=5678 id=f828ca60127d8646a0fa75cbf8db9ba3@dwarf.fict.example"
12
+ end
13
+
14
+ it "matches" do
15
+ expect(grok).to include("timestamp" => "1995-10-31 08:57:53")
16
+
17
+ if ecs_compatibility?
18
+ expect(grok).to include("exim"=>{"log"=>{
19
+ "flags"=>"<=",
20
+ "sender"=>{"email"=>"kryten@dwarf.fict.example"},
21
+ "message"=>{"id"=>"0tACW1-0005MB-00", "size"=>5678},
22
+ "header_id"=>"f828ca60127d8646a0fa75cbf8db9ba3@dwarf.fict.example"
23
+ }})
24
+ expect(grok).to include("source"=>{"address"=>"mailer.fict.example", "ip"=>"192.168.123.123"})
25
+ expect(grok).to include("network"=>{"protocol"=>"smtp"})
26
+ else
27
+ expect(grok).to include("exim_year" => "1995", "exim_month" => "10", "exim_day" => "31", "@version" => "1", "exim_time" => "08:57:53")
28
+ expect(grok.keys).to_not include("pid")
29
+ expect(grok).to include("exim_sender_email" => "kryten@dwarf.fict.example")
30
+ expect(grok).to include("exim_flags" => "<=")
31
+ expect(grok).to include("exim_msg_size" => "5678")
32
+ expect(grok).to include("exim_msgid" => "0tACW1-0005MB-00")
33
+ expect(grok).to include("remote_hostname" => "mailer.fict.example", "remote_host" => "192.168.123.123")
34
+ expect(grok).to include("protocol" => "smtp")
35
+ expect(grok).to include("exim_header_id" => "f828ca60127d8646a0fa75cbf8db9ba3@dwarf.fict.example")
36
+ end
37
+
38
+ expect(grok).to include("message" => message)
39
+ end
40
+
41
+ end
42
+
43
+ context 'message arrival (new)' do
44
+ let(:message) do
45
+ '2010-09-13 05:00:13 [1487] 1Ov4tU-0000Nz-Rm <= mailling.list@domain.com ' +
46
+ 'H=mailhost.domain.com [208.42.54.2]:51792 I=[67.215.162.175]:25 P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=21778 ' +
47
+ 'id=384a86a39e83be0d9b3a94d1feb3119f@domain.com T="Daily List: Chameleon" for user@example.com'
48
+ end
49
+
50
+ it "matches" do
51
+ expect(grok).to include("timestamp" => "2010-09-13 05:00:13") # new in legacy mode
52
+
53
+ if ecs_compatibility?
54
+ expect(grok).to include("process"=>{"pid"=>1487})
55
+ expect(grok).to include("exim"=>{"log"=>hash_including(
56
+ "message"=>{"id"=>"1Ov4tU-0000Nz-Rm", "size"=>21778, "subject"=>"Daily List: Chameleon"},
57
+ "flags"=>"<=",
58
+ "header_id"=>"384a86a39e83be0d9b3a94d1feb3119f@domain.com",
59
+ "sender"=>{"email"=>"mailling.list@domain.com"},
60
+ "recipient"=>{"email"=>"user@example.com"},
61
+ )})
62
+ expect(grok).to include("source"=>{"address"=>"mailhost.domain.com", "ip"=>"208.42.54.2", "port"=>51792})
63
+ expect(grok).to include("destination"=>{"ip"=>"67.215.162.175", "port"=>25})
64
+ else
65
+
66
+ expect(grok).to include("exim_year" => "2010", "exim_month" => "09", "exim_day" => "13", "exim_time" => "05:00:13")
67
+ expect(grok).to include("pid" => "1487") # new
68
+ expect(grok).to include("exim_sender_email" => "mailling.list@domain.com") # new
69
+ expect(grok).to include("remote_hostname" => "mailhost.domain.com", "remote_host" => "208.42.54.2", "remote_port" => "51792") # (remote_port) new
70
+ expect(grok).to include("exim_interface" => "67.215.162.175", "exim_interface_port" => "25")
71
+ expect(grok).to include("protocol" => "esmtps")
72
+ expect(grok).to include("exim_msg_size" => "21778")
73
+ expect(grok).to include("exim_header_id" => "384a86a39e83be0d9b3a94d1feb3119f@domain.com")
74
+ expect(grok).to include("exim_subject" => '"Daily List: Chameleon"')
75
+ expect(grok).to include("exim_recipient_email" => "user@example.com") # new
76
+ end
77
+
78
+ expect(grok).to include("message" => message)
79
+ end
80
+
81
+ end
82
+
83
+ context 'message arrival (simple)' do
84
+
85
+ let(:message) do
86
+ '2020-02-11 17:09:46 1j1Z2g-00Faoy-Uh <= example@strawberry.active-ns.com U=example P=local ' +
87
+ 'T="[Examples Galore] Please moderate: \"Hello world!\"" for admin@example.net'
88
+ end
89
+
90
+ it "matches" do
91
+ expect(grok).to include("timestamp"=>"2020-02-11 17:09:46")
92
+ if ecs_compatibility?
93
+ expect(grok).to include("exim"=>{"log"=>{
94
+ "flags"=>"<=",
95
+ "message"=>{"id"=>"1j1Z2g-00Faoy-Uh", "subject"=>'[Examples Galore] Please moderate: \\"Hello world!\\"'},
96
+ "sender"=>{"email"=>"example@strawberry.active-ns.com"},
97
+ "recipient"=>{"email"=>"admin@example.net"}
98
+ }})
99
+ expect(grok).to include("network"=>{"protocol"=>"local"})
100
+ else
101
+ expect(grok).to include(
102
+ "exim_msgid"=>"1j1Z2g-00Faoy-Uh",
103
+ "exim_sender_email"=>"example@strawberry.active-ns.com",
104
+ "exim_flags"=>"<=",
105
+ "protocol"=>"local",
106
+ "exim_subject"=>"\"[Examples Galore] Please moderate: \\\"Hello world!\\\"\""
107
+ )
108
+ end
109
+ end
110
+
111
+ end
112
+
113
+ context 'message arrival with quoted hostname' do
114
+
115
+ let(:message) do
116
+ '2013-03-20 12:44:02 1UIIN7-0004t9-8R <= root@example.com ' +
117
+ 'H=localhost (hostname.example.com) [127.0.0.1] ' +
118
+ 'P=esmtps X=TLSv1:DHE-RSA-AES256-SHA:256 S=811 id=201303201244.r2KCi11V018784@hostname.example.com'
119
+ end
120
+
121
+ it "matches" do
122
+ expect(grok).to include("timestamp"=>"2013-03-20 12:44:02")
123
+
124
+ if ecs_compatibility?
125
+ expect(grok).to include("exim"=>{"log"=>hash_including(
126
+ "sender"=>{ "email"=>"root@example.com" },
127
+ "message"=>{ "id"=>"1UIIN7-0004t9-8R", "size"=>811 },
128
+ "header_id"=>"201303201244.r2KCi11V018784@hostname.example.com",
129
+ "remote_address"=>"hostname.example.com")})
130
+ expect(grok).to include("source"=>{"address"=>"localhost", "ip"=>"127.0.0.1"})
131
+ expect(grok).to include("network"=>{"protocol"=>"esmtps"})
132
+ else
133
+ expect(grok).to include(
134
+ "exim_msgid"=>"1UIIN7-0004t9-8R",
135
+ "exim_sender_email"=>"root@example.com",
136
+ "exim_flags"=>"<=",
137
+ "protocol"=>"esmtps",
138
+ "exim_header_id"=>"201303201244.r2KCi11V018784@hostname.example.com"
139
+ )
140
+ expect(grok).to include(
141
+ "remote_host"=>"127.0.0.1",
142
+ "remote_heloname"=>"hostname.example.com",
143
+ "remote_hostname"=>"localhost"
144
+ )
145
+ end
146
+ end
147
+
148
+ end
149
+
150
+
151
+ context 'message arrival with quoted hostname and port' do
152
+
153
+ let(:message) do
154
+ '2014-08-10 11:18:35 [28107] 1gsu1C-003dCu-Hb <= aaron@domain.com ' +
155
+ 'H=localhost (10.5.40.204) [127.0.0.1]:39753 I=[127.0.0.1]:25 ' +
156
+ 'P=esmtpa A=dovecot_plain:aaron@domain.com S=4315 M8S=0 id=d2b648f00f1a1b0813c483d552778dc6@domain.com ' +
157
+ "T=\"what's up?!? ;-)\" from <aaron@domain.com> for aaron+forward@domain.com"
158
+ end
159
+
160
+ it "matches" do
161
+ if ecs_compatibility?
162
+ expect(grok).to include("exim"=>{"log"=>hash_including(
163
+ "message"=>hash_including("id"=>"1gsu1C-003dCu-Hb", "subject"=>"what's up?!? ;-)"),
164
+ )})
165
+ expect(grok).to include("destination"=>{"ip"=>"127.0.0.1", "port"=>25})
166
+ expect(grok).to include("exim"=>{"log"=>hash_including(
167
+ "sender"=>{"email"=>"aaron@domain.com", 'original'=>'aaron@domain.com'}
168
+ )})
169
+ expect(grok).to include("exim"=>{"log"=>hash_including("recipient"=>{"email"=>"aaron+forward@domain.com"})})
170
+ expect(grok).to include("source"=>{"address"=>"localhost", "ip"=>"127.0.0.1", "port"=>39753})
171
+ expect(grok).to include("exim"=>{"log" => hash_including("remote_address"=>'10.5.40.204')})
172
+ else
173
+ expect(grok).to include(
174
+ "exim_msgid"=>"1gsu1C-003dCu-Hb",
175
+ "exim_sender_email"=>"aaron@domain.com",
176
+ "exim_flags"=>"<=",
177
+ "protocol"=>"esmtpa"
178
+ )
179
+ expect(grok).to include(
180
+ "remote_host"=>"127.0.0.1", "remote_port"=>"39753",
181
+ "remote_heloname"=>"10.5.40.204",
182
+ "remote_hostname"=>"localhost"
183
+ )
184
+ end
185
+ end
186
+
187
+ end
188
+
189
+ context 'delivery failed' do
190
+
191
+ let(:message) do
192
+ '2020-02-11 17:09:47 1j1Z2g-00Faoy-Uh ** admin@example.net R=virtual_aliases: No such person at this address.'
193
+ end
194
+
195
+ it "does not parse" do # matching not implemented
196
+ expect(grok['tags']).to include("_grokparsefailure")
197
+ end
198
+
199
+ end
200
+
201
+ end
@@ -2,94 +2,185 @@
2
2
  require "spec_helper"
3
3
  require "logstash/patterns/core"
4
4
 
5
- describe "FIREWALLS" do
5
+ CISCOFW_ALLOWED_TOP_LEVEL_NAMESPACES = ['event', 'cisco', 'observer', 'source', 'destination'].freeze
6
6
 
7
+ describe_pattern "CISCOFW104001", ['legacy', 'ecs-v1'] do
7
8
 
8
- let(:pattern104001) { "CISCOFW104001" }
9
+ let(:message) { "(Secondary) Switching to ACTIVE - Service card in other unit has failed" }
9
10
 
10
- context "parsing a 104001 message" do
11
+ include_examples 'top-level namespaces', ['event'], if: -> { ecs_compatibility? }
11
12
 
12
- let(:value) { "(Secondary) Switching to ACTIVE - Service card in other unit has failed" }
13
+ it { expect(subject).to include("switch_reason" => "Service card in other unit has failed") unless ecs_compatibility? }
13
14
 
14
- subject { grok_match(pattern104001, value) }
15
+ it "keeps message field" do
16
+ expect(subject["message"]).to eql message
17
+ end
18
+
19
+ end
20
+
21
+ describe_pattern "CISCOFW106001", ['legacy', 'ecs-v1'] do
15
22
 
16
- it { should include("switch_reason" => "Service card in other unit has failed") }
23
+ let(:message) { "ASA-2-106001: Inbound TCP connection denied from 192.168.2.2/43803 to 10.10.10.10/14322 flags SYN on interface out111" }
17
24
 
18
- it "generates a message field" do
19
- expect(subject["message"]).to include("(Secondary) Switching to ACTIVE - Service card in other unit has failed")
25
+ include_examples 'top-level namespaces', CISCOFW_ALLOWED_TOP_LEVEL_NAMESPACES, if: -> { ecs_compatibility? }
26
+
27
+ it 'matches' do
28
+ if ecs_compatibility?
29
+ expect(subject).to include "source"=>{"ip"=>"192.168.2.2", "port"=>43803}
30
+ expect(subject).to include "destination"=>{"ip"=>"10.10.10.10", "port"=>14322}
31
+ expect(subject).to include "observer"=>{"egress"=>{"interface"=>{"name"=>"out111"}}}
32
+ expect(subject).to include "cisco"=>{"asa"=>hash_including("network"=>{"transport"=>"TCP", "direction"=>"Inbound"}, "tcp_flags"=>"SYN")}
33
+ else
34
+ expect(subject).to include("src_ip"=>"192.168.2.2", "src_port"=>'43803')
20
35
  end
21
36
  end
22
-
23
- let(:pattern106015) { "CISCOFW106015" }
24
37
 
25
- context "parsing a 106015 message" do
38
+ it "keeps message field" do
39
+ expect(subject["message"]).to eql message
40
+ end
41
+
42
+ end
26
43
 
27
- let(:value) { "Deny TCP (no connection) from 192.168.150.65/2278 to 64.101.128.83/80 flags RST on interface inside" }
44
+ describe_pattern "CISCOFW106006_106007_106010", ['legacy', 'ecs-v1'] do
28
45
 
29
- subject { grok_match(pattern106015, value) }
46
+ let(:message) { "ASA-2-106006: Deny inbound UDP from 192.168.2.2/65020 to 10.10.10.10/65021 on interface fw111" }
30
47
 
31
- it { should include("interface" => "inside") }
48
+ include_examples 'top-level namespaces', CISCOFW_ALLOWED_TOP_LEVEL_NAMESPACES, if: -> { ecs_compatibility? }
32
49
 
33
- it "generates a message field" do
34
- expect(subject["message"]).to include("Deny TCP (no connection) from 192.168.150.65/2278 to 64.101.128.83/80 flags RST on interface inside")
50
+ it 'matches' do
51
+ if ecs_compatibility?
52
+ expect(subject).to include "cisco" => {"asa"=>{"network"=>{"direction"=>"inbound", "transport"=>"UDP"}, "outcome"=>"Deny"}}
53
+ expect(subject).to include "source"=>{"ip"=>"192.168.2.2", "port"=>65020}
54
+ expect(subject).to include "destination"=>{"ip"=>"10.10.10.10", "port"=>65021}
55
+ expect(subject).to include "observer"=>{"egress"=>{"interface"=>{"name"=>"fw111"}}}
56
+ else
57
+ expect(subject).to include("src_ip"=>"192.168.2.2", "src_port"=>'65020')
35
58
  end
36
59
  end
37
60
 
38
- let(:pattern106100) { "CISCOFW106100" }
61
+ it "keeps message field" do
62
+ expect(subject["message"]).to eql message
63
+ end
39
64
 
40
- context "parsing a 106100 message" do
65
+ end
41
66
 
42
- let(:value) { "access-list inside permitted tcp inside/10.10.123.45(51763) -> outside/192.168.67.89(80) hit-cnt 1 first hit [0x62c4905, 0x0]" }
67
+ describe_pattern "CISCOFW106014", ['legacy', 'ecs-v1'] do
43
68
 
44
- subject { grok_match(pattern106100, value) }
69
+ let(:message) { "ASA-3-106014: Deny inbound icmp src fw111:10.10.10.10 dst fw111:10.10.10.11(type 8, code 0)" }
45
70
 
46
- it { should include("policy_id" => "inside") }
71
+ include_examples 'top-level namespaces', CISCOFW_ALLOWED_TOP_LEVEL_NAMESPACES, if: -> { ecs_compatibility? }
47
72
 
48
- it "generates a message field" do
49
- expect(subject["message"]).to include("access-list inside permitted tcp inside/10.10.123.45(51763) -> outside/192.168.67.89(80) hit-cnt 1 first hit [0x62c4905, 0x0]")
73
+ it 'matches' do
74
+ if ecs_compatibility?
75
+ expect(subject).to include "source"=>{"ip"=>"10.10.10.10"}
76
+ expect(subject).to include "destination"=>{"ip"=>"10.10.10.11"}
77
+ expect(subject).to include "cisco"=>{"asa"=>{"outcome"=>"Deny", "network"=>{"transport"=>"icmp", "direction"=>"inbound"}, "icmp_code"=>0, "icmp_type"=>8}}
78
+ expect(subject).to include "observer"=>{"ingress"=>{"interface"=>{"name"=>"fw111"}}, "egress"=>{"interface"=>{"name"=>"fw111"}}}
79
+ else
80
+ # NOTE: does not match due expecting space: "10.10.10.11 (type 8, code 0)"
50
81
  end
51
82
  end
52
83
 
53
- let(:pattern106100) { "CISCOFW106100" }
84
+ it "keeps message field" do
85
+ expect(subject["message"]).to eql message
86
+ end
54
87
 
55
- context "parsing a 106100 message with hypen in acl name" do
88
+ end
56
89
 
57
- let(:value) { "access-list outside-entry permitted tcp outside/10.11.12.13(54726) -> inside/192.168.17.18(80) hit-cnt 1 300-second interval [0x32b3835, 0x0]" }
90
+ describe_pattern "CISCOFW106015", ['legacy', 'ecs-v1'] do
58
91
 
59
- subject { grok_match(pattern106100, value) }
92
+ let(:message) { "Deny TCP (no connection) from 192.168.150.65/2278 to 64.101.128.83/80 flags RST on interface eth0" }
60
93
 
61
- it { should include("policy_id" => "outside-entry") }
94
+ include_examples 'top-level namespaces', CISCOFW_ALLOWED_TOP_LEVEL_NAMESPACES, if: -> { ecs_compatibility? }
62
95
 
63
- it "generates a message field" do
64
- expect(subject["message"]).to include("access-list outside-entry permitted tcp outside/10.11.12.13(54726) -> inside/192.168.17.18(80) hit-cnt 1 300-second interval [0x32b3835, 0x0]")
96
+ it 'matches' do
97
+ if ecs_compatibility?
98
+ expect(subject).to include "observer"=>{"egress"=>{"interface"=>{"name"=>"eth0"}}}
99
+ else
100
+ expect(subject).to include("interface" => "eth0")
65
101
  end
66
102
  end
67
103
 
68
- let(:pattern304001) { "CISCOFW304001" }
104
+ it "keeps message field" do
105
+ expect(subject["message"]).to eql message
106
+ end
107
+
108
+ end
69
109
 
70
- context "parsing a 304001 message" do
110
+ describe_pattern "CISCOFW106021", ['legacy', 'ecs-v1'] do
71
111
 
72
- let(:value) { "10.20.30.40(DOMAIN\\login) Accessed URL 10.11.12.13:http://example.org/" }
112
+ let(:message) { "ASA-4-106021: Deny TCP reverse path check from 192.168.2.2 to 10.10.10.10 on interface fw111" }
73
113
 
74
- subject { grok_match(pattern304001, value) }
114
+ include_examples 'top-level namespaces', CISCOFW_ALLOWED_TOP_LEVEL_NAMESPACES, if: -> { ecs_compatibility? }
75
115
 
76
- it 'should break the message up into fields' do
77
- expect(subject['src_ip']).to eq('10.20.30.40')
78
- expect(subject['src_fwuser']).to eq('DOMAIN\\login')
79
- expect(subject['dst_ip']).to eq('10.11.12.13')
80
- expect(subject['dst_url']).to eq('http://example.org/')
116
+ it 'matches' do
117
+ if ecs_compatibility?
118
+ expect(subject).to include "source"=>{"ip"=>"192.168.2.2"}, "destination"=>{"ip"=>"10.10.10.10"}
119
+ expect(subject).to include "cisco"=>{"asa"=>{"network"=>{"transport"=>"TCP"}, "outcome"=>"Deny"}}
120
+ expect(subject).to include "observer"=>{"egress"=>{"interface"=>{"name"=>"fw111"}}}
121
+ else
122
+ expect(subject).to include("interface" => "fw111")
81
123
  end
82
124
  end
83
125
 
84
- let(:pattern106023) { "CISCOFW106023" }
126
+ it "keeps message field" do
127
+ expect(subject["message"]).to eql message
128
+ end
129
+
130
+ end
131
+
132
+ describe_pattern "CISCOFW106100", ['legacy', 'ecs-v1'] do
85
133
 
86
- context "parsing a 106023 message" do
134
+ let(:message) { "access-list inside permitted tcp inside/10.10.123.45(51763) -> outside/192.168.67.89(80) hit-cnt 1 first hit [0x62c4905, 0x0]" }
87
135
 
88
- let(:value) { 'Deny tcp src outside:192.168.1.1/50240 dst inside:192.168.1.2/23 by access-group "S_OUTSIDE_TO_INSIDE" [0x54c7fa80, 0x0]' }
136
+ include_examples 'top-level namespaces', CISCOFW_ALLOWED_TOP_LEVEL_NAMESPACES, if: -> { ecs_compatibility? }
89
137
 
90
- subject { grok_match(pattern106023, value) }
138
+ it 'matches' do
139
+ if ecs_compatibility?
140
+ expect(subject).to include("cisco"=>{"asa"=>hash_including("rule_name" => "inside")})
141
+ else
142
+ expect(subject).to include("policy_id" => "inside")
143
+ end
144
+ end
91
145
 
92
- it 'should break the message up into fields' do
146
+ it "keeps message field" do
147
+ expect(subject["message"]).to eql message
148
+ end
149
+
150
+ end
151
+
152
+ describe_pattern "CISCOFW106100", ['legacy', 'ecs-v1'] do
153
+
154
+ let(:message) { "access-list outside-entry permitted tcp outside/10.11.12.13(54726) -> inside/192.168.17.18(80) hit-cnt 1 300-second interval [0x32b3835, 0x0]" }
155
+
156
+ include_examples 'top-level namespaces', CISCOFW_ALLOWED_TOP_LEVEL_NAMESPACES, if: -> { ecs_compatibility? }
157
+
158
+ it 'matches' do
159
+ if ecs_compatibility?
160
+ expect(subject).to include("cisco"=>{"asa"=>hash_including("rule_name" => "outside-entry")})
161
+ else
162
+ expect(subject).to include("policy_id" => "outside-entry")
163
+ end
164
+ end
165
+
166
+ it "keeps message field" do
167
+ expect(subject["message"]).to eql message
168
+ end
169
+
170
+ end
171
+
172
+ describe_pattern "CISCOFW106023", ['legacy', 'ecs-v1'] do
173
+
174
+ let(:message) { 'Deny tcp src outside:192.168.1.1/50240 dst inside:192.168.1.2/23 by access-group "S_OUTSIDE_TO_INSIDE" [0x54c7fa80, 0x0]' }
175
+
176
+ include_examples 'top-level namespaces', CISCOFW_ALLOWED_TOP_LEVEL_NAMESPACES, if: -> { ecs_compatibility? }
177
+
178
+ it 'matches' do
179
+ if ecs_compatibility?
180
+ expect(subject).to include "source"=>{"ip"=>"192.168.1.1", "port"=>50240}
181
+ expect(subject).to include "observer"=>{"egress"=>{"interface"=>{"name"=>"inside"}}, "ingress"=>{"interface"=>{"name"=>"outside"}}}
182
+ expect(subject).to include "cisco"=>{"asa"=>{"outcome"=>"Deny", "network"=>{"transport"=>"tcp"}, "rule_name"=>"S_OUTSIDE_TO_INSIDE"}}
183
+ else
93
184
  expect(subject['action']).to eq('Deny')
94
185
  expect(subject['src_interface']).to eq('outside')
95
186
  expect(subject['dst_interface']).to eq('inside')
@@ -100,37 +191,549 @@ describe "FIREWALLS" do
100
191
  end
101
192
  end
102
193
 
103
- context "parsing a 106023 message with a protocol number" do
194
+ context "a message with a protocol number" do
195
+
196
+ let(:message) { 'Deny protocol 103 src outside:192.168.1.1/50240 dst inside:192.168.1.2/23 by access-group "S_OUTSIDE_TO_INSIDE" [0x54c7fa80, 0x0]' }
197
+
198
+ it 'matches' do
199
+ if ecs_compatibility?
200
+ expect(subject).to include "destination"=>{"ip"=>"192.168.1.2", "port"=>23},
201
+ "cisco"=>{"asa"=>{"outcome"=>"Deny", "network"=>{"transport"=>"103"}, "rule_name"=>"S_OUTSIDE_TO_INSIDE"}}
202
+ else
203
+ expect(subject['action']).to eq('Deny')
204
+ expect(subject['src_interface']).to eq('outside')
205
+ expect(subject['dst_interface']).to eq('inside')
206
+ expect(subject['protocol']).to eq('103')
207
+ expect(subject['src_ip']).to eq('192.168.1.1')
208
+ expect(subject['dst_ip']).to eq('192.168.1.2')
209
+ expect(subject['policy_id']).to eq('S_OUTSIDE_TO_INSIDE')
210
+ end
211
+ end
212
+ end
104
213
 
105
- let(:value) { 'Deny protocol 103 src outside:192.168.1.1/50240 dst inside:192.168.1.2/23 by access-group "S_OUTSIDE_TO_INSIDE" [0x54c7fa80, 0x0]' }
106
214
 
107
- subject { grok_match(pattern106023, value) }
215
+ context "a message with a hostname" do
216
+
217
+ let(:message) { 'Deny tcp src outside:192.168.1.1/50240 dst inside:www.example.com/23 by access-group "S_OUTSIDE_TO_INSIDE" [0x54c7fa80, 0x0]' }
218
+
219
+ it 'matches' do
220
+ if ecs_compatibility?
221
+ expect(subject).to include "destination"=>{"port"=>23, "address"=>"www.example.com"}
222
+ expect(subject).to include "source"=>{"port"=>50240, "ip"=>"192.168.1.1"}
223
+ expect(subject).to include "observer"=>{"ingress"=>{"interface"=>{"name"=>"outside"}}, "egress"=>{"interface"=>{"name"=>"inside"}}}
224
+ else
225
+ expect(subject['action']).to eq('Deny')
226
+ expect(subject['src_interface']).to eq('outside')
227
+ expect(subject['dst_interface']).to eq('inside')
228
+ expect(subject['protocol']).to eq('tcp')
229
+ expect(subject['src_ip']).to eq('192.168.1.1')
230
+ expect(subject['dst_ip']).to eq('www.example.com')
231
+ expect(subject['policy_id']).to eq('S_OUTSIDE_TO_INSIDE')
232
+ end
233
+ end
234
+ end
108
235
 
109
- it 'should break the message up into fields' do
110
- expect(subject['action']).to eq('Deny')
111
- expect(subject['src_interface']).to eq('outside')
112
- expect(subject['dst_interface']).to eq('inside')
113
- expect(subject['protocol']).to eq('103')
114
- expect(subject['src_ip']).to eq('192.168.1.1')
115
- expect(subject['dst_ip']).to eq('192.168.1.2')
116
- expect(subject['policy_id']).to eq('S_OUTSIDE_TO_INSIDE')
236
+ end
237
+
238
+ describe_pattern "CISCOFW304001", ['legacy', 'ecs-v1'] do
239
+
240
+ let(:message) { "10.20.30.40(DOMAIN\\login) Accessed URL 10.11.12.13:http://example.org/" }
241
+
242
+ include_examples 'top-level namespaces', CISCOFW_ALLOWED_TOP_LEVEL_NAMESPACES + ['url'], if: -> { ecs_compatibility? }
243
+
244
+ it 'matches' do
245
+ if ecs_compatibility?
246
+ expect(subject).to include "source"=>{"ip"=>"10.20.30.40", "user"=>{"name"=>"DOMAIN\\login"}}
247
+ expect(subject).to include "url"=>{"original"=>"http://example.org/"}
248
+ else
249
+ expect(subject['src_ip']).to eq('10.20.30.40')
250
+ expect(subject['src_fwuser']).to eq('DOMAIN\\login')
251
+ expect(subject['dst_ip']).to eq('10.11.12.13')
252
+ expect(subject['dst_url']).to eq('http://example.org/')
117
253
  end
118
254
  end
119
255
 
120
- context "parsing a 106023 message with a hostname" do
256
+ end
257
+
258
+ describe_pattern "CISCOFW110002", ['legacy', 'ecs-v1'] do
121
259
 
122
- let(:value) { 'Deny tcp src outside:192.168.1.1/50240 dst inside:www.example.com/23 by access-group "S_OUTSIDE_TO_INSIDE" [0x54c7fa80, 0x0]' }
260
+ let(:message) { "ASA-6-110002: Failed to locate egress interface for TCP from sourceInterfaceName:91.240.17.178/7777 to 192.168.2.2/123412" }
123
261
 
124
- subject { grok_match(pattern106023, value) }
262
+ include_examples 'top-level namespaces', CISCOFW_ALLOWED_TOP_LEVEL_NAMESPACES, if: -> { ecs_compatibility? }
125
263
 
126
- it 'should break the message up into fields' do
127
- expect(subject['action']).to eq('Deny')
128
- expect(subject['src_interface']).to eq('outside')
129
- expect(subject['dst_interface']).to eq('inside')
130
- expect(subject['protocol']).to eq('tcp')
131
- expect(subject['src_ip']).to eq('192.168.1.1')
132
- expect(subject['dst_ip']).to eq('www.example.com')
133
- expect(subject['policy_id']).to eq('S_OUTSIDE_TO_INSIDE')
264
+ it 'matches' do
265
+ if ecs_compatibility?
266
+ expect(subject).to include "event"=>{"reason"=>"Failed to locate egress interface"}
267
+ expect(subject).to include "cisco"=>{"asa"=>{"network"=>{"transport"=>"TCP"}}}
268
+ expect(subject).to include "source"=>{"port"=>7777, "ip"=>"91.240.17.178"}
269
+ expect(subject).to include "observer"=>{"ingress"=>{"interface"=>{"name"=>"sourceInterfaceName"}}}
270
+ expect(subject).to include "destination"=>{"port"=>123412, "ip"=>"192.168.2.2"}
271
+ else
272
+ expect(subject['src_ip']).to eq('91.240.17.178')
273
+ expect(subject['dst_ip']).to eq('192.168.2.2')
274
+ end
275
+ end
276
+
277
+ end
278
+
279
+ describe_pattern "CISCOFW302013_302014_302015_302016", ['legacy', 'ecs-v1'] do
280
+
281
+ let(:message) { "ASA-6-302013: Built outbound TCP connection 11757 for outside:100.66.205.104/80 (100.66.205.104/80) to inside:172.31.98.44/1772 (172.31.98.44/1772)" }
282
+
283
+ include_examples 'top-level namespaces', CISCOFW_ALLOWED_TOP_LEVEL_NAMESPACES, if: -> { ecs_compatibility? }
284
+
285
+ it 'matches' do
286
+ if ecs_compatibility?
287
+ expect(subject).to include "source"=>{"ip"=>"100.66.205.104", "port"=>80, "nat"=>{"ip"=>"100.66.205.104", "port"=>80}}
288
+ expect(subject).to include "cisco"=>{"asa"=>{"network"=>{"direction"=>"outbound", "transport"=>"TCP"}, "outcome"=>"Built", "connection_id"=>"11757"}}
289
+ expect(subject).to include "observer"=>{"egress"=>{"interface"=>{"name"=>"inside"}}, "ingress"=>{"interface"=>{"name"=>"outside"}}}
290
+ else
291
+ expect(subject['src_ip']).to eq('100.66.205.104')
292
+ expect(subject['dst_ip']).to eq('172.31.98.44')
293
+ end
294
+ end
295
+
296
+ end
297
+
298
+ describe_pattern "CISCOFW302020_302021", ['legacy', 'ecs-v1'] do
299
+
300
+ let(:message) { "302020: Built inbound ICMP connection for faddr 10.137.200.251/18425 gaddr 10.137.10.1/0 laddr 10.137.10.10/0" }
301
+
302
+ include_examples 'top-level namespaces', CISCOFW_ALLOWED_TOP_LEVEL_NAMESPACES, if: -> { ecs_compatibility? }
303
+
304
+ it 'matches' do
305
+ if ecs_compatibility?
306
+ expect(subject).to include("cisco"=>{"asa"=>{
307
+ "outcome"=>"Built", "icmp_seq"=>18425, "network"=>{"direction"=>"inbound", "transport"=>"ICMP"}, "icmp_type"=>0
308
+ }})
309
+ expect(subject).to include("source"=>{"nat"=>{"ip"=>"10.137.10.1"}, "ip"=>"10.137.10.10"}, "destination"=>{"ip"=>"10.137.200.251"})
310
+ else
311
+ expect(subject['src_ip']).to eq('10.137.10.10')
312
+ expect(subject['dst_ip']).to eq('10.137.200.251')
313
+ end
314
+ end
315
+
316
+ context '302021' do
317
+
318
+ let(:message) { "6|Nov 28 2014 12:59:03|302021: Teardown ICMP connection for faddr 10.137.200.251/18425 gaddr 10.137.10.1/0 laddr 10.137.10.10/0" }
319
+
320
+ it 'matches' do
321
+ if ecs_compatibility?
322
+ expect(subject).to include "cisco"=>{"asa"=>{"outcome"=>"Teardown", "network"=>{"transport"=>"ICMP"}, "icmp_seq"=>18425, "icmp_type"=>0}}
323
+ expect(subject).to include "source"=>{"nat"=>{"ip"=>"10.137.10.1"}, "ip"=>"10.137.10.10"}, "destination"=>{"ip"=>"10.137.200.251"}
324
+ else
325
+ expect(subject['src_ip']).to eq('10.137.10.10')
326
+ expect(subject['dst_ip']).to eq('10.137.200.251')
327
+ end
328
+ end
329
+
330
+ end
331
+
332
+ end
333
+
334
+ describe_pattern "CISCOFW305011", ['legacy', 'ecs-v1'] do
335
+
336
+ let(:message) { "Built dynamic TCP translation from inside:172.31.98.44/1772 to outside:100.66.98.44/8256" }
337
+
338
+ include_examples 'top-level namespaces', CISCOFW_ALLOWED_TOP_LEVEL_NAMESPACES, if: -> { ecs_compatibility? }
339
+
340
+ it 'matches' do
341
+ if ecs_compatibility?
342
+ expect(subject).to include "source"=>{"ip"=>"172.31.98.44", "port"=>1772}
343
+ expect(subject).to include "destination"=>{"ip"=>"100.66.98.44", "port"=>8256}
344
+ expect(subject).to include "observer"=>{"ingress"=>{"interface"=>{"name"=>"inside"}}, "egress"=>{"interface"=>{"name"=>"outside"}}}
345
+ expect(subject).to include "cisco"=>{"asa"=>{"network"=>{"transport"=>"TCP"}, "outcome"=>"Built"}}
346
+ else
347
+ expect(subject['src_ip']).to eq('172.31.98.44')
348
+ expect(subject['src_xlated_ip']).to eq('100.66.98.44')
349
+ expect(subject).to include "src_xlated_interface"=>"outside", "src_interface"=>"inside"
350
+ end
351
+ end
352
+
353
+ end
354
+
355
+ describe_pattern "CISCOFW313001_313004_313008", ['legacy', 'ecs-v1'] do
356
+
357
+ let(:message) { "ASA-3-313001: Denied ICMP type=3, code=3 from 10.2.3.5 on interface Outside" }
358
+
359
+ include_examples 'top-level namespaces', CISCOFW_ALLOWED_TOP_LEVEL_NAMESPACES, if: -> { ecs_compatibility? }
360
+
361
+ it 'matches' do
362
+ if ecs_compatibility?
363
+ expect(subject).to include "source"=>{"ip"=>"10.2.3.5"}
364
+ expect(subject).to include "cisco"=>{"asa"=>{"outcome"=>"Denied", "network"=>{"transport"=>"ICMP"}, "icmp_type"=>3, "icmp_code"=>3}}
365
+ else
366
+ expect(subject['src_ip']).to eq('10.2.3.5')
367
+ end
368
+ end
369
+
370
+ end
371
+
372
+ describe_pattern "CISCOFW313005", ['legacy', 'ecs-v1'] do
373
+
374
+ let(:message) do
375
+ "No matching connection for ICMP error message: icmp src fw111:10.192.33.100 dst fw111:192.18.4.1 (type 3, code 3) " +
376
+ "on fw111 interface. Original IP payload: udp src 192.18.4.1/53 dst 8.8.8.8/10872."
377
+ end
378
+
379
+ include_examples 'top-level namespaces', CISCOFW_ALLOWED_TOP_LEVEL_NAMESPACES, if: -> { ecs_compatibility? }
380
+
381
+ it 'matches' do
382
+ if ecs_compatibility?
383
+ expect(subject).to include "event"=>{"reason"=>"No matching connection"}
384
+ expect(subject).to include "source"=>{"ip"=>"10.192.33.100"}, "destination"=>{"ip"=>"192.18.4.1"}
385
+ expect(subject).to include "observer"=>{"ingress"=>{"interface"=>{"name"=>"fw111"}}, "egress"=>{"interface"=>{"name"=>"fw111"}}}
386
+
387
+ expect(subject).to include("cisco"=>{"asa"=>{
388
+ "icmp_type"=>3, "icmp_code"=>3, "network"=>{"transport"=>"ICMP"},
389
+ "original_ip_payload"=>{
390
+ "destination"=>{"ip"=>"8.8.8.8", "port"=>10872},
391
+ "network"=>{"transport"=>"udp"},
392
+ "source"=>{"ip"=>"192.18.4.1", "port"=>53}
393
+ }
394
+ }})
395
+ else
396
+ # YAY, fails to match!
397
+ end
398
+ end
399
+
400
+ end
401
+
402
+ describe_pattern "CISCOFW402117", ['legacy', 'ecs-v1'] do
403
+
404
+ let(:message) do
405
+ "%ASA-4-402117: IPSEC: Received a non-IPSec packet (protocol= ICMP) from 10.5.1.127 to 192.168.6.102."
406
+ end
407
+
408
+ include_examples 'top-level namespaces', ['cisco', 'source', 'destination'], if: -> { ecs_compatibility? }
409
+
410
+ it 'matches' do
411
+ if ecs_compatibility?
412
+ expect(subject).to include("cisco"=>{"asa"=>{"network"=>{"transport"=>"ICMP", "type"=>"IPSEC"}}},
413
+ "source"=>{"ip"=>"10.5.1.127"}, "destination"=>{"ip"=>"192.168.6.102"})
414
+
415
+ else
416
+ expect(subject).to include "src_ip"=>"10.5.1.127", "orig_protocol"=>"ICMP", "protocol"=>"IPSEC", "dst_ip"=>"192.168.6.102"
417
+ end
418
+ end
419
+
420
+ end
421
+
422
+ describe_pattern "CISCOFW402119", ['legacy', 'ecs-v1'] do
423
+
424
+ let(:message) do
425
+ "%ASA-4-402119: IPSEC: Received an ESP packet (SPI= 0x1B86506B, sequence number= 0x28B) from 68.18.122.4 (user= Bangalo) to 10.10.1.1 that failed anti-replay checking."
426
+ end
427
+
428
+ include_examples 'top-level namespaces', ['cisco', 'source', 'destination'], if: -> { ecs_compatibility? }
429
+
430
+ it 'matches' do
431
+ if ecs_compatibility?
432
+ expect(subject).to include "destination"=>{"ip"=>"10.10.1.1"},
433
+ "cisco"=>{"asa"=>{
434
+ "ipsec"=>{"spi"=>"0x1B86506B", "protocol"=>"ESP", "seq_num"=>"0x28B"},
435
+ "network"=>{"type"=>"IPSEC"}
436
+ }},
437
+ "source"=>{"ip"=>"68.18.122.4", "user"=>{"name"=>"Bangalo"}}
438
+ else
439
+ expect(subject).to include "dst_ip"=>"10.10.1.1", "src_ip"=>"68.18.122.4",
440
+ "spi"=>"0x1B86506B", "seq_num"=>"0x28B",
441
+ "protocol"=>"IPSEC", "orig_protocol"=>"ESP",
442
+ "user"=>"Bangalo"
443
+ end
444
+ end
445
+
446
+ end
447
+
448
+ describe_pattern "CISCOFW419001", ['legacy', 'ecs-v1'] do
449
+
450
+ let(:message) do
451
+ "%ASA-4-419001: Dropping TCP packet from outside:65.55.184.155/80 to inside:192.168.10.11/49043, reason: MSS exceeded, MSS 1380, data 1460"
452
+ end
453
+
454
+ include_examples 'top-level namespaces', CISCOFW_ALLOWED_TOP_LEVEL_NAMESPACES, if: -> { ecs_compatibility? }
455
+
456
+ it 'matches' do
457
+ if ecs_compatibility?
458
+ expect(subject).to include("source"=>{"port"=>80, "ip"=>"65.55.184.155"},
459
+ "destination"=>{"port"=>49043, "ip"=>"192.168.10.11"},
460
+ "cisco"=>{"asa"=>{
461
+ "outcome"=>"Dropping", "network"=>{"transport"=>"TCP"}
462
+ }},
463
+ "observer"=>{
464
+ "ingress"=>{"interface"=>{"name"=>"outside"}},
465
+ "egress"=>{"interface"=>{"name"=>"inside"}}
466
+ })
467
+ expect(subject).to include "event"=>{"reason"=>"MSS exceeded, MSS 1380, data 1460"}
468
+ else
469
+ expect(subject).to include "src_ip"=>"65.55.184.155", "src_port"=>"80", "src_interface"=>"outside",
470
+ "dst_ip"=>"192.168.10.11", "dst_port"=>"49043", "dst_interface"=>"inside",
471
+ "protocol"=>"TCP", "action"=>"Dropping",
472
+ "reason"=>"MSS exceeded, MSS 1380, data 1460"
473
+ end
474
+ end
475
+
476
+ end
477
+
478
+ describe_pattern "CISCOFW419002", ['legacy', 'ecs-v1'] do
479
+
480
+ let(:message) do
481
+ "%ASA-4-419002: Duplicate TCP SYN from OUTSIDE:10.10.66.2/65087 to INSIDE:10.10.1.6/443 with different initial sequence number."
482
+ end
483
+
484
+ include_examples 'top-level namespaces', CISCOFW_ALLOWED_TOP_LEVEL_NAMESPACES, if: -> { ecs_compatibility? }
485
+
486
+ it 'matches' do
487
+ if ecs_compatibility?
488
+ expect(subject).to include "event"=>{"reason"=>"Duplicate TCP SYN"},
489
+ "source"=>{"port"=>65087, "ip"=>"10.10.66.2"},
490
+ "destination"=>{"port"=>443, "ip"=>"10.10.1.6"},
491
+ "observer"=>{"egress"=>{"interface"=>{"name"=>"INSIDE"}}, "ingress"=>{"interface"=>{"name"=>"OUTSIDE"}}}
492
+ else
493
+ expect(subject).to include "src_ip"=>"10.10.66.2", "src_port"=>"65087", "src_interface"=>"OUTSIDE",
494
+ "dst_ip"=>"10.10.1.6", "dst_port"=>"443", "dst_interface"=>"INSIDE",
495
+ "reason"=>"Duplicate TCP SYN"
496
+ end
497
+ end
498
+
499
+ end
500
+
501
+ describe_pattern "CISCOFW602303_602304", ['legacy', 'ecs-v1'] do
502
+
503
+ let(:message) do
504
+ "%ASA-6-602303: IPSEC: An outbound LAN-to-LAN SA (SPI= 0xF81283) between 91.240.17.178 and 192.168.2.2 (user= admin) has been created."
505
+ end
506
+
507
+ include_examples 'top-level namespaces', CISCOFW_ALLOWED_TOP_LEVEL_NAMESPACES, if: -> { ecs_compatibility? }
508
+
509
+ it 'matches' do
510
+ if ecs_compatibility?
511
+ expect(subject).to include("cisco"=>{"asa"=>{
512
+ "network"=>{"direction"=>"outbound", "type"=>"IPSEC"},
513
+ "outcome"=>"created",
514
+ "ipsec"=>{"spi"=>"0xF81283", "tunnel_type"=>"LAN-to-LAN"}}},
515
+ "destination"=>{"ip"=>"192.168.2.2"},
516
+ "source"=>{"ip"=>"91.240.17.178", "user"=>{"name"=>"admin"}})
517
+ else
518
+ expect(subject).to include "protocol"=>"IPSEC", "direction"=>"outbound", "tunnel_type"=>"LAN-to-LAN",
519
+ "src_ip"=>"91.240.17.178", "dst_ip"=>"192.168.2.2",
520
+ "spi"=>"0xF81283", "user"=>"admin", "action"=>"created"
521
+ end
522
+ end
523
+
524
+ end
525
+
526
+ describe_pattern "CISCOFW710001_710002_710003_710005_710006", ['legacy', 'ecs-v1'] do
527
+
528
+ let(:message) do
529
+ "%PIX-7-710001: TCP access requested from 192.168.1.2/2354 to inside:192.168.1.1/443"
530
+ end
531
+
532
+ include_examples 'top-level namespaces', CISCOFW_ALLOWED_TOP_LEVEL_NAMESPACES, if: -> { ecs_compatibility? }
533
+
534
+ it 'matches' do
535
+ if ecs_compatibility?
536
+ expect(subject).to include("source"=>{"ip"=>"192.168.1.2", "port"=>2354})
537
+ expect(subject).to include("destination"=>{"ip"=>"192.168.1.1", "port"=>443})
538
+ expect(subject).to include("observer"=>{"egress"=>{"interface"=>{"name"=>"inside"}}},
539
+ "cisco"=>{"asa"=>{"outcome"=>"requested", "network"=>{"transport"=>"TCP"}}})
540
+ else
541
+ expect(subject).to include "src_ip"=>"192.168.1.2", "src_port"=>"2354",
542
+ "dst_ip"=>"192.168.1.1", "dst_port"=>"443", "dst_interface"=>"inside",
543
+ "action"=>"requested"
134
544
  end
135
545
  end
546
+
547
+ end
548
+
549
+ describe_pattern "CISCOFW713172", ['legacy', 'ecs-v1'] do
550
+
551
+ let(:message) do
552
+ "%ASA-6-713172: Group = 212.9.5.245, IP = 212.9.5.245, Automatic NAT Detection Status: " +
553
+ "Remote end is NOT behind a NAT device This end IS behind a NAT device"
554
+ end
555
+
556
+ include_examples 'top-level namespaces', CISCOFW_ALLOWED_TOP_LEVEL_NAMESPACES, if: -> { ecs_compatibility? }
557
+
558
+ it 'matches' do
559
+ if ecs_compatibility?
560
+ expect(subject).to include("source"=>{"ip"=>"212.9.5.245"}, "cisco"=>{"asa"=>{"source"=>{"group"=>"212.9.5.245"}}})
561
+ expect(event.get('@metadata')).to include "cisco"=>{"asa"=>{"local_nat"=>"IS", "remote_nat"=>"is NOT"}} # needs processing
562
+ else
563
+ expect(subject).to include("group"=>"212.9.5.245", "src_ip"=>"212.9.5.245",
564
+ "is_local_natted"=>"IS", "is_remote_natted"=>"is NOT")
565
+ end
566
+ end
567
+
568
+ end
569
+
570
+ describe_pattern "CISCOFW733100", ['legacy', 'ecs-v1'] do
571
+
572
+ let(:message) do
573
+ "%ASA-4-733100: [192.168.2.2] drop rate-1 exceeded. Current burst rate is 0 per second, max configured rate is -4; " +
574
+ "Current average rate is 7 per second, max configured rate is -5; Cumulative total count is 9063"
575
+ end
576
+
577
+ include_examples 'top-level namespaces', CISCOFW_ALLOWED_TOP_LEVEL_NAMESPACES, if: -> { ecs_compatibility? }
578
+
579
+ it 'matches' do
580
+ if ecs_compatibility?
581
+ expect(subject).to include "cisco"=>{"asa"=>{"burst"=>{
582
+ "object"=>"192.168.2.2", "id"=>"rate-1",
583
+ "configured_rate"=>-4, "current_rate"=>0,
584
+ "avg_rate"=>7, "configured_avg_rate"=>-5,
585
+ "cumulative_count"=>9063}}}
586
+ else
587
+ expect(subject).to include "drop_type"=>"192.168.2.2", "drop_rate_id"=>"rate-1",
588
+ "drop_rate_current_avg"=>"7",
589
+ "drop_total_count"=>"9063",
590
+ "drop_rate_current_burst"=>"0",
591
+ "drop_rate_max_burst"=>"-4",
592
+ "drop_rate_max_avg"=>"-5"
593
+ end
594
+ end
595
+
136
596
  end
597
+
598
+
599
+ describe_pattern 'SFW2', ['legacy', 'ecs-v1'] do
600
+
601
+ let(:message) do
602
+ "Jan 29 00:00:28 myth kernel: SFW2-INext-DROP-DEFLT IN=ppp0 OUT= MAC= SRC=24.64.208.134 DST=216.58.112.55 LEN=512 TOS=0x00 PREC=0x00 TTL=70 ID=55012 PROTO=UDP SPT=24128 DPT=1026 LEN=492"
603
+ end
604
+
605
+ it 'matches' do
606
+ # NOTE: we do not match the second LEN=492 which is the length of the wrapped (UDP in this case) packet
607
+ # iptables.length (IP packet length) 512 = 492 (UDP/TCP packet length) + 20 (IPv4 header length = 20 bytes)
608
+ if ecs_compatibility?
609
+ expect(grok).to include(
610
+ "timestamp"=>"Jan 29 00:00:28",
611
+ "observer"=>{"hostname"=>"myth", "ingress"=>{"interface"=>{"name"=>"ppp0"}}},
612
+ "suse"=>{"firewall"=>{"action"=>"DROP-DEFLT", "log_prefix"=>"SFW2-INext-DROP-DEFLT"}},
613
+ "source"=>{"ip"=>"24.64.208.134", "port"=>24128},
614
+ "destination"=>{"ip"=>"216.58.112.55", "port"=>1026},
615
+ "iptables"=>{
616
+ "length"=>512, # IP packet length
617
+ "id"=>"55012",
618
+ "ttl"=>70,
619
+ "tos"=>"00",
620
+ "precedence_bits"=>"00"
621
+ },
622
+ "network"=>{"transport"=>"UDP"}
623
+ )
624
+ else
625
+ expect(grok).to include(
626
+ "nf_action"=>"DROP-DEFLT",
627
+ "nf_in_interface"=>"ppp0",
628
+ "nf_src_ip"=>"24.64.208.134",
629
+ "nf_dst_ip"=>"216.58.112.55",
630
+ "nf_protocol"=>"UDP"
631
+ )
632
+ end
633
+ end
634
+
635
+ context 'long message' do
636
+
637
+ let(:message) do
638
+ 'Mar 8 20:16:44 black kernel: [20474.050964] SFW2-INext-ACC-TCP IN=eth0 OUT= MAC=28:45:a7:f3:18:00:00:22:15:67:6a:25:08:00 SRC=192.168.0.101 DST=192.168.0.100 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=6429 DF PROTO=TCP SPT=59282 DPT=631 WINDOW=14600 RES=0x00 SYN URGP=0 OPT (020405B40402080A00825F5D0000000001030307)'
639
+ end
640
+
641
+ it 'matches' do
642
+ if ecs_compatibility?
643
+ expect(grok).to include(
644
+ "timestamp"=>"Mar 8 20:16:44",
645
+ "observer"=>{"hostname"=>"black", "ingress"=>{"interface"=>{"name"=>"eth0"}}},
646
+ "suse"=>{"firewall"=>{"action"=>"ACC-TCP", "log_prefix"=>"SFW2-INext-ACC-TCP"}},
647
+ "source"=>{"mac"=>"00:22:15:67:6a:25", "ip"=>"192.168.0.101", "port"=>59282},
648
+ "destination"=>{"mac"=>"28:45:a7:f3:18:00", "ip"=>"192.168.0.100", "port"=>631},
649
+ "iptables"=>{
650
+ "length"=>60,
651
+ "id"=>"6429",
652
+ "tos"=>"00", "fragment_flags"=>"DF",
653
+ "ttl"=>64,
654
+ "precedence_bits"=>"00",
655
+ "tcp"=>{"flags"=>"SYN ", "window"=>14600},
656
+ "tcp_reserved_bits"=>"00"
657
+ },
658
+ "network"=>{"transport"=>"TCP"}
659
+ )
660
+ else
661
+ expect(grok).to include(
662
+ "nagios_epoch"=>"20474.050964", # YAY!
663
+ "nf_action"=>"ACC-TCP",
664
+ "nf_in_interface"=>"eth0",
665
+ "nf_dst_port"=>"631",
666
+
667
+ "nf_dst_mac"=>"28:45:a7:f3:18:00",
668
+ "nf_src_mac"=>"00:22:15:67:6a:25",
669
+ "nf_dst_ip"=>"192.168.0.100",
670
+ "nf_src_ip"=>"192.168.0.101",
671
+ "nf_src_port"=>"59282",
672
+
673
+ "nf_protocol"=>"TCP"
674
+ )
675
+ end
676
+ end
677
+
678
+ end
679
+
680
+ context 'alternate log-prefixes' do
681
+
682
+ describe 'SuSE-FW-DROP-DEFAULT' do # by default we only match SFW2-INext-*
683
+
684
+ let(:message) do
685
+ "Mar 8 22:35:42 linux kernel: SuSE-FW-DROP-DEFAULT IN=ppp0 OUT= MAC= SRC=202.175.181.4 DST=64.238.136.187 LEN=48 TOS=0x00 PREC=0x00 TTL=113 ID=31151 DF PROTO=TCP SPT=3360 DPT=3127 WINDOW=65340 RES=0x00 SYN URGP=0 OPT (020405AC01010402)"
686
+ end
687
+
688
+ it 'does not match' do
689
+ expect(grok['tags']).to include('_grokparsefailure')
690
+ end
691
+
692
+ end
693
+
694
+ describe 'SFW2-IN-ACC-RELATED' do
695
+
696
+ let(:message) do
697
+ "Jan 15 11:21:13 IKCSWeb kernel: SFW2-IN-ACC-RELATED IN=eth1 OUT= MAC=00:19:bb:2e:85:42:00:17:c5:d8:2e:2c:08:00 SRC=59.64.166.81 DST=207.194.99.122 LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=48949 DF PROTO=TCP SPT=24093 DPT=22 WINDOW=137 RES=0x00 ACK URGP=0"
698
+ end
699
+
700
+ it 'does not match' do
701
+ expect(grok['tags']).to include('_grokparsefailure')
702
+ end
703
+
704
+ end
705
+
706
+ end
707
+
708
+ context 'IPv6 message' do
709
+
710
+ let(:message) do
711
+ "Jan 15 11:21:13 IKCS-Web kernel: SFW2-INext-ACC-RELATED IN=eth0 OUT=eth1 MAC= SRC=fe80:0000:0000:0000:16da:e9ff:feec:a04d DST=ff02:0000:0000:0000:0000:0000:0000:00fb LEN=527 TC=0 HOPLIMIT=255 FLOWLBL=804001 PROTO=UDP SPT=5353 DPT=5353 LEN=487"
712
+ end
713
+
714
+ it 'matches' do
715
+ if ecs_compatibility?
716
+ iptables = grok['iptables']
717
+ expect(iptables).to include("flow_label"=>"804001")
718
+ expect(iptables['ttl'].to_s).to eql('255')
719
+ expect(iptables['length'].to_s).to eql('527')
720
+ expect(grok).to include("observer"=>{"hostname"=>"IKCS-Web", "ingress"=>{"interface"=>{"name"=>"eth0"}}, "egress"=>{"interface"=>{"name"=>"eth1"}}})
721
+ expect(grok).to include(
722
+ "source"=>{"ip"=>"fe80:0000:0000:0000:16da:e9ff:feec:a04d", "port"=>5353},
723
+ "destination"=>{"ip"=>"ff02:0000:0000:0000:0000:0000:0000:00fb", "port"=>5353},
724
+ "network"=>{"transport"=>"UDP"}
725
+ )
726
+ pending
727
+ # TODO hitting a grok type-casting issue https://github.com/logstash-plugins/logstash-filter-grok/issues/165
728
+ expect(iptables).to include("ttl"=>255, "flow_label"=>"804001", "length"=>527)
729
+ else
730
+ expect(grok).to include("nf_src_ip"=>"fe80:0000:0000:0000:16da:e9ff:feec:a04d",
731
+ "nf_dst_ip"=>"ff02:0000:0000:0000:0000:0000:0000:00fb",
732
+ "nf_protocol"=>"UDP")
733
+ end
734
+ end
735
+
736
+ end
737
+
738
+ end
739
+