1 /*
2 ** Copyright (C) 2004-2020 by Carnegie Mellon University.
3 **
4 ** @OPENSOURCE_LICENSE_START@
5 ** See license information in ../../LICENSE.txt
6 ** @OPENSOURCE_LICENSE_END@
7 */
8 
9 #include <silk/silk.h>
10 
11 RCSIDENT("$SiLK: flowcapio.c ef14e54179be 2020-04-14 21:57:45Z mthomas $");
12 
13 #include "skstream_priv.h"
14 
15 /*
16 **  Converts FLOWCAP records to RWGENERIC records
17 **
18 */
19 
20 
21 /* Version to use when SK_RECORD_VERSION_ANY is specified */
22 #define DEFAULT_RECORD_VERSION 5
23 
24 
25 /* LOCAL FUNCTION PROTOTYPES */
26 
27 static int
28 flowcapioRecordUnpack_V5(
29     skstream_t         *stream,
30     rwGenericRec_V5    *rwrec,
31     uint8_t            *ar);
32 static int
33 flowcapioRecordUnpack_V3(
34     skstream_t         *stream,
35     rwGenericRec_V5    *rwrec,
36     uint8_t            *ar);
37 static int
38 flowcapioRecordPack_V3(
39     skstream_t             *stream,
40     const rwGenericRec_V5  *rwrec,
41     uint8_t                *ar);
42 
43 
44 
45 /* ********************************************************************* */
46 
47 /*
48 **  FLOWCAP VERSION 6
49 **
50 **    Flowcap version 6 is identical to V5, expect must clear the
51 **    application field when unpacking.  Packing functions for V5 and
52 **    V6 are identical.
53 */
54 
55 static int
flowcapioRecordUnpack_V6(skstream_t * stream,rwGenericRec_V5 * rwrec,uint8_t * ar)56 flowcapioRecordUnpack_V6(
57     skstream_t         *stream,
58     rwGenericRec_V5    *rwrec,
59     uint8_t            *ar)
60 {
61     int rv;
62 
63     rv = flowcapioRecordUnpack_V5(stream, rwrec, ar);
64     rwRecSetApplication(rwrec, 0);
65     return rv;
66 }
67 
68 
69 /* ********************************************************************* */
70 
71 /*
72 **  FLOWCAP VERSION 5
73 **
74 **  in the following: EXPANDED == ((tcp_state & SK_TCPSTATE_EXPANDED) ? 1 : 0)
75 **
76 **    uint32_t      sIP;             //  0- 3  Source IP
77 **    uint32_t      dIP;             //  4- 7  Destination IP
78 **
79 **    uint32_t      bytes;           //  8-11  Byte count
80 **
81 **    uint32_t      sTime;           // 12-15  Start time as UNIX epoch secs
82 **
83 **    uint16_t      elapsed;         // 16-17  Duration of flow in seconds
84 **    uint16_t      sPort;           // 18-19  Source port
85 **
86 **    uint16_t      dPort;           // 20-21  Destination port
87 **    uint16_t      service_port;    // 22-23  Port reported by flow collector
88 **
89 **    uint16_t      input;           // 24-25  SNMP Input
90 **    uint16_t      output;          // 26-27  SNMP Output
91 **
92 **    uint8_t       pkts[3]          // 28-30  Count of packets
93 **    uint8_t       proto            // 31     Protocol
94 **
95 **    uint8_t       flags            // 32     EXPANDED==0: All TCP Flags
96 **                                   //        EXPANDED==1: Flags !1st pkt
97 **    uint8_t       first_flags;     // 33     EXPANDED==0: 0
98 **                                   //        EXPANDED==1: TCP Flags 1st pkt
99 **    uint8_t       tcp_state;       // 34     TCP state machine info
100 **    uint8_t       time_frac[3];    // 35-37  sTime msec & elapsed msec
101 **
102 **
103 **  38 bytes on disk.
104 */
105 
106 #define RECLEN_FLOWCAP_V5 38
107 
108 
109 /*
110  *    Byte swap the FLOWCAP v5 record 'ar' in place.
111  */
112 #define flowcapioRecordSwap_V5(ar)                                      \
113     {                                                                   \
114         uint8_t swap_tmp;                                               \
115                                                                         \
116         SWAP_DATA32((ar) +  0);   /* sIP */                             \
117         SWAP_DATA32((ar) +  4);   /* dIP */                             \
118         SWAP_DATA32((ar) +  8);   /* bytes */                           \
119         SWAP_DATA32((ar) + 12);   /* sTime */                           \
120         SWAP_DATA16((ar) + 16);   /* dur */                             \
121         SWAP_DATA16((ar) + 18);   /* sPort */                           \
122         SWAP_DATA16((ar) + 20);   /* dPort */                           \
123         SWAP_DATA16((ar) + 22);   /* service_port */                    \
124         SWAP_DATA16((ar) + 24);   /* input */                           \
125         SWAP_DATA16((ar) + 26);   /* output */                          \
126                                                                         \
127         swap_tmp = ar[28];        /* packets */                         \
128         ar[28] = ar[30];                                                \
129         ar[30] = swap_tmp;                                              \
130                                                                         \
131         /* four bytes: proto(31), flags(32), first_flags(33) tcp_state(34) */ \
132         /* three bytes in hand-encoded time_frac[3] */                  \
133     }
134 
135 
136 /*
137  *  Unpack the array of bytes 'ar' into a record 'rwrec'
138  */
139 static int
flowcapioRecordUnpack_V5(skstream_t * stream,rwGenericRec_V5 * rwrec,uint8_t * ar)140 flowcapioRecordUnpack_V5(
141     skstream_t         *stream,
142     rwGenericRec_V5    *rwrec,
143     uint8_t            *ar)
144 {
145     uint32_t tmp32 = 0;
146     uint16_t elapsed = 0;
147 
148     /* swap if required */
149     if (stream->swapFlag) {
150         flowcapioRecordSwap_V5(ar);
151     }
152 
153     /* sIP, dIP, bytes */
154     rwRecMemSetSIPv4(rwrec, &ar[0]);
155     rwRecMemSetDIPv4(rwrec, &ar[4]);
156     rwRecMemSetBytes(rwrec, &ar[8]);
157 
158     /* sTime seconds, plus fractional seconds in bytes 35,36 */
159     memcpy(&tmp32, &ar[12], sizeof(tmp32));
160     rwRecSetStartTime(rwrec, sktimeCreate(tmp32,
161                                           ((ar[35] << 2)
162                                            |GET_MASKED_BITS(ar[36], 6, 2))));
163 
164     /* elapsed seconds, plus fractional seconds in bytes 36,37 */
165     memcpy(&elapsed, &ar[16], sizeof(elapsed));
166     rwRecSetElapsed(rwrec, (((uint32_t)1000 * elapsed)
167                             + ((GET_MASKED_BITS(ar[36], 0, 6) << 4)
168                                | GET_MASKED_BITS(ar[37], 4, 4))));
169 
170     /* sPort, dPort, application, input, output */
171     rwRecMemSetSPort(rwrec, &ar[18]);
172     rwRecMemSetDPort(rwrec, &ar[20]);
173     rwRecMemSetApplication(rwrec, &ar[22]);
174     rwRecMemSetInput(rwrec, &ar[24]);
175     rwRecMemSetOutput(rwrec, &ar[26]);
176 
177     /* packets, protocol */
178     tmp32 = 0;
179 #if SK_LITTLE_ENDIAN
180     memcpy(&tmp32, &ar[28], 3);
181 #else
182     memcpy((((uint8_t*)&tmp32) + 1), &ar[28], 3);
183 #endif
184     rwRecSetPkts(rwrec, tmp32);
185     rwRecSetProto(rwrec, ar[31]);
186 
187     /* Flags, Initial flags, TCP State */
188     rwRecSetTcpState(rwrec, ar[34]);
189     if (ar[34] & SK_TCPSTATE_EXPANDED) {
190         /* have separate initial and session flags */
191         rwRecSetFlags(rwrec, (ar[32] | ar[33]));
192         rwRecSetRestFlags(rwrec, ar[32]);
193         rwRecSetInitFlags(rwrec, ar[33]);
194     } else {
195         /* have a single flags field */
196         rwRecSetFlags(rwrec, ar[32]);
197     }
198 
199     /* Fractional times in bytes 35-37 handled above */
200 
201     /* Get sensor from header */
202     rwRecSetSensor(rwrec, stream->hdr_sensor);
203 
204     return SKSTREAM_OK;
205 }
206 
207 
208 /*
209  *  Pack the record 'rwrec' into an array of bytes 'ar'
210  */
211 static int
flowcapioRecordPack_V5(skstream_t * stream,const rwGenericRec_V5 * rwrec,uint8_t * ar)212 flowcapioRecordPack_V5(
213     skstream_t             *stream,
214     const rwGenericRec_V5  *rwrec,
215     uint8_t                *ar)
216 {
217     uint32_t tmp32;
218     uint16_t elapsed;
219 
220     /* sIP, dIP, bytes, sTime */
221     rwRecMemGetSIPv4(rwrec, &ar[0]);
222     rwRecMemGetDIPv4(rwrec, &ar[4]);
223     rwRecMemGetBytes(rwrec, &ar[8]);
224     rwRecMemGetStartSeconds(rwrec, &ar[12]);
225 
226     /* elapsed */
227     if (rwRecGetElapsedSeconds(rwrec) > UINT16_MAX) {
228         memset(&ar[16], 0xFF, sizeof(elapsed));
229     } else {
230         elapsed = (uint16_t)rwRecGetElapsedSeconds(rwrec);
231         memcpy(&ar[16], &elapsed, sizeof(elapsed));
232     }
233 
234     /* sPort, dPort, application, input, output */
235     rwRecMemGetSPort(rwrec, &ar[18]);
236     rwRecMemGetDPort(rwrec, &ar[20]);
237     rwRecMemGetApplication(rwrec, &ar[22]);
238     rwRecMemGetInput(rwrec, &ar[24]);
239     rwRecMemGetOutput(rwrec, &ar[26]);
240 
241     /* packets, protocol */
242     tmp32 = rwRecGetPkts(rwrec);
243     if (tmp32 > 0xFFFFFF) {
244         memset(&ar[28], 0xFF, 3);
245     } else {
246 #if SK_LITTLE_ENDIAN
247         memcpy(&ar[28], &tmp32, 3);
248 #else
249         memcpy(&ar[28], (((uint8_t*)&tmp32) + 1), 3);
250 #endif
251     }
252     ar[31] = rwRecGetProto(rwrec);
253 
254     /* Flags, Initial flags, TCP State */
255     ar[34] = rwRecGetTcpState(rwrec);
256     if (ar[34] & SK_TCPSTATE_EXPANDED) {
257         /* have separate initial and rest flags */
258         ar[32] = rwRecGetRestFlags(rwrec);
259         ar[33] = rwRecGetInitFlags(rwrec);
260     } else {
261         /* have a single flags field */
262         ar[32] = rwRecGetFlags(rwrec);
263         ar[33] = 0;
264     }
265 
266     /* Fractional time encoding: by hand, always big endian */
267     ar[35] = 0xFF & (rwRecGetStartMSec(rwrec) >> 2);
268     SET_MASKED_BITS(ar[36], rwRecGetStartMSec(rwrec), 6, 2);
269     SET_MASKED_BITS(ar[36], rwRecGetElapsedMSec(rwrec) >> 4, 0, 6);
270     ar[37] = 0xFF & (rwRecGetElapsedMSec(rwrec) << 4);
271 
272     /* swap if required */
273     if (stream->swapFlag) {
274         flowcapioRecordSwap_V5(ar);
275     }
276 
277     return SKSTREAM_OK;
278 }
279 
280 
281 /* ********************************************************************* */
282 
283 /*
284 **  FLOWCAP VERSION 4
285 **
286 **  in the following: EXPANDED == ((tcp_state & SK_TCPSTATE_EXPANDED) ? 1 : 0)
287 **
288 **    uint32_t      sIP;             //  0- 3  Source IP
289 **    uint32_t      dIP;             //  4- 7  Destination IP
290 **
291 **    uint32_t      bytes;           //  8-11  Byte count
292 **
293 **    uint32_t      sTime;           // 12-15  Start time as UNIX epoch secs
294 **
295 **    uint16_t      elapsed;         // 16-17  Duration of flow in seconds
296 **    uint16_t      sPort;           // 18-19  Source port
297 **
298 **    uint16_t      dPort;           // 20-21  Destination port
299 **    uint16_t      service_port;    // 22-23  Port reported by flow collector
300 **
301 **    uint8_t       input;           // 24     SNMP Input
302 **    uint8_t       output;          // 25     SNMP Output
303 **
304 **    uint8_t       pkts[3]          // 26-28  Count of packets
305 **    uint8_t       proto            // 29     Protocol
306 **
307 **    uint8_t       flags            // 30     EXPANDED==0: All TCP Flags
308 **                                   //        EXPANDED==1: Flags !1st pkt
309 **    uint8_t       first_flags;     // 31     EXPANDED==0: 0
310 **                                   //        EXPANDED==1: TCP Flags 1st pkt
311 **    uint8_t       tcp_state;       // 32     TCP state machine info
312 **    uint8_t       time_frac[3];    // 33-35  sTime msec & elapsed msec
313 **
314 **    uint32_t      payload_hash;    // 36-39  Hash of packet's payload
315 **
316 **
317 **  40 bytes on disk.
318 */
319 
320 #define RECLEN_FLOWCAP_V4 40
321 
322 
323 /*
324  *  Unpack the array of bytes 'ar' into a record 'rwrec'
325  */
326 static int
flowcapioRecordUnpack_V4(skstream_t * stream,rwGenericRec_V5 * rwrec,uint8_t * ar)327 flowcapioRecordUnpack_V4(
328     skstream_t         *stream,
329     rwGenericRec_V5    *rwrec,
330     uint8_t            *ar)
331 {
332     int rv;
333 
334     /* The first 36 bytes of a V4 are identical to V3 */
335     rv = flowcapioRecordUnpack_V3(stream, rwrec, ar);
336 
337     /* swap if required */
338     if (stream->swapFlag) {
339         /* only need to swap the payload hash */
340         SWAP_DATA32((ar) + 36);
341     }
342 
343     /* Put the payload hash into the nhIP */
344     if (rv == SKSTREAM_OK) {
345         rwRecMemSetNhIPv4(rwrec, &ar[36]);
346     }
347 
348     return rv;
349 }
350 
351 
352 /*
353  *  Pack the record 'rwrec' into an array of bytes 'ar'
354  */
355 static int
flowcapioRecordPack_V4(skstream_t * stream,const rwGenericRec_V5 * rwrec,uint8_t * ar)356 flowcapioRecordPack_V4(
357     skstream_t             *stream,
358     const rwGenericRec_V5  *rwrec,
359     uint8_t                *ar)
360 {
361     int rv;
362 
363     /* The first 36 bytes of a V4 are identical to V3 */
364     rv = flowcapioRecordPack_V3(stream, rwrec, ar);
365 
366     if (rv == SKSTREAM_OK) {
367         rwRecMemGetNhIPv4(rwrec, &ar[36]);
368     }
369 
370     /* swap if required */
371     if (stream->swapFlag) {
372         /* only need to swap the payload hash */
373         SWAP_DATA32((ar) + 36);
374     }
375 
376     return rv;
377 }
378 
379 
380 /* ********************************************************************* */
381 
382 /*
383 **  FLOWCAP VERSION 3
384 **
385 **  in the following: EXPANDED == ((tcp_state & SK_TCPSTATE_EXPANDED) ? 1 : 0)
386 **
387 **    uint32_t      sIP;             //  0- 3  Source IP
388 **    uint32_t      dIP;             //  4- 7  Destination IP
389 **
390 **    uint32_t      bytes;           //  8-11  Byte count
391 **
392 **    uint32_t      sTime;           // 12-15  Start time as UNIX epoch secs
393 **
394 **    uint16_t      elapsed;         // 16-17  Duration of flow in seconds
395 **    uint16_t      sPort;           // 18-19  Source port
396 **
397 **    uint16_t      dPort;           // 20-21  Destination port
398 **    uint16_t      service_port;    // 22-23  Port reported by flow collector
399 **
400 **    uint8_t       input;           // 24     SNMP Input
401 **    uint8_t       output;          // 25     SNMP Output
402 **
403 **    uint8_t       pkts[3]          // 26-28  Count of packets
404 **    uint8_t       proto            // 29     Protocol
405 **
406 **    uint8_t       flags            // 30     EXPANDED==0: All TCP Flags
407 **                                   //        EXPANDED==1: Flags !1st pkt
408 **    uint8_t       first_flags;     // 31     EXPANDED==0: 0
409 **                                   //        EXPANDED==1: TCP Flags 1st pkt
410 **    uint8_t       tcp_state;       // 32     TCP state machine info
411 **    uint8_t       time_frac[3];    // 33-35  sTime msec & elapsed msec
412 **
413 **
414 **  36 bytes on disk.
415 */
416 
417 #define RECLEN_FLOWCAP_V3 36
418 
419 
420 /*
421  *    Byte swap the FLOWCAP v3 record 'ar' in place.
422  */
423 #define flowcapioRecordSwap_V3(ar)                                      \
424     {                                                                   \
425         uint8_t swap_tmp;                                               \
426                                                                         \
427         SWAP_DATA32((ar) +  0);   /* sIP */                             \
428         SWAP_DATA32((ar) +  4);   /* dIP */                             \
429         SWAP_DATA32((ar) +  8);   /* bytes */                           \
430         SWAP_DATA32((ar) + 12);   /* sTime */                           \
431         SWAP_DATA16((ar) + 16);   /* dur */                             \
432         SWAP_DATA16((ar) + 18);   /* sPort */                           \
433         SWAP_DATA16((ar) + 20);   /* dPort */                           \
434         SWAP_DATA16((ar) + 22);   /* service_port */                    \
435         /* Two single byte values: input(24), output(25) */             \
436                                                                         \
437         swap_tmp = ar[26];        /* packets */                         \
438         ar[26] = ar[28];                                                \
439         ar[28] = swap_tmp;                                              \
440                                                                         \
441         /* four bytes: proto(29), flags(30), first_flags(31) tcp_state(32) */ \
442         /* three bytes in hand-encoded time_frac[3] */                  \
443     }
444 
445 
446 /*
447  *  Unpack the array of bytes 'ar' into a record 'rwrec'
448  */
449 static int
flowcapioRecordUnpack_V3(skstream_t * stream,rwGenericRec_V5 * rwrec,uint8_t * ar)450 flowcapioRecordUnpack_V3(
451     skstream_t         *stream,
452     rwGenericRec_V5    *rwrec,
453     uint8_t            *ar)
454 {
455     uint32_t tmp32 = 0;
456     uint16_t elapsed = 0;
457 
458     /* swap if required */
459     if (stream->swapFlag) {
460         flowcapioRecordSwap_V3(ar);
461     }
462 
463     /* sIP, dIP, bytes */
464     rwRecMemSetSIPv4(rwrec, &ar[0]);
465     rwRecMemSetDIPv4(rwrec, &ar[4]);
466     rwRecMemSetBytes(rwrec, &ar[8]);
467 
468     /* sTime seconds, plus fractional seconds in bytes 33,34 */
469     memcpy(&tmp32, &ar[12], sizeof(tmp32));
470     rwRecSetStartTime(rwrec, sktimeCreate(tmp32,
471                                           ((ar[33] << 2)
472                                            |GET_MASKED_BITS(ar[34], 6, 2))));
473 
474     /* elapsed seconds, plus fractional seconds in bytes 34,35 */
475     memcpy(&elapsed, &ar[16], sizeof(elapsed));
476     rwRecSetElapsed(rwrec, (((uint32_t)1000 * elapsed)
477                             + ((GET_MASKED_BITS(ar[34], 0, 6) << 4)
478                                | GET_MASKED_BITS(ar[35], 4, 4))));
479 
480     /* sPort, dPort, application */
481     rwRecMemSetSPort(rwrec, &ar[18]);
482     rwRecMemSetDPort(rwrec, &ar[20]);
483     rwRecMemSetApplication(rwrec, &ar[22]);
484 
485     /* input, output are single byte values */
486     rwRecSetInput(rwrec, ar[24]);
487     rwRecSetOutput(rwrec, ar[25]);
488 
489     /* packets, protocol */
490     tmp32 = 0;
491 #if SK_LITTLE_ENDIAN
492     memcpy(&tmp32, &ar[26], 3);
493 #else
494     memcpy((((uint8_t*)&tmp32) + 1), &ar[26], 3);
495 #endif
496     rwRecSetPkts(rwrec, tmp32);
497     rwRecSetProto(rwrec, ar[29]);
498 
499     /* Flags, Initial flags, TCP State */
500     rwRecSetTcpState(rwrec, ar[32]);
501     if (ar[32] & SK_TCPSTATE_EXPANDED) {
502         /* have separate initial and session flags */
503         rwRecSetFlags(rwrec, (ar[30] | ar[31]));
504         rwRecSetRestFlags(rwrec, ar[30]);
505         rwRecSetInitFlags(rwrec, ar[31]);
506     } else {
507         /* have a single flags field */
508         rwRecSetFlags(rwrec, ar[30]);
509     }
510 
511     /* Fractional times in bytes 33-35 handled above */
512 
513     /* Get sensor from header */
514     rwRecSetSensor(rwrec, stream->hdr_sensor);
515 
516     return SKSTREAM_OK;
517 }
518 
519 
520 /*
521  *  Pack the record 'rwrec' into an array of bytes 'ar'
522  */
523 static int
flowcapioRecordPack_V3(skstream_t * stream,const rwGenericRec_V5 * rwrec,uint8_t * ar)524 flowcapioRecordPack_V3(
525     skstream_t             *stream,
526     const rwGenericRec_V5  *rwrec,
527     uint8_t                *ar)
528 {
529     uint32_t tmp32;
530     uint16_t elapsed;
531 
532     /* sIP, dIP, bytes, sTime */
533     rwRecMemGetSIPv4(rwrec, &ar[0]);
534     rwRecMemGetDIPv4(rwrec, &ar[4]);
535     rwRecMemGetBytes(rwrec, &ar[8]);
536     rwRecMemGetStartSeconds(rwrec, &ar[12]);
537 
538     /* elapsed */
539     if (rwRecGetElapsedSeconds(rwrec) > UINT16_MAX) {
540         memset(&ar[16], 0xFF, sizeof(elapsed));
541     } else {
542         elapsed = (uint16_t)rwRecGetElapsedSeconds(rwrec);
543         memcpy(&ar[16], &elapsed, sizeof(elapsed));
544     }
545 
546     /* sPort, dPort, application */
547     rwRecMemGetSPort(rwrec, &ar[18]);
548     rwRecMemGetDPort(rwrec, &ar[20]);
549     rwRecMemGetApplication(rwrec, &ar[22]);
550 
551     /* input, output are single byte values */
552     ar[24] = 0xFF & rwRecGetInput(rwrec);
553     ar[25] = 0xFF & rwRecGetOutput(rwrec);
554 
555     /* packets, protocol */
556     tmp32 = rwRecGetPkts(rwrec);
557     if (tmp32 > 0xFFFFFF) {
558         memset(&ar[26], 0xFF, 3);
559     } else {
560 #if SK_LITTLE_ENDIAN
561         memcpy(&ar[26], &tmp32, 3);
562 #else
563         memcpy(&ar[26], (((uint8_t*)&tmp32) + 1), 3);
564 #endif
565     }
566     ar[29] = rwRecGetProto(rwrec);
567 
568     /* Flags, Initial flags, TCP State */
569     ar[32] = rwRecGetTcpState(rwrec);
570     if (ar[32] & SK_TCPSTATE_EXPANDED) {
571         /* have separate initial and rest flags */
572         ar[30] = rwRecGetRestFlags(rwrec);
573         ar[31] = rwRecGetInitFlags(rwrec);
574     } else {
575         /* have a single flags field */
576         ar[30] = rwRecGetFlags(rwrec);
577         ar[31] = 0;
578     }
579 
580     /* Fractional time encoding: by hand, always big endian */
581     ar[33] = 0xFF & (rwRecGetStartMSec(rwrec) >> 2);
582     SET_MASKED_BITS(ar[34], rwRecGetStartMSec(rwrec), 6, 2);
583     SET_MASKED_BITS(ar[34], rwRecGetElapsedMSec(rwrec) >> 4, 0, 6);
584     ar[35] = 0xFF & (rwRecGetElapsedMSec(rwrec) << 4);
585 
586     /* swap if required */
587     if (stream->swapFlag) {
588         flowcapioRecordSwap_V3(ar);
589     }
590 
591     return SKSTREAM_OK;
592 }
593 
594 
595 
596 /* ********************************************************************* */
597 
598 /*
599 **  FLOWCAP VERSION 2
600 **
601 **    uint32_t      sIP;             //  0- 3  Source IP
602 **    uint32_t      dIP;             //  4- 7  Destination IP
603 **
604 **    uint32_t      bytes;           //  8-11  Byte count
605 **
606 **    uint32_t      sTime;           // 12-15  Start time as UNIX epoch secs
607 **
608 **    uint16_t      elapsed;         // 16-17  Duration of flow in seconds
609 **    uint16_t      sPort;           // 18-19  Source port
610 **
611 **    uint16_t      dPort;           // 20-21  Destination port
612 **    uint8_t       input;           // 22     SNMP Input
613 **    uint8_t       output;          // 23     SNMP Output
614 **
615 **    uint8_t       pkts[3]          // 24-26  Count of packets
616 **    uint8_t       proto            // 27     Protocol
617 **
618 **    uint8_t       flags            // 28     OR of TCP Flags on all pkts
619 **    uint8_t       first_flags;     // 29     TOS (ignored)
620 **
621 **
622 **  30 bytes on disk.
623 */
624 
625 #define RECLEN_FLOWCAP_V2 30
626 
627 
628 /*
629  *    Byte swap the FLOWCAP v2 record 'ar' in place.
630  */
631 #define flowcapioRecordSwap_V2(ar)                              \
632     {                                                           \
633         uint8_t swap_tmp;                                       \
634                                                                 \
635         SWAP_DATA32((ar) +  0);   /* sIP */                     \
636         SWAP_DATA32((ar) +  4);   /* dIP */                     \
637         SWAP_DATA32((ar) +  8);   /* bytes */                   \
638         SWAP_DATA32((ar) + 12);   /* sTime */                   \
639         SWAP_DATA16((ar) + 16);   /* dur */                     \
640         SWAP_DATA16((ar) + 18);   /* sPort */                   \
641         SWAP_DATA16((ar) + 20);   /* dPort */                   \
642         /* Two single byte values: input(22), output(23) */     \
643                                                                 \
644         swap_tmp = ar[24];        /* packets */                 \
645         ar[24] = ar[26];                                        \
646         ar[26] = swap_tmp;                                      \
647                                                                 \
648         /* three bytes: proto(27), flags(28), TOS(29) */        \
649     }
650 
651 
652 /*
653  *  Unpack the array of bytes 'ar' into a record 'rwrec'
654  */
655 static int
flowcapioRecordUnpack_V2(skstream_t * stream,rwGenericRec_V5 * rwrec,uint8_t * ar)656 flowcapioRecordUnpack_V2(
657     skstream_t         *stream,
658     rwGenericRec_V5    *rwrec,
659     uint8_t            *ar)
660 {
661     uint32_t tmp32 = 0;
662     uint16_t elapsed = 0;
663 
664     /* swap if required */
665     if (stream->swapFlag) {
666         flowcapioRecordSwap_V2(ar);
667     }
668 
669     /* sIP, dIP, bytes */
670     rwRecMemSetSIPv4(rwrec, &ar[0]);
671     rwRecMemSetDIPv4(rwrec, &ar[4]);
672     rwRecMemSetBytes(rwrec, &ar[8]);
673 
674     /* sTime */
675     memcpy(&tmp32, &ar[12], sizeof(tmp32));
676     rwRecSetStartTime(rwrec, sktimeCreate(tmp32, 0));
677 
678     /* elapsed */
679     memcpy(&elapsed, &ar[16], sizeof(elapsed));
680     rwRecSetElapsed(rwrec, ((uint32_t)1000 * elapsed));
681 
682     /* sPort, dPort */
683     rwRecMemSetSPort(rwrec, &ar[18]);
684     rwRecMemSetDPort(rwrec, &ar[20]);
685 
686     /* input, output are single byte values */
687     rwRecSetInput(rwrec, ar[22]);
688     rwRecSetOutput(rwrec, ar[23]);
689 
690     /* packets, protocol */
691     tmp32 = 0;
692 #if SK_LITTLE_ENDIAN
693     memcpy(&tmp32, &ar[24], 3);
694 #else
695     memcpy((((uint8_t*)&tmp32) + 1), &ar[24], 3);
696 #endif
697     rwRecSetPkts(rwrec, tmp32);
698     rwRecSetProto(rwrec, ar[27]);
699 
700     /* Flags */
701     rwRecSetFlags(rwrec, ar[28]);
702 
703     /* Get sensor from header */
704     rwRecSetSensor(rwrec, stream->hdr_sensor);
705 
706     return SKSTREAM_OK;
707 }
708 
709 
710 /*
711  *  Pack the record 'rwrec' into an array of bytes 'ar'
712  */
713 static int
flowcapioRecordPack_V2(skstream_t * stream,const rwGenericRec_V5 * rwrec,uint8_t * ar)714 flowcapioRecordPack_V2(
715     skstream_t             *stream,
716     const rwGenericRec_V5  *rwrec,
717     uint8_t                *ar)
718 {
719     uint32_t tmp32;
720     uint16_t elapsed;
721 
722     /* sIP, dIP, bytes, sTime */
723     rwRecMemGetSIPv4(rwrec, &ar[0]);
724     rwRecMemGetDIPv4(rwrec, &ar[4]);
725     rwRecMemGetBytes(rwrec, &ar[8]);
726     rwRecMemGetStartSeconds(rwrec, &ar[12]);
727 
728     /* elapsed */
729     if (rwRecGetElapsedSeconds(rwrec) > UINT16_MAX) {
730         memset(&ar[16], 0xFF, sizeof(elapsed));
731     } else {
732         elapsed = (uint16_t)rwRecGetElapsedSeconds(rwrec);
733         memcpy(&ar[16], &elapsed, sizeof(elapsed));
734     }
735 
736     /* sPort, dPort */
737     rwRecMemGetSPort(rwrec, &ar[18]);
738     rwRecMemGetDPort(rwrec, &ar[20]);
739 
740     /* input, output are single byte values */
741     ar[22] = 0xFF & rwRecGetInput(rwrec);
742     ar[23] = 0xFF & rwRecGetOutput(rwrec);
743 
744     /* packets, protocol */
745     tmp32 = rwRecGetPkts(rwrec);
746     if (tmp32 > 0xFFFFFF) {
747         memset(&ar[24], 0xFF, 3);
748     } else {
749 #if SK_LITTLE_ENDIAN
750         memcpy(&ar[24], &tmp32, 3);
751 #else
752         memcpy(&ar[24], (((uint8_t*)&tmp32) + 1), 3);
753 #endif
754     }
755     ar[27] = rwRecGetProto(rwrec);
756 
757     /* Flags, TOS */
758     ar[28] = rwRecGetFlags(rwrec);
759     ar[29] = 0;
760 
761     /* swap if required */
762     if (stream->swapFlag) {
763         flowcapioRecordSwap_V2(ar);
764     }
765 
766     return SKSTREAM_OK;
767 }
768 
769 
770 /* ********************************************************************* */
771 
772 /*
773  *  Return length of record of specified version, or 0 if no such
774  *  version exists.  See skstream_priv.h for details.
775  */
776 uint16_t
flowcapioGetRecLen(sk_file_version_t vers)777 flowcapioGetRecLen(
778     sk_file_version_t   vers)
779 {
780     switch (vers) {
781       case 2:
782         return RECLEN_FLOWCAP_V2;
783       case 3:
784         return RECLEN_FLOWCAP_V3;
785       case 4:
786         return RECLEN_FLOWCAP_V4;
787       case 5:
788       case 6:
789         return RECLEN_FLOWCAP_V5;
790       default:
791         return 0;
792     }
793 }
794 
795 
796 /*
797  *  status = flowcapioPrepare(&stream);
798  *
799  *    Sets the record version to the default if it is unspecified,
800  *    checks that the record format supports the requested record
801  *    version, sets the record length, and sets the pack and unpack
802  *    functions for this record format and version.
803  */
804 int
flowcapioPrepare(skstream_t * stream)805 flowcapioPrepare(
806     skstream_t         *stream)
807 {
808 #define FILE_FORMAT "FT_FLOWCAP"
809     sk_file_header_t *hdr = stream->silk_hdr;
810     int rv = SKSTREAM_OK; /* return value */
811 
812     assert(skHeaderGetFileFormat(hdr) == FT_FLOWCAP);
813 
814     /* Set version if none was selected by caller */
815     if ((stream->io_mode == SK_IO_WRITE)
816         && (skHeaderGetRecordVersion(hdr) == SK_RECORD_VERSION_ANY))
817     {
818         skHeaderSetRecordVersion(hdr, DEFAULT_RECORD_VERSION);
819     }
820 
821     /* version check; set values based on version */
822     switch (skHeaderGetRecordVersion(hdr)) {
823       case 6:
824         stream->rwUnpackFn = &flowcapioRecordUnpack_V6;
825         stream->rwPackFn   = &flowcapioRecordPack_V5;
826         break;
827       case 5:
828         stream->rwUnpackFn = &flowcapioRecordUnpack_V5;
829         stream->rwPackFn   = &flowcapioRecordPack_V5;
830         break;
831       case 4:
832         stream->rwUnpackFn = &flowcapioRecordUnpack_V4;
833         stream->rwPackFn   = &flowcapioRecordPack_V4;
834         break;
835       case 3:
836         stream->rwUnpackFn = &flowcapioRecordUnpack_V3;
837         stream->rwPackFn   = &flowcapioRecordPack_V3;
838         break;
839       case 2:
840         stream->rwUnpackFn = &flowcapioRecordUnpack_V2;
841         stream->rwPackFn   = &flowcapioRecordPack_V2;
842         break;
843       case 1:
844         /* no longer supported */
845       case 0:
846       default:
847         rv = SKSTREAM_ERR_UNSUPPORT_VERSION;
848         goto END;
849     }
850 
851     stream->recLen = flowcapioGetRecLen(skHeaderGetRecordVersion(hdr));
852 
853     /* verify lengths */
854     if (stream->recLen == 0) {
855         skAppPrintErr("Record length not set for %s version %u",
856                       FILE_FORMAT, (unsigned)skHeaderGetRecordVersion(hdr));
857         skAbort();
858     }
859     if (stream->recLen != skHeaderGetRecordLength(hdr)) {
860         if (0 == skHeaderGetRecordLength(hdr)) {
861             skHeaderSetRecordLength(hdr, stream->recLen);
862         } else {
863             skAppPrintErr(("Record length mismatch for %s version %u\n"
864                            "\tcode = %" PRIu16 " bytes;  header = %lu bytes"),
865                           FILE_FORMAT, (unsigned)skHeaderGetRecordVersion(hdr),
866                           stream->recLen,
867                           (unsigned long)skHeaderGetRecordLength(hdr));
868             skAbort();
869         }
870     }
871 
872   END:
873     return rv;
874 }
875 
876 
877 /*
878 ** Local Variables:
879 ** mode:c
880 ** indent-tabs-mode:nil
881 ** c-basic-offset:4
882 ** End:
883 */
884