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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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.
83 * Just make sure we include the prototype for strptime as well
84 * (needed for glibc 2.2) but make sure we do this only if not
92 # define _XOPEN_SOURCE 600
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"
137 #include "text2pcap.h"
138 #include "svnversion.h"
141 #include <wsutil/unicode-utils.h>
144 /*--- Options --------------------------------------------------------------------*/
147 static int debug = 0;
149 static int quiet = FALSE;
151 /* Dummy Ethernet header */
152 static int hdr_ethernet = FALSE;
153 static unsigned long hdr_ethernet_proto = 0;
155 /* Dummy IP header */
156 static int hdr_ip = FALSE;
157 static long hdr_ip_proto = 0;
159 /* Dummy UDP header */
160 static int hdr_udp = FALSE;
161 static unsigned long hdr_dest_port = 0;
162 static unsigned long hdr_src_port = 0;
164 /* Dummy TCP header */
165 static int hdr_tcp = FALSE;
167 /* Dummy SCTP header */
168 static int hdr_sctp = FALSE;
169 static unsigned long hdr_sctp_src = 0;
170 static unsigned long hdr_sctp_dest = 0;
171 static unsigned long hdr_sctp_tag = 0;
173 /* Dummy DATA chunk header */
174 static int hdr_data_chunk = FALSE;
175 static unsigned char hdr_data_chunk_type = 0;
176 static unsigned char hdr_data_chunk_bits = 3;
177 static unsigned long hdr_data_chunk_tsn = 0;
178 static unsigned short hdr_data_chunk_sid = 0;
179 static unsigned short hdr_data_chunk_ssn = 0;
180 static unsigned long hdr_data_chunk_ppid = 0;
182 /* ASCII text dump identification */
183 static int identify_ascii = FALSE;
185 /*--- Local date -----------------------------------------------------------------*/
187 /* This is where we store the packet currently being built */
188 #define MAX_PACKET 64000
189 static unsigned char packet_buf[MAX_PACKET];
190 static unsigned long header_length;
191 static unsigned long ip_offset;
192 static unsigned long curr_offset;
193 static unsigned long max_offset = MAX_PACKET;
194 static unsigned long packet_start = 0;
195 static void start_new_packet (void);
197 /* This buffer contains strings present before the packet offset 0 */
198 #define PACKET_PREAMBLE_MAX_LEN 2048
199 static unsigned char packet_preamble[PACKET_PREAMBLE_MAX_LEN+1];
200 static int packet_preamble_len = 0;
202 /* Number of packets read and written */
203 static unsigned long num_packets_read = 0;
204 static unsigned long num_packets_written = 0;
205 static long bytes_written = 0;
207 /* Time code of packet, derived from packet_preamble */
208 static time_t ts_sec = 0;
209 static guint32 ts_usec = 0;
210 static char *ts_fmt = NULL;
211 static struct tm timecode_default;
213 static char new_date_fmt = 0;
214 static unsigned char* pkt_lnstart;
217 static const char *input_filename;
218 static FILE *input_file = NULL;
220 static const char *output_filename;
221 static FILE *output_file = NULL;
223 /* Offset base to parse */
224 static unsigned long offset_base = 16;
228 /* ----- State machine -----------------------------------------------------------*/
230 /* Current state of parser */
232 INIT, /* Waiting for start of new packet */
233 START_OF_LINE, /* Starting from beginning of line */
234 READ_OFFSET, /* Just read the offset */
235 READ_BYTE, /* Just read a byte */
236 READ_TEXT /* Just read text - ignore until EOL */
238 static parser_state_t state = INIT;
240 static const char *state_str[] = {"Init",
247 static const char *token_str[] = {"",
255 /* ----- Skeleton Packet Headers --------------------------------------------------*/
263 static hdr_ethernet_t HDR_ETHERNET = {
264 {0x0a, 0x02, 0x02, 0x02, 0x02, 0x02},
265 {0x0a, 0x01, 0x01, 0x01, 0x01, 0x01},
271 guint16 packet_length;
272 guint16 identification;
277 guint16 hdr_checksum;
282 static hdr_ip_t HDR_IP = {0x45, 0, 0, 0x3412, 0, 0, 0xff, 0, 0,
283 #ifdef WORDS_BIGENDIAN
284 0x0a010101, 0x0a020202
286 0x0101010a, 0x0202020a
290 static struct { /* pseudo header for checksum calculation */
305 static hdr_udp_t HDR_UDP = {0, 0, 0, 0};
319 static hdr_tcp_t HDR_TCP = {0, 0, 0, 0, 0x50, 0, 0, 0, 0};
328 static hdr_sctp_t HDR_SCTP = {0, 0, 0, 0};
340 static hdr_data_chunk_t HDR_DATA_CHUNK = {0, 0, 0, 0, 0, 0, 0};
342 static char tempbuf[64];
344 /*----------------------------------------------------------------------
345 * Stuff for writing a PCap file
347 #define PCAP_MAGIC 0xa1b2c3d4
349 /* "libpcap" file header (minus magic number). */
351 guint32 magic; /* magic */
352 guint16 version_major; /* major version number */
353 guint16 version_minor; /* minor version number */
354 guint32 thiszone; /* GMT to local correction */
355 guint32 sigfigs; /* accuracy of timestamps */
356 guint32 snaplen; /* max length of captured packets, in octets */
357 guint32 network; /* data link type */
360 /* "libpcap" record header. */
362 guint32 ts_sec; /* timestamp seconds */
363 guint32 ts_usec; /* timestamp microseconds */
364 guint32 incl_len; /* number of octets of packet saved in file */
365 guint32 orig_len; /* actual length of packet */
368 /* Link-layer type; see net/bpf.h for details */
369 static unsigned long pcap_link_type = 1; /* Default is DLT-EN10MB */
371 /*----------------------------------------------------------------------
372 * Parse a single hex number
373 * Will abort the program if it can't parse the number
374 * Pass in TRUE if this is an offset, FALSE if not
377 parse_num (const char *str, int offset)
382 num = strtoul(str, &c, offset ? offset_base : 16);
384 fprintf(stderr, "FATAL ERROR: Bad hex number? [%s]\n", str);
390 /*----------------------------------------------------------------------
391 * Write this byte into current packet
394 write_byte (const char *str)
398 num = parse_num(str, FALSE);
399 packet_buf[curr_offset] = (unsigned char) num;
401 if (curr_offset >= max_offset) /* packet full */
405 /*----------------------------------------------------------------------
406 * Write a number of bytes into current packet
410 write_bytes(const char bytes[], unsigned long nbytes)
414 if (curr_offset + nbytes < max_offset) {
415 for (i = 0; i < nbytes; i++) {
416 packet_buf[curr_offset] = bytes[i];
422 /*----------------------------------------------------------------------
423 * Remove bytes from the current packet
426 unwrite_bytes (unsigned long nbytes)
428 curr_offset -= nbytes;
431 /*----------------------------------------------------------------------
432 * Compute one's complement checksum (from RFC1071)
435 in_checksum (void *buf, unsigned long count)
437 unsigned long sum = 0;
441 /* This is the inner loop */
442 sum += g_ntohs(* (guint16 *) addr);
447 /* Add left-over byte, if any */
449 sum += g_ntohs(* (guint8 *) addr);
451 /* Fold 32-bit sum to 16 bits */
453 sum = (sum & 0xffff) + (sum >> 16);
459 /* The CRC32C code is taken from draft-ietf-tsvwg-sctpcsum-01.txt.
460 * That code is copyrighted by D. Otis and has been modified.
463 #define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF])
464 static guint32 crc_c[256] =
466 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
467 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
468 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
469 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
470 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
471 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
472 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
473 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
474 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
475 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
476 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
477 0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
478 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
479 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
480 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
481 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
482 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
483 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
484 0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
485 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
486 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
487 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
488 0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
489 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
490 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
491 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
492 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
493 0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
494 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
495 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
496 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
497 0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
498 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
499 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
500 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
501 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
502 0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
503 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
504 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
505 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
506 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
507 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
508 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
509 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
510 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
511 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
512 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
513 0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
514 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
515 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
516 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
517 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
518 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
519 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
520 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
521 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
522 0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
523 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
524 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
525 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
526 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
527 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
528 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
529 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L,
533 crc32c(const guint8* buf, unsigned int len, guint32 crc32_init)
539 for (i = 0; i < len; i++)
540 CRC32C(crc32, buf[i]);
546 finalize_crc32c(guint32 crc32)
549 guint8 byte0,byte1,byte2,byte3;
552 byte0 = result & 0xff;
553 byte1 = (result>>8) & 0xff;
554 byte2 = (result>>16) & 0xff;
555 byte3 = (result>>24) & 0xff;
556 result = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3);
561 number_of_padding_bytes (unsigned long length)
565 remainder = length % 4;
570 return 4 - remainder;
573 /*----------------------------------------------------------------------
574 * Write current packet out
577 write_current_packet (void)
579 unsigned long length = 0;
580 guint16 padding_length = 0;
583 if (curr_offset > header_length) {
584 /* Write the packet */
586 /* Compute packet length */
587 length = curr_offset;
589 /* Reset curr_offset, since we now write the headers */
592 /* Write Ethernet header */
594 HDR_ETHERNET.l3pid = g_htons(hdr_ethernet_proto);
595 write_bytes((const char *)&HDR_ETHERNET, sizeof(HDR_ETHERNET));
598 /* Write IP header */
600 HDR_IP.packet_length = g_htons(length - ip_offset);
601 HDR_IP.protocol = (guint8) hdr_ip_proto;
602 HDR_IP.hdr_checksum = 0;
603 HDR_IP.hdr_checksum = in_checksum(&HDR_IP, sizeof(HDR_IP));
604 write_bytes((const char *)&HDR_IP, sizeof(HDR_IP));
607 /* Write UDP header */
612 /* initialize pseudo header for checksum calculation */
613 pseudoh.src_addr = HDR_IP.src_addr;
614 pseudoh.dest_addr = HDR_IP.dest_addr;
616 pseudoh.protocol = (guint8) hdr_ip_proto;
617 pseudoh.length = g_htons(length - header_length + sizeof(HDR_UDP));
618 /* initialize the UDP header */
619 HDR_UDP.source_port = g_htons(hdr_src_port);
620 HDR_UDP.dest_port = g_htons(hdr_dest_port);
621 HDR_UDP.length = g_htons(length - header_length + sizeof(HDR_UDP));
622 HDR_UDP.checksum = 0;
623 /* Note: g_ntohs()/g_htons() macro arg may be eval'd twice so calc value before invoking macro */
624 x16 = in_checksum(&pseudoh, sizeof(pseudoh));
626 x16 = in_checksum(&HDR_UDP, sizeof(HDR_UDP));
628 x16 = in_checksum(packet_buf + header_length, length - header_length);
630 x16 = (u & 0xffff) + (u>>16);
631 HDR_UDP.checksum = g_htons(x16);
632 if (HDR_UDP.checksum == 0) /* differentiate between 'none' and 0 */
633 HDR_UDP.checksum = g_htons(1);
634 write_bytes((const char *)&HDR_UDP, sizeof(HDR_UDP));
637 /* Write TCP header */
642 /* initialize pseudo header for checksum calculation */
643 pseudoh.src_addr = HDR_IP.src_addr;
644 pseudoh.dest_addr = HDR_IP.dest_addr;
646 pseudoh.protocol = (guint8) hdr_ip_proto;
647 pseudoh.length = g_htons(length - header_length + sizeof(HDR_TCP));
648 /* initialize the TCP header */
649 HDR_TCP.source_port = g_htons(hdr_src_port);
650 HDR_TCP.dest_port = g_htons(hdr_dest_port);
651 /* HDR_TCP.seq_num already correct */
652 HDR_TCP.window = g_htons(0x2000);
653 HDR_TCP.checksum = 0;
654 /* Note: g_ntohs()/g_htons() macro arg may be eval'd twice so calc value before invoking macro */
655 x16 = in_checksum(&pseudoh, sizeof(pseudoh));
657 x16 = in_checksum(&HDR_TCP, sizeof(HDR_TCP));
659 x16 = in_checksum(packet_buf + header_length, length - header_length);
661 x16 = (u & 0xffff) + (u>>16);
662 HDR_TCP.checksum = g_htons(x16);
663 if (HDR_TCP.checksum == 0) /* differentiate between 'none' and 0 */
664 HDR_TCP.checksum = g_htons(1);
665 write_bytes((const char *)&HDR_TCP, sizeof(HDR_TCP));
666 HDR_TCP.seq_num = g_ntohl(HDR_TCP.seq_num) + length - header_length;
667 HDR_TCP.seq_num = g_htonl(HDR_TCP.seq_num);
670 /* Write SCTP common header */
674 padding_length = number_of_padding_bytes(length - header_length);
675 HDR_SCTP.src_port = g_htons(hdr_sctp_src);
676 HDR_SCTP.dest_port = g_htons(hdr_sctp_dest);
677 HDR_SCTP.tag = g_htonl(hdr_sctp_tag);
678 HDR_SCTP.checksum = g_htonl(0);
679 HDR_SCTP.checksum = crc32c((guint8 *)&HDR_SCTP, sizeof(HDR_SCTP), ~0L);
680 if (hdr_data_chunk) {
681 HDR_SCTP.checksum = crc32c((guint8 *)&HDR_DATA_CHUNK, sizeof(HDR_DATA_CHUNK), HDR_SCTP.checksum);
682 HDR_SCTP.checksum = crc32c((guint8 *)packet_buf + header_length, length - header_length, HDR_SCTP.checksum);
683 HDR_SCTP.checksum = crc32c((guint8 *)&zero, padding_length, HDR_SCTP.checksum);
685 HDR_SCTP.checksum = crc32c((guint8 *)packet_buf + header_length, length - header_length, HDR_SCTP.checksum);
687 HDR_SCTP.checksum = finalize_crc32c(HDR_SCTP.checksum);
688 HDR_SCTP.checksum = g_htonl(HDR_SCTP.checksum);
689 write_bytes((const char *)&HDR_SCTP, sizeof(HDR_SCTP));
692 /* Compute DATA chunk header and append padding */
693 if (hdr_data_chunk) {
694 HDR_DATA_CHUNK.type = hdr_data_chunk_type;
695 HDR_DATA_CHUNK.bits = hdr_data_chunk_bits;
696 HDR_DATA_CHUNK.length = g_htons(length - header_length + sizeof(HDR_DATA_CHUNK));
697 HDR_DATA_CHUNK.tsn = g_htonl(hdr_data_chunk_tsn);
698 HDR_DATA_CHUNK.sid = g_htons(hdr_data_chunk_sid);
699 HDR_DATA_CHUNK.ssn = g_htons(hdr_data_chunk_ssn);
700 HDR_DATA_CHUNK.ppid = g_htonl(hdr_data_chunk_ppid);
701 write_bytes((const char *)&HDR_DATA_CHUNK, sizeof(HDR_DATA_CHUNK));
704 /* Reset curr_offset, since we now write the trailers */
705 curr_offset = length;
707 /* Write DATA chunk padding */
708 if (hdr_data_chunk && (padding_length > 0)) {
709 memset(tempbuf, 0, padding_length);
710 write_bytes((const char *)&tempbuf, padding_length);
711 length += padding_length;
714 /* Write Ethernet trailer */
715 if (hdr_ethernet && (length < 60)) {
716 memset(tempbuf, 0, 60 - length);
717 write_bytes((const char *)&tempbuf, 60 - length);
720 if (!libpcap_write_packet(output_file,
724 &bytes_written, &err)) {
725 fprintf(stderr, "File write error [%s] : %s\n",
726 output_filename, g_strerror(err));
729 if (ts_fmt == NULL) {
730 /* fake packet counter */
734 fprintf(stderr, "Wrote packet of %lu bytes.\n", length);
736 num_packets_written ++;
739 packet_start += curr_offset;
740 curr_offset = header_length;
744 /*----------------------------------------------------------------------
745 * Write the PCap file header
748 write_file_header (void)
752 if (!libpcap_write_file_header(output_file, pcap_link_type, 102400,
753 FALSE, &bytes_written, &err)) {
754 fprintf(stderr, "File write error [%s] : %s\n",
755 output_filename, g_strerror(err));
760 /*----------------------------------------------------------------------
761 * Append a token to the packet preamble.
764 append_to_preamble(char *str)
768 if (packet_preamble_len != 0) {
769 if (packet_preamble_len == PACKET_PREAMBLE_MAX_LEN)
770 return; /* no room to add more preamble */
771 /* Add a blank separator between the previous token and this token. */
772 packet_preamble[packet_preamble_len++] = ' ';
774 toklen = strlen(str);
776 if (packet_preamble_len + toklen > PACKET_PREAMBLE_MAX_LEN)
777 return; /* no room to add the token to the preamble */
778 g_strlcpy(&packet_preamble[packet_preamble_len], str, PACKET_PREAMBLE_MAX_LEN);
779 packet_preamble_len += (int) toklen;
782 char xs[PACKET_PREAMBLE_MAX_LEN];
783 g_strlcpy(xs, packet_preamble, PACKET_PREAMBLE_MAX_LEN);
784 while ((c = strchr(xs, '\r')) != NULL) *c=' ';
785 fprintf (stderr, "[[append_to_preamble: \"%s\"]]", xs);
790 /*----------------------------------------------------------------------
791 * Parse the preamble to get the timecode.
795 parse_preamble (void)
804 * If no "-t" flag was specified, don't attempt to parse a packet
805 * preamble to extract a time stamp.
811 * Initialize to today localtime, just in case not all fields
812 * of the date and time are specified.
815 timecode = timecode_default;
819 * Null-terminate the preamble.
821 packet_preamble[packet_preamble_len] = '\0';
823 /* Ensure preamble has more than two chars before attempting to parse.
824 * This should cover line breaks etc that get counted.
826 if (strlen(packet_preamble) > 2) {
827 /* Get Time leaving subseconds */
828 subsecs = strptime( packet_preamble, ts_fmt, &timecode );
829 if (subsecs != NULL) {
830 /* Get the long time from the tm structure */
831 /* (will return -1 if failure) */
832 ts_sec = mktime( &timecode );
834 ts_sec = -1; /* we failed to parse it */
836 /* This will ensure incorrectly parsed dates get set to zero */
838 /* Sanitize - remove all '\r' */
840 while ((c = strchr(packet_preamble, '\r')) != NULL) *c=' ';
841 fprintf (stderr, "Failure processing time \"%s\" using time format \"%s\"\n (defaulting to Jan 1,1970 00:00:00 GMT)\n",
842 packet_preamble, ts_fmt);
844 fprintf(stderr, "timecode: %02d/%02d/%d %02d:%02d:%02d %d\n",
845 timecode.tm_mday, timecode.tm_mon, timecode.tm_year,
846 timecode.tm_hour, timecode.tm_min, timecode.tm_sec, timecode.tm_isdst);
848 ts_sec = 0; /* Jan 1,1970: 00:00 GMT; tshark/wireshark will display date/time as adjusted by timezone */
851 /* Parse subseconds */
852 ts_usec = strtol(subsecs, &p, 10);
858 * Convert that number to a number
859 * of microseconds; if it's N digits
860 * long, it's in units of 10^(-N) seconds,
861 * so, to convert it to units of
862 * 10^-6 seconds, we multiply by
865 subseclen = (int) (p - subsecs);
868 * *More* than 6 digits; 6-N is
869 * negative, so we divide by
872 for (i = subseclen - 6; i != 0; i--)
874 } else if (subseclen < 6) {
875 for (i = 6 - subseclen; i != 0; i--)
883 while ((c = strchr(packet_preamble, '\r')) != NULL) *c=' ';
884 fprintf(stderr, "[[parse_preamble: \"%s\"]]\n", packet_preamble);
885 fprintf(stderr, "Format(%s), time(%u), subsecs(%u)\n", ts_fmt, (guint32)ts_sec, ts_usec);
890 packet_preamble_len = 0;
893 /*----------------------------------------------------------------------
897 start_new_packet (void)
900 fprintf(stderr, "Start new packet\n");
902 /* Write out the current packet, if required */
903 write_current_packet();
906 /* Ensure we parse the packet preamble as it may contain the time */
910 /*----------------------------------------------------------------------
911 * Process a directive
914 process_directive (char *str)
916 fprintf(stderr, "\n--- Directive [%s] currently unsupported ---\n", str+10);
920 /*----------------------------------------------------------------------
921 * Parse a single token (called from the scanner)
924 parse_token (token_t token, char *str)
935 * This is implemented as a simple state machine of five states.
936 * State transitions are caused by tokens being received from the
937 * scanner. The code should be self_documenting.
941 /* Sanitize - remove all '\r' */
943 if (str!=NULL) { while ((c = strchr(str, '\r')) != NULL) *c=' '; }
945 fprintf(stderr, "(%s, %s \"%s\") -> (",
946 state_str[state], token_str[token], str ? str : "");
949 /* First token must be treated as a timestamp if time strip format is
951 if (state == INIT || state == START_OF_LINE) {
952 if (ts_fmt != NULL && new_date_fmt) {
959 /* ----- Waiting for new packet -------------------------------------------*/
963 append_to_preamble(str);
966 process_directive(str);
969 num = parse_num(str, TRUE);
971 /* New packet starts here */
974 pkt_lnstart = packet_buf + num;
978 /* Some describing text may be parsed as offset, but the invalid
979 offset will be checked in the state of START_OF_LINE, so
980 we add this transition to gain flexibility */
981 state = START_OF_LINE;
988 /* ----- Processing packet, start of new line -----------------------------*/
992 append_to_preamble(str);
995 process_directive(str);
998 num = parse_num(str, TRUE);
1000 /* New packet starts here */
1003 state = READ_OFFSET;
1004 } else if ((num - packet_start) != curr_offset) {
1006 * The offset we read isn't the one we expected.
1007 * This may only mean that we mistakenly interpreted
1008 * some text as byte values (e.g., if the text dump
1009 * of packet data included a number with spaces around
1010 * it). If the offset is less than what we expected,
1011 * assume that's the problem, and throw away the putative
1012 * extra byte values.
1014 if (num < curr_offset) {
1015 unwrite_bytes(curr_offset - num);
1016 state = READ_OFFSET;
1018 /* Bad offset; switch to INIT state */
1020 fprintf(stderr, "Inconsistent offset. Expecting %0lX, got %0lX. Ignoring rest of packet\n",
1022 write_current_packet();
1026 state = READ_OFFSET;
1027 pkt_lnstart = packet_buf + num;
1030 state = START_OF_LINE;
1037 /* ----- Processing packet, read offset -----------------------------------*/
1041 /* Record the byte */
1051 state = START_OF_LINE;
1058 /* ----- Processing packet, read byte -------------------------------------*/
1062 /* Record the byte */
1071 if (token == T_EOL) {
1073 state = START_OF_LINE;
1075 if (identify_ascii) {
1076 /* Here a line of pkt bytes reading is finished
1077 compare the ascii and hex to avoid such situation:
1078 "61 62 20 ab ", when ab is ascii dump then it should
1079 not be treat as byte */
1081 /* s2 is the ASCII string, s1 is the HEX string, e.g, when
1082 s2 = "ab ", s1 = "616220"
1083 we should find out the largest tail of s1 matches the head
1084 of s2, it means the matched part in tail is the ASCII dump
1085 of the head byte. These matched should be rollback */
1086 line_size = curr_offset-(int)(pkt_lnstart-packet_buf);
1087 s2 = (char*)g_malloc((line_size+1)/4+1);
1088 /* gather the possible pattern */
1089 for (i = 0; i < (line_size+1)/4; i++) {
1090 tmp_str[0] = pkt_lnstart[i*3];
1091 tmp_str[1] = pkt_lnstart[i*3+1];
1093 /* it is a valid convertable string */
1094 if (!isxdigit(tmp_str[0]) || !isxdigit(tmp_str[0])) {
1097 s2[i] = (char)strtoul(tmp_str, (char **)NULL, 16);
1099 /* the 3rd entry is not a delimiter, so the possible byte pattern will not shown */
1100 if (!(pkt_lnstart[i*3+2] == ' ')) {
1106 /* If packet line start contains possible byte pattern, the line end
1107 should contain the matched pattern if the user open the -a flag.
1108 The packet will be possible invalid if the byte pattern cannot find
1109 a matched one in the line of packet buffer.*/
1111 if (strncmp(pkt_lnstart+line_size-rollback, s2, rollback) == 0) {
1112 unwrite_bytes(rollback);
1114 /* Not matched. This line contains invalid packet bytes, so
1115 discard the whole line */
1117 unwrite_bytes(line_size);
1128 /* ----- Processing packet, read text -------------------------------------*/
1132 state = START_OF_LINE;
1140 fprintf(stderr, "FATAL ERROR: Bad state (%d)", state);
1145 fprintf(stderr, ", %s)\n", state_str[state]);
1149 /*----------------------------------------------------------------------
1150 * Print usage string and exit
1158 " (" SVNVERSION " from " SVNPATH ")"
1161 "Generate a capture file from an ASCII hexdump of packets.\n"
1162 "See http://www.wireshark.org for more information.\n"
1164 "Usage: text2pcap [options] <infile> <outfile>\n"
1166 "where <infile> specifies input filename (use - for standard input)\n"
1167 " <outfile> specifies output filename (use - for standard output)\n"
1170 " -o hex|oct|dec parse offsets as (h)ex, (o)ctal or (d)ecimal;\n"
1171 " default is hex.\n"
1172 " -t <timefmt> treat the text before the packet as a date/time code;\n"
1173 " the specified argument is a format string of the sort\n"
1174 " supported by strptime.\n"
1175 " Example: The time \"10:15:14.5476\" has the format code\n"
1176 " \"%%H:%%M:%%S.\"\n"
1177 " NOTE: The subsecond component delimiter, '.', must be\n"
1178 " given, but no pattern is required; the remaining\n"
1179 " number is assumed to be fractions of a second.\n"
1180 " NOTE: Date/time fields from the current date/time are\n"
1181 " used as the default for unspecified fields.\n"
1182 " -a enable ASCII text dump identification.\n"
1183 " It allows to identify the start of the ASCII text\n"
1184 " dump and not include it in the packet even if it\n"
1185 " looks like HEX dump.\n"
1186 " NOTE: Do not enable it if the input file does not\n"
1187 " contain the ASCII text dump.\n"
1190 " -l <typenum> link-layer type number; default is 1 (Ethernet).\n"
1191 " See the file net/bpf.h for list of numbers.\n"
1192 " Use this option if your dump is a complete hex dump\n"
1193 " of an encapsulated packet and you wish to specify\n"
1194 " the exact type of encapsulation.\n"
1195 " Example: -l 7 for ARCNet packets.\n"
1196 " -m <max-packet> max packet length in output; default is %d\n"
1198 "Prepend dummy header:\n"
1199 " -e <l3pid> prepend dummy Ethernet II header with specified L3PID\n"
1201 " Example: -e 0x806 to specify an ARP packet.\n"
1202 " -i <proto> prepend dummy IP header with specified IP protocol\n"
1204 " Automatically prepends Ethernet header as well.\n"
1206 " -u <srcp>,<destp> prepend dummy UDP header with specified\n"
1207 " dest and source ports (in DECIMAL).\n"
1208 " Automatically prepends Ethernet & IP headers as well.\n"
1209 " Example: -u 1000,69 to make the packets look like\n"
1210 " TFTP/UDP packets.\n"
1211 " -T <srcp>,<destp> prepend dummy TCP header with specified\n"
1212 " dest and source ports (in DECIMAL).\n"
1213 " Automatically prepends Ethernet & IP headers as well.\n"
1214 " Example: -T 50,60\n"
1215 " -s <srcp>,<dstp>,<tag> prepend dummy SCTP header with specified\n"
1216 " dest/source ports and verification tag (in DECIMAL).\n"
1217 " Automatically prepends Ethernet & IP headers as well.\n"
1218 " Example: -s 30,40,34\n"
1219 " -S <srcp>,<dstp>,<ppi> prepend dummy SCTP header with specified\n"
1220 " dest/source ports and verification tag 0.\n"
1221 " Automatically prepends a dummy SCTP DATA\n"
1222 " chunk header with payload protocol identifier ppi.\n"
1223 " Example: -S 30,40,34\n"
1226 " -h display this help and exit.\n"
1227 " -d show detailed debug of parser states.\n"
1228 " -q generate no output at all (automatically turns off -d).\n"
1230 VERSION, MAX_PACKET);
1235 /*----------------------------------------------------------------------
1239 parse_options (int argc, char *argv[])
1245 arg_list_utf_16to8(argc, argv);
1248 /* Scan CLI parameters */
1249 while ((c = getopt(argc, argv, "Ddhqe:i:l:m:o:u:s:S:t:T:a")) != -1) {
1251 case '?': usage(); break;
1252 case 'h': usage(); break;
1253 case 'D': new_date_fmt = 1; break;
1254 case 'd': if (!quiet) debug++; break;
1255 case 'q': quiet = TRUE; debug = FALSE; break;
1256 case 'l': pcap_link_type = strtol(optarg, NULL, 0); break;
1257 case 'm': max_offset = strtol(optarg, NULL, 0); break;
1259 if (optarg[0]!='h' && optarg[0] != 'o' && optarg[0] != 'd') {
1260 fprintf(stderr, "Bad argument for '-o': %s\n", optarg);
1264 case 'o': offset_base = 8; break;
1265 case 'h': offset_base = 16; break;
1266 case 'd': offset_base = 10; break;
1270 hdr_ethernet = TRUE;
1271 if (sscanf(optarg, "%lx", &hdr_ethernet_proto) < 1) {
1272 fprintf(stderr, "Bad argument for '-e': %s\n", optarg);
1279 hdr_ip_proto = strtol(optarg, &p, 10);
1280 if (p == optarg || *p != '\0' || hdr_ip_proto < 0 ||
1281 hdr_ip_proto > 255) {
1282 fprintf(stderr, "Bad argument for '-i': %s\n", optarg);
1285 hdr_ethernet = TRUE;
1286 hdr_ethernet_proto = 0x800;
1291 hdr_data_chunk = FALSE;
1294 hdr_sctp_src = strtol(optarg, &p, 10);
1295 if (p == optarg || (*p != ',' && *p != '\0')) {
1296 fprintf(stderr, "Bad src port for '-%c'\n", c);
1300 fprintf(stderr, "No dest port specified for '-%c'\n", c);
1305 hdr_sctp_dest = strtol(optarg, &p, 10);
1306 if (p == optarg || (*p != ',' && *p != '\0')) {
1307 fprintf(stderr, "Bad dest port for '-s'\n");
1311 fprintf(stderr, "No tag specified for '-%c'\n", c);
1316 hdr_sctp_tag = strtol(optarg, &p, 10);
1317 if (p == optarg || *p != '\0') {
1318 fprintf(stderr, "Bad tag for '-%c'\n", c);
1324 hdr_ethernet = TRUE;
1325 hdr_ethernet_proto = 0x800;
1329 hdr_data_chunk = TRUE;
1332 hdr_sctp_src = strtol(optarg, &p, 10);
1333 if (p == optarg || (*p != ',' && *p != '\0')) {
1334 fprintf(stderr, "Bad src port for '-%c'\n", c);
1338 fprintf(stderr, "No dest port specified for '-%c'\n", c);
1343 hdr_sctp_dest = strtol(optarg, &p, 10);
1344 if (p == optarg || (*p != ',' && *p != '\0')) {
1345 fprintf(stderr, "Bad dest port for '-s'\n");
1349 fprintf(stderr, "No ppi specified for '-%c'\n", c);
1354 hdr_data_chunk_ppid = strtoul(optarg, &p, 10);
1355 if (p == optarg || *p != '\0') {
1356 fprintf(stderr, "Bad ppi for '-%c'\n", c);
1362 hdr_ethernet = TRUE;
1363 hdr_ethernet_proto = 0x800;
1374 hdr_data_chunk = FALSE;
1375 hdr_src_port = strtol(optarg, &p, 10);
1376 if (p == optarg || (*p != ',' && *p != '\0')) {
1377 fprintf(stderr, "Bad src port for '-u'\n");
1381 fprintf(stderr, "No dest port specified for '-u'\n");
1386 hdr_dest_port = strtol(optarg, &p, 10);
1387 if (p == optarg || *p != '\0') {
1388 fprintf(stderr, "Bad dest port for '-u'\n");
1393 hdr_ethernet = TRUE;
1394 hdr_ethernet_proto = 0x800;
1401 hdr_data_chunk = FALSE;
1402 hdr_src_port = strtol(optarg, &p, 10);
1403 if (p == optarg || (*p != ',' && *p != '\0')) {
1404 fprintf(stderr, "Bad src port for '-T'\n");
1408 fprintf(stderr, "No dest port specified for '-u'\n");
1413 hdr_dest_port = strtol(optarg, &p, 10);
1414 if (p == optarg || *p != '\0') {
1415 fprintf(stderr, "Bad dest port for '-T'\n");
1420 hdr_ethernet = TRUE;
1421 hdr_ethernet_proto = 0x800;
1425 identify_ascii = TRUE;
1433 if (optind >= argc || argc-optind < 2) {
1434 fprintf(stderr, "Must specify input and output filename\n");
1438 if (strcmp(argv[optind], "-")) {
1439 input_filename = g_strdup(argv[optind]);
1440 input_file = ws_fopen(input_filename, "rb");
1442 fprintf(stderr, "Cannot open file [%s] for reading: %s\n",
1443 input_filename, g_strerror(errno));
1447 input_filename = "Standard input";
1451 if (strcmp(argv[optind+1], "-")) {
1452 output_filename = g_strdup(argv[optind+1]);
1453 output_file = ws_fopen(output_filename, "wb");
1455 fprintf(stderr, "Cannot open file [%s] for writing: %s\n",
1456 output_filename, g_strerror(errno));
1460 output_filename = "Standard output";
1461 output_file = stdout;
1464 /* Some validation */
1465 if (pcap_link_type != 1 && hdr_ethernet) {
1466 fprintf(stderr, "Dummy headers (-e, -i, -u, -s, -S -T) cannot be specified with link type override (-l)\n");
1470 /* Set up our variables */
1473 input_filename = "Standard input";
1476 output_file = stdout;
1477 output_filename = "Standard output";
1480 ts_sec = time(0); /* initialize to current time */
1481 timecode_default = *localtime(&ts_sec);
1482 timecode_default.tm_isdst = -1; /* Unknown for now, depends on time given to the strptime() function */
1484 /* Display summary of our state */
1486 fprintf(stderr, "Input from: %s\n", input_filename);
1487 fprintf(stderr, "Output to: %s\n", output_filename);
1489 if (hdr_ethernet) fprintf(stderr, "Generate dummy Ethernet header: Protocol: 0x%0lX\n",
1490 hdr_ethernet_proto);
1491 if (hdr_ip) fprintf(stderr, "Generate dummy IP header: Protocol: %ld\n",
1493 if (hdr_udp) fprintf(stderr, "Generate dummy UDP header: Source port: %ld. Dest port: %ld\n",
1494 hdr_src_port, hdr_dest_port);
1495 if (hdr_tcp) fprintf(stderr, "Generate dummy TCP header: Source port: %ld. Dest port: %ld\n",
1496 hdr_src_port, hdr_dest_port);
1497 if (hdr_sctp) fprintf(stderr, "Generate dummy SCTP header: Source port: %ld. Dest port: %ld. Tag: %ld\n",
1498 hdr_sctp_src, hdr_sctp_dest, hdr_sctp_tag);
1499 if (hdr_data_chunk) fprintf(stderr, "Generate dummy DATA chunk header: TSN: %lu. SID: %d. SSN: %d. PPID: %lu\n",
1500 hdr_data_chunk_tsn, hdr_data_chunk_sid, hdr_data_chunk_ssn, hdr_data_chunk_ppid);
1505 main(int argc, char *argv[])
1507 parse_options(argc, argv);
1509 assert(input_file != NULL);
1510 assert(output_file != NULL);
1512 write_file_header();
1516 header_length += sizeof(HDR_ETHERNET);
1519 ip_offset = header_length;
1520 header_length += sizeof(HDR_IP);
1523 header_length += sizeof(HDR_SCTP);
1525 if (hdr_data_chunk) {
1526 header_length += sizeof(HDR_DATA_CHUNK);
1529 header_length += sizeof(HDR_TCP);
1532 header_length += sizeof(HDR_UDP);
1534 curr_offset = header_length;
1539 write_current_packet();
1541 fclose(output_file);
1543 fprintf(stderr, "\n-------------------------\n");
1545 fprintf(stderr, "Read %ld potential packet%s, wrote %ld packet%s\n",
1546 num_packets_read, (num_packets_read == 1) ? "" : "s",
1547 num_packets_written, (num_packets_written == 1) ? "" : "s");