Link version code statically again
[metze/wireshark/wip.git] / text2pcap.c
1 /**-*-C-*-**********************************************************************
2  *
3  * text2pcap.c
4  *
5  * Utility to convert an ASCII hexdump into a libpcap-format capture file
6  *
7  * (c) Copyright 2001 Ashok Narayanan <ashokn@cisco.com>
8  *
9  * Wireshark - Network traffic analyzer
10  * By Gerald Combs <gerald@wireshark.org>
11  * Copyright 1998 Gerald Combs
12  *
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.
17  *
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.
22  *
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.
26  *
27  *******************************************************************************/
28
29 /*******************************************************************************
30  *
31  * This utility reads in an ASCII hexdump of this common format:
32  *
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......
37  *
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:
44  *
45  * - No text appears between the offset and the bytes (any bytes appearing after
46  *   such text would be ignored)
47  *
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
51  *
52  * A packet start is signaled by a zero offset.
53  *
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.
58  *
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.
63  *
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.
68  *
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.
73  *
74  * This converter cannot read a single packet greater than 64KiB-1. Packet
75  * snaplength is automatically set to 64KiB-1.
76  */
77
78 #include <config.h>
79
80 /*
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
83  * yet defined.
84  */
85 #ifndef __USE_XOPEN
86 #  define __USE_XOPEN
87 #endif
88 #ifndef _XOPEN_SOURCE
89 #  ifndef __sun
90 #    define _XOPEN_SOURCE 600
91 #  endif
92 #endif
93
94 /*
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.
97  *
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.
103  *
104  * So we define __EXTENSIONS__ so that "strptime()" is declared.
105  */
106 #ifndef __EXTENSIONS__
107 #  define __EXTENSIONS__
108 #endif
109
110 #include <stdio.h>
111 #include <stdlib.h>
112 #include <string.h>
113 #include <wsutil/file_util.h>
114 #include <wsutil/crash_info.h>
115 #include <ws_version_info.h>
116 #include <wsutil/inet_addr.h>
117
118 #include <time.h>
119 #include <glib.h>
120
121 #ifdef HAVE_GETOPT_H
122 #include <getopt.h>
123 #endif
124
125 #include <errno.h>
126 #include <assert.h>
127
128 #ifndef HAVE_GETOPT_LONG
129 #include "wsutil/wsgetopt.h"
130 #endif
131
132 #ifndef HAVE_STRPTIME
133 # include "wsutil/strptime.h"
134 #endif
135
136 #include "writecap/pcapio.h"
137 #include "text2pcap.h"
138
139 #ifdef _WIN32
140 #include <wsutil/unicode-utils.h>
141 #endif /* _WIN32 */
142
143 /*--- Options --------------------------------------------------------------------*/
144
145 /* File format */
146 static gboolean use_pcapng = FALSE;
147
148 /* Debug level */
149 static int debug = 0;
150 /* Be quiet */
151 static int quiet = FALSE;
152
153 /* Dummy Ethernet header */
154 static int hdr_ethernet = FALSE;
155 static guint32 hdr_ethernet_proto = 0;
156
157 /* Dummy IP header */
158 static int hdr_ip = FALSE;
159 static int hdr_ipv6 = FALSE;
160 static long hdr_ip_proto = 0;
161
162 /* Destination and source addresses for IP header */
163 static guint32 hdr_ip_dest_addr = 0;
164 static guint32 hdr_ip_src_addr = 0;
165 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}};
166 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}};
167 static struct e_in6_addr NO_IPv6_ADDRESS    = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
168
169 /* Dummy UDP header */
170 static int     hdr_udp       = FALSE;
171 static guint32 hdr_dest_port = 0;
172 static guint32 hdr_src_port  = 0;
173
174 /* Dummy TCP header */
175 static int hdr_tcp = FALSE;
176
177 /* TCP sequence numbers when has_direction is true */
178 static guint32 tcp_in_seq_num = 0;
179 static guint32 tcp_out_seq_num = 0;
180
181 /* Dummy SCTP header */
182 static int hdr_sctp = FALSE;
183 static guint32 hdr_sctp_src  = 0;
184 static guint32 hdr_sctp_dest = 0;
185 static guint32 hdr_sctp_tag  = 0;
186
187 /* Dummy DATA chunk header */
188 static int hdr_data_chunk = FALSE;
189 static guint8  hdr_data_chunk_type = 0;
190 static guint8  hdr_data_chunk_bits = 0;
191 static guint32 hdr_data_chunk_tsn  = 0;
192 static guint16 hdr_data_chunk_sid  = 0;
193 static guint16 hdr_data_chunk_ssn  = 0;
194 static guint32 hdr_data_chunk_ppid = 0;
195
196 /* ASCII text dump identification */
197 static int identify_ascii = FALSE;
198
199 static gboolean has_direction = FALSE;
200 static guint32 direction = 0;
201
202 /*--- Local date -----------------------------------------------------------------*/
203
204 /* This is where we store the packet currently being built */
205 #define MAX_PACKET 65535
206 static guint8  packet_buf[MAX_PACKET];
207 static guint32 header_length;
208 static guint32 ip_offset;
209 static guint32 curr_offset;
210 static guint32 max_offset = MAX_PACKET;
211 static guint32 packet_start = 0;
212
213 static void start_new_packet(gboolean);
214
215 /* This buffer contains strings present before the packet offset 0 */
216 #define PACKET_PREAMBLE_MAX_LEN     2048
217 static guint8 packet_preamble[PACKET_PREAMBLE_MAX_LEN+1];
218 static int    packet_preamble_len = 0;
219
220 /* Number of packets read and written */
221 static guint32 num_packets_read    = 0;
222 static guint32 num_packets_written = 0;
223 static guint64 bytes_written       = 0;
224
225 /* Time code of packet, derived from packet_preamble */
226 static time_t   ts_sec  = 0;
227 static guint32  ts_nsec = 0;
228 static char    *ts_fmt  = NULL;
229 static struct tm timecode_default;
230
231 static guint8* pkt_lnstart;
232
233 /* Input file */
234 static const char *input_filename;
235 static FILE       *input_file  = NULL;
236 /* Output file */
237 static const char *output_filename;
238 static FILE       *output_file = NULL;
239
240 /* Offset base to parse */
241 static guint32 offset_base = 16;
242
243 extern FILE *yyin;
244
245 /* ----- State machine -----------------------------------------------------------*/
246
247 /* Current state of parser */
248 typedef enum {
249     INIT,             /* Waiting for start of new packet */
250     START_OF_LINE,    /* Starting from beginning of line */
251     READ_OFFSET,      /* Just read the offset */
252     READ_BYTE,        /* Just read a byte */
253     READ_TEXT         /* Just read text - ignore until EOL */
254 } parser_state_t;
255 static parser_state_t state = INIT;
256
257 static const char *state_str[] = {"Init",
258                            "Start-of-line",
259                            "Offset",
260                            "Byte",
261                            "Text"
262 };
263
264 static const char *token_str[] = {"",
265                            "Byte",
266                            "Offset",
267                            "Directive",
268                            "Text",
269                            "End-of-line"
270 };
271
272 /* ----- Skeleton Packet Headers --------------------------------------------------*/
273
274 typedef struct {
275     guint8  dest_addr[6];
276     guint8  src_addr[6];
277     guint16 l3pid;
278 } hdr_ethernet_t;
279
280 static hdr_ethernet_t HDR_ETHERNET = {
281     {0x0a, 0x02, 0x02, 0x02, 0x02, 0x02},
282     {0x0a, 0x01, 0x01, 0x01, 0x01, 0x01},
283     0};
284
285 typedef struct {
286     guint8  ver_hdrlen;
287     guint8  dscp;
288     guint16 packet_length;
289     guint16 identification;
290     guint8  flags;
291     guint8  fragment;
292     guint8  ttl;
293     guint8  protocol;
294     guint16 hdr_checksum;
295     guint32 src_addr;
296     guint32 dest_addr;
297 } hdr_ip_t;
298
299 static hdr_ip_t HDR_IP = {0x45, 0, 0, 0x3412, 0, 0, 0xff, 0, 0,
300 #ifdef WORDS_BIGENDIAN
301 0x0a010101, 0x0a020202
302 #else
303 0x0101010a, 0x0202020a
304 #endif
305 };
306
307 /* Fixed IP address values */
308 #ifdef WORDS_BIGENDIAN
309 #define IP_SRC 0x0a010101
310 #define IP_DST 0x0a020202
311 #else
312 #define IP_SRC 0x0101010a
313 #define IP_DST 0x0202020a
314 #endif
315
316 static struct {         /* pseudo header for checksum calculation */
317     guint32 src_addr;
318     guint32 dest_addr;
319     guint8  zero;
320     guint8  protocol;
321     guint16 length;
322 } pseudoh;
323
324
325 /* headers taken from glibc */
326
327 typedef struct {
328     union  {
329         struct ip6_hdrctl {
330             guint32 ip6_un1_flow;   /* 24 bits of flow-ID */
331             guint16 ip6_un1_plen;   /* payload length */
332             guint8  ip6_un1_nxt;    /* next header */
333             guint8  ip6_un1_hlim;   /* hop limit */
334         } ip6_un1;
335         guint8 ip6_un2_vfc;       /* 4 bits version, 4 bits priority */
336     } ip6_ctlun;
337     struct e_in6_addr ip6_src;      /* source address */
338     struct e_in6_addr ip6_dst;      /* destination address */
339 } hdr_ipv6_t;
340
341 static hdr_ipv6_t HDR_IPv6;
342
343 static struct {                 /* pseudo header ipv6 for checksum calculation */
344     struct  e_in6_addr src_addr6;
345     struct  e_in6_addr dst_addr6;
346     guint32 protocol;
347     guint32 zero;
348 } pseudoh6;
349
350
351 typedef struct {
352     guint16 source_port;
353     guint16 dest_port;
354     guint16 length;
355     guint16 checksum;
356 } hdr_udp_t;
357
358 static hdr_udp_t HDR_UDP = {0, 0, 0, 0};
359
360 typedef struct {
361     guint16 source_port;
362     guint16 dest_port;
363     guint32 seq_num;
364     guint32 ack_num;
365     guint8  hdr_length;
366     guint8  flags;
367     guint16 window;
368     guint16 checksum;
369     guint16 urg;
370 } hdr_tcp_t;
371
372 static hdr_tcp_t HDR_TCP = {0, 0, 0, 0, 0x50, 0, 0, 0, 0};
373
374 typedef struct {
375     guint16 src_port;
376     guint16 dest_port;
377     guint32 tag;
378     guint32 checksum;
379 } hdr_sctp_t;
380
381 static hdr_sctp_t HDR_SCTP = {0, 0, 0, 0};
382
383 typedef struct {
384     guint8  type;
385     guint8  bits;
386     guint16 length;
387     guint32 tsn;
388     guint16 sid;
389     guint16 ssn;
390     guint32 ppid;
391 } hdr_data_chunk_t;
392
393 static hdr_data_chunk_t HDR_DATA_CHUNK = {0, 0, 0, 0, 0, 0, 0};
394
395 static char tempbuf[64];
396
397 /*----------------------------------------------------------------------
398  * Stuff for writing a PCap file
399  */
400 #define PCAP_SNAPLEN        0xffff
401
402 /* Link-layer type; see http://www.tcpdump.org/linktypes.html for details */
403 static guint32 pcap_link_type = 1;   /* Default is LINKTYPE_ETHERNET */
404
405 /*----------------------------------------------------------------------
406  * Parse a single hex number
407  * Will abort the program if it can't parse the number
408  * Pass in TRUE if this is an offset, FALSE if not
409  */
410 static guint32
411 parse_num (const char *str, int offset)
412 {
413     guint32  num;
414     char    *c;
415
416     if (str == NULL) {
417         fprintf(stderr, "FATAL ERROR: str is NULL\n");
418         exit(1);
419     }
420
421     num = (guint32)strtoul(str, &c, offset ? offset_base : 16);
422     if (c == str) {
423         fprintf(stderr, "FATAL ERROR: Bad hex number? [%s]\n", str);
424         exit(1);
425     }
426     return num;
427 }
428
429 /*----------------------------------------------------------------------
430  * Write this byte into current packet
431  */
432 static void
433 write_byte (const char *str)
434 {
435     guint32 num;
436
437     num = parse_num(str, FALSE);
438     packet_buf[curr_offset] = (guint8) num;
439     curr_offset++;
440     if (curr_offset - header_length >= max_offset) /* packet full */
441         start_new_packet(TRUE);
442 }
443
444 /*----------------------------------------------------------------------
445  * Write a number of bytes into current packet
446  */
447
448 static void
449 write_bytes (const char bytes[], guint32 nbytes)
450 {
451     guint32 i;
452
453     if (curr_offset + nbytes < MAX_PACKET) {
454         for (i = 0; i < nbytes; i++) {
455             packet_buf[curr_offset] = bytes[i];
456             curr_offset++;
457         }
458     }
459 }
460
461 /*----------------------------------------------------------------------
462  * Remove bytes from the current packet
463  */
464 static void
465 unwrite_bytes (guint32 nbytes)
466 {
467     curr_offset -= nbytes;
468 }
469
470 /*----------------------------------------------------------------------
471  * Compute one's complement checksum (from RFC1071)
472  */
473 static guint16
474 in_checksum (void *buf, guint32 count)
475 {
476     guint32 sum = 0;
477     guint16 *addr = (guint16 *)buf;
478
479     while (count > 1) {
480         /*  This is the inner loop */
481         sum += g_ntohs(* (guint16 *) addr);
482         addr++;
483         count -= 2;
484     }
485
486     /*  Add left-over byte, if any */
487     if (count > 0)
488         sum += g_ntohs(* (guint8 *) addr);
489
490     /*  Fold 32-bit sum to 16 bits */
491     while (sum>>16)
492         sum = (sum & 0xffff) + (sum >> 16);
493
494     sum = ~sum;
495     return g_htons(sum);
496 }
497
498 /* The CRC32C code is taken from draft-ietf-tsvwg-sctpcsum-01.txt.
499  * That code is copyrighted by D. Otis and has been modified.
500  */
501
502 #define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF])
503 static guint32 crc_c[256] =
504 {
505 0x00000000U, 0xF26B8303U, 0xE13B70F7U, 0x1350F3F4U,
506 0xC79A971FU, 0x35F1141CU, 0x26A1E7E8U, 0xD4CA64EBU,
507 0x8AD958CFU, 0x78B2DBCCU, 0x6BE22838U, 0x9989AB3BU,
508 0x4D43CFD0U, 0xBF284CD3U, 0xAC78BF27U, 0x5E133C24U,
509 0x105EC76FU, 0xE235446CU, 0xF165B798U, 0x030E349BU,
510 0xD7C45070U, 0x25AFD373U, 0x36FF2087U, 0xC494A384U,
511 0x9A879FA0U, 0x68EC1CA3U, 0x7BBCEF57U, 0x89D76C54U,
512 0x5D1D08BFU, 0xAF768BBCU, 0xBC267848U, 0x4E4DFB4BU,
513 0x20BD8EDEU, 0xD2D60DDDU, 0xC186FE29U, 0x33ED7D2AU,
514 0xE72719C1U, 0x154C9AC2U, 0x061C6936U, 0xF477EA35U,
515 0xAA64D611U, 0x580F5512U, 0x4B5FA6E6U, 0xB93425E5U,
516 0x6DFE410EU, 0x9F95C20DU, 0x8CC531F9U, 0x7EAEB2FAU,
517 0x30E349B1U, 0xC288CAB2U, 0xD1D83946U, 0x23B3BA45U,
518 0xF779DEAEU, 0x05125DADU, 0x1642AE59U, 0xE4292D5AU,
519 0xBA3A117EU, 0x4851927DU, 0x5B016189U, 0xA96AE28AU,
520 0x7DA08661U, 0x8FCB0562U, 0x9C9BF696U, 0x6EF07595U,
521 0x417B1DBCU, 0xB3109EBFU, 0xA0406D4BU, 0x522BEE48U,
522 0x86E18AA3U, 0x748A09A0U, 0x67DAFA54U, 0x95B17957U,
523 0xCBA24573U, 0x39C9C670U, 0x2A993584U, 0xD8F2B687U,
524 0x0C38D26CU, 0xFE53516FU, 0xED03A29BU, 0x1F682198U,
525 0x5125DAD3U, 0xA34E59D0U, 0xB01EAA24U, 0x42752927U,
526 0x96BF4DCCU, 0x64D4CECFU, 0x77843D3BU, 0x85EFBE38U,
527 0xDBFC821CU, 0x2997011FU, 0x3AC7F2EBU, 0xC8AC71E8U,
528 0x1C661503U, 0xEE0D9600U, 0xFD5D65F4U, 0x0F36E6F7U,
529 0x61C69362U, 0x93AD1061U, 0x80FDE395U, 0x72966096U,
530 0xA65C047DU, 0x5437877EU, 0x4767748AU, 0xB50CF789U,
531 0xEB1FCBADU, 0x197448AEU, 0x0A24BB5AU, 0xF84F3859U,
532 0x2C855CB2U, 0xDEEEDFB1U, 0xCDBE2C45U, 0x3FD5AF46U,
533 0x7198540DU, 0x83F3D70EU, 0x90A324FAU, 0x62C8A7F9U,
534 0xB602C312U, 0x44694011U, 0x5739B3E5U, 0xA55230E6U,
535 0xFB410CC2U, 0x092A8FC1U, 0x1A7A7C35U, 0xE811FF36U,
536 0x3CDB9BDDU, 0xCEB018DEU, 0xDDE0EB2AU, 0x2F8B6829U,
537 0x82F63B78U, 0x709DB87BU, 0x63CD4B8FU, 0x91A6C88CU,
538 0x456CAC67U, 0xB7072F64U, 0xA457DC90U, 0x563C5F93U,
539 0x082F63B7U, 0xFA44E0B4U, 0xE9141340U, 0x1B7F9043U,
540 0xCFB5F4A8U, 0x3DDE77ABU, 0x2E8E845FU, 0xDCE5075CU,
541 0x92A8FC17U, 0x60C37F14U, 0x73938CE0U, 0x81F80FE3U,
542 0x55326B08U, 0xA759E80BU, 0xB4091BFFU, 0x466298FCU,
543 0x1871A4D8U, 0xEA1A27DBU, 0xF94AD42FU, 0x0B21572CU,
544 0xDFEB33C7U, 0x2D80B0C4U, 0x3ED04330U, 0xCCBBC033U,
545 0xA24BB5A6U, 0x502036A5U, 0x4370C551U, 0xB11B4652U,
546 0x65D122B9U, 0x97BAA1BAU, 0x84EA524EU, 0x7681D14DU,
547 0x2892ED69U, 0xDAF96E6AU, 0xC9A99D9EU, 0x3BC21E9DU,
548 0xEF087A76U, 0x1D63F975U, 0x0E330A81U, 0xFC588982U,
549 0xB21572C9U, 0x407EF1CAU, 0x532E023EU, 0xA145813DU,
550 0x758FE5D6U, 0x87E466D5U, 0x94B49521U, 0x66DF1622U,
551 0x38CC2A06U, 0xCAA7A905U, 0xD9F75AF1U, 0x2B9CD9F2U,
552 0xFF56BD19U, 0x0D3D3E1AU, 0x1E6DCDEEU, 0xEC064EEDU,
553 0xC38D26C4U, 0x31E6A5C7U, 0x22B65633U, 0xD0DDD530U,
554 0x0417B1DBU, 0xF67C32D8U, 0xE52CC12CU, 0x1747422FU,
555 0x49547E0BU, 0xBB3FFD08U, 0xA86F0EFCU, 0x5A048DFFU,
556 0x8ECEE914U, 0x7CA56A17U, 0x6FF599E3U, 0x9D9E1AE0U,
557 0xD3D3E1ABU, 0x21B862A8U, 0x32E8915CU, 0xC083125FU,
558 0x144976B4U, 0xE622F5B7U, 0xF5720643U, 0x07198540U,
559 0x590AB964U, 0xAB613A67U, 0xB831C993U, 0x4A5A4A90U,
560 0x9E902E7BU, 0x6CFBAD78U, 0x7FAB5E8CU, 0x8DC0DD8FU,
561 0xE330A81AU, 0x115B2B19U, 0x020BD8EDU, 0xF0605BEEU,
562 0x24AA3F05U, 0xD6C1BC06U, 0xC5914FF2U, 0x37FACCF1U,
563 0x69E9F0D5U, 0x9B8273D6U, 0x88D28022U, 0x7AB90321U,
564 0xAE7367CAU, 0x5C18E4C9U, 0x4F48173DU, 0xBD23943EU,
565 0xF36E6F75U, 0x0105EC76U, 0x12551F82U, 0xE03E9C81U,
566 0x34F4F86AU, 0xC69F7B69U, 0xD5CF889DU, 0x27A40B9EU,
567 0x79B737BAU, 0x8BDCB4B9U, 0x988C474DU, 0x6AE7C44EU,
568 0xBE2DA0A5U, 0x4C4623A6U, 0x5F16D052U, 0xAD7D5351U,
569 };
570
571 static guint32
572 crc32c (const guint8* buf, unsigned int len, guint32 crc32_init)
573 {
574     unsigned int i;
575     guint32 crc;
576
577     crc = crc32_init;
578     for (i = 0; i < len; i++)
579         CRC32C(crc, buf[i]);
580
581     return crc;
582 }
583
584 static guint32
585 finalize_crc32c (guint32 crc)
586 {
587     guint32 result;
588     guint8 byte0,byte1,byte2,byte3;
589
590     result = ~crc;
591     byte0 = result & 0xff;
592     byte1 = (result>>8) & 0xff;
593     byte2 = (result>>16) & 0xff;
594     byte3 = (result>>24) & 0xff;
595     result = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3);
596     return result;
597 }
598
599 static guint16
600 number_of_padding_bytes (guint32 length)
601 {
602     guint16 remainder;
603
604     remainder = length % 4;
605
606     if (remainder == 0)
607         return 0;
608     else
609         return 4 - remainder;
610 }
611
612 /*----------------------------------------------------------------------
613  * Write current packet out
614  */
615 static void
616 write_current_packet (gboolean cont)
617 {
618     guint32  length         = 0;
619     guint16  padding_length = 0;
620     int      err;
621     guint16  ihatemacros;
622     gboolean success;
623
624     if (curr_offset > header_length) {
625         /* Write the packet */
626
627         /* Is direction indication on with an inbound packet? */
628         gboolean isInbound = has_direction && (direction == 2);
629
630         /* if defined IPv6 we should rewrite hdr_ethernet_proto anyways */
631         if (hdr_ipv6) {
632             hdr_ethernet_proto = 0x86DD;
633             hdr_ip = FALSE;
634         }
635
636         /* Compute packet length */
637         length = curr_offset;
638         if (hdr_sctp) {
639             padding_length = number_of_padding_bytes(length - header_length );
640         } else {
641             padding_length = 0;
642         }
643         /* Reset curr_offset, since we now write the headers */
644         curr_offset = 0;
645
646         /* Write Ethernet header */
647         if (hdr_ethernet) {
648             HDR_ETHERNET.l3pid = g_htons(hdr_ethernet_proto);
649             write_bytes((const char *)&HDR_ETHERNET, sizeof(HDR_ETHERNET));
650         }
651
652         /* Write IP header */
653         if (hdr_ip) {
654             if (isInbound) {
655                 HDR_IP.src_addr = hdr_ip_dest_addr ? hdr_ip_dest_addr : IP_DST;
656                 HDR_IP.dest_addr = hdr_ip_src_addr? hdr_ip_src_addr : IP_SRC;
657             }
658             else {
659                 HDR_IP.src_addr = hdr_ip_src_addr? hdr_ip_src_addr : IP_SRC;
660                 HDR_IP.dest_addr = hdr_ip_dest_addr ? hdr_ip_dest_addr : IP_DST;
661             }
662
663             HDR_IP.packet_length = g_htons(length - ip_offset + padding_length);
664             HDR_IP.protocol = (guint8) hdr_ip_proto;
665             HDR_IP.hdr_checksum = 0;
666             HDR_IP.hdr_checksum = in_checksum(&HDR_IP, sizeof(HDR_IP));
667             write_bytes((const char *)&HDR_IP, sizeof(HDR_IP));
668         } else if (hdr_ipv6) {
669             if (memcmp(isInbound ? &hdr_ipv6_dest_addr : &hdr_ipv6_src_addr, &NO_IPv6_ADDRESS, sizeof(struct e_in6_addr)))
670                 memcpy(&HDR_IPv6.ip6_src, isInbound ? &hdr_ipv6_dest_addr : &hdr_ipv6_src_addr, sizeof(struct e_in6_addr));
671             if (memcmp(isInbound ? &hdr_ipv6_src_addr : &hdr_ipv6_dest_addr, &NO_IPv6_ADDRESS, sizeof(struct e_in6_addr)))
672                 memcpy(&HDR_IPv6.ip6_dst, isInbound ? &hdr_ipv6_src_addr : &hdr_ipv6_dest_addr, sizeof(struct e_in6_addr));
673
674             HDR_IPv6.ip6_ctlun.ip6_un2_vfc &= 0x0F;
675             HDR_IPv6.ip6_ctlun.ip6_un2_vfc |= (6<< 4);
676             HDR_IPv6.ip6_ctlun.ip6_un1.ip6_un1_plen = g_htons(length - ip_offset + padding_length);
677             HDR_IPv6.ip6_ctlun.ip6_un1.ip6_un1_nxt  = (guint8) hdr_ip_proto;
678             HDR_IPv6.ip6_ctlun.ip6_un1.ip6_un1_hlim = 32;
679             write_bytes((const char *)&HDR_IPv6, sizeof(HDR_IPv6));
680
681             /* initialize pseudo ipv6 header for checksum calculation */
682             pseudoh6.src_addr6  = HDR_IPv6.ip6_src;
683             pseudoh6.dst_addr6  = HDR_IPv6.ip6_dst;
684             pseudoh6.zero       = 0;
685             pseudoh6.protocol   = (guint8) hdr_ip_proto;
686             ihatemacros         = g_ntohs(HDR_IPv6.ip6_ctlun.ip6_un1.ip6_un1_plen);
687             pseudoh.length      = g_htons(length - ihatemacros + sizeof(HDR_UDP));
688         }
689
690         if (!hdr_ipv6) {
691             /* initialize pseudo header for checksum calculation */
692             pseudoh.src_addr    = HDR_IP.src_addr;
693             pseudoh.dest_addr   = HDR_IP.dest_addr;
694             pseudoh.zero        = 0;
695             pseudoh.protocol    = (guint8) hdr_ip_proto;
696             pseudoh.length      = g_htons(length - header_length + sizeof(HDR_UDP));
697         }
698
699         /* Write UDP header */
700         if (hdr_udp) {
701             guint16 x16;
702             guint32 u;
703
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      = 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));
711             u    = g_ntohs(x16);
712             x16  = in_checksum(&HDR_UDP, sizeof(HDR_UDP));
713             u   += g_ntohs(x16);
714             x16  = in_checksum(packet_buf + header_length, length - header_length);
715             u   += g_ntohs(x16);
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));
721         }
722
723         /* Write TCP header */
724         if (hdr_tcp) {
725             guint16 x16;
726             guint32 u;
727
728              /* initialize pseudo header for checksum calculation */
729             pseudoh.src_addr    = HDR_IP.src_addr;
730             pseudoh.dest_addr   = HDR_IP.dest_addr;
731             pseudoh.zero        = 0;
732             pseudoh.protocol    = (guint8) hdr_ip_proto;
733             pseudoh.length      = g_htons(length - header_length + sizeof(HDR_TCP));
734             /* initialize the TCP header */
735             HDR_TCP.source_port = isInbound ? g_htons(hdr_dest_port): g_htons(hdr_src_port);
736             HDR_TCP.dest_port = isInbound ? g_htons(hdr_src_port) : g_htons(hdr_dest_port);
737             /* set ack number if we have direction */
738             if (has_direction) {
739                 HDR_TCP.flags = 0x10;
740                 HDR_TCP.ack_num = g_ntohl(isInbound ? tcp_out_seq_num : tcp_in_seq_num);
741                 HDR_TCP.ack_num = g_htonl(HDR_TCP.ack_num);
742             }
743             else {
744                 HDR_TCP.flags = 0;
745                 HDR_TCP.ack_num = 0;
746             }
747             HDR_TCP.seq_num = isInbound ? tcp_in_seq_num : tcp_out_seq_num;
748             HDR_TCP.window = g_htons(0x2000);
749             HDR_TCP.checksum = 0;
750             /* Note: g_ntohs()/g_htons() macro arg may be eval'd twice so calc value before invoking macro */
751             x16  = in_checksum(&pseudoh, sizeof(pseudoh));
752             u    = g_ntohs(x16);
753             x16  = in_checksum(&HDR_TCP, sizeof(HDR_TCP));
754             u   += g_ntohs(x16);
755             x16  = in_checksum(packet_buf + header_length, length - header_length);
756             u   += g_ntohs(x16);
757             x16  = (u & 0xffff) + (u>>16);
758             HDR_TCP.checksum = g_htons(x16);
759             if (HDR_TCP.checksum == 0) /* differentiate between 'none' and 0 */
760                 HDR_TCP.checksum = g_htons(1);
761             write_bytes((const char *)&HDR_TCP, sizeof(HDR_TCP));
762             if (isInbound) {
763                 tcp_in_seq_num = g_ntohl(tcp_in_seq_num) + length - header_length;
764                 tcp_in_seq_num = g_htonl(tcp_in_seq_num);
765             }
766             else {
767                 tcp_out_seq_num = g_ntohl(tcp_out_seq_num) + length - header_length;
768                 tcp_out_seq_num = g_htonl(tcp_out_seq_num);
769             }
770         }
771
772         /* Compute DATA chunk header */
773         if (hdr_data_chunk) {
774             hdr_data_chunk_bits = 0;
775             if (packet_start == 0) {
776                 hdr_data_chunk_bits |= 0x02;
777             }
778             if (!cont) {
779                 hdr_data_chunk_bits |= 0x01;
780             }
781             HDR_DATA_CHUNK.type   = hdr_data_chunk_type;
782             HDR_DATA_CHUNK.bits   = hdr_data_chunk_bits;
783             HDR_DATA_CHUNK.length = g_htons(length - header_length + sizeof(HDR_DATA_CHUNK));
784             HDR_DATA_CHUNK.tsn    = g_htonl(hdr_data_chunk_tsn);
785             HDR_DATA_CHUNK.sid    = g_htons(hdr_data_chunk_sid);
786             HDR_DATA_CHUNK.ssn    = g_htons(hdr_data_chunk_ssn);
787             HDR_DATA_CHUNK.ppid   = g_htonl(hdr_data_chunk_ppid);
788             hdr_data_chunk_tsn++;
789             if (!cont) {
790                 hdr_data_chunk_ssn++;
791             }
792         }
793
794         /* Write SCTP common header */
795         if (hdr_sctp) {
796             guint32 zero = 0;
797
798             HDR_SCTP.src_port  = isInbound ? g_htons(hdr_sctp_dest): g_htons(hdr_sctp_src);
799             HDR_SCTP.dest_port = isInbound ? g_htons(hdr_sctp_src) : g_htons(hdr_sctp_dest);
800             HDR_SCTP.tag       = g_htonl(hdr_sctp_tag);
801             HDR_SCTP.checksum  = g_htonl(0);
802             HDR_SCTP.checksum  = crc32c((guint8 *)&HDR_SCTP, sizeof(HDR_SCTP), ~0);
803             if (hdr_data_chunk) {
804                 HDR_SCTP.checksum  = crc32c((guint8 *)&HDR_DATA_CHUNK, sizeof(HDR_DATA_CHUNK), HDR_SCTP.checksum);
805                 HDR_SCTP.checksum  = crc32c((guint8 *)packet_buf + header_length, length - header_length, HDR_SCTP.checksum);
806                 HDR_SCTP.checksum  = crc32c((guint8 *)&zero, padding_length, HDR_SCTP.checksum);
807             } else {
808                 HDR_SCTP.checksum  = crc32c((guint8 *)packet_buf + header_length, length - header_length, HDR_SCTP.checksum);
809             }
810             HDR_SCTP.checksum = finalize_crc32c(HDR_SCTP.checksum);
811             HDR_SCTP.checksum  = g_htonl(HDR_SCTP.checksum);
812             write_bytes((const char *)&HDR_SCTP, sizeof(HDR_SCTP));
813         }
814
815         /* Write DATA chunk header */
816         if (hdr_data_chunk) {
817             write_bytes((const char *)&HDR_DATA_CHUNK, sizeof(HDR_DATA_CHUNK));
818         }
819
820         /* Reset curr_offset, since we now write the trailers */
821         curr_offset = length;
822
823         /* Write DATA chunk padding */
824         if (hdr_data_chunk && (padding_length > 0)) {
825             memset(tempbuf, 0, padding_length);
826             write_bytes((const char *)&tempbuf, padding_length);
827             length += padding_length;
828         }
829
830         /* Write Ethernet trailer */
831         if (hdr_ethernet && (length < 60)) {
832             memset(tempbuf, 0, 60 - length);
833             write_bytes((const char *)&tempbuf, 60 - length);
834             length = 60;
835         }
836         if (use_pcapng) {
837             success = pcapng_write_enhanced_packet_block(output_file,
838                                                          NULL,
839                                                          ts_sec, ts_nsec,
840                                                          length, length,
841                                                          0,
842                                                          1000000000,
843                                                          packet_buf, direction,
844                                                          &bytes_written, &err);
845         } else {
846             success = libpcap_write_packet(output_file,
847                                            ts_sec, ts_nsec/1000,
848                                            length, length,
849                                            packet_buf,
850                                            &bytes_written, &err);
851         }
852         if (!success) {
853             fprintf(stderr, "File write error [%s] : %s\n",
854                     output_filename, g_strerror(err));
855             exit(1);
856         }
857         if (ts_fmt == NULL) {
858             /* fake packet counter */
859             if (use_pcapng)
860                 ts_nsec++;
861             else
862                 ts_nsec += 1000;
863         }
864         if (!quiet) {
865             fprintf(stderr, "Wrote packet of %u bytes.\n", length);
866         }
867         num_packets_written++;
868     }
869
870     packet_start += curr_offset - header_length;
871     curr_offset = header_length;
872     return;
873 }
874
875 /*----------------------------------------------------------------------
876  * Write file header and trailer
877  */
878 static void
879 write_file_header (void)
880 {
881     int      err;
882     gboolean success;
883
884     if (use_pcapng) {
885         char *appname;
886         char *comment;
887
888         appname = g_strdup_printf("text2pcap (Wireshark) %s", get_ws_vcs_version_info());
889         comment = g_strdup_printf("Generated from input file %s.", input_filename);
890         success = pcapng_write_session_header_block(output_file,
891                                                     comment,
892                                                     NULL,    /* HW */
893                                                     NULL,    /* OS */
894                                                     appname,
895                                                     -1,      /* section_length */
896                                                     &bytes_written,
897                                                     &err);
898         g_free(appname);
899         g_free(comment);
900         if (success) {
901             success = pcapng_write_interface_description_block(output_file,
902                                                                NULL,
903                                                                NULL,
904                                                                NULL,
905                                                                "",
906                                                                NULL,
907                                                                pcap_link_type,
908                                                                PCAP_SNAPLEN,
909                                                                &bytes_written,
910                                                                0,
911                                                                9,
912                                                                &err);
913         }
914     } else {
915         success = libpcap_write_file_header(output_file, pcap_link_type,
916                                             PCAP_SNAPLEN, FALSE,
917                                             &bytes_written, &err);
918     }
919     if (!success) {
920         fprintf(stderr, "File write error [%s] : %s\n",
921                 output_filename, g_strerror(err));
922         exit(1);
923     }
924 }
925
926 /*----------------------------------------------------------------------
927  * Append a token to the packet preamble.
928  */
929 static void
930 append_to_preamble (char *str)
931 {
932     size_t toklen;
933
934     if (packet_preamble_len != 0) {
935         if (packet_preamble_len == PACKET_PREAMBLE_MAX_LEN)
936             return; /* no room to add more preamble */
937         /* Add a blank separator between the previous token and this token. */
938         packet_preamble[packet_preamble_len++] = ' ';
939     }
940     toklen = strlen(str);
941     if (toklen != 0) {
942         if (packet_preamble_len + toklen > PACKET_PREAMBLE_MAX_LEN)
943             return; /* no room to add the token to the preamble */
944         g_strlcpy(&packet_preamble[packet_preamble_len], str, PACKET_PREAMBLE_MAX_LEN);
945         packet_preamble_len += (int) toklen;
946         if (debug >= 2) {
947             char *c;
948             char xs[PACKET_PREAMBLE_MAX_LEN];
949             g_strlcpy(xs, packet_preamble, PACKET_PREAMBLE_MAX_LEN);
950             while ((c = strchr(xs, '\r')) != NULL) *c=' ';
951             fprintf (stderr, "[[append_to_preamble: \"%s\"]]", xs);
952         }
953     }
954 }
955
956 /*----------------------------------------------------------------------
957  * Parse the preamble to get the timecode.
958  */
959
960 static void
961 parse_preamble (void)
962 {
963     struct tm  timecode;
964     char      *subsecs;
965     char      *p;
966     int        subseclen;
967     int        i;
968
969      /*
970      * Null-terminate the preamble.
971      */
972     packet_preamble[packet_preamble_len] = '\0';
973     if (debug > 0)
974         fprintf(stderr, "[[parse_preamble: \"%s\"]]\n", packet_preamble);
975
976     if (has_direction) {
977         switch (packet_preamble[0]) {
978         case 'i':
979         case 'I':
980             direction = 0x00000001;
981             packet_preamble[0] = ' ';
982             break;
983         case 'o':
984         case 'O':
985             direction = 0x00000002;
986             packet_preamble[0] = ' ';
987             break;
988         default:
989             direction = 0x00000000;
990             break;
991         }
992         i = 0;
993         while (packet_preamble[i] == ' ' ||
994                packet_preamble[i] == '\r' ||
995                packet_preamble[i] == '\t') {
996             i++;
997         }
998         packet_preamble_len -= i;
999         /* Also move the trailing '\0'. */
1000         memmove(packet_preamble, packet_preamble + i, packet_preamble_len + 1);
1001     }
1002
1003
1004     /*
1005      * If no "-t" flag was specified, don't attempt to parse the packet
1006      * preamble to extract a time stamp.
1007      */
1008     if (ts_fmt == NULL) {
1009         /* Clear Preamble */
1010         packet_preamble_len = 0;
1011         return;
1012     }
1013
1014     /*
1015      * Initialize to today localtime, just in case not all fields
1016      * of the date and time are specified.
1017      */
1018
1019     timecode = timecode_default;
1020     ts_nsec = 0;
1021
1022     /* Ensure preamble has more than two chars before attempting to parse.
1023      * This should cover line breaks etc that get counted.
1024      */
1025     if (strlen(packet_preamble) > 2) {
1026         /* Get Time leaving subseconds */
1027         subsecs = strptime( packet_preamble, ts_fmt, &timecode );
1028         if (subsecs != NULL) {
1029             /* Get the long time from the tm structure */
1030             /*  (will return -1 if failure)            */
1031             ts_sec  = mktime( &timecode );
1032         } else
1033             ts_sec = -1;    /* we failed to parse it */
1034
1035         /* This will ensure incorrectly parsed dates get set to zero */
1036         if (-1 == ts_sec) {
1037             /* Sanitize - remove all '\r' */
1038             char *c;
1039             while ((c = strchr(packet_preamble, '\r')) != NULL) *c=' ';
1040             fprintf (stderr, "Failure processing time \"%s\" using time format \"%s\"\n   (defaulting to Jan 1,1970 00:00:00 GMT)\n",
1041                  packet_preamble, ts_fmt);
1042             if (debug >= 2) {
1043                 fprintf(stderr, "timecode: %02d/%02d/%d %02d:%02d:%02d %d\n",
1044                     timecode.tm_mday, timecode.tm_mon, timecode.tm_year,
1045                     timecode.tm_hour, timecode.tm_min, timecode.tm_sec, timecode.tm_isdst);
1046             }
1047             ts_sec  = 0;  /* Jan 1,1970: 00:00 GMT; tshark/wireshark will display date/time as adjusted by timezone */
1048             ts_nsec = 0;
1049         } else {
1050             /* Parse subseconds */
1051             ts_nsec = (guint32)strtol(subsecs, &p, 10);
1052             if (subsecs == p) {
1053                 /* Error */
1054                 ts_nsec = 0;
1055             } else {
1056                 /*
1057                  * Convert that number to a number
1058                  * of microseconds; if it's N digits
1059                  * long, it's in units of 10^(-N) seconds,
1060                  * so, to convert it to units of
1061                  * 10^-9 seconds, we multiply by
1062                  * 10^(9-N).
1063                  */
1064                 subseclen = (int) (p - subsecs);
1065                 if (subseclen > 9) {
1066                     /*
1067                      * *More* than 9 digits; 9-N is
1068                      * negative, so we divide by
1069                      * 10^(N-9).
1070                      */
1071                     for (i = subseclen - 9; i != 0; i--)
1072                         ts_nsec /= 10;
1073                 } else if (subseclen < 9) {
1074                     for (i = 9 - subseclen; i != 0; i--)
1075                         ts_nsec *= 10;
1076                 }
1077             }
1078         }
1079     }
1080     if (debug >= 2) {
1081         char *c;
1082         while ((c = strchr(packet_preamble, '\r')) != NULL) *c=' ';
1083         fprintf(stderr, "[[parse_preamble: \"%s\"]]\n", packet_preamble);
1084         fprintf(stderr, "Format(%s), time(%u), subsecs(%u)\n", ts_fmt, (guint32)ts_sec, ts_nsec);
1085     }
1086
1087
1088     /* Clear Preamble */
1089     packet_preamble_len = 0;
1090 }
1091
1092 /*----------------------------------------------------------------------
1093  * Start a new packet
1094  */
1095 static void
1096 start_new_packet (gboolean cont)
1097 {
1098     if (debug >= 1)
1099         fprintf(stderr, "Start new packet (cont = %s).\n", cont ? "TRUE" : "FALSE");
1100
1101     /* Write out the current packet, if required */
1102     write_current_packet(cont);
1103     num_packets_read++;
1104
1105     /* Ensure we parse the packet preamble as it may contain the time */
1106     parse_preamble();
1107 }
1108
1109 /*----------------------------------------------------------------------
1110  * Process a directive
1111  */
1112 static void
1113 process_directive (char *str)
1114 {
1115     fprintf(stderr, "\n--- Directive [%s] currently unsupported ---\n", str + 10);
1116 }
1117
1118 /*----------------------------------------------------------------------
1119  * Parse a single token (called from the scanner)
1120  */
1121 void
1122 parse_token (token_t token, char *str)
1123 {
1124     guint32  num;
1125     int      by_eol;
1126     int      rollback = 0;
1127     int      line_size;
1128     int      i;
1129     char    *s2;
1130     char     tmp_str[3];
1131
1132     /*
1133      * This is implemented as a simple state machine of five states.
1134      * State transitions are caused by tokens being received from the
1135      * scanner. The code should be self-documenting.
1136      */
1137
1138     if (debug >= 2) {
1139         /* Sanitize - remove all '\r' */
1140         char *c;
1141         if (str!=NULL) { while ((c = strchr(str, '\r')) != NULL) *c=' '; }
1142
1143         fprintf(stderr, "(%s, %s \"%s\") -> (",
1144                 state_str[state], token_str[token], str ? str : "");
1145     }
1146
1147     switch (state) {
1148
1149     /* ----- Waiting for new packet -------------------------------------------*/
1150     case INIT:
1151         if (!str && token != T_EOL) goto fail_null_str;
1152         switch (token) {
1153         case T_TEXT:
1154             append_to_preamble(str);
1155             break;
1156         case T_DIRECTIVE:
1157             process_directive(str);
1158             break;
1159         case T_OFFSET:
1160             num = parse_num(str, TRUE);
1161             if (num == 0) {
1162                 /* New packet starts here */
1163                 start_new_packet(FALSE);
1164                 state = READ_OFFSET;
1165                 pkt_lnstart = packet_buf + num;
1166             }
1167             break;
1168         case T_EOL:
1169             /* Some describing text may be parsed as offset, but the invalid
1170                offset will be checked in the state of START_OF_LINE, so
1171                we add this transition to gain flexibility */
1172             state = START_OF_LINE;
1173             break;
1174         default:
1175             break;
1176         }
1177         break;
1178
1179     /* ----- Processing packet, start of new line -----------------------------*/
1180     case START_OF_LINE:
1181         if (!str && token != T_EOL) goto fail_null_str;
1182         switch (token) {
1183         case T_TEXT:
1184             append_to_preamble(str);
1185             break;
1186         case T_DIRECTIVE:
1187             process_directive(str);
1188             break;
1189         case T_OFFSET:
1190             num = parse_num(str, TRUE);
1191             if (num == 0) {
1192                 /* New packet starts here */
1193                 start_new_packet(FALSE);
1194                 packet_start = 0;
1195                 state = READ_OFFSET;
1196             } else if ((num - packet_start) != curr_offset - header_length) {
1197                 /*
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.
1205                  */
1206                 if (num < curr_offset) {
1207                     unwrite_bytes(curr_offset - num);
1208                     state = READ_OFFSET;
1209                 } else {
1210                     /* Bad offset; switch to INIT state */
1211                     if (debug >= 1)
1212                         fprintf(stderr, "Inconsistent offset. Expecting %0X, got %0X. Ignoring rest of packet\n",
1213                                 curr_offset, num);
1214                     write_current_packet(FALSE);
1215                     state = INIT;
1216                 }
1217             } else {
1218                 state = READ_OFFSET;
1219             }
1220             pkt_lnstart = packet_buf + num;
1221             break;
1222         case T_EOL:
1223             state = START_OF_LINE;
1224             break;
1225         default:
1226             break;
1227         }
1228         break;
1229
1230     /* ----- Processing packet, read offset -----------------------------------*/
1231     case READ_OFFSET:
1232         switch (token) {
1233         case T_BYTE:
1234             /* Record the byte */
1235             state = READ_BYTE;
1236             if (!str) goto fail_null_str;
1237             write_byte(str);
1238             break;
1239         case T_TEXT:
1240         case T_DIRECTIVE:
1241         case T_OFFSET:
1242             state = READ_TEXT;
1243             break;
1244         case T_EOL:
1245             state = START_OF_LINE;
1246             break;
1247         default:
1248             break;
1249         }
1250         break;
1251
1252     /* ----- Processing packet, read byte -------------------------------------*/
1253     case READ_BYTE:
1254         switch (token) {
1255         case T_BYTE:
1256             /* Record the byte */
1257             write_byte(str);
1258             break;
1259         case T_TEXT:
1260         case T_DIRECTIVE:
1261         case T_OFFSET:
1262         case T_EOL:
1263             by_eol = 0;
1264             state = READ_TEXT;
1265             if (token == T_EOL) {
1266                 by_eol = 1;
1267                 state = START_OF_LINE;
1268             }
1269             if (identify_ascii) {
1270                 /* Here a line of pkt bytes reading is finished
1271                    compare the ascii and hex to avoid such situation:
1272                    "61 62 20 ab ", when ab is ascii dump then it should
1273                    not be treat as byte */
1274                 rollback = 0;
1275                 /* s2 is the ASCII string, s1 is the HEX string, e.g, when
1276                    s2 = "ab ", s1 = "616220"
1277                    we should find out the largest tail of s1 matches the head
1278                    of s2, it means the matched part in tail is the ASCII dump
1279                    of the head byte. These matched should be rollback */
1280                 line_size = curr_offset-(int)(pkt_lnstart-packet_buf);
1281                 s2 = (char*)g_malloc((line_size+1)/4+1);
1282                 /* gather the possible pattern */
1283                 for (i = 0; i < (line_size+1)/4; i++) {
1284                     tmp_str[0] = pkt_lnstart[i*3];
1285                     tmp_str[1] = pkt_lnstart[i*3+1];
1286                     tmp_str[2] = '\0';
1287                     /* it is a valid convertable string */
1288                     if (!g_ascii_isxdigit(tmp_str[0]) || !g_ascii_isxdigit(tmp_str[1])) {
1289                         break;
1290                     }
1291                     s2[i] = (char)strtoul(tmp_str, (char **)NULL, 16);
1292                     rollback++;
1293                     /* the 3rd entry is not a delimiter, so the possible byte pattern will not shown */
1294                     if (!(pkt_lnstart[i*3+2] == ' ')) {
1295                         if (by_eol != 1)
1296                             rollback--;
1297                         break;
1298                     }
1299                 }
1300                 /* If packet line start contains possible byte pattern, the line end
1301                    should contain the matched pattern if the user open the -a flag.
1302                    The packet will be possible invalid if the byte pattern cannot find
1303                    a matched one in the line of packet buffer.*/
1304                 if (rollback > 0) {
1305                     if (strncmp(pkt_lnstart+line_size-rollback, s2, rollback) == 0) {
1306                         unwrite_bytes(rollback);
1307                     }
1308                     /* Not matched. This line contains invalid packet bytes, so
1309                        discard the whole line */
1310                     else {
1311                         unwrite_bytes(line_size);
1312                     }
1313                 }
1314                 g_free(s2);
1315             }
1316             break;
1317         default:
1318             break;
1319         }
1320         break;
1321
1322     /* ----- Processing packet, read text -------------------------------------*/
1323     case READ_TEXT:
1324         switch (token) {
1325         case T_EOL:
1326             state = START_OF_LINE;
1327             break;
1328         default:
1329             break;
1330         }
1331         break;
1332
1333     default:
1334         fprintf(stderr, "FATAL ERROR: Bad state (%d)", state);
1335         exit(1);
1336     }
1337
1338     if (debug >= 2)
1339         fprintf(stderr, ", %s)\n", state_str[state]);
1340
1341     return;
1342
1343 fail_null_str:
1344     fprintf(stderr, "FATAL ERROR: got NULL str pointer in state (%d)", state);
1345     exit(1);
1346
1347 }
1348
1349 /*----------------------------------------------------------------------
1350  * Print usage string and exit
1351  */
1352 static void
1353 print_usage (FILE *output)
1354 {
1355     fprintf(output,
1356             "\n"
1357             "Usage: text2pcap [options] <infile> <outfile>\n"
1358             "\n"
1359             "where  <infile> specifies input  filename (use - for standard input)\n"
1360             "      <outfile> specifies output filename (use - for standard output)\n"
1361             "\n"
1362             "Input:\n"
1363             "  -o hex|oct|dec         parse offsets as (h)ex, (o)ctal or (d)ecimal;\n"
1364             "                         default is hex.\n"
1365             "  -t <timefmt>           treat the text before the packet as a date/time code;\n"
1366             "                         the specified argument is a format string of the sort\n"
1367             "                         supported by strptime.\n"
1368             "                         Example: The time \"10:15:14.5476\" has the format code\n"
1369             "                         \"%%H:%%M:%%S.\"\n"
1370             "                         NOTE: The subsecond component delimiter, '.', must be\n"
1371             "                         given, but no pattern is required; the remaining\n"
1372             "                         number is assumed to be fractions of a second.\n"
1373             "                         NOTE: Date/time fields from the current date/time are\n"
1374             "                         used as the default for unspecified fields.\n"
1375             "  -D                     the text before the packet starts with an I or an O,\n"
1376             "                         indicating that the packet is inbound or outbound.\n"
1377             "                         This is only stored if the output format is PCAP-NG.\n"
1378             "  -a                     enable ASCII text dump identification.\n"
1379             "                         The start of the ASCII text dump can be identified\n"
1380             "                         and excluded from the packet data, even if it looks\n"
1381             "                         like a HEX dump.\n"
1382             "                         NOTE: Do not enable it if the input file does not\n"
1383             "                         contain the ASCII text dump.\n"
1384             "\n"
1385             "Output:\n"
1386             "  -l <typenum>           link-layer type number; default is 1 (Ethernet).  See\n"
1387             "                         http://www.tcpdump.org/linktypes.html for a list of\n"
1388             "                         numbers.  Use this option if your dump is a complete\n"
1389             "                         hex dump of an encapsulated packet and you wish to\n"
1390             "                         specify the exact type of encapsulation.\n"
1391             "                         Example: -l 7 for ARCNet packets.\n"
1392             "  -m <max-packet>        max packet length in output; default is %d\n"
1393             "\n"
1394             "Prepend dummy header:\n"
1395             "  -e <l3pid>             prepend dummy Ethernet II header with specified L3PID\n"
1396             "                         (in HEX).\n"
1397             "                         Example: -e 0x806 to specify an ARP packet.\n"
1398             "  -i <proto>             prepend dummy IP header with specified IP protocol\n"
1399             "                         (in DECIMAL).\n"
1400             "                         Automatically prepends Ethernet header as well.\n"
1401             "                         Example: -i 46\n"
1402             "  -4 <srcip>,<destip>    prepend dummy IPv4 header with specified\n"
1403             "                         dest and source address.\n"
1404             "                         Example: -4 10.0.0.1,10.0.0.2\n"
1405             "  -6 <srcip>,<destip>    replace IPv6 header with specified\n"
1406             "                         dest and source address.\n"
1407             "                         Example: -6 fe80:0:0:0:202:b3ff:fe1e:8329,2001:0db8:85a3:0000:0000:8a2e:0370:7334\n"
1408             "  -u <srcp>,<destp>      prepend dummy UDP header with specified\n"
1409             "                         source and destination ports (in DECIMAL).\n"
1410             "                         Automatically prepends Ethernet & IP headers as well.\n"
1411             "                         Example: -u 1000,69 to make the packets look like\n"
1412             "                         TFTP/UDP packets.\n"
1413             "  -T <srcp>,<destp>      prepend dummy TCP header with specified\n"
1414             "                         source and destination ports (in DECIMAL).\n"
1415             "                         Automatically prepends Ethernet & IP headers as well.\n"
1416             "                         Example: -T 50,60\n"
1417             "  -s <srcp>,<dstp>,<tag> prepend dummy SCTP header with specified\n"
1418             "                         source/dest ports and verification tag (in DECIMAL).\n"
1419             "                         Automatically prepends Ethernet & IP headers as well.\n"
1420             "                         Example: -s 30,40,34\n"
1421             "  -S <srcp>,<dstp>,<ppi> prepend dummy SCTP header with specified\n"
1422             "                         source/dest ports and verification tag 0.\n"
1423             "                         Automatically prepends a dummy SCTP DATA\n"
1424             "                         chunk header with payload protocol identifier ppi.\n"
1425             "                         Example: -S 30,40,34\n"
1426             "\n"
1427             "Miscellaneous:\n"
1428             "  -h                     display this help and exit.\n"
1429             "  -d                     show detailed debug of parser states.\n"
1430             "  -q                     generate no output at all (automatically disables -d).\n"
1431             "  -n                     use PCAP-NG instead of PCAP as output format.\n"
1432             "",
1433             MAX_PACKET);
1434 }
1435
1436 /*----------------------------------------------------------------------
1437  * Parse CLI options
1438  */
1439 static void
1440 parse_options (int argc, char *argv[])
1441 {
1442     GString *comp_info_str;
1443     GString *runtime_info_str;
1444     int   c;
1445     char *p;
1446     static const struct option long_options[] = {
1447         {"help", no_argument, NULL, 'h'},
1448         {"version", no_argument, NULL, 'v'},
1449         {0, 0, 0, 0 }
1450     };
1451
1452 #ifdef _WIN32
1453     arg_list_utf_16to8(argc, argv);
1454     create_app_running_mutex();
1455 #endif /* _WIN32 */
1456
1457     /* Get the compile-time version information string */
1458     comp_info_str = get_compiled_version_info(NULL, NULL);
1459
1460     /* get the run-time version information string */
1461     runtime_info_str = get_runtime_version_info(NULL);
1462
1463     /* Add it to the information to be reported on a crash. */
1464     ws_add_crash_info("Text2pcap (Wireshark) %s\n"
1465          "\n"
1466          "%s"
1467          "\n"
1468          "%s",
1469       get_ws_vcs_version_info(), comp_info_str->str, runtime_info_str->str);
1470
1471     /* Scan CLI parameters */
1472     while ((c = getopt_long(argc, argv, "aDdhqe:i:l:m:no:u:s:S:t:T:v4:6:", long_options, NULL)) != -1) {
1473         switch (c) {
1474         case 'h':
1475             printf("Text2pcap (Wireshark) %s\n"
1476                    "Generate a capture file from an ASCII hexdump of packets.\n"
1477                    "See https://www.wireshark.org for more information.\n",
1478                    get_ws_vcs_version_info());
1479             print_usage(stdout);
1480             exit(0);
1481             break;
1482         case 'd': if (!quiet) debug++; break;
1483         case 'D': has_direction = TRUE; break;
1484         case 'q': quiet = TRUE; debug = FALSE; break;
1485         case 'l': pcap_link_type = (guint32)strtol(optarg, NULL, 0); break;
1486         case 'm': max_offset = (guint32)strtol(optarg, NULL, 0); break;
1487         case 'n': use_pcapng = TRUE; break;
1488         case 'o':
1489             if (optarg[0] != 'h' && optarg[0] != 'o' && optarg[0] != 'd') {
1490                 fprintf(stderr, "Bad argument for '-o': %s\n", optarg);
1491                 print_usage(stderr);
1492                 exit(1);
1493             }
1494             switch (optarg[0]) {
1495             case 'o': offset_base =  8; break;
1496             case 'h': offset_base = 16; break;
1497             case 'd': offset_base = 10; break;
1498             }
1499             break;
1500         case 'e':
1501             hdr_ethernet = TRUE;
1502             if (sscanf(optarg, "%x", &hdr_ethernet_proto) < 1) {
1503                 fprintf(stderr, "Bad argument for '-e': %s\n", optarg);
1504                 print_usage(stderr);
1505                 exit(1);
1506             }
1507             break;
1508
1509         case 'i':
1510             hdr_ip = TRUE;
1511             hdr_ip_proto = strtol(optarg, &p, 10);
1512             if (p == optarg || *p != '\0' || hdr_ip_proto < 0 ||
1513                   hdr_ip_proto > 255) {
1514                 fprintf(stderr, "Bad argument for '-i': %s\n", optarg);
1515                 print_usage(stderr);
1516                 exit(1);
1517             }
1518             hdr_ethernet = TRUE;
1519             hdr_ethernet_proto = 0x800;
1520             break;
1521
1522         case 's':
1523             hdr_sctp = TRUE;
1524             hdr_data_chunk = FALSE;
1525             hdr_tcp = FALSE;
1526             hdr_udp = FALSE;
1527             hdr_sctp_src   = (guint32)strtol(optarg, &p, 10);
1528             if (p == optarg || (*p != ',' && *p != '\0')) {
1529                 fprintf(stderr, "Bad src port for '-%c'\n", c);
1530                 print_usage(stderr);
1531                 exit(1);
1532             }
1533             if (*p == '\0') {
1534                 fprintf(stderr, "No dest port specified for '-%c'\n", c);
1535                 print_usage(stderr);
1536                 exit(1);
1537             }
1538             p++;
1539             optarg = p;
1540             hdr_sctp_dest = (guint32)strtol(optarg, &p, 10);
1541             if (p == optarg || (*p != ',' && *p != '\0')) {
1542                 fprintf(stderr, "Bad dest port for '-s'\n");
1543                 print_usage(stderr);
1544                 exit(1);
1545             }
1546             if (*p == '\0') {
1547                 fprintf(stderr, "No tag specified for '-%c'\n", c);
1548                 print_usage(stderr);
1549                 exit(1);
1550             }
1551             p++;
1552             optarg = p;
1553             hdr_sctp_tag = (guint32)strtol(optarg, &p, 10);
1554             if (p == optarg || *p != '\0') {
1555                 fprintf(stderr, "Bad tag for '-%c'\n", c);
1556                 print_usage(stderr);
1557                 exit(1);
1558             }
1559
1560             hdr_ip = TRUE;
1561             hdr_ip_proto = 132;
1562             hdr_ethernet = TRUE;
1563             hdr_ethernet_proto = 0x800;
1564             break;
1565         case 'S':
1566             hdr_sctp = TRUE;
1567             hdr_data_chunk = TRUE;
1568             hdr_tcp = FALSE;
1569             hdr_udp = FALSE;
1570             hdr_sctp_src   = (guint32)strtol(optarg, &p, 10);
1571             if (p == optarg || (*p != ',' && *p != '\0')) {
1572                 fprintf(stderr, "Bad src port for '-%c'\n", c);
1573                 print_usage(stderr);
1574                 exit(1);
1575             }
1576             if (*p == '\0') {
1577                 fprintf(stderr, "No dest port specified for '-%c'\n", c);
1578                 print_usage(stderr);
1579                 exit(1);
1580             }
1581             p++;
1582             optarg = p;
1583             hdr_sctp_dest = (guint32)strtol(optarg, &p, 10);
1584             if (p == optarg || (*p != ',' && *p != '\0')) {
1585                 fprintf(stderr, "Bad dest port for '-s'\n");
1586                 print_usage(stderr);
1587                 exit(1);
1588             }
1589             if (*p == '\0') {
1590                 fprintf(stderr, "No ppi specified for '-%c'\n", c);
1591                 print_usage(stderr);
1592                 exit(1);
1593             }
1594             p++;
1595             optarg = p;
1596             hdr_data_chunk_ppid = (guint32)strtoul(optarg, &p, 10);
1597             if (p == optarg || *p != '\0') {
1598                 fprintf(stderr, "Bad ppi for '-%c'\n", c);
1599                 print_usage(stderr);
1600                 exit(1);
1601             }
1602
1603             hdr_ip = TRUE;
1604             hdr_ip_proto = 132;
1605             hdr_ethernet = TRUE;
1606             hdr_ethernet_proto = 0x800;
1607             break;
1608
1609         case 't':
1610             ts_fmt = optarg;
1611             break;
1612
1613         case 'u':
1614             hdr_udp = TRUE;
1615             hdr_tcp = FALSE;
1616             hdr_sctp = FALSE;
1617             hdr_data_chunk = FALSE;
1618             hdr_src_port = (guint32)strtol(optarg, &p, 10);
1619             if (p == optarg || (*p != ',' && *p != '\0')) {
1620                 fprintf(stderr, "Bad src port for '-u'\n");
1621                 print_usage(stderr);
1622                 exit(1);
1623             }
1624             if (*p == '\0') {
1625                 fprintf(stderr, "No dest port specified for '-u'\n");
1626                 print_usage(stderr);
1627                 exit(1);
1628             }
1629             p++;
1630             optarg = p;
1631             hdr_dest_port = (guint32)strtol(optarg, &p, 10);
1632             if (p == optarg || *p != '\0') {
1633                 fprintf(stderr, "Bad dest port for '-u'\n");
1634                 print_usage(stderr);
1635                 exit(1);
1636             }
1637             hdr_ip = TRUE;
1638             hdr_ip_proto = 17;
1639             hdr_ethernet = TRUE;
1640             hdr_ethernet_proto = 0x800;
1641             break;
1642
1643         case 'T':
1644             hdr_tcp = TRUE;
1645             hdr_udp = FALSE;
1646             hdr_sctp = FALSE;
1647             hdr_data_chunk = FALSE;
1648             hdr_src_port = (guint32)strtol(optarg, &p, 10);
1649             if (p == optarg || (*p != ',' && *p != '\0')) {
1650                 fprintf(stderr, "Bad src port for '-T'\n");
1651                 print_usage(stderr);
1652                 exit(1);
1653             }
1654             if (*p == '\0') {
1655                 fprintf(stderr, "No dest port specified for '-u'\n");
1656                 print_usage(stderr);
1657                 exit(1);
1658             }
1659             p++;
1660             optarg = p;
1661             hdr_dest_port = (guint32)strtol(optarg, &p, 10);
1662             if (p == optarg || *p != '\0') {
1663                 fprintf(stderr, "Bad dest port for '-T'\n");
1664                 print_usage(stderr);
1665                 exit(1);
1666             }
1667             hdr_ip = TRUE;
1668             hdr_ip_proto = 6;
1669             hdr_ethernet = TRUE;
1670             hdr_ethernet_proto = 0x800;
1671             break;
1672
1673         case 'a':
1674             identify_ascii = TRUE;
1675             break;
1676
1677         case 'v':
1678             show_version("Text2pcap (Wireshark)", comp_info_str, runtime_info_str);
1679             g_string_free(comp_info_str, TRUE);
1680             g_string_free(runtime_info_str, TRUE);
1681             exit(0);
1682             break;
1683
1684         case '4':
1685         case '6':
1686             p = strchr(optarg, ',');
1687
1688             if (!p) {
1689                 fprintf(stderr, "Bad source param addr for '-%c'\n", c);
1690                 print_usage(stderr);
1691                 exit(1);
1692             }
1693
1694             *p = '\0';
1695             if (c == '6')
1696             {
1697                 hdr_ipv6 = TRUE;
1698                 hdr_ethernet_proto = 0x86DD;
1699             }
1700             else
1701             {
1702                 hdr_ip = TRUE;
1703                 hdr_ethernet_proto = 0x800;
1704             }
1705             hdr_ethernet = TRUE;
1706
1707             if (hdr_ipv6 == TRUE) {
1708                 if (!ws_inet_pton6(optarg, &hdr_ipv6_src_addr)) {
1709                         fprintf(stderr, "Bad src addr -%c '%s'\n", c, p);
1710                         print_usage(stderr);
1711                         exit(1);
1712                 }
1713             } else {
1714                 if (!ws_inet_pton4(optarg, &hdr_ip_src_addr)) {
1715                         fprintf(stderr, "Bad src addr -%c '%s'\n", c, p);
1716                         print_usage(stderr);
1717                         exit(1);
1718                 }
1719             }
1720
1721             p++;
1722             if (*p == '\0') {
1723                 fprintf(stderr, "No dest addr specified for '-%c'\n", c);
1724                 print_usage(stderr);
1725                 exit(1);
1726             }
1727
1728             if (hdr_ipv6 == TRUE) {
1729                 if (!ws_inet_pton6(p, &hdr_ipv6_dest_addr)) {
1730                         fprintf(stderr, "Bad dest addr for -%c '%s'\n", c, p);
1731                         print_usage(stderr);
1732                         exit(1);
1733                 }
1734             } else {
1735                 if (!ws_inet_pton4(p, &hdr_ip_dest_addr)) {
1736                         fprintf(stderr, "Bad dest addr for -%c '%s'\n", c, p);
1737                         print_usage(stderr);
1738                         exit(1);
1739                 }
1740             }
1741             break;
1742
1743
1744         case '?':
1745         default:
1746             print_usage(stderr);
1747             exit(1);
1748         }
1749     }
1750
1751     if (optind >= argc || argc-optind < 2) {
1752         fprintf(stderr, "Must specify input and output filename\n");
1753         print_usage(stderr);
1754         exit(1);
1755     }
1756
1757     if (strcmp(argv[optind], "-")) {
1758         input_filename = g_strdup(argv[optind]);
1759         input_file = ws_fopen(input_filename, "rb");
1760         if (!input_file) {
1761             fprintf(stderr, "Cannot open file [%s] for reading: %s\n",
1762                     input_filename, g_strerror(errno));
1763             exit(1);
1764         }
1765     } else {
1766         input_filename = "Standard input";
1767         input_file = stdin;
1768     }
1769
1770     if (strcmp(argv[optind+1], "-")) {
1771         output_filename = g_strdup(argv[optind+1]);
1772         output_file = ws_fopen(output_filename, "wb");
1773         if (!output_file) {
1774             fprintf(stderr, "Cannot open file [%s] for writing: %s\n",
1775                     output_filename, g_strerror(errno));
1776             exit(1);
1777         }
1778     } else {
1779         output_filename = "Standard output";
1780         output_file = stdout;
1781     }
1782
1783     /* Some validation */
1784     if (pcap_link_type != 1 && hdr_ethernet) {
1785         fprintf(stderr, "Dummy headers (-e, -i, -u, -s, -S -T) cannot be specified with link type override (-l)\n");
1786         exit(1);
1787     }
1788
1789     /* Set up our variables */
1790     if (!input_file) {
1791         input_file = stdin;
1792         input_filename = "Standard input";
1793     }
1794     if (!output_file) {
1795         output_file = stdout;
1796         output_filename = "Standard output";
1797     }
1798
1799     ts_sec = time(0);               /* initialize to current time */
1800     timecode_default = *localtime(&ts_sec);
1801     timecode_default.tm_isdst = -1; /* Unknown for now, depends on time given to the strptime() function */
1802
1803     /* Display summary of our state */
1804     if (!quiet) {
1805         fprintf(stderr, "Input from: %s\n", input_filename);
1806         fprintf(stderr, "Output to: %s\n",  output_filename);
1807         fprintf(stderr, "Output format: %s\n", use_pcapng ? "PCAP-NG" : "PCAP");
1808
1809         if (hdr_ethernet) fprintf(stderr, "Generate dummy Ethernet header: Protocol: 0x%0X\n",
1810                                   hdr_ethernet_proto);
1811         if (hdr_ip) fprintf(stderr, "Generate dummy IP header: Protocol: %ld\n",
1812                             hdr_ip_proto);
1813         if (hdr_udp) fprintf(stderr, "Generate dummy UDP header: Source port: %u. Dest port: %u\n",
1814                              hdr_src_port, hdr_dest_port);
1815         if (hdr_tcp) fprintf(stderr, "Generate dummy TCP header: Source port: %u. Dest port: %u\n",
1816                              hdr_src_port, hdr_dest_port);
1817         if (hdr_sctp) fprintf(stderr, "Generate dummy SCTP header: Source port: %u. Dest port: %u. Tag: %u\n",
1818                               hdr_sctp_src, hdr_sctp_dest, hdr_sctp_tag);
1819         if (hdr_data_chunk) fprintf(stderr, "Generate dummy DATA chunk header: TSN: %u. SID: %u. SSN: %u. PPID: %u\n",
1820                                     hdr_data_chunk_tsn, hdr_data_chunk_sid, hdr_data_chunk_ssn, hdr_data_chunk_ppid);
1821     }
1822 }
1823
1824 int
1825 main(int argc, char *argv[])
1826 {
1827     parse_options(argc, argv);
1828
1829     assert(input_file  != NULL);
1830     assert(output_file != NULL);
1831
1832     write_file_header();
1833
1834     header_length = 0;
1835     if (hdr_ethernet) {
1836         header_length += (int)sizeof(HDR_ETHERNET);
1837     }
1838     if (hdr_ip) {
1839         ip_offset = header_length;
1840         header_length += (int)sizeof(HDR_IP);
1841     } else if (hdr_ipv6) {
1842         ip_offset = header_length;
1843         header_length += (int)sizeof(HDR_IPv6);
1844     }
1845     if (hdr_sctp) {
1846         header_length += (int)sizeof(HDR_SCTP);
1847     }
1848     if (hdr_data_chunk) {
1849         header_length += (int)sizeof(HDR_DATA_CHUNK);
1850     }
1851     if (hdr_tcp) {
1852         header_length += (int)sizeof(HDR_TCP);
1853     }
1854     if (hdr_udp) {
1855         header_length += (int)sizeof(HDR_UDP);
1856     }
1857     curr_offset = header_length;
1858
1859     yyin = input_file;
1860     yylex();
1861
1862     write_current_packet(FALSE);
1863     fclose(input_file);
1864     fclose(output_file);
1865     if (debug)
1866         fprintf(stderr, "\n-------------------------\n");
1867     if (!quiet) {
1868         fprintf(stderr, "Read %u potential packet%s, wrote %u packet%s (%" G_GINT64_MODIFIER "u byte%s).\n",
1869                 num_packets_read, (num_packets_read == 1) ? "" : "s",
1870                 num_packets_written, (num_packets_written == 1) ? "" : "s",
1871                 bytes_written, (bytes_written == 1) ? "" : "s");
1872     }
1873     return 0;
1874 }
1875
1876 /*
1877  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
1878  *
1879  * Local variables:
1880  * c-basic-offset: 4
1881  * tab-width: 8
1882  * indent-tabs-mode: nil
1883  * End:
1884  *
1885  * vi: set shiftwidth=4 tabstop=8 expandtab:
1886  * :indentSize=4:tabSize=8:noTabs=true:
1887  */
1888