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 * SPDX-License-Identifier: GPL-2.0-or-later
15 *******************************************************************************/
17 /*******************************************************************************
19 * This utility reads in an ASCII hexdump of this common format:
21 * 00000000 00 E0 1E A7 05 6F 00 10 5A A0 B9 12 08 00 46 00 .....o..Z.....F.
22 * 00000010 03 68 00 00 00 00 0A 2E EE 33 0F 19 08 7F 0F 19 .h.......3......
23 * 00000020 03 80 94 04 00 00 10 01 16 A2 0A 00 03 50 00 0C .............P..
24 * 00000030 01 01 0F 19 03 80 11 01 1E 61 00 0C 03 01 0F 19 .........a......
26 * Each bytestring line consists of an offset, one or more bytes, and
27 * text at the end. An offset is defined as a hex string of more than
28 * two characters. A byte is defined as a hex string of exactly two
29 * characters. The text at the end is ignored, as is any text before
30 * the offset. Bytes read from a bytestring line are added to the
31 * current packet only if all the following conditions are satisfied:
33 * - No text appears between the offset and the bytes (any bytes appearing after
34 * such text would be ignored)
36 * - The offset must be arithmetically correct, i.e. if the offset is 00000020,
37 * then exactly 32 bytes must have been read into this packet before this.
38 * If the offset is wrong, the packet is immediately terminated
40 * A packet start is signaled by a zero offset.
42 * Lines starting with #TEXT2PCAP are directives. These allow the user
43 * to embed instructions into the capture file which allows text2pcap
44 * to take some actions (e.g. specifying the encapsulation
45 * etc.). Currently no directives are implemented.
47 * Lines beginning with # which are not directives are ignored as
48 * comments. Currently all non-hexdump text is ignored by text2pcap;
49 * in the future, text processing may be added, but lines prefixed
50 * with '#' will still be ignored.
52 * The output is a libpcap packet containing Ethernet frames by
53 * default. This program takes options which allow the user to add
54 * dummy Ethernet, IP and UDP, TCP or SCTP headers to the packets in order
55 * to allow dumps of L3 or higher protocols to be decoded.
57 * Considerable flexibility is built into this code to read hexdumps
58 * of slightly different formats. For example, any text prefixing the
59 * hexdump line is dropped (including mail forwarding '>'). The offset
60 * can be any hex number of four digits or greater.
62 * This converter cannot read a single packet greater than
63 * WTAP_MAX_PACKET_SIZE_STANDARD. The snapshot length is automatically
64 * set to WTAP_MAX_PACKET_SIZE_STANDARD.
70 * Just make sure we include the prototype for strptime as well
71 * (needed for glibc 2.2) but make sure we do this only if not
79 # define _XOPEN_SOURCE 600
84 * Defining _XOPEN_SOURCE is needed on some platforms, e.g. platforms
85 * using glibc, to expand the set of things system header files define.
87 * Unfortunately, on other platforms, such as some versions of Solaris
88 * (including Solaris 10), it *reduces* that set as well, causing
89 * strptime() not to be declared, presumably because the version of the
90 * X/Open spec that _XOPEN_SOURCE implies doesn't include strptime() and
91 * blah blah blah namespace pollution blah blah blah.
93 * So we define __EXTENSIONS__ so that "strptime()" is declared.
95 #ifndef __EXTENSIONS__
96 # define __EXTENSIONS__
102 #include <wsutil/file_util.h>
103 #include <cli_main.h>
104 #include <version_info.h>
105 #include <wsutil/inet_addr.h>
108 #include <io.h> /* for _setmode */
109 #include <fcntl.h> /* for O_BINARY */
122 #ifndef HAVE_GETOPT_LONG
123 #include "wsutil/wsgetopt.h"
126 #ifndef HAVE_STRPTIME
127 # include "wsutil/strptime.h"
130 #include "writecap/pcapio.h"
131 #include "text2pcap.h"
133 #include "wiretap/wtap.h"
135 /*--- Options --------------------------------------------------------------------*/
138 static gboolean use_pcapng = FALSE;
141 static char *interface_name = NULL;
144 static int debug = 0;
146 static gboolean quiet = FALSE;
148 /* Dummy Ethernet header */
149 static int hdr_ethernet = FALSE;
150 static guint8 hdr_eth_dest_addr[6] = {0x0a, 0x02, 0x02, 0x02, 0x02, 0x02};
151 static guint8 hdr_eth_src_addr[6] = {0x0a, 0x02, 0x02, 0x02, 0x02, 0x01};
152 static guint32 hdr_ethernet_proto = 0;
154 /* Dummy IP header */
155 static gboolean hdr_ip = FALSE;
156 static gboolean hdr_ipv6 = FALSE;
157 static long hdr_ip_proto = -1;
159 /* Destination and source addresses for IP header */
160 static guint32 hdr_ip_dest_addr = 0;
161 static guint32 hdr_ip_src_addr = 0;
162 static ws_in6_addr hdr_ipv6_dest_addr = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
163 static ws_in6_addr hdr_ipv6_src_addr = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
164 static ws_in6_addr NO_IPv6_ADDRESS = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
166 /* Dummy UDP header */
167 static gboolean hdr_udp = FALSE;
168 static guint32 hdr_dest_port = 0;
169 static guint32 hdr_src_port = 0;
171 /* Dummy TCP header */
172 static gboolean hdr_tcp = FALSE;
174 /* TCP sequence numbers when has_direction is true */
175 static guint32 tcp_in_seq_num = 0;
176 static guint32 tcp_out_seq_num = 0;
178 /* Dummy SCTP header */
179 static gboolean hdr_sctp = FALSE;
180 static guint32 hdr_sctp_src = 0;
181 static guint32 hdr_sctp_dest = 0;
182 static guint32 hdr_sctp_tag = 0;
184 /* Dummy DATA chunk header */
185 static gboolean hdr_data_chunk = FALSE;
186 static guint8 hdr_data_chunk_type = 0;
187 static guint8 hdr_data_chunk_bits = 0;
188 static guint32 hdr_data_chunk_tsn = 0;
189 static guint16 hdr_data_chunk_sid = 0;
190 static guint16 hdr_data_chunk_ssn = 0;
191 static guint32 hdr_data_chunk_ppid = 0;
193 /* ASCII text dump identification */
194 static gboolean identify_ascii = FALSE;
196 static gboolean has_direction = FALSE;
197 static guint32 direction = 0;
199 /*--- Local data -----------------------------------------------------------------*/
201 /* This is where we store the packet currently being built */
202 static guint8 packet_buf[WTAP_MAX_PACKET_SIZE_STANDARD];
203 static guint32 header_length;
204 static guint32 ip_offset;
205 static guint32 curr_offset;
206 static guint32 max_offset = WTAP_MAX_PACKET_SIZE_STANDARD;
207 static guint32 packet_start = 0;
209 static int start_new_packet(gboolean);
211 /* This buffer contains strings present before the packet offset 0 */
212 #define PACKET_PREAMBLE_MAX_LEN 2048
213 static guint8 packet_preamble[PACKET_PREAMBLE_MAX_LEN+1];
214 static int packet_preamble_len = 0;
216 /* Number of packets read and written */
217 static guint32 num_packets_read = 0;
218 static guint32 num_packets_written = 0;
219 static guint64 bytes_written = 0;
221 /* Time code of packet, derived from packet_preamble */
222 static time_t ts_sec = 0;
223 static guint32 ts_nsec = 0;
224 static char *ts_fmt = NULL;
225 static struct tm timecode_default;
227 static guint8* pkt_lnstart;
230 static char *input_filename;
231 static FILE *input_file = NULL;
233 static char *output_filename;
234 static FILE *output_file = NULL;
236 /* Offset base to parse */
237 static guint32 offset_base = 16;
239 extern FILE *text2pcap_in;
241 /* ----- State machine -----------------------------------------------------------*/
243 /* Current state of parser */
245 INIT, /* Waiting for start of new packet */
246 START_OF_LINE, /* Starting from beginning of line */
247 READ_OFFSET, /* Just read the offset */
248 READ_BYTE, /* Just read a byte */
249 READ_TEXT /* Just read text - ignore until EOL */
251 static parser_state_t state = INIT;
253 static const char *state_str[] = {"Init",
260 static const char *token_str[] = {"",
268 /* ----- Skeleton Packet Headers --------------------------------------------------*/
276 static hdr_ethernet_t HDR_ETHERNET;
281 guint16 packet_length;
282 guint16 identification;
287 guint16 hdr_checksum;
292 /* Fixed IP address values */
293 #if G_BYTE_ORDER == G_BIG_ENDIAN
295 #define IP_SRC 0x0a010101
296 #define IP_DST 0x0a020202
299 #define IP_SRC 0x0101010a
300 #define IP_DST 0x0202020a
303 static hdr_ip_t HDR_IP = {0x45, 0, 0, IP_ID, 0, 0, 0xff, 0, 0, IP_SRC, IP_DST};
305 static struct { /* pseudo header for checksum calculation */
314 /* headers taken from glibc */
319 guint32 ip6_un1_flow; /* 24 bits of flow-ID */
320 guint16 ip6_un1_plen; /* payload length */
321 guint8 ip6_un1_nxt; /* next header */
322 guint8 ip6_un1_hlim; /* hop limit */
324 guint8 ip6_un2_vfc; /* 4 bits version, 4 bits priority */
326 ws_in6_addr ip6_src; /* source address */
327 ws_in6_addr ip6_dst; /* destination address */
330 static hdr_ipv6_t HDR_IPv6;
332 /* https://tools.ietf.org/html/rfc2460#section-8.1 */
333 static struct { /* pseudo header ipv6 for checksum calculation */
334 struct e_in6_addr src_addr6;
335 struct e_in6_addr dst_addr6;
349 static hdr_udp_t HDR_UDP = {0, 0, 0, 0};
363 static hdr_tcp_t HDR_TCP = {0, 0, 0, 0, 0x50, 0, 0, 0, 0};
372 static hdr_sctp_t HDR_SCTP = {0, 0, 0, 0};
384 static hdr_data_chunk_t HDR_DATA_CHUNK = {0, 0, 0, 0, 0, 0, 0};
386 static char tempbuf[64];
388 /*----------------------------------------------------------------------
389 * Stuff for writing a PCap file
392 /* Link-layer type; see http://www.tcpdump.org/linktypes.html for details */
393 static guint32 pcap_link_type = 1; /* Default is LINKTYPE_ETHERNET */
395 /*----------------------------------------------------------------------
396 * Parse a single hex number
397 * Will abort the program if it can't parse the number
398 * Pass in TRUE if this is an offset, FALSE if not
401 parse_num(const char *str, int offset, guint32* num)
406 fprintf(stderr, "FATAL ERROR: str is NULL\n");
410 *num = (guint32)strtoul(str, &c, offset ? offset_base : 16);
412 fprintf(stderr, "FATAL ERROR: Bad hex number? [%s]\n", str);
418 /*----------------------------------------------------------------------
419 * Write this byte into current packet
422 write_byte(const char *str)
426 if (parse_num(str, FALSE, &num) != EXIT_SUCCESS)
429 packet_buf[curr_offset] = (guint8) num;
431 if (curr_offset - header_length >= max_offset) /* packet full */
432 if (start_new_packet(TRUE) != EXIT_SUCCESS)
438 /*----------------------------------------------------------------------
439 * Write a number of bytes into current packet
443 write_bytes (const char bytes[], guint32 nbytes)
447 if (curr_offset + nbytes < WTAP_MAX_PACKET_SIZE_STANDARD) {
448 for (i = 0; i < nbytes; i++) {
449 packet_buf[curr_offset] = bytes[i];
455 /*----------------------------------------------------------------------
456 * Remove bytes from the current packet
459 unwrite_bytes (guint32 nbytes)
461 curr_offset -= nbytes;
464 /*----------------------------------------------------------------------
465 * Compute one's complement checksum (from RFC1071)
468 in_checksum (void *buf, guint32 count)
471 guint16 *addr = (guint16 *)buf;
474 /* This is the inner loop */
475 sum += g_ntohs(* (guint16 *) addr);
480 /* Add left-over byte, if any */
482 sum += g_ntohs(* (guint8 *) addr);
484 /* Fold 32-bit sum to 16 bits */
486 sum = (sum & 0xffff) + (sum >> 16);
492 /* The CRC32C code is taken from draft-ietf-tsvwg-sctpcsum-01.txt.
493 * That code is copyrighted by D. Otis and has been modified.
496 #define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF])
497 static guint32 crc_c[256] =
499 0x00000000U, 0xF26B8303U, 0xE13B70F7U, 0x1350F3F4U,
500 0xC79A971FU, 0x35F1141CU, 0x26A1E7E8U, 0xD4CA64EBU,
501 0x8AD958CFU, 0x78B2DBCCU, 0x6BE22838U, 0x9989AB3BU,
502 0x4D43CFD0U, 0xBF284CD3U, 0xAC78BF27U, 0x5E133C24U,
503 0x105EC76FU, 0xE235446CU, 0xF165B798U, 0x030E349BU,
504 0xD7C45070U, 0x25AFD373U, 0x36FF2087U, 0xC494A384U,
505 0x9A879FA0U, 0x68EC1CA3U, 0x7BBCEF57U, 0x89D76C54U,
506 0x5D1D08BFU, 0xAF768BBCU, 0xBC267848U, 0x4E4DFB4BU,
507 0x20BD8EDEU, 0xD2D60DDDU, 0xC186FE29U, 0x33ED7D2AU,
508 0xE72719C1U, 0x154C9AC2U, 0x061C6936U, 0xF477EA35U,
509 0xAA64D611U, 0x580F5512U, 0x4B5FA6E6U, 0xB93425E5U,
510 0x6DFE410EU, 0x9F95C20DU, 0x8CC531F9U, 0x7EAEB2FAU,
511 0x30E349B1U, 0xC288CAB2U, 0xD1D83946U, 0x23B3BA45U,
512 0xF779DEAEU, 0x05125DADU, 0x1642AE59U, 0xE4292D5AU,
513 0xBA3A117EU, 0x4851927DU, 0x5B016189U, 0xA96AE28AU,
514 0x7DA08661U, 0x8FCB0562U, 0x9C9BF696U, 0x6EF07595U,
515 0x417B1DBCU, 0xB3109EBFU, 0xA0406D4BU, 0x522BEE48U,
516 0x86E18AA3U, 0x748A09A0U, 0x67DAFA54U, 0x95B17957U,
517 0xCBA24573U, 0x39C9C670U, 0x2A993584U, 0xD8F2B687U,
518 0x0C38D26CU, 0xFE53516FU, 0xED03A29BU, 0x1F682198U,
519 0x5125DAD3U, 0xA34E59D0U, 0xB01EAA24U, 0x42752927U,
520 0x96BF4DCCU, 0x64D4CECFU, 0x77843D3BU, 0x85EFBE38U,
521 0xDBFC821CU, 0x2997011FU, 0x3AC7F2EBU, 0xC8AC71E8U,
522 0x1C661503U, 0xEE0D9600U, 0xFD5D65F4U, 0x0F36E6F7U,
523 0x61C69362U, 0x93AD1061U, 0x80FDE395U, 0x72966096U,
524 0xA65C047DU, 0x5437877EU, 0x4767748AU, 0xB50CF789U,
525 0xEB1FCBADU, 0x197448AEU, 0x0A24BB5AU, 0xF84F3859U,
526 0x2C855CB2U, 0xDEEEDFB1U, 0xCDBE2C45U, 0x3FD5AF46U,
527 0x7198540DU, 0x83F3D70EU, 0x90A324FAU, 0x62C8A7F9U,
528 0xB602C312U, 0x44694011U, 0x5739B3E5U, 0xA55230E6U,
529 0xFB410CC2U, 0x092A8FC1U, 0x1A7A7C35U, 0xE811FF36U,
530 0x3CDB9BDDU, 0xCEB018DEU, 0xDDE0EB2AU, 0x2F8B6829U,
531 0x82F63B78U, 0x709DB87BU, 0x63CD4B8FU, 0x91A6C88CU,
532 0x456CAC67U, 0xB7072F64U, 0xA457DC90U, 0x563C5F93U,
533 0x082F63B7U, 0xFA44E0B4U, 0xE9141340U, 0x1B7F9043U,
534 0xCFB5F4A8U, 0x3DDE77ABU, 0x2E8E845FU, 0xDCE5075CU,
535 0x92A8FC17U, 0x60C37F14U, 0x73938CE0U, 0x81F80FE3U,
536 0x55326B08U, 0xA759E80BU, 0xB4091BFFU, 0x466298FCU,
537 0x1871A4D8U, 0xEA1A27DBU, 0xF94AD42FU, 0x0B21572CU,
538 0xDFEB33C7U, 0x2D80B0C4U, 0x3ED04330U, 0xCCBBC033U,
539 0xA24BB5A6U, 0x502036A5U, 0x4370C551U, 0xB11B4652U,
540 0x65D122B9U, 0x97BAA1BAU, 0x84EA524EU, 0x7681D14DU,
541 0x2892ED69U, 0xDAF96E6AU, 0xC9A99D9EU, 0x3BC21E9DU,
542 0xEF087A76U, 0x1D63F975U, 0x0E330A81U, 0xFC588982U,
543 0xB21572C9U, 0x407EF1CAU, 0x532E023EU, 0xA145813DU,
544 0x758FE5D6U, 0x87E466D5U, 0x94B49521U, 0x66DF1622U,
545 0x38CC2A06U, 0xCAA7A905U, 0xD9F75AF1U, 0x2B9CD9F2U,
546 0xFF56BD19U, 0x0D3D3E1AU, 0x1E6DCDEEU, 0xEC064EEDU,
547 0xC38D26C4U, 0x31E6A5C7U, 0x22B65633U, 0xD0DDD530U,
548 0x0417B1DBU, 0xF67C32D8U, 0xE52CC12CU, 0x1747422FU,
549 0x49547E0BU, 0xBB3FFD08U, 0xA86F0EFCU, 0x5A048DFFU,
550 0x8ECEE914U, 0x7CA56A17U, 0x6FF599E3U, 0x9D9E1AE0U,
551 0xD3D3E1ABU, 0x21B862A8U, 0x32E8915CU, 0xC083125FU,
552 0x144976B4U, 0xE622F5B7U, 0xF5720643U, 0x07198540U,
553 0x590AB964U, 0xAB613A67U, 0xB831C993U, 0x4A5A4A90U,
554 0x9E902E7BU, 0x6CFBAD78U, 0x7FAB5E8CU, 0x8DC0DD8FU,
555 0xE330A81AU, 0x115B2B19U, 0x020BD8EDU, 0xF0605BEEU,
556 0x24AA3F05U, 0xD6C1BC06U, 0xC5914FF2U, 0x37FACCF1U,
557 0x69E9F0D5U, 0x9B8273D6U, 0x88D28022U, 0x7AB90321U,
558 0xAE7367CAU, 0x5C18E4C9U, 0x4F48173DU, 0xBD23943EU,
559 0xF36E6F75U, 0x0105EC76U, 0x12551F82U, 0xE03E9C81U,
560 0x34F4F86AU, 0xC69F7B69U, 0xD5CF889DU, 0x27A40B9EU,
561 0x79B737BAU, 0x8BDCB4B9U, 0x988C474DU, 0x6AE7C44EU,
562 0xBE2DA0A5U, 0x4C4623A6U, 0x5F16D052U, 0xAD7D5351U,
566 crc32c (const guint8* buf, unsigned int len, guint32 crc32_init)
572 for (i = 0; i < len; i++)
579 finalize_crc32c (guint32 crc)
582 guint8 byte0,byte1,byte2,byte3;
585 byte0 = result & 0xff;
586 byte1 = (result>>8) & 0xff;
587 byte2 = (result>>16) & 0xff;
588 byte3 = (result>>24) & 0xff;
589 result = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3);
594 number_of_padding_bytes (guint32 length)
598 remainder = length % 4;
603 return 4 - remainder;
606 /*----------------------------------------------------------------------
607 * Write current packet out
610 write_current_packet (gboolean cont)
613 guint16 padding_length = 0;
617 if (curr_offset > header_length) {
618 /* Write the packet */
620 /* Is direction indication on with an inbound packet? */
621 gboolean isInbound = has_direction && (direction == 2);
623 /* Compute packet length */
624 length = curr_offset;
626 padding_length = number_of_padding_bytes(length - header_length );
630 /* Reset curr_offset, since we now write the headers */
633 /* Write Ethernet header */
637 memcpy(HDR_ETHERNET.dest_addr, hdr_eth_src_addr, 6);
638 memcpy(HDR_ETHERNET.src_addr, hdr_eth_dest_addr, 6);
640 memcpy(HDR_ETHERNET.dest_addr, hdr_eth_dest_addr, 6);
641 memcpy(HDR_ETHERNET.src_addr, hdr_eth_src_addr, 6);
643 HDR_ETHERNET.l3pid = g_htons(hdr_ethernet_proto);
644 write_bytes((const char *)&HDR_ETHERNET, sizeof(HDR_ETHERNET));
647 /* Write IP header */
650 HDR_IP.src_addr = hdr_ip_dest_addr ? hdr_ip_dest_addr : IP_DST;
651 HDR_IP.dest_addr = hdr_ip_src_addr? hdr_ip_src_addr : IP_SRC;
654 HDR_IP.src_addr = hdr_ip_src_addr? hdr_ip_src_addr : IP_SRC;
655 HDR_IP.dest_addr = hdr_ip_dest_addr ? hdr_ip_dest_addr : IP_DST;
658 HDR_IP.packet_length = g_htons(length - ip_offset + padding_length);
659 HDR_IP.protocol = (guint8) hdr_ip_proto;
660 HDR_IP.hdr_checksum = 0;
661 HDR_IP.hdr_checksum = in_checksum(&HDR_IP, sizeof(HDR_IP));
662 write_bytes((const char *)&HDR_IP, sizeof(HDR_IP));
664 /* initialize pseudo header for checksum calculation */
665 pseudoh.src_addr = HDR_IP.src_addr;
666 pseudoh.dest_addr = HDR_IP.dest_addr;
668 pseudoh.protocol = (guint8) hdr_ip_proto;
670 pseudoh.length = g_htons(length - header_length + sizeof(HDR_TCP));
671 } else if (hdr_udp) {
672 pseudoh.length = g_htons(length - header_length + sizeof(HDR_UDP));
674 } else if (hdr_ipv6) {
675 if (memcmp(isInbound ? &hdr_ipv6_dest_addr : &hdr_ipv6_src_addr, &NO_IPv6_ADDRESS, sizeof(ws_in6_addr)))
676 memcpy(&HDR_IPv6.ip6_src, isInbound ? &hdr_ipv6_dest_addr : &hdr_ipv6_src_addr, sizeof(ws_in6_addr));
677 if (memcmp(isInbound ? &hdr_ipv6_src_addr : &hdr_ipv6_dest_addr, &NO_IPv6_ADDRESS, sizeof(ws_in6_addr)))
678 memcpy(&HDR_IPv6.ip6_dst, isInbound ? &hdr_ipv6_src_addr : &hdr_ipv6_dest_addr, sizeof(ws_in6_addr));
680 HDR_IPv6.ip6_ctlun.ip6_un2_vfc &= 0x0F;
681 HDR_IPv6.ip6_ctlun.ip6_un2_vfc |= (6<< 4);
682 HDR_IPv6.ip6_ctlun.ip6_un1.ip6_un1_plen = g_htons(length - ip_offset - sizeof(HDR_IPv6) + padding_length);
683 HDR_IPv6.ip6_ctlun.ip6_un1.ip6_un1_nxt = (guint8) hdr_ip_proto;
684 HDR_IPv6.ip6_ctlun.ip6_un1.ip6_un1_hlim = 32;
685 write_bytes((const char *)&HDR_IPv6, sizeof(HDR_IPv6));
687 /* initialize pseudo ipv6 header for checksum calculation */
688 pseudoh6.src_addr6 = HDR_IPv6.ip6_src;
689 pseudoh6.dst_addr6 = HDR_IPv6.ip6_dst;
690 memset(pseudoh6.zero, 0, sizeof(pseudoh6.zero));
691 pseudoh6.next_header = (guint8) hdr_ip_proto;
693 pseudoh6.length = g_htons(length - header_length + sizeof(HDR_TCP));
694 } else if (hdr_udp) {
695 pseudoh6.length = g_htons(length - header_length + sizeof(HDR_UDP));
699 /* Write UDP header */
704 /* initialize the UDP header */
705 HDR_UDP.source_port = isInbound ? g_htons(hdr_dest_port): g_htons(hdr_src_port);
706 HDR_UDP.dest_port = isInbound ? g_htons(hdr_src_port) : g_htons(hdr_dest_port);
707 HDR_UDP.length = hdr_ipv6 ? pseudoh6.length : pseudoh.length;
708 HDR_UDP.checksum = 0;
709 /* Note: g_ntohs()/g_htons() macro arg may be eval'd twice so calc value before invoking macro */
710 x16 = hdr_ipv6 ? in_checksum(&pseudoh6, sizeof(pseudoh6)) : in_checksum(&pseudoh, sizeof(pseudoh));
712 x16 = in_checksum(&HDR_UDP, sizeof(HDR_UDP));
714 x16 = in_checksum(packet_buf + header_length, length - header_length);
716 x16 = (u & 0xffff) + (u>>16);
717 HDR_UDP.checksum = g_htons(x16);
718 if (HDR_UDP.checksum == 0) /* differentiate between 'none' and 0 */
719 HDR_UDP.checksum = g_htons(1);
720 write_bytes((const char *)&HDR_UDP, sizeof(HDR_UDP));
723 /* Write TCP header */
728 /* initialize the TCP header */
729 HDR_TCP.source_port = isInbound ? g_htons(hdr_dest_port): g_htons(hdr_src_port);
730 HDR_TCP.dest_port = isInbound ? g_htons(hdr_src_port) : g_htons(hdr_dest_port);
731 /* set ack number if we have direction */
733 HDR_TCP.flags = 0x10;
734 HDR_TCP.ack_num = g_ntohl(isInbound ? tcp_out_seq_num : tcp_in_seq_num);
735 HDR_TCP.ack_num = g_htonl(HDR_TCP.ack_num);
741 HDR_TCP.seq_num = isInbound ? tcp_in_seq_num : tcp_out_seq_num;
742 HDR_TCP.window = g_htons(0x2000);
743 HDR_TCP.checksum = 0;
744 /* Note: g_ntohs()/g_htons() macro arg may be eval'd twice so calc value before invoking macro */
745 x16 = hdr_ipv6 ? in_checksum(&pseudoh6, sizeof(pseudoh6)) : in_checksum(&pseudoh, sizeof(pseudoh));
747 x16 = in_checksum(&HDR_TCP, sizeof(HDR_TCP));
749 x16 = in_checksum(packet_buf + header_length, length - header_length);
751 x16 = (u & 0xffff) + (u>>16);
752 HDR_TCP.checksum = g_htons(x16);
753 if (HDR_TCP.checksum == 0) /* differentiate between 'none' and 0 */
754 HDR_TCP.checksum = g_htons(1);
755 write_bytes((const char *)&HDR_TCP, sizeof(HDR_TCP));
757 tcp_in_seq_num = g_ntohl(tcp_in_seq_num) + length - header_length;
758 tcp_in_seq_num = g_htonl(tcp_in_seq_num);
761 tcp_out_seq_num = g_ntohl(tcp_out_seq_num) + length - header_length;
762 tcp_out_seq_num = g_htonl(tcp_out_seq_num);
766 /* Compute DATA chunk header */
767 if (hdr_data_chunk) {
768 hdr_data_chunk_bits = 0;
769 if (packet_start == 0) {
770 hdr_data_chunk_bits |= 0x02;
773 hdr_data_chunk_bits |= 0x01;
775 HDR_DATA_CHUNK.type = hdr_data_chunk_type;
776 HDR_DATA_CHUNK.bits = hdr_data_chunk_bits;
777 HDR_DATA_CHUNK.length = g_htons(length - header_length + sizeof(HDR_DATA_CHUNK));
778 HDR_DATA_CHUNK.tsn = g_htonl(hdr_data_chunk_tsn);
779 HDR_DATA_CHUNK.sid = g_htons(hdr_data_chunk_sid);
780 HDR_DATA_CHUNK.ssn = g_htons(hdr_data_chunk_ssn);
781 HDR_DATA_CHUNK.ppid = g_htonl(hdr_data_chunk_ppid);
782 hdr_data_chunk_tsn++;
784 hdr_data_chunk_ssn++;
788 /* Write SCTP common header */
792 HDR_SCTP.src_port = isInbound ? g_htons(hdr_sctp_dest): g_htons(hdr_sctp_src);
793 HDR_SCTP.dest_port = isInbound ? g_htons(hdr_sctp_src) : g_htons(hdr_sctp_dest);
794 HDR_SCTP.tag = g_htonl(hdr_sctp_tag);
795 HDR_SCTP.checksum = g_htonl(0);
796 HDR_SCTP.checksum = crc32c((guint8 *)&HDR_SCTP, sizeof(HDR_SCTP), ~0);
797 if (hdr_data_chunk) {
798 HDR_SCTP.checksum = crc32c((guint8 *)&HDR_DATA_CHUNK, sizeof(HDR_DATA_CHUNK), HDR_SCTP.checksum);
799 HDR_SCTP.checksum = crc32c((guint8 *)packet_buf + header_length, length - header_length, HDR_SCTP.checksum);
800 HDR_SCTP.checksum = crc32c((guint8 *)&zero, padding_length, HDR_SCTP.checksum);
802 HDR_SCTP.checksum = crc32c((guint8 *)packet_buf + header_length, length - header_length, HDR_SCTP.checksum);
804 HDR_SCTP.checksum = finalize_crc32c(HDR_SCTP.checksum);
805 HDR_SCTP.checksum = g_htonl(HDR_SCTP.checksum);
806 write_bytes((const char *)&HDR_SCTP, sizeof(HDR_SCTP));
809 /* Write DATA chunk header */
810 if (hdr_data_chunk) {
811 write_bytes((const char *)&HDR_DATA_CHUNK, sizeof(HDR_DATA_CHUNK));
814 /* Reset curr_offset, since we now write the trailers */
815 curr_offset = length;
817 /* Write DATA chunk padding */
818 if (hdr_data_chunk && (padding_length > 0)) {
819 memset(tempbuf, 0, padding_length);
820 write_bytes((const char *)&tempbuf, padding_length);
821 length += padding_length;
824 /* Write Ethernet trailer */
825 if (hdr_ethernet && (length < 60)) {
826 memset(tempbuf, 0, 60 - length);
827 write_bytes((const char *)&tempbuf, 60 - length);
831 success = pcapng_write_enhanced_packet_block(output_file,
837 packet_buf, direction,
838 &bytes_written, &err);
840 success = libpcap_write_packet(output_file,
841 ts_sec, ts_nsec/1000,
844 &bytes_written, &err);
847 fprintf(stderr, "File write error [%s] : %s\n",
848 output_filename, g_strerror(err));
851 if (ts_fmt == NULL) {
852 /* fake packet counter */
859 fprintf(stderr, "Wrote packet of %u bytes.\n", length);
861 num_packets_written++;
864 packet_start += curr_offset - header_length;
865 curr_offset = header_length;
869 /*----------------------------------------------------------------------
870 * Write file header and trailer
873 write_file_header (void)
881 comment = g_strdup_printf("Generated from input file %s.", input_filename);
882 success = pcapng_write_section_header_block(output_file,
886 get_appname_and_version(),
887 -1, /* section_length */
892 success = pcapng_write_interface_description_block(output_file,
899 WTAP_MAX_PACKET_SIZE_STANDARD,
906 success = libpcap_write_file_header(output_file, pcap_link_type,
907 WTAP_MAX_PACKET_SIZE_STANDARD, FALSE,
908 &bytes_written, &err);
911 fprintf(stderr, "File write error [%s] : %s\n",
912 output_filename, g_strerror(err));
919 /*----------------------------------------------------------------------
920 * Append a token to the packet preamble.
923 append_to_preamble (char *str)
927 if (packet_preamble_len != 0) {
928 if (packet_preamble_len == PACKET_PREAMBLE_MAX_LEN)
929 return; /* no room to add more preamble */
930 /* Add a blank separator between the previous token and this token. */
931 packet_preamble[packet_preamble_len++] = ' ';
933 toklen = strlen(str);
935 if (packet_preamble_len + toklen > PACKET_PREAMBLE_MAX_LEN)
936 return; /* no room to add the token to the preamble */
937 g_strlcpy(&packet_preamble[packet_preamble_len], str, PACKET_PREAMBLE_MAX_LEN);
938 packet_preamble_len += (int) toklen;
941 char xs[PACKET_PREAMBLE_MAX_LEN];
942 g_strlcpy(xs, packet_preamble, PACKET_PREAMBLE_MAX_LEN);
943 while ((c = strchr(xs, '\r')) != NULL) *c=' ';
944 fprintf (stderr, "[[append_to_preamble: \"%s\"]]", xs);
949 /*----------------------------------------------------------------------
950 * Parse the preamble to get the timecode.
954 parse_preamble (void)
963 * Null-terminate the preamble.
965 packet_preamble[packet_preamble_len] = '\0';
967 fprintf(stderr, "[[parse_preamble: \"%s\"]]\n", packet_preamble);
970 switch (packet_preamble[0]) {
973 direction = 0x00000001;
974 packet_preamble[0] = ' ';
978 direction = 0x00000002;
979 packet_preamble[0] = ' ';
982 direction = 0x00000000;
986 while (packet_preamble[i] == ' ' ||
987 packet_preamble[i] == '\r' ||
988 packet_preamble[i] == '\t') {
991 packet_preamble_len -= i;
992 /* Also move the trailing '\0'. */
993 memmove(packet_preamble, packet_preamble + i, packet_preamble_len + 1);
998 * If no "-t" flag was specified, don't attempt to parse the packet
999 * preamble to extract a time stamp.
1001 if (ts_fmt == NULL) {
1002 /* Clear Preamble */
1003 packet_preamble_len = 0;
1008 * Initialize to today localtime, just in case not all fields
1009 * of the date and time are specified.
1012 timecode = timecode_default;
1015 /* Ensure preamble has more than two chars before attempting to parse.
1016 * This should cover line breaks etc that get counted.
1018 if (strlen(packet_preamble) > 2) {
1019 /* Get Time leaving subseconds */
1020 subsecs = strptime( packet_preamble, ts_fmt, &timecode );
1021 if (subsecs != NULL) {
1022 /* Get the long time from the tm structure */
1023 /* (will return -1 if failure) */
1024 ts_sec = mktime( &timecode );
1026 ts_sec = -1; /* we failed to parse it */
1028 /* This will ensure incorrectly parsed dates get set to zero */
1030 /* Sanitize - remove all '\r' */
1032 while ((c = strchr(packet_preamble, '\r')) != NULL) *c=' ';
1033 fprintf (stderr, "Failure processing time \"%s\" using time format \"%s\"\n (defaulting to Jan 1,1970 00:00:00 GMT)\n",
1034 packet_preamble, ts_fmt);
1036 fprintf(stderr, "timecode: %02d/%02d/%d %02d:%02d:%02d %d\n",
1037 timecode.tm_mday, timecode.tm_mon, timecode.tm_year,
1038 timecode.tm_hour, timecode.tm_min, timecode.tm_sec, timecode.tm_isdst);
1040 ts_sec = 0; /* Jan 1,1970: 00:00 GMT; tshark/wireshark will display date/time as adjusted by timezone */
1043 /* Parse subseconds */
1044 ts_nsec = (guint32)strtol(subsecs, &p, 10);
1050 * Convert that number to a number
1051 * of microseconds; if it's N digits
1052 * long, it's in units of 10^(-N) seconds,
1053 * so, to convert it to units of
1054 * 10^-9 seconds, we multiply by
1057 subseclen = (int) (p - subsecs);
1058 if (subseclen > 9) {
1060 * *More* than 9 digits; 9-N is
1061 * negative, so we divide by
1064 for (i = subseclen - 9; i != 0; i--)
1066 } else if (subseclen < 9) {
1067 for (i = 9 - subseclen; i != 0; i--)
1075 while ((c = strchr(packet_preamble, '\r')) != NULL) *c=' ';
1076 fprintf(stderr, "[[parse_preamble: \"%s\"]]\n", packet_preamble);
1077 fprintf(stderr, "Format(%s), time(%u), subsecs(%u)\n", ts_fmt, (guint32)ts_sec, ts_nsec);
1081 /* Clear Preamble */
1082 packet_preamble_len = 0;
1085 /*----------------------------------------------------------------------
1086 * Start a new packet
1089 start_new_packet (gboolean cont)
1092 fprintf(stderr, "Start new packet (cont = %s).\n", cont ? "TRUE" : "FALSE");
1094 /* Write out the current packet, if required */
1095 if (write_current_packet(cont) != EXIT_SUCCESS)
1096 return EXIT_FAILURE;
1099 /* Ensure we parse the packet preamble as it may contain the time */
1102 return EXIT_SUCCESS;
1105 /*----------------------------------------------------------------------
1106 * Process a directive
1109 process_directive (char *str)
1111 fprintf(stderr, "\n--- Directive [%s] currently unsupported ---\n", str + 10);
1114 /*----------------------------------------------------------------------
1115 * Parse a single token (called from the scanner)
1118 parse_token (token_t token, char *str)
1129 * This is implemented as a simple state machine of five states.
1130 * State transitions are caused by tokens being received from the
1131 * scanner. The code should be self-documenting.
1135 /* Sanitize - remove all '\r' */
1137 if (str!=NULL) { while ((c = strchr(str, '\r')) != NULL) *c=' '; }
1139 fprintf(stderr, "(%s, %s \"%s\") -> (",
1140 state_str[state], token_str[token], str ? str : "");
1145 /* ----- Waiting for new packet -------------------------------------------*/
1147 if (!str && token != T_EOL) goto fail_null_str;
1150 append_to_preamble(str);
1153 process_directive(str);
1156 if (parse_num(str, TRUE, &num) != EXIT_SUCCESS)
1157 return EXIT_FAILURE;
1159 /* New packet starts here */
1160 if (start_new_packet(FALSE) != EXIT_SUCCESS)
1161 return EXIT_FAILURE;
1162 state = READ_OFFSET;
1163 pkt_lnstart = packet_buf + num;
1167 /* Some describing text may be parsed as offset, but the invalid
1168 offset will be checked in the state of START_OF_LINE, so
1169 we add this transition to gain flexibility */
1170 state = START_OF_LINE;
1177 /* ----- Processing packet, start of new line -----------------------------*/
1179 if (!str && token != T_EOL) goto fail_null_str;
1182 append_to_preamble(str);
1185 process_directive(str);
1188 if (parse_num(str, TRUE, &num) != EXIT_SUCCESS)
1189 return EXIT_FAILURE;
1191 /* New packet starts here */
1192 if (start_new_packet(FALSE) != EXIT_SUCCESS)
1193 return EXIT_FAILURE;
1195 state = READ_OFFSET;
1196 } else if ((num - packet_start) != curr_offset - header_length) {
1198 * The offset we read isn't the one we expected.
1199 * This may only mean that we mistakenly interpreted
1200 * some text as byte values (e.g., if the text dump
1201 * of packet data included a number with spaces around
1202 * it). If the offset is less than what we expected,
1203 * assume that's the problem, and throw away the putative
1204 * extra byte values.
1206 if (num < curr_offset) {
1207 unwrite_bytes(curr_offset - num);
1208 state = READ_OFFSET;
1210 /* Bad offset; switch to INIT state */
1212 fprintf(stderr, "Inconsistent offset. Expecting %0X, got %0X. Ignoring rest of packet\n",
1214 if (write_current_packet(FALSE) != EXIT_SUCCESS)
1215 return EXIT_FAILURE;
1219 state = READ_OFFSET;
1221 pkt_lnstart = packet_buf + num;
1224 state = START_OF_LINE;
1231 /* ----- Processing packet, read offset -----------------------------------*/
1235 /* Record the byte */
1237 if (!str) goto fail_null_str;
1238 if (write_byte(str) != EXIT_SUCCESS)
1239 return EXIT_FAILURE;
1247 state = START_OF_LINE;
1254 /* ----- Processing packet, read byte -------------------------------------*/
1258 /* Record the byte */
1259 if (write_byte(str) != EXIT_SUCCESS)
1260 return EXIT_FAILURE;
1268 if (token == T_EOL) {
1270 state = START_OF_LINE;
1272 if (identify_ascii) {
1273 /* Here a line of pkt bytes reading is finished
1274 compare the ascii and hex to avoid such situation:
1275 "61 62 20 ab ", when ab is ascii dump then it should
1276 not be treat as byte */
1278 /* s2 is the ASCII string, s1 is the HEX string, e.g, when
1279 s2 = "ab ", s1 = "616220"
1280 we should find out the largest tail of s1 matches the head
1281 of s2, it means the matched part in tail is the ASCII dump
1282 of the head byte. These matched should be rollback */
1283 line_size = curr_offset-(int)(pkt_lnstart-packet_buf);
1284 s2 = (char*)g_malloc((line_size+1)/4+1);
1285 /* gather the possible pattern */
1286 for (i = 0; i < (line_size+1)/4; i++) {
1287 tmp_str[0] = pkt_lnstart[i*3];
1288 tmp_str[1] = pkt_lnstart[i*3+1];
1290 /* it is a valid convertable string */
1291 if (!g_ascii_isxdigit(tmp_str[0]) || !g_ascii_isxdigit(tmp_str[1])) {
1294 s2[i] = (char)strtoul(tmp_str, (char **)NULL, 16);
1296 /* the 3rd entry is not a delimiter, so the possible byte pattern will not shown */
1297 if (!(pkt_lnstart[i*3+2] == ' ')) {
1303 /* If packet line start contains possible byte pattern, the line end
1304 should contain the matched pattern if the user open the -a flag.
1305 The packet will be possible invalid if the byte pattern cannot find
1306 a matched one in the line of packet buffer.*/
1308 if (strncmp(pkt_lnstart+line_size-rollback, s2, rollback) == 0) {
1309 unwrite_bytes(rollback);
1311 /* Not matched. This line contains invalid packet bytes, so
1312 discard the whole line */
1314 unwrite_bytes(line_size);
1325 /* ----- Processing packet, read text -------------------------------------*/
1329 state = START_OF_LINE;
1337 fprintf(stderr, "FATAL ERROR: Bad state (%d)", state);
1338 return EXIT_FAILURE;
1342 fprintf(stderr, ", %s)\n", state_str[state]);
1344 return EXIT_SUCCESS;
1347 fprintf(stderr, "FATAL ERROR: got NULL str pointer in state (%d)", state);
1348 return EXIT_FAILURE;
1351 /*----------------------------------------------------------------------
1352 * Print usage string and exit
1355 print_usage (FILE *output)
1359 "Usage: text2pcap [options] <infile> <outfile>\n"
1361 "where <infile> specifies input filename (use - for standard input)\n"
1362 " <outfile> specifies output filename (use - for standard output)\n"
1365 " -o hex|oct|dec parse offsets as (h)ex, (o)ctal or (d)ecimal;\n"
1366 " default is hex.\n"
1367 " -t <timefmt> treat the text before the packet as a date/time code;\n"
1368 " the specified argument is a format string of the sort\n"
1369 " supported by strptime.\n"
1370 " Example: The time \"10:15:14.5476\" has the format code\n"
1371 " \"%%H:%%M:%%S.\"\n"
1372 " NOTE: The subsecond component delimiter, '.', must be\n"
1373 " given, but no pattern is required; the remaining\n"
1374 " number is assumed to be fractions of a second.\n"
1375 " NOTE: Date/time fields from the current date/time are\n"
1376 " used as the default for unspecified fields.\n"
1377 " -D the text before the packet starts with an I or an O,\n"
1378 " indicating that the packet is inbound or outbound.\n"
1379 " This is used when generating dummy headers.\n"
1380 " The indication is only stored if the output format is pcapng.\n"
1381 " -a enable ASCII text dump identification.\n"
1382 " The start of the ASCII text dump can be identified\n"
1383 " and excluded from the packet data, even if it looks\n"
1384 " like a HEX dump.\n"
1385 " NOTE: Do not enable it if the input file does not\n"
1386 " contain the ASCII text dump.\n"
1389 " -l <typenum> link-layer type number; default is 1 (Ethernet). See\n"
1390 " http://www.tcpdump.org/linktypes.html for a list of\n"
1391 " numbers. Use this option if your dump is a complete\n"
1392 " hex dump of an encapsulated packet and you wish to\n"
1393 " specify the exact type of encapsulation.\n"
1394 " Example: -l 7 for ARCNet packets.\n"
1395 " -m <max-packet> max packet length in output; default is %d\n"
1396 " -n use pcapng instead of pcap as output format.\n"
1397 " -N <intf-name> assign name to the interface in the pcapng file.\n"
1399 "Prepend dummy header:\n"
1400 " -e <l3pid> prepend dummy Ethernet II header with specified L3PID\n"
1402 " Example: -e 0x806 to specify an ARP packet.\n"
1403 " -i <proto> prepend dummy IP header with specified IP protocol\n"
1405 " Automatically prepends Ethernet header as well.\n"
1407 " -4 <srcip>,<destip> prepend dummy IPv4 header with specified\n"
1408 " dest and source address.\n"
1409 " Example: -4 10.0.0.1,10.0.0.2\n"
1410 " -6 <srcip>,<destip> prepend dummy IPv6 header with specified\n"
1411 " dest and source address.\n"
1412 " Example: -6 fe80::202:b3ff:fe1e:8329,2001:0db8:85a3::8a2e:0370:7334\n"
1413 " -u <srcp>,<destp> prepend dummy UDP header with specified\n"
1414 " source and destination ports (in DECIMAL).\n"
1415 " Automatically prepends Ethernet & IP headers as well.\n"
1416 " Example: -u 1000,69 to make the packets look like\n"
1417 " TFTP/UDP packets.\n"
1418 " -T <srcp>,<destp> prepend dummy TCP header with specified\n"
1419 " source and destination ports (in DECIMAL).\n"
1420 " Automatically prepends Ethernet & IP headers as well.\n"
1421 " Example: -T 50,60\n"
1422 " -s <srcp>,<dstp>,<tag> prepend dummy SCTP header with specified\n"
1423 " source/dest ports and verification tag (in DECIMAL).\n"
1424 " Automatically prepends Ethernet & IP headers as well.\n"
1425 " Example: -s 30,40,34\n"
1426 " -S <srcp>,<dstp>,<ppi> prepend dummy SCTP header with specified\n"
1427 " source/dest ports and verification tag 0.\n"
1428 " Automatically prepends a dummy SCTP DATA\n"
1429 " chunk header with payload protocol identifier ppi.\n"
1430 " Example: -S 30,40,34\n"
1433 " -h display this help and exit.\n"
1434 " -d show detailed debug of parser states.\n"
1435 " -q generate no output at all (automatically disables -d).\n"
1437 WTAP_MAX_PACKET_SIZE_STANDARD);
1440 /*----------------------------------------------------------------------
1444 parse_options (int argc, char *argv[])
1448 static const struct option long_options[] = {
1449 {"help", no_argument, NULL, 'h'},
1450 {"version", no_argument, NULL, 'v'},
1455 /* Initialize the version information. */
1456 ws_init_version_info("Text2pcap (Wireshark)", NULL, NULL, NULL);
1458 /* Scan CLI parameters */
1459 while ((c = getopt_long(argc, argv, "aDdhqe:i:l:m:nN:o:u:s:S:t:T:v4:6:", long_options, NULL)) != -1) {
1462 show_help_header("Generate a capture file from an ASCII hexdump of packets.");
1463 print_usage(stdout);
1466 case 'd': if (!quiet) debug++; break;
1467 case 'D': has_direction = TRUE; break;
1468 case 'q': quiet = TRUE; debug = 0; break;
1469 case 'l': pcap_link_type = (guint32)strtol(optarg, NULL, 0); break;
1470 case 'm': max_offset = (guint32)strtol(optarg, NULL, 0); break;
1471 case 'n': use_pcapng = TRUE; break;
1472 case 'N': interface_name = optarg; break;
1474 if (optarg[0] != 'h' && optarg[0] != 'o' && optarg[0] != 'd') {
1475 fprintf(stderr, "Bad argument for '-o': %s\n", optarg);
1476 print_usage(stderr);
1477 return EXIT_FAILURE;
1479 switch (optarg[0]) {
1480 case 'o': offset_base = 8; break;
1481 case 'h': offset_base = 16; break;
1482 case 'd': offset_base = 10; break;
1486 hdr_ethernet = TRUE;
1487 if (sscanf(optarg, "%x", &hdr_ethernet_proto) < 1) {
1488 fprintf(stderr, "Bad argument for '-e': %s\n", optarg);
1489 print_usage(stderr);
1490 return EXIT_FAILURE;
1495 hdr_ip_proto = strtol(optarg, &p, 10);
1496 if (p == optarg || *p != '\0' || hdr_ip_proto < 0 ||
1497 hdr_ip_proto > 255) {
1498 fprintf(stderr, "Bad argument for '-i': %s\n", optarg);
1499 print_usage(stderr);
1500 return EXIT_FAILURE;
1502 hdr_ethernet = TRUE;
1507 hdr_data_chunk = FALSE;
1510 hdr_sctp_src = (guint32)strtol(optarg, &p, 10);
1511 if (p == optarg || (*p != ',' && *p != '\0')) {
1512 fprintf(stderr, "Bad src port for '-%c'\n", c);
1513 print_usage(stderr);
1514 return EXIT_FAILURE;
1517 fprintf(stderr, "No dest port specified for '-%c'\n", c);
1518 print_usage(stderr);
1519 return EXIT_FAILURE;
1523 hdr_sctp_dest = (guint32)strtol(optarg, &p, 10);
1524 if (p == optarg || (*p != ',' && *p != '\0')) {
1525 fprintf(stderr, "Bad dest port for '-s'\n");
1526 print_usage(stderr);
1527 return EXIT_FAILURE;
1530 fprintf(stderr, "No tag specified for '-%c'\n", c);
1531 print_usage(stderr);
1532 return EXIT_FAILURE;
1536 hdr_sctp_tag = (guint32)strtol(optarg, &p, 10);
1537 if (p == optarg || *p != '\0') {
1538 fprintf(stderr, "Bad tag for '-%c'\n", c);
1539 print_usage(stderr);
1540 return EXIT_FAILURE;
1544 hdr_ethernet = TRUE;
1548 hdr_data_chunk = TRUE;
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 ppi specified for '-%c'\n", c);
1572 print_usage(stderr);
1573 return EXIT_FAILURE;
1577 hdr_data_chunk_ppid = (guint32)strtoul(optarg, &p, 10);
1578 if (p == optarg || *p != '\0') {
1579 fprintf(stderr, "Bad ppi for '-%c'\n", c);
1580 print_usage(stderr);
1581 return EXIT_FAILURE;
1585 hdr_ethernet = TRUE;
1596 hdr_data_chunk = FALSE;
1597 hdr_src_port = (guint32)strtol(optarg, &p, 10);
1598 if (p == optarg || (*p != ',' && *p != '\0')) {
1599 fprintf(stderr, "Bad src port for '-u'\n");
1600 print_usage(stderr);
1601 return EXIT_FAILURE;
1604 fprintf(stderr, "No dest port specified for '-u'\n");
1605 print_usage(stderr);
1606 return EXIT_FAILURE;
1610 hdr_dest_port = (guint32)strtol(optarg, &p, 10);
1611 if (p == optarg || *p != '\0') {
1612 fprintf(stderr, "Bad dest port for '-u'\n");
1613 print_usage(stderr);
1614 return EXIT_FAILURE;
1617 hdr_ethernet = TRUE;
1624 hdr_data_chunk = FALSE;
1625 hdr_src_port = (guint32)strtol(optarg, &p, 10);
1626 if (p == optarg || (*p != ',' && *p != '\0')) {
1627 fprintf(stderr, "Bad src port for '-T'\n");
1628 print_usage(stderr);
1629 return EXIT_FAILURE;
1632 fprintf(stderr, "No dest port specified for '-u'\n");
1633 print_usage(stderr);
1634 return EXIT_FAILURE;
1638 hdr_dest_port = (guint32)strtol(optarg, &p, 10);
1639 if (p == optarg || *p != '\0') {
1640 fprintf(stderr, "Bad dest port for '-T'\n");
1641 print_usage(stderr);
1642 return EXIT_FAILURE;
1645 hdr_ethernet = TRUE;
1649 identify_ascii = TRUE;
1659 p = strchr(optarg, ',');
1662 fprintf(stderr, "Bad source param addr for '-%c'\n", c);
1663 print_usage(stderr);
1664 return EXIT_FAILURE;
1678 hdr_ethernet = TRUE;
1680 if (hdr_ipv6 == TRUE) {
1681 if (!ws_inet_pton6(optarg, &hdr_ipv6_src_addr)) {
1682 fprintf(stderr, "Bad src addr -%c '%s'\n", c, p);
1683 print_usage(stderr);
1684 return EXIT_FAILURE;
1687 if (!ws_inet_pton4(optarg, &hdr_ip_src_addr)) {
1688 fprintf(stderr, "Bad src addr -%c '%s'\n", c, p);
1689 print_usage(stderr);
1690 return EXIT_FAILURE;
1696 fprintf(stderr, "No dest addr specified for '-%c'\n", c);
1697 print_usage(stderr);
1698 return EXIT_FAILURE;
1701 if (hdr_ipv6 == TRUE) {
1702 if (!ws_inet_pton6(p, &hdr_ipv6_dest_addr)) {
1703 fprintf(stderr, "Bad dest addr for -%c '%s'\n", c, p);
1704 print_usage(stderr);
1705 return EXIT_FAILURE;
1708 if (!ws_inet_pton4(p, &hdr_ip_dest_addr)) {
1709 fprintf(stderr, "Bad dest addr for -%c '%s'\n", c, p);
1710 print_usage(stderr);
1711 return EXIT_FAILURE;
1719 print_usage(stderr);
1720 return EXIT_FAILURE;
1724 if (optind >= argc || argc-optind < 2) {
1725 fprintf(stderr, "Must specify input and output filename\n");
1726 print_usage(stderr);
1727 return EXIT_FAILURE;
1730 if (max_offset > WTAP_MAX_PACKET_SIZE_STANDARD) {
1731 fprintf(stderr, "Maximum packet length cannot be more than %d bytes\n",
1732 WTAP_MAX_PACKET_SIZE_STANDARD);
1733 return EXIT_FAILURE;
1736 if (strcmp(argv[optind], "-") != 0) {
1737 input_filename = argv[optind];
1738 input_file = ws_fopen(input_filename, "rb");
1740 fprintf(stderr, "Cannot open file [%s] for reading: %s\n",
1741 input_filename, g_strerror(errno));
1742 return EXIT_FAILURE;
1745 input_filename = "Standard input";
1749 if (strcmp(argv[optind+1], "-") != 0) {
1750 /* Write to a file. Open the file, in binary mode. */
1751 output_filename = argv[optind+1];
1752 output_file = ws_fopen(output_filename, "wb");
1754 fprintf(stderr, "Cannot open file [%s] for writing: %s\n",
1755 output_filename, g_strerror(errno));
1756 return EXIT_FAILURE;
1759 /* Write to the standard output. */
1761 /* Put the standard output in binary mode. */
1762 if (_setmode(1, O_BINARY) == -1) {
1763 /* "Should not happen" */
1764 fprintf(stderr, "Cannot put standard output in binary mode: %s\n",
1766 return EXIT_FAILURE;
1769 output_filename = "Standard output";
1770 output_file = stdout;
1773 /* Some validation */
1774 if (pcap_link_type != 1 && hdr_ethernet) {
1775 fprintf(stderr, "Dummy headers (-e, -i, -u, -s, -S -T) cannot be specified with link type override (-l)\n");
1776 return EXIT_FAILURE;
1779 /* Set up our variables */
1782 input_filename = "Standard input";
1785 output_file = stdout;
1786 output_filename = "Standard output";
1789 ts_sec = time(0); /* initialize to current time */
1790 now_tm = localtime(&ts_sec);
1791 if (now_tm == NULL) {
1793 * This shouldn't happen - on UN*X, this should Just Work, and
1794 * on Windows, it won't work if ts_sec is before the Epoch,
1795 * but it's long after 1970, so....
1797 fprintf(stderr, "localtime(right now) failed\n");
1798 return EXIT_FAILURE;
1800 timecode_default = *now_tm;
1801 timecode_default.tm_isdst = -1; /* Unknown for now, depends on time given to the strptime() function */
1803 if (hdr_ip_proto != -1 && !(hdr_ip || hdr_ipv6)) {
1804 /* If -i <proto> option is specified without -4 or -6 then add the default IPv4 header */
1808 if (hdr_ip_proto == -1 && (hdr_ip || hdr_ipv6)) {
1809 /* if -4 or -6 option is specified without an IP protocol then fail */
1810 fprintf(stderr, "IP protocol requires a next layer protocol number\n");
1811 return EXIT_FAILURE;
1814 if ((hdr_tcp || hdr_udp || hdr_sctp) && !(hdr_ip || hdr_ipv6)) {
1816 * If TCP (-T), UDP (-u) or SCTP (-s/-S) header options are specified
1817 * but none of IPv4 (-4) or IPv6 (-6) options then add an IPv4 header
1824 hdr_ethernet_proto = 0x0800;
1825 } else if (hdr_ipv6)
1827 hdr_ethernet_proto = 0x86DD;
1830 /* Display summary of our state */
1832 fprintf(stderr, "Input from: %s\n", input_filename);
1833 fprintf(stderr, "Output to: %s\n", output_filename);
1834 fprintf(stderr, "Output format: %s\n", use_pcapng ? "pcapng" : "pcap");
1836 if (hdr_ethernet) fprintf(stderr, "Generate dummy Ethernet header: Protocol: 0x%0X\n",
1837 hdr_ethernet_proto);
1838 if (hdr_ip) fprintf(stderr, "Generate dummy IP header: Protocol: %ld\n",
1840 if (hdr_ipv6) fprintf(stderr, "Generate dummy IPv6 header: Protocol: %ld\n",
1842 if (hdr_udp) fprintf(stderr, "Generate dummy UDP header: Source port: %u. Dest port: %u\n",
1843 hdr_src_port, hdr_dest_port);
1844 if (hdr_tcp) fprintf(stderr, "Generate dummy TCP header: Source port: %u. Dest port: %u\n",
1845 hdr_src_port, hdr_dest_port);
1846 if (hdr_sctp) fprintf(stderr, "Generate dummy SCTP header: Source port: %u. Dest port: %u. Tag: %u\n",
1847 hdr_sctp_src, hdr_sctp_dest, hdr_sctp_tag);
1848 if (hdr_data_chunk) fprintf(stderr, "Generate dummy DATA chunk header: TSN: %u. SID: %u. SSN: %u. PPID: %u\n",
1849 hdr_data_chunk_tsn, hdr_data_chunk_sid, hdr_data_chunk_ssn, hdr_data_chunk_ppid);
1852 return EXIT_SUCCESS;
1856 main(int argc, char *argv[])
1858 int ret = EXIT_SUCCESS;
1861 create_app_running_mutex();
1864 if (parse_options(argc, argv) != EXIT_SUCCESS) {
1869 assert(input_file != NULL);
1870 assert(output_file != NULL);
1872 if (write_file_header() != EXIT_SUCCESS) {
1879 header_length += (int)sizeof(HDR_ETHERNET);
1882 ip_offset = header_length;
1883 header_length += (int)sizeof(HDR_IP);
1884 } else if (hdr_ipv6) {
1885 ip_offset = header_length;
1886 header_length += (int)sizeof(HDR_IPv6);
1889 header_length += (int)sizeof(HDR_SCTP);
1891 if (hdr_data_chunk) {
1892 header_length += (int)sizeof(HDR_DATA_CHUNK);
1895 header_length += (int)sizeof(HDR_TCP);
1898 header_length += (int)sizeof(HDR_UDP);
1900 curr_offset = header_length;
1902 text2pcap_in = input_file;
1903 if (text2pcap_scan() == EXIT_SUCCESS) {
1904 if (write_current_packet(FALSE) != EXIT_SUCCESS)
1910 fprintf(stderr, "\n-------------------------\n");
1912 fprintf(stderr, "Read %u potential packet%s, wrote %u packet%s (%" G_GINT64_MODIFIER "u byte%s).\n",
1913 num_packets_read, (num_packets_read == 1) ? "" : "s",
1914 num_packets_written, (num_packets_written == 1) ? "" : "s",
1915 bytes_written, (bytes_written == 1) ? "" : "s");
1922 fclose(output_file);
1928 * Editor modelines - http://www.wireshark.org/tools/modelines.html
1933 * indent-tabs-mode: nil
1936 * vi: set shiftwidth=4 tabstop=8 expandtab:
1937 * :indentSize=4:tabSize=8:noTabs=true: