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_raw.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 
raw_prolog(void)61 void raw_prolog(void) {
62 	recordCount = 0;
63 	memset(data_string, 0, STRINGSIZE);
64 } // End of raw_prolog
65 
raw_epilog(void)66 void raw_epilog(void) {
67 	// empty
68 } // End of raw_epilog
69 
flow_record_to_raw(void * record,char ** s,int tag)70 void flow_record_to_raw(void *record, char ** s, int tag) {
71 char 		*_s, as[IP_STRING_LEN], ds[IP_STRING_LEN], datestr1[64], datestr2[64], datestr3[64];
72 char		s_snet[IP_STRING_LEN], s_dnet[IP_STRING_LEN];
73 int			i, id;
74 ssize_t		slen, _slen;
75 time_t		when;
76 struct tm 	*ts;
77 master_record_t *r = (master_record_t *)record;
78 extension_map_t	*extension_map = r->map_ref;
79 
80 	as[0] = 0;
81 	ds[0] = 0;
82 	if ( TestFlag(r->flags,FLAG_IPV6_ADDR ) != 0 ) { // IPv6
83 		uint64_t snet[2];
84 		uint64_t dnet[2];
85 
86 		snet[0] = htonll(r->V6.srcaddr[0]);
87 		snet[1] = htonll(r->V6.srcaddr[1]);
88 		dnet[0] = htonll(r->V6.dstaddr[0]);
89 		dnet[1] = htonll(r->V6.dstaddr[1]);
90 		inet_ntop(AF_INET6, snet, as, sizeof(as));
91 		inet_ntop(AF_INET6, dnet, ds, sizeof(ds));
92 
93 		inet6_ntop_mask(r->V6.srcaddr, r->src_mask, s_snet, sizeof(s_snet));
94 		inet6_ntop_mask(r->V6.dstaddr, r->dst_mask, s_dnet, sizeof(s_dnet));
95 
96 	} else {	// IPv4
97 		uint32_t snet, dnet;
98 		snet = htonl(r->V4.srcaddr);
99 		dnet = htonl(r->V4.dstaddr);
100 		inet_ntop(AF_INET, &snet, as, sizeof(as));
101 		inet_ntop(AF_INET, &dnet, ds, sizeof(ds));
102 
103 		inet_ntop_mask(r->V4.srcaddr, r->src_mask, s_snet, sizeof(s_snet));
104 		inet_ntop_mask(r->V4.dstaddr, r->dst_mask, s_dnet, sizeof(s_dnet));
105 
106 	}
107 	as[IP_STRING_LEN-1] = 0;
108 	ds[IP_STRING_LEN-1] = 0;
109 
110 	when = r->first;
111 	ts = localtime(&when);
112 	strftime(datestr1, 63, "%Y-%m-%d %H:%M:%S", ts);
113 
114 	when = r->last;
115 	ts = localtime(&when);
116 	strftime(datestr2, 63, "%Y-%m-%d %H:%M:%S", ts);
117 
118 	_s = data_string;
119 	slen = STRINGSIZE;
120 	snprintf(_s, slen-1, "\n"
121 "Flow Record: \n"
122 "  Flags        =              0x%.2x %s, %s\n"
123 "  label        =  %16s\n"
124 "  export sysid =             %5u\n"
125 "  size         =             %5u\n"
126 "  first        =        %10u [%s]\n"
127 "  last         =        %10u [%s]\n"
128 "  msec_first   =             %5u\n"
129 "  msec_last    =             %5u\n"
130 "  src addr     =  %16s\n"
131 "  dst addr     =  %16s\n"
132 ,
133 		r->flags, TestFlag(r->flags, FLAG_EVENT) ? "EVENT" : "FLOW",
134 		TestFlag(r->flags, FLAG_SAMPLED) ? "Sampled" : "Unsampled",
135 		r->label ? r->label : "<none>",
136 		r->exporter_sysid, r->size, r->first,
137 		datestr1, r->last, datestr2, r->msec_first, r->msec_last,
138 		as, ds );
139 
140 	_slen = strlen(data_string);
141 	_s = data_string + _slen;
142 	slen = STRINGSIZE - _slen;
143 
144 	if ( r->prot == IPPROTO_ICMP || r->prot == IPPROTO_ICMPV6 ) { // ICMP
145 		snprintf(_s, slen-1,
146 "  ICMP         =              %2u.%-2u type.code\n",
147 		r->icmp_type, r->icmp_code);
148 	} else {
149 		snprintf(_s, slen-1,
150 "  src port     =             %5u\n"
151 "  dst port     =             %5u\n",
152 		r->srcport, r->dstport);
153 	}
154 
155 	_slen = strlen(data_string);
156 	_s = data_string + _slen;
157 	slen = STRINGSIZE - _slen;
158 
159 	snprintf(_s, slen-1,
160 "  fwd status   =               %3u\n"
161 "  tcp flags    =              0x%.2x %s\n"
162 "  proto        =               %3u %s\n"
163 "  (src)tos     =               %3u\n"
164 "  (in)packets  =        %10llu\n"
165 "  (in)bytes    =        %10llu\n",
166 	r->fwd_status, r->tcp_flags, FlagsString(r->tcp_flags), r->prot, ProtoString(r->prot, 0), r->tos,
167 		(unsigned long long)r->dPkts, (unsigned long long)r->dOctets);
168 
169 	_slen = strlen(data_string);
170 	_s = data_string + _slen;
171 	slen = STRINGSIZE - _slen;
172 
173 	i = 0;
174 	while ( (id = extension_map->ex_id[i]) != 0 ) {
175 		if ( slen <= 20 ) {
176 			fprintf(stderr, "String too short! Missing record data!\n");
177 			data_string[STRINGSIZE-1] = 0;
178 			*s = data_string;
179 		}
180 		switch(id) {
181 			case EX_IO_SNMP_2:
182 			case EX_IO_SNMP_4:
183 				snprintf(_s, slen-1,
184 "  input        =             %5u\n"
185 "  output       =             %5u\n"
186 , r->input, r->output);
187 				_slen = strlen(data_string);
188 				_s = data_string + _slen;
189 				slen = STRINGSIZE - _slen;
190 				break;
191 			case EX_AS_2:
192 			case EX_AS_4:
193 				snprintf(_s, slen-1,
194 "  src as       =             %5u\n"
195 "  dst as       =             %5u\n"
196 , r->srcas, r->dstas);
197 				_slen = strlen(data_string);
198 				_s = data_string + _slen;
199 				slen = STRINGSIZE - _slen;
200 				break;
201 			case EX_BGPADJ:
202 				snprintf(_s, slen-1,
203 "  next as      =             %5u\n"
204 "  prev as      =             %5u\n"
205 , r->bgpNextAdjacentAS, r->bgpPrevAdjacentAS);
206 				_slen = strlen(data_string);
207 				_s = data_string + _slen;
208 				slen = STRINGSIZE - _slen;
209 				break;
210 			case EX_MULIPLE:
211 				snprintf(_s, slen-1,
212 "  src mask     =             %5u %s/%u\n"
213 "  dst mask     =             %5u %s/%u\n"
214 "  dst tos      =               %3u\n"
215 "  direction    =               %3u\n"
216 , r->src_mask, s_snet, r->src_mask, r->dst_mask, s_dnet, r->dst_mask, r->dst_tos, r->dir );
217 				_slen = strlen(data_string);
218 				_s = data_string + _slen;
219 				slen = STRINGSIZE - _slen;
220 				break;
221 			case EX_NEXT_HOP_v4:
222 			case EX_NEXT_HOP_v6:
223 				if ( (r->flags & FLAG_IPV6_NH ) != 0 ) { // IPv6
224 					as[0] = 0;
225 					r->ip_nexthop.V6[0] = htonll(r->ip_nexthop.V6[0]);
226 					r->ip_nexthop.V6[1] = htonll(r->ip_nexthop.V6[1]);
227 					inet_ntop(AF_INET6, r->ip_nexthop.V6, as, sizeof(as));
228 					as[IP_STRING_LEN-1] = 0;
229 				} else {
230 					as[0] = 0;
231 					r->ip_nexthop.V4 = htonl(r->ip_nexthop.V4);
232 					inet_ntop(AF_INET, &r->ip_nexthop.V4, as, sizeof(as));
233 					as[IP_STRING_LEN-1] = 0;
234 				}
235 
236 				snprintf(_s, slen-1,
237 "  ip next hop  =  %16s\n"
238 , as);
239 				_slen = strlen(data_string);
240 				_s = data_string + _slen;
241 				slen = STRINGSIZE - _slen;
242 			break;
243 			case EX_NEXT_HOP_BGP_v4:
244 			case EX_NEXT_HOP_BGP_v6:
245 				if ( (r->flags & FLAG_IPV6_NHB ) != 0 ) { // IPv6
246 					as[0] = 0;
247 					r->bgp_nexthop.V6[0] = htonll(r->bgp_nexthop.V6[0]);
248 					r->bgp_nexthop.V6[1] = htonll(r->bgp_nexthop.V6[1]);
249 					inet_ntop(AF_INET6, r->ip_nexthop.V6, as, sizeof(as));
250 					as[IP_STRING_LEN-1] = 0;
251 				} else {
252 					as[0] = 0;
253 					r->bgp_nexthop.V4 = htonl(r->bgp_nexthop.V4);
254 					inet_ntop(AF_INET, &r->bgp_nexthop.V4, as, sizeof(as));
255 					as[IP_STRING_LEN-1] = 0;
256 				}
257 				snprintf(_s, slen-1,
258 "  bgp next hop =  %16s\n"
259 , as);
260 				_slen = strlen(data_string);
261 				_s = data_string + _slen;
262 				slen = STRINGSIZE - _slen;
263 			break;
264 			case EX_VLAN:
265 				snprintf(_s, slen-1,
266 "  src vlan     =             %5u\n"
267 "  dst vlan     =             %5u\n"
268 , r->src_vlan, r->dst_vlan);
269 				_slen = strlen(data_string);
270 				_s = data_string + _slen;
271 				slen = STRINGSIZE - _slen;
272 			break;
273 			case EX_OUT_PKG_4:
274 			case EX_OUT_PKG_8:
275 				snprintf(_s, slen-1,
276 "  out packets  =        %10llu\n"
277 , (long long unsigned)r->out_pkts);
278 				_slen = strlen(data_string);
279 				_s = data_string + _slen;
280 				slen = STRINGSIZE - _slen;
281 			break;
282 			case EX_OUT_BYTES_4:
283 			case EX_OUT_BYTES_8:
284 				snprintf(_s, slen-1,
285 "  out bytes    =        %10llu\n"
286 , (long long unsigned)r->out_bytes);
287 				_slen = strlen(data_string);
288 				_s = data_string + _slen;
289 				slen = STRINGSIZE - _slen;
290 			break;
291 			case EX_AGGR_FLOWS_4:
292 			case EX_AGGR_FLOWS_8:
293 				snprintf(_s, slen-1,
294 "  aggr flows   =        %10llu\n"
295 , (long long unsigned)r->aggr_flows);
296 				_slen = strlen(data_string);
297 				_s = data_string + _slen;
298 				slen = STRINGSIZE - _slen;
299 			break;
300 			case EX_MAC_1: {
301 				int i;
302 				uint8_t mac1[6], mac2[6];
303 
304 				for ( i=0; i<6; i++ ) {
305 					mac1[i] = (r->in_src_mac >> ( i*8 )) & 0xFF;
306 				}
307 				for ( i=0; i<6; i++ ) {
308 					mac2[i] = (r->out_dst_mac >> ( i*8 )) & 0xFF;
309 				}
310 
311 				snprintf(_s, slen-1,
312 "  in src mac   = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n"
313 "  out dst mac  = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n"
314 , mac1[5], mac1[4], mac1[3], mac1[2], mac1[1], mac1[0], mac2[5], mac2[4], mac2[3], mac2[2], mac2[1], mac2[0] );
315 				_slen = strlen(data_string);
316 				_s = data_string + _slen;
317 				slen = STRINGSIZE - _slen;
318 			} break;
319 			case EX_MAC_2: {
320 				int i;
321 				uint8_t mac1[6], mac2[6];
322 
323 				for ( i=0; i<6; i++ ) {
324 					mac1[i] = (r->in_dst_mac >> ( i*8 )) & 0xFF;
325 				}
326 				for ( i=0; i<6; i++ ) {
327 					mac2[i] = (r->out_src_mac >> ( i*8 )) & 0xFF;
328 				}
329 
330 				snprintf(_s, slen-1,
331 "  in dst mac   = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n"
332 "  out src mac  = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n"
333 , mac1[5], mac1[4], mac1[3], mac1[2], mac1[1], mac1[0], mac2[5], mac2[4], mac2[3], mac2[2], mac2[1], mac2[0] );
334 				_slen = strlen(data_string);
335 				_s = data_string + _slen;
336 				slen = STRINGSIZE - _slen;
337 			} break;
338 			case EX_MPLS: {
339 				unsigned int i;
340 				for ( i=0; i<10; i++ ) {
341 					snprintf(_s, slen-1,
342 "  MPLS Lbl %2u  =      %8u-%1u-%1u\n", i+1
343 , r->mpls_label[i] >> 4 , (r->mpls_label[i] & 0xF ) >> 1, r->mpls_label[i] & 1 );
344 					_slen = strlen(data_string);
345 					_s = data_string + _slen;
346 					slen = STRINGSIZE - _slen;
347 				}
348 			} break;
349 			case EX_ROUTER_IP_v4:
350 				as[0] = 0;
351 				r->ip_router.V4 = htonl(r->ip_router.V4);
352 				inet_ntop(AF_INET, &r->ip_router.V4, as, sizeof(as));
353 				as[IP_STRING_LEN-1] = 0;
354 
355 				snprintf(_s, slen-1,
356 "  ip router    =  %16s\n"
357 , as);
358 				_slen = strlen(data_string);
359 				_s = data_string + _slen;
360 				slen = STRINGSIZE - _slen;
361 
362 			break;
363 			case EX_ROUTER_IP_v6:
364 				as[0] = 0;
365 				r->ip_router.V6[0] = htonll(r->ip_router.V6[0]);
366 				r->ip_router.V6[1] = htonll(r->ip_router.V6[1]);
367 				inet_ntop(AF_INET6, &r->ip_router.V6, as, sizeof(as));
368 				as[IP_STRING_LEN-1] = 0;
369 
370 				snprintf(_s, slen-1,
371 "  ip router    =  %16s\n"
372 , as);
373 				_slen = strlen(data_string);
374 				_s = data_string + _slen;
375 				slen = STRINGSIZE - _slen;
376 			break;
377 			case EX_LATENCY: {
378 				double f1, f2, f3;
379 				f1 = (double)r->client_nw_delay_usec / 1000.0;
380 				f2 = (double)r->server_nw_delay_usec / 1000.0;
381 				f3 = (double)r->appl_latency_usec / 1000.0;
382 
383 				snprintf(_s, slen-1,
384 "  cli latency  =         %9.3f ms\n"
385 "  srv latency  =         %9.3f ms\n"
386 "  app latency  =         %9.3f ms\n"
387 , f1, f2, f3);
388 
389 				_slen = strlen(data_string);
390 				_s = data_string + _slen;
391 				slen = STRINGSIZE - _slen;
392 
393 			} break;
394 			case EX_ROUTER_ID:
395 				snprintf(_s, slen-1,
396 "  engine type  =             %5u\n"
397 "  engine ID    =             %5u\n"
398 , r->engine_type, r->engine_id);
399 				_slen = strlen(data_string);
400 				_s = data_string + _slen;
401 				slen = STRINGSIZE - _slen;
402 				break;
403 			case EX_RECEIVED:
404 				when = r->received / 1000LL;
405 				ts = localtime(&when);
406 				strftime(datestr3, 63, "%Y-%m-%d %H:%M:%S", ts);
407 
408 				snprintf(_s, slen-1,
409 "  received at  =     %13llu [%s.%03llu]\n"
410 , (long long unsigned)r->received, datestr3, (long long unsigned)(r->received % 1000L));
411 				_slen = strlen(data_string);
412 				_s = data_string + _slen;
413 				slen = STRINGSIZE - _slen;
414 				break;
415 #ifdef NSEL
416 			case EX_NSEL_COMMON: {
417 				when = r->event_time / 1000LL;
418 				ts = localtime(&when);
419 				strftime(datestr3, 63, "%Y-%m-%d %H:%M:%S", ts);
420 				snprintf(_s, slen-1,
421 "  connect ID   =        %10u\n"
422 "  fw event     =             %5u: %s\n"
423 "  fw ext event =             %5u: %s\n"
424 "  secgroup tag =             %5u\n"
425 "  Event time   =     %13llu [%s.%03llu]\n"
426 , r->conn_id, r->event, r->event_flag == FW_EVENT ? FwEventString(r->event) : EventString(r->event)
427 , r->fw_xevent, EventXString(r->fw_xevent), r->sec_group_tag
428 , (long long unsigned)r->event_time, datestr3, (long long unsigned)(r->event_time % 1000L));
429 				_slen = strlen(data_string);
430 				_s = data_string + _slen;
431 				slen = STRINGSIZE - _slen;
432 				} break;
433 			case EX_NEL_COMMON: {
434 				snprintf(_s, slen-1,
435 "  nat event    =             %5u: %s\n"
436 "  ingress VRF  =        %10u\n"
437 "  egress VRF   =        %10u\n"
438 , r->event, r->event_flag == FW_EVENT ? FwEventString(r->event) : EventString(r->event)
439 , r->ingress_vrfid, r->egress_vrfid);
440 				_slen = strlen(data_string);
441 				_s = data_string + _slen;
442 				slen = STRINGSIZE - _slen;
443 				} break;
444 			case EX_NSEL_XLATE_PORTS: {
445 				snprintf(_s, slen-1,
446 "  src xlt port =             %5u\n"
447 "  dst xlt port =             %5u\n"
448 , r->xlate_src_port, r->xlate_dst_port );
449 				_slen = strlen(data_string);
450 				_s = data_string + _slen;
451 				slen = STRINGSIZE - _slen;
452 				} break;
453 			case EX_PORT_BLOCK_ALLOC: {
454 				snprintf(_s, slen-1,
455 "  pblock start =             %5u\n"
456 "  pblock end   =             %5u\n"
457 "  pblock step  =             %5u\n"
458 "  pblock size  =             %5u\n"
459 , r->block_start, r->block_end, r->block_step, r->block_size );
460 				_slen = strlen(data_string);
461 				_s = data_string + _slen;
462 				slen = STRINGSIZE - _slen;
463 				} break;
464 			case EX_NSEL_XLATE_IP_v4:
465 				as[0] = 0;
466 				ds[0] = 0;
467 				r->xlate_src_ip.V4 = htonl(r->xlate_src_ip.V4);
468 				r->xlate_dst_ip.V4 = htonl(r->xlate_dst_ip.V4);
469 				inet_ntop(AF_INET, &r->xlate_src_ip.V4, as, sizeof(as));
470 				inet_ntop(AF_INET, &r->xlate_dst_ip.V4, ds, sizeof(ds));
471 				as[IP_STRING_LEN-1] = 0;
472 				ds[IP_STRING_LEN-1] = 0;
473 
474 				snprintf(_s, slen-1,
475 "  src xlt ip   =  %16s\n"
476 "  dst xlt ip   =  %16s\n"
477 , as, ds);
478 				_slen = strlen(data_string);
479 				_s = data_string + _slen;
480 				slen = STRINGSIZE - _slen;
481 			break;
482 			case EX_NSEL_XLATE_IP_v6:
483 				as[0] = 0;
484 				ds[0] = 0;
485 				r->xlate_src_ip.V6[0] = htonll(r->xlate_src_ip.V6[0]);
486 				r->xlate_src_ip.V6[1] = htonll(r->xlate_src_ip.V6[1]);
487 				r->xlate_dst_ip.V6[0] = htonll(r->xlate_dst_ip.V6[0]);
488 				r->xlate_dst_ip.V6[1] = htonll(r->xlate_dst_ip.V6[1]);
489 				inet_ntop(AF_INET6, &r->xlate_src_ip.V6, as, sizeof(as));
490 				inet_ntop(AF_INET6, &r->xlate_dst_ip.V6, ds, sizeof(ds));
491 				as[IP_STRING_LEN-1] = 0;
492 				ds[IP_STRING_LEN-1] = 0;
493 
494 				snprintf(_s, slen-1,
495 "  src xlate ip =  %16s\n"
496 "  dst xlate ip =  %16s\n"
497 , as, ds);
498 				_slen = strlen(data_string);
499 				_s = data_string + _slen;
500 				slen = STRINGSIZE - _slen;
501 			break;
502 			case EX_NSEL_ACL:
503 				snprintf(_s, slen-1,
504 "  Ingress ACL  =       0x%x/0x%x/0x%x\n"
505 "  Egress ACL   =       0x%x/0x%x/0x%x\n"
506 , r->ingress_acl_id[0], r->ingress_acl_id[1], r->ingress_acl_id[2],
507   r->egress_acl_id[0], r->egress_acl_id[1], r->egress_acl_id[2]);
508 				_slen = strlen(data_string);
509 				_s = data_string + _slen;
510 				slen = STRINGSIZE - _slen;
511 				break;
512 			case EX_NSEL_USER:
513 			case EX_NSEL_USER_MAX:
514 				snprintf(_s, slen-1,
515 "  User name    = %s\n"
516 , r->username[0] ? r->username : "          <empty>");
517 				_slen = strlen(data_string);
518 				_s = data_string + _slen;
519 				slen = STRINGSIZE - _slen;
520 				break;
521 #endif
522 			default:
523 				snprintf(_s, slen-1, "Type %u not implemented\n", id);
524 
525 		}
526 		i++;
527 	}
528 
529 	data_string[STRINGSIZE-1] = 0;
530 	*s = data_string;
531 
532 } // End of flow_record_to_raw
533