/* ** Copyright (C) 2001-2006 by Carnegie Mellon University. ** ** @OPENSOURCE_HEADER_START@ ** ** Use of the SILK system and related source code is subject to the terms ** of the following licenses: ** ** GNU Public License (GPL) Rights pursuant to Version 2, June 1991 ** Government Purpose License Rights (GPLR) pursuant to DFARS 252.225-7013 ** ** NO WARRANTY ** ** ANY INFORMATION, MATERIALS, SERVICES, INTELLECTUAL PROPERTY OR OTHER ** PROPERTY OR RIGHTS GRANTED OR PROVIDED BY CARNEGIE MELLON UNIVERSITY ** PURSUANT TO THIS LICENSE (HEREINAFTER THE "DELIVERABLES") ARE ON AN ** "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY ** KIND, EITHER EXPRESS OR IMPLIED AS TO ANY MATTER INCLUDING, BUT NOT ** LIMITED TO, WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE, ** MERCHANTABILITY, INFORMATIONAL CONTENT, NONINFRINGEMENT, OR ERROR-FREE ** OPERATION. CARNEGIE MELLON UNIVERSITY SHALL NOT BE LIABLE FOR INDIRECT, ** SPECIAL OR CONSEQUENTIAL DAMAGES, SUCH AS LOSS OF PROFITS OR INABILITY ** TO USE SAID INTELLECTUAL PROPERTY, UNDER THIS LICENSE, REGARDLESS OF ** WHETHER SUCH PARTY WAS AWARE OF THE POSSIBILITY OF SUCH DAMAGES. ** LICENSEE AGREES THAT IT WILL NOT MAKE ANY WARRANTY ON BEHALF OF ** CARNEGIE MELLON UNIVERSITY, EXPRESS OR IMPLIED, TO ANY PERSON ** CONCERNING THE APPLICATION OF OR THE RESULTS TO BE OBTAINED WITH THE ** DELIVERABLES UNDER THIS LICENSE. ** ** Licensee hereby agrees to defend, indemnify, and hold harmless Carnegie ** Mellon University, its trustees, officers, employees, and agents from ** all claims or demands made against them (and any related losses, ** expenses, or attorney's fees) arising out of, or relating to Licensee's ** and/or its sub licensees' negligent use or willful misuse of or ** negligent conduct or willful misconduct regarding the Software, ** facilities, or other rights or assistance granted by Carnegie Mellon ** University under this License, including, but not limited to, any ** claims of product liability, personal injury, death, damage to ** property, or violation of any laws or regulations. ** ** Carnegie Mellon University Software Engineering Institute authored ** documents are sponsored by the U.S. Department of Defense under ** Contract F19628-00-C-0003. Carnegie Mellon University retains ** copyrights in all material produced under this contract. The U.S. ** Government retains a non-exclusive, royalty-free license to publish or ** reproduce these documents, or allow others to do so, for U.S. ** Government purposes only pursuant to the copyright license under the ** contract clause at 252.227.7013. ** ** @OPENSOURCE_HEADER_END@ */ /* ** rwgenericio.c ** ** Suresh L Konda ** routines to do io stuff with generic records. */ #include "silk.h" RCSIDENT("$SiLK: rwgenericio.c 5883 2006-12-08 21:54:58Z mthomas $"); #include "librw_priv.h" /* Version to use when SK_FILE_VERSION_ANY is specified */ #define DEFAULT_FILE_VERSION 4 /* * Version where data compression is enabled. We support full * compression as of this version. For files one version below this, * we only support reading compressed files---files created with * SiLK-0.10.0 through SiLK-0.10.4 */ #define COMPMETHOD_SUPPORTED 4 /* ********************************************************************* */ /* ** RWGENERIC VERSION 0 ** RWGENERIC VERSION 1 ** ** ipUnion sIP; // 0- 3 Source IP ** ipUnion dIP; // 4- 7 Destination IP ** ** uint16_t sPort; // 8- 9 Source port ** uint16_t dPort; // 10-11 Destination port ** ** uint8_t proto; // 12 IP protocol ** uint8_t flags; // 13 OR of all TCP flags on all pkts ** uint8_t input; // 14 Router incoming SNMP interface ** uint8_t output; // 15 Router outgoing SNMP interface ** ** ipUnion nhIP; // 16-19 Router Next Hop IP ** uint32_t sTime; // 20-23 Start time of flow-epoch secs ** uint32_t pkts; // 24-27 Count of packets ** uint32_t bytes; // 28-31 Count of bytes ** uint32_t elapsed; // 32-35 Duration of flow ** ** uint8_t sID; // 36 Sensor ID ** uint8_t padding[3]; // 37-39 Padding ** ** 40 bytes on disk with padding (VERSION 0) ** 37 bytes on disk without padding (VERSION 1) */ #define RECLEN_RWGENERIC_V0 40 #define RECLEN_RWGENERIC_V1 37 /* * Unpack the array of bytes 'ar' into a record 'rwRP' */ static int _genericioRecordUnpack_V1( rwIOStruct_t UNUSED(*rwIOS), rwGenericRec_V3 *rwRP, const uint8_t *ar) { /* sIP, dIP, sPort, dPort */ memcpy(&rwRP->sIP, &ar[0], 4); memcpy(&rwRP->dIP, &ar[4], 4); memcpy(&rwRP->sPort, &ar[8], 2); memcpy(&rwRP->dPort, &ar[10], 2); /* proto, flags, input, output */ rwRP->proto = ar[12]; rwRP->flags = ar[13]; rwRP->input = ar[14]; rwRP->output = ar[15]; /* nhIP */ memcpy(&rwRP->nhIP, &ar[16], 4); /* sTime, pkts, bytes, elapsed */ memcpy(&rwRP->sTime, &ar[20], 4); memcpy(&rwRP->pkts, &ar[24], 4); memcpy(&rwRP->bytes, &ar[28], 4); memcpy(&rwRP->elapsed, &ar[32], 4); /* sID */ rwRP->sID = ar[36]; /* everything else not in this format */ rwRP->flow_type = SK_INVALID_FLOWTYPE; return LIBRW_OK; } /* * Pack the record 'rwRP' into an array of bytes 'ar' */ static int _genericioRecordPack_V1( rwIOStruct_t UNUSED(*rwIOS), const rwGenericRec_V3 *rwRP, uint8_t *ar) { /* Check sizes of fields we've expanded in later versions */ if (rwRP->input > 255 || rwRP->output > 255) { return LIBRW_ERR_SNMP_OVRFLO; } /* Check sizes of fields we've expanded in later versions */ if (rwRP->sID > 255) { return LIBRW_ERR_SENSORID_OVRFLO; } /* sIP, dIP, sPort, dPort */ memcpy(&ar[0], &rwRP->sIP, 4); memcpy(&ar[4], &rwRP->dIP, 4); memcpy(&ar[8], &rwRP->sPort, 2); memcpy(&ar[10], &rwRP->dPort, 2); /* proto, flags, input, output */ ar[12] = rwRP->proto; ar[13] = rwRP->flags; ar[14] = (uint8_t)rwRP->input; ar[15] = (uint8_t)rwRP->output; /* nhIP */ memcpy(&ar[16], &rwRP->nhIP, 4); /* sTime, pkts, bytes, elapsed */ memcpy(&ar[20], &rwRP->sTime, 4); memcpy(&ar[24], &rwRP->pkts, 4); memcpy(&ar[28], &rwRP->bytes, 4); memcpy(&ar[32], &rwRP->elapsed, 4); /* sID */ ar[36] = (uint8_t)rwRP->sID; return LIBRW_OK; } /* * _genericioRecordSwap_V1(dataPtr); * * Treat dataPtr as an RWGENERIC_V1 record and byte-swap it in place. */ static void _genericioRecordSwap_V1(uint8_t *dataPtr) { SWAP_DATA32(dataPtr + 0); /* sIP */ SWAP_DATA32(dataPtr + 4); /* dIP */ SWAP_DATA16(dataPtr + 8); /* sPort */ SWAP_DATA16(dataPtr + 10); /* dPort */ /* Four single bytes: (12)proto, (13)flags, (14)input, (15)output */ SWAP_DATA32(dataPtr + 16); /* nhIP */ SWAP_DATA32(dataPtr + 20); /* sTime */ SWAP_DATA32(dataPtr + 24); /* pkts */ SWAP_DATA32(dataPtr + 28); /* bytes */ SWAP_DATA32(dataPtr + 32); /* elapsed */ /* One single bytes: (36)sensorId */ } /* ********************************************************************* */ /* ** RWGENERIC VERSION 2 ** ** ipUnion sIP; // 0- 3 Source IP ** ipUnion dIP; // 4- 7 Destination IP ** ** uint16_t sPort; // 8- 9 Source port ** uint16_t dPort; // 10-11 Destination port ** ** ipUnion nhIP; // 12-15 Router Next Hop IP ** uint16_t input; // 16-17 Router incoming SNMP interface ** uint16_t output; // 18-19 Router outgoing SNMP interface ** ** uint32_t sTime; // 20-23 Start time of flow-epoch secs ** uint32_t elapsed; // 24-27 Duration of flow ** ** uint32_t pkts; // 28-31 Count of packets ** uint32_t bytes; // 32-35 Count of bytes ** ** uint8_t proto; // 36 IP protocol ** uint8_t flow_type; // 37 Class & Type info ** sensorID_t sID; // 38-39 Sensor ID ** ** uint8_t flags; // 40 OR of all flags (Netflow flags) ** uint8_t init_flags; // 41 TCP flags in first packet ** // or blank for "legacy" data ** uint8_t rest_flags; // 42 TCP flags on non-initial packet ** // or blank for "legacy" data ** uint8_t tcp_state; // 43 TCP state machine information ** ** uint32_t bpp; // 44-47 Bytes-per-Packet ** ** ** 48 bytes on disk. */ #define RECLEN_RWGENERIC_V2 48 /* * Unpack the array of bytes 'ar' into a record 'rwRP' */ static int _genericioRecordUnpack_V2( rwIOStruct_t UNUSED(*rwIOS), rwGenericRec_V3 *rwRP, const uint8_t *ar) { /* V2 is like V3 except V3 has millisec times */ memcpy(&rwRP->sIP, &ar[0], RECLEN_RWGENERIC_V2); /* everything else not in this format */ rwRP->sTime_msec = 0; rwRP->elapsed_msec = 0; rwRP->application = 0; return LIBRW_OK; } /* * Pack the record 'rwRP' into an array of bytes 'ar' */ static int _genericioRecordPack_V2( rwIOStruct_t UNUSED(*rwIOS), const rwGenericRec_V3 *rwRP, uint8_t *ar) { /* sIP, dIP, sPort, dPort, nhIP, input, output */ #if 1 memcpy(&ar[0], &rwRP->sIP, 20); #else memcpy(&ar[0], &rwRP->sIP, 4); memcpy(&ar[4], &rwRP->dIP, 4); memcpy(&ar[8], &rwRP->sPort, 2); memcpy(&ar[10], &rwRP->dPort, 2); memcpy(&ar[12], &rwRP->nhIP, 4); memcpy(&ar[16], &rwRP->input, 2); memcpy(&ar[18], &rwRP->output, 2); #endif /* sTime, elapsed */ memcpy(&ar[20], &rwRP->sTime, 4); memcpy(&ar[24], &rwRP->elapsed, 4); /* pkts, bytes, proto, flow_type, sID, flags, init_flags, * rest_flags, tcp_state, bpp */ #if 1 memcpy(&ar[28], &rwRP->pkts, 20); #else memcpy(&ar[28], &rwRP->pkts, 4); memcpy(&ar[32], &rwRP->bytes, 4); memcpy(&ar[36], &rwRP->proto, 1); memcpy(&ar[37], &rwRP->flow_type, 1); memcpy(&ar[38], &rwRP->sID, 2); memcpy(&ar[40], &rwRP->flags, 1); memcpy(&ar[41], &rwRP->init_flags, 1); memcpy(&ar[42], &rwRP->rest_flags, 1); memcpy(&ar[43], &rwRP->tcp_state, 1); memcpy(&ar[44], &rwRP->bpp, 4); #endif return LIBRW_OK; } /* * _genericioRecordSwap_V2(dataPtr); * * Treat dataPtr as an RWGENERIC_V2 record and byte-swap it in place. */ static void _genericioRecordSwap_V2(uint8_t *dataPtr) { SWAP_DATA32(dataPtr + 0); /* sIP */ SWAP_DATA32(dataPtr + 4); /* dIP */ SWAP_DATA16(dataPtr + 8); /* sPort */ SWAP_DATA16(dataPtr + 10); /* dPort */ SWAP_DATA32(dataPtr + 12); /* nhIP */ SWAP_DATA16(dataPtr + 16); /* input */ SWAP_DATA16(dataPtr + 18); /* output */ SWAP_DATA32(dataPtr + 20); /* sTime */ SWAP_DATA32(dataPtr + 24); /* elapsed */ SWAP_DATA32(dataPtr + 28); /* pkts */ SWAP_DATA32(dataPtr + 32); /* bytes */ /* Two single bytes: (36)proto, (37)flow_type */ SWAP_DATA16(dataPtr + 38); /* sID */ /* Four single bytes: (40)flags, (41)init_flags, * (42)rest_flags, (43)tcp_state */ SWAP_DATA32(dataPtr + 44); /* bpp */ } /* ********************************************************************* */ /* ** RWGENERIC VERSION 3 ** RWGENERIC VERSION 4 ** ** ipUnion sIP; // 0- 3 Source IP ** ipUnion dIP; // 4- 7 Destination IP ** ** uint16_t sPort; // 8- 9 Source port ** uint16_t dPort; // 10-11 Destination port ** ** ipUnion nhIP; // 12-15 Router Next Hop IP ** uint16_t input; // 16-17 Router incoming SNMP interface ** uint16_t output; // 18-19 Router outgoing SNMP interface ** ** uint32_t sTime; // 20-23 Start time of flow-epoch secs ** uint32_t elapsed; // 24-27 Duration of flow ** ** uint32_t pkts; // 28-31 Count of packets ** uint32_t bytes; // 32-35 Count of bytes ** ** uint8_t proto; // 36 IP protocol ** uint8_t flow_type; // 37 Class & Type info ** sensorID_t sID; // 38-39 Sensor ID ** ** uint8_t flags; // 40 OR of all flags (Netflow flags) ** uint8_t init_flags; // 41 TCP flags in first packet ** // or blank for "legacy" data ** uint8_t rest_flags; // 42 TCP flags on non-initial packet ** // or blank for "legacy" data ** uint8_t tcp_state; // 43 TCP state machine information ** ** uint32_t bpp; // 44-47 Bytes-per-Packet ** ** uint16_t sTime_msec; // 48-49 Start time fraction (millisec) ** uint16_t elapsed_msec; // 50-51 Elapsed time fraction (millisec) ** ** uint16_t application; // 52-53 Type of traffic ** ** ** 54 bytes on disk. */ #define RECLEN_RWGENERIC_V3 sizeof(rwGenericRec_V3) #define RECLEN_RWGENERIC_V4 RECLEN_RWGENERIC_V3 /* * Unpack the array of bytes 'ar' into a record 'rwRP' */ static int _genericioRecordUnpack_V3( rwIOStruct_t UNUSED(*rwIOS), rwGenericRec_V3 *rwRP, const uint8_t *ar) { memcpy(rwRP, ar, RECLEN_RWGENERIC_V3); return LIBRW_OK; } /* * Pack the record 'rwRP' into an array of bytes 'ar' */ static int _genericioRecordPack_V3( rwIOStruct_t UNUSED(*rwIOS), const rwGenericRec_V3 *rwRP, uint8_t *ar) { memcpy(ar, rwRP, RECLEN_RWGENERIC_V3); return LIBRW_OK; } /* * _genericioRecordSwap_V3(dataPtr); * * Treat dataPtr as an RWGENERIC_V3 record and byte-swap it in place. */ static void _genericioRecordSwap_V3(uint8_t *dataPtr) { #if 0 SWAP_DATA32(dataPtr + 0); /* sIP */ SWAP_DATA32(dataPtr + 4); /* dIP */ SWAP_DATA16(dataPtr + 8); /* sPort */ SWAP_DATA16(dataPtr + 10); /* dPort */ SWAP_DATA32(dataPtr + 12); /* nhIP */ SWAP_DATA16(dataPtr + 16); /* input */ SWAP_DATA16(dataPtr + 18); /* output */ SWAP_DATA32(dataPtr + 20); /* sTime */ SWAP_DATA32(dataPtr + 24); /* elapsed */ SWAP_DATA32(dataPtr + 28); /* pkts */ SWAP_DATA32(dataPtr + 32); /* bytes */ /* Two single bytes: (36)proto, (37)flow_type */ SWAP_DATA16(dataPtr + 38); /* sID */ /* Four single bytes: (40)flags, (41)init_flags, * (42)rest_flags, (43)tcp_state */ SWAP_DATA32(dataPtr + 44); /* bpp */ SWAP_DATA16(dataPtr + 48); /* sTime_msec */ SWAP_DATA16(dataPtr + 50); /* elapsed_msec */ SWAP_DATA16(dataPtr + 52); /* application */ #else rwGenericRec_V3 *rwRP = (rwGenericRec_V3*)dataPtr; rwRP->sIP.ipnum = BSWAP32(rwRP->sIP.ipnum ); rwRP->dIP.ipnum = BSWAP32(rwRP->dIP.ipnum ); rwRP->sPort = BSWAP16(rwRP->sPort ); rwRP->dPort = BSWAP16(rwRP->dPort ); rwRP->nhIP.ipnum = BSWAP32(rwRP->nhIP.ipnum ); rwRP->input = BSWAP16(rwRP->input ); rwRP->output = BSWAP16(rwRP->output ); rwRP->sTime = BSWAP32(rwRP->sTime ); rwRP->elapsed = BSWAP32(rwRP->elapsed ); rwRP->pkts = BSWAP32(rwRP->pkts ); rwRP->bytes = BSWAP32(rwRP->bytes ); rwRP->sID = BSWAP16(rwRP->sID ); rwRP->bpp = BSWAP32(rwRP->bpp ); rwRP->sTime_msec = BSWAP16(rwRP->sTime_msec ); rwRP->elapsed_msec = BSWAP16(rwRP->elapsed_msec); rwRP->application = BSWAP16(rwRP->application ); #endif } /* ********************************************************************* */ /* * GENERIC HEADER * * Nothing in addition to the 'genericHeader'. */ /* * status = _genericioHeaderWrite(rwIOS, rwrec); * * Write the stream header pointed to in the rwIOS to the output * stream. The 'rwrec' argument is ignored. Returns 0 (LIBRW_OK) * on success, or non-zero on failure. * * Assumes the rwIOS and header have been correctly initialized. * * Do not use this function when appending to a file, otherwise a * header will appear in mid-stream. */ static int _genericioHeaderWrite( rwIOStruct_t *rwIOS, const rwRec UNUSED(*rwRP)) { int rv; /* write the genericHeader part of the header */ if (RWIO_WRITE(rwIOS, rwIOS->hdr, sizeof(genericHeader))) { rwIOS->errnum = errno; rv = LIBRW_ERR_WRITE; goto END; } /* Write the header padding */ rv = _ioHandleHeaderPadding(rwIOS); END: return rv; } static int _genericioHeaderRead( rwIOStruct_t *rwIOS) { /* we've already read the genericHeader, the only thing left is * the padding */ return _ioHandleHeaderPadding(rwIOS); } /* ********************************************************************* */ /* * Return length of record of specified version, or 0 if no such * version exists. See librw_priv.h for details. */ uint16_t _genericioGetRecLen(fileVersion_t vers) { switch (vers) { case 0: return RECLEN_RWGENERIC_V0; case 1: return RECLEN_RWGENERIC_V1; case 2: return RECLEN_RWGENERIC_V2; case 3: return RECLEN_RWGENERIC_V3; case 4: return RECLEN_RWGENERIC_V4; default: return 0; } } /* * status = _genericioSetFuncs(&rwIOSPtr); * * Checks that the file's version is allowed by this type, and sets * the record length and the read and write functions for this type. */ static int _genericioSetFuncs(rwIOStruct *rwIOS) { int rv = LIBRW_OK; /* return value */ assert(rwGetFileType(rwIOS) == FT_RWGENERIC); /* version check; set values based on version */ switch (rwGetFileVersion(rwIOS)) { case 0: case 1: /* Version 0 and Version 1 records are nearly the same; the * on-disk Version 0 records included the 3 bytes of in-core * padding; the on-disk Version 1 records do not include these * 3 bytes. */ rwIOS->hdrLen = sizeof(genericHeader); rwIOS->rwUnpackFn = &_genericioRecordUnpack_V1; rwIOS->rwPackFn = &_genericioRecordPack_V1; rwIOS->rwSwapFn = &_genericioRecordSwap_V1; rwIOS->writeHdrFn = &_genericioHeaderWrite; break; case 2: rwIOS->hdrLen = sizeof(genericHeader); rwIOS->rwUnpackFn = &_genericioRecordUnpack_V2; rwIOS->rwPackFn = &_genericioRecordPack_V2; rwIOS->rwSwapFn = &_genericioRecordSwap_V2; rwIOS->writeHdrFn = &_genericioHeaderWrite; break; case 3: case 4: /* V3 and V4 differ only in that V4 supports compression on * read and write; V3 supports compression only on read */ rwIOS->hdrLen = sizeof(genericHeader); rwIOS->rwUnpackFn = &_genericioRecordUnpack_V3; rwIOS->rwPackFn = &_genericioRecordPack_V3; rwIOS->rwSwapFn = &_genericioRecordSwap_V3; rwIOS->writeHdrFn = &_genericioHeaderWrite; break; default: rv = LIBRW_ERR_UNSUPPORT_VERSION; goto END; } /* check compression */ if ((rwGetFileVersion(rwIOS) < COMPMETHOD_SUPPORTED) && (rwGetFileCompMethod(rwIOS) != SK_COMPMETHOD_NONE)) { if ((rwGetFileVersion(rwIOS) < (COMPMETHOD_SUPPORTED-1)) || (rwIOS->io_mode != SK_RWIO_READ)) { rv = LIBRW_ERR_UNSUPPORT_COMPRESS; goto END; } } rwIOS->recLen = _genericioGetRecLen(rwGetFileVersion(rwIOS)); if ( rwIOS->recLen == 0) { skAppPrintErr("Record length not set for RWGENERIC version %u", (unsigned int)rwGetFileVersion(rwIOS)); assert(rwIOS->recLen > 0); abort(); } END: return rv; } /* * status = _genericioPrepareWrite(&rwIOS); * * Fills out the rwIOStruct and header for a brand new output stream: * it checks that the version is valid for this type of file, sets * record and header lengths, and it sets reading and memswapping * function pointers appropriately for the file's type and version. * * The writing function pointer is set so that the file's header will * be printed when the first record is output. * * Do not call this function when appending records to an existing * file. * * Returns LIBRW_OK on success; otherwise prints an error and returns * error code on failure: bad version. */ int _genericioPrepareWrite(rwIOStruct *rwIOS) { int rv; /* Set version if none was selected by caller */ if (rwGetFileVersion(rwIOS) == SK_FILE_VERSION_ANY) { ((genericHeader*)rwIOS->hdr)->version = DEFAULT_FILE_VERSION; } /* check version; set reader/writer functions */ rv = _genericioSetFuncs(rwIOS); if (rv) { goto END; } /* no need to create header since header should already be a * generic header. */ END: return rv; } /* * Set sizes and functions by version; read header after * genericHeader. See librw_priv.h for details. */ int _genericioPrepareRead(rwIOStruct *rwIOS) { int rv = LIBRW_OK; rv = _genericioSetFuncs(rwIOS); if (rv) { goto END; } /* read remainder of header */ rv = _genericioHeaderRead(rwIOS); if (rv) { goto END; } END: return rv; }