forked from elastic/beats
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcef.rl
159 lines (139 loc) · 5.42 KB
/
cef.rl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// Code generated by ragel DO NOT EDIT.
package cef
import (
"fmt"
"strconv"
"go.uber.org/multierr"
)
%%{
machine cef;
write data;
variable p p;
variable pe pe;
}%%
// unpack unpacks a CEF message.
func (e *Event) unpack(data string) error {
cs, p, pe, eof := 0, 0, len(data), len(data)
mark := 0
// Extension key.
var extKey string
// Extension value start and end indices.
extValueStart, extValueEnd := 0, 0
// recoveredErrs are problems with the message that the parser was able to
// recover from (though the parsing might not be "correct").
var recoveredErrs []error
e.init(data)
%%{
# Actions to execute while executing state machine.
action mark {
mark = p
}
action version {
e.Version, _ = strconv.Atoi(data[mark:p])
}
action device_vendor {
e.DeviceVendor = replaceHeaderEscapes(data[mark:p])
}
action device_product {
e.DeviceProduct = replaceHeaderEscapes(data[mark:p])
}
action device_version {
e.DeviceVersion = replaceHeaderEscapes(data[mark:p])
}
action device_event_class_id {
e.DeviceEventClassID = replaceHeaderEscapes(data[mark:p])
}
action name {
e.Name = replaceHeaderEscapes(data[mark:p])
}
action severity {
e.Severity = data[mark:p]
}
action extension_key {
// A new extension key marks the end of the last extension value.
if len(extKey) > 0 && extValueStart <= mark - 1 {
e.pushExtension(extKey, replaceExtensionEscapes(data[extValueStart:mark-1]))
extKey, extValueStart, extValueEnd = "", 0, 0
}
extKey = data[mark:p]
}
action extension_value_start {
extValueStart = p;
extValueEnd = p
}
action extension_value_mark {
extValueEnd = p+1
}
action extension_eof {
// Reaching the EOF marks the end of the final extension value.
if len(extKey) > 0 && extValueStart <= extValueEnd {
e.pushExtension(extKey, replaceExtensionEscapes(data[extValueStart:extValueEnd]))
extKey, extValueStart, extValueEnd = "", 0, 0
}
}
action extension_err {
recoveredErrs = append(recoveredErrs, fmt.Errorf("malformed value for %s at pos %d", extKey, p+1))
fhold; fgoto gobble_extension;
}
action recover_next_extension {
extKey, extValueStart, extValueEnd = "", 0, 0
// Resume processing at p, the start of the next extension key.
p = mark;
fgoto extensions;
}
# Define what header characters are allowed.
pipe = "|";
escape = "\\";
escape_pipe = escape pipe;
backslash = "\\\\";
device_chars = backslash | escape_pipe | (any -- pipe -- escape);
severity_chars = ( alpha | digit | "-" );
# Header fields.
version = "CEF:" digit+ >mark %version;
device_vendor = device_chars* >mark %device_vendor;
device_product = device_chars* >mark %device_product;
device_version = device_chars* >mark %device_version;
device_event_class_id = device_chars* >mark %device_event_class_id;
name = device_chars* >mark %name;
severity = severity_chars* >mark %severity;
header = version pipe
device_vendor pipe
device_product pipe
device_version pipe
device_event_class_id pipe
name pipe
severity pipe;
# Define what extension characters are allowed.
equal = "=";
escape_equal = escape equal;
# Only alnum is defined in the CEF spec. The other characters allow
# non-conforming extension keys to be parsed.
extension_key_start_chars = alnum | '_';
extension_key_chars = extension_key_start_chars | '.' | ',' | '[' | ']';
extension_key_pattern = extension_key_start_chars extension_key_chars*;
extension_value_chars_nospace = backslash | escape_equal | (any -- equal -- escape -- space);
# Extension fields.
extension_key = extension_key_pattern >mark %extension_key;
extension_value = (space* extension_value_chars_nospace @extension_value_mark)* >extension_value_start $err(extension_err);
extension = extension_key equal extension_value;
extensions = " "* extension (space* " " extension)* space* %/extension_eof;
# gobble_extension attempts recovery from a malformed value by trying to
# advance to the next extension key and re-entering the main state machine.
gobble_extension := any* (" " >mark) extension_key_pattern equal @recover_next_extension;
# CEF message.
cef = header extensions?;
main := cef;
write init;
write exec;
}%%
// Check if state machine completed.
if cs < cef_first_final {
// Reached an early end.
if p == pe {
return multierr.Append(multierr.Combine(recoveredErrs...), fmt.Errorf("unexpected end of CEF event"))
}
// Encountered invalid input.
return multierr.Append(multierr.Combine(recoveredErrs...), fmt.Errorf("error in CEF event at pos %d", p+1))
}
return multierr.Combine(recoveredErrs...)
}