net/capfileconvert/capfileconvert_example.c

Reference Documentation

product_line_custom
Napatech SmartNIC
category
Reference Information

Description

This source file contain source code to convert cap files. /* * %NT_SOFTWARE_LICENSE% */ /** * @example net/capfileconvert/capfileconvert_example.c * * @section capfileconvert_example_description Description * * This source file contain source code to convert cap files. */ #define _GNU_SOURCE #include <stdio.h> #include <stdarg.h> #include <string.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> #include <sys/types.h> #include <sys/mman.h> #include <sys/stat.h> #include <fcntl.h> #include <netinet/in.h> #include <argparse.h> #include <nt.h> #include "capfileconvert_example.h" #ifdef WIN32 #undef lseek #define lseek _lseeki64 #endif #define PKTBUF_SIZE (16*1024) #define CAPFILE_MAX_SIZE ((size_t)-1) /******************************************************************************/ /* Internal variables */ /******************************************************************************/ static enum InputFormat_e { INPUT_FORMAT_UNKNOWN = 0, INPUT_FORMAT_3GD, INPUT_FORMAT_PCAP, INPUT_FORMAT_PCAPNANO, INPUT_FORMAT_2GD } input_format = 0; // Complete version string constant which can be searched for in the binary static const char* progname = "capfileconvert"; static int appRunning = 1; static unsigned long long pktNum; /* Count all packets */ static unsigned long long pktSkipNum; /* Count packets larger then 16kB */ static char* opt_input_file = NULL; static char* opt_output_file = NULL; static char* opt_output_format = NULL; static char* opt_input_format = NULL; static int opt_verbose = 0; static enum OutputFormat_e { OUTPUT_FORMAT_UNKNOWN=0, OUTPUT_FORMAT_PCAP, OUTPUT_FORMAT_PCAPNANO, OUTPUT_FORMAT_NT3GD } opt_outputformat = 0; static enum InputPCAPFormat_e { INPUT_PCAPFORMAT_UNKNOWN=0, INPUT_PCAPFORMAT_LIBPCAP, INPUT_PCAPFORMAT_NAPATECH, } opt_inputformat = 0; /** * Table of valid options. Mainly used for the getopt_long_only * function. For further info see the manpage. */ struct argparse_option arg_options[] = { OPT_HELP(), OPT_BOOLEAN('v', "verbose", &opt_verbose, "Print extra information", NULL, 0, 0, NULL), OPT_STRING( 'i', "input", &opt_input_file, "Specifies the input file", NULL, 0, 0, "file"), OPT_STRING( 'o', "output", &opt_output_file, "Specifies the output file", NULL, 0, 0, "file"), OPT_STRING( 'f', "outputformat", &opt_output_format, "Specifies the output format: <pcap | pcapnano | nt3gd>", NULL, 0, 0, "format"), OPT_STRING( 'n', "inputformat", &opt_input_format, "Specifies the input format when converting a pcap file: <libpcap | ntpcap>", NULL, 0, 0, "format"), OPT_END(), }; #define NT_2GD_SEGMENT_DUMP_MAGIC 0xFEDEABBA struct Nt2GSegmentDumpHeader_s { uint64_t magic0; uint64_t magic1; struct { uint32_t sectionOffset; uint32_t numBytesAvailable; uint32_t numDescriptorsAvailable; uint64_t numDroppedFrames; } segmentInfo; }; static struct NtFileHeader0_s nt3gdFileHeader = { NT_STID_FILE_HEADER0, 0, NT_FILE_HEADER0_COOKIE, NT_TIMESTAMP_TYPE_NATIVE, 0, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, }; #define PCAP_MAGIC 0xa1b2c3d4 #define PCAP_SWAPPED_MAGIC 0xd4c3b2a1 #define PCAP_MODIFIED_MAGIC 0xa1b2cd34 #define PCAP_SWAPPED_MODIFIED_MAGIC 0x34cdb2a1 #define PCAP_NSEC_MAGIC 0xa1b23c4d #define PCAP_SWAPPED_NSEC_MAGIC 0x4d3cb2a1 #define SWAPLONG(y) \ ((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff)) #define SWAPSHORT(y) \ ( (((y)&0xff)<<8) | ((u_short)((y)&0xff00)>>8) ) /* The following has been taken from: http://wiki.wireshark.org/Development/LibpcapFileFormat */ struct pcap_hdr_s { uint32_t magic_number; /* magic number = 0xa1b2c3d4 */ uint16_t version_major; /* major version number = 2 */ uint16_t version_minor; /* minor version number = 4 */ int32_t thiszone; /* GMT to local correction = 0 */ uint32_t sigfigs; /* accuracy of timestamps = 0 */ uint32_t snaplen; /* max length of captured packets, in octets = 10k */ uint32_t network; /* data link type = 1 */ }; static struct pcap_hdr_s pcapGlobalHdr = { PCAP_MAGIC, 2, 4, 0, 0, 10000, 1 }; static struct pcap_hdr_s pcapGlobalHdrNano = { PCAP_NSEC_MAGIC, 2, 4, 0, 0, 10000, 1 }; struct nttimeval { uint32_t tv_sec; uint32_t tv_usec; }; struct ntpcap { struct nttimeval tv; uint32_t caplen; uint32_t len; }; static void DisplayProgramHeader(void) { printf("\r%s\n", progname); /* Print separator line */ for (int i = 0; i < 78; ++i) { printf("="); } printf("\n"); } static void DisplayProgramFooter (void) { printf("\n"); } /* * The function called when user is pressing CTRL-C */ static void StopApplication(int sig) { (void)sig; appRunning = 0; } static int _Convert(void) { FILE* hof = NULL; int fdin = -1; // init by invalid file descriptor off_t tmp_fSize; size_t fSize = 0, dSize = 0; uint8_t* pin = 0; size_t offset = 0; int pcap = 0; // Pcap format? int nanotime = 0; // Is the pcap in nano time int pcap_swapped = 0; void* pktBuf; int Result = 0; if ((pktBuf = malloc(PKTBUF_SIZE)) == NULL) { perror("Failed to allocate packet buffer of 16k\n"); appRunning=0; return 7; } // Open the output file if ((hof = fopen(opt_output_file, "w+b")) == NULL) { perror("Failed to create output file."); appRunning = 0; Result = 7; goto _done; } // Open the input file #ifdef WIN32 if ((fdin = open(opt_input_file, _O_RDONLY | _O_BINARY, _S_IREAD)) == -1) { // NOTE: the mode parameter 0666 (RW-RW-RW) is ignored, because flag O_CREAT is not used #else if (strcmp(opt_input_file, "-") == 0) { fdin = 0; } else if ((fdin = open(opt_input_file, O_RDONLY, 0666)) == -1) { // NOTE: the mode parameter 0666 (RW-RW-RW) is ignored, because flag O_CREAT is not used #endif perror("Failed to open input file."); appRunning = 0; Result = 7; goto _done; } /* Get the file size. Note: 32-bit platforms can only handle files up to 4 GB due because the implementation mmap's the file into memory. The type size_t is intended for sizes that relate to a process, whereas the type off_t is intended for file offsets, and the range of off_t is typically wider than that of size_t. */ (void)lseek(fdin, 0, SEEK_SET); tmp_fSize = lseek(fdin, 0, SEEK_END); if ((uint64_t)tmp_fSize > (uint64_t)CAPFILE_MAX_SIZE) { fprintf(stderr, "The cap file is too big.\n"); appRunning = 0; Result = 9; goto _done; } fSize = (size_t)tmp_fSize; /* Safe to cast due to test above */ lseek(fdin, 0, SEEK_SET); if (fSize < 16) { fprintf(stderr, "Input file too small.\n"); appRunning = 0; Result = 9; goto _done; } // MMAP the input file, this makes it a lot easier to ++ through it if ((pin = (uint8_t*)mmap(NULL, fSize, PROT_READ, MAP_PRIVATE, fdin, 0)) == MAP_FAILED) { perror("Failed to mmap input file.\n"); appRunning = 0; Result = 7; goto _done; } /** * Try to detect input file format */ // Check for 3GD file type if ((((NtFileHeader0_t*)pin)->cookie == NT_FILE_HEADER0_COOKIE) && (((NtFileHeader0_t*)pin)->structid == NT_STID_FILE_HEADER0)) { printf("Input file detected as 3GD capture file.\n"); offset=sizeof(NtFileHeader0_t); dSize = fSize; input_format = INPUT_FORMAT_3GD; if (opt_inputformat != INPUT_PCAPFORMAT_UNKNOWN) { fprintf(stderr, "Input format must only be set when converting a PCAP file.\n"); appRunning = 0; Result = 3; goto _done; } } // Check for 2GD segment dump else if ((((struct Nt2GSegmentDumpHeader_s*)pin)->magic0 == NT_2GD_SEGMENT_DUMP_MAGIC) && (((struct Nt2GSegmentDumpHeader_s*)pin)->magic1 == NT_2GD_SEGMENT_DUMP_MAGIC)) { printf("Input file detected as \"2GD segment dump\".\n"); offset=sizeof(struct Nt2GSegmentDumpHeader_s); dSize = ((struct Nt2GSegmentDumpHeader_s*)pin)->segmentInfo.numBytesAvailable+offset; input_format = INPUT_FORMAT_2GD; if (opt_inputformat != INPUT_PCAPFORMAT_UNKNOWN) { fprintf(stderr, "Input format must only be set when converting a PCAP file.\n"); appRunning = 0; Result = 3; goto _done; } } // Check for pcap and default to legacy 2GD capture else { switch (((struct pcap_hdr_s*)pin)->magic_number) { case PCAP_NSEC_MAGIC: nanotime=1; // fall through case PCAP_MAGIC: // fall through case PCAP_MODIFIED_MAGIC: pcap=1; offset = sizeof(struct pcap_hdr_s); dSize = fSize; if (nanotime) { input_format = INPUT_FORMAT_PCAPNANO; printf("Input file detected as \"PCAP-nano\".\n"); } else { input_format = INPUT_FORMAT_PCAP; printf("Input file detected as \"PCAP\".\n"); } if (opt_inputformat == INPUT_PCAPFORMAT_UNKNOWN) { fprintf(stderr, "Input format detected is PCAP. Type of PCAP format must be specified.\n"); appRunning = 0; Result = 3; goto _done; } break; case PCAP_SWAPPED_NSEC_MAGIC: nanotime=1; // fall through case PCAP_SWAPPED_MODIFIED_MAGIC: // fall through case PCAP_SWAPPED_MAGIC: pcap=1; offset = sizeof(struct pcap_hdr_s); dSize = fSize; if (nanotime) { printf("Input file detected as \"PCAP-nano\".\n"); input_format = INPUT_FORMAT_PCAPNANO; } else { printf("Input file detected as \"PCAP\".\n"); input_format = INPUT_FORMAT_PCAP; } pcap_swapped = 1; if (opt_inputformat == INPUT_PCAPFORMAT_UNKNOWN) { fprintf(stderr, "Input format detected is PCAP. Type of PCAP format must be specified.\n"); appRunning = 0; Result = 3; goto _done; } break; default: { /** * PCAP has not been detected, assume legacy 2GD Capture but * perform some sanity checks first though. */ const struct NtStd0Descr_s *p1 = (struct NtStd0Descr_s*)pin; const unsigned SIZE_MAX_PKT = 10000U; const unsigned SIZE_2GD_STD_DESC = 16U; const unsigned SIZE_2GD_EXT_HDR = p1->extensionLength * 8U; const unsigned MAX_STORED_LENGTH = SIZE_MAX_PKT + SIZE_2GD_STD_DESC + SIZE_2GD_EXT_HDR; int err=0; if ((p1->storedLength <= fSize) && (p1->storedLength <= MAX_STORED_LENGTH)) { if (p1->frameSliced) { if (p1->wireLength < p1->storedLength) { err=1; } } else if (p1->storedLength < p1->wireLength) { err=1; } if (p1->storedLength < fSize) { const struct NtStd0Descr_s *p2 = (struct NtStd0Descr_s*)((uint8_t*)pin+p1->storedLength); if (p2->storedLength <= MAX_STORED_LENGTH) { if (p2->frameSliced) { if (p2->wireLength < p2->storedLength) { err=1; } } else if (p2->storedLength < p2->wireLength) { err=1; } } else { err=1; } } } else { err=1; } if (err) { fprintf(stderr, "Cannot detect input format.\n"); appRunning=0; Result = 9; goto _done; } printf("Input file detected as \"2GD capture\".\n"); dSize = fSize; input_format = INPUT_FORMAT_2GD; } break; } } /** * The input file has been detected at this point. Do the convertion. */ // Start by creating the file header switch (opt_outputformat) { case OUTPUT_FORMAT_PCAP: fwrite(&pcapGlobalHdr, sizeof(pcapGlobalHdr), 1, hof); break; case OUTPUT_FORMAT_PCAPNANO: fwrite(&pcapGlobalHdrNano, sizeof(pcapGlobalHdr), 1, hof); break; case OUTPUT_FORMAT_NT3GD: fwrite(&nt3gdFileHeader, sizeof(nt3gdFileHeader), 1, hof); break; default: fprintf(stderr, "Unhandled output format.\n"); appRunning = 0; Result = 2; goto _done; } // Now convert the packets while ((offset < dSize) && appRunning) { uint32_t storedLength; void *descr = (void*)(pin+offset); if (((NtDynDescr_t*)descr)->ntDynDescr) { storedLength = ((NtDynDescr_t*)descr)->capLength; } else if (((NtStd0Descr_t*)descr)->descriptorType) { storedLength = ((NtStd0Descr_t*)descr)->storedLength; } else { if (pcap_swapped == 1) { // PCAP native swapped format. Must be swapped before saving storedLength = 16 + ntohl(((struct ntpcap *)descr)->caplen); } else { storedLength = 16 + (((struct ntpcap *)descr)->caplen); } } if ((storedLength == 0) || (pcap && (storedLength == 16))){ fprintf(stderr, "File error. StoredLength == 0 detected.\n"); appRunning=0; Result = 9; break; } // Check that the packet is not too big if (storedLength > PKTBUF_SIZE) { (void)fprintf(stderr, "Warning: Packet at offset %lld is too big (>%d kB) " "and will be skipped.\n", (unsigned long long)offset, (PKTBUF_SIZE / 1024)); pktSkipNum++; goto _NEXT_PACKET; } switch (opt_outputformat) { case OUTPUT_FORMAT_PCAP: switch (input_format) { case INPUT_FORMAT_PCAP: if (opt_inputformat == INPUT_PCAPFORMAT_LIBPCAP) { if (pcap_swapped == 1) { // PCAP native swapped format. Must be swapped before saving memcpy(pktBuf, descr, 16+ntohl(((struct ntpcap *)descr)->caplen)); ((struct ntpcap *)pktBuf)->caplen = ntohl(((struct ntpcap *)pktBuf)->caplen); ((struct ntpcap *)pktBuf)->len = ntohl(((struct ntpcap *)pktBuf)->len); ((struct ntpcap *)pktBuf)->tv.tv_sec = ntohl(((struct ntpcap *)pktBuf)->tv.tv_sec); ((struct ntpcap *)pktBuf)->tv.tv_usec = ntohl(((struct ntpcap *)pktBuf)->tv.tv_usec); fwrite(pktBuf, 16+((struct ntpcap *)pktBuf)->caplen, 1, hof); } else { // PCAP native format. No convert. Just copy the packet fwrite(descr, 16+((struct ntpcap *)descr)->caplen, 1, hof); } } else { // PCAP format is Napatech PCAP. Remove Padding and CRC. if (((struct NtStd0Descr_s *)pktBuf)->storedLength >= ((struct NtStd0Descr_s *)pktBuf)->wireLength) { memcpy(pktBuf, descr, 16+((struct NtStd0Descr_s *)pktBuf)->storedLength); ((struct NtStd0Descr_s *)pktBuf)->wireLength = (unsigned short)(((struct NtStd0Descr_s *)pktBuf)->wireLength - 4); ((struct NtStd0Descr_s *)pktBuf)->storedLength = ((struct NtStd0Descr_s *)pktBuf)->wireLength; fwrite(pktBuf, 16+((struct NtStd0Descr_s *)pktBuf)->storedLength, 1, hof); } else { fwrite(descr, 16+((struct NtStd0Descr_s *)pktBuf)->storedLength, 1, hof); } } break; case INPUT_FORMAT_PCAPNANO: // Only convert timestamp if (opt_inputformat == INPUT_PCAPFORMAT_LIBPCAP) { if (pcap_swapped == 1) { // PCAP native swapped format. Must be swapped before saving and convert timestamp memcpy(pktBuf, descr, 16+ntohl(((struct ntpcap *)descr)->caplen)); ((struct ntpcap *)pktBuf)->caplen = ntohl(((struct ntpcap *)pktBuf)->caplen); ((struct ntpcap *)pktBuf)->len = ntohl(((struct ntpcap *)pktBuf)->len); ((struct ntpcap *)pktBuf)->tv.tv_sec = ntohl(((struct ntpcap *)pktBuf)->tv.tv_sec); ((struct ntpcap *)pktBuf)->tv.tv_usec = ntohl(((struct ntpcap *)pktBuf)->tv.tv_usec)/1000; fwrite(pktBuf, 16+((struct ntpcap *)pktBuf)->caplen, 1, hof); } else { // PCAP native format. No convert. Just copy the packet memcpy(pktBuf, descr, 16+((struct ntpcap *)pktBuf)->caplen); ((struct nttimeval*)pktBuf)->tv_usec = ((struct nttimeval*)pktBuf)->tv_usec/1000; fwrite(pktBuf, 16+((struct ntpcap *)pktBuf)->caplen, 1, hof); } } else { // PCAP format is Napatech PCAP. Remove Padding and CRC. memcpy(pktBuf, descr, 16+((struct ntpcap *)pktBuf)->caplen); ((struct nttimeval*)pktBuf)->tv_usec = ((struct nttimeval*)pktBuf)->tv_usec/1000; if (((struct ntpcap *)pktBuf)->caplen >= ((struct ntpcap *)pktBuf)->len) { ((struct NtStd0Descr_s *)pktBuf)->wireLength = (unsigned short)(((struct NtStd0Descr_s *)pktBuf)->wireLength - 4); ((struct NtStd0Descr_s *)pktBuf)->storedLength = ((struct NtStd0Descr_s *)pktBuf)->wireLength; fwrite(pktBuf, 16+((struct NtStd0Descr_s *)pktBuf)->storedLength, 1, hof); } else { fwrite(pktBuf, 16+((struct ntpcap *)pktBuf)->caplen, 1, hof); } } break; case INPUT_FORMAT_2GD: case INPUT_FORMAT_3GD: if (((NtDynDescr_t*)descr)->ntDynDescr) { NtDynDescr_t *pDyn = (NtDynDescr_t*)descr; // Convert by only copying storedLength, wireLength and timestamp ((struct ntpcap*)pktBuf)->len = pDyn->capLength - pDyn->descrLength - 4; // pcap wirelength is wo crc ((struct ntpcap*)pktBuf)->caplen = ((struct ntpcap*)pktBuf)->len; switch ((enum NtDynamicDescriptorFormat_e)((NtDynDescr_t*)descr)->descrFormat) { case NT_DYNAMIC_DESCRIPTOR_FORMAT_1: { NtDyn1Descr_t *pDyn1 = (NtDyn1Descr_t*)descr; // Convert the ts. ((struct ntpcap*)pktBuf)->tv.tv_sec = (uint32_t)(pDyn1->timestamp/100000000); ((struct ntpcap*)pktBuf)->tv.tv_usec = ((uint32_t)(pDyn1->timestamp%100000000)/100); // Copy the payload memcpy((uint8_t*)pktBuf+16, (uint8_t*)descr+pDyn1->descrLength, ((struct ntpcap*)pktBuf)->caplen); // Write the packet to disk fwrite(pktBuf, 16+((struct ntpcap*)pktBuf)->caplen, 1, hof); break; } case NT_DYNAMIC_DESCRIPTOR_FORMAT_2: { NtDyn2Descr_t *pDyn2 = (NtDyn2Descr_t*)descr; // Convert the ts. ((struct ntpcap*)pktBuf)->tv.tv_sec = (uint32_t)(pDyn2->timestamp/100000000); ((struct ntpcap*)pktBuf)->tv.tv_usec = ((uint32_t)(pDyn2->timestamp%100000000)/100); // Copy the payload memcpy((uint8_t*)pktBuf+16, (uint8_t*)descr+pDyn2->descrLength, ((struct ntpcap*)pktBuf)->caplen); // Write the packet to disk fwrite(pktBuf, 16+((struct ntpcap*)pktBuf)->caplen, 1, hof); break; } case NT_DYNAMIC_DESCRIPTOR_FORMAT_3: { NtDyn3Descr_t *pDyn3 = (NtDyn3Descr_t*)descr; // Convert the ts. ((struct ntpcap*)pktBuf)->tv.tv_sec = (uint32_t)(pDyn3->timestamp/100000000); ((struct ntpcap*)pktBuf)->tv.tv_usec = ((uint32_t)(pDyn3->timestamp%100000000)/100); // Copy the payload memcpy((uint8_t*)pktBuf+16, (uint8_t*)descr+pDyn3->descrLength, ((struct ntpcap*)pktBuf)->caplen); // Write the packet to disk fwrite(pktBuf, 16+((struct ntpcap*)pktBuf)->caplen, 1, hof); break; } case NT_DYNAMIC_DESCRIPTOR_FORMAT_4: { NtDyn4Descr_t *pDyn4 = (NtDyn4Descr_t*)descr; // Convert the ts. ((struct ntpcap*)pktBuf)->tv.tv_sec = (uint32_t)(pDyn4->timestamp/100000000); ((struct ntpcap*)pktBuf)->tv.tv_usec = ((uint32_t)(pDyn4->timestamp%100000000)/100); // Copy the payload memcpy((uint8_t*)pktBuf+16, (uint8_t*)descr+pDyn4->descrLength, ((struct ntpcap*)pktBuf)->caplen); // Write the packet to disk fwrite(pktBuf, 16+((struct ntpcap*)pktBuf)->caplen, 1, hof); break; } } } else { // Convert by only copying storedLength, wireLength and timestamp ((struct ntpcap*)pktBuf)->len = ((struct NtStd0Descr_s *)descr)->wireLength-4; // pcap wirelength is wo crc ((struct ntpcap*)pktBuf)->caplen = (((struct NtStd0Descr_s *)descr)->storedLength-(((struct NtStd0Descr_s *)descr)->extensionLength<<3)-16); // In pcap stored cannot be longer than wire if (((struct ntpcap*)pktBuf)->caplen > ((struct ntpcap*)pktBuf)->len) { ((struct ntpcap*)pktBuf)->caplen = ((struct ntpcap*)pktBuf)->len; } // Convert the ts. ((struct ntpcap*)pktBuf)->tv.tv_sec = (uint32_t)(((struct NtStd0Descr_s *)descr)->timestamp/100000000); ((struct ntpcap*)pktBuf)->tv.tv_usec = (uint32_t)((((struct NtStd0Descr_s *)descr)->timestamp%100000000)/100); // Copy the payload memcpy((uint8_t*)pktBuf+16, (uint8_t*)descr+(((struct NtStd0Descr_s *)descr)->extensionLength<<3)+16, ((struct ntpcap*)pktBuf)->caplen); // Write the packet to disk fwrite(pktBuf, 16+((struct ntpcap*)pktBuf)->caplen, 1, hof); } break; default: fprintf(stderr, "Unhandled input format.\n"); appRunning=0; Result = 2; goto _done; } break; case OUTPUT_FORMAT_PCAPNANO: switch (input_format) { case INPUT_FORMAT_PCAP: // Only convert timestamp if (opt_inputformat == INPUT_PCAPFORMAT_LIBPCAP) { if (pcap_swapped == 1) { // PCAP native swapped format. Must be swapped before saving memcpy(pktBuf, descr, 16+ntohl(((struct ntpcap *)descr)->caplen)); ((struct ntpcap *)pktBuf)->caplen = ntohl(((struct ntpcap *)pktBuf)->caplen); ((struct ntpcap *)pktBuf)->len = ntohl(((struct ntpcap *)pktBuf)->len); ((struct ntpcap *)pktBuf)->tv.tv_sec = ntohl(((struct ntpcap *)pktBuf)->tv.tv_sec); ((struct ntpcap *)pktBuf)->tv.tv_usec = ntohl(((struct ntpcap *)pktBuf)->tv.tv_usec)*1000; fwrite(pktBuf, 16+((struct ntpcap *)pktBuf)->caplen, 1, hof); } else { // PCAP native format. No convert. Just copy the packet memcpy(pktBuf, descr, 16+((NtStd0Descr_t *)descr)->storedLength); ((struct nttimeval*)pktBuf)->tv_usec = (((struct nttimeval*)pktBuf)->tv_usec*1000); fwrite(pktBuf, 16+((NtStd0Descr_t *)descr)->storedLength, 1, hof); } } else { // PCAP format is Napatech PCAP. Remove Padding and CRC. if (((NtStd0Descr_t *)descr)->storedLength >= ((NtStd0Descr_t *)descr)->wireLength) { memcpy(pktBuf, descr, 16+((NtStd0Descr_t *)descr)->storedLength); ((struct NtStd0Descr_s *)pktBuf)->wireLength = (unsigned short)(((struct NtStd0Descr_s *)pktBuf)->wireLength - 4); ((struct NtStd0Descr_s *)pktBuf)->storedLength = ((struct NtStd0Descr_s *)pktBuf)->wireLength; ((struct nttimeval*)pktBuf)->tv_usec = (((struct nttimeval*)pktBuf)->tv_usec*1000); fwrite(pktBuf, 16+((struct NtStd0Descr_s *)pktBuf)->storedLength, 1, hof); } else { memcpy(pktBuf, descr, 16+((NtStd0Descr_t *)descr)->storedLength); ((struct nttimeval*)pktBuf)->tv_usec = (((struct nttimeval*)pktBuf)->tv_usec*1000); fwrite(pktBuf, 16+((NtStd0Descr_t *)descr)->storedLength, 1, hof); } } break; case INPUT_FORMAT_PCAPNANO: if (opt_inputformat == INPUT_PCAPFORMAT_LIBPCAP) { if (pcap_swapped == 1) { // PCAP native swapped format. Must be swapped before saving memcpy(pktBuf, descr, 16+ntohl(((struct ntpcap *)descr)->caplen)); ((struct ntpcap *)pktBuf)->caplen = ntohl(((struct ntpcap *)pktBuf)->caplen); ((struct ntpcap *)pktBuf)->len = ntohl(((struct ntpcap *)pktBuf)->len); ((struct ntpcap *)pktBuf)->tv.tv_sec = ntohl(((struct ntpcap *)pktBuf)->tv.tv_sec); ((struct ntpcap *)pktBuf)->tv.tv_usec = ntohl(((struct ntpcap *)pktBuf)->tv.tv_usec); fwrite(pktBuf, 16+((struct ntpcap *)pktBuf)->caplen, 1, hof); } else { // PCAP native format. No convert. Just copy the packet fwrite(descr, 16+((NtStd0Descr_t *)descr)->storedLength, 1, hof); } } else { // PCAP format is Napatech PCAP. Remove Padding and CRC. if (((NtStd0Descr_t *)descr)->storedLength >= ((NtStd0Descr_t *)descr)->wireLength) { memcpy(pktBuf, descr, 16+((NtStd0Descr_t *)descr)->storedLength); ((struct NtStd0Descr_s *)pktBuf)->wireLength = (unsigned short)(((struct NtStd0Descr_s *)pktBuf)->wireLength - 4); ((struct NtStd0Descr_s *)pktBuf)->storedLength = ((struct NtStd0Descr_s *)pktBuf)->wireLength; fwrite(pktBuf, 16+((struct NtStd0Descr_s *)pktBuf)->storedLength, 1, hof); } else { fwrite(descr, 16+((NtStd0Descr_t *)descr)->storedLength, 1, hof); } } break; case INPUT_FORMAT_2GD: case INPUT_FORMAT_3GD: if (((NtDynDescr_t*)descr)->ntDynDescr) { NtDynDescr_t *pDyn = (NtDynDescr_t*)descr; // Convert by only copying storedLength, wireLength and timestamp ((struct ntpcap*)pktBuf)->len = pDyn->capLength - pDyn->descrLength - 4; // pcap wirelength is wo crc ((struct ntpcap*)pktBuf)->caplen = ((struct ntpcap*)pktBuf)->len; switch ((enum NtDynamicDescriptorFormat_e)((NtDynDescr_t*)descr)->descrFormat) { case NT_DYNAMIC_DESCRIPTOR_FORMAT_1: { NtDyn1Descr_t *pDyn1 = (NtDyn1Descr_t*)descr; // Convert the ts. ((struct ntpcap*)pktBuf)->tv.tv_sec = (uint32_t)(pDyn1->timestamp/100000000); ((struct ntpcap*)pktBuf)->tv.tv_usec = (uint32_t)((pDyn1->timestamp%100000000)*10); // Copy the payload memcpy((uint8_t*)pktBuf+16, (uint8_t*)descr+pDyn1->descrLength, ((struct ntpcap*)pktBuf)->caplen); // Write the packet to disk fwrite(pktBuf, 16+((struct ntpcap*)pktBuf)->caplen, 1, hof); break; } case NT_DYNAMIC_DESCRIPTOR_FORMAT_2: { NtDyn2Descr_t *pDyn2 = (NtDyn2Descr_t*)descr; // Convert the ts. ((struct ntpcap*)pktBuf)->tv.tv_sec = (uint32_t)(pDyn2->timestamp/100000000); ((struct ntpcap*)pktBuf)->tv.tv_usec = (uint32_t)((pDyn2->timestamp%100000000)*10); // Copy the payload memcpy((uint8_t*)pktBuf+16, (uint8_t*)descr+pDyn2->descrLength, ((struct ntpcap*)pktBuf)->caplen); // Write the packet to disk fwrite(pktBuf, 16+((struct ntpcap*)pktBuf)->caplen, 1, hof); break; } case NT_DYNAMIC_DESCRIPTOR_FORMAT_3: { NtDyn3Descr_t *pDyn3 = (NtDyn3Descr_t*)descr; // Convert the ts. ((struct ntpcap*)pktBuf)->tv.tv_sec = (uint32_t)(pDyn3->timestamp/100000000); ((struct ntpcap*)pktBuf)->tv.tv_usec = (uint32_t)((pDyn3->timestamp%100000000)*10); // Copy the payload memcpy((uint8_t*)pktBuf+16, (uint8_t*)descr+pDyn3->descrLength, ((struct ntpcap*)pktBuf)->caplen); // Write the packet to disk fwrite(pktBuf, 16+((struct ntpcap*)pktBuf)->caplen, 1, hof); break; } case NT_DYNAMIC_DESCRIPTOR_FORMAT_4: { NtDyn4Descr_t *pDyn4 = (NtDyn4Descr_t*)descr; // Convert the ts. ((struct ntpcap*)pktBuf)->tv.tv_sec = (uint32_t)(pDyn4->timestamp/100000000); ((struct ntpcap*)pktBuf)->tv.tv_usec = (uint32_t)((pDyn4->timestamp%100000000)*10); // Copy the payload memcpy((uint8_t*)pktBuf+16, (uint8_t*)descr+pDyn4->descrLength, ((struct ntpcap*)pktBuf)->caplen); // Write the packet to disk fwrite(pktBuf, 16+((struct ntpcap*)pktBuf)->caplen, 1, hof); break; } } } else { // Convert by only copying storedLength, wireLength and timestamp ((struct ntpcap*)pktBuf)->len = ((NtStd0Descr_t *)descr)->wireLength-4; // pcap wirelength is wo crc ((struct ntpcap*)pktBuf)->caplen = (((NtStd0Descr_t *)descr)->storedLength-(((NtStd0Descr_t *)descr)->extensionLength<<3)-16); // In pcap stored cannot be longer than wire if (((struct ntpcap*)pktBuf)->caplen > ((struct ntpcap*)pktBuf)->len) { ((struct ntpcap*)pktBuf)->caplen = ((struct ntpcap*)pktBuf)->len; } // Convert the ts. ((struct ntpcap*)pktBuf)->tv.tv_sec = (uint32_t)(((NtStd0Descr_t *)descr)->timestamp/100000000); ((struct ntpcap*)pktBuf)->tv.tv_usec = (uint32_t)((((NtStd0Descr_t *)descr)->timestamp%100000000)*10); // Copy the payload. Payload (packet data) will immediately follow the packet header (header size is 4*32-bit words (16 bytes)) memcpy((uint8_t*)pktBuf+16, (uint8_t*)descr+(((NtStd0Descr_t *)descr)->extensionLength<<3)+16, ((struct ntpcap*)pktBuf)->caplen); // Write the packet to disk fwrite(pktBuf, 16+((struct ntpcap*)pktBuf)->caplen, 1, hof); } break; default: fprintf(stderr, "Unhandled input format.\n"); appRunning=0; Result = 2; goto _done; } break; case OUTPUT_FORMAT_NT3GD: switch (input_format) { case INPUT_FORMAT_PCAPNANO: case INPUT_FORMAT_PCAP: // Clear the packet descriptor *((uint64_t*)pktBuf+0)=0; *((uint64_t*)pktBuf+1)=0; // Convert timestamp if (pcap_swapped == 1) { if (nanotime) { ((struct NtStd0Descr_s *)pktBuf)->timestamp = ((((uint64_t)ntohl(((struct ntpcap*)descr)->tv.tv_sec))*100000000)+(((uint64_t)ntohl(((struct ntpcap*)descr)->tv.tv_usec))/10)); } else { ((struct NtStd0Descr_s *)pktBuf)->timestamp = ((((uint64_t)ntohl(((struct ntpcap*)descr)->tv.tv_sec))*100000000)+(((uint64_t)ntohl(((struct ntpcap*)descr)->tv.tv_usec))*100)); } } else { if (nanotime) { ((struct NtStd0Descr_s *)pktBuf)->timestamp = ((((uint64_t)((struct ntpcap*)descr)->tv.tv_sec)*100000000)+(((uint64_t)((struct ntpcap*)descr)->tv.tv_usec)/10)); } else { ((struct NtStd0Descr_s *)pktBuf)->timestamp = ((((uint64_t)((struct ntpcap*)descr)->tv.tv_sec)*100000000)+(((uint64_t)((struct ntpcap*)descr)->tv.tv_usec)*100)); } } ((struct NtStd0Descr_s *)pktBuf)->descriptorType=1; // Mark NT descriptor if (opt_inputformat == INPUT_PCAPFORMAT_LIBPCAP) { // PCAP native format. uint32_t caplen; uint32_t len; if (pcap_swapped == 1) { caplen = ntohl(((struct ntpcap*)descr)->caplen); len = ntohl(((struct ntpcap*)descr)->len); } else { caplen = ((struct ntpcap*)descr)->caplen; len = ((struct ntpcap*)descr)->len; } if (len > caplen) { // Sliced packet ((struct NtStd0Descr_s *)pktBuf)->frameSliced=1; ((struct NtStd0Descr_s *)pktBuf)->storedLength=(uint16_t)((caplen+16+7)&~7); } else if (len < caplen) { fprintf(stderr, "Error in Packet at offset %lld. Stored length %d must not be larger than the wire length %d.\n", (unsigned long long)offset, caplen, len); fprintf(stderr, "This could be a Napatech capture file with PCAP headers.\n"); (void)fprintf(stderr, "Try to run the tool again with --inputformat=ntpcap.\n"); appRunning=0; Result = 9; goto _done; } else { // Remember 4byte crc ((struct NtStd0Descr_s *)pktBuf)->storedLength=(uint16_t)((caplen+16+4+7)&~7); } if (len > 10000) { // Hard sliced packet ((struct NtStd0Descr_s *)pktBuf)->hardSlice=1; ((struct NtStd0Descr_s *)pktBuf)->storedLength=((10000+sizeof(struct NtStd0Descr_s)+7)&~7); // StoredLength must be 8byte aligned } ((struct NtStd0Descr_s *)pktBuf)->wireLength=(uint16_t)(len+4); // NT format is with checksum but we need to ask the HW to recalc it ((struct NtStd0Descr_s *)pktBuf)->txCrcOverride=1; // Copy payload memcpy((uint8_t*)pktBuf+16, (uint8_t*)descr+16, caplen); } else { // PCAP format is Napatech PCAP. Padding and CRC is already done in the file. if (((struct ntpcap*)descr)->len > ((struct ntpcap*)descr)->caplen) { // Sliced packet ((struct NtStd0Descr_s *)pktBuf)->frameSliced=1; ((struct NtStd0Descr_s *)pktBuf)->storedLength=(uint16_t)(((struct ntpcap*)descr)->caplen+16); } else { // The 4 byte crc is already included. Remove padding if exist and add them again. ((struct NtStd0Descr_s *)pktBuf)->storedLength=(uint16_t)((((struct ntpcap*)descr)->len+16+7)&~7); } if (((struct ntpcap*)descr)->len > 10000) { // Hard sliced packet ((struct NtStd0Descr_s *)pktBuf)->hardSlice=1; ((struct NtStd0Descr_s *)pktBuf)->storedLength=((10000+sizeof(struct NtStd0Descr_s)+7)&~7); // StoredLength must be 8byte aligned } ((struct NtStd0Descr_s *)pktBuf)->wireLength=(uint16_t)(((struct ntpcap*)descr)->len); // NT format is with checksum but we need to ask the HW to recalc it ((struct NtStd0Descr_s *)pktBuf)->txCrcOverride=1; // Copy payload memcpy((uint8_t*)pktBuf+16, (uint8_t*)descr+16, ((struct ntpcap*)descr)->caplen); } fwrite(pktBuf, ((struct NtStd0Descr_s *)pktBuf)->storedLength, 1, hof); break; case INPUT_FORMAT_2GD: case INPUT_FORMAT_3GD: // No convert. Just copy the packet if (((NtDynDescr_t*)descr)->ntDynDescr) { fwrite(descr, ((NtDynDescr_t *)descr)->capLength, 1, hof); } else { fwrite(descr, ((NtStd0Descr_t *)descr)->storedLength, 1, hof); } break; default: fprintf(stderr, "Unhandled input format.\n"); appRunning=0; Result = 2; goto _done; } break; default: fprintf(stderr, "Unhandled output format.\n"); appRunning=0; Result = 2; goto _done; } // Next packet _NEXT_PACKET: offset += storedLength; pktNum++; } if (opt_verbose) { printf("File size: 0x%lX (%ld) offset: 0x%lX (%ld)\n", dSize, dSize, offset, offset); } if (!pktSkipNum) (void)printf("Conversion done. Converted %llu packets.\n", pktNum); else (void)printf("Conversion done. Converted %llu and skipped %llu packets.\n", (pktNum - pktSkipNum), pktSkipNum); _done: // Unmap the input file if (pin) { munmap(pin, fSize); } // Close input file if (fdin != -1) { close(fdin); } // Close output file if (hof) { fclose(hof); } /* Release heap memory */ free(pktBuf); return Result; } // // main // int main(int argc, const char *argv[]) { int ApplExitCode; struct argparse argparse; DisplayProgramHeader(); argparse_init(&argparse, arg_options, usageText, 0); argparse_parse(&argparse, argc, argv); if (opt_output_format != NULL) { if (strstr(opt_output_format, "pcapnano")) { opt_outputformat = OUTPUT_FORMAT_PCAPNANO; } else if (strstr(opt_output_format, "pcap")) { opt_outputformat = OUTPUT_FORMAT_PCAP; } else if (strstr(opt_output_format, "nt3gd")) { opt_outputformat = OUTPUT_FORMAT_NT3GD; } else { fprintf(stderr, "Unknown output format: %s\n", opt_output_format); return 2; } } if (opt_input_format != NULL) { if (strstr(opt_input_format, "libpcap")) { opt_inputformat = INPUT_PCAPFORMAT_LIBPCAP; } else if (strstr(opt_input_format, "ntpcap")) { opt_inputformat = INPUT_PCAPFORMAT_NAPATECH; } else { fprintf(stderr, "Unknown input format: %s\n", opt_input_format); return 2; } } if (opt_outputformat==0) { fprintf(stderr, "No output format provided.\n"); return 4; } if (opt_input_file==NULL) { fprintf(stderr, "No input file provided.\n"); return 4; } if (opt_output_file==NULL) { fprintf(stderr, "No output file provided.\n"); return 4; } struct sigaction newaction; memset(&newaction, 0, sizeof(newaction)); newaction.sa_handler = StopApplication; if (sigaction(SIGINT, &newaction, NULL) < 0) { fprintf(stderr, "Failed to register SIGINT sigaction.\n"); exit(7); } if ((ApplExitCode = _Convert()) != 0) { fprintf(stderr, ">>> Error: Convert failed.\n"); } DisplayProgramFooter(); return ApplExitCode; } // // EOF //