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