@@ -49,18 +49,35 @@ fn parse_flowsets<'a>(
49
49
let mut remaining = i;
50
50
51
51
// Header.count represents total number of records in data + records in templates
52
- while count > 0 {
53
- let ( i, flowset) = FlowSet :: parse ( remaining, parser) ?;
54
- remaining = i;
52
+ while count > 0 && !remaining. is_empty ( ) {
53
+ let ( i, mut flowset) = FlowSet :: parse ( remaining, parser) ?;
55
54
56
- if flowset. template . is_some ( ) || flowset. options_template . is_some ( ) {
57
- count = count. saturating_sub ( 1 ) ;
58
- } else if let Some ( data) = flowset. data . as_ref ( ) {
55
+ if let Some ( data) = & flowset. templates {
56
+ count = count. saturating_sub ( data. len ( ) ) ;
57
+ }
58
+
59
+ if let Some ( data) = & flowset. options_templates {
60
+ count = count. saturating_sub ( data. len ( ) ) ;
61
+ }
62
+
63
+ if let Some ( data) = & flowset. data . as_ref ( ) {
59
64
count = count. saturating_sub ( data. data_fields . len ( ) ) ;
60
- } else if flowset. options_data . as_ref ( ) . is_some ( ) {
65
+ }
66
+
67
+ if flowset. options_data . as_ref ( ) . is_some ( ) {
61
68
count = count. saturating_sub ( 1 ) ;
62
69
}
63
70
71
+ if flowset. is_empty ( ) {
72
+ flowset. unparsed_data = Some ( remaining. to_vec ( ) ) ;
73
+ remaining = & [ ] ;
74
+ } else if flowset. is_unparsed ( ) {
75
+ flowset. unparsed_data = Some ( remaining[ ..flowset. length as usize ] . to_vec ( ) ) ;
76
+ remaining = & remaining[ flowset. length as usize ..] ;
77
+ } else {
78
+ remaining = i;
79
+ }
80
+
64
81
flowsets. push ( flowset)
65
82
}
66
83
@@ -104,26 +121,39 @@ pub struct FlowSet {
104
121
/// the template record that describes option fields (described below) has a
105
122
/// FlowSet ID of 1. A data record always has a nonzero FlowSet ID greater than 255.
106
123
pub flow_set_id : u16 ,
124
+ /// This field gives the length of the data FlowSet. Length is expressed in TLV format,
125
+ /// meaning that the value includes the bytes used for the FlowSet ID and the length bytes
126
+ /// themselves, as well as the combined lengths of any included data records.
127
+ pub length : u16 ,
107
128
/// Templates
108
129
#[ nom(
109
130
Cond = "flow_set_id == TEMPLATE_ID" ,
110
131
// Save our templates
111
- PostExec = "if let Some(template) = template.clone() { parser.templates.insert(template.template_id, template); }"
132
+ PostExec = "if let Some(templates) = templates.clone() {
133
+ for template in templates {
134
+ parser.templates.insert(template.template_id, template);
135
+ }
136
+ }"
112
137
) ]
113
138
#[ serde( skip_serializing_if = "Option::is_none" ) ]
114
- pub template : Option < Template > ,
139
+ pub templates : Option < Vec < Template > > ,
115
140
// Options template
116
141
#[ nom(
117
142
Cond = "flow_set_id == OPTIONS_TEMPLATE_ID" ,
143
+ Parse = "{ |i| parse_options_template_vec(i, length) }" ,
118
144
// Save our options templates
119
- PostExec = "if let Some(options_template) = options_template.clone() { parser.options_templates.insert(options_template.template_id, options_template); }"
145
+ PostExec = "if let Some(options_templates) = options_templates.clone() {
146
+ for template in options_templates {
147
+ parser.options_templates.insert(template.template_id, template);
148
+ }
149
+ }"
120
150
) ]
121
151
#[ serde( skip_serializing_if = "Option::is_none" ) ]
122
- pub options_template : Option < OptionsTemplate > ,
152
+ pub options_templates : Option < Vec < OptionsTemplate > > ,
123
153
// Options Data
124
154
#[ nom(
125
155
Cond = "flow_set_id > FLOW_SET_MIN_RANGE && parser.options_templates.get(&flow_set_id).is_some()" ,
126
- Parse = "{ |i| OptionsData::parse(i, parser, flow_set_id) }"
156
+ Parse = "{ |i| OptionsData::parse(i, parser, flow_set_id, length ) }"
127
157
) ]
128
158
#[ serde( skip_serializing_if = "Option::is_none" ) ]
129
159
pub options_data : Option < OptionsData > ,
@@ -134,18 +164,27 @@ pub struct FlowSet {
134
164
) ]
135
165
#[ serde( skip_serializing_if = "Option::is_none" ) ]
136
166
pub data : Option < Data > ,
167
+ // Unparsed data
168
+ #[ nom( Ignore ) ]
169
+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
170
+ pub unparsed_data : Option < Vec < u8 > > ,
171
+ }
172
+
173
+ impl FlowSet {
174
+ fn is_unparsed ( & self ) -> bool {
175
+ self . templates . is_none ( )
176
+ && self . options_templates . is_none ( )
177
+ && self . data . is_none ( )
178
+ && self . options_data . is_none ( )
179
+ }
180
+
181
+ fn is_empty ( & self ) -> bool {
182
+ self . length == 0
183
+ }
137
184
}
138
185
139
186
#[ derive( Debug , PartialEq , Clone , Serialize , Nom ) ]
140
187
pub struct Template {
141
- /// Length refers to the total length of this FlowSet. Because an individual
142
- /// template FlowSet may contain multiple template IDs (as illustrated above),
143
- /// the length value should be used to determine the position of the next FlowSet
144
- /// record, which could be either a template or a data FlowSet.
145
- /// Length is expressed in Type/Length/Value (TLV) format, meaning that the value
146
- /// includes the bytes used for the FlowSet ID and the length bytes themselves, as
147
- /// well as the combined lengths of all template records included in this FlowSet.
148
- pub length : u16 ,
149
188
/// As a router generates different template FlowSets to match the type of NetFlow
150
189
/// data it will be exporting, each template is given a unique ID. This uniqueness
151
190
/// is local to the router that generated the template ID.
@@ -162,10 +201,8 @@ pub struct Template {
162
201
}
163
202
164
203
#[ derive( Debug , PartialEq , Clone , Serialize , Nom ) ]
204
+ #[ nom( ExtraArgs ( flowset_length: u16 ) ) ]
165
205
pub struct OptionsTemplate {
166
- /// This field gives the total length of this FlowSet. Because an individual template FlowSet might contain multiple template IDs, the length value must be used to determine the position of the next FlowSet record, which might be either a template or a data FlowSet.
167
- /// Length is expressed in TLV format, meaning that the value includes the bytes used for the FlowSet ID and the length bytes themselves, and the combined lengths of all template records included in this FlowSet.
168
- pub length : u16 ,
169
206
/// As a router generates different template FlowSets to match the type of NetFlow data it is exporting, each template is given a unique ID. This uniqueness is local to the router that generated the template ID. The Template ID is greater than 255. Template IDs inferior to 255 are reserved.
170
207
pub template_id : u16 ,
171
208
/// This field gives the length in bytes of any scope fields that are contained in this options template.
@@ -181,12 +218,25 @@ pub struct OptionsTemplate {
181
218
/// Padding
182
219
#[ nom(
183
220
Map = "|i: &[u8]| i.to_vec()" ,
184
- Take = "(length .saturating_sub(options_scope_length).saturating_sub(options_length).saturating_sub(10)) as usize"
221
+ Take = "(flowset_length .saturating_sub(options_scope_length).saturating_sub(options_length).saturating_sub(10)) as usize"
185
222
) ]
186
223
#[ serde( skip_serializing) ]
187
224
padding : Vec < u8 > ,
188
225
}
189
226
227
+ fn parse_options_template_vec < ' a > (
228
+ i : & ' a [ u8 ] ,
229
+ flowset_length : u16 ,
230
+ ) -> IResult < & ' a [ u8 ] , Vec < OptionsTemplate > > {
231
+ let mut fields = vec ! [ ] ;
232
+ let mut remaining = i;
233
+ while let Ok ( ( rem, data) ) = OptionsTemplate :: parse ( remaining, flowset_length) {
234
+ fields. push ( data) ;
235
+ remaining = rem;
236
+ }
237
+ Ok ( ( remaining, fields) )
238
+ }
239
+
190
240
/// Options Scope Fields
191
241
#[ derive( Debug , PartialEq , Clone , Serialize , Nom ) ]
192
242
pub struct OptionsTemplateScopeField {
@@ -214,10 +264,8 @@ pub struct TemplateField {
214
264
}
215
265
216
266
#[ derive( Debug , PartialEq , Clone , Serialize , Nom ) ]
217
- #[ nom( ExtraArgs ( parser: & mut V9Parser , flow_set_id: u16 ) ) ]
267
+ #[ nom( ExtraArgs ( parser: & mut V9Parser , flow_set_id: u16 , flowset_length : u16 ) ) ]
218
268
pub struct OptionsData {
219
- // Length
220
- pub length : u16 ,
221
269
// Scope Data
222
270
#[ nom(
223
271
Parse = "{ |i| parse_scope_data_fields(i, flow_set_id, &parser.options_templates) }"
@@ -230,7 +278,7 @@ pub struct OptionsData {
230
278
pub options_fields : Vec < OptionDataField > ,
231
279
#[ nom(
232
280
Map = "|i: &[u8]| i.to_vec()" ,
233
- Take = "get_total_options_length(flow_set_id, length , parser)"
281
+ Take = "get_total_options_length(flow_set_id, flowset_length , parser)"
234
282
) ]
235
283
#[ serde( skip_serializing) ]
236
284
padding : Vec < u8 > ,
@@ -319,10 +367,6 @@ pub struct ScopeDataField {
319
367
#[ derive( Debug , PartialEq , Clone , Serialize , Nom ) ]
320
368
#[ nom( ExtraArgs ( parser: & mut V9Parser , flow_set_id: u16 ) ) ]
321
369
pub struct Data {
322
- /// This field gives the length of the data FlowSet. Length is expressed in TLV format,
323
- /// meaning that the value includes the bytes used for the FlowSet ID and the length bytes
324
- /// themselves, as well as the combined lengths of any included data records.
325
- pub length : u16 ,
326
370
// Data Fields
327
371
#[ nom( Parse = "{ |i| parse_fields(i, parser.templates.get(&flow_set_id)) }" ) ]
328
372
pub data_fields : Vec < BTreeMap < V9Field , FieldValue > > ,
0 commit comments