nfrb 0.0.1.alpha

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+