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.
- data/.document +5 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +27 -0
- data/LICENSE.txt +32 -0
- data/README.rdoc +56 -0
- data/Rakefile +58 -0
- data/ext/rb_nfrb/README.files +14 -0
- data/ext/rb_nfrb/config.h +37 -0
- data/ext/rb_nfrb/dnc/nffile_inline.c +579 -0
- data/ext/rb_nfrb/extconf.rb +3 -0
- data/ext/rb_nfrb/fts_compat.c +1129 -0
- data/ext/rb_nfrb/fts_compat.h +126 -0
- data/ext/rb_nfrb/lzoconf.h +413 -0
- data/ext/rb_nfrb/lzodefs.h +1545 -0
- data/ext/rb_nfrb/minilzo.h +102 -0
- data/ext/rb_nfrb/nf_common.h +117 -0
- data/ext/rb_nfrb/nffile.c +1167 -0
- data/ext/rb_nfrb/nffile.h +1439 -0
- data/ext/rb_nfrb/nfrb.c +368 -0
- data/ext/rb_nfrb/nfx.c +636 -0
- data/ext/rb_nfrb/nfx.h +83 -0
- data/ext/rb_nfrb/util.c +517 -0
- data/ext/rb_nfrb/util.h +84 -0
- data/lib/nfrb.rb +5 -0
- data/lib/nfrb/version.rb +16 -0
- data/test/helper.rb +18 -0
- data/test/test_nfrb.rb +7 -0
- metadata +184 -0
data/ext/rb_nfrb/nfrb.c
ADDED
@@ -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
|
+
}
|
data/ext/rb_nfrb/nfx.c
ADDED
@@ -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
|
+
|