net/capfileconvert/capfileconvert_example.c

Reference Documentation

Platform
Intel® PAC
Napatech SmartNIC
Content Type
Reference Information
Capture Software Version
Link™ Capture Software 12.10
Napatech Software Suite: net/capfileconvert/capfileconvert_example.c
net/capfileconvert/capfileconvert_example.c

Description

This source file contain source code to convert cap files.

/*
*
* Copyright 2023 Napatech A/S. All Rights Reserved.
*
* 1. Copying, modification, and distribution of this file, or executable
* versions of this file, is governed by the terms of the Napatech Software
* license agreement under which this file was made available. If you do not
* agree to the terms of the license do not install, copy, access or
* otherwise use this file.
*
* 2. Under the Napatech Software license agreement you are granted a
* limited, non-exclusive, non-assignable, copyright license to copy, modify
* and distribute this file in conjunction with Napatech SmartNIC's and
* similar hardware manufactured or supplied by Napatech A/S.
*
* 3. The full Napatech Software license agreement is included in this
* distribution, please see "NP-0405 Napatech Software license
* agreement.pdf"
*
* 4. Redistributions of source code must retain this copyright notice,
* list of conditions and the following disclaimer.
*
* THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTIES, EXPRESS OR
* IMPLIED, AND NAPATECH DISCLAIMS ALL IMPLIED WARRANTIES INCLUDING ANY
* IMPLIED WARRANTY OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, OR OF
* FITNESS FOR A PARTICULAR PURPOSE. TO THE EXTENT NOT PROHIBITED BY
* APPLICABLE LAW, IN NO EVENT SHALL NAPATECH BE LIABLE FOR PERSONAL INJURY,
* OR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES WHATSOEVER,
* INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, CORRUPTION OR
* LOSS OF DATA, FAILURE TO TRANSMIT OR RECEIVE ANY DATA OR INFORMATION,
* BUSINESS INTERRUPTION OR ANY OTHER COMMERCIAL DAMAGES OR LOSSES, ARISING
* OUT OF OR RELATED TO YOUR USE OR INABILITY TO USE NAPATECH SOFTWARE OR
* SERVICES OR ANY THIRD PARTY SOFTWARE OR APPLICATIONS IN CONJUNCTION WITH
* THE NAPATECH SOFTWARE OR SERVICES, HOWEVER CAUSED, REGARDLESS OF THE THEORY
* OF LIABILITY (CONTRACT, TORT OR OTHERWISE) AND EVEN IF NAPATECH HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME JURISDICTIONS DO NOT ALLOW
* THE EXCLUSION OR LIMITATION OF LIABILITY FOR PERSONAL INJURY, OR OF
* INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY TO YOU.
*
*
*/
/**
* @example net/capfileconvert/capfileconvert_example.c
*
* @section capfileconvert_example_description Description
*
* This source file contain source code to convert cap files.
*/
// Include this in order to access the Napatech API
#include <nt.h>
#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>
#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 {
// 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 {
static enum InputPCAPFormat_e {
/**
* Table of valid options. Mainly used for the getopt_long_only
* function. For further info see the manpage.
*/
struct argparse_option arg_options[] = {
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 | nt3gdnano>", 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"),
};
#define NT_2GD_SEGMENT_DUMP_MAGIC 0xFEDEABBA
uint64_t magic0;
uint64_t magic1;
struct
{
uint32_t sectionOffset;
uint64_t numDroppedFrames;
};
static struct NtFileHeader0_s nt3gdFileHeader =
{
NT_STID_FILE_HEADER0,
0,
NT_FILE_HEADER0_COOKIE,
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,},
};
static struct NtFileHeader0_s nt3gdNsFileHeader =
{
NT_STID_FILE_HEADER0,
0,
NT_FILE_HEADER0_COOKIE,
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 =
{
2,
4,
0,
0,
10000,
1
};
static struct pcap_hdr_s pcapGlobalHdrNano =
{
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;
}
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 nt3gdnano=0; //Is the nt3gd 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");
return 7;
}
// Open the output file
if ((hof = fopen(opt_output_file, "w+b")) == NULL) {
perror("Failed to create output file.");
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.");
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");
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");
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");
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;
if (((NtFileHeader0_t*)pin)->tsType == NT_TIMESTAMP_TYPE_UNIX_NANOTIME) {
printf("Input file detected as 3GD capture file with UNIX_NANO timestamp.\n");
nanotime=1;
} else {
printf("Input file detected as 3GD capture file.\n");
}
fprintf(stderr, "Input format must only be set when converting a PCAP file.\n");
Result = 3;
goto _done;
}
} // Check for 2GD segment dump
else if ((((struct Nt2GSegmentDumpHeader_s*)pin)->magic0 == 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;
fprintf(stderr, "Input format must only be set when converting a PCAP file.\n");
Result = 3;
goto _done;
}
} // Check for pcap and default to legacy 2GD capture
else {
switch (((struct pcap_hdr_s*)pin)->magic_number) {
nanotime=1;
// fall through
case PCAP_MAGIC:
// fall through
pcap=1;
offset = sizeof(struct pcap_hdr_s);
dSize = fSize;
if (nanotime) {
printf("Input file detected as \"PCAP-nano\".\n");
} else {
printf("Input file detected as \"PCAP\".\n");
}
fprintf(stderr, "Input format detected is PCAP. Type of PCAP format must be specified.\n");
Result = 3;
goto _done;
}
break;
nanotime=1;
// fall through
// fall through
pcap=1;
offset = sizeof(struct pcap_hdr_s);
dSize = fSize;
if (nanotime) {
printf("Input file detected as \"PCAP-nano\".\n");
} else {
printf("Input file detected as \"PCAP\".\n");
}
pcap_swapped = 1;
fprintf(stderr, "Input format detected is PCAP. Type of PCAP format must be specified.\n");
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");
Result = 9;
goto _done;
}
printf("Input file detected as \"2GD capture\".\n");
dSize = fSize;
}
break;
}
}
/**
* The input file has been detected at this point. Do the convertion.
*/
// Start by creating the file header
switch (opt_outputformat) {
printf("Outputfile type is PCAP\n");
fwrite(&pcapGlobalHdr, sizeof(pcapGlobalHdr), 1, hof);
break;
printf("Outputfile type is PCAP NANO\n");
fwrite(&pcapGlobalHdrNano, sizeof(pcapGlobalHdr), 1, hof);
break;
printf("Outputfile type is NT3GD\n");
fwrite(&nt3gdFileHeader, sizeof(nt3gdFileHeader), 1, hof);
break;
printf("Outputfile type is NT3GD NANO\n");
fwrite(&nt3gdNsFileHeader, sizeof(nt3gdNsFileHeader), 1, hof);
nt3gdnano = 1;
break;
default:
fprintf(stderr, "Unhandled output format.\n");
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");
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));
goto _NEXT_PACKET;
}
switch (opt_outputformat) {
switch (input_format) {
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.
const struct NtStd0Descr_s *const src = descr;
struct NtStd0Descr_s *const dst = pktBuf;
memcpy(dst, src, 16U + src->storedLength);
if (src->storedLength >= src->wireLength) {
// Adjust for padding and CRC
dst->wireLength = (uint16_t)(src->wireLength - 4U);
dst->storedLength = src->wireLength;
}
fwrite(dst, 16U + dst->storedLength, 1, hof);
}
break;
// Only convert timestamp
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, 16U + ((struct ntpcap *)descr)->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, 16U + ((struct ntpcap *)descr)->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;
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) {
{
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;
}
{
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;
}
{
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;
}
{
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");
Result = 2;
goto _done;
}
break;
switch (input_format) {
// Only convert timestamp
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;
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;
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) {
{
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;
}
{
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;
}
{
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;
}
{
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.
if (nanotime) {
((struct ntpcap*)pktBuf)->tv.tv_sec = (uint32_t)(((NtStd0Descr_t *)descr)->timestamp/1000000000);
((struct ntpcap*)pktBuf)->tv.tv_usec = (uint32_t)(((NtStd0Descr_t *)descr)->timestamp%1000000000);
} else {
((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");
Result = 2;
goto _done;
}
break;
switch (input_format) {
// Clear the packet descriptor
*((uint64_t*)pktBuf+0)=0;
*((uint64_t*)pktBuf+1)=0;
// Convert timestamp
if (pcap_swapped == 1) {
if (nanotime) {
if (nt3gdnano) { //Going from a 1ns PCAP to a 1ns NT3gd
((struct NtStd0Descr_s *)pktBuf)->timestamp = (((uint64_t)ntohl(((struct ntpcap*)descr)->tv.tv_sec))*1000000000)+(uint64_t)ntohl(((struct ntpcap*)descr)->tv.tv_usec);
} else { //Going from a 1ns PCAP to a 10ns NT3gd
((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 {
if (nt3gdnano) { //Going from a 1us PCAP to a 1ns NT3gd
((struct NtStd0Descr_s *)pktBuf)->timestamp = (((uint64_t)ntohl(((struct ntpcap*)descr)->tv.tv_sec))*1000000000)+(uint64_t)ntohl(((struct ntpcap*)descr)->tv.tv_usec)*1000;
} else { //Going from a 1us PCAP to a 10ns NT3gd
((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) {
if (nt3gdnano) { //Going from a 1ns PCAP to a 1ns NT3gd
((struct NtStd0Descr_s *)pktBuf)->timestamp = (((uint64_t)((struct ntpcap*)descr)->tv.tv_sec)*1000000000)+
(((uint64_t)((struct ntpcap*)descr)->tv.tv_usec));
} else {
((struct NtStd0Descr_s *)pktBuf)->timestamp = ((((uint64_t)((struct ntpcap*)descr)->tv.tv_sec)*100000000)+
(((uint64_t)((struct ntpcap*)descr)->tv.tv_usec)/10));
}
} else {
if (nt3gdnano) { //Going from a 1us PCAP to a 1ns NT3gd
((struct NtStd0Descr_s *)pktBuf)->timestamp = ((((uint64_t)((struct ntpcap*)descr)->tv.tv_sec)*1000000000)+
(((uint64_t)((struct ntpcap*)descr)->tv.tv_usec)*1000));
} 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
// 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");
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;
// 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");
Result = 2;
goto _done;
}
break;
default:
fprintf(stderr, "Unhandled output format.\n");
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",
_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;
argparse_init(&argparse, arg_options, usageText, 0);
argparse_parse(&argparse, argc, argv);
if (opt_output_format != NULL) {
if (strstr(opt_output_format, "pcapnano")) {
} else if (strstr(opt_output_format, "pcap")) {
} else if (strstr(opt_output_format, "nt3gdnano")) {
} else if (strstr(opt_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")) {
} else if (strstr(opt_input_format, "ntpcap")) {
} 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");
}
return ApplExitCode;
}
//
// EOF
//