fluent-plugin-parser-winevt_xml 0.2.7 → 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 +83 -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 -18
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,8 +44,10 @@ module Fluent::Plugin
|
|
|
19
44
|
(low & 0xffff) | (high & 0xffff) << 16
|
|
20
45
|
end
|
|
21
46
|
|
|
22
|
-
def
|
|
23
|
-
|
|
47
|
+
def event_id_nokogiri(system_elem)
|
|
48
|
+
if @preserve_qualifiers
|
|
49
|
+
return ((system_elem/'EventID').text rescue nil)
|
|
50
|
+
end
|
|
24
51
|
|
|
25
52
|
qualifiers = (system_elem/'EventID').attribute("Qualifiers").text rescue nil
|
|
26
53
|
if qualifiers
|
|
@@ -32,16 +59,29 @@ module Fluent::Plugin
|
|
|
32
59
|
end
|
|
33
60
|
end
|
|
34
61
|
|
|
35
|
-
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)
|
|
36
76
|
record = {}
|
|
37
77
|
doc = Nokogiri::XML(text)
|
|
38
78
|
system_elem = doc/'Event'/'System'
|
|
39
79
|
record["ProviderName"] = (system_elem/"Provider").attribute("Name").text rescue nil
|
|
40
80
|
record["ProviderGUID"] = (system_elem/"Provider").attribute("Guid").text rescue nil
|
|
41
81
|
if @preserve_qualifiers
|
|
42
|
-
record["Qualifiers"]
|
|
82
|
+
record["Qualifiers"] = (system_elem/'EventID').attribute("Qualifiers").text rescue nil
|
|
43
83
|
end
|
|
44
|
-
record["EventID"] =
|
|
84
|
+
record["EventID"] = event_id_nokogiri(system_elem)
|
|
45
85
|
record["Level"] = (system_elem/'Level').text rescue nil
|
|
46
86
|
record["Task"] = (system_elem/'Task').text rescue nil
|
|
47
87
|
record["Opcode"] = (system_elem/'Opcode').text rescue nil
|
|
@@ -57,6 +97,43 @@ module Fluent::Plugin
|
|
|
57
97
|
record["UserID"] = (system_elem/'Security').attribute("UserID").text rescue nil
|
|
58
98
|
record["Version"] = (system_elem/'Version').text rescue nil
|
|
59
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
|
|
60
137
|
yield time, record
|
|
61
138
|
end
|
|
62
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,25 +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
|
-
- - "
|
|
81
|
-
- !ruby/object:Gem::Version
|
|
82
|
-
version: 1.12.5
|
|
83
|
-
- - "<"
|
|
93
|
+
- - "~>"
|
|
84
94
|
- !ruby/object:Gem::Version
|
|
85
|
-
version: '
|
|
95
|
+
version: '3.2'
|
|
86
96
|
type: :runtime
|
|
87
97
|
prerelease: false
|
|
88
98
|
version_requirements: !ruby/object:Gem::Requirement
|
|
89
99
|
requirements:
|
|
90
|
-
- - "
|
|
91
|
-
- !ruby/object:Gem::Version
|
|
92
|
-
version: 1.12.5
|
|
93
|
-
- - "<"
|
|
100
|
+
- - "~>"
|
|
94
101
|
- !ruby/object:Gem::Version
|
|
95
|
-
version: '
|
|
102
|
+
version: '3.2'
|
|
96
103
|
- !ruby/object:Gem::Dependency
|
|
97
104
|
name: base64
|
|
98
105
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -141,7 +148,8 @@ files:
|
|
|
141
148
|
- fluent-plugin-parser-winevt_xml.gemspec
|
|
142
149
|
- lib/fluent/plugin/parser_winevt_sax.rb
|
|
143
150
|
- lib/fluent/plugin/parser_winevt_xml.rb
|
|
144
|
-
- lib/fluent/plugin/
|
|
151
|
+
- lib/fluent/plugin/winevt_sax_document_nokogiri.rb
|
|
152
|
+
- lib/fluent/plugin/winevt_sax_document_rexml.rb
|
|
145
153
|
- test/data/eventlog-with-qualifiers.xml
|
|
146
154
|
- test/data/eventlog.xml
|
|
147
155
|
- test/helper.rb
|
|
@@ -151,7 +159,6 @@ homepage: https://github.com/fluent/fluent-plugin-parser-winevt_xml
|
|
|
151
159
|
licenses:
|
|
152
160
|
- Apache-2.0
|
|
153
161
|
metadata: {}
|
|
154
|
-
post_install_message:
|
|
155
162
|
rdoc_options: []
|
|
156
163
|
require_paths:
|
|
157
164
|
- lib
|
|
@@ -166,8 +173,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
166
173
|
- !ruby/object:Gem::Version
|
|
167
174
|
version: '0'
|
|
168
175
|
requirements: []
|
|
169
|
-
rubygems_version:
|
|
170
|
-
signing_key:
|
|
176
|
+
rubygems_version: 4.0.10
|
|
171
177
|
specification_version: 4
|
|
172
178
|
summary: Fluentd Parser plugin to parse XML rendered windows event log.
|
|
173
179
|
test_files:
|