1 /*
2 ** Copyright (C) 2001-2020 by Carnegie Mellon University.
3 **
4 ** @OPENSOURCE_LICENSE_START@
5 ** See license information in ../../LICENSE.txt
6 ** @OPENSOURCE_LICENSE_END@
7 */
8
9 /*
10 ** rwroutedio.c
11 **
12 ** Suresh L Konda
13 ** routines to do io stuff with routed records.
14 */
15
16 #include <silk/silk.h>
17
18 RCSIDENT("$SiLK: rwroutedio.c ef14e54179be 2020-04-14 21:57:45Z mthomas $");
19
20 /* #define RWPACK_BYTES_PACKETS 1 */
21 #define RWPACK_FLAGS_TIMES_VOLUMES 1
22 /* #define RWPACK_PROTO_FLAGS 1 */
23 #define RWPACK_SBB_PEF 1
24 #define RWPACK_TIME_BYTES_PKTS_FLAGS 1
25 /* #define RWPACK_TIMES_FLAGS_PROTO 1 */
26 #include "skstream_priv.h"
27 #include "rwpack.c"
28
29
30 /* Version to use when SK_RECORD_VERSION_ANY is specified */
31 #define DEFAULT_RECORD_VERSION 5
32
33
34 /* ********************************************************************* */
35
36 /*
37 ** RWROUTED VERSION 5
38 **
39 ** uint32_t stime_bb1; // 0- 3
40 ** // uint32_t stime :22 // Start time:msec offset from hour
41 ** // uint32_t bPPkt1 :10; // Whole bytes-per-packet (hi 10)
42 **
43 ** uint32_t bb2_elapsed; // 4- 7
44 ** // uint32_t bPPkt2 : 4; // Whole bytes-per-packet (low 4)
45 ** // uint32_t bPPFrac : 6; // Fractional bytes-per-packet
46 ** // uint32_t elapsed :22; // Duration of flow in msec
47 **
48 ** uint32_t pro_flg_pkts; // 8-11
49 ** // uint32_t prot_flags: 8; // is_tcp==0: IP protocol
50 ** // is_tcp==1: TCPflags/All pkts
51 ** // uint32_t pflag : 1; // 'pkts' requires multiplier?
52 ** // uint32_t is_tcp : 1; // 1 if flow is TCP; 0 otherwise
53 ** // uint32_t padding : 2; //
54 ** // uint32_t pkts :20; // Count of packets
55 **
56 ** uint16_t sPort; // 12-13 Source port
57 ** uint16_t dPort; // 14-15 Destination port
58 **
59 ** uint16_t input; // 16-17 Router incoming SNMP interface
60 ** uint16_t output; // 18-19 Router outgoing SNMP interface
61 **
62 ** uint32_t sIP; // 20-23 Source IP
63 ** uint32_t dIP; // 24-27 Destination IP
64 **
65 ** uint32_t nhIP; // 28-31 Router Next Hop IP
66 **
67 **
68 ** 32 bytes on disk.
69 */
70
71 #define RECLEN_RWROUTED_V5 32
72
73
74 /*
75 * Byte swap the RWROUTED v5 record 'ar' in place.
76 */
77 #define routedioRecordSwap_V5(ar) \
78 { \
79 SWAP_DATA32((ar) + 0); /* stime_bb1 */ \
80 SWAP_DATA32((ar) + 4); /* bb2_elapsed */ \
81 SWAP_DATA32((ar) + 8); /* pro_flg_pkts */ \
82 SWAP_DATA16((ar) + 12); /* sPort */ \
83 SWAP_DATA16((ar) + 14); /* dPort */ \
84 SWAP_DATA16((ar) + 16); /* input */ \
85 SWAP_DATA16((ar) + 18); /* output */ \
86 SWAP_DATA32((ar) + 20); /* sIP */ \
87 SWAP_DATA32((ar) + 24); /* dIP */ \
88 SWAP_DATA32((ar) + 28); /* nhIP */ \
89 }
90
91
92 /*
93 * Unpack the array of bytes 'ar' into a record 'rwrec'
94 */
95 static int
routedioRecordUnpack_V5(skstream_t * stream,rwGenericRec_V5 * rwrec,uint8_t * ar)96 routedioRecordUnpack_V5(
97 skstream_t *stream,
98 rwGenericRec_V5 *rwrec,
99 uint8_t *ar)
100 {
101 /* swap if required */
102 if (stream->swapFlag) {
103 routedioRecordSwap_V5(ar);
104 }
105
106 /* sTime, elapsed, pkts, bytes, proto, tcp-flags */
107 rwpackUnpackFlagsTimesVolumes(rwrec, ar, stream->hdr_starttime, 12, 0);
108
109 /* sPort, dPort */
110 rwRecMemSetSPort(rwrec, &ar[12]);
111 rwRecMemSetDPort(rwrec, &ar[14]);
112
113 /* input, output */
114 rwRecMemSetInput(rwrec, &ar[16]);
115 rwRecMemSetOutput(rwrec, &ar[18]);
116
117 /* sIP, dIP, nhIP */
118 rwRecMemSetSIPv4(rwrec, &ar[20]);
119 rwRecMemSetDIPv4(rwrec, &ar[24]);
120 rwRecMemSetNhIPv4(rwrec, &ar[28]);
121
122 /* sensor, flow_type from file name/header */
123 rwRecSetSensor(rwrec, stream->hdr_sensor);
124 rwRecSetFlowType(rwrec, stream->hdr_flowtype);
125
126 return SKSTREAM_OK;
127 }
128
129
130 /*
131 * Pack the record 'rwrec' into an array of bytes 'ar'
132 */
133 static int
routedioRecordPack_V5(skstream_t * stream,const rwGenericRec_V5 * rwrec,uint8_t * ar)134 routedioRecordPack_V5(
135 skstream_t *stream,
136 const rwGenericRec_V5 *rwrec,
137 uint8_t *ar)
138 {
139 int rv = SKSTREAM_OK; /* return value */
140
141 /* sTime, elapsed, pkts, bytes, proto, tcp-flags */
142 rv = rwpackPackFlagsTimesVolumes(ar, rwrec, stream->hdr_starttime, 12);
143 if (rv) {
144 return rv;
145 }
146
147 /* sPort, dPort */
148 rwRecMemGetSPort(rwrec, &ar[12]);
149 rwRecMemGetDPort(rwrec, &ar[14]);
150
151 /* input, output */
152 rwRecMemGetInput(rwrec, &ar[16]);
153 rwRecMemGetOutput(rwrec, &ar[18]);
154
155 /* sIP, dIP, nhIP */
156 rwRecMemGetSIPv4(rwrec, &ar[20]);
157 rwRecMemGetDIPv4(rwrec, &ar[24]);
158 rwRecMemGetNhIPv4(rwrec, &ar[28]);
159
160 /* swap if required */
161 if (stream->swapFlag) {
162 routedioRecordSwap_V5(ar);
163 }
164
165 return SKSTREAM_OK;
166 }
167
168
169 /* ********************************************************************* */
170
171 /*
172 ** RWROUTED VERSION 3
173 ** RWROUTED VERSION 4
174 **
175 ** uint32_t sIP; // 0- 3 Source IP
176 ** uint32_t dIP; // 4- 7 Destination IP
177 **
178 ** uint16_t sPort; // 8- 9 Source port
179 ** uint16_t dPort; // 10-11 Destination port
180 **
181 ** uint32_t pkts_stime; // 12-15
182 ** // uint32_t pkts :20; // Count of packets
183 ** // uint32_t sTime :12; // Start time--offset from hour
184 **
185 ** uint32_t bbe; // 16-19
186 ** // uint32_t bPPkt :14; // Whole bytes-per-packet
187 ** // uint32_t bPPFrac : 6; // Fractional bytes-per-packet
188 ** // uint32_t elapsed :12; // Duration of flow
189 **
190 ** uint32_t msec_flags // 20-23
191 ** // uint32_t sTime_msec:10; // Fractional sTime (millisec)
192 ** // uint32_t elaps_msec:10; // Fractional elapsed (millisec)
193 ** // uint32_t pflag : 1; // 'pkts' requires multiplier?
194 ** // uint32_t is_tcp : 1; // 1 if flow is TCP; 0 otherwise
195 ** // uint32_t padding : 2; // padding/reserved
196 ** // uint32_t prot_flags: 8; // is_tcp==0: IP protocol
197 ** // is_tcp==1: TCP flags
198 **
199 ** uint32_t nhIP; // 24-27 Router Next Hop IP
200 **
201 ** uint16_t input; // 28-29 Router incoming SNMP interface
202 ** uint16_t output; // 30-31 Router outgoing SNMP interface
203 **
204 **
205 ** 32 bytes on disk.
206 */
207
208 #define RECLEN_RWROUTED_V3 32
209 #define RECLEN_RWROUTED_V4 32
210
211
212 /*
213 * Byte swap the RWROUTED v3 record 'ar' in place.
214 */
215 #define routedioRecordSwap_V3(ar) \
216 { \
217 SWAP_DATA32((ar) + 0); /* sIP */ \
218 SWAP_DATA32((ar) + 4); /* dIP */ \
219 SWAP_DATA16((ar) + 8); /* sPort */ \
220 SWAP_DATA16((ar) + 10); /* dPort */ \
221 SWAP_DATA32((ar) + 12); /* pkts_stime */ \
222 SWAP_DATA32((ar) + 16); /* bbe */ \
223 SWAP_DATA32((ar) + 20); /* msec_flags */ \
224 SWAP_DATA32((ar) + 24); /* nhIP */ \
225 SWAP_DATA16((ar) + 28); /* input */ \
226 SWAP_DATA16((ar) + 30); /* output */ \
227 }
228
229
230 /*
231 * Unpack the array of bytes 'ar' into a record 'rwrec'
232 */
233 static int
routedioRecordUnpack_V3(skstream_t * stream,rwGenericRec_V5 * rwrec,uint8_t * ar)234 routedioRecordUnpack_V3(
235 skstream_t *stream,
236 rwGenericRec_V5 *rwrec,
237 uint8_t *ar)
238 {
239 /* swap if required */
240 if (stream->swapFlag) {
241 routedioRecordSwap_V3(ar);
242 }
243
244 /* sIP, dIP, sPort, dPort */
245 rwRecMemSetSIPv4(rwrec, &ar[0]);
246 rwRecMemSetDIPv4(rwrec, &ar[4]);
247 rwRecMemSetSPort(rwrec, &ar[8]);
248 rwRecMemSetDPort(rwrec, &ar[10]);
249
250 /* sTime, pkts, bytes, elapsed, proto, tcp-flags, bpp */
251 rwpackUnpackTimeBytesPktsFlags(rwrec, stream->hdr_starttime,
252 (uint32_t*)&ar[12], (uint32_t*)&ar[16],
253 (uint32_t*)&ar[20]);
254
255 /* next hop, input & output interfaces */
256 rwRecMemSetNhIPv4(rwrec, &ar[24]);
257 rwRecMemSetInput(rwrec, &ar[28]);
258 rwRecMemSetOutput(rwrec, &ar[30]);
259
260 /* sensor, flow_type from file name/header */
261 rwRecSetSensor(rwrec, stream->hdr_sensor);
262 rwRecSetFlowType(rwrec, stream->hdr_flowtype);
263
264 return SKSTREAM_OK;
265 }
266
267
268 /*
269 * Pack the record 'rwrec' into an array of bytes 'ar'
270 */
271 static int
routedioRecordPack_V3(skstream_t * stream,const rwGenericRec_V5 * rwrec,uint8_t * ar)272 routedioRecordPack_V3(
273 skstream_t *stream,
274 const rwGenericRec_V5 *rwrec,
275 uint8_t *ar)
276 {
277 int rv = SKSTREAM_OK; /* return value */
278
279 /* sTime, pkts, bytes, elapsed, proto, tcp-flags, bpp */
280 rv = rwpackPackTimeBytesPktsFlags((uint32_t*)&ar[12], (uint32_t*)&ar[16],
281 (uint32_t*)&ar[20],
282 rwrec, stream->hdr_starttime);
283 if (rv) {
284 return rv;
285 }
286
287 /* sIP, dIP, sPort, dPort */
288 rwRecMemGetSIPv4(rwrec, &ar[0]);
289 rwRecMemGetDIPv4(rwrec, &ar[4]);
290 rwRecMemGetSPort(rwrec, &ar[8]);
291 rwRecMemGetDPort(rwrec, &ar[10]);
292
293 /* next hop, input & output interfaces */
294 rwRecMemGetNhIPv4(rwrec, &ar[24]);
295 rwRecMemGetInput(rwrec, &ar[28]);
296 rwRecMemGetOutput(rwrec, &ar[30]);
297
298 /* swap if required */
299 if (stream->swapFlag) {
300 routedioRecordSwap_V3(ar);
301 }
302
303 return SKSTREAM_OK;
304 }
305
306
307 /* ********************************************************************* */
308
309 /*
310 ** RWROUTED VERSION 1
311 ** RWROUTED VERSION 2
312 **
313 ** uint32_t sIP; // 0- 3 Source IP
314 ** uint32_t dIP; // 4- 7 Destination IP
315 **
316 ** uint32_t nhIP; // 8-11 Router Next Hop IP
317 **
318 ** uint16_t sPort; // 12-23 Source port
319 ** uint16_t dPort; // 14-15 Destination port
320 **
321 ** uint32_t pef; // 16-19
322 ** // uint32_t pkts :20; // Count of packets
323 ** // uint32_t elapsed :11; // Duration of flow
324 ** // uint32_t pflag : 1; // 'pkts' requires multiplier?
325 **
326 ** uint32_t sbb; // 20-23
327 ** // uint32_t sTime :12; // Start time--offset from hour
328 ** // uint32_t bPPkt :14; // Whole bytes-per-packet
329 ** // uint32_t bPPFrac : 6; // Fractional bytes-per-packet
330 **
331 ** uint8_t proto; // 24 IP protocol
332 ** uint8_t flags; // 25 OR of all TCP flags on all pkts
333 ** uint8_t input; // 26 Router incoming SNMP interface
334 ** uint8_t output; // 27 Router outgoing SNMP interface
335 **
336 **
337 ** 28 bytes on disk.
338 */
339
340 #define RECLEN_RWROUTED_V1 28
341 #define RECLEN_RWROUTED_V2 28
342
343
344 /*
345 * Byte swap the RWROUTED v1 record 'ar' in place.
346 */
347 #define routedioRecordSwap_V1(ar) \
348 { \
349 SWAP_DATA32((ar) + 0); /* sIP */ \
350 SWAP_DATA32((ar) + 4); /* dIP */ \
351 SWAP_DATA32((ar) + 8); /* nhIP */ \
352 SWAP_DATA16((ar) + 12); /* sPort */ \
353 SWAP_DATA16((ar) + 14); /* dPort */ \
354 SWAP_DATA32((ar) + 16); /* pef */ \
355 SWAP_DATA32((ar) + 20); /* sbb */ \
356 /* Four single bytes: (24)proto, (25)flags, (26)input, (27)output */ \
357 }
358
359
360 /*
361 * Unpack the array of bytes 'ar' into a record 'rwrec'
362 */
363 static int
routedioRecordUnpack_V1(skstream_t * stream,rwGenericRec_V5 * rwrec,uint8_t * ar)364 routedioRecordUnpack_V1(
365 skstream_t *stream,
366 rwGenericRec_V5 *rwrec,
367 uint8_t *ar)
368 {
369 /* swap if required */
370 if (stream->swapFlag) {
371 routedioRecordSwap_V1(ar);
372 }
373
374 /* sIP, dIP, nhIP, sPort, dPort */
375 rwRecMemSetSIPv4(rwrec, &ar[0]);
376 rwRecMemSetDIPv4(rwrec, &ar[4]);
377 rwRecMemSetNhIPv4(rwrec, &ar[8]);
378 rwRecMemSetSPort(rwrec, &ar[12]);
379 rwRecMemSetDPort(rwrec, &ar[14]);
380
381 /* pkts, elapsed, sTime, bytes, bpp */
382 rwpackUnpackSbbPef(rwrec, stream->hdr_starttime,
383 (uint32_t*)&ar[20], (uint32_t*)&ar[16]);
384
385 /* proto, flags, input&output interfaces */
386 rwRecSetProto(rwrec, ar[24]);
387 rwRecSetFlags(rwrec, ar[25]);
388 rwRecSetInput(rwrec, ar[26]);
389 rwRecSetOutput(rwrec, ar[27]);
390
391 /* sensor, flow_type from file name/header */
392 rwRecSetSensor(rwrec, stream->hdr_sensor);
393 rwRecSetFlowType(rwrec, stream->hdr_flowtype);
394
395 return SKSTREAM_OK;
396 }
397
398
399 /*
400 * Pack the record 'rwrec' into an array of bytes 'ar'
401 */
402 static int
routedioRecordPack_V1(skstream_t * stream,const rwGenericRec_V5 * rwrec,uint8_t * ar)403 routedioRecordPack_V1(
404 skstream_t *stream,
405 const rwGenericRec_V5 *rwrec,
406 uint8_t *ar)
407 {
408 int rv = SKSTREAM_OK; /* return value */
409
410 /* Check sizes of fields we've expanded in later versions */
411 if (rwRecGetInput(rwrec) > 255 || rwRecGetOutput(rwrec) > 255) {
412 return SKSTREAM_ERR_SNMP_OVRFLO;
413 }
414
415 /* pkts, elapsed, sTime, bytes, bpp */
416 rv = rwpackPackSbbPef((uint32_t*)&ar[20], (uint32_t*)&ar[16],
417 rwrec, stream->hdr_starttime);
418 if (rv) {
419 return rv;
420 }
421
422 /* sIP, dIP, nhIP, sPort, dPort */
423 rwRecMemGetSIPv4(rwrec, &ar[0]);
424 rwRecMemGetDIPv4(rwrec, &ar[4]);
425 rwRecMemGetNhIPv4(rwrec, &ar[8]);
426 rwRecMemGetSPort(rwrec, &ar[12]);
427 rwRecMemGetDPort(rwrec, &ar[14]);
428
429 /* proto, flags, input interface, output interface */
430 ar[24] = rwRecGetProto(rwrec);
431 ar[25] = rwRecGetFlags(rwrec);
432 ar[26] = (uint8_t)rwRecGetInput(rwrec);
433 ar[27] = (uint8_t)rwRecGetOutput(rwrec);
434
435 /* swap if required */
436 if (stream->swapFlag) {
437 routedioRecordSwap_V1(ar);
438 }
439
440 return SKSTREAM_OK;
441 }
442
443
444 /* ********************************************************************* */
445
446 /*
447 * Return length of record of specified version, or 0 if no such
448 * version exists. See skstream_priv.h for details.
449 */
450 uint16_t
routedioGetRecLen(sk_file_version_t vers)451 routedioGetRecLen(
452 sk_file_version_t vers)
453 {
454 switch (vers) {
455 case 1:
456 return RECLEN_RWROUTED_V1;
457 case 2:
458 return RECLEN_RWROUTED_V2;
459 case 3:
460 return RECLEN_RWROUTED_V3;
461 case 4:
462 return RECLEN_RWROUTED_V4;
463 case 5:
464 return RECLEN_RWROUTED_V5;
465 default:
466 return 0;
467 }
468 }
469
470
471 /*
472 * status = routedioPrepare(&stream);
473 *
474 * Sets the record version to the default if it is unspecified,
475 * checks that the record format supports the requested record
476 * version, sets the record length, and sets the pack and unpack
477 * functions for this record format and version.
478 */
479 int
routedioPrepare(skstream_t * stream)480 routedioPrepare(
481 skstream_t *stream)
482 {
483 #define FILE_FORMAT "FT_RWROUTED"
484 sk_file_header_t *hdr = stream->silk_hdr;
485 int rv = SKSTREAM_OK; /* return value */
486
487 assert(skHeaderGetFileFormat(hdr) == FT_RWROUTED);
488
489 /* Set version if none was selected by caller */
490 if ((stream->io_mode == SK_IO_WRITE)
491 && (skHeaderGetRecordVersion(hdr) == SK_RECORD_VERSION_ANY))
492 {
493 skHeaderSetRecordVersion(hdr, DEFAULT_RECORD_VERSION);
494 }
495
496 /* version check; set values based on version */
497 switch (skHeaderGetRecordVersion(hdr)) {
498 case 5:
499 stream->rwUnpackFn = &routedioRecordUnpack_V5;
500 stream->rwPackFn = &routedioRecordPack_V5;
501 break;
502 case 4:
503 case 3:
504 /* V3 and V4 differ only in that V4 supports compression on
505 * read and write; V3 supports compression only on read */
506 stream->rwUnpackFn = &routedioRecordUnpack_V3;
507 stream->rwPackFn = &routedioRecordPack_V3;
508 break;
509 case 2:
510 case 1:
511 /* V1 and V2 differ only in the padding of the header */
512 stream->rwUnpackFn = &routedioRecordUnpack_V1;
513 stream->rwPackFn = &routedioRecordPack_V1;
514 break;
515 case 0:
516 default:
517 rv = SKSTREAM_ERR_UNSUPPORT_VERSION;
518 goto END;
519 }
520
521 stream->recLen = routedioGetRecLen(skHeaderGetRecordVersion(hdr));
522
523 /* verify lengths */
524 if (stream->recLen == 0) {
525 skAppPrintErr("Record length not set for %s version %u",
526 FILE_FORMAT, (unsigned)skHeaderGetRecordVersion(hdr));
527 skAbort();
528 }
529 if (stream->recLen != skHeaderGetRecordLength(hdr)) {
530 if (0 == skHeaderGetRecordLength(hdr)) {
531 skHeaderSetRecordLength(hdr, stream->recLen);
532 } else {
533 skAppPrintErr(("Record length mismatch for %s version %u\n"
534 "\tcode = %" PRIu16 " bytes; header = %lu bytes"),
535 FILE_FORMAT, (unsigned)skHeaderGetRecordVersion(hdr),
536 stream->recLen,
537 (unsigned long)skHeaderGetRecordLength(hdr));
538 skAbort();
539 }
540 }
541
542 END:
543 return rv;
544 }
545
546
547 /*
548 ** Local Variables:
549 ** mode:c
550 ** indent-tabs-mode:nil
551 ** c-basic-offset:4
552 ** End:
553 */
554