nfrb 0.0.1.alpha

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.
@@ -0,0 +1,368 @@
1
+ /*
2
+ * This file is part of the nfrb gem for Ruby.
3
+ * Copyright (C) 2011 Davide Guerri
4
+ *
5
+ * This code is largely derived from nfreader.c of nfdump suite.
6
+ *
7
+ */
8
+
9
+ #include <ruby.h>
10
+
11
+ #include <stdio.h>
12
+ #include <unistd.h>
13
+ #include <stdlib.h>
14
+ #include <stdarg.h>
15
+ #include <errno.h>
16
+ #include <time.h>
17
+ #include <string.h>
18
+ #include <ctype.h>
19
+ #include <sys/types.h>
20
+ #include <sys/socket.h>
21
+ #include <netinet/in.h>
22
+ #include <arpa/inet.h>
23
+ #include <sys/stat.h>
24
+ #include <fcntl.h>
25
+
26
+ #include "nffile.h"
27
+ #include "nfx.h"
28
+ #include "util.h"
29
+
30
+ #include "config.h"
31
+
32
+ #if ( SIZEOF_VOID_P == 8 )
33
+ typedef uint64_t pointer_addr_t;
34
+ #else
35
+ typedef uint32_t pointer_addr_t;
36
+ #endif
37
+
38
+ #include "dnc/nffile_inline.c"
39
+
40
+ VALUE source_address_sym;
41
+ VALUE destination_address_sym;
42
+ VALUE first_seen_sym;
43
+ VALUE last_seen_sym;
44
+ VALUE msec_first_seen_sym;
45
+ VALUE msec_last_seen_sym;
46
+ VALUE protocol_sym;
47
+ VALUE source_port_sym;
48
+ VALUE destination_port_sym;
49
+ VALUE tcp_flags_sym;
50
+ VALUE packets_sym;
51
+ VALUE bytes_sym;
52
+ VALUE forwarding_status_sym;
53
+ VALUE tos_sym;
54
+ VALUE input_interface_sym;
55
+ VALUE output_interface_sym;
56
+ VALUE destination_as_sym;
57
+ VALUE source_as_sym;
58
+ VALUE source_mask_sym;
59
+ VALUE destination_mask_sym;
60
+ VALUE destination_tos_sym;
61
+ VALUE direction_sym;
62
+ VALUE next_hop_sym;
63
+ VALUE bgp_next_hop_sym;
64
+ VALUE source_vlan_sym;
65
+ VALUE destination_vlan_sym;
66
+
67
+ typedef struct nfreader_s {
68
+ extension_map_list_t ext_maps;
69
+ } nfreader_t;
70
+
71
+
72
+ static void nfreader_free(void *ptr) {
73
+ nfreader_t *nfreader_prt;
74
+ FreeExtensionMaps(&nfreader_prt->ext_maps);
75
+ }
76
+
77
+ static int process_file(extension_map_list_t *ext_maps, nffile_t *nffile) {
78
+ master_record_t master_record;
79
+ common_record_t *flow_record = NULL;
80
+ int done, ret, i, j, id;
81
+ char source_ip[40], destination_ip[40], nexthop_ip[40];
82
+ VALUE hash_v;
83
+
84
+ hash_v = rb_hash_new();
85
+
86
+ done = 0;
87
+ while (!done) {
88
+ // get next data block from file
89
+ ret = ReadBlock(nffile);
90
+
91
+ switch (ret) {
92
+ case NF_CORRUPT:
93
+ case NF_ERROR:
94
+ return ret; // Corrupt datafile
95
+ case NF_EOF: {
96
+ done = 1;
97
+ continue;
98
+ } break; // not really needed
99
+ }
100
+
101
+ if (nffile->block_header->id == Large_BLOCK_Type) {
102
+ // skip
103
+ continue;
104
+ }
105
+
106
+ if (nffile->block_header->id != DATA_BLOCK_TYPE_2) {
107
+ // Can't process block type "nffile->block_header->id". Skip block...
108
+ continue;
109
+ }
110
+
111
+ flow_record = nffile->buff_ptr;
112
+ for (i=0; i < nffile->block_header->NumRecords; i++) {
113
+ if (flow_record->type == CommonRecordType) {
114
+ uint32_t map_id = flow_record->ext_map;
115
+ if (ext_maps->slot[map_id] == NULL) {
116
+ // Corrupt data file! No such extension map id: "flow_record->ext_map". Skip record...
117
+ } else {
118
+ ExpandRecord_v2(flow_record, ext_maps->slot[flow_record->ext_map], &master_record);
119
+
120
+ // update number of flows matching a given map
121
+ ext_maps->slot[map_id]->ref_count++;
122
+
123
+ // Prepare an hash for the ruby block paramater
124
+ if ( (master_record.flags & FLAG_IPV6_ADDR ) != 0 ) { // IPv6
125
+ master_record.v6.srcaddr[0] = htonll(master_record.v6.srcaddr[0]);
126
+ master_record.v6.srcaddr[1] = htonll(master_record.v6.srcaddr[1]);
127
+ master_record.v6.dstaddr[0] = htonll(master_record.v6.dstaddr[0]);
128
+ master_record.v6.dstaddr[1] = htonll(master_record.v6.dstaddr[1]);
129
+ inet_ntop(AF_INET6, master_record.v6.srcaddr, source_ip, sizeof(source_ip));
130
+ inet_ntop(AF_INET6, master_record.v6.dstaddr, destination_ip, sizeof(destination_ip));
131
+ } else { // IPv4
132
+ master_record.v4.srcaddr = htonl(master_record.v4.srcaddr);
133
+ master_record.v4.dstaddr = htonl(master_record.v4.dstaddr);
134
+ inet_ntop(AF_INET, &master_record.v4.srcaddr, source_ip, sizeof(source_ip));
135
+ inet_ntop(AF_INET, &master_record.v4.dstaddr, destination_ip, sizeof(destination_ip));
136
+ }
137
+ source_ip[40-1] = 0;
138
+ destination_ip[40-1] = 0;
139
+
140
+ // netflow common record fields
141
+ rb_hash_aset(hash_v, source_address_sym, rb_tainted_str_new2(source_ip));
142
+ rb_hash_aset(hash_v, destination_address_sym, rb_tainted_str_new2(destination_ip));
143
+ rb_hash_aset(hash_v, first_seen_sym, INT2NUM(master_record.first));
144
+ rb_hash_aset(hash_v, last_seen_sym, INT2NUM(master_record.last));
145
+ rb_hash_aset(hash_v, msec_first_seen_sym, INT2NUM(master_record.msec_first));
146
+ rb_hash_aset(hash_v, msec_last_seen_sym, INT2NUM(master_record.msec_last));
147
+ rb_hash_aset(hash_v, protocol_sym, INT2FIX(master_record.prot));
148
+ rb_hash_aset(hash_v, source_port_sym, INT2FIX(master_record.srcport));
149
+ rb_hash_aset(hash_v, destination_port_sym, INT2FIX(master_record.dstport));
150
+ rb_hash_aset(hash_v, tcp_flags_sym, INT2FIX(master_record.tcp_flags));
151
+ rb_hash_aset(hash_v, packets_sym, INT2NUM((unsigned long long) master_record.dPkts));
152
+ rb_hash_aset(hash_v, bytes_sym, INT2NUM((unsigned long long) master_record.dOctets));
153
+ rb_hash_aset(hash_v, forwarding_status_sym, INT2FIX(master_record.fwd_status));
154
+ rb_hash_aset(hash_v, tos_sym, INT2FIX(master_record.tos));
155
+
156
+ // netflow extension fields
157
+ rb_hash_aset(hash_v, input_interface_sym , Qnil);
158
+ rb_hash_aset(hash_v, output_interface_sym, Qnil);
159
+ rb_hash_aset(hash_v, destination_as_sym , Qnil);
160
+ rb_hash_aset(hash_v, source_as_sym , Qnil);
161
+ rb_hash_aset(hash_v, source_mask_sym , Qnil);
162
+ rb_hash_aset(hash_v, destination_mask_sym, Qnil);
163
+ rb_hash_aset(hash_v, destination_tos_sym , Qnil);
164
+ rb_hash_aset(hash_v, direction_sym , Qnil);
165
+ rb_hash_aset(hash_v, next_hop_sym , Qnil);
166
+ rb_hash_aset(hash_v, bgp_next_hop_sym , Qnil);
167
+ rb_hash_aset(hash_v, source_vlan_sym , Qnil);
168
+ rb_hash_aset(hash_v, destination_vlan_sym, Qnil);
169
+
170
+ j=0;
171
+ while ( (id = master_record.map_ref->ex_id[j++]) != 0 ) {
172
+ switch(id) {
173
+ case EX_IO_SNMP_2:
174
+ rb_hash_aset(hash_v, input_interface_sym, INT2FIX(master_record.input));
175
+ rb_hash_aset(hash_v, output_interface_sym, INT2FIX(master_record.output));
176
+ break;
177
+ case EX_IO_SNMP_4:
178
+ rb_hash_aset(hash_v, input_interface_sym, INT2NUM(master_record.input));
179
+ rb_hash_aset(hash_v, output_interface_sym, INT2NUM(master_record.output));
180
+ break;
181
+ case EX_AS_2:
182
+ rb_hash_aset(hash_v, destination_as_sym, INT2FIX(master_record.dstas));
183
+ rb_hash_aset(hash_v, source_as_sym, INT2FIX(master_record.input));
184
+ break;
185
+ case EX_AS_4:
186
+ rb_hash_aset(hash_v, destination_as_sym, INT2NUM(master_record.dstas));
187
+ rb_hash_aset(hash_v, source_as_sym, INT2NUM(master_record.input));
188
+ break;
189
+ case EX_MULIPLE:
190
+ rb_hash_aset(hash_v, source_mask_sym, INT2NUM(master_record.src_mask));
191
+ rb_hash_aset(hash_v, destination_mask_sym, INT2NUM(master_record.dst_mask));
192
+ rb_hash_aset(hash_v, destination_tos_sym, INT2FIX(master_record.dst_tos));
193
+ rb_hash_aset(hash_v, direction_sym, INT2FIX(master_record.dir));
194
+ break;
195
+ case EX_NEXT_HOP_v4:
196
+ master_record.ip_nexthop.v4=htonl(master_record.ip_nexthop.v4);
197
+ nexthop_ip[0] = 0;
198
+ inet_ntop(AF_INET, &master_record.ip_nexthop.v4, nexthop_ip, sizeof(nexthop_ip));
199
+ nexthop_ip[40-1] = 0;
200
+ rb_hash_aset(hash_v, next_hop_sym, rb_tainted_str_new2(nexthop_ip));
201
+ break;
202
+ case EX_NEXT_HOP_v6:
203
+ nexthop_ip[0] = 0;
204
+ master_record.ip_nexthop.v6[0] = htonll(master_record.ip_nexthop.v6[0]);
205
+ master_record.ip_nexthop.v6[1] = htonll(master_record.ip_nexthop.v6[1]);
206
+ inet_ntop(AF_INET6, master_record.ip_nexthop.v6, nexthop_ip, sizeof(nexthop_ip));
207
+ nexthop_ip[40-1] = 0;
208
+ rb_hash_aset(hash_v, next_hop_sym, rb_tainted_str_new2(nexthop_ip));
209
+ break;
210
+ case EX_NEXT_HOP_BGP_v4:
211
+ master_record.ip_nexthop.v4=htonl(master_record.bgp_nexthop.v4);
212
+ nexthop_ip[0] = 0;
213
+ inet_ntop(AF_INET, &master_record.bgp_nexthop.v4, nexthop_ip, sizeof(nexthop_ip));
214
+ nexthop_ip[40-1] = 0;
215
+ rb_hash_aset(hash_v, bgp_next_hop_sym, rb_tainted_str_new2(nexthop_ip));
216
+ break;
217
+ case EX_NEXT_HOP_BGP_v6:
218
+ nexthop_ip[0] = 0;
219
+ master_record.bgp_nexthop.v6[0] = htonll(master_record.bgp_nexthop.v6[0]);
220
+ master_record.bgp_nexthop.v6[1] = htonll(master_record.bgp_nexthop.v6[1]);
221
+ inet_ntop(AF_INET6, master_record.bgp_nexthop.v6, nexthop_ip, sizeof(nexthop_ip));
222
+ nexthop_ip[40-1] = 0;
223
+ rb_hash_aset(hash_v, bgp_next_hop_sym, rb_tainted_str_new2(nexthop_ip));
224
+ break;
225
+ case EX_VLAN:
226
+ rb_hash_aset(hash_v, source_vlan_sym, INT2FIX(master_record.src_vlan));
227
+ rb_hash_aset(hash_v, destination_vlan_sym, INT2FIX(master_record.dst_vlan));
228
+ break;
229
+ default:
230
+ ;
231
+ // Not implemented
232
+ }
233
+ }
234
+
235
+ // Yield to the ruby block
236
+ rb_yield(hash_v);
237
+ }
238
+
239
+ } else if (flow_record->type == ExtensionMapType) {
240
+ extension_map_t *map = (extension_map_t *)flow_record;
241
+ Insert_Extension_Map(ext_maps, map);
242
+ } // else Skip unknown record type flow_record->type
243
+ // Advance pointer by number of bytes for netflow record
244
+ flow_record = (common_record_t *)((pointer_addr_t)flow_record + flow_record->size);
245
+ } // for all records
246
+ } // while
247
+
248
+ return 0;
249
+
250
+ } // End of process_data
251
+
252
+ static VALUE rb_process_file(VALUE self, VALUE filename_v) {
253
+ nfreader_t *nfreader_prt = NULL;
254
+ nffile_t *nffile = NULL;
255
+ int ret;
256
+
257
+ Check_Type(filename_v, T_STRING);
258
+
259
+ Data_Get_Struct(self, nfreader_t, nfreader_prt);
260
+ InitExtensionMaps(&nfreader_prt->ext_maps);
261
+
262
+ nffile = OpenFile(RSTRING(filename_v)->ptr, NULL);
263
+ if (!nffile)
264
+ rb_raise(rb_eIOError, "problem opening file '%s'", RSTRING(filename_v)->ptr);
265
+
266
+ ret = process_file(&nfreader_prt->ext_maps, nffile);
267
+
268
+ CloseFile(nffile);
269
+ DisposeFile(nffile);
270
+
271
+ PackExtensionMapList(&nfreader_prt->ext_maps);
272
+
273
+ return Qnil;
274
+ }
275
+
276
+ static VALUE rb_process_files(VALUE self, VALUE filenames_a) {
277
+ nfreader_t *nfreader_prt = NULL;
278
+ nffile_t *nffile = NULL;
279
+ VALUE filename_v;
280
+ long i;
281
+ int ret;
282
+
283
+ Check_Type(filenames_a, T_ARRAY);
284
+
285
+ if (!rb_block_given_p())
286
+ rb_raise(rb_eArgError, "a block is required");
287
+
288
+ Data_Get_Struct(self, nfreader_t, nfreader_prt);
289
+ InitExtensionMaps(&nfreader_prt->ext_maps);
290
+
291
+ for (i=0 ; i < RARRAY_LEN(filenames_a) ; i++) {
292
+ filename_v = rb_ary_entry(filenames_a, i);
293
+ Check_Type(filename_v, T_STRING);
294
+
295
+ nffile = OpenFile(RSTRING(filename_v)->ptr, NULL);
296
+ if (!nffile)
297
+ rb_raise(rb_eIOError, "problem opening file '%s'", RSTRING(filename_v)->ptr);
298
+
299
+ ret = process_file(&nfreader_prt->ext_maps, nffile);
300
+
301
+ CloseFile(nffile);
302
+ DisposeFile(nffile);
303
+ }
304
+
305
+ PackExtensionMapList(&nfreader_prt->ext_maps);
306
+
307
+ return Qnil;
308
+ }
309
+
310
+
311
+ static VALUE rb_nfreader_init(VALUE self) {
312
+ nfreader_t *nfreader_prt = NULL;
313
+
314
+ Data_Get_Struct(self, nfreader_t, nfreader_prt);
315
+
316
+ return self;
317
+ }
318
+
319
+
320
+ VALUE rb_nfreader_new(VALUE nfreader_class) {
321
+ nfreader_t *nfreader_prt = NULL;
322
+
323
+ VALUE nfreader_data = Data_Make_Struct(nfreader_class, nfreader_t, NULL, NULL, nfreader_prt);
324
+
325
+ rb_obj_call_init(nfreader_data, 0, NULL);
326
+
327
+ return nfreader_data;
328
+ }
329
+
330
+
331
+ void Init_rb_nfrb() {
332
+ VALUE nfrbModule = rb_define_module("NfRb");
333
+
334
+ VALUE rb_nfreader_class = rb_define_class_under(nfrbModule, "NfReader", rb_cObject);
335
+ rb_define_singleton_method(rb_nfreader_class, "new", rb_nfreader_new, 0);
336
+ rb_define_method(rb_nfreader_class, "initialize", rb_nfreader_init, 0);
337
+ rb_define_method(rb_nfreader_class, "process_file", rb_process_file, 1);
338
+ rb_define_method(rb_nfreader_class, "process_files", rb_process_files, 1);
339
+
340
+ // Symbols inits
341
+ source_address_sym = ID2SYM(rb_intern("source_address"));
342
+ destination_address_sym = ID2SYM(rb_intern("destination_address"));
343
+ first_seen_sym = ID2SYM(rb_intern("first_seen"));
344
+ last_seen_sym = ID2SYM(rb_intern("last_seen"));
345
+ msec_first_seen_sym = ID2SYM(rb_intern("msec_first_seen"));
346
+ msec_last_seen_sym = ID2SYM(rb_intern("msec_last_seen"));
347
+ protocol_sym = ID2SYM(rb_intern("protocol"));
348
+ source_port_sym = ID2SYM(rb_intern("source_port"));
349
+ destination_port_sym = ID2SYM(rb_intern("destination_port"));
350
+ tcp_flags_sym = ID2SYM(rb_intern("tcp_flags"));
351
+ packets_sym = ID2SYM(rb_intern("packets"));
352
+ bytes_sym = ID2SYM(rb_intern("bytes"));
353
+ forwarding_status_sym = ID2SYM(rb_intern("forwarding_status"));
354
+ tos_sym = ID2SYM(rb_intern("tos"));
355
+ input_interface_sym = ID2SYM(rb_intern("input_interface"));
356
+ output_interface_sym = ID2SYM(rb_intern("output_interface"));
357
+ destination_as_sym = ID2SYM(rb_intern("destination_as"));
358
+ source_as_sym = ID2SYM(rb_intern("source_as"));
359
+ source_mask_sym = ID2SYM(rb_intern("source_mask"));
360
+ destination_mask_sym = ID2SYM(rb_intern("destination_mask"));
361
+ destination_tos_sym = ID2SYM(rb_intern("destination_tos"));
362
+ direction_sym = ID2SYM(rb_intern("direction"));
363
+ next_hop_sym = ID2SYM(rb_intern("next_hop"));
364
+ bgp_next_hop_sym = ID2SYM(rb_intern("bgp_next_hop"));
365
+ source_vlan_sym = ID2SYM(rb_intern("source_vlan"));
366
+ destination_vlan_sym = ID2SYM(rb_intern("destination_vlan"));
367
+
368
+ }
@@ -0,0 +1,636 @@
1
+ /*
2
+ * Copyright (c) 2009, Peter Haag
3
+ * Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
4
+ * All rights reserved.
5
+ *
6
+ * Redistribution and use in source and binary forms, with or without
7
+ * modification, are permitted provided that the following conditions are met:
8
+ *
9
+ * * Redistributions of source code must retain the above copyright notice,
10
+ * this list of conditions and the following disclaimer.
11
+ * * Redistributions in binary form must reproduce the above copyright notice,
12
+ * this list of conditions and the following disclaimer in the documentation
13
+ * and/or other materials provided with the distribution.
14
+ * * Neither the name of SWITCH nor the names of its contributors may be
15
+ * used to endorse or promote products derived from this software without
16
+ * specific prior written permission.
17
+ *
18
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
+ * POSSIBILITY OF SUCH DAMAGE.
29
+ *
30
+ * $Author: haag $
31
+ *
32
+ * $Id: nfx.c 58 2010-02-26 12:26:07Z haag $
33
+ *
34
+ * $LastChangedRevision: 58 $
35
+ *
36
+ */
37
+
38
+ #include "config.h"
39
+
40
+ #include <sys/types.h>
41
+ #include <unistd.h>
42
+ #include <stdio.h>
43
+ #include <errno.h>
44
+ #include <unistd.h>
45
+ #include <stdlib.h>
46
+ #include <ctype.h>
47
+ #include <string.h>
48
+ #include <syslog.h>
49
+ #include <stdarg.h>
50
+
51
+ #ifdef HAVE_STDINT_H
52
+ #include <stdint.h>
53
+ #endif
54
+
55
+ #ifndef DEVEL
56
+ # define dbg_printf(...) /* printf(__VA_ARGS__) */
57
+ #else
58
+ # define dbg_printf(...) printf(__VA_ARGS__)
59
+ #endif
60
+
61
+ #include "nf_common.h"
62
+ #include "nffile.h"
63
+ #include "util.h"
64
+ #include "nfx.h"
65
+
66
+ /* global vars */
67
+
68
+ /*
69
+ * see nffile.h for detailed extension description
70
+ */
71
+ extension_descriptor_t extension_descriptor[] = {
72
+ // fill indices 0 - 3
73
+ { COMMON_BLOCK_ID, 0, 0, 1, "Required extension: Common record"},
74
+ { EX_IPv4v6, 0, 0, 1, "Required extension: IPv4/IPv6 src/dst address"},
75
+ { EX_PACKET_4_8, 0, 0, 1, "Required extension: 4/8 byte input packets"},
76
+ { EX_BYTE_4_8, 0, 0, 1, "Required extension: 4/8 byte input bytes"},
77
+
78
+ // the optional extension
79
+ { EX_IO_SNMP_2, 4, 1, 1, "2 byte input/output interface index"},
80
+ { EX_IO_SNMP_4, 8, 1, 1, "4 byte input/output interface index"},
81
+ { EX_AS_2, 4, 2, 1, "2 byte src/dst AS number"},
82
+ { EX_AS_4, 8, 2, 1, "4 byte src/dst AS number"},
83
+ { EX_MULIPLE, 4, 3, 0, "dst tos, direction, src/dst mask"},
84
+ { EX_NEXT_HOP_v4, 4, 4, 0, "IPv4 next hop"},
85
+ { EX_NEXT_HOP_v6, 16, 4, 0, "IPv6 next hop"},
86
+ { EX_NEXT_HOP_BGP_v4, 4, 5, 0, "IPv4 BGP next IP"},
87
+ { EX_NEXT_HOP_BGP_v6, 16, 5, 0, "IPv6 BGP next IP"},
88
+ { EX_VLAN, 4, 6, 0, "src/dst vlan id"},
89
+ { EX_OUT_PKG_4, 4, 7, 0, "4 byte output packets"},
90
+ { EX_OUT_PKG_8, 8, 7, 0, "8 byte output packets"},
91
+ { EX_OUT_BYTES_4, 4, 8, 0, "4 byte output bytes"},
92
+ { EX_OUT_BYTES_8, 8, 8, 0, "8 byte output bytes"},
93
+ { EX_AGGR_FLOWS_4, 4, 9, 0, "4 byte aggregated flows"},
94
+ { EX_AGGR_FLOWS_8, 8, 9, 0, "8 byte aggregated flows"},
95
+ { EX_MAC_1, 16, 10, 0, "in src/out dst mac address"},
96
+ { EX_MAC_2, 16, 11, 0, "in dst/out src mac address"},
97
+ { EX_MPLS, 40, 12, 0, "MPLS Labels"},
98
+ { EX_ROUTER_IP_v4, 4, 13, 0, "IPv4 router IP addr"},
99
+ { EX_ROUTER_IP_v6, 16, 13, 0, "IPv6 router IP addr"},
100
+ { EX_ROUTER_ID, 4, 14, 0, "router ID"},
101
+
102
+ // last entry
103
+ { 0, 0, 0, 0, NULL }
104
+ };
105
+
106
+ uint32_t Max_num_extensions;
107
+
108
+ void FixExtensionMap(extension_map_t *map);
109
+
110
+ void InitExtensionMaps(extension_map_list_t *extension_map_list ) {
111
+ int i;
112
+ memset((void *)extension_map_list->slot, 0, MAX_EXTENSION_MAPS * sizeof(extension_info_t *));
113
+ memset((void *)extension_map_list->page, 0, MAX_EXTENSION_MAPS * sizeof(extension_info_t *));
114
+
115
+ extension_map_list->next_free = 0;
116
+ extension_map_list->max_used = -1;
117
+
118
+ Max_num_extensions = 0;
119
+ i = 1;
120
+ while ( extension_descriptor[i++].id )
121
+ Max_num_extensions++;
122
+
123
+ } // End of InitExtensionMaps
124
+
125
+ void FreeExtensionMaps(extension_map_list_t *extension_map_list) {
126
+ int i;
127
+
128
+ if ( extension_map_list == NULL )
129
+ return;
130
+
131
+ // free all maps
132
+ for ( i=0; i <= extension_map_list->max_used; i++ ) {
133
+ if ( extension_map_list->slot[i] ) {
134
+ if ( extension_map_list->slot[i]->map ) {
135
+ free(extension_map_list->slot[i]->map);
136
+ extension_map_list->slot[i]->map = NULL;
137
+ }
138
+ free(extension_map_list->slot[i]);
139
+ extension_map_list->slot[i] = NULL;
140
+ }
141
+
142
+ }
143
+
144
+ // free all paged maps
145
+ for ( i=0; i < extension_map_list->next_free; i++ ) {
146
+ if ( extension_map_list->page[i] ) {
147
+ if ( extension_map_list->page[i]->map ) {
148
+ free(extension_map_list->page[i]->map);
149
+ extension_map_list->page[i]->map = NULL;
150
+ }
151
+ free(extension_map_list->page[i]);
152
+ extension_map_list->page[i] = NULL;
153
+ }
154
+ }
155
+
156
+ InitExtensionMaps(extension_map_list);
157
+
158
+ } // End of FreeExtensionMaps
159
+
160
+ int Insert_Extension_Map(extension_map_list_t *extension_map_list, extension_map_t *map) {
161
+ uint32_t next_free = extension_map_list->next_free;
162
+ uint16_t map_id;
163
+
164
+ map_id = map->map_id == INIT_ID ? 0 : map->map_id & EXTENSION_MAP_MASK;
165
+ map->map_id = map_id;
166
+ dbg_printf("Insert Extension Map:\n");
167
+ #ifdef DEVEL
168
+ PrintExtensionMap(map);
169
+ #endif
170
+ // is this slot free
171
+ if ( extension_map_list->slot[map_id] ) {
172
+ int i, map_found;
173
+ dbg_printf("Map %d already exists\n", map_id);
174
+ // no - check if same map already in slot
175
+ if ( extension_map_list->slot[map_id]->map->size == map->size ) {
176
+ // existing map and new map have the same size
177
+ dbg_printf("New map same size:\n");
178
+
179
+ // we must compare the maps
180
+ i = 0;
181
+ while ( extension_map_list->slot[map_id]->map->ex_id[i] && (extension_map_list->slot[map_id]->map->ex_id[i] == map->ex_id[i]) )
182
+ i++;
183
+
184
+ // if last entry == 0 => last map entry => maps are the same
185
+ if ( extension_map_list->slot[map_id]->map->ex_id[i] == 0 ) {
186
+ dbg_printf("Same map => nothing to do\n");
187
+ // same map
188
+ return 0;
189
+ }
190
+ dbg_printf("Different map => continue\n");
191
+ }
192
+
193
+ dbg_printf("Search for map in extension page\n");
194
+ map_found = -1;
195
+ // new map is different but has same id - search for map in page list
196
+ for ( i = 0 ; i < next_free; i++ ) {
197
+ int j;
198
+ j = 0;
199
+ if ( extension_map_list->page[i]->map->size == map->size ) {
200
+ while ( extension_map_list->page[i]->map->ex_id[j] && (extension_map_list->page[i]->map->ex_id[j] == map->ex_id[j]) )
201
+ j++;
202
+ }
203
+ if ( extension_map_list->page[i]->map->ex_id[j] == 0 ) {
204
+ dbg_printf("Map found in page slot %i\n", i);
205
+ map_found = i;
206
+ }
207
+ }
208
+ if ( map_found >= 0 ) {
209
+ extension_info_t *tmp;
210
+ dbg_printf("Move map from page slot %i to slot %i\n", map_found ,map_id);
211
+
212
+ // exchange the two maps
213
+ tmp = extension_map_list->slot[map_id];
214
+ extension_map_list->slot[map_id] = extension_map_list->page[map_found];
215
+ extension_map_list->slot[map_id]->map->map_id = map_id;
216
+
217
+ extension_map_list->page[map_found] = tmp;
218
+ extension_map_list->page[map_found]->map->map_id = map_found;
219
+ return 1;
220
+
221
+ } else {
222
+ dbg_printf("Map not found in extension page\n");
223
+ // map not found - move it to the extension page to a currently free slot
224
+ if ( next_free < MAX_EXTENSION_MAPS ) {
225
+ dbg_printf("Move existing map from slot %d to page slot %d\n",map_id, next_free);
226
+ extension_map_list->page[next_free] = extension_map_list->slot[map_id];
227
+ extension_map_list->page[next_free]->map->map_id = next_free;
228
+ extension_map_list->slot[map_id] = NULL;
229
+ // ready to fill new slot
230
+ } else {
231
+ fprintf(stderr, "Extension map list exhausted - too many extension maps ( > %d ) to process;\n", MAX_EXTENSION_MAPS);
232
+ exit(255);
233
+ }
234
+ }
235
+ }
236
+
237
+ FixExtensionMap(map);
238
+
239
+ // add new entry to slot
240
+ extension_map_list->slot[map_id] = (extension_info_t *)calloc(1,sizeof(extension_info_t));
241
+ if ( !extension_map_list->slot[map_id] ) {
242
+ fprintf(stderr, "calloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
243
+ exit(255);
244
+ }
245
+ extension_map_list->slot[map_id]->map = (extension_map_t *)malloc((ssize_t)map->size);
246
+ if ( !extension_map_list->slot[map_id]->map ) {
247
+ fprintf(stderr, "malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
248
+ exit(255);
249
+ }
250
+ memcpy((void *)extension_map_list->slot[map->map_id]->map, (void *)map, map->size);
251
+
252
+ extension_map_list->slot[map_id]->ref_count = 0;
253
+
254
+ if ( map_id > extension_map_list->max_used ) {
255
+ extension_map_list->max_used = map_id;
256
+ }
257
+
258
+ // Update next_free page slot, if it's used now
259
+ while ( extension_map_list->page[next_free] && (next_free < MAX_EXTENSION_MAPS))
260
+ next_free++;
261
+ extension_map_list->next_free = next_free;
262
+
263
+ // if all slots are exhausted next_free is now MAX_EXTENSION_MAPS. The next time an empty slot is needed, it will properly fail.
264
+ dbg_printf("Installed map in slot %d. Next free page slot: %d\n", map_id, next_free);
265
+
266
+ //map changed
267
+ return 1;
268
+
269
+ } // End of Insert_Extension_Map
270
+
271
+ void PackExtensionMapList(extension_map_list_t *extension_map_list) {
272
+ int i, free_slot;
273
+
274
+ dbg_printf("Pack extensions maps\n");
275
+ // compact extension map list - close gaps
276
+ free_slot = -1;
277
+ for ( i=0; i <= extension_map_list->max_used; i++ ) {
278
+ dbg_printf("Check slot: %i, ref: %u\n", i, extension_map_list->slot[i] ? extension_map_list->slot[i]->ref_count : 0);
279
+ if ( extension_map_list->slot[i] != NULL && extension_map_list->slot[i]->ref_count == 0 ) {
280
+ // Destroy slot, if no flows referenced this map
281
+ free(extension_map_list->slot[i]->map);
282
+ free(extension_map_list->slot[i]);
283
+ extension_map_list->slot[i] = NULL;
284
+ dbg_printf("Free slot: %i\n", i);
285
+ }
286
+ if ( extension_map_list->slot[i] == NULL && free_slot == -1 ) {
287
+ // remember this free slot
288
+ dbg_printf("Remember free slot at %i\n", i);
289
+ free_slot = i;
290
+ } else if ( free_slot != -1 && extension_map_list->slot[i] != NULL ) {
291
+ int j;
292
+ // move this slot down to compact the list
293
+ extension_map_list->slot[free_slot] = extension_map_list->slot[i];
294
+ extension_map_list->slot[free_slot]->map->map_id = free_slot;
295
+ extension_map_list->slot[i] = NULL;
296
+ dbg_printf("Move slot %i down to %i\n", i, free_slot);
297
+
298
+ // search for next free slot - latest slot[i] is free now
299
+ for ( j = free_slot + 1; j <= i; j++ ) {
300
+ if ( extension_map_list->slot[j] == NULL ) {
301
+ free_slot = j;
302
+ dbg_printf("Next free slot found at %i\n", free_slot);
303
+ break;
304
+ }
305
+ }
306
+ } else {
307
+ dbg_printf("Fell through\n");
308
+ }
309
+ }
310
+
311
+ // get max index - set index to map
312
+ i = 0;
313
+ while ( extension_map_list->slot[i] != NULL && i < MAX_EXTENSION_MAPS ) {
314
+ dbg_printf("Slot: %i, ref: %u\n", i, extension_map_list->slot[i]->ref_count);
315
+ i++;
316
+ }
317
+
318
+ if ( i == MAX_EXTENSION_MAPS ) {
319
+ // ups! - should not really happen - so we are done for now
320
+ if ( extension_map_list->next_free == 0 ) {
321
+ // map slots full but no maps im page list - we are done
322
+ return;
323
+ } else {
324
+ // we can't handle this event for now - too many maps - but MAX_EXTENSION_MAPS should be more than enough
325
+ fprintf(stderr, "Critical error in %s line %d: %s\n", __FILE__, __LINE__, "Out of maps!" );
326
+ exit(255);
327
+ }
328
+ }
329
+
330
+ // this points to the next free slot
331
+ free_slot = i;
332
+
333
+ for ( i=0; i < extension_map_list->next_free; i++ ) {
334
+ if ( free_slot < MAX_EXTENSION_MAPS ) {
335
+ if ( extension_map_list->page[i]->ref_count ) {
336
+ dbg_printf("Move page %u to slot %u\n", i, free_slot);
337
+ extension_map_list->slot[free_slot] = extension_map_list->page[i];
338
+ extension_map_list->slot[free_slot]->map->map_id = free_slot;
339
+ extension_map_list->page[i] = NULL;
340
+ free_slot++;
341
+ } else {
342
+ dbg_printf("Skip page %u. Zero ref count \n", i);
343
+ }
344
+ } else {
345
+ // we can't handle this event for now, but should not happen anyway
346
+ fprintf(stderr, "Critical error in %s line %d: %s\n", __FILE__, __LINE__, "Out of maps!" );
347
+ exit(255);
348
+ }
349
+ }
350
+
351
+ extension_map_list->max_used = free_slot - 1;
352
+ dbg_printf("Packed maps: %i\n", free_slot);
353
+
354
+ #ifdef DEVEL
355
+ // Check maps
356
+ i = 0;
357
+ while ( extension_map_list->slot[i] != NULL && i < MAX_EXTENSION_MAPS ) {
358
+ if ( extension_map_list->slot[i]->map->map_id != i )
359
+ printf("*** Map ID missmatch in slot: %i, id: %u\n", i, extension_map_list->slot[i]->map->map_id);
360
+ i++;
361
+ }
362
+ #endif
363
+
364
+ } // End of PackExtensionMapList
365
+
366
+ void SetupExtensionDescriptors(char *options) {
367
+ int i, *mask;
368
+ char *p, *q, *s;
369
+
370
+ Max_num_extensions = 0;
371
+ i = 1;
372
+ while ( extension_descriptor[i++].id )
373
+ Max_num_extensions++;
374
+
375
+ mask = (int *)calloc(Max_num_extensions+1, sizeof(int));
376
+ if ( !mask ) {
377
+ fprintf(stderr, "malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
378
+ exit(255);
379
+ }
380
+
381
+ s = (char *)malloc(strlen(options));
382
+ if ( !s ) {
383
+ fprintf(stderr, "malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
384
+ exit(255);
385
+ }
386
+ q = s;
387
+ *q = '\0';
388
+ p = options;
389
+ while ( *p ) {
390
+ if ( !isspace(*p) )
391
+ *q++ = *p;
392
+ p++;
393
+ }
394
+ *q = '\0';
395
+
396
+ p = s;
397
+ while ( p && *p ) {
398
+ int sign;
399
+ q = strchr(p, ',');
400
+ if ( q )
401
+ *q++ = '\0';
402
+
403
+ // get possible sign
404
+ sign = 1;
405
+ if ( *p == '-' ) {
406
+ sign = -1;
407
+ p++;
408
+ }
409
+ if ( *p == '+' ) {
410
+ sign = 1;
411
+ p++;
412
+ }
413
+
414
+ if ( strcmp(p, "all") == 0 ) {
415
+ for (i=4; i<= Max_num_extensions; i++ )
416
+ extension_descriptor[i].enabled = sign == 1 ? : 0;
417
+ } else {
418
+ switch ( *p ) {
419
+ case '\0':
420
+ fprintf(stderr, "Extension format error: Unexpected end of format.\n");
421
+ exit(255);
422
+ break;
423
+ case '*':
424
+ for (i=4; i<= Max_num_extensions; i++ )
425
+ extension_descriptor[i].enabled = sign == 1 ? : 0;
426
+ break;
427
+ default: {
428
+ int i = strtol(p, NULL, 10);
429
+ if ( i == 0 ) {
430
+ fprintf(stderr, "Extension format error: Unexpected string: %s.\n", p);
431
+ exit(255);
432
+ }
433
+ if ( i > Max_num_extensions ) {
434
+ fprintf(stderr, "Extension format error: Invalid extension: %i\n", i);
435
+ exit(255);
436
+ }
437
+ mask[i] = sign;
438
+ }
439
+
440
+ }
441
+ }
442
+ p = q;
443
+ }
444
+ for (i=4; i<= Max_num_extensions; i++ ) {
445
+ int ui = extension_descriptor[i].user_index;
446
+
447
+ // mask[ui] == 0 means no input from user -> default behaviour or already overwritten by '*'
448
+ if ( mask[ui] < 0 ) {
449
+ extension_descriptor[i].enabled = 0;
450
+ }
451
+ if ( mask[ui] > 0 ) {
452
+ extension_descriptor[i].enabled = 1;
453
+ }
454
+ if ( extension_descriptor[i].enabled ) {
455
+ dbg_printf("Add extension: %s\n", extension_descriptor[i].description);
456
+ syslog(LOG_INFO, "Add extension: %s", extension_descriptor[i].description);
457
+ }
458
+ }
459
+
460
+ free(mask);
461
+
462
+ } // End of SetupExtensionDescriptors
463
+
464
+ void PrintExtensionMap(extension_map_t *map) {
465
+ int i;
466
+
467
+ printf("Extension Map:\n");
468
+ printf(" Map ID = %u\n", map->map_id);
469
+ printf(" Map Size = %u\n", map->size);
470
+ printf(" Ext Size = %u\n", map->extension_size);
471
+ i=0;
472
+ while (map->ex_id[i]) {
473
+ int id = map->ex_id[i++];
474
+ printf(" Index %3i, ext %3u = %s\n", extension_descriptor[id].user_index, id, extension_descriptor[id].description );
475
+ }
476
+ printf("\n");
477
+
478
+ } // End of PrintExtensionMap
479
+
480
+ int VerifyExtensionMap(extension_map_t *map) {
481
+ int i, failed, extension_size, max_elements;
482
+
483
+ failed = 0;
484
+ if (( map->size & 0x3 ) != 0 ) {
485
+ printf("Verify map id %i: WARNING: map size %i not aligned!\n", map->map_id, map->size);
486
+ failed = 1;
487
+ }
488
+
489
+ if ( ((int)map->size - (int)sizeof(extension_map_t)) <= 0 ) {
490
+ printf("Verify map id %i: ERROR: map size %i too small!\n", map->map_id, map->size);
491
+ failed = 1;
492
+ return 0;
493
+ }
494
+
495
+ max_elements = (map->size - sizeof(extension_map_t)) / sizeof(uint16_t);
496
+ extension_size = 0;
497
+ i=0;
498
+ while (map->ex_id[i] && i <= max_elements) {
499
+ int id = map->ex_id[i];
500
+ if ( id > Max_num_extensions ) {
501
+ printf("Verify map id %i: ERROR: element id %i out of range [%i]!\n", map->map_id, id, Max_num_extensions);
502
+ failed = 1;
503
+ }
504
+ extension_size += extension_descriptor[id].size;
505
+ i++;
506
+ }
507
+
508
+ if ( (extension_size != map->extension_size ) ) {
509
+ printf("Verify map id %i: ERROR extension size: Expected %i, Map reports: %i!\n", map->map_id,
510
+ extension_size, map->extension_size);
511
+ failed = 1;
512
+ }
513
+ if ( (i != max_elements ) && ((max_elements-i) != 1) ) {
514
+ // off by 1 is the opt alignment
515
+ printf("Verify map id %i: ERROR: Expected %i elements in map, but found %i!\n", map->map_id, max_elements, i);
516
+ failed = 1;
517
+ }
518
+
519
+ return failed;
520
+
521
+ } // End of VerifyExtensionMap
522
+
523
+ void FixExtensionMap(extension_map_t *map) {
524
+ int i, extension_size, max_elements;
525
+
526
+ if (( map->size & 0x3 ) != 0 ) {
527
+ printf("PANIC! - Verify map id %i: WARNING: map size %i not aligned!\n", map->map_id, map->size);
528
+ exit(255);
529
+ }
530
+
531
+ if ( ((int)map->size - (int)sizeof(extension_map_t)) <= 0 ) {
532
+ printf("PANIC! - Verify map id %i: ERROR: map size %i too small!\n", map->map_id, map->size);
533
+ exit(255);
534
+ }
535
+
536
+ max_elements = (map->size - sizeof(extension_map_t)) / sizeof(uint16_t);
537
+ extension_size = 0;
538
+ i=0;
539
+ while (map->ex_id[i] && i <= max_elements) {
540
+ int id = map->ex_id[i];
541
+ if ( id > Max_num_extensions ) {
542
+ printf("PANIC! - Verify map id %i: ERROR: element id %i out of range [%i]!\n", map->map_id, id, Max_num_extensions);
543
+ }
544
+ extension_size += extension_descriptor[id].size;
545
+ i++;
546
+ }
547
+
548
+ // silently fix extension size bug of nfdump <= 1.6.2 ..
549
+ if ( (extension_size != map->extension_size ) ) {
550
+ #ifdef DEVEL
551
+ printf("FixExtension map extension size from %i to %i\n", map->extension_size, extension_size);
552
+ #endif
553
+ map->extension_size = extension_size;
554
+ }
555
+
556
+ if ( (i != max_elements ) && ((max_elements-i) != 1) ) {
557
+ // off by 1 is the opt alignment
558
+ printf("Verify map id %i: ERROR: Expected %i elements in map, but found %i!\n", map->map_id, max_elements, i);
559
+ }
560
+
561
+ } // End of FixExtensionMap
562
+
563
+
564
+ void DumpExMaps(char *filename) {
565
+ int i, done;
566
+ nffile_t *nffile;
567
+ common_record_t *flow_record;
568
+ uint32_t skipped_blocks;
569
+ uint64_t total_bytes;
570
+
571
+ Max_num_extensions = 0;
572
+ i = 1;
573
+ while ( extension_descriptor[i++].id )
574
+ Max_num_extensions++;
575
+
576
+ printf("\nDump all extension maps:\n");
577
+ printf("========================\n");
578
+
579
+ nffile = OpenFile(filename, NULL);
580
+ if ( !nffile ) {
581
+ return;
582
+ }
583
+
584
+ done = 0;
585
+ while ( !done ) {
586
+ int i, ret;
587
+
588
+ // get next data block from file
589
+ ret = ReadBlock(nffile);
590
+
591
+ switch (ret) {
592
+ case NF_CORRUPT:
593
+ case NF_ERROR:
594
+ if ( ret == NF_CORRUPT )
595
+ LogError("Corrupt data file '%s': '%s'\n",filename);
596
+ else
597
+ LogError("Read error in file '%s': %s\n",filename, strerror(errno) );
598
+ done = 1;
599
+ continue;
600
+ break;
601
+ // fall through - get next file in chain
602
+ case NF_EOF:
603
+ done = 1;
604
+ continue;
605
+ break;
606
+
607
+ default:
608
+ // successfully read block
609
+ total_bytes += ret;
610
+ }
611
+
612
+ if ( nffile->block_header->id != DATA_BLOCK_TYPE_2 ) {
613
+ skipped_blocks++;
614
+ continue;
615
+ }
616
+
617
+ // block type = 2
618
+
619
+ flow_record = (common_record_t *)nffile->buff_ptr;
620
+ for ( i=0; i < nffile->block_header->NumRecords; i++ ) {
621
+ if ( flow_record->type == ExtensionMapType ) {
622
+ extension_map_t *map = (extension_map_t *)flow_record;
623
+ VerifyExtensionMap(map);
624
+ PrintExtensionMap(map);
625
+ }
626
+
627
+ // Advance pointer by number of bytes for netflow record
628
+ flow_record = (common_record_t *)((pointer_addr_t)flow_record + flow_record->size);
629
+ }
630
+ }
631
+
632
+ CloseFile(nffile);
633
+ DisposeFile(nffile);
634
+
635
+ } // End of DumpExMaps
636
+