fluent-plugin-parser-winevt_xml 0.2.8 → 0.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.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +18 -1
- data/.github/workflows/linux-test.yaml +14 -9
- data/.github/workflows/macos-test.yaml +13 -3
- data/.github/workflows/windows-test.yaml +13 -3
- data/README.md +3 -2
- data/fluent-plugin-parser-winevt_xml.gemspec +4 -2
- data/lib/fluent/plugin/parser_winevt_sax.rb +38 -5
- data/lib/fluent/plugin/parser_winevt_xml.rb +81 -6
- data/lib/fluent/plugin/{winevt_sax_document.rb → winevt_sax_document_nokogiri.rb} +2 -1
- data/lib/fluent/plugin/winevt_sax_document_rexml.rb +98 -0
- data/test/plugin/test_parser_winevt_sax.rb +51 -31
- data/test/plugin/test_parser_winevt_xml.rb +51 -32
- metadata +24 -12
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3da55ba29ddc8b7c6c0a9e76525ecbe15775e5d682dd7448b329a50715f49c7a
|
|
4
|
+
data.tar.gz: 8a4f47f6b7c1bdc10822eab7cf35751f25c67ba6b156568b49c11f2616ea7644
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a81f1049873ed70f491fe6373ba666d3e0e76d883f49936ce585015089697784e6d95797a9052dde46b20a219b5146c8230417ce181fdd3255dd6005104ac55e
|
|
7
|
+
data.tar.gz: f5aeaba0d414bbc15206f4055f3685e6a49ba781f156e226a523abd560b59e79c4e1eaddb70299e370e0b6ad86c55020f244d26a6ca8fe00d6b5c0f525e87ed7
|
data/.github/dependabot.yml
CHANGED
|
@@ -3,4 +3,21 @@ updates:
|
|
|
3
3
|
- package-ecosystem: 'github-actions'
|
|
4
4
|
directory: '/'
|
|
5
5
|
schedule:
|
|
6
|
-
interval: '
|
|
6
|
+
interval: 'monthly'
|
|
7
|
+
groups:
|
|
8
|
+
# PR: "Security update [package] from [old] to [new]"
|
|
9
|
+
# This PR should be merged in hurry
|
|
10
|
+
security-updates:
|
|
11
|
+
applies-to: security-updates
|
|
12
|
+
patterns:
|
|
13
|
+
- '*'
|
|
14
|
+
|
|
15
|
+
# PR: "Bump [package] from [old] to [new]"
|
|
16
|
+
# No need to be merged this PR in hurry. It is enough to merge
|
|
17
|
+
# once in a month.
|
|
18
|
+
monthly-updates:
|
|
19
|
+
applies-to: version-updates
|
|
20
|
+
patterns:
|
|
21
|
+
- '*'
|
|
22
|
+
# Allow to create PR both of security and normal updates.
|
|
23
|
+
open-pull-requests-limit: 1
|
|
@@ -5,27 +5,32 @@ on:
|
|
|
5
5
|
branches: [master]
|
|
6
6
|
pull_request:
|
|
7
7
|
branches: [master]
|
|
8
|
+
schedule:
|
|
9
|
+
- cron: '0 0 1 * *'
|
|
8
10
|
|
|
9
11
|
jobs:
|
|
12
|
+
ruby-versions:
|
|
13
|
+
uses: ruby/actions/.github/workflows/ruby_versions.yml@master
|
|
14
|
+
with:
|
|
15
|
+
engine: cruby
|
|
16
|
+
min_version: 3.2
|
|
10
17
|
test:
|
|
18
|
+
needs: ruby-versions
|
|
11
19
|
runs-on: ${{ matrix.os }}
|
|
12
|
-
continue-on-error: ${{ matrix.
|
|
20
|
+
continue-on-error: ${{ matrix.ruby == 'head' }}
|
|
13
21
|
strategy:
|
|
14
22
|
fail-fast: false
|
|
15
23
|
matrix:
|
|
16
|
-
ruby:
|
|
24
|
+
ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }}
|
|
25
|
+
exclude:
|
|
26
|
+
- ruby: ${{ github.event_name != 'schedule' && 'head' || '__none__' }}
|
|
17
27
|
os: [ubuntu-latest]
|
|
18
|
-
experimental: [false]
|
|
19
|
-
include:
|
|
20
|
-
- ruby: head
|
|
21
|
-
os: ubuntu-latest
|
|
22
|
-
experimental: true
|
|
23
28
|
|
|
24
29
|
name: Ruby ${{ matrix.ruby }} on ${{ matrix.os }}
|
|
25
30
|
steps:
|
|
26
|
-
- uses: actions/checkout@
|
|
31
|
+
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
27
32
|
- name: Set up Ruby
|
|
28
|
-
uses: ruby/setup-ruby@v1
|
|
33
|
+
uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
|
|
29
34
|
with:
|
|
30
35
|
ruby-version: ${{ matrix.ruby }}
|
|
31
36
|
- name: Install dependencies
|
|
@@ -5,21 +5,31 @@ on:
|
|
|
5
5
|
branches: [master]
|
|
6
6
|
pull_request:
|
|
7
7
|
branches: [master]
|
|
8
|
+
schedule:
|
|
9
|
+
- cron: '0 0 1 * *'
|
|
8
10
|
|
|
9
11
|
jobs:
|
|
12
|
+
ruby-versions:
|
|
13
|
+
uses: ruby/actions/.github/workflows/ruby_versions.yml@master
|
|
14
|
+
with:
|
|
15
|
+
engine: cruby
|
|
16
|
+
min_version: 3.2
|
|
10
17
|
test:
|
|
18
|
+
needs: ruby-versions
|
|
11
19
|
runs-on: ${{ matrix.os }}
|
|
12
20
|
strategy:
|
|
13
21
|
fail-fast: false
|
|
14
22
|
matrix:
|
|
15
|
-
ruby:
|
|
23
|
+
ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }}
|
|
24
|
+
exclude:
|
|
25
|
+
- ruby: ${{ github.event_name != 'schedule' && 'head' || '__none__' }}
|
|
16
26
|
os: [macos-latest]
|
|
17
27
|
|
|
18
28
|
name: Ruby ${{ matrix.ruby }} on ${{ matrix.os }}
|
|
19
29
|
steps:
|
|
20
|
-
- uses: actions/checkout@
|
|
30
|
+
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
21
31
|
- name: Set up Ruby
|
|
22
|
-
uses: ruby/setup-ruby@v1
|
|
32
|
+
uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
|
|
23
33
|
with:
|
|
24
34
|
ruby-version: ${{ matrix.ruby }}
|
|
25
35
|
- name: Install dependencies
|
|
@@ -5,21 +5,31 @@ on:
|
|
|
5
5
|
branches: [master]
|
|
6
6
|
pull_request:
|
|
7
7
|
branches: [master]
|
|
8
|
+
schedule:
|
|
9
|
+
- cron: '0 0 1 * *'
|
|
8
10
|
|
|
9
11
|
jobs:
|
|
12
|
+
ruby-versions:
|
|
13
|
+
uses: ruby/actions/.github/workflows/ruby_versions.yml@master
|
|
14
|
+
with:
|
|
15
|
+
engine: cruby
|
|
16
|
+
min_version: 3.2
|
|
10
17
|
test:
|
|
18
|
+
needs: ruby-versions
|
|
11
19
|
runs-on: ${{ matrix.os }}
|
|
12
20
|
strategy:
|
|
13
21
|
fail-fast: false
|
|
14
22
|
matrix:
|
|
15
|
-
ruby:
|
|
23
|
+
ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }}
|
|
24
|
+
exclude:
|
|
25
|
+
- ruby: ${{ github.event_name != 'schedule' && 'head' || '__none__' }}
|
|
16
26
|
os:
|
|
17
27
|
- windows-latest
|
|
18
28
|
name: Ruby ${{ matrix.ruby }} on ${{ matrix.os }}
|
|
19
29
|
steps:
|
|
20
|
-
- uses: actions/checkout@
|
|
30
|
+
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
21
31
|
- name: Set up Ruby
|
|
22
|
-
uses: ruby/setup-ruby@v1
|
|
32
|
+
uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
|
|
23
33
|
with:
|
|
24
34
|
ruby-version: ${{ matrix.ruby }}
|
|
25
35
|
- name: Install dependencies
|
data/README.md
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# fluent-plugin-parser-winevt_xml
|
|
2
2
|
|
|
3
|
-
[](https://github.com/fluent/fluent-plugin-parser-winevt_xml/actions/workflows/macos-test.yaml)
|
|
4
|
+
[](https://github.com/fluent/fluent-plugin-parser-winevt_xml/actions/workflows/linux-test.yaml)
|
|
5
|
+
[](https://github.com/fluent/fluent-plugin-parser-winevt_xml/actions/workflows/windows-test.yaml)
|
|
5
6
|
|
|
6
7
|
## Component
|
|
7
8
|
|
|
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
|
4
4
|
|
|
5
5
|
Gem::Specification.new do |spec|
|
|
6
6
|
spec.name = "fluent-plugin-parser-winevt_xml"
|
|
7
|
-
spec.version = "0.
|
|
7
|
+
spec.version = "0.3.0"
|
|
8
8
|
spec.authors = ["Hiroshi Hatake", "Masahiro Nakagawa"]
|
|
9
9
|
spec.email = ["cosmo0920.oucc@gmail.com", "repeatedly@gmail.com"]
|
|
10
10
|
spec.summary = %q{Fluentd Parser plugin to parse XML rendered windows event log.}
|
|
@@ -20,8 +20,10 @@ Gem::Specification.new do |spec|
|
|
|
20
20
|
spec.add_development_dependency "bundler"
|
|
21
21
|
spec.add_development_dependency "rake"
|
|
22
22
|
spec.add_development_dependency "test-unit", "~> 3.4.0"
|
|
23
|
+
spec.add_development_dependency "nokogiri", ">= 1.12.5"
|
|
24
|
+
|
|
23
25
|
spec.add_runtime_dependency "fluentd", [">= 0.14.12", "< 2"]
|
|
24
|
-
spec.add_runtime_dependency "
|
|
26
|
+
spec.add_runtime_dependency "rexml", "~> 3.2"
|
|
25
27
|
|
|
26
28
|
# gems that aren't default gems as of Ruby 3.4
|
|
27
29
|
spec.add_runtime_dependency "base64", "~> 0.2"
|
|
@@ -1,12 +1,38 @@
|
|
|
1
1
|
require 'fluent/plugin/parser'
|
|
2
|
-
require 'fluent/plugin/winevt_sax_document'
|
|
3
|
-
require 'nokogiri'
|
|
4
2
|
|
|
5
3
|
module Fluent::Plugin
|
|
6
4
|
class WinevtSAXparser < Parser
|
|
7
5
|
Fluent::Plugin.register_parser('winevt_sax', self)
|
|
8
6
|
|
|
9
7
|
config_param :preserve_qualifiers, :bool, default: true
|
|
8
|
+
config_param :parser, :enum, list: [:auto, :rexml, :nokogiri], default: :auto
|
|
9
|
+
|
|
10
|
+
def initialize
|
|
11
|
+
super
|
|
12
|
+
@use_nokogiri = false
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def configure(conf)
|
|
16
|
+
super
|
|
17
|
+
if @parser != :rexml
|
|
18
|
+
begin
|
|
19
|
+
require 'nokogiri'
|
|
20
|
+
require 'fluent/plugin/winevt_sax_document_nokogiri'
|
|
21
|
+
@use_nokogiri = true
|
|
22
|
+
rescue
|
|
23
|
+
if @parser == :nokogiri
|
|
24
|
+
raise Fluent::ConfigError,
|
|
25
|
+
"Nokogiri is required when 'parser nokogiri' is specified, but it isn't installed. " \
|
|
26
|
+
"Install nokogiri, or set 'parser' to 'rexml' or 'auto': #{e.message}"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
if !@use_nokogiri
|
|
32
|
+
require 'rexml/parsers/sax2parser'
|
|
33
|
+
require 'fluent/plugin/winevt_sax_document_rexml'
|
|
34
|
+
end
|
|
35
|
+
end
|
|
10
36
|
|
|
11
37
|
def winevt_xml?
|
|
12
38
|
true
|
|
@@ -17,9 +43,16 @@ module Fluent::Plugin
|
|
|
17
43
|
end
|
|
18
44
|
|
|
19
45
|
def parse(text)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
46
|
+
if @use_nokogiri
|
|
47
|
+
evtxml = WinevtXMLDocumentNokogiri.new(@preserve_qualifiers)
|
|
48
|
+
parser = Nokogiri::XML::SAX::Parser.new(evtxml)
|
|
49
|
+
parser.parse(text)
|
|
50
|
+
else
|
|
51
|
+
evtxml = WinevtXMLDocumentREXML.new(@preserve_qualifiers)
|
|
52
|
+
parser = REXML::Parsers::SAX2Parser.new(text)
|
|
53
|
+
parser.listen(evtxml)
|
|
54
|
+
parser.parse
|
|
55
|
+
end
|
|
23
56
|
time = @estimate_current_event ? Fluent::EventTime.now : nil
|
|
24
57
|
yield time, evtxml.result
|
|
25
58
|
end
|
|
@@ -1,11 +1,36 @@
|
|
|
1
1
|
require 'fluent/plugin/parser'
|
|
2
|
-
require 'nokogiri'
|
|
3
2
|
|
|
4
3
|
module Fluent::Plugin
|
|
5
4
|
class WinevtXMLparser < Parser
|
|
6
5
|
Fluent::Plugin.register_parser('winevt_xml', self)
|
|
7
6
|
|
|
8
7
|
config_param :preserve_qualifiers, :bool, default: true
|
|
8
|
+
config_param :parser, :enum, list: [:auto, :rexml, :nokogiri], default: :auto
|
|
9
|
+
|
|
10
|
+
def initialize
|
|
11
|
+
super
|
|
12
|
+
@use_nokogiri = false
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def configure(conf)
|
|
16
|
+
super
|
|
17
|
+
if @parser != :rexml
|
|
18
|
+
begin
|
|
19
|
+
require 'nokogiri'
|
|
20
|
+
@use_nokogiri = true
|
|
21
|
+
rescue
|
|
22
|
+
if @parser == :nokogiri
|
|
23
|
+
raise Fluent::ConfigError,
|
|
24
|
+
"Nokogiri is required when 'parser nokogiri' is specified, but it isn't installed. " \
|
|
25
|
+
"Install nokogiri, or set 'parser' to 'rexml' or 'auto': #{e.message}"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
if !@use_nokogiri
|
|
31
|
+
require 'rexml/document'
|
|
32
|
+
end
|
|
33
|
+
end
|
|
9
34
|
|
|
10
35
|
def winevt_xml?
|
|
11
36
|
true
|
|
@@ -19,9 +44,9 @@ module Fluent::Plugin
|
|
|
19
44
|
(low & 0xffff) | (high & 0xffff) << 16
|
|
20
45
|
end
|
|
21
46
|
|
|
22
|
-
def
|
|
47
|
+
def event_id_nokogiri(system_elem)
|
|
23
48
|
if @preserve_qualifiers
|
|
24
|
-
return (system_elem/'EventID').text rescue nil
|
|
49
|
+
return ((system_elem/'EventID').text rescue nil)
|
|
25
50
|
end
|
|
26
51
|
|
|
27
52
|
qualifiers = (system_elem/'EventID').attribute("Qualifiers").text rescue nil
|
|
@@ -34,16 +59,29 @@ module Fluent::Plugin
|
|
|
34
59
|
end
|
|
35
60
|
end
|
|
36
61
|
|
|
37
|
-
def
|
|
62
|
+
def event_id_rexml(system_elem)
|
|
63
|
+
return system_elem.elements['EventID'].text rescue nil if @preserve_qualifiers
|
|
64
|
+
|
|
65
|
+
qualifiers = system_elem.elements['EventID'].attributes['Qualifiers'] rescue nil
|
|
66
|
+
if qualifiers
|
|
67
|
+
event_id = system_elem.elements['EventID'].text
|
|
68
|
+
event_id = MAKELONG(event_id.to_i, qualifiers.to_i)
|
|
69
|
+
event_id.to_s
|
|
70
|
+
else
|
|
71
|
+
system_elem.elements['EventID'].text rescue nil
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def parse_nokogiri(text)
|
|
38
76
|
record = {}
|
|
39
77
|
doc = Nokogiri::XML(text)
|
|
40
78
|
system_elem = doc/'Event'/'System'
|
|
41
79
|
record["ProviderName"] = (system_elem/"Provider").attribute("Name").text rescue nil
|
|
42
80
|
record["ProviderGUID"] = (system_elem/"Provider").attribute("Guid").text rescue nil
|
|
43
81
|
if @preserve_qualifiers
|
|
44
|
-
record["Qualifiers"]
|
|
82
|
+
record["Qualifiers"] = (system_elem/'EventID').attribute("Qualifiers").text rescue nil
|
|
45
83
|
end
|
|
46
|
-
record["EventID"] =
|
|
84
|
+
record["EventID"] = event_id_nokogiri(system_elem)
|
|
47
85
|
record["Level"] = (system_elem/'Level').text rescue nil
|
|
48
86
|
record["Task"] = (system_elem/'Task').text rescue nil
|
|
49
87
|
record["Opcode"] = (system_elem/'Opcode').text rescue nil
|
|
@@ -59,6 +97,43 @@ module Fluent::Plugin
|
|
|
59
97
|
record["UserID"] = (system_elem/'Security').attribute("UserID").text rescue nil
|
|
60
98
|
record["Version"] = (system_elem/'Version').text rescue nil
|
|
61
99
|
time = @estimate_current_event ? Fluent::EventTime.now : nil
|
|
100
|
+
return time, record
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def parse_rexml(text)
|
|
104
|
+
record = {}
|
|
105
|
+
doc = REXML::Document.new(text)
|
|
106
|
+
system_elem = doc.root.elements['System'] rescue nil
|
|
107
|
+
record["ProviderName"] = system_elem.elements['Provider'].attributes['Name'] rescue nil
|
|
108
|
+
record["ProviderGUID"] = system_elem.elements['Provider'].attributes['Guid'] rescue nil
|
|
109
|
+
if @preserve_qualifiers
|
|
110
|
+
record["Qualifiers"] = system_elem.elements['EventID'].attributes['Qualifiers'] rescue nil
|
|
111
|
+
end
|
|
112
|
+
record["EventID"] = event_id_rexml(system_elem)
|
|
113
|
+
record["Level"] = system_elem.elements['Level'].text rescue nil
|
|
114
|
+
record["Task"] = system_elem.elements['Task'].text rescue nil
|
|
115
|
+
record["Opcode"] = system_elem.elements['Opcode'].text rescue nil
|
|
116
|
+
record["Keywords"] = system_elem.elements['Keywords'].text rescue nil
|
|
117
|
+
record["TimeCreated"] = system_elem.elements['TimeCreated'].attributes['SystemTime'] rescue nil
|
|
118
|
+
record["EventRecordID"] = system_elem.elements['EventRecordID'].text rescue nil
|
|
119
|
+
record["ActivityID"] = system_elem.elements['Correlation'].attributes['ActivityID'] rescue nil
|
|
120
|
+
record["RelatedActivityID"] = system_elem.elements['Correlation'].attributes['RelatedActivityID'] rescue nil
|
|
121
|
+
record["ThreadID"] = system_elem.elements['Execution'].attributes['ThreadID'] rescue nil
|
|
122
|
+
record["ProcessID"] = system_elem.elements['Execution'].attributes['ProcessID'] rescue nil
|
|
123
|
+
record["Channel"] = system_elem.elements['Channel'].text rescue nil
|
|
124
|
+
record["Computer"] = system_elem.elements['Computer'].text rescue nil
|
|
125
|
+
record["UserID"] = system_elem.elements['Security'].attributes['UserID'] rescue nil
|
|
126
|
+
record["Version"] = system_elem.elements['Version'].text rescue nil
|
|
127
|
+
time = @estimate_current_event ? Fluent::EventTime.now : nil
|
|
128
|
+
return time, record
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def parse(text)
|
|
132
|
+
if @use_nokogiri
|
|
133
|
+
time, record = parse_nokogiri(text)
|
|
134
|
+
else
|
|
135
|
+
time, record = parse_rexml(text)
|
|
136
|
+
end
|
|
62
137
|
yield time, record
|
|
63
138
|
end
|
|
64
139
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
require 'nokogiri'
|
|
2
2
|
|
|
3
|
-
class
|
|
3
|
+
class WinevtXMLDocumentNokogiri < Nokogiri::XML::SAX::Document
|
|
4
4
|
def initialize(preserve_qualifiers)
|
|
5
5
|
@stack = []
|
|
6
6
|
@result = {}
|
|
@@ -66,6 +66,7 @@ class WinevtXMLDocument < Nokogiri::XML::SAX::Document
|
|
|
66
66
|
end
|
|
67
67
|
|
|
68
68
|
def end_element(name, attributes = [])
|
|
69
|
+
@stack.pop
|
|
69
70
|
end
|
|
70
71
|
|
|
71
72
|
def end_document
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
require 'rexml/parsers/sax2parser'
|
|
2
|
+
|
|
3
|
+
class WinevtXMLDocumentREXML
|
|
4
|
+
def initialize(preserve_qualifiers)
|
|
5
|
+
@stack = []
|
|
6
|
+
@result = {}
|
|
7
|
+
@preserve_qualifiers = preserve_qualifiers
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def MAKELONG(low, high)
|
|
11
|
+
(low & 0xffff) | (high & 0xffff) << 16
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def event_id
|
|
15
|
+
if @result.has_key?("Qualifiers")
|
|
16
|
+
qualifiers = @result.delete("Qualifiers")
|
|
17
|
+
event_id = @result['EventID']
|
|
18
|
+
event_id = MAKELONG(event_id.to_i, qualifiers.to_i)
|
|
19
|
+
@result['EventID'] = event_id.to_s
|
|
20
|
+
else
|
|
21
|
+
@result['EventID']
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def result
|
|
26
|
+
return @result if @preserve_qualifiers
|
|
27
|
+
|
|
28
|
+
if @result
|
|
29
|
+
@result['EventID'] = event_id
|
|
30
|
+
end
|
|
31
|
+
@result
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def start_element(*args)
|
|
35
|
+
# REXML SAX2 may pass (uri, localname, qname, attributes) or (qname, attributes)
|
|
36
|
+
name = if args.length >= 3
|
|
37
|
+
args[1].to_s
|
|
38
|
+
else
|
|
39
|
+
args[0].to_s
|
|
40
|
+
end
|
|
41
|
+
# normalize namespace/prefix
|
|
42
|
+
name = name.split('}').last if name.include?('}')
|
|
43
|
+
name = name.split(':').last if name.include?(':')
|
|
44
|
+
@stack << name
|
|
45
|
+
|
|
46
|
+
attrs = args.last || {}
|
|
47
|
+
|
|
48
|
+
# helper to fetch attribute value from different attribute containers
|
|
49
|
+
get_attr = lambda do |a, k|
|
|
50
|
+
begin
|
|
51
|
+
if a.is_a?(Array)
|
|
52
|
+
pair = a.find { |p| p && p[0] && p[0].to_s == k.to_s }
|
|
53
|
+
pair && pair[1]
|
|
54
|
+
elsif a.respond_to?(:[])
|
|
55
|
+
a[k] || a[k.to_sym]
|
|
56
|
+
else
|
|
57
|
+
nil
|
|
58
|
+
end
|
|
59
|
+
rescue
|
|
60
|
+
nil
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
if name == "Provider"
|
|
65
|
+
@result["ProviderName"] = get_attr.call(attrs, 'Name')
|
|
66
|
+
@result["ProviderGUID"] = get_attr.call(attrs, 'Guid')
|
|
67
|
+
elsif name == "EventID"
|
|
68
|
+
@result["Qualifiers"] = get_attr.call(attrs, 'Qualifiers')
|
|
69
|
+
elsif name == "TimeCreated"
|
|
70
|
+
@result["TimeCreated"] = get_attr.call(attrs, 'SystemTime')
|
|
71
|
+
elsif name == "Correlation"
|
|
72
|
+
@result["ActivityID"] = get_attr.call(attrs, 'ActivityID')
|
|
73
|
+
@result["RelatedActivityID"] = get_attr.call(attrs, 'RelatedActivityID')
|
|
74
|
+
elsif name == "Execution"
|
|
75
|
+
@result["ProcessID"] = get_attr.call(attrs, 'ProcessID')
|
|
76
|
+
@result["ThreadID"] = get_attr.call(attrs, 'ThreadID')
|
|
77
|
+
elsif name == "Security"
|
|
78
|
+
@result["UserID"] = get_attr.call(attrs, 'UserID')
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def characters(string)
|
|
83
|
+
element = @stack.last
|
|
84
|
+
return unless element
|
|
85
|
+
|
|
86
|
+
if /^EventID|Level|Task|Opcode|Keywords|EventRecordID|ActivityID|Channel|Computer|Security|Version$/ === element
|
|
87
|
+
@result[element] = (@result[element] || '') + string
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def end_element(*_)
|
|
92
|
+
@stack.pop
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def method_missing(name, *args, &block)
|
|
96
|
+
# Ignore any SAX2 events we don't explicitly handle (e.g., progress)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -2,43 +2,56 @@ require_relative '../helper'
|
|
|
2
2
|
|
|
3
3
|
class WinevtSAXparserTest < Test::Unit::TestCase
|
|
4
4
|
|
|
5
|
-
def setup
|
|
6
|
-
Fluent::Test.setup
|
|
7
|
-
end
|
|
8
|
-
|
|
9
5
|
CONFIG = %[]
|
|
10
|
-
XMLLOG = File.open(File.join(__dir__, "..", "data", "eventlog.xml") )
|
|
11
6
|
|
|
12
7
|
def create_driver(conf = CONFIG)
|
|
13
8
|
Fluent::Test::Driver::Parser.new(Fluent::Plugin::WinevtSAXparser).configure(conf)
|
|
14
9
|
end
|
|
15
10
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
"Task" => "12544",
|
|
25
|
-
"Opcode" => "0",
|
|
26
|
-
"Keywords" => "0x8020000000000000",
|
|
27
|
-
"TimeCreated" => "2019-06-13T09:21:23.345889600Z",
|
|
28
|
-
"EventRecordID" => "80688",
|
|
29
|
-
"ActivityID" => "{587F0743-1F71-0006-5007-7F58711FD501}",
|
|
30
|
-
"RelatedActivityID" => nil,
|
|
31
|
-
"ProcessID" => "912",
|
|
32
|
-
"ThreadID" => "24708",
|
|
33
|
-
"Channel" => "Security",
|
|
34
|
-
"Computer" => "Fluentd-Developing-Windows",
|
|
35
|
-
"UserID" => nil,
|
|
36
|
-
"Version" => "2",}
|
|
37
|
-
d.instance.parse(xml) do |time, record|
|
|
38
|
-
assert_equal(expected, record)
|
|
11
|
+
class ParseTest < self
|
|
12
|
+
def setup
|
|
13
|
+
Fluent::Test.setup
|
|
14
|
+
@xml = File.open(File.join(__dir__, "..", "data", "eventlog.xml"))
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def teardown
|
|
18
|
+
@xml.close
|
|
39
19
|
end
|
|
40
20
|
|
|
41
|
-
|
|
21
|
+
data(
|
|
22
|
+
"auto" => [%[parser auto], true],
|
|
23
|
+
"nokogiri" => [%[parser nokogiri], true],
|
|
24
|
+
"rexml" => [%[parser rexml], false]
|
|
25
|
+
)
|
|
26
|
+
def test_parse(data)
|
|
27
|
+
config, expected_use_nokogiri = data
|
|
28
|
+
d = create_driver(CONFIG + config)
|
|
29
|
+
@xml = File.open(File.join(__dir__, "..", "data", "eventlog.xml"))
|
|
30
|
+
expected = {"ProviderName" => "Microsoft-Windows-Security-Auditing",
|
|
31
|
+
"ProviderGUID" => "{54849625-5478-4994-A5BA-3E3B0328C30D}",
|
|
32
|
+
"EventID" => "4624",
|
|
33
|
+
"Qualifiers" => nil,
|
|
34
|
+
"Level" => "0",
|
|
35
|
+
"Task" => "12544",
|
|
36
|
+
"Opcode" => "0",
|
|
37
|
+
"Keywords" => "0x8020000000000000",
|
|
38
|
+
"TimeCreated" => "2019-06-13T09:21:23.345889600Z",
|
|
39
|
+
"EventRecordID" => "80688",
|
|
40
|
+
"ActivityID" => "{587F0743-1F71-0006-5007-7F58711FD501}",
|
|
41
|
+
"RelatedActivityID" => nil,
|
|
42
|
+
"ProcessID" => "912",
|
|
43
|
+
"ThreadID" => "24708",
|
|
44
|
+
"Channel" => "Security",
|
|
45
|
+
"Computer" => "Fluentd-Developing-Windows",
|
|
46
|
+
"UserID" => nil,
|
|
47
|
+
"Version" => "2",}
|
|
48
|
+
d.instance.parse(@xml) do |time, record|
|
|
49
|
+
assert_equal(expected, record)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
assert_true(d.instance.winevt_xml?)
|
|
53
|
+
assert_equal(expected_use_nokogiri, d.instance.instance_variable_get(:@use_nokogiri))
|
|
54
|
+
end
|
|
42
55
|
end
|
|
43
56
|
|
|
44
57
|
class QualifiersTest < self
|
|
@@ -50,8 +63,14 @@ class WinevtSAXparserTest < Test::Unit::TestCase
|
|
|
50
63
|
@xml.close
|
|
51
64
|
end
|
|
52
65
|
|
|
53
|
-
|
|
54
|
-
|
|
66
|
+
data(
|
|
67
|
+
"auto" => [%[parser auto], true],
|
|
68
|
+
"nokogiri" => [%[parser nokogiri], true],
|
|
69
|
+
"rexml" => [%[parser rexml], false]
|
|
70
|
+
)
|
|
71
|
+
def test_parse_without_qualifiers(data)
|
|
72
|
+
config, expected_use_nokogiri = data
|
|
73
|
+
d = create_driver(CONFIG + config + %[\npreserve_qualifiers false])
|
|
55
74
|
expected = {"ActivityID" => nil,
|
|
56
75
|
"Channel" => "Application",
|
|
57
76
|
"Computer" => "DESKTOP-G457RDR",
|
|
@@ -74,6 +93,7 @@ class WinevtSAXparserTest < Test::Unit::TestCase
|
|
|
74
93
|
end
|
|
75
94
|
|
|
76
95
|
assert_true(d.instance.winevt_xml?)
|
|
96
|
+
assert_equal(expected_use_nokogiri, d.instance.instance_variable_get(:@use_nokogiri))
|
|
77
97
|
end
|
|
78
98
|
end
|
|
79
99
|
end
|
|
@@ -2,44 +2,56 @@ require_relative '../helper'
|
|
|
2
2
|
|
|
3
3
|
class WinevtXMLparserTest < Test::Unit::TestCase
|
|
4
4
|
|
|
5
|
-
def setup
|
|
6
|
-
Fluent::Test.setup
|
|
7
|
-
end
|
|
8
|
-
|
|
9
5
|
CONFIG = %[]
|
|
10
|
-
XMLLOG = File.open(File.join(__dir__, "..", "data", "eventlog.xml"))
|
|
11
6
|
|
|
12
7
|
def create_driver(conf = CONFIG)
|
|
13
8
|
Fluent::Test::Driver::Parser.new(Fluent::Plugin::WinevtXMLparser).configure(conf)
|
|
14
9
|
end
|
|
15
10
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
"Task" => "12544",
|
|
25
|
-
"Opcode" => "0",
|
|
26
|
-
"Keywords" => "0x8020000000000000",
|
|
27
|
-
"TimeCreated" => "2019-06-13T09:21:23.345889600Z",
|
|
28
|
-
"EventRecordID" => "80688",
|
|
29
|
-
"ActivityID" => "{587F0743-1F71-0006-5007-7F58711FD501}",
|
|
30
|
-
"RelatedActivityID" => nil,
|
|
31
|
-
"ProcessID" => "912",
|
|
32
|
-
"ThreadID" => "24708",
|
|
33
|
-
"Channel" => "Security",
|
|
34
|
-
"Computer" => "Fluentd-Developing-Windows",
|
|
35
|
-
"UserID" => nil,
|
|
36
|
-
"Version" => "2",}
|
|
37
|
-
d.instance.parse(xml) do |time, record|
|
|
38
|
-
assert_equal(expected, record)
|
|
11
|
+
class ParseTest < self
|
|
12
|
+
def setup
|
|
13
|
+
Fluent::Test.setup
|
|
14
|
+
@xml = File.open(File.join(__dir__, "..", "data", "eventlog.xml"))
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def teardown
|
|
18
|
+
@xml.close
|
|
39
19
|
end
|
|
40
|
-
xml.close
|
|
41
20
|
|
|
42
|
-
|
|
21
|
+
data(
|
|
22
|
+
"auto" => [%[parser auto], true],
|
|
23
|
+
"nokogiri" => [%[parser nokogiri], true],
|
|
24
|
+
"rexml" => [%[parser rexml], false]
|
|
25
|
+
)
|
|
26
|
+
def test_parse(data)
|
|
27
|
+
config, expected_use_nokogiri = data
|
|
28
|
+
d = create_driver(CONFIG + config)
|
|
29
|
+
@xml = File.open(File.join(__dir__, "..", "data", "eventlog.xml"))
|
|
30
|
+
expected = {"ProviderName" => "Microsoft-Windows-Security-Auditing",
|
|
31
|
+
"ProviderGUID" => "{54849625-5478-4994-A5BA-3E3B0328C30D}",
|
|
32
|
+
"EventID" => "4624",
|
|
33
|
+
"Qualifiers" => nil,
|
|
34
|
+
"Level" => "0",
|
|
35
|
+
"Task" => "12544",
|
|
36
|
+
"Opcode" => "0",
|
|
37
|
+
"Keywords" => "0x8020000000000000",
|
|
38
|
+
"TimeCreated" => "2019-06-13T09:21:23.345889600Z",
|
|
39
|
+
"EventRecordID" => "80688",
|
|
40
|
+
"ActivityID" => "{587F0743-1F71-0006-5007-7F58711FD501}",
|
|
41
|
+
"RelatedActivityID" => nil,
|
|
42
|
+
"ProcessID" => "912",
|
|
43
|
+
"ThreadID" => "24708",
|
|
44
|
+
"Channel" => "Security",
|
|
45
|
+
"Computer" => "Fluentd-Developing-Windows",
|
|
46
|
+
"UserID" => nil,
|
|
47
|
+
"Version" => "2",}
|
|
48
|
+
d.instance.parse(@xml) do |time, record|
|
|
49
|
+
assert_equal(expected, record)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
assert_true(d.instance.winevt_xml?)
|
|
53
|
+
assert_equal(expected_use_nokogiri, d.instance.instance_variable_get(:@use_nokogiri))
|
|
54
|
+
end
|
|
43
55
|
end
|
|
44
56
|
|
|
45
57
|
class QualifiersTest < self
|
|
@@ -51,8 +63,14 @@ class WinevtXMLparserTest < Test::Unit::TestCase
|
|
|
51
63
|
@xml.close
|
|
52
64
|
end
|
|
53
65
|
|
|
54
|
-
|
|
55
|
-
|
|
66
|
+
data(
|
|
67
|
+
"auto" => [%[parser auto], true],
|
|
68
|
+
"nokogiri" => [%[parser nokogiri], true],
|
|
69
|
+
"rexml" => [%[parser rexml], false]
|
|
70
|
+
)
|
|
71
|
+
def test_parse_without_qualifiers(data)
|
|
72
|
+
config, expected_use_nokogiri = data
|
|
73
|
+
d = create_driver(CONFIG + config + %[\npreserve_qualifiers false])
|
|
56
74
|
expected = {"ActivityID" => nil,
|
|
57
75
|
"Channel" => "Application",
|
|
58
76
|
"Computer" => "DESKTOP-G457RDR",
|
|
@@ -75,6 +93,7 @@ class WinevtXMLparserTest < Test::Unit::TestCase
|
|
|
75
93
|
end
|
|
76
94
|
|
|
77
95
|
assert_true(d.instance.winevt_xml?)
|
|
96
|
+
assert_equal(expected_use_nokogiri, d.instance.instance_variable_get(:@use_nokogiri))
|
|
78
97
|
end
|
|
79
98
|
end
|
|
80
99
|
end
|
metadata
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fluent-plugin-parser-winevt_xml
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Hiroshi Hatake
|
|
8
8
|
- Masahiro Nakagawa
|
|
9
|
-
autorequire:
|
|
10
9
|
bindir: bin
|
|
11
10
|
cert_chain: []
|
|
12
|
-
date:
|
|
11
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
13
12
|
dependencies:
|
|
14
13
|
- !ruby/object:Gem::Dependency
|
|
15
14
|
name: bundler
|
|
@@ -53,6 +52,20 @@ dependencies:
|
|
|
53
52
|
- - "~>"
|
|
54
53
|
- !ruby/object:Gem::Version
|
|
55
54
|
version: 3.4.0
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: nokogiri
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: 1.12.5
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: 1.12.5
|
|
56
69
|
- !ruby/object:Gem::Dependency
|
|
57
70
|
name: fluentd
|
|
58
71
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -74,19 +87,19 @@ dependencies:
|
|
|
74
87
|
- !ruby/object:Gem::Version
|
|
75
88
|
version: '2'
|
|
76
89
|
- !ruby/object:Gem::Dependency
|
|
77
|
-
name:
|
|
90
|
+
name: rexml
|
|
78
91
|
requirement: !ruby/object:Gem::Requirement
|
|
79
92
|
requirements:
|
|
80
|
-
- - "
|
|
93
|
+
- - "~>"
|
|
81
94
|
- !ruby/object:Gem::Version
|
|
82
|
-
version:
|
|
95
|
+
version: '3.2'
|
|
83
96
|
type: :runtime
|
|
84
97
|
prerelease: false
|
|
85
98
|
version_requirements: !ruby/object:Gem::Requirement
|
|
86
99
|
requirements:
|
|
87
|
-
- - "
|
|
100
|
+
- - "~>"
|
|
88
101
|
- !ruby/object:Gem::Version
|
|
89
|
-
version:
|
|
102
|
+
version: '3.2'
|
|
90
103
|
- !ruby/object:Gem::Dependency
|
|
91
104
|
name: base64
|
|
92
105
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -135,7 +148,8 @@ files:
|
|
|
135
148
|
- fluent-plugin-parser-winevt_xml.gemspec
|
|
136
149
|
- lib/fluent/plugin/parser_winevt_sax.rb
|
|
137
150
|
- lib/fluent/plugin/parser_winevt_xml.rb
|
|
138
|
-
- lib/fluent/plugin/
|
|
151
|
+
- lib/fluent/plugin/winevt_sax_document_nokogiri.rb
|
|
152
|
+
- lib/fluent/plugin/winevt_sax_document_rexml.rb
|
|
139
153
|
- test/data/eventlog-with-qualifiers.xml
|
|
140
154
|
- test/data/eventlog.xml
|
|
141
155
|
- test/helper.rb
|
|
@@ -145,7 +159,6 @@ homepage: https://github.com/fluent/fluent-plugin-parser-winevt_xml
|
|
|
145
159
|
licenses:
|
|
146
160
|
- Apache-2.0
|
|
147
161
|
metadata: {}
|
|
148
|
-
post_install_message:
|
|
149
162
|
rdoc_options: []
|
|
150
163
|
require_paths:
|
|
151
164
|
- lib
|
|
@@ -160,8 +173,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
160
173
|
- !ruby/object:Gem::Version
|
|
161
174
|
version: '0'
|
|
162
175
|
requirements: []
|
|
163
|
-
rubygems_version:
|
|
164
|
-
signing_key:
|
|
176
|
+
rubygems_version: 4.0.10
|
|
165
177
|
specification_version: 4
|
|
166
178
|
summary: Fluentd Parser plugin to parse XML rendered windows event log.
|
|
167
179
|
test_files:
|