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
@@ -0,0 +1,102 @@
|
|
1
|
+
/* minilzo.h -- mini subset of the LZO real-time data compression library
|
2
|
+
|
3
|
+
This file is part of the LZO real-time data compression library.
|
4
|
+
|
5
|
+
Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
|
6
|
+
Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
|
7
|
+
Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
|
8
|
+
Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
|
9
|
+
Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
|
10
|
+
Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
|
11
|
+
Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
|
12
|
+
Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
|
13
|
+
Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
|
14
|
+
Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
|
15
|
+
All Rights Reserved.
|
16
|
+
|
17
|
+
The LZO library is free software; you can redistribute it and/or
|
18
|
+
modify it under the terms of the GNU General Public License,
|
19
|
+
version 2, as published by the Free Software Foundation.
|
20
|
+
|
21
|
+
The LZO library is distributed in the hope that it will be useful,
|
22
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
23
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
24
|
+
GNU General Public License for more details.
|
25
|
+
|
26
|
+
You should have received a copy of the GNU General Public License
|
27
|
+
along with the LZO library; see the file COPYING.
|
28
|
+
If not, write to the Free Software Foundation, Inc.,
|
29
|
+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
30
|
+
|
31
|
+
Markus F.X.J. Oberhumer
|
32
|
+
<markus@oberhumer.com>
|
33
|
+
http://www.oberhumer.com/opensource/lzo/
|
34
|
+
*/
|
35
|
+
|
36
|
+
/*
|
37
|
+
* NOTE:
|
38
|
+
* the full LZO package can be found at
|
39
|
+
* http://www.oberhumer.com/opensource/lzo/
|
40
|
+
*/
|
41
|
+
|
42
|
+
|
43
|
+
#ifndef __MINILZO_H
|
44
|
+
#define __MINILZO_H 1
|
45
|
+
|
46
|
+
#define MINILZO_VERSION 0x2020
|
47
|
+
|
48
|
+
#ifdef __LZOCONF_H
|
49
|
+
# error "you cannot use both LZO and miniLZO"
|
50
|
+
#endif
|
51
|
+
|
52
|
+
#undef LZO_HAVE_CONFIG_H
|
53
|
+
#include "lzoconf.h"
|
54
|
+
|
55
|
+
#if !defined(LZO_VERSION) || (LZO_VERSION != MINILZO_VERSION)
|
56
|
+
# error "version mismatch in header files"
|
57
|
+
#endif
|
58
|
+
|
59
|
+
|
60
|
+
#ifdef __cplusplus
|
61
|
+
extern "C" {
|
62
|
+
#endif
|
63
|
+
|
64
|
+
|
65
|
+
/***********************************************************************
|
66
|
+
//
|
67
|
+
************************************************************************/
|
68
|
+
|
69
|
+
/* Memory required for the wrkmem parameter.
|
70
|
+
* When the required size is 0, you can also pass a NULL pointer.
|
71
|
+
*/
|
72
|
+
|
73
|
+
#define LZO1X_MEM_COMPRESS LZO1X_1_MEM_COMPRESS
|
74
|
+
#define LZO1X_1_MEM_COMPRESS ((lzo_uint32) (16384L * lzo_sizeof_dict_t))
|
75
|
+
#define LZO1X_MEM_DECOMPRESS (0)
|
76
|
+
|
77
|
+
|
78
|
+
/* compression */
|
79
|
+
LZO_EXTERN(int)
|
80
|
+
lzo1x_1_compress ( const lzo_bytep src, lzo_uint src_len,
|
81
|
+
lzo_bytep dst, lzo_uintp dst_len,
|
82
|
+
lzo_voidp wrkmem );
|
83
|
+
|
84
|
+
/* decompression */
|
85
|
+
LZO_EXTERN(int)
|
86
|
+
lzo1x_decompress ( const lzo_bytep src, lzo_uint src_len,
|
87
|
+
lzo_bytep dst, lzo_uintp dst_len,
|
88
|
+
lzo_voidp wrkmem /* NOT USED */ );
|
89
|
+
|
90
|
+
/* safe decompression with overrun testing */
|
91
|
+
LZO_EXTERN(int)
|
92
|
+
lzo1x_decompress_safe ( const lzo_bytep src, lzo_uint src_len,
|
93
|
+
lzo_bytep dst, lzo_uintp dst_len,
|
94
|
+
lzo_voidp wrkmem /* NOT USED */ );
|
95
|
+
|
96
|
+
|
97
|
+
#ifdef __cplusplus
|
98
|
+
} /* extern "C" */
|
99
|
+
#endif
|
100
|
+
|
101
|
+
#endif /* already included */
|
102
|
+
|
@@ -0,0 +1,117 @@
|
|
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: nf_common.h 39 2009-11-25 08:11:15Z haag $
|
33
|
+
*
|
34
|
+
* $LastChangedRevision: 39 $
|
35
|
+
*
|
36
|
+
*
|
37
|
+
*/
|
38
|
+
|
39
|
+
#ifndef _NF_COMMON_H
|
40
|
+
#define _NF_COMMON_H 1
|
41
|
+
|
42
|
+
|
43
|
+
typedef void (*printer_t)(void *, char **, int);
|
44
|
+
|
45
|
+
#if ( SIZEOF_VOID_P == 8 )
|
46
|
+
typedef uint64_t pointer_addr_t;
|
47
|
+
#else
|
48
|
+
typedef uint32_t pointer_addr_t;
|
49
|
+
#endif
|
50
|
+
|
51
|
+
typedef struct msec_time_s {
|
52
|
+
time_t sec;
|
53
|
+
uint16_t msec;
|
54
|
+
} msec_time_tt;
|
55
|
+
|
56
|
+
/* common minimum netflow header for all versions */
|
57
|
+
typedef struct common_flow_header {
|
58
|
+
uint16_t version;
|
59
|
+
uint16_t count;
|
60
|
+
} common_flow_header_t;
|
61
|
+
|
62
|
+
|
63
|
+
/* prototypes */
|
64
|
+
|
65
|
+
int InitSymbols(void);
|
66
|
+
|
67
|
+
void Setv6Mode(int mode);
|
68
|
+
|
69
|
+
int Getv6Mode(void);
|
70
|
+
|
71
|
+
int Proto_num(char *protostr);
|
72
|
+
|
73
|
+
void format_file_block_header(void *header, char **s, int tag);
|
74
|
+
|
75
|
+
char *format_csv_header(void);
|
76
|
+
|
77
|
+
char *get_record_header(void);
|
78
|
+
|
79
|
+
void set_record_header(void);
|
80
|
+
|
81
|
+
void format_file_block_record(void *record, char **s, int tag);
|
82
|
+
|
83
|
+
void flow_record_to_pipe(void *record, char ** s, int tag);
|
84
|
+
|
85
|
+
void flow_record_to_csv(void *record, char ** s, int tag);
|
86
|
+
|
87
|
+
int ParseOutputFormat(char *format, int plain_numbers);
|
88
|
+
|
89
|
+
void format_special(void *record, char ** s, int tag);
|
90
|
+
|
91
|
+
|
92
|
+
uint32_t Get_fwd_status_id(char *status);
|
93
|
+
|
94
|
+
char *Get_fwd_status_name(uint32_t id);
|
95
|
+
|
96
|
+
#define FIXED_WIDTH 1
|
97
|
+
#define VAR_LENGTH 0
|
98
|
+
|
99
|
+
#ifdef __SUNPRO_C
|
100
|
+
extern
|
101
|
+
#endif
|
102
|
+
inline void Proto_string(uint8_t protonum, char *protostr);
|
103
|
+
|
104
|
+
#ifdef __SUNPRO_C
|
105
|
+
extern
|
106
|
+
#endif
|
107
|
+
inline void format_number(uint64_t num, char *s, int fixed_width);
|
108
|
+
|
109
|
+
#ifdef __SUNPRO_C
|
110
|
+
extern
|
111
|
+
#endif
|
112
|
+
inline void condense_v6(char *s);
|
113
|
+
|
114
|
+
#define TAG_CHAR ''
|
115
|
+
|
116
|
+
#endif //_NF_COMMON_H
|
117
|
+
|
@@ -0,0 +1,1167 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2011, 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: nffile.c 41 2009-12-31 14:46:28Z haag $
|
33
|
+
*
|
34
|
+
* $LastChangedRevision: 41 $
|
35
|
+
*
|
36
|
+
*/
|
37
|
+
|
38
|
+
#include "config.h"
|
39
|
+
|
40
|
+
#include <sys/types.h>
|
41
|
+
#include <sys/uio.h>
|
42
|
+
#include <unistd.h>
|
43
|
+
#include <string.h>
|
44
|
+
#include <fcntl.h>
|
45
|
+
#include <sys/stat.h>
|
46
|
+
#include <sys/param.h>
|
47
|
+
#include <stdio.h>
|
48
|
+
#include <errno.h>
|
49
|
+
#include <unistd.h>
|
50
|
+
#include <stdlib.h>
|
51
|
+
|
52
|
+
#ifdef HAVE_STDINT_H
|
53
|
+
#include <stdint.h>
|
54
|
+
#endif
|
55
|
+
|
56
|
+
#include "minilzo.h"
|
57
|
+
#include "nf_common.h"
|
58
|
+
#include "nffile.h"
|
59
|
+
#include "util.h"
|
60
|
+
|
61
|
+
/* global vars */
|
62
|
+
|
63
|
+
// required for idet filter in nftree.c
|
64
|
+
char *CurrentIdent;
|
65
|
+
|
66
|
+
/* local vars */
|
67
|
+
static file_header_t FileHeader;
|
68
|
+
|
69
|
+
#define READ_FILE 1
|
70
|
+
#define WRITE_FILE 1
|
71
|
+
|
72
|
+
// LZO params
|
73
|
+
#define LZO_BUFFSIZE ((BUFFSIZE + BUFFSIZE / 16 + 64 + 3) + sizeof(data_block_header_t))
|
74
|
+
#define HEAP_ALLOC(var,size) \
|
75
|
+
lzo_align_t __LZO_MMODEL var [ ((size) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t) ]
|
76
|
+
|
77
|
+
static HEAP_ALLOC(wrkmem,LZO1X_1_MEM_COMPRESS);
|
78
|
+
static void *lzo_buff;
|
79
|
+
static int lzo_initialized = 0;
|
80
|
+
|
81
|
+
#define ERR_SIZE 256
|
82
|
+
static char error_string[ERR_SIZE];
|
83
|
+
|
84
|
+
static int LZO_initialize(void);
|
85
|
+
|
86
|
+
extern char *nf_error;
|
87
|
+
|
88
|
+
/* function prototypes */
|
89
|
+
static nffile_t *NewFile(void);
|
90
|
+
|
91
|
+
/* function definitions */
|
92
|
+
|
93
|
+
void SumStatRecords(stat_record_t *s1, stat_record_t *s2) {
|
94
|
+
|
95
|
+
s1->numflows += s2->numflows;
|
96
|
+
s1->numbytes += s2->numbytes;
|
97
|
+
s1->numpackets += s2->numpackets;
|
98
|
+
s1->numflows_tcp += s2->numflows_tcp;
|
99
|
+
s1->numflows_udp += s2->numflows_udp;
|
100
|
+
s1->numflows_icmp += s2->numflows_icmp;
|
101
|
+
s1->numflows_other += s2->numflows_other;
|
102
|
+
s1->numbytes_tcp += s2->numbytes_tcp;
|
103
|
+
s1->numbytes_udp += s2->numbytes_udp;
|
104
|
+
s1->numbytes_icmp += s2->numbytes_icmp;
|
105
|
+
s1->numbytes_other += s2->numbytes_other;
|
106
|
+
s1->numpackets_tcp += s2->numpackets_tcp;
|
107
|
+
s1->numpackets_udp += s2->numpackets_udp;
|
108
|
+
s1->numpackets_icmp += s2->numpackets_icmp;
|
109
|
+
s1->numpackets_other += s2->numpackets_other;
|
110
|
+
s1->sequence_failure += s2->sequence_failure;
|
111
|
+
|
112
|
+
if ( s2->first_seen < s1->first_seen ) {
|
113
|
+
s1->first_seen = s2->first_seen;
|
114
|
+
s1->msec_first = s2->msec_first;
|
115
|
+
}
|
116
|
+
if ( s2->first_seen == s1->first_seen &&
|
117
|
+
s2->msec_first < s1->msec_first )
|
118
|
+
s1->msec_first = s2->msec_first;
|
119
|
+
|
120
|
+
if ( s2->last_seen > s1->last_seen ) {
|
121
|
+
s1->last_seen = s2->last_seen;
|
122
|
+
s1->msec_last = s2->msec_last;
|
123
|
+
}
|
124
|
+
if ( s2->last_seen == s1->last_seen &&
|
125
|
+
s2->msec_last > s1->msec_last )
|
126
|
+
s1->msec_last = s2->msec_last;
|
127
|
+
|
128
|
+
} // End of SumStatRecords
|
129
|
+
|
130
|
+
|
131
|
+
static int LZO_initialize(void) {
|
132
|
+
|
133
|
+
if (lzo_init() != LZO_E_OK) {
|
134
|
+
// this usually indicates a compiler bug - try recompiling
|
135
|
+
// without optimizations, and enable `-DLZO_DEBUG' for diagnostics
|
136
|
+
LogError("Compression lzo_init() failed.\n");
|
137
|
+
return 0;
|
138
|
+
}
|
139
|
+
lzo_buff = malloc(BUFFSIZE+ sizeof(data_block_header_t));
|
140
|
+
if ( !lzo_buff ) {
|
141
|
+
LogError("malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
142
|
+
return 0;
|
143
|
+
}
|
144
|
+
lzo_initialized = 1;
|
145
|
+
|
146
|
+
return 1;
|
147
|
+
|
148
|
+
} // End of LZO_initialize
|
149
|
+
|
150
|
+
|
151
|
+
nffile_t *OpenFile(char *filename, nffile_t *nffile){
|
152
|
+
struct stat stat_buf;
|
153
|
+
int ret, allocated;
|
154
|
+
|
155
|
+
if ( !nffile ) {
|
156
|
+
nffile = NewFile();
|
157
|
+
if ( nffile == NULL ) {
|
158
|
+
return NULL;
|
159
|
+
}
|
160
|
+
allocated = 1;
|
161
|
+
} else
|
162
|
+
allocated = 0;
|
163
|
+
|
164
|
+
|
165
|
+
if ( filename == NULL ) {
|
166
|
+
// stdin
|
167
|
+
// Zero Stat
|
168
|
+
nffile->fd = STDIN_FILENO;
|
169
|
+
} else {
|
170
|
+
// regular file
|
171
|
+
if ( stat(filename, &stat_buf) ) {
|
172
|
+
LogError("Can't stat '%s': %s\n", filename, strerror(errno));
|
173
|
+
if ( allocated ) {
|
174
|
+
DisposeFile(nffile);
|
175
|
+
return NULL;
|
176
|
+
}
|
177
|
+
}
|
178
|
+
|
179
|
+
if (!S_ISREG(stat_buf.st_mode) ) {
|
180
|
+
LogError("'%s' is not a file\n", filename);
|
181
|
+
if ( allocated ) {
|
182
|
+
DisposeFile(nffile);
|
183
|
+
return NULL;
|
184
|
+
}
|
185
|
+
}
|
186
|
+
|
187
|
+
// printf("Statfile %s\n",filename);
|
188
|
+
nffile->fd = open(filename, O_RDONLY);
|
189
|
+
if ( nffile->fd < 0 ) {
|
190
|
+
LogError("Error open file: %s\n", strerror(errno));
|
191
|
+
if ( allocated ) {
|
192
|
+
DisposeFile(nffile);
|
193
|
+
return NULL;
|
194
|
+
}
|
195
|
+
}
|
196
|
+
|
197
|
+
}
|
198
|
+
|
199
|
+
ret = read(nffile->fd, (void *)nffile->file_header, sizeof(file_header_t));
|
200
|
+
if ( nffile->file_header->magic != MAGIC ) {
|
201
|
+
LogError("Open file '%s': bad magic: 0x%X\n", filename ? filename : "<stdin>", FileHeader.magic );
|
202
|
+
CloseFile(nffile);
|
203
|
+
if ( allocated ) {
|
204
|
+
DisposeFile(nffile);
|
205
|
+
return NULL;
|
206
|
+
}
|
207
|
+
}
|
208
|
+
|
209
|
+
if ( nffile->file_header->version != LAYOUT_VERSION_1 ) {
|
210
|
+
LogError("Open file %s: bad version: %u\n", filename, FileHeader.version );
|
211
|
+
CloseFile(nffile);
|
212
|
+
if ( allocated ) {
|
213
|
+
DisposeFile(nffile);
|
214
|
+
return NULL;
|
215
|
+
}
|
216
|
+
}
|
217
|
+
|
218
|
+
ret = read(nffile->fd, (void *)nffile->stat_record, sizeof(stat_record_t));
|
219
|
+
if ( ret < 0 ) {
|
220
|
+
LogError("read() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
221
|
+
CloseFile(nffile);
|
222
|
+
if ( allocated ) {
|
223
|
+
DisposeFile(nffile);
|
224
|
+
return NULL;
|
225
|
+
}
|
226
|
+
}
|
227
|
+
|
228
|
+
CurrentIdent = nffile->file_header->ident;
|
229
|
+
|
230
|
+
if ( FILE_IS_COMPRESSED(nffile) && !lzo_initialized && !LZO_initialize() ) {
|
231
|
+
if ( allocated ) {
|
232
|
+
DisposeFile(nffile);
|
233
|
+
return NULL;
|
234
|
+
}
|
235
|
+
}
|
236
|
+
|
237
|
+
return nffile;
|
238
|
+
|
239
|
+
} // End of OpenFile
|
240
|
+
|
241
|
+
void CloseFile(nffile_t *nffile){
|
242
|
+
|
243
|
+
if ( !nffile )
|
244
|
+
return;
|
245
|
+
|
246
|
+
// do not close stdout
|
247
|
+
if ( nffile->fd )
|
248
|
+
close(nffile->fd);
|
249
|
+
|
250
|
+
} // End of CloseFile
|
251
|
+
|
252
|
+
int ChangeIdent(char *filename, char *Ident) {
|
253
|
+
struct stat stat_buf;
|
254
|
+
int fd, ret;
|
255
|
+
|
256
|
+
if ( filename == NULL )
|
257
|
+
return 0;
|
258
|
+
|
259
|
+
if ( stat(filename, &stat_buf) ) {
|
260
|
+
LogError("Can't stat '%s': %s\n", filename, strerror(errno));
|
261
|
+
return -1;
|
262
|
+
}
|
263
|
+
|
264
|
+
if (!S_ISREG(stat_buf.st_mode) ) {
|
265
|
+
LogError("'%s' is not a file\n", filename);
|
266
|
+
return -1;
|
267
|
+
}
|
268
|
+
|
269
|
+
fd = open(filename, O_RDWR);
|
270
|
+
if ( fd < 0 ) {
|
271
|
+
LogError("Error open file: %s\n", strerror(errno));
|
272
|
+
return fd;
|
273
|
+
}
|
274
|
+
|
275
|
+
ret = read(fd, (void *)&FileHeader, sizeof(FileHeader));
|
276
|
+
if ( FileHeader.magic != MAGIC ) {
|
277
|
+
LogError("Open file '%s': bad magic: 0x%X\n", filename, FileHeader.magic );
|
278
|
+
close(fd);
|
279
|
+
return -1;
|
280
|
+
}
|
281
|
+
if ( FileHeader.version != LAYOUT_VERSION_1 ) {
|
282
|
+
LogError("Open file %s: bad version: %u\n", filename, FileHeader.version );
|
283
|
+
close(fd);
|
284
|
+
return -1;
|
285
|
+
}
|
286
|
+
|
287
|
+
strncpy(FileHeader.ident, Ident, IDENTLEN);
|
288
|
+
FileHeader.ident[IDENTLEN - 1] = 0;
|
289
|
+
|
290
|
+
if ( lseek(fd, 0, SEEK_SET) < 0 ) {
|
291
|
+
LogError("lseek() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
292
|
+
close(fd);
|
293
|
+
return -1;
|
294
|
+
}
|
295
|
+
|
296
|
+
if ( write(fd, (void *)&FileHeader, sizeof(file_header_t)) <= 0 ) {
|
297
|
+
LogError("write() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
298
|
+
}
|
299
|
+
|
300
|
+
if ( close(fd) < 0 ) {
|
301
|
+
LogError("close() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
302
|
+
return -1;
|
303
|
+
}
|
304
|
+
|
305
|
+
return 0;
|
306
|
+
|
307
|
+
} // End of ChangeIdent
|
308
|
+
|
309
|
+
|
310
|
+
void PrintStat(stat_record_t *s) {
|
311
|
+
|
312
|
+
if ( s == NULL )
|
313
|
+
return;
|
314
|
+
|
315
|
+
// format info: make compiler happy with conversion to (unsigned long long),
|
316
|
+
// which does not change the size of the parameter
|
317
|
+
printf("Ident: %s\n", FileHeader.ident);
|
318
|
+
printf("Flows: %llu\n", (unsigned long long)s->numflows);
|
319
|
+
printf("Flows_tcp: %llu\n", (unsigned long long)s->numflows_tcp);
|
320
|
+
printf("Flows_udp: %llu\n", (unsigned long long)s->numflows_udp);
|
321
|
+
printf("Flows_icmp: %llu\n", (unsigned long long)s->numflows_icmp);
|
322
|
+
printf("Flows_other: %llu\n", (unsigned long long)s->numflows_other);
|
323
|
+
printf("Packets: %llu\n", (unsigned long long)s->numpackets);
|
324
|
+
printf("Packets_tcp: %llu\n", (unsigned long long)s->numpackets_tcp);
|
325
|
+
printf("Packets_udp: %llu\n", (unsigned long long)s->numpackets_udp);
|
326
|
+
printf("Packets_icmp: %llu\n", (unsigned long long)s->numpackets_icmp);
|
327
|
+
printf("Packets_other: %llu\n", (unsigned long long)s->numpackets_other);
|
328
|
+
printf("Bytes: %llu\n", (unsigned long long)s->numbytes);
|
329
|
+
printf("Bytes_tcp: %llu\n", (unsigned long long)s->numbytes_tcp);
|
330
|
+
printf("Bytes_udp: %llu\n", (unsigned long long)s->numbytes_udp);
|
331
|
+
printf("Bytes_icmp: %llu\n", (unsigned long long)s->numbytes_icmp);
|
332
|
+
printf("Bytes_other: %llu\n", (unsigned long long)s->numbytes_other);
|
333
|
+
printf("First: %u\n", s->first_seen);
|
334
|
+
printf("Last: %u\n", s->last_seen);
|
335
|
+
printf("msec_first: %u\n", s->msec_first);
|
336
|
+
printf("msec_last: %u\n", s->msec_last);
|
337
|
+
printf("Sequence failures: %u\n", s->sequence_failure);
|
338
|
+
} // End of PrintStat
|
339
|
+
|
340
|
+
static nffile_t *NewFile(void) {
|
341
|
+
nffile_t *nffile;
|
342
|
+
|
343
|
+
// Create struct
|
344
|
+
nffile = calloc(1, sizeof(nffile_t));
|
345
|
+
if ( !nffile ) {
|
346
|
+
LogError("malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
347
|
+
return NULL;
|
348
|
+
}
|
349
|
+
nffile->buff_ptr = NULL;
|
350
|
+
nffile->fd = 0;
|
351
|
+
|
352
|
+
// Init file header
|
353
|
+
nffile->file_header = calloc(1, sizeof(file_header_t));
|
354
|
+
if ( !nffile->file_header ) {
|
355
|
+
LogError("malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
356
|
+
return NULL;
|
357
|
+
}
|
358
|
+
nffile->file_header->magic = MAGIC;
|
359
|
+
nffile->file_header->version = LAYOUT_VERSION_1;
|
360
|
+
nffile->file_header->flags = 0;
|
361
|
+
nffile->file_header->NumBlocks = 0;
|
362
|
+
|
363
|
+
nffile->stat_record = calloc(1, sizeof(stat_record_t));
|
364
|
+
if ( !nffile->stat_record ) {
|
365
|
+
LogError("malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
366
|
+
return NULL;
|
367
|
+
}
|
368
|
+
|
369
|
+
// init data buffer
|
370
|
+
nffile->block_header = malloc(BUFFSIZE + sizeof(data_block_header_t));
|
371
|
+
if ( !nffile->block_header ) {
|
372
|
+
LogError("malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
373
|
+
return NULL;
|
374
|
+
}
|
375
|
+
nffile->block_header->size = 0;
|
376
|
+
nffile->block_header->NumRecords = 0;
|
377
|
+
nffile->block_header->id = DATA_BLOCK_TYPE_2;
|
378
|
+
nffile->block_header->pad = 0;
|
379
|
+
|
380
|
+
nffile->buff_ptr = (void *)((pointer_addr_t)nffile->block_header + sizeof(data_block_header_t));
|
381
|
+
|
382
|
+
return nffile;
|
383
|
+
|
384
|
+
} // End of NewFile
|
385
|
+
|
386
|
+
nffile_t *DisposeFile(nffile_t *nffile) {
|
387
|
+
free(nffile->file_header);
|
388
|
+
free(nffile->stat_record);
|
389
|
+
if (nffile->block_header)
|
390
|
+
free(nffile->block_header);
|
391
|
+
free(nffile);
|
392
|
+
return NULL;
|
393
|
+
} // End of DisposeFile
|
394
|
+
|
395
|
+
nffile_t *OpenNewFile(char *filename, nffile_t *nffile, int compressed, int anonymized, char *ident) {
|
396
|
+
size_t len;
|
397
|
+
int flags;
|
398
|
+
|
399
|
+
// Allocate new struct if not given
|
400
|
+
if ( nffile == NULL ) {
|
401
|
+
nffile = NewFile();
|
402
|
+
if ( nffile == NULL ) {
|
403
|
+
return NULL;
|
404
|
+
}
|
405
|
+
}
|
406
|
+
|
407
|
+
flags = compressed ? FLAG_COMPRESSED : 0;
|
408
|
+
if ( anonymized )
|
409
|
+
SetFlag(flags, FLAG_ANONYMIZED);
|
410
|
+
|
411
|
+
nffile->file_header->flags = flags;
|
412
|
+
|
413
|
+
if ( strcmp(filename, "-") == 0 ) { // output to stdout
|
414
|
+
nffile->fd = STDOUT_FILENO;
|
415
|
+
} else {
|
416
|
+
nffile->fd = open(filename, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
|
417
|
+
if ( nffile->fd < 0 ) {
|
418
|
+
LogError("Failed to open file %s: '%s'" , filename, strerror(errno));
|
419
|
+
return NULL;
|
420
|
+
}
|
421
|
+
}
|
422
|
+
|
423
|
+
memset((void *)nffile->stat_record, 0, sizeof(stat_record_t));
|
424
|
+
nffile->stat_record->first_seen = 0x7fffffff;
|
425
|
+
nffile->stat_record->msec_first = 999;
|
426
|
+
|
427
|
+
if ( ident ) {
|
428
|
+
strncpy(nffile->file_header->ident, ident, IDENTLEN);
|
429
|
+
nffile->file_header->ident[IDENTLEN - 1] = 0;
|
430
|
+
}
|
431
|
+
|
432
|
+
|
433
|
+
if ( TestFlag(flags, FLAG_COMPRESSED) ) {
|
434
|
+
if ( !lzo_initialized && !LZO_initialize() ) {
|
435
|
+
LogError("Failed to initialize compression");
|
436
|
+
close(nffile->fd);
|
437
|
+
return NULL;
|
438
|
+
}
|
439
|
+
}
|
440
|
+
|
441
|
+
nffile->file_header->NumBlocks = 0;
|
442
|
+
len = sizeof(file_header_t);
|
443
|
+
if ( write(nffile->fd, (void *)nffile->file_header, len) < len ) {
|
444
|
+
LogError("write() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
445
|
+
close(nffile->fd);
|
446
|
+
return NULL;
|
447
|
+
}
|
448
|
+
|
449
|
+
// write empty stat record - ist updated when file gets closed
|
450
|
+
len = sizeof(stat_record_t);
|
451
|
+
if ( write(nffile->fd, (void *)nffile->stat_record, len) < len ) {
|
452
|
+
LogError("write() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
453
|
+
close(nffile->fd);
|
454
|
+
return NULL;
|
455
|
+
}
|
456
|
+
|
457
|
+
return nffile;
|
458
|
+
|
459
|
+
} /* End of OpenNewFile */
|
460
|
+
|
461
|
+
nffile_t *AppendFile(char *filename) {
|
462
|
+
nffile_t *nffile;
|
463
|
+
|
464
|
+
// try to open the existing file
|
465
|
+
nffile = OpenFile(filename, NULL);
|
466
|
+
if ( !nffile )
|
467
|
+
return NULL;
|
468
|
+
|
469
|
+
// file is valid - re-open the file mode RDWR
|
470
|
+
close(nffile->fd);
|
471
|
+
nffile->fd = open(filename, O_RDWR | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
|
472
|
+
if ( nffile->fd < 0 ) {
|
473
|
+
LogError("Failed to open file %s: '%s'" , filename, strerror(errno));
|
474
|
+
DisposeFile(nffile);
|
475
|
+
return NULL;
|
476
|
+
}
|
477
|
+
|
478
|
+
// init output data buffer
|
479
|
+
nffile->block_header = malloc(BUFFSIZE + sizeof(data_block_header_t));
|
480
|
+
if ( !nffile->block_header ) {
|
481
|
+
LogError("malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
482
|
+
close(nffile->fd);
|
483
|
+
DisposeFile(nffile);
|
484
|
+
return NULL;
|
485
|
+
}
|
486
|
+
nffile->block_header->size = 0;
|
487
|
+
nffile->block_header->NumRecords = 0;
|
488
|
+
nffile->block_header->id = DATA_BLOCK_TYPE_2;
|
489
|
+
nffile->block_header->pad = 0;
|
490
|
+
nffile->buff_ptr = (void *)((pointer_addr_t)nffile->block_header + sizeof(data_block_header_t));
|
491
|
+
|
492
|
+
// initialize output lzo buffer
|
493
|
+
if ( FILE_IS_COMPRESSED(nffile) ) {
|
494
|
+
if ( !lzo_initialized && !LZO_initialize() ) {
|
495
|
+
LogError("Failed to initialize compression");
|
496
|
+
close(nffile->fd);
|
497
|
+
DisposeFile(nffile);
|
498
|
+
return NULL;
|
499
|
+
}
|
500
|
+
}
|
501
|
+
|
502
|
+
return nffile;
|
503
|
+
|
504
|
+
} /* End of AppendFile */
|
505
|
+
|
506
|
+
int CloseUpdateFile(nffile_t *nffile, char *ident) {
|
507
|
+
file_header_t file_header;
|
508
|
+
|
509
|
+
if ( nffile->block_header->size ) {
|
510
|
+
int ret = WriteBlock(nffile);
|
511
|
+
if ( ret < 0 ) {
|
512
|
+
LogError("Failed to flush output buffer");
|
513
|
+
return 0;
|
514
|
+
}
|
515
|
+
}
|
516
|
+
|
517
|
+
if ( lseek(nffile->fd, 0, SEEK_SET) < 0 ) {
|
518
|
+
// lseek on stdout works if output redirected:
|
519
|
+
// e.g. -w - > outfile
|
520
|
+
// but fails on pipe e.g. -w - | ./nfdump ....
|
521
|
+
if ( nffile->fd == STDOUT_FILENO ) {
|
522
|
+
return 1;
|
523
|
+
} else {
|
524
|
+
LogError("lseek() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
525
|
+
close(nffile->fd);
|
526
|
+
return 0;
|
527
|
+
}
|
528
|
+
}
|
529
|
+
|
530
|
+
if ( ident ) {
|
531
|
+
strncpy(nffile->file_header->ident, ident, IDENTLEN);
|
532
|
+
} else {
|
533
|
+
if ( strlen(nffile->file_header->ident) == 0 )
|
534
|
+
strncpy(nffile->file_header->ident, IDENTNONE, IDENTLEN);
|
535
|
+
}
|
536
|
+
file_header.ident[IDENTLEN - 1] = 0;
|
537
|
+
|
538
|
+
if ( write(nffile->fd, (void *)nffile->file_header, sizeof(file_header_t)) <= 0 ) {
|
539
|
+
LogError("write() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
540
|
+
}
|
541
|
+
if ( write(nffile->fd, (void *)nffile->stat_record, sizeof(stat_record_t)) <= 0 ) {
|
542
|
+
LogError("write() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
543
|
+
}
|
544
|
+
if ( close(nffile->fd) < 0 ) {
|
545
|
+
LogError("close() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
546
|
+
return 0;
|
547
|
+
}
|
548
|
+
|
549
|
+
nffile->file_header->NumBlocks = 0;
|
550
|
+
|
551
|
+
return 1;
|
552
|
+
|
553
|
+
} /* End of CloseUpdateFile */
|
554
|
+
|
555
|
+
int ReadBlock(nffile_t *nffile) {
|
556
|
+
ssize_t ret, read_bytes, buff_bytes, request_size;
|
557
|
+
void *read_ptr, *buff;
|
558
|
+
|
559
|
+
ret = read(nffile->fd, nffile->block_header, sizeof(data_block_header_t));
|
560
|
+
if ( ret == 0 ) // EOF
|
561
|
+
return NF_EOF;
|
562
|
+
|
563
|
+
if ( ret == -1 ) // ERROR
|
564
|
+
return NF_ERROR;
|
565
|
+
|
566
|
+
// Check for sane buffer size
|
567
|
+
if ( ret != sizeof(data_block_header_t) ) {
|
568
|
+
// this is most likely a corrupt file
|
569
|
+
LogError("Corrupt data file: Read %i bytes, requested %u\n", ret, sizeof(data_block_header_t));
|
570
|
+
return NF_CORRUPT;
|
571
|
+
}
|
572
|
+
|
573
|
+
// block header read successfully
|
574
|
+
read_bytes = ret;
|
575
|
+
|
576
|
+
// Check for sane buffer size
|
577
|
+
if ( nffile->block_header->size > BUFFSIZE ) {
|
578
|
+
// this is most likely a corrupt file
|
579
|
+
LogError("Corrupt data file: Requested buffer size %u exceeds max. buffer size.\n", nffile->block_header->size);
|
580
|
+
return NF_CORRUPT;
|
581
|
+
}
|
582
|
+
|
583
|
+
buff = FILE_IS_COMPRESSED(nffile) ? lzo_buff : nffile->buff_ptr;
|
584
|
+
|
585
|
+
ret = read(nffile->fd, buff, nffile->block_header->size);
|
586
|
+
if ( ret == nffile->block_header->size ) {
|
587
|
+
lzo_uint new_len;
|
588
|
+
// we have the whole record and are done for now
|
589
|
+
if ( FILE_IS_COMPRESSED(nffile) ) {
|
590
|
+
int r;
|
591
|
+
r = lzo1x_decompress(lzo_buff,nffile->block_header->size,nffile->buff_ptr,&new_len,NULL);
|
592
|
+
if (r != LZO_E_OK ) {
|
593
|
+
/* this should NEVER happen */
|
594
|
+
LogError("ReadBlock() error decompression failed in %s line %d: LZO error: %d\n", __FILE__, __LINE__, r);
|
595
|
+
return NF_CORRUPT;
|
596
|
+
}
|
597
|
+
nffile->block_header->size = new_len;
|
598
|
+
return read_bytes + new_len;
|
599
|
+
} else
|
600
|
+
return read_bytes + ret;
|
601
|
+
}
|
602
|
+
|
603
|
+
if ( ret == 0 ) {
|
604
|
+
// EOF not expected here - this should never happen, file may be corrupt
|
605
|
+
LogError("ReadBlock() Corrupt data file: Unexpected EOF while reading data block.\n");
|
606
|
+
return NF_CORRUPT;
|
607
|
+
}
|
608
|
+
|
609
|
+
if ( ret == -1 ) { // ERROR
|
610
|
+
LogError("read() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
611
|
+
return NF_ERROR;
|
612
|
+
}
|
613
|
+
|
614
|
+
// Ups! - ret is != block_header->size
|
615
|
+
// this was a short read - most likely reading from the stdin pipe
|
616
|
+
// loop until we have requested size
|
617
|
+
|
618
|
+
buff_bytes = ret; // already in buffer
|
619
|
+
request_size = nffile->block_header->size - buff_bytes; // still to go for this amount of data
|
620
|
+
|
621
|
+
read_ptr = (void *)((pointer_addr_t)buff + buff_bytes);
|
622
|
+
do {
|
623
|
+
ret = read(nffile->fd, read_ptr, request_size);
|
624
|
+
if ( ret < 0 )
|
625
|
+
// -1: Error - not expected
|
626
|
+
LogError("read() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
627
|
+
return NF_ERROR;
|
628
|
+
|
629
|
+
if ( ret == 0 ) {
|
630
|
+
// 0: EOF - not expected
|
631
|
+
LogError(error_string, ERR_SIZE, "Corrupt data file: Unexpected EOF. Short read of data block.\n");
|
632
|
+
return NF_CORRUPT;
|
633
|
+
}
|
634
|
+
|
635
|
+
buff_bytes += ret;
|
636
|
+
request_size = nffile->block_header->size - buff_bytes;
|
637
|
+
|
638
|
+
if ( request_size > 0 ) {
|
639
|
+
// still a short read - continue in read loop
|
640
|
+
read_ptr = (void *)((pointer_addr_t)buff + buff_bytes);
|
641
|
+
}
|
642
|
+
} while ( request_size > 0 );
|
643
|
+
|
644
|
+
if ( FILE_IS_COMPRESSED(nffile) ) {
|
645
|
+
int r;
|
646
|
+
lzo_uint new_len;
|
647
|
+
r = lzo1x_decompress(lzo_buff, nffile->block_header->size, nffile->buff_ptr, &new_len, NULL);
|
648
|
+
if (r != LZO_E_OK ) {
|
649
|
+
/* this should NEVER happen */
|
650
|
+
LogError("ReadBlock() error decompression failed in %s line %d: LZO error: %d\n", __FILE__, __LINE__, r);
|
651
|
+
return NF_CORRUPT;
|
652
|
+
}
|
653
|
+
nffile->block_header->size = new_len;
|
654
|
+
return read_bytes + new_len;
|
655
|
+
|
656
|
+
} else {
|
657
|
+
// finally - we are done for now
|
658
|
+
return read_bytes + buff_bytes;
|
659
|
+
}
|
660
|
+
|
661
|
+
/* not reached */
|
662
|
+
|
663
|
+
} // End of ReadBlock
|
664
|
+
|
665
|
+
int WriteBlock(nffile_t *nffile) {
|
666
|
+
data_block_header_t *out_block_header;
|
667
|
+
int r, ret;
|
668
|
+
unsigned char __LZO_MMODEL *in;
|
669
|
+
unsigned char __LZO_MMODEL *out;
|
670
|
+
lzo_uint in_len;
|
671
|
+
lzo_uint out_len;
|
672
|
+
|
673
|
+
// empty blocks need not to be stored
|
674
|
+
if ( nffile->block_header->size == 0 )
|
675
|
+
return 1;
|
676
|
+
|
677
|
+
if ( !TestFlag(nffile->file_header->flags, FLAG_COMPRESSED) ) {
|
678
|
+
ret = write(nffile->fd, (void *)nffile->block_header, sizeof(data_block_header_t) + nffile->block_header->size);
|
679
|
+
if ( ret > 0 ) {
|
680
|
+
nffile->block_header->size = 0;
|
681
|
+
nffile->block_header->NumRecords = 0;
|
682
|
+
nffile->buff_ptr = (void *)((pointer_addr_t)nffile->block_header + sizeof(data_block_header_t) );
|
683
|
+
nffile->file_header->NumBlocks++;
|
684
|
+
}
|
685
|
+
return ret;
|
686
|
+
}
|
687
|
+
|
688
|
+
out_block_header = (data_block_header_t *)lzo_buff;
|
689
|
+
*out_block_header = *(nffile->block_header);
|
690
|
+
|
691
|
+
in = (unsigned char __LZO_MMODEL *)((pointer_addr_t)nffile->block_header + sizeof(data_block_header_t));
|
692
|
+
out = (unsigned char __LZO_MMODEL *)((pointer_addr_t)out_block_header + sizeof(data_block_header_t));
|
693
|
+
in_len = nffile->block_header->size;
|
694
|
+
r = lzo1x_1_compress(in,in_len,out,&out_len,wrkmem);
|
695
|
+
|
696
|
+
if (r != LZO_E_OK) {
|
697
|
+
snprintf(error_string, ERR_SIZE,"compression failed: %d" , r);
|
698
|
+
error_string[ERR_SIZE-1] = 0;
|
699
|
+
return -2;
|
700
|
+
}
|
701
|
+
|
702
|
+
out_block_header->size = out_len;
|
703
|
+
ret = write(nffile->fd, (void *)out_block_header, sizeof(data_block_header_t) + out_block_header->size);
|
704
|
+
if ( ret > 0 ) {
|
705
|
+
nffile->block_header->size = 0;
|
706
|
+
nffile->block_header->NumRecords = 0;
|
707
|
+
nffile->buff_ptr = (void *)((pointer_addr_t)nffile->block_header + sizeof(data_block_header_t) );
|
708
|
+
nffile->file_header->NumBlocks++;
|
709
|
+
}
|
710
|
+
|
711
|
+
return ret;
|
712
|
+
|
713
|
+
} // End of WriteBlock
|
714
|
+
|
715
|
+
int WriteExtraBlock(nffile_t *nffile, data_block_header_t *block_header) {
|
716
|
+
data_block_header_t *out_block_header;
|
717
|
+
int r, ret;
|
718
|
+
unsigned char __LZO_MMODEL *in;
|
719
|
+
unsigned char __LZO_MMODEL *out;
|
720
|
+
lzo_uint in_len;
|
721
|
+
lzo_uint out_len;
|
722
|
+
|
723
|
+
if ( !TestFlag(nffile->file_header->flags, FLAG_COMPRESSED) ) {
|
724
|
+
ret = write(nffile->fd, (void *)block_header, sizeof(data_block_header_t) + block_header->size);
|
725
|
+
if ( ret > 0 ) {
|
726
|
+
nffile->file_header->NumBlocks++;
|
727
|
+
}
|
728
|
+
return ret;
|
729
|
+
}
|
730
|
+
|
731
|
+
out_block_header = (data_block_header_t *)lzo_buff;
|
732
|
+
*out_block_header = *(block_header);
|
733
|
+
|
734
|
+
in = (unsigned char __LZO_MMODEL *)((pointer_addr_t)block_header + sizeof(data_block_header_t));
|
735
|
+
out = (unsigned char __LZO_MMODEL *)((pointer_addr_t)out_block_header + sizeof(data_block_header_t));
|
736
|
+
in_len = block_header->size;
|
737
|
+
r = lzo1x_1_compress(in,in_len,out,&out_len,wrkmem);
|
738
|
+
|
739
|
+
if (r != LZO_E_OK) {
|
740
|
+
snprintf(error_string, ERR_SIZE,"compression failed: %d" , r);
|
741
|
+
error_string[ERR_SIZE-1] = 0;
|
742
|
+
return -2;
|
743
|
+
}
|
744
|
+
|
745
|
+
out_block_header->size = out_len;
|
746
|
+
ret = write(nffile->fd, (void *)out_block_header, sizeof(data_block_header_t) + out_block_header->size);
|
747
|
+
if ( ret > 0 ) {
|
748
|
+
nffile->file_header->NumBlocks++;
|
749
|
+
}
|
750
|
+
|
751
|
+
return ret;
|
752
|
+
|
753
|
+
} // End of WriteExtraBlock
|
754
|
+
|
755
|
+
|
756
|
+
inline void ExpandRecord_v1(common_record_t *input_record, master_record_t *output_record ) {
|
757
|
+
uint32_t *u;
|
758
|
+
size_t size;
|
759
|
+
void *p = (void *)input_record;
|
760
|
+
|
761
|
+
// Copy common data block
|
762
|
+
size = sizeof(common_record_t) - sizeof(uint8_t[4]);
|
763
|
+
memcpy((void *)output_record, p, size);
|
764
|
+
p = (void *)input_record->data;
|
765
|
+
|
766
|
+
if ( (input_record->flags & FLAG_IPV6_ADDR) != 0 ) { // IPv6
|
767
|
+
// IPv6
|
768
|
+
memcpy((void *)output_record->v6.srcaddr, p, 4 * sizeof(uint64_t));
|
769
|
+
p = (void *)((pointer_addr_t)p + 4 * sizeof(uint64_t));
|
770
|
+
} else {
|
771
|
+
// IPv4
|
772
|
+
u = (uint32_t *)p;
|
773
|
+
output_record->v6.srcaddr[0] = 0;
|
774
|
+
output_record->v6.srcaddr[1] = 0;
|
775
|
+
output_record->v4.srcaddr = u[0];
|
776
|
+
|
777
|
+
output_record->v6.dstaddr[0] = 0;
|
778
|
+
output_record->v6.dstaddr[1] = 0;
|
779
|
+
output_record->v4.dstaddr = u[1];
|
780
|
+
p = (void *)((pointer_addr_t)p + 2 * sizeof(uint32_t));
|
781
|
+
}
|
782
|
+
|
783
|
+
// packet counter
|
784
|
+
if ( (input_record->flags & FLAG_PKG_64 ) != 0 ) {
|
785
|
+
// 64bit packet counter
|
786
|
+
value64_t l, *v = (value64_t *)p;
|
787
|
+
l.val.val32[0] = v->val.val32[0];
|
788
|
+
l.val.val32[1] = v->val.val32[1];
|
789
|
+
output_record->dPkts = l.val.val64;
|
790
|
+
p = (void *)((pointer_addr_t)p + sizeof(uint64_t));
|
791
|
+
} else {
|
792
|
+
// 32bit packet counter
|
793
|
+
output_record->dPkts = *((uint32_t *)p);
|
794
|
+
p = (void *)((pointer_addr_t)p + sizeof(uint32_t));
|
795
|
+
}
|
796
|
+
|
797
|
+
// byte counter
|
798
|
+
if ( (input_record->flags & FLAG_BYTES_64 ) != 0 ) {
|
799
|
+
// 64bit byte counter
|
800
|
+
value64_t l, *v = (value64_t *)p;
|
801
|
+
l.val.val32[0] = v->val.val32[0];
|
802
|
+
l.val.val32[1] = v->val.val32[1];
|
803
|
+
output_record->dOctets = l.val.val64;
|
804
|
+
p = (void *)((pointer_addr_t)p + sizeof(uint64_t));
|
805
|
+
} else {
|
806
|
+
// 32bit bytes counter
|
807
|
+
output_record->dOctets = *((uint32_t *)p);
|
808
|
+
p = (void *)((pointer_addr_t)p + sizeof(uint32_t));
|
809
|
+
}
|
810
|
+
|
811
|
+
} // End of ExpandRecord_v1
|
812
|
+
|
813
|
+
void UnCompressFile(char * filename) {
|
814
|
+
int i, flags, compressed, anonymized;
|
815
|
+
ssize_t ret;
|
816
|
+
nffile_t *nffile_r, *nffile_w;
|
817
|
+
stat_record_t *_s;
|
818
|
+
char outfile[MAXPATHLEN];
|
819
|
+
void *tmp;
|
820
|
+
|
821
|
+
nffile_r = OpenFile(filename, NULL);
|
822
|
+
if ( !nffile_r ) {
|
823
|
+
return;
|
824
|
+
}
|
825
|
+
|
826
|
+
// tmp filename for new output file
|
827
|
+
snprintf(outfile, MAXPATHLEN, "%s-tmp", filename);
|
828
|
+
outfile[MAXPATHLEN-1] = '\0';
|
829
|
+
|
830
|
+
flags = nffile_r->file_header->flags;
|
831
|
+
if ( FILE_IS_COMPRESSED(nffile_r) ) {
|
832
|
+
printf("Uncompress file %s ..\n", filename);
|
833
|
+
compressed = 0;
|
834
|
+
} else {
|
835
|
+
printf("Compress file %s .. \n", filename);
|
836
|
+
compressed = 1;
|
837
|
+
}
|
838
|
+
anonymized = IP_ANONYMIZED(nffile_r);
|
839
|
+
|
840
|
+
// allocate output file
|
841
|
+
nffile_w = OpenNewFile(outfile, NULL, compressed, anonymized, NULL);
|
842
|
+
if ( !nffile_w ) {
|
843
|
+
CloseFile(nffile_r);
|
844
|
+
DisposeFile(nffile_r);
|
845
|
+
return;
|
846
|
+
}
|
847
|
+
|
848
|
+
// Use same buffer for read/write
|
849
|
+
tmp = nffile_r->block_header;
|
850
|
+
nffile_r->block_header = nffile_w->block_header;
|
851
|
+
nffile_r->buff_ptr = nffile_w->buff_ptr;
|
852
|
+
|
853
|
+
// swap stat records :)
|
854
|
+
_s = nffile_r->stat_record;
|
855
|
+
nffile_r->stat_record = nffile_w->stat_record;
|
856
|
+
nffile_w->stat_record = _s;
|
857
|
+
|
858
|
+
for ( i=0; i < nffile_r->file_header->NumBlocks; i++ ) {
|
859
|
+
ret = ReadBlock(nffile_r);
|
860
|
+
if ( ret < 0 ) {
|
861
|
+
LogError("Error while reading data block. Abort.\n");
|
862
|
+
nffile_r->block_header = tmp;
|
863
|
+
CloseFile(nffile_r);
|
864
|
+
DisposeFile(nffile_r);
|
865
|
+
CloseFile(nffile_w);
|
866
|
+
DisposeFile(nffile_w);
|
867
|
+
unlink(outfile);
|
868
|
+
return;
|
869
|
+
}
|
870
|
+
if ( WriteBlock(nffile_w) <= 0 ) {
|
871
|
+
LogError("Failed to write output buffer to disk: '%s'" , strerror(errno));
|
872
|
+
nffile_r->block_header = tmp;
|
873
|
+
CloseFile(nffile_r);
|
874
|
+
DisposeFile(nffile_r);
|
875
|
+
CloseFile(nffile_w);
|
876
|
+
DisposeFile(nffile_w);
|
877
|
+
unlink(outfile);
|
878
|
+
return;
|
879
|
+
}
|
880
|
+
}
|
881
|
+
|
882
|
+
// file processed
|
883
|
+
nffile_r->block_header = tmp;
|
884
|
+
CloseFile(nffile_r);
|
885
|
+
|
886
|
+
if ( !CloseUpdateFile(nffile_w, nffile_r->file_header->ident) ) {
|
887
|
+
unlink(outfile);
|
888
|
+
LogError("Failed to close file: '%s'" , strerror(errno));
|
889
|
+
} else {
|
890
|
+
unlink(filename);
|
891
|
+
rename(outfile, filename);
|
892
|
+
}
|
893
|
+
|
894
|
+
DisposeFile(nffile_r);
|
895
|
+
DisposeFile(nffile_w);
|
896
|
+
|
897
|
+
} // End of UnCompressFile
|
898
|
+
|
899
|
+
void QueryFile(char *filename) {
|
900
|
+
int i;
|
901
|
+
nffile_t *nffile;
|
902
|
+
uint32_t num_records, type1, type2, type3;
|
903
|
+
struct stat stat_buf;
|
904
|
+
ssize_t ret;
|
905
|
+
off_t fsize;
|
906
|
+
|
907
|
+
if ( stat(filename, &stat_buf) ) {
|
908
|
+
LogError("Can't stat '%s': %s\n", filename, strerror(errno));
|
909
|
+
return;
|
910
|
+
}
|
911
|
+
|
912
|
+
nffile = OpenFile(filename, NULL);
|
913
|
+
if ( !nffile ) {
|
914
|
+
return;
|
915
|
+
}
|
916
|
+
|
917
|
+
num_records = 0;
|
918
|
+
// set file size to current position ( file header )
|
919
|
+
fsize = lseek(nffile->fd, 0, SEEK_CUR);
|
920
|
+
type1 = 0;
|
921
|
+
type2 = 0;
|
922
|
+
type3 = 0;
|
923
|
+
printf("File : %s\n", filename);
|
924
|
+
printf("Version : %u - %s\n", nffile->file_header->version, FILE_IS_COMPRESSED(nffile) ? "compressed" : "not compressed");
|
925
|
+
printf("Blocks : %u\n", nffile->file_header->NumBlocks);
|
926
|
+
for ( i=0; i < nffile->file_header->NumBlocks; i++ ) {
|
927
|
+
if ( (fsize + sizeof(data_block_header_t)) > stat_buf.st_size ) {
|
928
|
+
LogError("Unexpected read beyond EOF! File corrupted. Abort.\n");
|
929
|
+
LogError("Expected %u blocks, counted %i\n", nffile->file_header->NumBlocks, i);
|
930
|
+
break;
|
931
|
+
}
|
932
|
+
ret = read(nffile->fd, (void *)nffile->block_header, sizeof(data_block_header_t));
|
933
|
+
if ( ret < 0 ) {
|
934
|
+
LogError("Error reading block %i: %s\n", i, strerror(errno));
|
935
|
+
break;
|
936
|
+
}
|
937
|
+
|
938
|
+
// Should never happen, as catched already in first check, but test it anyway ..
|
939
|
+
if ( ret == 0 ) {
|
940
|
+
LogError("Unexpected end of file reached. Expected %u blocks, counted %i\n", nffile->file_header->NumBlocks, i);
|
941
|
+
break;
|
942
|
+
}
|
943
|
+
if ( ret < sizeof(data_block_header_t) ) {
|
944
|
+
LogError("Short read: Expected %u bytes, read: %i\n", sizeof(data_block_header_t), ret);
|
945
|
+
break;
|
946
|
+
}
|
947
|
+
fsize += sizeof(data_block_header_t);
|
948
|
+
|
949
|
+
num_records += nffile->block_header->NumRecords;
|
950
|
+
switch ( nffile->block_header->id) {
|
951
|
+
case DATA_BLOCK_TYPE_1:
|
952
|
+
type1++;
|
953
|
+
break;
|
954
|
+
case DATA_BLOCK_TYPE_2:
|
955
|
+
type2++;
|
956
|
+
break;
|
957
|
+
case Large_BLOCK_Type:
|
958
|
+
type3++;
|
959
|
+
break;
|
960
|
+
default:
|
961
|
+
printf("block %i has unknown type %u\n", i, nffile->block_header->id);
|
962
|
+
}
|
963
|
+
|
964
|
+
if ( (fsize + nffile->block_header->size ) > stat_buf.st_size ) {
|
965
|
+
LogError("Expected to seek beyond EOF! File corrupted. Abort.\n");
|
966
|
+
break;
|
967
|
+
}
|
968
|
+
fsize += nffile->block_header->size;
|
969
|
+
|
970
|
+
ret = lseek(nffile->fd, nffile->block_header->size, SEEK_CUR);
|
971
|
+
if ( ret < 0 ) {
|
972
|
+
LogError("Error seeking block %i: %s\n", i, strerror(errno));
|
973
|
+
break;
|
974
|
+
}
|
975
|
+
if ( fsize != ret ) {
|
976
|
+
LogError("Expected seek: Expected: %u, got: %u\n", fsize, ret);
|
977
|
+
break;
|
978
|
+
}
|
979
|
+
}
|
980
|
+
|
981
|
+
if ( fsize < stat_buf.st_size ) {
|
982
|
+
LogError("Extra data detected after regular blocks: %i bytes\n", stat_buf.st_size-fsize);
|
983
|
+
}
|
984
|
+
|
985
|
+
printf(" Type 1 : %u\n", type1);
|
986
|
+
printf(" Type 2 : %u\n", type2);
|
987
|
+
printf(" Type 3 : %u\n", type3);
|
988
|
+
printf("Records : %u\n", num_records);
|
989
|
+
|
990
|
+
CloseFile(nffile);
|
991
|
+
DisposeFile(nffile);
|
992
|
+
|
993
|
+
} // End of QueryFile
|
994
|
+
|
995
|
+
// simple interface to get a statrecord from a file without nffile overhead
|
996
|
+
stat_record_t *GetStatRecord(char *filename, stat_record_t *stat_record) {
|
997
|
+
file_header_t file_header;
|
998
|
+
int fd, ret;
|
999
|
+
|
1000
|
+
fd = open(filename, O_RDONLY);
|
1001
|
+
if ( fd < 0 ) {
|
1002
|
+
LogError("open() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
1003
|
+
return NULL;
|
1004
|
+
}
|
1005
|
+
|
1006
|
+
ret = read(fd, (void *)&file_header, sizeof(file_header_t));
|
1007
|
+
if ( ret < 0 ) {
|
1008
|
+
LogError("read() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
1009
|
+
close(fd);
|
1010
|
+
return NULL;
|
1011
|
+
}
|
1012
|
+
|
1013
|
+
if ( file_header.magic != MAGIC ) {
|
1014
|
+
LogError("Open file '%s': bad magic: 0x%X\n", filename ? filename : "<stdin>", FileHeader.magic );
|
1015
|
+
close(fd);
|
1016
|
+
return NULL;
|
1017
|
+
}
|
1018
|
+
|
1019
|
+
if ( file_header.version != LAYOUT_VERSION_1 ) {
|
1020
|
+
LogError("Open file %s: bad version: %u\n", filename, FileHeader.version );
|
1021
|
+
close(fd);
|
1022
|
+
return NULL;
|
1023
|
+
}
|
1024
|
+
|
1025
|
+
ret = read(fd, (void *)stat_record, sizeof(stat_record_t));
|
1026
|
+
if ( ret < 0 ) {
|
1027
|
+
LogError("read() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
1028
|
+
close(fd);
|
1029
|
+
return NULL;
|
1030
|
+
}
|
1031
|
+
|
1032
|
+
close(fd);
|
1033
|
+
return stat_record;
|
1034
|
+
|
1035
|
+
} // End of GetStatRecord
|
1036
|
+
|
1037
|
+
#ifdef COMPAT15
|
1038
|
+
/*
|
1039
|
+
* v1 -> v2 record conversion:
|
1040
|
+
* A netflow record in v1 block format has the same size as in v2 block format.
|
1041
|
+
* Therefore, the conversion rearranges the v1 layout into v2 layout
|
1042
|
+
*
|
1043
|
+
* old record size = new record size = 36bytes + x, where x is the sum of
|
1044
|
+
* IP address block (IPv4 or IPv6) + packet counter + byte counter ( 4/8 bytes)
|
1045
|
+
*
|
1046
|
+
* v1 v2
|
1047
|
+
*
|
1048
|
+
* 0 uint32_t flags; uint16_t type;
|
1049
|
+
* uint16_t size;
|
1050
|
+
*
|
1051
|
+
* 1 uint16_t size; uint8_t flags;
|
1052
|
+
* uint8_t exporter_ref;
|
1053
|
+
* uint16_t exporter_ref; => 0 uint16_t ext_map;
|
1054
|
+
*
|
1055
|
+
* 2 uint16_t msec_first; uint16_t msec_first;
|
1056
|
+
* uint16_t msec_last; uint16_t msec_last;
|
1057
|
+
*
|
1058
|
+
* 3 uint32_t first; uint32_t first;
|
1059
|
+
* 4 uint32_t last; uint32_t last;
|
1060
|
+
*
|
1061
|
+
* 5 uint8_t dir; uint8_t fwd_status;
|
1062
|
+
* uint8_t tcp_flags; uint8_t tcp_flags;
|
1063
|
+
* uint8_t prot; uint8_t prot;
|
1064
|
+
* uint8_t tos; uint8_t tos;
|
1065
|
+
*
|
1066
|
+
* 6 uint16_t input; uint16_t srcport;
|
1067
|
+
* uint16_t output; uint16_t dstport;
|
1068
|
+
*
|
1069
|
+
* 7 uint16_t srcport; x bytes IP/pkts/bytes
|
1070
|
+
* uint16_t dstport;
|
1071
|
+
*
|
1072
|
+
* 8 uint16_t srcas;
|
1073
|
+
* uint16_t dstas;
|
1074
|
+
* uint16_t input;
|
1075
|
+
* uint16_t output;
|
1076
|
+
*
|
1077
|
+
* uint16_t srcas;
|
1078
|
+
* 9 x bytes IP/pkts/byte uint16_t dstas;
|
1079
|
+
*
|
1080
|
+
*
|
1081
|
+
*/
|
1082
|
+
|
1083
|
+
void Convert_v1_to_v2(void *mem) {
|
1084
|
+
common_record_t *v2 = (common_record_t *)mem;
|
1085
|
+
common_record_v1_t *v1 = (common_record_v1_t *)mem;
|
1086
|
+
uint32_t *index = (uint32_t *)mem;
|
1087
|
+
uint16_t tmp1, tmp2, srcas, dstas, *tmp3;
|
1088
|
+
size_t cplen;
|
1089
|
+
|
1090
|
+
// index 0
|
1091
|
+
tmp1 = v1->flags;
|
1092
|
+
v2->type = CommonRecordType;
|
1093
|
+
v2->size = v1->size;
|
1094
|
+
|
1095
|
+
// index 1
|
1096
|
+
v2->flags = tmp1;
|
1097
|
+
v2->exporter_ref = 0;
|
1098
|
+
v2->ext_map = 0;
|
1099
|
+
|
1100
|
+
// index 2, 3, 4 already in sync
|
1101
|
+
|
1102
|
+
// index 5
|
1103
|
+
v2->fwd_status = 0;
|
1104
|
+
|
1105
|
+
// index 6
|
1106
|
+
tmp1 = v1->input;
|
1107
|
+
tmp2 = v1->output;
|
1108
|
+
v2->srcport = v1->srcport;
|
1109
|
+
v2->dstport = v1->dstport;
|
1110
|
+
|
1111
|
+
// save AS numbers
|
1112
|
+
srcas = v1->srcas;
|
1113
|
+
dstas = v1->dstas;
|
1114
|
+
|
1115
|
+
cplen = 0;
|
1116
|
+
switch (v2->flags) {
|
1117
|
+
case 0:
|
1118
|
+
// IPv4 8 byte + 2 x 4 byte counter
|
1119
|
+
cplen = 16;
|
1120
|
+
break;
|
1121
|
+
case 1:
|
1122
|
+
// IPv6 32 byte + 2 x 4 byte counter
|
1123
|
+
cplen = 40;
|
1124
|
+
break;
|
1125
|
+
case 2:
|
1126
|
+
// IPv4 8 byte + 1 x 4 + 1 x 8 byte counter
|
1127
|
+
cplen = 20;
|
1128
|
+
break;
|
1129
|
+
case 3:
|
1130
|
+
// IPv6 32 byte + 1 x 4 + 1 x 8 byte counter
|
1131
|
+
cplen = 44;
|
1132
|
+
break;
|
1133
|
+
case 4:
|
1134
|
+
// IPv4 8 byte + 1 x 8 + 1 x 4 byte counter
|
1135
|
+
cplen = 20;
|
1136
|
+
break;
|
1137
|
+
case 5:
|
1138
|
+
// IPv6 32 byte + 1 x 8 + 1 x 4 byte counter
|
1139
|
+
cplen = 44;
|
1140
|
+
break;
|
1141
|
+
case 6:
|
1142
|
+
// IPv4 8 byte + 2 x 8 byte counter
|
1143
|
+
cplen = 24;
|
1144
|
+
break;
|
1145
|
+
case 7:
|
1146
|
+
// IPv6 32 byte + 2 x 8 byte counter
|
1147
|
+
cplen = 48;
|
1148
|
+
break;
|
1149
|
+
default:
|
1150
|
+
// this should never happen - catch it anyway
|
1151
|
+
cplen = 0;
|
1152
|
+
}
|
1153
|
+
// copy IP/pkts/bytes block
|
1154
|
+
memcpy((void *)&index[7], (void *)&index[9], cplen );
|
1155
|
+
|
1156
|
+
// hook 16 bit array at the end of copied block
|
1157
|
+
tmp3 = (uint16_t *)&index[7+(cplen>>2)];
|
1158
|
+
// 2 byte I/O interfaces
|
1159
|
+
tmp3[0] = tmp1;
|
1160
|
+
tmp3[1] = tmp2;
|
1161
|
+
// AS numbers
|
1162
|
+
tmp3[2] = srcas;
|
1163
|
+
tmp3[3] = dstas;
|
1164
|
+
|
1165
|
+
} // End of Convert_v1_to_v2
|
1166
|
+
#endif
|
1167
|
+
|