1 /*
2 * Copyright (c) 2019-2020, Peter Haag
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * * Neither the name of the author nor the names of its contributors may be
14 * used to endorse or promote products derived from this software without
15 * specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 *
29 */
30
31 #include "config.h"
32
33 #include <stdio.h>
34 #include <stddef.h>
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <arpa/inet.h>
39 #include <time.h>
40 #include <string.h>
41
42 #ifdef HAVE_STDINT_H
43 #include <stdint.h>
44 #endif
45
46 #include "util.h"
47 #include "nfdump.h"
48 #include "nffile.h"
49 #include "nfx.h"
50 #include "output_util.h"
51 #include "output_csv.h"
52
53 #define STRINGSIZE 10240
54 #define IP_STRING_LEN (INET6_ADDRSTRLEN)
55
56 static char data_string[STRINGSIZE];
57
58 // record counter
59 static uint32_t recordCount;
60
csv_prolog(void)61 void csv_prolog(void) {
62 recordCount = 0;
63 memset(data_string, 0, STRINGSIZE);
64
65 printf("ts,te,td,sa,da,sp,dp,pr,flg,fwd,stos,ipkt,ibyt,opkt,obyt,in,out,sas,das,smk,dmk,dtos,dir,nh,nhb,svln,dvln,ismc,odmc,idmc,osmc,mpls1,mpls2,mpls3,mpls4,mpls5,mpls6,mpls7,mpls8,mpls9,mpls10,cl,sl,al,ra,eng,exid,tr");
66
67 } // End of csv_prolog
68
csv_epilog(void)69 void csv_epilog(void) {
70
71 } // End of csv_epilog
72
flow_record_to_csv(void * record,char ** s,int tag)73 void flow_record_to_csv(void *record, char ** s, int tag) {
74 char *_s, as[IP_STRING_LEN], ds[IP_STRING_LEN];
75 char datestr1[64], datestr2[64], datestr3[64];
76 char s_snet[IP_STRING_LEN], s_dnet[IP_STRING_LEN];
77 ssize_t slen, _slen;
78 time_t when;
79 struct tm *ts;
80 master_record_t *r = (master_record_t *)record;
81
82 as[0] = 0;
83 ds[0] = 0;
84 if ( (r->flags & FLAG_IPV6_ADDR ) != 0 ) { // IPv6
85 uint64_t snet[2];
86 uint64_t dnet[2];
87
88 snet[0] = htonll(r->V6.srcaddr[0]);
89 snet[1] = htonll(r->V6.srcaddr[1]);
90 dnet[0] = htonll(r->V6.dstaddr[0]);
91 dnet[1] = htonll(r->V6.dstaddr[1]);
92 inet_ntop(AF_INET6, snet, as, sizeof(as));
93 inet_ntop(AF_INET6, dnet, ds, sizeof(ds));
94
95 inet6_ntop_mask(r->V6.srcaddr, r->src_mask, s_snet, sizeof(s_snet));
96 inet6_ntop_mask(r->V6.dstaddr, r->dst_mask, s_dnet, sizeof(s_dnet));
97
98 } else { // IPv4
99 uint32_t snet, dnet;
100 snet = htonl(r->V4.srcaddr);
101 dnet = htonl(r->V4.dstaddr);
102 inet_ntop(AF_INET, &snet, as, sizeof(as));
103 inet_ntop(AF_INET, &dnet, ds, sizeof(ds));
104
105 inet_ntop_mask(r->V4.srcaddr, r->src_mask, s_snet, sizeof(s_snet));
106 inet_ntop_mask(r->V4.dstaddr, r->dst_mask, s_dnet, sizeof(s_dnet));
107
108 }
109 as[IP_STRING_LEN-1] = 0;
110 ds[IP_STRING_LEN-1] = 0;
111
112 when = r->first;
113 ts = localtime(&when);
114 strftime(datestr1, 63, "%Y-%m-%d %H:%M:%S", ts);
115
116 when = r->last;
117 ts = localtime(&when);
118 strftime(datestr2, 63, "%Y-%m-%d %H:%M:%S", ts);
119
120 double duration = r->last - r->first;
121 duration += ((double)r->msec_last - (double)r->msec_first) / 1000.0;
122
123 _s = data_string;
124 slen = STRINGSIZE;
125 snprintf(_s, slen-1, "%s,%s,%.3f,%s,%s,%u,%u,%s,%s,%u,%u,%llu,%llu,%llu,%llu",
126 datestr1, datestr2, duration, as,ds,r->srcport, r->dstport, ProtoString(r->prot, 0),
127 FlagsString(r->tcp_flags), r->fwd_status, r->tos, (unsigned long long)r->dPkts,
128 (unsigned long long)r->dOctets, (long long unsigned)r->out_pkts, (long long unsigned)r->out_bytes);
129
130 _slen = strlen(data_string);
131 _s += _slen;
132 slen -= _slen;
133
134 // EX_IO_SNMP_2:
135 // EX_IO_SNMP_4:
136 snprintf(_s, slen-1, ",%u,%u" , r->input, r->output);
137 _slen = strlen(data_string);
138 _s = data_string + _slen;
139 slen = STRINGSIZE - _slen;
140
141 // EX_AS_2:
142 // EX_AS_4:
143 snprintf(_s, slen-1, ",%u,%u", r->srcas, r->dstas);
144 _slen = strlen(data_string);
145 _s = data_string + _slen;
146 slen = STRINGSIZE - _slen;
147
148 // EX_MULIPLE:
149 snprintf(_s, slen-1, ",%u,%u,%u,%u" , r->src_mask, r->dst_mask, r->dst_tos, r->dir );
150 _slen = strlen(data_string);
151 _s = data_string + _slen;
152 slen = STRINGSIZE - _slen;
153
154 if ( (r->flags & FLAG_IPV6_NH ) != 0 ) { // IPv6
155 // EX_NEXT_HOP_v6:
156 as[0] = 0;
157 r->ip_nexthop.V6[0] = htonll(r->ip_nexthop.V6[0]);
158 r->ip_nexthop.V6[1] = htonll(r->ip_nexthop.V6[1]);
159 inet_ntop(AF_INET6, r->ip_nexthop.V6, as, sizeof(as));
160 as[IP_STRING_LEN-1] = 0;
161
162 snprintf(_s, slen-1, ",%s", as);
163 _slen = strlen(data_string);
164 _s = data_string + _slen;
165 slen = STRINGSIZE - _slen;
166
167 } else {
168 // EX_NEXT_HOP_v4:
169 as[0] = 0;
170 r->ip_nexthop.V4 = htonl(r->ip_nexthop.V4);
171 inet_ntop(AF_INET, &r->ip_nexthop.V4, as, sizeof(as));
172 as[IP_STRING_LEN-1] = 0;
173
174 snprintf(_s, slen-1, ",%s", as);
175 _slen = strlen(data_string);
176 _s = data_string + _slen;
177 slen = STRINGSIZE - _slen;
178 }
179
180 if ( (r->flags & FLAG_IPV6_NHB ) != 0 ) { // IPv6
181 // EX_NEXT_HOP_BGP_v6:
182 as[0] = 0;
183 r->bgp_nexthop.V6[0] = htonll(r->bgp_nexthop.V6[0]);
184 r->bgp_nexthop.V6[1] = htonll(r->bgp_nexthop.V6[1]);
185 inet_ntop(AF_INET6, r->ip_nexthop.V6, as, sizeof(as));
186 as[IP_STRING_LEN-1] = 0;
187
188 snprintf(_s, slen-1, ",%s", as);
189 _slen = strlen(data_string);
190 _s = data_string + _slen;
191 slen = STRINGSIZE - _slen;
192
193 } else {
194 // EX_NEXT_HOP_BGP_v4:
195 as[0] = 0;
196 r->bgp_nexthop.V4 = htonl(r->bgp_nexthop.V4);
197 inet_ntop(AF_INET, &r->bgp_nexthop.V4, as, sizeof(as));
198 as[IP_STRING_LEN-1] = 0;
199
200 snprintf(_s, slen-1, ",%s", as);
201 _slen = strlen(data_string);
202 _s = data_string + _slen;
203 slen = STRINGSIZE - _slen;
204
205 }
206
207 // EX_VLAN:
208 snprintf(_s, slen-1, ",%u,%u", r->src_vlan, r->dst_vlan);
209 _slen = strlen(data_string);
210 _s = data_string + _slen;
211 slen = STRINGSIZE - _slen;
212
213
214 /* already in default output:
215 EX_OUT_PKG_4:
216 EX_OUT_PKG_8:
217 EX_OUT_BYTES_4:
218 EX_OUT_BYTES_8:
219 */
220
221 // case EX_MAC_1:
222 {
223 int i;
224 uint8_t mac1[6], mac2[6];
225
226 for ( i=0; i<6; i++ ) {
227 mac1[i] = (r->in_src_mac >> ( i*8 )) & 0xFF;
228 }
229 for ( i=0; i<6; i++ ) {
230 mac2[i] = (r->out_dst_mac >> ( i*8 )) & 0xFF;
231 }
232
233 snprintf(_s, slen-1, ",%.2x:%.2x:%.2x:%.2x:%.2x:%.2x,%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
234 mac1[5], mac1[4], mac1[3], mac1[2], mac1[1], mac1[0],
235 mac2[5], mac2[4], mac2[3], mac2[2], mac2[1], mac2[0] );
236 _slen = strlen(data_string);
237 _s = data_string + _slen;
238 slen = STRINGSIZE - _slen;
239 }
240
241 // EX_MAC_2:
242 {
243 int i;
244 uint8_t mac1[6], mac2[6];
245
246 for ( i=0; i<6; i++ ) {
247 mac1[i] = (r->in_dst_mac >> ( i*8 )) & 0xFF;
248 }
249 for ( i=0; i<6; i++ ) {
250 mac2[i] = (r->out_src_mac >> ( i*8 )) & 0xFF;
251 }
252
253 snprintf(_s, slen-1, ",%.2x:%.2x:%.2x:%.2x:%.2x:%.2x,%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
254 mac1[5], mac1[4], mac1[3], mac1[2], mac1[1], mac1[0],
255 mac2[5], mac2[4], mac2[3], mac2[2], mac2[1], mac2[0] );
256 _slen = strlen(data_string);
257 _s = data_string + _slen;
258 slen = STRINGSIZE - _slen;
259 }
260
261 // EX_MPLS:
262 {
263 unsigned int i;
264 for ( i=0; i<10; i++ ) {
265 snprintf(_s, slen-1, ",%u-%1u-%1u",
266 r->mpls_label[i] >> 4 , (r->mpls_label[i] & 0xF ) >> 1, r->mpls_label[i] & 1 );
267 _slen = strlen(data_string);
268 _s = data_string + _slen;
269 slen = STRINGSIZE - _slen;
270 }
271 }
272
273 {
274 double f1, f2, f3;
275 f1 = (double)r->client_nw_delay_usec / 1000.0;
276 f2 = (double)r->server_nw_delay_usec / 1000.0;
277 f3 = (double)r->appl_latency_usec / 1000.0;
278
279 snprintf(_s, slen-1,
280 ",%9.3f,%9.3f,%9.3f", f1, f2, f3);
281
282 _slen = strlen(data_string);
283 _s = data_string + _slen;
284 slen = STRINGSIZE - _slen;
285 }
286
287
288 // EX_ROUTER_IP_v4:
289 if ( (r->flags & FLAG_IPV6_EXP ) != 0 ) { // IPv6
290 // EX_NEXT_HOP_v6:
291 as[0] = 0;
292 r->ip_router.V6[0] = htonll(r->ip_router.V6[0]);
293 r->ip_router.V6[1] = htonll(r->ip_router.V6[1]);
294 inet_ntop(AF_INET6, r->ip_router.V6, as, sizeof(as));
295 as[IP_STRING_LEN-1] = 0;
296
297 snprintf(_s, slen-1, ",%s", as);
298 _slen = strlen(data_string);
299 _s = data_string + _slen;
300 slen = STRINGSIZE - _slen;
301
302 } else {
303 // EX_NEXT_HOP_v4:
304 as[0] = 0;
305 r->ip_router.V4 = htonl(r->ip_router.V4);
306 inet_ntop(AF_INET, &r->ip_router.V4, as, sizeof(as));
307 as[IP_STRING_LEN-1] = 0;
308
309 snprintf(_s, slen-1, ",%s", as);
310 _slen = strlen(data_string);
311 _s = data_string + _slen;
312 slen = STRINGSIZE - _slen;
313 }
314
315 // EX_ROUTER_ID
316 snprintf(_s, slen-1, ",%u/%u", r->engine_type, r->engine_id);
317 _slen = strlen(data_string);
318 _s = data_string + _slen;
319 slen = STRINGSIZE - _slen;
320
321 // Exporter SysID
322 snprintf(_s, slen-1, ",%u", r->exporter_sysid);
323 _slen = strlen(data_string);
324 _s = data_string + _slen;
325 slen = STRINGSIZE - _slen;
326
327 // Date flow received
328 when = r->received / 1000LL;
329 ts = localtime(&when);
330 strftime(datestr3, 63, ",%Y-%m-%d %H:%M:%S", ts);
331
332 snprintf(_s, slen-1, "%s.%03llu", datestr3, (long long unsigned)r->received % 1000LL);
333 _slen = strlen(data_string);
334 _s = data_string + _slen;
335 slen = STRINGSIZE - _slen;
336
337 // snprintf(_s, slen-1, "\n");
338 data_string[STRINGSIZE-1] = 0;
339 *s = data_string;
340
341 } // End of flow_record_to_csv
342