1 /**-*-C-*-**********************************************************************
5 * Utility to convert an ASCII hexdump into a libpcap-format capture file
7 * (c) Copyright 2001 Ashok Narayanan <ashokn@cisco.com>
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 *******************************************************************************/
29 /*******************************************************************************
31 * This utility reads in an ASCII hexdump of this common format:
33 * 00000000 00 E0 1E A7 05 6F 00 10 5A A0 B9 12 08 00 46 00 .....o..Z.....F.
34 * 00000010 03 68 00 00 00 00 0A 2E EE 33 0F 19 08 7F 0F 19 .h.......3...
\7f..
35 * 00000020 03 80 94 04 00 00 10 01 16 A2 0A 00 03 50 00 0C .............P..
36 * 00000030 01 01 0F 19 03 80 11 01 1E 61 00 0C 03 01 0F 19 .........a......
38 * Each bytestring line consists of an offset, one or more bytes, and
39 * text at the end. An offset is defined as a hex string of more than
40 * two characters. A byte is defined as a hex string of exactly two
41 * characters. The text at the end is ignored, as is any text before
42 * the offset. Bytes read from a bytestring line are added to the
43 * current packet only if all the following conditions are satisfied:
45 * - No text appears between the offset and the bytes (any bytes appearing after
46 * such text would be ignored)
48 * - The offset must be arithmetically correct, i.e. if the offset is 00000020, then
49 * exactly 32 bytes must have been read into this packet before this. If the offset
50 * is wrong, the packet is immediately terminated
52 * A packet start is signaled by a zero offset.
54 * Lines starting with #TEXT2PCAP are directives. These allow the user
55 * to embed instructions into the capture file which allows text2pcap
56 * to take some actions (e.g. specifying the encapsulation
57 * etc.). Currently no directives are implemented.
59 * Lines beginning with # which are not directives are ignored as
60 * comments. Currently all non-hexdump text is ignored by text2pcap;
61 * in the future, text processing may be added, but lines prefixed
62 * with '#' will still be ignored.
64 * The output is a libpcap packet containing Ethernet frames by
65 * default. This program takes options which allow the user to add
66 * dummy Ethernet, IP and UDP or TCP headers to the packets in order
67 * to allow dumps of L3 or higher protocols to be decoded.
69 * Considerable flexibility is built into this code to read hexdumps
70 * of slightly different formats. For example, any text prefixing the
71 * hexdump line is dropped (including mail forwarding '>'). The offset
72 * can be any hex number of four digits or greater.
74 * This converter cannot read a single packet greater than 64KiB-1. Packet
75 * snaplength is automatically set to 64KiB-1.
81 * Just make sure we include the prototype for strptime as well
82 * (needed for glibc 2.2) but make sure we do this only if not
90 # define _XOPEN_SOURCE 600
95 * Defining _XOPEN_SOURCE is needed on some platforms, e.g. platforms
96 * using glibc, to expand the set of things system header files define.
98 * Unfortunately, on other platforms, such as some versions of Solaris
99 * (including Solaris 10), it *reduces* that set as well, causing
100 * strptime() not to be declared, presumably because the version of the
101 * X/Open spec that _XOPEN_SOURCE implies doesn't include strptime() and
102 * blah blah blah namespace pollution blah blah blah.
104 * So we define __EXTENSIONS__ so that "strptime()" is declared.
106 #ifndef __EXTENSIONS__
107 # define __EXTENSIONS__
113 #include <wsutil/file_util.h>
114 #include <wsutil/crash_info.h>
115 #include <ws_version_info.h>
116 #include <wsutil/inet_addr.h>
119 #include <io.h> /* for _setmode */
120 #include <fcntl.h> /* for O_BINARY */
133 #ifndef HAVE_GETOPT_LONG
134 #include "wsutil/wsgetopt.h"
137 #ifndef HAVE_STRPTIME
138 # include "wsutil/strptime.h"
141 #include "writecap/pcapio.h"
142 #include "text2pcap.h"
144 #include "wiretap/wtap.h"
147 #include <wsutil/unicode-utils.h>
150 /*--- Options --------------------------------------------------------------------*/
153 static gboolean use_pcapng = FALSE;
156 static int debug = 0;
158 static int quiet = FALSE;
160 /* Dummy Ethernet header */
161 static int hdr_ethernet = FALSE;
162 static guint32 hdr_ethernet_proto = 0;
164 /* Dummy IP header */
165 static int hdr_ip = FALSE;
166 static int hdr_ipv6 = FALSE;
167 static long hdr_ip_proto = 0;
169 /* Destination and source addresses for IP header */
170 static guint32 hdr_ip_dest_addr = 0;
171 static guint32 hdr_ip_src_addr = 0;
172 static struct e_in6_addr hdr_ipv6_dest_addr = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
173 static struct e_in6_addr hdr_ipv6_src_addr = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
174 static struct e_in6_addr NO_IPv6_ADDRESS = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
176 /* Dummy UDP header */
177 static int hdr_udp = FALSE;
178 static guint32 hdr_dest_port = 0;
179 static guint32 hdr_src_port = 0;
181 /* Dummy TCP header */
182 static int hdr_tcp = FALSE;
184 /* TCP sequence numbers when has_direction is true */
185 static guint32 tcp_in_seq_num = 0;
186 static guint32 tcp_out_seq_num = 0;
188 /* Dummy SCTP header */
189 static int hdr_sctp = FALSE;
190 static guint32 hdr_sctp_src = 0;
191 static guint32 hdr_sctp_dest = 0;
192 static guint32 hdr_sctp_tag = 0;
194 /* Dummy DATA chunk header */
195 static int hdr_data_chunk = FALSE;
196 static guint8 hdr_data_chunk_type = 0;
197 static guint8 hdr_data_chunk_bits = 0;
198 static guint32 hdr_data_chunk_tsn = 0;
199 static guint16 hdr_data_chunk_sid = 0;
200 static guint16 hdr_data_chunk_ssn = 0;
201 static guint32 hdr_data_chunk_ppid = 0;
203 /* ASCII text dump identification */
204 static int identify_ascii = FALSE;
206 static gboolean has_direction = FALSE;
207 static guint32 direction = 0;
209 /*--- Local date -----------------------------------------------------------------*/
211 /* This is where we store the packet currently being built */
212 static guint8 packet_buf[WTAP_MAX_PACKET_SIZE_STANDARD];
213 static guint32 header_length;
214 static guint32 ip_offset;
215 static guint32 curr_offset;
216 static guint32 max_offset = WTAP_MAX_PACKET_SIZE_STANDARD;
217 static guint32 packet_start = 0;
219 static int start_new_packet(gboolean);
221 /* This buffer contains strings present before the packet offset 0 */
222 #define PACKET_PREAMBLE_MAX_LEN 2048
223 static guint8 packet_preamble[PACKET_PREAMBLE_MAX_LEN+1];
224 static int packet_preamble_len = 0;
226 /* Number of packets read and written */
227 static guint32 num_packets_read = 0;
228 static guint32 num_packets_written = 0;
229 static guint64 bytes_written = 0;
231 /* Time code of packet, derived from packet_preamble */
232 static time_t ts_sec = 0;
233 static guint32 ts_nsec = 0;
234 static char *ts_fmt = NULL;
235 static struct tm timecode_default;
237 static guint8* pkt_lnstart;
240 static char *input_filename;
241 static FILE *input_file = NULL;
243 static char *output_filename;
244 static FILE *output_file = NULL;
246 /* Offset base to parse */
247 static guint32 offset_base = 16;
249 extern FILE *text2pcap_in;
251 /* ----- State machine -----------------------------------------------------------*/
253 /* Current state of parser */
255 INIT, /* Waiting for start of new packet */
256 START_OF_LINE, /* Starting from beginning of line */
257 READ_OFFSET, /* Just read the offset */
258 READ_BYTE, /* Just read a byte */
259 READ_TEXT /* Just read text - ignore until EOL */
261 static parser_state_t state = INIT;
263 static const char *state_str[] = {"Init",
270 static const char *token_str[] = {"",
278 /* ----- Skeleton Packet Headers --------------------------------------------------*/
286 static hdr_ethernet_t HDR_ETHERNET = {
287 {0x0a, 0x02, 0x02, 0x02, 0x02, 0x02},
288 {0x0a, 0x01, 0x01, 0x01, 0x01, 0x01},
294 guint16 packet_length;
295 guint16 identification;
300 guint16 hdr_checksum;
305 static hdr_ip_t HDR_IP = {0x45, 0, 0, 0x3412, 0, 0, 0xff, 0, 0,
306 #ifdef WORDS_BIGENDIAN
307 0x0a010101, 0x0a020202
309 0x0101010a, 0x0202020a
313 /* Fixed IP address values */
314 #ifdef WORDS_BIGENDIAN
315 #define IP_SRC 0x0a010101
316 #define IP_DST 0x0a020202
318 #define IP_SRC 0x0101010a
319 #define IP_DST 0x0202020a
322 static struct { /* pseudo header for checksum calculation */
331 /* headers taken from glibc */
336 guint32 ip6_un1_flow; /* 24 bits of flow-ID */
337 guint16 ip6_un1_plen; /* payload length */
338 guint8 ip6_un1_nxt; /* next header */
339 guint8 ip6_un1_hlim; /* hop limit */
341 guint8 ip6_un2_vfc; /* 4 bits version, 4 bits priority */
343 struct e_in6_addr ip6_src; /* source address */
344 struct e_in6_addr ip6_dst; /* destination address */
347 static hdr_ipv6_t HDR_IPv6;
349 static struct { /* pseudo header ipv6 for checksum calculation */
350 struct e_in6_addr src_addr6;
351 struct e_in6_addr dst_addr6;
364 static hdr_udp_t HDR_UDP = {0, 0, 0, 0};
378 static hdr_tcp_t HDR_TCP = {0, 0, 0, 0, 0x50, 0, 0, 0, 0};
387 static hdr_sctp_t HDR_SCTP = {0, 0, 0, 0};
399 static hdr_data_chunk_t HDR_DATA_CHUNK = {0, 0, 0, 0, 0, 0, 0};
401 static char tempbuf[64];
403 /*----------------------------------------------------------------------
404 * Stuff for writing a PCap file
406 #define PCAP_SNAPLEN 0xffff
408 /* Link-layer type; see http://www.tcpdump.org/linktypes.html for details */
409 static guint32 pcap_link_type = 1; /* Default is LINKTYPE_ETHERNET */
411 /*----------------------------------------------------------------------
412 * Parse a single hex number
413 * Will abort the program if it can't parse the number
414 * Pass in TRUE if this is an offset, FALSE if not
417 parse_num(const char *str, int offset, guint32* num)
422 fprintf(stderr, "FATAL ERROR: str is NULL\n");
426 *num = (guint32)strtoul(str, &c, offset ? offset_base : 16);
428 fprintf(stderr, "FATAL ERROR: Bad hex number? [%s]\n", str);
434 /*----------------------------------------------------------------------
435 * Write this byte into current packet
438 write_byte(const char *str)
442 if (parse_num(str, FALSE, &num) != EXIT_SUCCESS)
445 packet_buf[curr_offset] = (guint8) num;
447 if (curr_offset - header_length >= max_offset) /* packet full */
448 if (start_new_packet(TRUE) != EXIT_SUCCESS)
454 /*----------------------------------------------------------------------
455 * Write a number of bytes into current packet
459 write_bytes (const char bytes[], guint32 nbytes)
463 if (curr_offset + nbytes < WTAP_MAX_PACKET_SIZE_STANDARD) {
464 for (i = 0; i < nbytes; i++) {
465 packet_buf[curr_offset] = bytes[i];
471 /*----------------------------------------------------------------------
472 * Remove bytes from the current packet
475 unwrite_bytes (guint32 nbytes)
477 curr_offset -= nbytes;
480 /*----------------------------------------------------------------------
481 * Compute one's complement checksum (from RFC1071)
484 in_checksum (void *buf, guint32 count)
487 guint16 *addr = (guint16 *)buf;
490 /* This is the inner loop */
491 sum += g_ntohs(* (guint16 *) addr);
496 /* Add left-over byte, if any */
498 sum += g_ntohs(* (guint8 *) addr);
500 /* Fold 32-bit sum to 16 bits */
502 sum = (sum & 0xffff) + (sum >> 16);
508 /* The CRC32C code is taken from draft-ietf-tsvwg-sctpcsum-01.txt.
509 * That code is copyrighted by D. Otis and has been modified.
512 #define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF])
513 static guint32 crc_c[256] =
515 0x00000000U, 0xF26B8303U, 0xE13B70F7U, 0x1350F3F4U,
516 0xC79A971FU, 0x35F1141CU, 0x26A1E7E8U, 0xD4CA64EBU,
517 0x8AD958CFU, 0x78B2DBCCU, 0x6BE22838U, 0x9989AB3BU,
518 0x4D43CFD0U, 0xBF284CD3U, 0xAC78BF27U, 0x5E133C24U,
519 0x105EC76FU, 0xE235446CU, 0xF165B798U, 0x030E349BU,
520 0xD7C45070U, 0x25AFD373U, 0x36FF2087U, 0xC494A384U,
521 0x9A879FA0U, 0x68EC1CA3U, 0x7BBCEF57U, 0x89D76C54U,
522 0x5D1D08BFU, 0xAF768BBCU, 0xBC267848U, 0x4E4DFB4BU,
523 0x20BD8EDEU, 0xD2D60DDDU, 0xC186FE29U, 0x33ED7D2AU,
524 0xE72719C1U, 0x154C9AC2U, 0x061C6936U, 0xF477EA35U,
525 0xAA64D611U, 0x580F5512U, 0x4B5FA6E6U, 0xB93425E5U,
526 0x6DFE410EU, 0x9F95C20DU, 0x8CC531F9U, 0x7EAEB2FAU,
527 0x30E349B1U, 0xC288CAB2U, 0xD1D83946U, 0x23B3BA45U,
528 0xF779DEAEU, 0x05125DADU, 0x1642AE59U, 0xE4292D5AU,
529 0xBA3A117EU, 0x4851927DU, 0x5B016189U, 0xA96AE28AU,
530 0x7DA08661U, 0x8FCB0562U, 0x9C9BF696U, 0x6EF07595U,
531 0x417B1DBCU, 0xB3109EBFU, 0xA0406D4BU, 0x522BEE48U,
532 0x86E18AA3U, 0x748A09A0U, 0x67DAFA54U, 0x95B17957U,
533 0xCBA24573U, 0x39C9C670U, 0x2A993584U, 0xD8F2B687U,
534 0x0C38D26CU, 0xFE53516FU, 0xED03A29BU, 0x1F682198U,
535 0x5125DAD3U, 0xA34E59D0U, 0xB01EAA24U, 0x42752927U,
536 0x96BF4DCCU, 0x64D4CECFU, 0x77843D3BU, 0x85EFBE38U,
537 0xDBFC821CU, 0x2997011FU, 0x3AC7F2EBU, 0xC8AC71E8U,
538 0x1C661503U, 0xEE0D9600U, 0xFD5D65F4U, 0x0F36E6F7U,
539 0x61C69362U, 0x93AD1061U, 0x80FDE395U, 0x72966096U,
540 0xA65C047DU, 0x5437877EU, 0x4767748AU, 0xB50CF789U,
541 0xEB1FCBADU, 0x197448AEU, 0x0A24BB5AU, 0xF84F3859U,
542 0x2C855CB2U, 0xDEEEDFB1U, 0xCDBE2C45U, 0x3FD5AF46U,
543 0x7198540DU, 0x83F3D70EU, 0x90A324FAU, 0x62C8A7F9U,
544 0xB602C312U, 0x44694011U, 0x5739B3E5U, 0xA55230E6U,
545 0xFB410CC2U, 0x092A8FC1U, 0x1A7A7C35U, 0xE811FF36U,
546 0x3CDB9BDDU, 0xCEB018DEU, 0xDDE0EB2AU, 0x2F8B6829U,
547 0x82F63B78U, 0x709DB87BU, 0x63CD4B8FU, 0x91A6C88CU,
548 0x456CAC67U, 0xB7072F64U, 0xA457DC90U, 0x563C5F93U,
549 0x082F63B7U, 0xFA44E0B4U, 0xE9141340U, 0x1B7F9043U,
550 0xCFB5F4A8U, 0x3DDE77ABU, 0x2E8E845FU, 0xDCE5075CU,
551 0x92A8FC17U, 0x60C37F14U, 0x73938CE0U, 0x81F80FE3U,
552 0x55326B08U, 0xA759E80BU, 0xB4091BFFU, 0x466298FCU,
553 0x1871A4D8U, 0xEA1A27DBU, 0xF94AD42FU, 0x0B21572CU,
554 0xDFEB33C7U, 0x2D80B0C4U, 0x3ED04330U, 0xCCBBC033U,
555 0xA24BB5A6U, 0x502036A5U, 0x4370C551U, 0xB11B4652U,
556 0x65D122B9U, 0x97BAA1BAU, 0x84EA524EU, 0x7681D14DU,
557 0x2892ED69U, 0xDAF96E6AU, 0xC9A99D9EU, 0x3BC21E9DU,
558 0xEF087A76U, 0x1D63F975U, 0x0E330A81U, 0xFC588982U,
559 0xB21572C9U, 0x407EF1CAU, 0x532E023EU, 0xA145813DU,
560 0x758FE5D6U, 0x87E466D5U, 0x94B49521U, 0x66DF1622U,
561 0x38CC2A06U, 0xCAA7A905U, 0xD9F75AF1U, 0x2B9CD9F2U,
562 0xFF56BD19U, 0x0D3D3E1AU, 0x1E6DCDEEU, 0xEC064EEDU,
563 0xC38D26C4U, 0x31E6A5C7U, 0x22B65633U, 0xD0DDD530U,
564 0x0417B1DBU, 0xF67C32D8U, 0xE52CC12CU, 0x1747422FU,
565 0x49547E0BU, 0xBB3FFD08U, 0xA86F0EFCU, 0x5A048DFFU,
566 0x8ECEE914U, 0x7CA56A17U, 0x6FF599E3U, 0x9D9E1AE0U,
567 0xD3D3E1ABU, 0x21B862A8U, 0x32E8915CU, 0xC083125FU,
568 0x144976B4U, 0xE622F5B7U, 0xF5720643U, 0x07198540U,
569 0x590AB964U, 0xAB613A67U, 0xB831C993U, 0x4A5A4A90U,
570 0x9E902E7BU, 0x6CFBAD78U, 0x7FAB5E8CU, 0x8DC0DD8FU,
571 0xE330A81AU, 0x115B2B19U, 0x020BD8EDU, 0xF0605BEEU,
572 0x24AA3F05U, 0xD6C1BC06U, 0xC5914FF2U, 0x37FACCF1U,
573 0x69E9F0D5U, 0x9B8273D6U, 0x88D28022U, 0x7AB90321U,
574 0xAE7367CAU, 0x5C18E4C9U, 0x4F48173DU, 0xBD23943EU,
575 0xF36E6F75U, 0x0105EC76U, 0x12551F82U, 0xE03E9C81U,
576 0x34F4F86AU, 0xC69F7B69U, 0xD5CF889DU, 0x27A40B9EU,
577 0x79B737BAU, 0x8BDCB4B9U, 0x988C474DU, 0x6AE7C44EU,
578 0xBE2DA0A5U, 0x4C4623A6U, 0x5F16D052U, 0xAD7D5351U,
582 crc32c (const guint8* buf, unsigned int len, guint32 crc32_init)
588 for (i = 0; i < len; i++)
595 finalize_crc32c (guint32 crc)
598 guint8 byte0,byte1,byte2,byte3;
601 byte0 = result & 0xff;
602 byte1 = (result>>8) & 0xff;
603 byte2 = (result>>16) & 0xff;
604 byte3 = (result>>24) & 0xff;
605 result = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3);
610 number_of_padding_bytes (guint32 length)
614 remainder = length % 4;
619 return 4 - remainder;
622 /*----------------------------------------------------------------------
623 * Write current packet out
626 write_current_packet (gboolean cont)
629 guint16 padding_length = 0;
634 if (curr_offset > header_length) {
635 /* Write the packet */
637 /* Is direction indication on with an inbound packet? */
638 gboolean isInbound = has_direction && (direction == 2);
640 /* if defined IPv6 we should rewrite hdr_ethernet_proto anyways */
642 hdr_ethernet_proto = 0x86DD;
646 /* Compute packet length */
647 length = curr_offset;
649 padding_length = number_of_padding_bytes(length - header_length );
653 /* Reset curr_offset, since we now write the headers */
656 /* Write Ethernet header */
658 HDR_ETHERNET.l3pid = g_htons(hdr_ethernet_proto);
659 write_bytes((const char *)&HDR_ETHERNET, sizeof(HDR_ETHERNET));
662 /* Write IP header */
665 HDR_IP.src_addr = hdr_ip_dest_addr ? hdr_ip_dest_addr : IP_DST;
666 HDR_IP.dest_addr = hdr_ip_src_addr? hdr_ip_src_addr : IP_SRC;
669 HDR_IP.src_addr = hdr_ip_src_addr? hdr_ip_src_addr : IP_SRC;
670 HDR_IP.dest_addr = hdr_ip_dest_addr ? hdr_ip_dest_addr : IP_DST;
673 HDR_IP.packet_length = g_htons(length - ip_offset + padding_length);
674 HDR_IP.protocol = (guint8) hdr_ip_proto;
675 HDR_IP.hdr_checksum = 0;
676 HDR_IP.hdr_checksum = in_checksum(&HDR_IP, sizeof(HDR_IP));
677 write_bytes((const char *)&HDR_IP, sizeof(HDR_IP));
678 } else if (hdr_ipv6) {
679 if (memcmp(isInbound ? &hdr_ipv6_dest_addr : &hdr_ipv6_src_addr, &NO_IPv6_ADDRESS, sizeof(struct e_in6_addr)))
680 memcpy(&HDR_IPv6.ip6_src, isInbound ? &hdr_ipv6_dest_addr : &hdr_ipv6_src_addr, sizeof(struct e_in6_addr));
681 if (memcmp(isInbound ? &hdr_ipv6_src_addr : &hdr_ipv6_dest_addr, &NO_IPv6_ADDRESS, sizeof(struct e_in6_addr)))
682 memcpy(&HDR_IPv6.ip6_dst, isInbound ? &hdr_ipv6_src_addr : &hdr_ipv6_dest_addr, sizeof(struct e_in6_addr));
684 HDR_IPv6.ip6_ctlun.ip6_un2_vfc &= 0x0F;
685 HDR_IPv6.ip6_ctlun.ip6_un2_vfc |= (6<< 4);
686 HDR_IPv6.ip6_ctlun.ip6_un1.ip6_un1_plen = g_htons(length - ip_offset + padding_length);
687 HDR_IPv6.ip6_ctlun.ip6_un1.ip6_un1_nxt = (guint8) hdr_ip_proto;
688 HDR_IPv6.ip6_ctlun.ip6_un1.ip6_un1_hlim = 32;
689 write_bytes((const char *)&HDR_IPv6, sizeof(HDR_IPv6));
691 /* initialize pseudo ipv6 header for checksum calculation */
692 pseudoh6.src_addr6 = HDR_IPv6.ip6_src;
693 pseudoh6.dst_addr6 = HDR_IPv6.ip6_dst;
695 pseudoh6.protocol = (guint8) hdr_ip_proto;
696 ihatemacros = g_ntohs(HDR_IPv6.ip6_ctlun.ip6_un1.ip6_un1_plen);
697 pseudoh.length = g_htons(length - ihatemacros + sizeof(HDR_UDP));
701 /* initialize pseudo header for checksum calculation */
702 pseudoh.src_addr = HDR_IP.src_addr;
703 pseudoh.dest_addr = HDR_IP.dest_addr;
705 pseudoh.protocol = (guint8) hdr_ip_proto;
706 pseudoh.length = g_htons(length - header_length + sizeof(HDR_UDP));
709 /* Write UDP header */
714 /* initialize the UDP header */
715 HDR_UDP.source_port = isInbound ? g_htons(hdr_dest_port): g_htons(hdr_src_port);
716 HDR_UDP.dest_port = isInbound ? g_htons(hdr_src_port) : g_htons(hdr_dest_port);
717 HDR_UDP.length = pseudoh.length;
718 HDR_UDP.checksum = 0;
719 /* Note: g_ntohs()/g_htons() macro arg may be eval'd twice so calc value before invoking macro */
720 x16 = hdr_ipv6 ? in_checksum(&pseudoh6, sizeof(pseudoh6)) : in_checksum(&pseudoh, sizeof(pseudoh));
722 x16 = in_checksum(&HDR_UDP, sizeof(HDR_UDP));
724 x16 = in_checksum(packet_buf + header_length, length - header_length);
726 x16 = (u & 0xffff) + (u>>16);
727 HDR_UDP.checksum = g_htons(x16);
728 if (HDR_UDP.checksum == 0) /* differentiate between 'none' and 0 */
729 HDR_UDP.checksum = g_htons(1);
730 write_bytes((const char *)&HDR_UDP, sizeof(HDR_UDP));
733 /* Write TCP header */
738 /* initialize pseudo header for checksum calculation */
739 pseudoh.src_addr = HDR_IP.src_addr;
740 pseudoh.dest_addr = HDR_IP.dest_addr;
742 pseudoh.protocol = (guint8) hdr_ip_proto;
743 pseudoh.length = g_htons(length - header_length + sizeof(HDR_TCP));
744 /* initialize the TCP header */
745 HDR_TCP.source_port = isInbound ? g_htons(hdr_dest_port): g_htons(hdr_src_port);
746 HDR_TCP.dest_port = isInbound ? g_htons(hdr_src_port) : g_htons(hdr_dest_port);
747 /* set ack number if we have direction */
749 HDR_TCP.flags = 0x10;
750 HDR_TCP.ack_num = g_ntohl(isInbound ? tcp_out_seq_num : tcp_in_seq_num);
751 HDR_TCP.ack_num = g_htonl(HDR_TCP.ack_num);
757 HDR_TCP.seq_num = isInbound ? tcp_in_seq_num : tcp_out_seq_num;
758 HDR_TCP.window = g_htons(0x2000);
759 HDR_TCP.checksum = 0;
760 /* Note: g_ntohs()/g_htons() macro arg may be eval'd twice so calc value before invoking macro */
761 x16 = in_checksum(&pseudoh, sizeof(pseudoh));
763 x16 = in_checksum(&HDR_TCP, sizeof(HDR_TCP));
765 x16 = in_checksum(packet_buf + header_length, length - header_length);
767 x16 = (u & 0xffff) + (u>>16);
768 HDR_TCP.checksum = g_htons(x16);
769 if (HDR_TCP.checksum == 0) /* differentiate between 'none' and 0 */
770 HDR_TCP.checksum = g_htons(1);
771 write_bytes((const char *)&HDR_TCP, sizeof(HDR_TCP));
773 tcp_in_seq_num = g_ntohl(tcp_in_seq_num) + length - header_length;
774 tcp_in_seq_num = g_htonl(tcp_in_seq_num);
777 tcp_out_seq_num = g_ntohl(tcp_out_seq_num) + length - header_length;
778 tcp_out_seq_num = g_htonl(tcp_out_seq_num);
782 /* Compute DATA chunk header */
783 if (hdr_data_chunk) {
784 hdr_data_chunk_bits = 0;
785 if (packet_start == 0) {
786 hdr_data_chunk_bits |= 0x02;
789 hdr_data_chunk_bits |= 0x01;
791 HDR_DATA_CHUNK.type = hdr_data_chunk_type;
792 HDR_DATA_CHUNK.bits = hdr_data_chunk_bits;
793 HDR_DATA_CHUNK.length = g_htons(length - header_length + sizeof(HDR_DATA_CHUNK));
794 HDR_DATA_CHUNK.tsn = g_htonl(hdr_data_chunk_tsn);
795 HDR_DATA_CHUNK.sid = g_htons(hdr_data_chunk_sid);
796 HDR_DATA_CHUNK.ssn = g_htons(hdr_data_chunk_ssn);
797 HDR_DATA_CHUNK.ppid = g_htonl(hdr_data_chunk_ppid);
798 hdr_data_chunk_tsn++;
800 hdr_data_chunk_ssn++;
804 /* Write SCTP common header */
808 HDR_SCTP.src_port = isInbound ? g_htons(hdr_sctp_dest): g_htons(hdr_sctp_src);
809 HDR_SCTP.dest_port = isInbound ? g_htons(hdr_sctp_src) : g_htons(hdr_sctp_dest);
810 HDR_SCTP.tag = g_htonl(hdr_sctp_tag);
811 HDR_SCTP.checksum = g_htonl(0);
812 HDR_SCTP.checksum = crc32c((guint8 *)&HDR_SCTP, sizeof(HDR_SCTP), ~0);
813 if (hdr_data_chunk) {
814 HDR_SCTP.checksum = crc32c((guint8 *)&HDR_DATA_CHUNK, sizeof(HDR_DATA_CHUNK), HDR_SCTP.checksum);
815 HDR_SCTP.checksum = crc32c((guint8 *)packet_buf + header_length, length - header_length, HDR_SCTP.checksum);
816 HDR_SCTP.checksum = crc32c((guint8 *)&zero, padding_length, HDR_SCTP.checksum);
818 HDR_SCTP.checksum = crc32c((guint8 *)packet_buf + header_length, length - header_length, HDR_SCTP.checksum);
820 HDR_SCTP.checksum = finalize_crc32c(HDR_SCTP.checksum);
821 HDR_SCTP.checksum = g_htonl(HDR_SCTP.checksum);
822 write_bytes((const char *)&HDR_SCTP, sizeof(HDR_SCTP));
825 /* Write DATA chunk header */
826 if (hdr_data_chunk) {
827 write_bytes((const char *)&HDR_DATA_CHUNK, sizeof(HDR_DATA_CHUNK));
830 /* Reset curr_offset, since we now write the trailers */
831 curr_offset = length;
833 /* Write DATA chunk padding */
834 if (hdr_data_chunk && (padding_length > 0)) {
835 memset(tempbuf, 0, padding_length);
836 write_bytes((const char *)&tempbuf, padding_length);
837 length += padding_length;
840 /* Write Ethernet trailer */
841 if (hdr_ethernet && (length < 60)) {
842 memset(tempbuf, 0, 60 - length);
843 write_bytes((const char *)&tempbuf, 60 - length);
847 success = pcapng_write_enhanced_packet_block(output_file,
853 packet_buf, direction,
854 &bytes_written, &err);
856 success = libpcap_write_packet(output_file,
857 ts_sec, ts_nsec/1000,
860 &bytes_written, &err);
863 fprintf(stderr, "File write error [%s] : %s\n",
864 output_filename, g_strerror(err));
867 if (ts_fmt == NULL) {
868 /* fake packet counter */
875 fprintf(stderr, "Wrote packet of %u bytes.\n", length);
877 num_packets_written++;
880 packet_start += curr_offset - header_length;
881 curr_offset = header_length;
885 /*----------------------------------------------------------------------
886 * Write file header and trailer
889 write_file_header (void)
898 appname = g_strdup_printf("text2pcap (Wireshark) %s", get_ws_vcs_version_info());
899 comment = g_strdup_printf("Generated from input file %s.", input_filename);
900 success = pcapng_write_session_header_block(output_file,
905 -1, /* section_length */
911 success = pcapng_write_interface_description_block(output_file,
925 success = libpcap_write_file_header(output_file, pcap_link_type,
927 &bytes_written, &err);
930 fprintf(stderr, "File write error [%s] : %s\n",
931 output_filename, g_strerror(err));
938 /*----------------------------------------------------------------------
939 * Append a token to the packet preamble.
942 append_to_preamble (char *str)
946 if (packet_preamble_len != 0) {
947 if (packet_preamble_len == PACKET_PREAMBLE_MAX_LEN)
948 return; /* no room to add more preamble */
949 /* Add a blank separator between the previous token and this token. */
950 packet_preamble[packet_preamble_len++] = ' ';
952 toklen = strlen(str);
954 if (packet_preamble_len + toklen > PACKET_PREAMBLE_MAX_LEN)
955 return; /* no room to add the token to the preamble */
956 g_strlcpy(&packet_preamble[packet_preamble_len], str, PACKET_PREAMBLE_MAX_LEN);
957 packet_preamble_len += (int) toklen;
960 char xs[PACKET_PREAMBLE_MAX_LEN];
961 g_strlcpy(xs, packet_preamble, PACKET_PREAMBLE_MAX_LEN);
962 while ((c = strchr(xs, '\r')) != NULL) *c=' ';
963 fprintf (stderr, "[[append_to_preamble: \"%s\"]]", xs);
968 /*----------------------------------------------------------------------
969 * Parse the preamble to get the timecode.
973 parse_preamble (void)
982 * Null-terminate the preamble.
984 packet_preamble[packet_preamble_len] = '\0';
986 fprintf(stderr, "[[parse_preamble: \"%s\"]]\n", packet_preamble);
989 switch (packet_preamble[0]) {
992 direction = 0x00000001;
993 packet_preamble[0] = ' ';
997 direction = 0x00000002;
998 packet_preamble[0] = ' ';
1001 direction = 0x00000000;
1005 while (packet_preamble[i] == ' ' ||
1006 packet_preamble[i] == '\r' ||
1007 packet_preamble[i] == '\t') {
1010 packet_preamble_len -= i;
1011 /* Also move the trailing '\0'. */
1012 memmove(packet_preamble, packet_preamble + i, packet_preamble_len + 1);
1017 * If no "-t" flag was specified, don't attempt to parse the packet
1018 * preamble to extract a time stamp.
1020 if (ts_fmt == NULL) {
1021 /* Clear Preamble */
1022 packet_preamble_len = 0;
1027 * Initialize to today localtime, just in case not all fields
1028 * of the date and time are specified.
1031 timecode = timecode_default;
1034 /* Ensure preamble has more than two chars before attempting to parse.
1035 * This should cover line breaks etc that get counted.
1037 if (strlen(packet_preamble) > 2) {
1038 /* Get Time leaving subseconds */
1039 subsecs = strptime( packet_preamble, ts_fmt, &timecode );
1040 if (subsecs != NULL) {
1041 /* Get the long time from the tm structure */
1042 /* (will return -1 if failure) */
1043 ts_sec = mktime( &timecode );
1045 ts_sec = -1; /* we failed to parse it */
1047 /* This will ensure incorrectly parsed dates get set to zero */
1049 /* Sanitize - remove all '\r' */
1051 while ((c = strchr(packet_preamble, '\r')) != NULL) *c=' ';
1052 fprintf (stderr, "Failure processing time \"%s\" using time format \"%s\"\n (defaulting to Jan 1,1970 00:00:00 GMT)\n",
1053 packet_preamble, ts_fmt);
1055 fprintf(stderr, "timecode: %02d/%02d/%d %02d:%02d:%02d %d\n",
1056 timecode.tm_mday, timecode.tm_mon, timecode.tm_year,
1057 timecode.tm_hour, timecode.tm_min, timecode.tm_sec, timecode.tm_isdst);
1059 ts_sec = 0; /* Jan 1,1970: 00:00 GMT; tshark/wireshark will display date/time as adjusted by timezone */
1062 /* Parse subseconds */
1063 ts_nsec = (guint32)strtol(subsecs, &p, 10);
1069 * Convert that number to a number
1070 * of microseconds; if it's N digits
1071 * long, it's in units of 10^(-N) seconds,
1072 * so, to convert it to units of
1073 * 10^-9 seconds, we multiply by
1076 subseclen = (int) (p - subsecs);
1077 if (subseclen > 9) {
1079 * *More* than 9 digits; 9-N is
1080 * negative, so we divide by
1083 for (i = subseclen - 9; i != 0; i--)
1085 } else if (subseclen < 9) {
1086 for (i = 9 - subseclen; i != 0; i--)
1094 while ((c = strchr(packet_preamble, '\r')) != NULL) *c=' ';
1095 fprintf(stderr, "[[parse_preamble: \"%s\"]]\n", packet_preamble);
1096 fprintf(stderr, "Format(%s), time(%u), subsecs(%u)\n", ts_fmt, (guint32)ts_sec, ts_nsec);
1100 /* Clear Preamble */
1101 packet_preamble_len = 0;
1104 /*----------------------------------------------------------------------
1105 * Start a new packet
1108 start_new_packet (gboolean cont)
1111 fprintf(stderr, "Start new packet (cont = %s).\n", cont ? "TRUE" : "FALSE");
1113 /* Write out the current packet, if required */
1114 if (write_current_packet(cont) != EXIT_SUCCESS)
1115 return EXIT_FAILURE;
1118 /* Ensure we parse the packet preamble as it may contain the time */
1121 return EXIT_SUCCESS;
1124 /*----------------------------------------------------------------------
1125 * Process a directive
1128 process_directive (char *str)
1130 fprintf(stderr, "\n--- Directive [%s] currently unsupported ---\n", str + 10);
1133 /*----------------------------------------------------------------------
1134 * Parse a single token (called from the scanner)
1137 parse_token (token_t token, char *str)
1148 * This is implemented as a simple state machine of five states.
1149 * State transitions are caused by tokens being received from the
1150 * scanner. The code should be self-documenting.
1154 /* Sanitize - remove all '\r' */
1156 if (str!=NULL) { while ((c = strchr(str, '\r')) != NULL) *c=' '; }
1158 fprintf(stderr, "(%s, %s \"%s\") -> (",
1159 state_str[state], token_str[token], str ? str : "");
1164 /* ----- Waiting for new packet -------------------------------------------*/
1166 if (!str && token != T_EOL) goto fail_null_str;
1169 append_to_preamble(str);
1172 process_directive(str);
1175 if (parse_num(str, TRUE, &num) != EXIT_SUCCESS)
1176 return EXIT_FAILURE;
1178 /* New packet starts here */
1179 if (start_new_packet(FALSE) != EXIT_SUCCESS)
1180 return EXIT_FAILURE;
1181 state = READ_OFFSET;
1182 pkt_lnstart = packet_buf + num;
1186 /* Some describing text may be parsed as offset, but the invalid
1187 offset will be checked in the state of START_OF_LINE, so
1188 we add this transition to gain flexibility */
1189 state = START_OF_LINE;
1196 /* ----- Processing packet, start of new line -----------------------------*/
1198 if (!str && token != T_EOL) goto fail_null_str;
1201 append_to_preamble(str);
1204 process_directive(str);
1207 if (parse_num(str, TRUE, &num) != EXIT_SUCCESS)
1208 return EXIT_FAILURE;
1210 /* New packet starts here */
1211 if (start_new_packet(FALSE) != EXIT_SUCCESS)
1212 return EXIT_FAILURE;
1214 state = READ_OFFSET;
1215 } else if ((num - packet_start) != curr_offset - header_length) {
1217 * The offset we read isn't the one we expected.
1218 * This may only mean that we mistakenly interpreted
1219 * some text as byte values (e.g., if the text dump
1220 * of packet data included a number with spaces around
1221 * it). If the offset is less than what we expected,
1222 * assume that's the problem, and throw away the putative
1223 * extra byte values.
1225 if (num < curr_offset) {
1226 unwrite_bytes(curr_offset - num);
1227 state = READ_OFFSET;
1229 /* Bad offset; switch to INIT state */
1231 fprintf(stderr, "Inconsistent offset. Expecting %0X, got %0X. Ignoring rest of packet\n",
1233 if (write_current_packet(FALSE) != EXIT_SUCCESS)
1234 return EXIT_FAILURE;
1238 state = READ_OFFSET;
1240 pkt_lnstart = packet_buf + num;
1243 state = START_OF_LINE;
1250 /* ----- Processing packet, read offset -----------------------------------*/
1254 /* Record the byte */
1256 if (!str) goto fail_null_str;
1257 if (write_byte(str) != EXIT_SUCCESS)
1258 return EXIT_FAILURE;
1266 state = START_OF_LINE;
1273 /* ----- Processing packet, read byte -------------------------------------*/
1277 /* Record the byte */
1278 if (write_byte(str) != EXIT_SUCCESS)
1279 return EXIT_FAILURE;
1287 if (token == T_EOL) {
1289 state = START_OF_LINE;
1291 if (identify_ascii) {
1292 /* Here a line of pkt bytes reading is finished
1293 compare the ascii and hex to avoid such situation:
1294 "61 62 20 ab ", when ab is ascii dump then it should
1295 not be treat as byte */
1297 /* s2 is the ASCII string, s1 is the HEX string, e.g, when
1298 s2 = "ab ", s1 = "616220"
1299 we should find out the largest tail of s1 matches the head
1300 of s2, it means the matched part in tail is the ASCII dump
1301 of the head byte. These matched should be rollback */
1302 line_size = curr_offset-(int)(pkt_lnstart-packet_buf);
1303 s2 = (char*)g_malloc((line_size+1)/4+1);
1304 /* gather the possible pattern */
1305 for (i = 0; i < (line_size+1)/4; i++) {
1306 tmp_str[0] = pkt_lnstart[i*3];
1307 tmp_str[1] = pkt_lnstart[i*3+1];
1309 /* it is a valid convertable string */
1310 if (!g_ascii_isxdigit(tmp_str[0]) || !g_ascii_isxdigit(tmp_str[1])) {
1313 s2[i] = (char)strtoul(tmp_str, (char **)NULL, 16);
1315 /* the 3rd entry is not a delimiter, so the possible byte pattern will not shown */
1316 if (!(pkt_lnstart[i*3+2] == ' ')) {
1322 /* If packet line start contains possible byte pattern, the line end
1323 should contain the matched pattern if the user open the -a flag.
1324 The packet will be possible invalid if the byte pattern cannot find
1325 a matched one in the line of packet buffer.*/
1327 if (strncmp(pkt_lnstart+line_size-rollback, s2, rollback) == 0) {
1328 unwrite_bytes(rollback);
1330 /* Not matched. This line contains invalid packet bytes, so
1331 discard the whole line */
1333 unwrite_bytes(line_size);
1344 /* ----- Processing packet, read text -------------------------------------*/
1348 state = START_OF_LINE;
1356 fprintf(stderr, "FATAL ERROR: Bad state (%d)", state);
1357 return EXIT_FAILURE;
1361 fprintf(stderr, ", %s)\n", state_str[state]);
1363 return EXIT_SUCCESS;
1366 fprintf(stderr, "FATAL ERROR: got NULL str pointer in state (%d)", state);
1367 return EXIT_FAILURE;
1370 /*----------------------------------------------------------------------
1371 * Print usage string and exit
1374 print_usage (FILE *output)
1378 "Usage: text2pcap [options] <infile> <outfile>\n"
1380 "where <infile> specifies input filename (use - for standard input)\n"
1381 " <outfile> specifies output filename (use - for standard output)\n"
1384 " -o hex|oct|dec parse offsets as (h)ex, (o)ctal or (d)ecimal;\n"
1385 " default is hex.\n"
1386 " -t <timefmt> treat the text before the packet as a date/time code;\n"
1387 " the specified argument is a format string of the sort\n"
1388 " supported by strptime.\n"
1389 " Example: The time \"10:15:14.5476\" has the format code\n"
1390 " \"%%H:%%M:%%S.\"\n"
1391 " NOTE: The subsecond component delimiter, '.', must be\n"
1392 " given, but no pattern is required; the remaining\n"
1393 " number is assumed to be fractions of a second.\n"
1394 " NOTE: Date/time fields from the current date/time are\n"
1395 " used as the default for unspecified fields.\n"
1396 " -D the text before the packet starts with an I or an O,\n"
1397 " indicating that the packet is inbound or outbound.\n"
1398 " This is only stored if the output format is PCAP-NG.\n"
1399 " -a enable ASCII text dump identification.\n"
1400 " The start of the ASCII text dump can be identified\n"
1401 " and excluded from the packet data, even if it looks\n"
1402 " like a HEX dump.\n"
1403 " NOTE: Do not enable it if the input file does not\n"
1404 " contain the ASCII text dump.\n"
1407 " -l <typenum> link-layer type number; default is 1 (Ethernet). See\n"
1408 " http://www.tcpdump.org/linktypes.html for a list of\n"
1409 " numbers. Use this option if your dump is a complete\n"
1410 " hex dump of an encapsulated packet and you wish to\n"
1411 " specify the exact type of encapsulation.\n"
1412 " Example: -l 7 for ARCNet packets.\n"
1413 " -m <max-packet> max packet length in output; default is %d\n"
1415 "Prepend dummy header:\n"
1416 " -e <l3pid> prepend dummy Ethernet II header with specified L3PID\n"
1418 " Example: -e 0x806 to specify an ARP packet.\n"
1419 " -i <proto> prepend dummy IP header with specified IP protocol\n"
1421 " Automatically prepends Ethernet header as well.\n"
1423 " -4 <srcip>,<destip> prepend dummy IPv4 header with specified\n"
1424 " dest and source address.\n"
1425 " Example: -4 10.0.0.1,10.0.0.2\n"
1426 " -6 <srcip>,<destip> replace IPv6 header with specified\n"
1427 " dest and source address.\n"
1428 " Example: -6 fe80:0:0:0:202:b3ff:fe1e:8329,2001:0db8:85a3:0000:0000:8a2e:0370:7334\n"
1429 " -u <srcp>,<destp> prepend dummy UDP header with specified\n"
1430 " source and destination ports (in DECIMAL).\n"
1431 " Automatically prepends Ethernet & IP headers as well.\n"
1432 " Example: -u 1000,69 to make the packets look like\n"
1433 " TFTP/UDP packets.\n"
1434 " -T <srcp>,<destp> prepend dummy TCP header with specified\n"
1435 " source and destination ports (in DECIMAL).\n"
1436 " Automatically prepends Ethernet & IP headers as well.\n"
1437 " Example: -T 50,60\n"
1438 " -s <srcp>,<dstp>,<tag> prepend dummy SCTP header with specified\n"
1439 " source/dest ports and verification tag (in DECIMAL).\n"
1440 " Automatically prepends Ethernet & IP headers as well.\n"
1441 " Example: -s 30,40,34\n"
1442 " -S <srcp>,<dstp>,<ppi> prepend dummy SCTP header with specified\n"
1443 " source/dest ports and verification tag 0.\n"
1444 " Automatically prepends a dummy SCTP DATA\n"
1445 " chunk header with payload protocol identifier ppi.\n"
1446 " Example: -S 30,40,34\n"
1449 " -h display this help and exit.\n"
1450 " -d show detailed debug of parser states.\n"
1451 " -q generate no output at all (automatically disables -d).\n"
1452 " -n use PCAP-NG instead of PCAP as output format.\n"
1454 WTAP_MAX_PACKET_SIZE_STANDARD);
1457 /*----------------------------------------------------------------------
1461 parse_options (int argc, char *argv[])
1463 GString *comp_info_str;
1464 GString *runtime_info_str;
1467 static const struct option long_options[] = {
1468 {"help", no_argument, NULL, 'h'},
1469 {"version", no_argument, NULL, 'v'},
1475 arg_list_utf_16to8(argc, argv);
1476 create_app_running_mutex();
1479 /* Get the compile-time version information string */
1480 comp_info_str = get_compiled_version_info(NULL, NULL);
1482 /* get the run-time version information string */
1483 runtime_info_str = get_runtime_version_info(NULL);
1485 /* Add it to the information to be reported on a crash. */
1486 ws_add_crash_info("Text2pcap (Wireshark) %s\n"
1491 get_ws_vcs_version_info(), comp_info_str->str, runtime_info_str->str);
1492 g_string_free(comp_info_str, TRUE);
1493 g_string_free(runtime_info_str, TRUE);
1495 /* Scan CLI parameters */
1496 while ((c = getopt_long(argc, argv, "aDdhqe:i:l:m:no:u:s:S:t:T:v4:6:", long_options, NULL)) != -1) {
1499 printf("Text2pcap (Wireshark) %s\n"
1500 "Generate a capture file from an ASCII hexdump of packets.\n"
1501 "See https://www.wireshark.org for more information.\n",
1502 get_ws_vcs_version_info());
1503 print_usage(stdout);
1506 case 'd': if (!quiet) debug++; break;
1507 case 'D': has_direction = TRUE; break;
1508 case 'q': quiet = TRUE; debug = FALSE; break;
1509 case 'l': pcap_link_type = (guint32)strtol(optarg, NULL, 0); break;
1510 case 'm': max_offset = (guint32)strtol(optarg, NULL, 0); break;
1511 case 'n': use_pcapng = TRUE; break;
1513 if (optarg[0] != 'h' && optarg[0] != 'o' && optarg[0] != 'd') {
1514 fprintf(stderr, "Bad argument for '-o': %s\n", optarg);
1515 print_usage(stderr);
1516 return EXIT_FAILURE;
1518 switch (optarg[0]) {
1519 case 'o': offset_base = 8; break;
1520 case 'h': offset_base = 16; break;
1521 case 'd': offset_base = 10; break;
1525 hdr_ethernet = TRUE;
1526 if (sscanf(optarg, "%x", &hdr_ethernet_proto) < 1) {
1527 fprintf(stderr, "Bad argument for '-e': %s\n", optarg);
1528 print_usage(stderr);
1529 return EXIT_FAILURE;
1535 hdr_ip_proto = strtol(optarg, &p, 10);
1536 if (p == optarg || *p != '\0' || hdr_ip_proto < 0 ||
1537 hdr_ip_proto > 255) {
1538 fprintf(stderr, "Bad argument for '-i': %s\n", optarg);
1539 print_usage(stderr);
1540 return EXIT_FAILURE;
1542 hdr_ethernet = TRUE;
1543 hdr_ethernet_proto = 0x800;
1548 hdr_data_chunk = FALSE;
1551 hdr_sctp_src = (guint32)strtol(optarg, &p, 10);
1552 if (p == optarg || (*p != ',' && *p != '\0')) {
1553 fprintf(stderr, "Bad src port for '-%c'\n", c);
1554 print_usage(stderr);
1555 return EXIT_FAILURE;
1558 fprintf(stderr, "No dest port specified for '-%c'\n", c);
1559 print_usage(stderr);
1560 return EXIT_FAILURE;
1564 hdr_sctp_dest = (guint32)strtol(optarg, &p, 10);
1565 if (p == optarg || (*p != ',' && *p != '\0')) {
1566 fprintf(stderr, "Bad dest port for '-s'\n");
1567 print_usage(stderr);
1568 return EXIT_FAILURE;
1571 fprintf(stderr, "No tag specified for '-%c'\n", c);
1572 print_usage(stderr);
1573 return EXIT_FAILURE;
1577 hdr_sctp_tag = (guint32)strtol(optarg, &p, 10);
1578 if (p == optarg || *p != '\0') {
1579 fprintf(stderr, "Bad tag for '-%c'\n", c);
1580 print_usage(stderr);
1581 return EXIT_FAILURE;
1586 hdr_ethernet = TRUE;
1587 hdr_ethernet_proto = 0x800;
1591 hdr_data_chunk = TRUE;
1594 hdr_sctp_src = (guint32)strtol(optarg, &p, 10);
1595 if (p == optarg || (*p != ',' && *p != '\0')) {
1596 fprintf(stderr, "Bad src port for '-%c'\n", c);
1597 print_usage(stderr);
1598 return EXIT_FAILURE;
1601 fprintf(stderr, "No dest port specified for '-%c'\n", c);
1602 print_usage(stderr);
1603 return EXIT_FAILURE;
1607 hdr_sctp_dest = (guint32)strtol(optarg, &p, 10);
1608 if (p == optarg || (*p != ',' && *p != '\0')) {
1609 fprintf(stderr, "Bad dest port for '-s'\n");
1610 print_usage(stderr);
1611 return EXIT_FAILURE;
1614 fprintf(stderr, "No ppi specified for '-%c'\n", c);
1615 print_usage(stderr);
1616 return EXIT_FAILURE;
1620 hdr_data_chunk_ppid = (guint32)strtoul(optarg, &p, 10);
1621 if (p == optarg || *p != '\0') {
1622 fprintf(stderr, "Bad ppi for '-%c'\n", c);
1623 print_usage(stderr);
1624 return EXIT_FAILURE;
1629 hdr_ethernet = TRUE;
1630 hdr_ethernet_proto = 0x800;
1641 hdr_data_chunk = FALSE;
1642 hdr_src_port = (guint32)strtol(optarg, &p, 10);
1643 if (p == optarg || (*p != ',' && *p != '\0')) {
1644 fprintf(stderr, "Bad src port for '-u'\n");
1645 print_usage(stderr);
1646 return EXIT_FAILURE;
1649 fprintf(stderr, "No dest port specified for '-u'\n");
1650 print_usage(stderr);
1651 return EXIT_FAILURE;
1655 hdr_dest_port = (guint32)strtol(optarg, &p, 10);
1656 if (p == optarg || *p != '\0') {
1657 fprintf(stderr, "Bad dest port for '-u'\n");
1658 print_usage(stderr);
1659 return EXIT_FAILURE;
1663 hdr_ethernet = TRUE;
1664 hdr_ethernet_proto = 0x800;
1671 hdr_data_chunk = FALSE;
1672 hdr_src_port = (guint32)strtol(optarg, &p, 10);
1673 if (p == optarg || (*p != ',' && *p != '\0')) {
1674 fprintf(stderr, "Bad src port for '-T'\n");
1675 print_usage(stderr);
1676 return EXIT_FAILURE;
1679 fprintf(stderr, "No dest port specified for '-u'\n");
1680 print_usage(stderr);
1681 return EXIT_FAILURE;
1685 hdr_dest_port = (guint32)strtol(optarg, &p, 10);
1686 if (p == optarg || *p != '\0') {
1687 fprintf(stderr, "Bad dest port for '-T'\n");
1688 print_usage(stderr);
1689 return EXIT_FAILURE;
1693 hdr_ethernet = TRUE;
1694 hdr_ethernet_proto = 0x800;
1698 identify_ascii = TRUE;
1702 comp_info_str = get_compiled_version_info(NULL, NULL);
1703 runtime_info_str = get_runtime_version_info(NULL);
1704 show_version("Text2pcap (Wireshark)", comp_info_str, runtime_info_str);
1705 g_string_free(comp_info_str, TRUE);
1706 g_string_free(runtime_info_str, TRUE);
1712 p = strchr(optarg, ',');
1715 fprintf(stderr, "Bad source param addr for '-%c'\n", c);
1716 print_usage(stderr);
1717 return EXIT_FAILURE;
1724 hdr_ethernet_proto = 0x86DD;
1729 hdr_ethernet_proto = 0x800;
1731 hdr_ethernet = TRUE;
1733 if (hdr_ipv6 == TRUE) {
1734 if (!ws_inet_pton6(optarg, &hdr_ipv6_src_addr)) {
1735 fprintf(stderr, "Bad src addr -%c '%s'\n", c, p);
1736 print_usage(stderr);
1737 return EXIT_FAILURE;
1740 if (!ws_inet_pton4(optarg, &hdr_ip_src_addr)) {
1741 fprintf(stderr, "Bad src addr -%c '%s'\n", c, p);
1742 print_usage(stderr);
1743 return EXIT_FAILURE;
1749 fprintf(stderr, "No dest addr specified for '-%c'\n", c);
1750 print_usage(stderr);
1751 return EXIT_FAILURE;
1754 if (hdr_ipv6 == TRUE) {
1755 if (!ws_inet_pton6(p, &hdr_ipv6_dest_addr)) {
1756 fprintf(stderr, "Bad dest addr for -%c '%s'\n", c, p);
1757 print_usage(stderr);
1758 return EXIT_FAILURE;
1761 if (!ws_inet_pton4(p, &hdr_ip_dest_addr)) {
1762 fprintf(stderr, "Bad dest addr for -%c '%s'\n", c, p);
1763 print_usage(stderr);
1764 return EXIT_FAILURE;
1772 print_usage(stderr);
1773 return EXIT_FAILURE;
1777 if (optind >= argc || argc-optind < 2) {
1778 fprintf(stderr, "Must specify input and output filename\n");
1779 print_usage(stderr);
1780 return EXIT_FAILURE;
1783 if (strcmp(argv[optind], "-") != 0) {
1784 input_filename = argv[optind];
1785 input_file = ws_fopen(input_filename, "rb");
1787 fprintf(stderr, "Cannot open file [%s] for reading: %s\n",
1788 input_filename, g_strerror(errno));
1789 return EXIT_FAILURE;
1792 input_filename = "Standard input";
1796 if (strcmp(argv[optind+1], "-") != 0) {
1797 /* Write to a file. Open the file, in binary mode. */
1798 output_filename = argv[optind+1];
1799 output_file = ws_fopen(output_filename, "wb");
1801 fprintf(stderr, "Cannot open file [%s] for writing: %s\n",
1802 output_filename, g_strerror(errno));
1803 return EXIT_FAILURE;
1806 /* Write to the standard output. */
1808 /* Put the standard output in binary mode. */
1809 if (_setmode(1, O_BINARY) == -1) {
1810 /* "Should not happen" */
1811 fprintf(stderr, "Cannot put standard output in binary mode: %s\n",
1813 return EXIT_FAILURE;
1816 output_filename = "Standard output";
1817 output_file = stdout;
1820 /* Some validation */
1821 if (pcap_link_type != 1 && hdr_ethernet) {
1822 fprintf(stderr, "Dummy headers (-e, -i, -u, -s, -S -T) cannot be specified with link type override (-l)\n");
1823 return EXIT_FAILURE;
1826 /* Set up our variables */
1829 input_filename = "Standard input";
1832 output_file = stdout;
1833 output_filename = "Standard output";
1836 ts_sec = time(0); /* initialize to current time */
1837 now_tm = localtime(&ts_sec);
1838 if (now_tm == NULL) {
1840 * This shouldn't happen - on UN*X, this should Just Work, and
1841 * on Windows, it won't work if ts_sec is before the Epoch,
1842 * but it's long after 1970, so....
1844 fprintf(stderr, "localtime(right now) failed\n");
1845 return EXIT_FAILURE;
1847 timecode_default = *now_tm;
1848 timecode_default.tm_isdst = -1; /* Unknown for now, depends on time given to the strptime() function */
1850 /* Display summary of our state */
1852 fprintf(stderr, "Input from: %s\n", input_filename);
1853 fprintf(stderr, "Output to: %s\n", output_filename);
1854 fprintf(stderr, "Output format: %s\n", use_pcapng ? "PCAP-NG" : "PCAP");
1856 if (hdr_ethernet) fprintf(stderr, "Generate dummy Ethernet header: Protocol: 0x%0X\n",
1857 hdr_ethernet_proto);
1858 if (hdr_ip) fprintf(stderr, "Generate dummy IP header: Protocol: %ld\n",
1860 if (hdr_udp) fprintf(stderr, "Generate dummy UDP header: Source port: %u. Dest port: %u\n",
1861 hdr_src_port, hdr_dest_port);
1862 if (hdr_tcp) fprintf(stderr, "Generate dummy TCP header: Source port: %u. Dest port: %u\n",
1863 hdr_src_port, hdr_dest_port);
1864 if (hdr_sctp) fprintf(stderr, "Generate dummy SCTP header: Source port: %u. Dest port: %u. Tag: %u\n",
1865 hdr_sctp_src, hdr_sctp_dest, hdr_sctp_tag);
1866 if (hdr_data_chunk) fprintf(stderr, "Generate dummy DATA chunk header: TSN: %u. SID: %u. SSN: %u. PPID: %u\n",
1867 hdr_data_chunk_tsn, hdr_data_chunk_sid, hdr_data_chunk_ssn, hdr_data_chunk_ppid);
1870 return EXIT_SUCCESS;
1874 main(int argc, char *argv[])
1876 int ret = EXIT_SUCCESS;
1878 parse_options(argc, argv);
1880 assert(input_file != NULL);
1881 assert(output_file != NULL);
1883 if (write_file_header() != EXIT_SUCCESS) {
1890 header_length += (int)sizeof(HDR_ETHERNET);
1893 ip_offset = header_length;
1894 header_length += (int)sizeof(HDR_IP);
1895 } else if (hdr_ipv6) {
1896 ip_offset = header_length;
1897 header_length += (int)sizeof(HDR_IPv6);
1900 header_length += (int)sizeof(HDR_SCTP);
1902 if (hdr_data_chunk) {
1903 header_length += (int)sizeof(HDR_DATA_CHUNK);
1906 header_length += (int)sizeof(HDR_TCP);
1909 header_length += (int)sizeof(HDR_UDP);
1911 curr_offset = header_length;
1913 text2pcap_in = input_file;
1914 if (text2pcap_lex() == EXIT_SUCCESS) {
1915 if (write_current_packet(FALSE) != EXIT_SUCCESS)
1921 fprintf(stderr, "\n-------------------------\n");
1923 fprintf(stderr, "Read %u potential packet%s, wrote %u packet%s (%" G_GINT64_MODIFIER "u byte%s).\n",
1924 num_packets_read, (num_packets_read == 1) ? "" : "s",
1925 num_packets_written, (num_packets_written == 1) ? "" : "s",
1926 bytes_written, (bytes_written == 1) ? "" : "s");
1929 text2pcap_lex_destroy();
1931 fclose(output_file);
1936 * Editor modelines - http://www.wireshark.org/tools/modelines.html
1941 * indent-tabs-mode: nil
1944 * vi: set shiftwidth=4 tabstop=8 expandtab:
1945 * :indentSize=4:tabSize=8:noTabs=true: