1 /**-*-C-*-**********************************************************************
5 * Utility to convert an ASCII hexdump into a libpcap-format capture file
7 * (c) Copyright 2001 Ashok Narayanan <ashokn@cisco.com>
11 * Wireshark - Network traffic analyzer
12 * By Gerald Combs <gerald@wireshark.org>
13 * Copyright 1998 Gerald Combs
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 *******************************************************************************/
31 /*******************************************************************************
33 * This utility reads in an ASCII hexdump of this common format:
35 * 00000000 00 E0 1E A7 05 6F 00 10 5A A0 B9 12 08 00 46 00 .....o..Z.....F.
36 * 00000010 03 68 00 00 00 00 0A 2E EE 33 0F 19 08 7F 0F 19 .h.......3...
\7f..
37 * 00000020 03 80 94 04 00 00 10 01 16 A2 0A 00 03 50 00 0C .............P..
38 * 00000030 01 01 0F 19 03 80 11 01 1E 61 00 0C 03 01 0F 19 .........a......
40 * Each bytestring line consists of an offset, one or more bytes, and
41 * text at the end. An offset is defined as a hex string of more than
42 * two characters. A byte is defined as a hex string of exactly two
43 * characters. The text at the end is ignored, as is any text before
44 * the offset. Bytes read from a bytestring line are added to the
45 * current packet only if all the following conditions are satisfied:
47 * - No text appears between the offset and the bytes (any bytes appearing after
48 * such text would be ignored)
50 * - The offset must be arithmetically correct, i.e. if the offset is 00000020, then
51 * exactly 32 bytes must have been read into this packet before this. If the offset
52 * is wrong, the packet is immediately terminated
54 * A packet start is signaled by a zero offset.
56 * Lines starting with #TEXT2PCAP are directives. These allow the user
57 * to embed instructions into the capture file which allows text2pcap
58 * to take some actions (e.g. specifying the encapsulation
59 * etc.). Currently no directives are implemented.
61 * Lines beginning with # which are not directives are ignored as
62 * comments. Currently all non-hexdump text is ignored by text2pcap;
63 * in the future, text processing may be added, but lines prefixed
64 * with '#' will still be ignored.
66 * The output is a libpcap packet containing Ethernet frames by
67 * default. This program takes options which allow the user to add
68 * dummy Ethernet, IP and UDP or TCP headers to the packets in order
69 * to allow dumps of L3 or higher protocols to be decoded.
71 * Considerable flexibility is built into this code to read hexdumps
72 * of slightly different formats. For example, any text prefixing the
73 * hexdump line is dropped (including mail forwarding '>'). The offset
74 * can be any hex number of four digits or greater.
76 * This converter cannot read a single packet greater than 64K. Packet
77 * snaplength is automatically set to 64K.
85 * Just make sure we include the prototype for strptime as well
86 * (needed for glibc 2.2) but make sure we do this only if not
93 # define _XOPEN_SOURCE
97 * Defining _XOPEN_SOURCE is needed on some platforms, e.g. platforms
98 * using glibc, to expand the set of things system header files define.
100 * Unfortunately, on other platforms, such as some versions of Solaris
101 * (including Solaris 10), it *reduces* that set as well, causing
102 * strptime() not to be declared, presumably because the version of the
103 * X/Open spec that _XOPEN_SOURCE implies doesn't include strptime() and
104 * blah blah blah namespace pollution blah blah blah.
106 * So we define __EXTENSIONS__ so that "strptime()" is declared.
108 #ifndef __EXTENSIONS__
109 # define __EXTENSIONS__
116 #include <wsutil/file_util.h>
129 #include "wsutil/wsgetopt.h"
132 #ifdef NEED_STRPTIME_H
133 # include "wsutil/strptime.h"
136 #include "text2pcap.h"
137 #include "svnversion.h"
140 #include <wsutil/unicode-utils.h>
143 /*--- Options --------------------------------------------------------------------*/
146 static int debug = 0;
148 static int quiet = FALSE;
150 /* Dummy Ethernet header */
151 static int hdr_ethernet = FALSE;
152 static unsigned long hdr_ethernet_proto = 0;
154 /* Dummy IP header */
155 static int hdr_ip = FALSE;
156 static long hdr_ip_proto = 0;
158 /* Dummy UDP header */
159 static int hdr_udp = FALSE;
160 static unsigned long hdr_dest_port = 0;
161 static unsigned long hdr_src_port = 0;
163 /* Dummy TCP header */
164 static int hdr_tcp = FALSE;
166 /* Dummy SCTP header */
167 static int hdr_sctp = FALSE;
168 static unsigned long hdr_sctp_src = 0;
169 static unsigned long hdr_sctp_dest = 0;
170 static unsigned long hdr_sctp_tag = 0;
172 /* Dummy DATA chunk header */
173 static int hdr_data_chunk = FALSE;
174 static unsigned char hdr_data_chunk_type = 0;
175 static unsigned char hdr_data_chunk_bits = 3;
176 static unsigned long hdr_data_chunk_tsn = 0;
177 static unsigned short hdr_data_chunk_sid = 0;
178 static unsigned short hdr_data_chunk_ssn = 0;
179 static unsigned long hdr_data_chunk_ppid = 0;
182 /*--- Local date -----------------------------------------------------------------*/
184 /* This is where we store the packet currently being built */
185 #define MAX_PACKET 64000
186 static unsigned char packet_buf[MAX_PACKET];
187 static unsigned long curr_offset = 0;
188 static unsigned long max_offset = MAX_PACKET;
189 static unsigned long packet_start = 0;
190 static void start_new_packet (void);
192 /* This buffer contains strings present before the packet offset 0 */
193 #define PACKET_PREAMBLE_MAX_LEN 2048
194 static unsigned char packet_preamble[PACKET_PREAMBLE_MAX_LEN+1];
195 static int packet_preamble_len = 0;
197 /* Number of packets read and written */
198 static unsigned long num_packets_read = 0;
199 static unsigned long num_packets_written = 0;
201 /* Time code of packet, derived from packet_preamble */
202 static time_t ts_sec = 0;
203 static guint32 ts_usec = 0;
204 static char *ts_fmt = NULL;
205 static struct tm timecode_default;
207 static char new_date_fmt = 0;
208 static unsigned char* pkt_lnstart;
211 static const char *input_filename;
212 static FILE *input_file = NULL;
214 static const char *output_filename;
215 static FILE *output_file = NULL;
217 /* Offset base to parse */
218 static unsigned long offset_base = 16;
222 /* ----- State machine -----------------------------------------------------------*/
224 /* Current state of parser */
226 INIT, /* Waiting for start of new packet */
227 START_OF_LINE, /* Starting from beginning of line */
228 READ_OFFSET, /* Just read the offset */
229 READ_BYTE, /* Just read a byte */
230 READ_TEXT /* Just read text - ignore until EOL */
232 static parser_state_t state = INIT;
234 static const char *state_str[] = {"Init",
241 static const char *token_str[] = {"",
249 /* ----- Skeleton Packet Headers --------------------------------------------------*/
257 static hdr_ethernet_t HDR_ETHERNET = {
258 {0x0a, 0x02, 0x02, 0x02, 0x02, 0x02},
259 {0x0a, 0x01, 0x01, 0x01, 0x01, 0x01},
265 guint16 packet_length;
266 guint16 identification;
271 guint16 hdr_checksum;
276 static hdr_ip_t HDR_IP = {0x45, 0, 0, 0x3412, 0, 0, 0xff, 0, 0, 0x0101010a, 0x0202020a};
278 static struct { /* pseudo header for checksum calculation */
293 static hdr_udp_t HDR_UDP = {0, 0, 0, 0};
307 static hdr_tcp_t HDR_TCP = {0, 0, 0, 0, 0x50, 0, 0, 0, 0};
316 static hdr_sctp_t HDR_SCTP = {0, 0, 0, 0};
328 static hdr_data_chunk_t HDR_DATA_CHUNK = {0, 0, 0, 0, 0, 0, 0};
330 static char tempbuf[64];
332 /*----------------------------------------------------------------------
333 * Stuff for writing a PCap file
335 #define PCAP_MAGIC 0xa1b2c3d4
337 /* "libpcap" file header (minus magic number). */
339 guint32 magic; /* magic */
340 guint16 version_major; /* major version number */
341 guint16 version_minor; /* minor version number */
342 guint32 thiszone; /* GMT to local correction */
343 guint32 sigfigs; /* accuracy of timestamps */
344 guint32 snaplen; /* max length of captured packets, in octets */
345 guint32 network; /* data link type */
348 /* "libpcap" record header. */
350 guint32 ts_sec; /* timestamp seconds */
351 guint32 ts_usec; /* timestamp microseconds */
352 guint32 incl_len; /* number of octets of packet saved in file */
353 guint32 orig_len; /* actual length of packet */
356 /* Link-layer type; see net/bpf.h for details */
357 static unsigned long pcap_link_type = 1; /* Default is DLT-EN10MB */
359 /*----------------------------------------------------------------------
360 * Parse a single hex number
361 * Will abort the program if it can't parse the number
362 * Pass in TRUE if this is an offset, FALSE if not
365 parse_num (const char *str, int offset)
370 num = strtoul(str, &c, offset ? offset_base : 16);
372 fprintf(stderr, "FATAL ERROR: Bad hex number? [%s]\n", str);
378 /*----------------------------------------------------------------------
379 * Write this byte into current packet
382 write_byte (const char *str)
386 num = parse_num(str, FALSE);
387 packet_buf[curr_offset] = (unsigned char) num;
389 if (curr_offset >= max_offset) /* packet full */
393 /*----------------------------------------------------------------------
394 * Remove bytes from the current packet
397 unwrite_bytes (unsigned long nbytes)
399 curr_offset -= nbytes;
402 /*----------------------------------------------------------------------
403 * Compute one's complement checksum (from RFC1071)
406 in_checksum (void *buf, unsigned long count)
408 unsigned long sum = 0;
412 /* This is the inner loop */
413 sum += g_ntohs(* (guint16 *) addr);
418 /* Add left-over byte, if any */
420 sum += g_ntohs(* (guint8 *) addr);
422 /* Fold 32-bit sum to 16 bits */
424 sum = (sum & 0xffff) + (sum >> 16);
430 /* The CRC32C code is taken from draft-ietf-tsvwg-sctpcsum-01.txt.
431 * That code is copyrighted by D. Otis and has been modified.
434 #define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF])
435 static guint32 crc_c[256] =
437 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
438 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
439 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
440 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
441 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
442 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
443 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
444 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
445 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
446 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
447 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
448 0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
449 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
450 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
451 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
452 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
453 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
454 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
455 0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
456 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
457 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
458 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
459 0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
460 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
461 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
462 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
463 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
464 0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
465 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
466 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
467 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
468 0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
469 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
470 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
471 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
472 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
473 0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
474 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
475 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
476 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
477 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
478 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
479 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
480 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
481 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
482 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
483 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
484 0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
485 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
486 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
487 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
488 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
489 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
490 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
491 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
492 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
493 0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
494 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
495 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
496 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
497 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
498 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
499 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
500 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L,
504 crc32c(const guint8* buf, unsigned int len, guint32 crc32_init)
510 for (i = 0; i < len; i++)
511 CRC32C(crc32, buf[i]);
517 finalize_crc32c(guint32 crc32)
520 guint8 byte0,byte1,byte2,byte3;
523 byte0 = result & 0xff;
524 byte1 = (result>>8) & 0xff;
525 byte2 = (result>>16) & 0xff;
526 byte3 = (result>>24) & 0xff;
527 result = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3);
532 number_of_padding_bytes (unsigned long length)
534 unsigned long remainder;
536 remainder = length % 4;
541 return 4 - remainder;
544 /*----------------------------------------------------------------------
545 * Write current packet out
548 write_current_packet (void)
551 int proto_length = 0;
553 int eth_trailer_length = 0;
554 int i, padding_length;
556 struct pcaprec_hdr ph;
558 if (curr_offset > 0) {
559 /* Write the packet */
561 /* Compute packet length */
562 length = curr_offset;
563 if (hdr_data_chunk) { length += sizeof(HDR_DATA_CHUNK) + number_of_padding_bytes(curr_offset); }
564 if (hdr_sctp) { length += sizeof(HDR_SCTP); }
565 if (hdr_udp) { length += sizeof(HDR_UDP); proto_length = length; }
566 if (hdr_tcp) { length += sizeof(HDR_TCP); proto_length = length; }
567 if (hdr_ip) { length += sizeof(HDR_IP); ip_length = length; }
569 length += sizeof(HDR_ETHERNET);
572 eth_trailer_length = 60 - length;
577 /* Write PCAP header */
578 ph.ts_sec = (guint32)ts_sec;
579 ph.ts_usec = ts_usec;
580 if (ts_fmt == NULL) { ts_usec++; } /* fake packet counter */
581 ph.incl_len = length;
582 ph.orig_len = length;
583 if (fwrite(&ph, sizeof(ph), 1, output_file) != 1)
584 goto write_current_packet_err;
586 /* Write Ethernet header */
588 HDR_ETHERNET.l3pid = g_htons(hdr_ethernet_proto);
589 if (fwrite(&HDR_ETHERNET, sizeof(HDR_ETHERNET), 1, output_file) != 1)
590 goto write_current_packet_err;
593 /* Write IP header */
595 HDR_IP.packet_length = g_htons(ip_length);
596 HDR_IP.protocol = (guint8) hdr_ip_proto;
597 HDR_IP.hdr_checksum = 0;
598 HDR_IP.hdr_checksum = in_checksum(&HDR_IP, sizeof(HDR_IP));
599 if (fwrite(&HDR_IP, sizeof(HDR_IP), 1, output_file) != 1)
600 goto write_current_packet_err;
603 /* initialize pseudo header for checksum calculation */
604 pseudoh.src_addr = HDR_IP.src_addr;
605 pseudoh.dest_addr = HDR_IP.dest_addr;
607 pseudoh.protocol = (guint8) hdr_ip_proto;
608 pseudoh.length = g_htons(proto_length);
610 /* Write UDP header */
613 HDR_UDP.source_port = g_htons(hdr_src_port);
614 HDR_UDP.dest_port = g_htons(hdr_dest_port);
615 HDR_UDP.length = g_htons(proto_length);
617 /* Note: g_ntohs()/g_htons() macro arg may be eval'd twice so calc value before invoking macro */
618 HDR_UDP.checksum = 0;
619 x16 = in_checksum(&pseudoh, sizeof(pseudoh));
621 x16 = in_checksum(&HDR_UDP, sizeof(HDR_UDP));
623 x16 = in_checksum(packet_buf, curr_offset);
625 x16 = (u & 0xffff) + (u>>16);
626 HDR_UDP.checksum = g_htons(x16);
627 if (HDR_UDP.checksum == 0) /* differentiate between 'none' and 0 */
628 HDR_UDP.checksum = g_htons(1);
630 if (fwrite(&HDR_UDP, sizeof(HDR_UDP), 1, output_file) != 1)
631 goto write_current_packet_err;
634 /* Write TCP header */
637 HDR_TCP.source_port = g_htons(hdr_src_port);
638 HDR_TCP.dest_port = g_htons(hdr_dest_port);
639 /* HDR_TCP.seq_num already correct */
640 HDR_TCP.window = g_htons(0x2000);
642 /* Note: g_ntohs()/g_htons() macro arg may be eval'd twice so calc value before invoking macro */
643 HDR_TCP.checksum = 0;
644 x16 = in_checksum(&pseudoh, sizeof(pseudoh));
646 x16 = in_checksum(&HDR_TCP, sizeof(HDR_TCP));
648 x16 = in_checksum(packet_buf, curr_offset);
650 x16 = (u & 0xffff) + (u>>16);
651 HDR_TCP.checksum = g_htons(x16);
652 if (HDR_TCP.checksum == 0) /* differentiate between 'none' and 0 */
653 HDR_TCP.checksum = g_htons(1);
655 if (fwrite(&HDR_TCP, sizeof(HDR_TCP), 1, output_file) != 1)
656 goto write_current_packet_err;
659 /* Compute DATA chunk header and append padding */
660 if (hdr_data_chunk) {
661 HDR_DATA_CHUNK.type = hdr_data_chunk_type;
662 HDR_DATA_CHUNK.bits = hdr_data_chunk_bits;
663 HDR_DATA_CHUNK.length = g_htons(curr_offset + sizeof(HDR_DATA_CHUNK));
664 HDR_DATA_CHUNK.tsn = g_htonl(hdr_data_chunk_tsn);
665 HDR_DATA_CHUNK.sid = g_htons(hdr_data_chunk_sid);
666 HDR_DATA_CHUNK.ssn = g_htons(hdr_data_chunk_ssn);
667 HDR_DATA_CHUNK.ppid = g_htonl(hdr_data_chunk_ppid);
669 padding_length = number_of_padding_bytes(curr_offset);
670 for (i=0; i<padding_length; i++)
674 /* Write SCTP header */
677 HDR_SCTP.src_port = g_htons(hdr_sctp_src);
678 HDR_SCTP.dest_port = g_htons(hdr_sctp_dest);
679 HDR_SCTP.tag = g_htonl(hdr_sctp_tag);
680 HDR_SCTP.checksum = g_htonl(0);
681 HDR_SCTP.checksum = crc32c((guint8 *)&HDR_SCTP, sizeof(HDR_SCTP), ~0L);
683 HDR_SCTP.checksum = crc32c((guint8 *)&HDR_DATA_CHUNK, sizeof(HDR_DATA_CHUNK), HDR_SCTP.checksum);
684 /* Note: g_ntohl() macro arg may be eval'd twice so calc value before invoking macro */
685 x32 = finalize_crc32c(crc32c(packet_buf, curr_offset, HDR_SCTP.checksum));
686 HDR_SCTP.checksum = g_htonl(x32);
688 if (fwrite(&HDR_SCTP, sizeof(HDR_SCTP), 1, output_file) != 1)
689 goto write_current_packet_err;
692 /* Write DATA chunk header */
693 if (hdr_data_chunk) {
694 if (fwrite(&HDR_DATA_CHUNK, sizeof(HDR_DATA_CHUNK), 1, output_file) != 1)
695 goto write_current_packet_err;
698 if (fwrite(packet_buf, curr_offset, 1, output_file) != 1)
699 goto write_current_packet_err;
701 /* Write Ethernet trailer */
702 if (hdr_ethernet && eth_trailer_length > 0) {
703 memset(tempbuf, 0, eth_trailer_length);
704 if (fwrite(tempbuf, eth_trailer_length, 1, output_file) != 1)
705 goto write_current_packet_err;
709 fprintf(stderr, "Wrote packet of %lu bytes at %u\n", curr_offset, g_ntohl(HDR_TCP.seq_num));
710 num_packets_written ++;
712 HDR_TCP.seq_num = g_ntohl(HDR_TCP.seq_num) + curr_offset;
713 HDR_TCP.seq_num = g_htonl(HDR_TCP.seq_num);
715 packet_start += curr_offset;
719 write_current_packet_err:
720 fprintf(stderr, "File write error [%s] : %s\n",
721 output_filename, g_strerror(errno));
725 /*----------------------------------------------------------------------
726 * Write the PCap file header
729 write_file_header (void)
733 fh.magic = PCAP_MAGIC;
734 fh.version_major = 2;
735 fh.version_minor = 4;
739 fh.network = pcap_link_type;
741 if (fwrite(&fh, sizeof(fh), 1, output_file) != 1) {
742 fprintf(stderr, "File write error [%s] : %s\n",
743 output_filename, g_strerror(errno));
748 /*----------------------------------------------------------------------
749 * Append a token to the packet preamble.
752 append_to_preamble(char *str)
756 if (packet_preamble_len != 0) {
757 if (packet_preamble_len == PACKET_PREAMBLE_MAX_LEN)
758 return; /* no room to add more preamble */
759 /* Add a blank separator between the previous token and this token. */
760 packet_preamble[packet_preamble_len++] = ' ';
762 toklen = strlen(str);
764 if (packet_preamble_len + toklen > PACKET_PREAMBLE_MAX_LEN)
765 return; /* no room to add the token to the preamble */
766 g_strlcpy(&packet_preamble[packet_preamble_len], str, PACKET_PREAMBLE_MAX_LEN);
767 packet_preamble_len += (int) toklen;
770 char xs[PACKET_PREAMBLE_MAX_LEN];
771 g_strlcpy(xs, packet_preamble, PACKET_PREAMBLE_MAX_LEN);
772 while ((c = strchr(xs, '\r')) != NULL) *c=' ';
773 fprintf (stderr, "[[append_to_preamble: \"%s\"]]", xs);
778 /*----------------------------------------------------------------------
779 * Parse the preamble to get the timecode.
783 parse_preamble (void)
792 * If no "-t" flag was specified, don't attempt to parse a packet
793 * preamble to extract a time stamp.
799 * Initialize to today localtime, just in case not all fields
800 * of the date and time are specified.
803 timecode = timecode_default;
807 * Null-terminate the preamble.
809 packet_preamble[packet_preamble_len] = '\0';
811 /* Ensure preamble has more than two chars before attempting to parse.
812 * This should cover line breaks etc that get counted.
814 if ( strlen(packet_preamble) > 2 ) {
815 /* Get Time leaving subseconds */
816 subsecs = strptime( packet_preamble, ts_fmt, &timecode );
817 if (subsecs != NULL) {
818 /* Get the long time from the tm structure */
819 /* (will return -1 if failure) */
820 ts_sec = mktime( &timecode );
822 ts_sec = -1; /* we failed to parse it */
824 /* This will ensure incorrectly parsed dates get set to zero */
827 /* Sanitize - remove all '\r' */
829 while ((c = strchr(packet_preamble, '\r')) != NULL) *c=' ';
830 fprintf (stderr, "Failure processing time \"%s\" using time format \"%s\"\n (defaulting to Jan 1,1970 00:00:00 GMT)\n",
831 packet_preamble, ts_fmt);
833 fprintf(stderr, "timecode: %02d/%02d/%d %02d:%02d:%02d %d\n",
834 timecode.tm_mday, timecode.tm_mon, timecode.tm_year,
835 timecode.tm_hour, timecode.tm_min, timecode.tm_sec, timecode.tm_isdst);
837 ts_sec = 0; /* Jan 1,1970: 00:00 GMT; tshark/wireshark will display date/time as adjusted by timezone */
842 /* Parse subseconds */
843 ts_usec = strtol(subsecs, &p, 10);
849 * Convert that number to a number
850 * of microseconds; if it's N digits
851 * long, it's in units of 10^(-N) seconds,
852 * so, to convert it to units of
853 * 10^-6 seconds, we multiply by
856 subseclen = (int) (p - subsecs);
859 * *More* than 6 digits; 6-N is
860 * negative, so we divide by
863 for (i = subseclen - 6; i != 0; i--)
865 } else if (subseclen < 6) {
866 for (i = 6 - subseclen; i != 0; i--)
874 while ((c = strchr(packet_preamble, '\r')) != NULL) *c=' ';
875 fprintf(stderr, "[[parse_preamble: \"%s\"]]\n", packet_preamble);
876 fprintf(stderr, "Format(%s), time(%u), subsecs(%u)\n", ts_fmt, (guint32)ts_sec, ts_usec);
881 packet_preamble_len = 0;
884 /*----------------------------------------------------------------------
888 start_new_packet (void)
891 fprintf(stderr, "Start new packet\n");
893 /* Write out the current packet, if required */
894 write_current_packet();
897 /* Ensure we parse the packet preamble as it may contain the time */
901 /*----------------------------------------------------------------------
902 * Process a directive
905 process_directive (char *str)
907 fprintf(stderr, "\n--- Directive [%s] currently unsupported ---\n", str+10);
911 /*----------------------------------------------------------------------
912 * Parse a single token (called from the scanner)
915 parse_token (token_t token, char *str)
926 * This is implemented as a simple state machine of five states.
927 * State transitions are caused by tokens being received from the
928 * scanner. The code should be self_documenting.
932 /* Sanitize - remove all '\r' */
934 if (str!=NULL) { while ((c = strchr(str, '\r')) != NULL) *c=' '; }
936 fprintf(stderr, "(%s, %s \"%s\") -> (",
937 state_str[state], token_str[token], str ? str : "");
940 /* First token must be treated as a timestamp if time strip format is
942 if (state == INIT || state == START_OF_LINE) {
943 if (ts_fmt != NULL && new_date_fmt) {
950 /* ----- Waiting for new packet -------------------------------------------*/
954 append_to_preamble(str);
957 process_directive(str);
960 num = parse_num(str, TRUE);
962 /* New packet starts here */
965 pkt_lnstart = packet_buf + num;
969 /* Some describing text may be parsed as offset, but the invalid
970 offset will be checked in the state of START_OF_LINE, so
971 we add this transition to gain flexibility */
972 state = START_OF_LINE;
979 /* ----- Processing packet, start of new line -----------------------------*/
983 append_to_preamble(str);
986 process_directive(str);
989 num = parse_num(str, TRUE);
991 /* New packet starts here */
995 } else if ((num - packet_start) != curr_offset) {
997 * The offset we read isn't the one we expected.
998 * This may only mean that we mistakenly interpreted
999 * some text as byte values (e.g., if the text dump
1000 * of packet data included a number with spaces around
1001 * it). If the offset is less than what we expected,
1002 * assume that's the problem, and throw away the putative
1003 * extra byte values.
1005 if (num < curr_offset) {
1006 unwrite_bytes(curr_offset - num);
1007 state = READ_OFFSET;
1009 /* Bad offset; switch to INIT state */
1011 fprintf(stderr, "Inconsistent offset. Expecting %0lX, got %0lX. Ignoring rest of packet\n",
1013 write_current_packet();
1017 state = READ_OFFSET;
1018 pkt_lnstart = packet_buf + num;
1021 state = START_OF_LINE;
1028 /* ----- Processing packet, read offset -----------------------------------*/
1032 /* Record the byte */
1042 state = START_OF_LINE;
1049 /* ----- Processing packet, read byte -------------------------------------*/
1053 /* Record the byte */
1062 if (token == T_EOL) {
1064 state = START_OF_LINE;
1066 /* Here a line of pkt bytes reading is finished
1067 compare the ascii and hex to avoid such situation:
1068 "61 62 20 ab ", when ab is ascii dump then it should
1069 not be treat as byte */
1071 /* s2 is the ASCII string, s1 is the HEX string, e.g, when
1072 s2 = "ab ", s1 = "616220"
1073 we should find out the largest tail of s1 matches the head
1074 of s2, it means the matched part in tail is the ASCII dump
1075 of the head byte. These matched should be rollback */
1076 line_size = curr_offset-(int)(pkt_lnstart-packet_buf);
1077 s2 = (char*)malloc((line_size+1)/4+1);
1078 /* gather the possible pattern */
1079 for(i=0; i<(line_size+1)/4; i++) {
1080 tmp_str[0] = pkt_lnstart[i*3];
1081 tmp_str[1] = pkt_lnstart[i*3+1];
1083 /* it is a valid convertable string */
1084 if (!isxdigit(tmp_str[0]) || !isxdigit(tmp_str[0])) {
1087 s2[i] = (char)strtoul(tmp_str, (char **)NULL, 16);
1089 /* the 3rd entry is not a delimiter, so the possible byte pattern will not shown */
1090 if (!(pkt_lnstart[i*3+2] == ' ')) {
1096 /* If packet line start contains possible byte pattern, the line end
1097 should contain the matched pattern if the user open the -a flag.
1098 The packet will be possible invalid if the byte pattern cannot find
1099 a matched one in the line of packet buffer.*/
1101 if (strncmp(pkt_lnstart+line_size-rollback, s2, rollback) == 0) {
1102 unwrite_bytes(rollback);
1104 /* Not matched. This line contains invalid packet bytes, so
1105 discard the whole line */
1107 unwrite_bytes(line_size);
1117 /* ----- Processing packet, read text -------------------------------------*/
1121 state = START_OF_LINE;
1129 fprintf(stderr, "FATAL ERROR: Bad state (%d)", state);
1134 fprintf(stderr, ", %s)\n", state_str[state]);
1138 /*----------------------------------------------------------------------
1139 * Print usage string and exit
1147 " (" SVNVERSION " from " SVNPATH ")"
1150 "Generate a capture file from an ASCII hexdump of packets.\n"
1151 "See http://www.wireshark.org for more information.\n"
1153 "Usage: text2pcap [options] <infile> <outfile>\n"
1155 "where <infile> specifies input filename (use - for standard input)\n"
1156 " <outfile> specifies output filename (use - for standard output)\n"
1159 " -o hex|oct|dec parse offsets as (h)ex, (o)ctal or (d)ecimal;\n"
1160 " default is hex.\n"
1161 " -t <timefmt> treat the text before the packet as a date/time code;\n"
1162 " the specified argument is a format string of the sort\n"
1163 " supported by strptime.\n"
1164 " Example: The time \"10:15:14.5476\" has the format code\n"
1165 " \"%%H:%%M:%%S.\"\n"
1166 " NOTE: The subsecond component delimiter, '.', must be\n"
1167 " given, but no pattern is required; the remaining\n"
1168 " number is assumed to be fractions of a second.\n"
1169 " NOTE: Date/time fields from the current date/time are\n"
1170 " used as the default for unspecified fields.\n"
1173 " -l <typenum> link-layer type number; default is 1 (Ethernet).\n"
1174 " See the file net/bpf.h for list of numbers.\n"
1175 " Use this option if your dump is a complete hex dump\n"
1176 " of an encapsulated packet and you wish to specify\n"
1177 " the exact type of encapsulation.\n"
1178 " Example: -l 7 for ARCNet packets.\n"
1179 " -m <max-packet> max packet length in output; default is %d\n"
1181 "Prepend dummy header:\n"
1182 " -e <l3pid> prepend dummy Ethernet II header with specified L3PID\n"
1184 " Example: -e 0x806 to specify an ARP packet.\n"
1185 " -i <proto> prepend dummy IP header with specified IP protocol\n"
1187 " Automatically prepends Ethernet header as well.\n"
1189 " -u <srcp>,<destp> prepend dummy UDP header with specified\n"
1190 " dest and source ports (in DECIMAL).\n"
1191 " Automatically prepends Ethernet & IP headers as well.\n"
1192 " Example: -u 1000,69 to make the packets look like\n"
1193 " TFTP/UDP packets.\n"
1194 " -T <srcp>,<destp> prepend dummy TCP header with specified\n"
1195 " dest and source ports (in DECIMAL).\n"
1196 " Automatically prepends Ethernet & IP headers as well.\n"
1197 " Example: -T 50,60\n"
1198 " -s <srcp>,<dstp>,<tag> prepend dummy SCTP header with specified\n"
1199 " dest/source ports and verification tag (in DECIMAL).\n"
1200 " Automatically prepends Ethernet & IP headers as well.\n"
1201 " Example: -s 30,40,34\n"
1202 " -S <srcp>,<dstp>,<ppi> prepend dummy SCTP header with specified\n"
1203 " dest/source ports and verification tag 0.\n"
1204 " Automatically prepends a dummy SCTP DATA\n"
1205 " chunk header with payload protocol identifier ppi.\n"
1206 " Example: -S 30,40,34\n"
1209 " -h display this help and exit.\n"
1210 " -d show detailed debug of parser states.\n"
1211 " -q generate no output at all (automatically turns off -d).\n"
1213 VERSION, MAX_PACKET);
1218 /*----------------------------------------------------------------------
1222 parse_options (int argc, char *argv[])
1228 arg_list_utf_16to8(argc, argv);
1231 /* Scan CLI parameters */
1232 while ((c = getopt(argc, argv, "Ddhqe:i:l:m:o:u:s:S:t:T:")) != -1) {
1234 case '?': usage(); break;
1235 case 'h': usage(); break;
1236 case 'D': new_date_fmt = 1; break;
1237 case 'd': if (!quiet) debug++; break;
1238 case 'q': quiet = TRUE; debug = FALSE; break;
1239 case 'l': pcap_link_type = strtol(optarg, NULL, 0); break;
1240 case 'm': max_offset = strtol(optarg, NULL, 0); break;
1242 if (optarg[0]!='h' && optarg[0] != 'o' && optarg[0] != 'd') {
1243 fprintf(stderr, "Bad argument for '-o': %s\n", optarg);
1247 case 'o': offset_base = 8; break;
1248 case 'h': offset_base = 16; break;
1249 case 'd': offset_base = 10; break;
1253 hdr_ethernet = TRUE;
1254 if (sscanf(optarg, "%lx", &hdr_ethernet_proto) < 1) {
1255 fprintf(stderr, "Bad argument for '-e': %s\n", optarg);
1262 hdr_ip_proto = strtol(optarg, &p, 10);
1263 if (p == optarg || *p != '\0' || hdr_ip_proto < 0 ||
1264 hdr_ip_proto > 255) {
1265 fprintf(stderr, "Bad argument for '-i': %s\n", optarg);
1268 hdr_ethernet = TRUE;
1269 hdr_ethernet_proto = 0x800;
1274 hdr_sctp_src = strtol(optarg, &p, 10);
1275 if (p == optarg || (*p != ',' && *p != '\0')) {
1276 fprintf(stderr, "Bad src port for '-%c'\n", c);
1280 fprintf(stderr, "No dest port specified for '-%c'\n", c);
1285 hdr_sctp_dest = strtol(optarg, &p, 10);
1286 if (p == optarg || (*p != ',' && *p != '\0')) {
1287 fprintf(stderr, "Bad dest port for '-s'\n");
1291 fprintf(stderr, "No tag specified for '-%c'\n", c);
1296 hdr_sctp_tag = strtol(optarg, &p, 10);
1297 if (p == optarg || *p != '\0') {
1298 fprintf(stderr, "Bad tag for '-%c'\n", c);
1304 hdr_ethernet = TRUE;
1305 hdr_ethernet_proto = 0x800;
1309 hdr_data_chunk = TRUE;
1310 hdr_sctp_src = strtol(optarg, &p, 10);
1311 if (p == optarg || (*p != ',' && *p != '\0')) {
1312 fprintf(stderr, "Bad src port for '-%c'\n", c);
1316 fprintf(stderr, "No dest port specified for '-%c'\n", c);
1321 hdr_sctp_dest = strtol(optarg, &p, 10);
1322 if (p == optarg || (*p != ',' && *p != '\0')) {
1323 fprintf(stderr, "Bad dest port for '-s'\n");
1327 fprintf(stderr, "No ppi specified for '-%c'\n", c);
1332 hdr_data_chunk_ppid = strtoul(optarg, &p, 10);
1333 if (p == optarg || *p != '\0') {
1334 fprintf(stderr, "Bad ppi for '-%c'\n", c);
1340 hdr_ethernet = TRUE;
1341 hdr_ethernet_proto = 0x800;
1351 hdr_src_port = strtol(optarg, &p, 10);
1352 if (p == optarg || (*p != ',' && *p != '\0')) {
1353 fprintf(stderr, "Bad src port for '-u'\n");
1357 fprintf(stderr, "No dest port specified for '-u'\n");
1362 hdr_dest_port = strtol(optarg, &p, 10);
1363 if (p == optarg || *p != '\0') {
1364 fprintf(stderr, "Bad dest port for '-u'\n");
1369 hdr_ethernet = TRUE;
1370 hdr_ethernet_proto = 0x800;
1376 hdr_src_port = strtol(optarg, &p, 10);
1377 if (p == optarg || (*p != ',' && *p != '\0')) {
1378 fprintf(stderr, "Bad src port for '-T'\n");
1382 fprintf(stderr, "No dest port specified for '-u'\n");
1387 hdr_dest_port = strtol(optarg, &p, 10);
1388 if (p == optarg || *p != '\0') {
1389 fprintf(stderr, "Bad dest port for '-T'\n");
1394 hdr_ethernet = TRUE;
1395 hdr_ethernet_proto = 0x800;
1403 if (optind >= argc || argc-optind < 2) {
1404 fprintf(stderr, "Must specify input and output filename\n");
1408 if (strcmp(argv[optind], "-")) {
1409 input_filename = g_strdup(argv[optind]);
1410 input_file = ws_fopen(input_filename, "rb");
1412 fprintf(stderr, "Cannot open file [%s] for reading: %s\n",
1413 input_filename, g_strerror(errno));
1417 input_filename = "Standard input";
1421 if (strcmp(argv[optind+1], "-")) {
1422 output_filename = g_strdup(argv[optind+1]);
1423 output_file = ws_fopen(output_filename, "wb");
1425 fprintf(stderr, "Cannot open file [%s] for writing: %s\n",
1426 output_filename, g_strerror(errno));
1430 output_filename = "Standard output";
1431 output_file = stdout;
1434 /* Some validation */
1435 if (pcap_link_type != 1 && hdr_ethernet) {
1436 fprintf(stderr, "Dummy headers (-e, -i, -u, -s, -S -T) cannot be specified with link type override (-l)\n");
1440 /* Set up our variables */
1443 input_filename = "Standard input";
1446 output_file = stdout;
1447 output_filename = "Standard output";
1450 ts_sec = time(0); /* initialize to current time */
1451 timecode_default = *localtime(&ts_sec);
1452 timecode_default.tm_isdst = -1; /* Unknown for now, depends on time given to the strptime() function */
1454 /* Display summary of our state */
1456 fprintf(stderr, "Input from: %s\n", input_filename);
1457 fprintf(stderr, "Output to: %s\n", output_filename);
1459 if (hdr_ethernet) fprintf(stderr, "Generate dummy Ethernet header: Protocol: 0x%0lX\n",
1460 hdr_ethernet_proto);
1461 if (hdr_ip) fprintf(stderr, "Generate dummy IP header: Protocol: %ld\n",
1463 if (hdr_udp) fprintf(stderr, "Generate dummy UDP header: Source port: %ld. Dest port: %ld\n",
1464 hdr_src_port, hdr_dest_port);
1465 if (hdr_tcp) fprintf(stderr, "Generate dummy TCP header: Source port: %ld. Dest port: %ld\n",
1466 hdr_src_port, hdr_dest_port);
1467 if (hdr_sctp) fprintf(stderr, "Generate dummy SCTP header: Source port: %ld. Dest port: %ld. Tag: %ld\n",
1468 hdr_sctp_src, hdr_sctp_dest, hdr_sctp_tag);
1469 if (hdr_data_chunk) fprintf(stderr, "Generate dummy DATA chunk header: TSN: %lu. SID: %d. SSN: %d. PPID: %lu\n",
1470 hdr_data_chunk_tsn, hdr_data_chunk_sid, hdr_data_chunk_ssn, hdr_data_chunk_ppid);
1475 main(int argc, char *argv[])
1477 parse_options(argc, argv);
1479 assert(input_file != NULL);
1480 assert(output_file != NULL);
1482 write_file_header();
1487 write_current_packet();
1489 fclose(output_file);
1491 fprintf(stderr, "\n-------------------------\n");
1493 fprintf(stderr, "Read %ld potential packet%s, wrote %ld packet%s\n",
1494 num_packets_read, (num_packets_read==1) ?"":"s",
1495 num_packets_written, (num_packets_written==1)?"":"s");