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