1aab81a84e38579f6499cc61b73c73197b93b7b6
[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  * $Id$
10  *
11  * Wireshark - Network traffic analyzer
12  * By Gerald Combs <gerald@wireshark.org>
13  * Copyright 1998 Gerald Combs
14  *
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28  *
29  *******************************************************************************/
30
31 /*******************************************************************************
32  *
33  * This utility reads in an ASCII hexdump of this common format:
34  *
35  * 00000000  00 E0 1E A7 05 6F 00 10 5A A0 B9 12 08 00 46 00 .....o..Z.....F.
36  * 00000010  03 68 00 00 00 00 0A 2E EE 33 0F 19 08 7F 0F 19 .h.......3...\7f..
37  * 00000020  03 80 94 04 00 00 10 01 16 A2 0A 00 03 50 00 0C .............P..
38  * 00000030  01 01 0F 19 03 80 11 01 1E 61 00 0C 03 01 0F 19 .........a......
39  *
40  * Each bytestring line consists of an offset, one or more bytes, and
41  * text at the end. An offset is defined as a hex string of more than
42  * two characters. A byte is defined as a hex string of exactly two
43  * characters. The text at the end is ignored, as is any text before
44  * the offset. Bytes read from a bytestring line are added to the
45  * current packet only if all the following conditions are satisfied:
46  *
47  * - No text appears between the offset and the bytes (any bytes appearing after
48  *   such text would be ignored)
49  *
50  * - The offset must be arithmetically correct, i.e. if the offset is 00000020, then
51  *   exactly 32 bytes must have been read into this packet before this. If the offset
52  *   is wrong, the packet is immediately terminated
53  *
54  * A packet start is signaled by a zero offset.
55  *
56  * Lines starting with #TEXT2PCAP are directives. These allow the user
57  * to embed instructions into the capture file which allows text2pcap
58  * to take some actions (e.g. specifying the encapsulation
59  * etc.). Currently no directives are implemented.
60  *
61  * Lines beginning with # which are not directives are ignored as
62  * comments. Currently all non-hexdump text is ignored by text2pcap;
63  * in the future, text processing may be added, but lines prefixed
64  * with '#' will still be ignored.
65  *
66  * The output is a libpcap packet containing Ethernet frames by
67  * default. This program takes options which allow the user to add
68  * dummy Ethernet, IP and UDP or TCP headers to the packets in order
69  * to allow dumps of L3 or higher protocols to be decoded.
70  *
71  * Considerable flexibility is built into this code to read hexdumps
72  * of slightly different formats. For example, any text prefixing the
73  * hexdump line is dropped (including mail forwarding '>'). The offset
74  * can be any hex number of four digits or greater.
75  *
76  * This converter cannot read a single packet greater than 64KiB-1. Packet
77  * snaplength is automatically set to 64KiB-1.
78  */
79
80 #include "config.h"
81
82 /*
83  * Just make sure we include the prototype for strptime as well
84  * (needed for glibc 2.2) but make sure we do this only if not
85  * yet defined.
86  */
87 #ifndef __USE_XOPEN
88 #  define __USE_XOPEN
89 #endif
90 #ifndef _XOPEN_SOURCE
91 #  ifndef __sun
92 #    define _XOPEN_SOURCE 600
93 #  endif
94 #endif
95
96 /*
97  * Defining _XOPEN_SOURCE is needed on some platforms, e.g. platforms
98  * using glibc, to expand the set of things system header files define.
99  *
100  * Unfortunately, on other platforms, such as some versions of Solaris
101  * (including Solaris 10), it *reduces* that set as well, causing
102  * strptime() not to be declared, presumably because the version of the
103  * X/Open spec that _XOPEN_SOURCE implies doesn't include strptime() and
104  * blah blah blah namespace pollution blah blah blah.
105  *
106  * So we define __EXTENSIONS__ so that "strptime()" is declared.
107  */
108 #ifndef __EXTENSIONS__
109 #  define __EXTENSIONS__
110 #endif
111
112 #include <ctype.h>
113 #include <stdio.h>
114 #include <stdlib.h>
115 #include <string.h>
116 #include <wsutil/file_util.h>
117
118 #include <time.h>
119 #include <glib.h>
120
121 #ifdef HAVE_UNISTD_H
122 # include <unistd.h>
123 #endif
124
125 #include <errno.h>
126 #include <assert.h>
127
128 #ifndef HAVE_GETOPT
129 #include "wsutil/wsgetopt.h"
130 #endif
131
132 #ifdef NEED_STRPTIME_H
133 # include "wsutil/strptime.h"
134 #endif
135
136 #include "pcapio.h"
137 #include "text2pcap.h"
138 #include "svnversion.h"
139
140 #ifdef _WIN32
141 #include <wsutil/unicode-utils.h>
142 #endif /* _WIN32 */
143
144 #ifdef HAVE_ARPA_INET_H
145 #include <arpa/inet.h>
146 #endif
147
148 #ifdef HAVE_WINSOCK2_H
149 #include <winsock2.h>       /* needed to define AF_ values on Windows */
150 #endif
151
152 #ifdef NEED_INET_ATON_H
153 # include "wsutil/inet_aton.h"
154 #endif
155
156 #ifdef HAVE_SYS_SOCKET_H
157 #include <sys/socket.h>
158 #endif
159
160 #ifdef NEED_INET_V6DEFS_H
161 # include "wsutil/inet_v6defs.h"
162 #endif
163
164 /*--- Options --------------------------------------------------------------------*/
165
166 /* File format */
167 static gboolean use_pcapng = FALSE;
168
169 /* Debug level */
170 static int debug = 0;
171 /* Be quiet */
172 static int quiet = FALSE;
173
174 /* Dummy Ethernet header */
175 static int hdr_ethernet = FALSE;
176 static guint32 hdr_ethernet_proto = 0;
177
178 /* Dummy IP header */
179 static int hdr_ip = FALSE;
180 static int hdr_ipv6 = FALSE;
181 static long hdr_ip_proto = 0;
182
183 /* Destination and source addresses for IP header */
184 static unsigned long hdr_ip_dest_addr = 0;
185 static unsigned long hdr_ip_src_addr = 0;
186 static guint8 hdr_ipv6_dest_addr[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
187 static guint8 hdr_ipv6_src_addr[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
188 static guint8 NO_IPv6_ADDRESS[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
189
190 /* Dummy UDP header */
191 static int hdr_udp = FALSE;
192 static guint32 hdr_dest_port = 0;
193 static guint32 hdr_src_port = 0;
194
195 /* Dummy TCP header */
196 static int hdr_tcp = FALSE;
197
198 /* Dummy SCTP header */
199 static int hdr_sctp = FALSE;
200 static guint32 hdr_sctp_src  = 0;
201 static guint32 hdr_sctp_dest = 0;
202 static guint32 hdr_sctp_tag  = 0;
203
204 /* Dummy DATA chunk header */
205 static int hdr_data_chunk = FALSE;
206 static guint8  hdr_data_chunk_type = 0;
207 static guint8  hdr_data_chunk_bits = 0;
208 static guint32 hdr_data_chunk_tsn  = 0;
209 static guint16 hdr_data_chunk_sid  = 0;
210 static guint16 hdr_data_chunk_ssn  = 0;
211 static guint32 hdr_data_chunk_ppid = 0;
212
213 /* ASCII text dump identification */
214 static int identify_ascii = FALSE;
215
216 static gboolean has_direction = FALSE;
217 static guint32 direction = 0;
218
219 /*--- Local date -----------------------------------------------------------------*/
220
221 /* This is where we store the packet currently being built */
222 #define MAX_PACKET 65535
223 static guint8 packet_buf[MAX_PACKET];
224 static guint32 header_length;
225 static guint32 ip_offset;
226 static guint32 curr_offset;
227 static guint32 max_offset = MAX_PACKET;
228 static guint32 packet_start = 0;
229 static void start_new_packet(gboolean);
230
231 /* This buffer contains strings present before the packet offset 0 */
232 #define PACKET_PREAMBLE_MAX_LEN     2048
233 static guint8 packet_preamble[PACKET_PREAMBLE_MAX_LEN+1];
234 static int packet_preamble_len = 0;
235
236 /* Number of packets read and written */
237 static guint32 num_packets_read = 0;
238 static guint32 num_packets_written = 0;
239 static guint64 bytes_written = 0;
240
241 /* Time code of packet, derived from packet_preamble */
242 static time_t ts_sec  = 0;
243 static guint32 ts_usec = 0;
244 static char *ts_fmt = NULL;
245 static struct tm timecode_default;
246
247 static guint8* pkt_lnstart;
248
249 /* Input file */
250 static const char *input_filename;
251 static FILE *input_file = NULL;
252 /* Output file */
253 static const char *output_filename;
254 static FILE *output_file = NULL;
255
256 /* Offset base to parse */
257 static guint32 offset_base = 16;
258
259 extern FILE *yyin;
260
261 /* ----- State machine -----------------------------------------------------------*/
262
263 /* Current state of parser */
264 typedef enum {
265     INIT,             /* Waiting for start of new packet */
266     START_OF_LINE,    /* Starting from beginning of line */
267     READ_OFFSET,      /* Just read the offset */
268     READ_BYTE,        /* Just read a byte */
269     READ_TEXT         /* Just read text - ignore until EOL */
270 } parser_state_t;
271 static parser_state_t state = INIT;
272
273 static const char *state_str[] = {"Init",
274                            "Start-of-line",
275                            "Offset",
276                            "Byte",
277                            "Text"
278 };
279
280 static const char *token_str[] = {"",
281                            "Byte",
282                            "Offset",
283                            "Directive",
284                            "Text",
285                            "End-of-line"
286 };
287
288 /* ----- Skeleton Packet Headers --------------------------------------------------*/
289
290 typedef struct {
291     guint8  dest_addr[6];
292     guint8  src_addr[6];
293     guint16 l3pid;
294 } hdr_ethernet_t;
295
296 static hdr_ethernet_t HDR_ETHERNET = {
297     {0x0a, 0x02, 0x02, 0x02, 0x02, 0x02},
298     {0x0a, 0x01, 0x01, 0x01, 0x01, 0x01},
299     0};
300
301 typedef struct {
302     guint8  ver_hdrlen;
303     guint8  dscp;
304     guint16 packet_length;
305     guint16 identification;
306     guint8  flags;
307     guint8  fragment;
308     guint8  ttl;
309     guint8  protocol;
310     guint16 hdr_checksum;
311     guint32 src_addr;
312     guint32 dest_addr;
313 } hdr_ip_t;
314
315 static hdr_ip_t HDR_IP = {0x45, 0, 0, 0x3412, 0, 0, 0xff, 0, 0,
316 #ifdef WORDS_BIGENDIAN
317 0x0a010101, 0x0a020202
318 #else
319 0x0101010a, 0x0202020a
320 #endif
321 };
322
323 static struct {         /* pseudo header for checksum calculation */
324     guint32 src_addr;
325     guint32 dest_addr;
326     guint8  zero;
327     guint8  protocol;
328     guint16 length;
329 } pseudoh;
330
331
332 /* headers taken from glibc */
333
334 /* IPv6 address */
335 struct hdr_in6_addr
336 {
337     union
338     {
339        guint8  __u6_addr8[16];
340        guint16 __u6_addr16[8];
341        guint32 __u6_addr32[4];
342     } __in6_u;
343 };
344
345 typedef struct {
346         union  {
347                 struct ip6_hdrctl {
348                         guint32 ip6_un1_flow;   /* 24 bits of flow-ID */
349                         guint16 ip6_un1_plen;   /* payload length */
350                         guint8  ip6_un1_nxt;    /* next header */
351                         guint8  ip6_un1_hlim;   /* hop limit */
352                 } ip6_un1;
353                 guint8 ip6_un2_vfc;       /* 4 bits version, 4 bits priority */
354         } ip6_ctlun;
355         struct hdr_in6_addr ip6_src;      /* source address */
356         struct hdr_in6_addr ip6_dst;      /* destination address */
357 } hdr_ipv6_t;
358
359 static hdr_ipv6_t HDR_IPv6;
360
361 static struct {                 /* pseudo header ipv6 for checksum calculation */
362         struct  hdr_in6_addr src_addr6;
363         struct  hdr_in6_addr dst_addr6;
364         guint32 protocol;
365         guint32 zero;
366 } pseudoh6;
367
368
369 typedef struct {
370     guint16 source_port;
371     guint16 dest_port;
372     guint16 length;
373     guint16 checksum;
374 } hdr_udp_t;
375
376 static hdr_udp_t HDR_UDP = {0, 0, 0, 0};
377
378 typedef struct {
379     guint16 source_port;
380     guint16 dest_port;
381     guint32 seq_num;
382     guint32 ack_num;
383     guint8  hdr_length;
384     guint8  flags;
385     guint16 window;
386     guint16 checksum;
387     guint16 urg;
388 } hdr_tcp_t;
389
390 static hdr_tcp_t HDR_TCP = {0, 0, 0, 0, 0x50, 0, 0, 0, 0};
391
392 typedef struct {
393     guint16 src_port;
394     guint16 dest_port;
395     guint32 tag;
396     guint32 checksum;
397 } hdr_sctp_t;
398
399 static hdr_sctp_t HDR_SCTP = {0, 0, 0, 0};
400
401 typedef struct {
402     guint8  type;
403     guint8  bits;
404     guint16 length;
405     guint32 tsn;
406     guint16 sid;
407     guint16 ssn;
408     guint32 ppid;
409 } hdr_data_chunk_t;
410
411 static hdr_data_chunk_t HDR_DATA_CHUNK = {0, 0, 0, 0, 0, 0, 0};
412
413 static char tempbuf[64];
414
415 /*----------------------------------------------------------------------
416  * Stuff for writing a PCap file
417  */
418 #define PCAP_MAGIC          0xa1b2c3d4
419 #define PCAP_SNAPLEN        0xffff
420
421 /* "libpcap" file header (minus magic number). */
422 struct pcap_hdr {
423     guint32 magic;          /* magic */
424     guint16 version_major;  /* major version number */
425     guint16 version_minor;  /* minor version number */
426     guint32 thiszone;       /* GMT to local correction */
427     guint32 sigfigs;        /* accuracy of timestamps */
428     guint32 snaplen;        /* max length of captured packets, in octets */
429     guint32 network;        /* data link type */
430 };
431
432 /* "libpcap" record header. */
433 struct pcaprec_hdr {
434     guint32 ts_sec;         /* timestamp seconds */
435     guint32 ts_usec;        /* timestamp microseconds */
436     guint32 incl_len;       /* number of octets of packet saved in file */
437     guint32 orig_len;       /* actual length of packet */
438 };
439
440 /* Link-layer type; see net/bpf.h for details */
441 static guint32 pcap_link_type = 1;   /* Default is DLT-EN10MB */
442
443 /*----------------------------------------------------------------------
444  * Parse a single hex number
445  * Will abort the program if it can't parse the number
446  * Pass in TRUE if this is an offset, FALSE if not
447  */
448 static guint32
449 parse_num (const char *str, int offset)
450 {
451     guint32 num;
452     char *c;
453
454     num = (guint32)strtoul(str, &c, offset ? offset_base : 16);
455     if (c==str) {
456         fprintf(stderr, "FATAL ERROR: Bad hex number? [%s]\n", str);
457         exit(-1);
458     }
459     return num;
460 }
461
462 /*----------------------------------------------------------------------
463  * Write this byte into current packet
464  */
465 static void
466 write_byte (const char *str)
467 {
468     guint32 num;
469
470     num = parse_num(str, FALSE);
471     packet_buf[curr_offset] = (guint8) num;
472     curr_offset ++;
473     if (curr_offset - header_length >= max_offset) /* packet full */
474         start_new_packet(TRUE);
475 }
476
477 /*----------------------------------------------------------------------
478  * Write a number of bytes into current packet
479  */
480
481 static void
482 write_bytes(const char bytes[], guint32 nbytes)
483 {
484     guint32 i;
485
486     if (curr_offset + nbytes < MAX_PACKET) {
487         for (i = 0; i < nbytes; i++) {
488             packet_buf[curr_offset] = bytes[i];
489             curr_offset++;
490         }
491     }
492 }
493
494 /*----------------------------------------------------------------------
495  * Remove bytes from the current packet
496  */
497 static void
498 unwrite_bytes (guint32 nbytes)
499 {
500     curr_offset -= nbytes;
501 }
502
503 /*----------------------------------------------------------------------
504  * Compute one's complement checksum (from RFC1071)
505  */
506 static guint16
507 in_checksum (void *buf, guint32 count)
508 {
509     guint32 sum = 0;
510     guint16 *addr = (guint16 *)buf;
511
512     while (count > 1) {
513         /*  This is the inner loop */
514         sum += g_ntohs(* (guint16 *) addr);
515         addr++;
516         count -= 2;
517     }
518
519     /*  Add left-over byte, if any */
520     if (count > 0)
521         sum += g_ntohs(* (guint8 *) addr);
522
523     /*  Fold 32-bit sum to 16 bits */
524     while (sum>>16)
525         sum = (sum & 0xffff) + (sum >> 16);
526
527     sum = ~sum;
528     return g_htons(sum);
529 }
530
531 /* The CRC32C code is taken from draft-ietf-tsvwg-sctpcsum-01.txt.
532  * That code is copyrighted by D. Otis and has been modified.
533  */
534
535 #define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF])
536 static guint32 crc_c[256] =
537 {
538 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
539 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
540 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
541 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
542 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
543 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
544 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
545 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
546 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
547 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
548 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
549 0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
550 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
551 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
552 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
553 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
554 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
555 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
556 0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
557 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
558 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
559 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
560 0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
561 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
562 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
563 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
564 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
565 0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
566 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
567 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
568 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
569 0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
570 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
571 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
572 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
573 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
574 0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
575 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
576 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
577 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
578 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
579 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
580 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
581 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
582 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
583 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
584 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
585 0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
586 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
587 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
588 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
589 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
590 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
591 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
592 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
593 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
594 0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
595 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
596 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
597 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
598 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
599 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
600 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
601 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L,
602 };
603
604 static guint32
605 crc32c(const guint8* buf, unsigned int len, guint32 crc32_init)
606 {
607     unsigned int i;
608     guint32 crc32;
609
610     crc32 = crc32_init;
611     for (i = 0; i < len; i++)
612         CRC32C(crc32, buf[i]);
613
614     return ( crc32 );
615 }
616
617 static guint32
618 finalize_crc32c(guint32 crc32)
619 {
620     guint32 result;
621     guint8 byte0,byte1,byte2,byte3;
622
623     result = ~crc32;
624     byte0 = result & 0xff;
625     byte1 = (result>>8) & 0xff;
626     byte2 = (result>>16) & 0xff;
627     byte3 = (result>>24) & 0xff;
628     result = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3);
629     return ( result );
630 }
631
632 static guint16
633 number_of_padding_bytes (guint32 length)
634 {
635     guint16 remainder;
636
637     remainder = length % 4;
638
639     if (remainder == 0)
640         return 0;
641     else
642         return 4 - remainder;
643 }
644
645 /*----------------------------------------------------------------------
646  * Write current packet out
647  */
648 static void
649 write_current_packet(gboolean cont)
650 {
651     guint32 length = 0;
652     guint16 padding_length = 0;
653     int err;
654     guint16 ihatemacros;
655     gboolean success;
656
657     if (curr_offset > header_length) {
658         /* Write the packet */
659
660         /* if defined IPv6 we should rewrite hdr_ethernet_proto anyways */
661         if(hdr_ipv6) {
662             hdr_ethernet_proto = 0x86DD;
663             hdr_ip = FALSE;
664         }
665
666         /* Compute packet length */
667         length = curr_offset;
668         if (hdr_sctp) {
669             padding_length = number_of_padding_bytes(length - header_length );
670         } else {
671             padding_length = 0;
672         }
673         /* Reset curr_offset, since we now write the headers */
674         curr_offset = 0;
675
676         /* Write Ethernet header */
677         if (hdr_ethernet) {
678             HDR_ETHERNET.l3pid = g_htons(hdr_ethernet_proto);
679             write_bytes((const char *)&HDR_ETHERNET, sizeof(HDR_ETHERNET));
680         }
681
682         /* Write IP header */
683         if (hdr_ip) {
684             if(hdr_ip_src_addr) HDR_IP.src_addr = hdr_ip_src_addr;
685             if(hdr_ip_dest_addr) HDR_IP.dest_addr = hdr_ip_dest_addr;
686
687             HDR_IP.packet_length = g_htons(length - ip_offset + padding_length);
688             HDR_IP.protocol = (guint8) hdr_ip_proto;
689             HDR_IP.hdr_checksum = 0;
690             HDR_IP.hdr_checksum = in_checksum(&HDR_IP, sizeof(HDR_IP));
691             write_bytes((const char *)&HDR_IP, sizeof(HDR_IP));
692         } else if (hdr_ipv6) {
693             if(memcmp(hdr_ipv6_src_addr, NO_IPv6_ADDRESS, sizeof(struct hdr_in6_addr)))
694                 memcpy(&HDR_IPv6.ip6_src, &hdr_ipv6_src_addr, sizeof(struct hdr_in6_addr));
695             if(memcmp(hdr_ipv6_dest_addr, NO_IPv6_ADDRESS, sizeof(struct hdr_in6_addr)))
696                 memcpy(&HDR_IPv6.ip6_dst, &hdr_ipv6_dest_addr, sizeof(struct hdr_in6_addr));
697
698             HDR_IPv6.ip6_ctlun.ip6_un2_vfc &= 0x0F;
699             HDR_IPv6.ip6_ctlun.ip6_un2_vfc |= (6<< 4);
700             HDR_IPv6.ip6_ctlun.ip6_un1.ip6_un1_plen = g_htons(length - ip_offset + padding_length);
701             HDR_IPv6.ip6_ctlun.ip6_un1.ip6_un1_nxt  = (guint8) hdr_ip_proto;
702             HDR_IPv6.ip6_ctlun.ip6_un1.ip6_un1_hlim = 32;
703             write_bytes((const char *)&HDR_IPv6, sizeof(HDR_IPv6));
704
705             /* initialize pseudo ipv6 header for checksum calculation */
706             pseudoh6.src_addr6  = HDR_IPv6.ip6_src;
707             pseudoh6.dst_addr6  = HDR_IPv6.ip6_dst;
708             pseudoh6.zero       = 0;
709             pseudoh6.protocol   = (guint8) hdr_ip_proto;
710             ihatemacros         = g_ntohs(HDR_IPv6.ip6_ctlun.ip6_un1.ip6_un1_plen);
711             pseudoh.length      = g_htons(length - ihatemacros + sizeof(HDR_UDP));
712         }
713
714         if(!hdr_ipv6) {
715             /* initialize pseudo header for checksum calculation */
716             pseudoh.src_addr    = HDR_IP.src_addr;
717             pseudoh.dest_addr   = HDR_IP.dest_addr;
718             pseudoh.zero        = 0;
719             pseudoh.protocol    = (guint8) hdr_ip_proto;
720             pseudoh.length      = g_htons(length - header_length + sizeof(HDR_UDP));
721         }
722
723         /* Write UDP header */
724         if (hdr_udp) {
725             guint16 x16;
726             guint32 u;
727
728             /* initialize the UDP header */
729             HDR_UDP.source_port = g_htons(hdr_src_port);
730             HDR_UDP.dest_port = g_htons(hdr_dest_port);
731             HDR_UDP.length      = pseudoh.length;
732             HDR_UDP.checksum = 0;
733             /* Note: g_ntohs()/g_htons() macro arg may be eval'd twice so calc value before invoking macro */
734             x16  = hdr_ipv6 ? in_checksum(&pseudoh6, sizeof(pseudoh6)) : in_checksum(&pseudoh, sizeof(pseudoh));
735             u    = g_ntohs(x16);
736             x16  = in_checksum(&HDR_UDP, sizeof(HDR_UDP));
737             u   += g_ntohs(x16);
738             x16  = in_checksum(packet_buf + header_length, length - header_length);
739             u   += g_ntohs(x16);
740             x16  = (u & 0xffff) + (u>>16);
741             HDR_UDP.checksum = g_htons(x16);
742             if (HDR_UDP.checksum == 0) /* differentiate between 'none' and 0 */
743                 HDR_UDP.checksum = g_htons(1);
744             write_bytes((const char *)&HDR_UDP, sizeof(HDR_UDP));
745         }
746
747         /* Write TCP header */
748         if (hdr_tcp) {
749             guint16 x16;
750             guint32 u;
751
752              /* initialize pseudo header for checksum calculation */
753             pseudoh.src_addr    = HDR_IP.src_addr;
754             pseudoh.dest_addr   = HDR_IP.dest_addr;
755             pseudoh.zero        = 0;
756             pseudoh.protocol    = (guint8) hdr_ip_proto;
757             pseudoh.length      = g_htons(length - header_length + sizeof(HDR_TCP));
758             /* initialize the TCP header */
759             HDR_TCP.source_port = g_htons(hdr_src_port);
760             HDR_TCP.dest_port = g_htons(hdr_dest_port);
761             /* HDR_TCP.seq_num already correct */
762             HDR_TCP.window = g_htons(0x2000);
763             HDR_TCP.checksum = 0;
764             /* Note: g_ntohs()/g_htons() macro arg may be eval'd twice so calc value before invoking macro */
765             x16  = in_checksum(&pseudoh, sizeof(pseudoh));
766             u    = g_ntohs(x16);
767             x16  = in_checksum(&HDR_TCP, sizeof(HDR_TCP));
768             u   += g_ntohs(x16);
769             x16  = in_checksum(packet_buf + header_length, length - header_length);
770             u   += g_ntohs(x16);
771             x16  = (u & 0xffff) + (u>>16);
772             HDR_TCP.checksum = g_htons(x16);
773             if (HDR_TCP.checksum == 0) /* differentiate between 'none' and 0 */
774                 HDR_TCP.checksum = g_htons(1);
775             write_bytes((const char *)&HDR_TCP, sizeof(HDR_TCP));
776             HDR_TCP.seq_num = g_ntohl(HDR_TCP.seq_num) + length - header_length;
777             HDR_TCP.seq_num = g_htonl(HDR_TCP.seq_num);
778         }
779
780         /* Compute DATA chunk header */
781         if (hdr_data_chunk) {
782             hdr_data_chunk_bits = 0;
783             if (packet_start == 0) {
784                 hdr_data_chunk_bits |= 0x02;
785             }
786             if (!cont) {
787                 hdr_data_chunk_bits |= 0x01;
788             }
789             HDR_DATA_CHUNK.type   = hdr_data_chunk_type;
790             HDR_DATA_CHUNK.bits   = hdr_data_chunk_bits;
791             HDR_DATA_CHUNK.length = g_htons(length - header_length + sizeof(HDR_DATA_CHUNK));
792             HDR_DATA_CHUNK.tsn    = g_htonl(hdr_data_chunk_tsn);
793             HDR_DATA_CHUNK.sid    = g_htons(hdr_data_chunk_sid);
794             HDR_DATA_CHUNK.ssn    = g_htons(hdr_data_chunk_ssn);
795             HDR_DATA_CHUNK.ppid   = g_htonl(hdr_data_chunk_ppid);
796             hdr_data_chunk_tsn++;
797             if (!cont) {
798                 hdr_data_chunk_ssn++;
799             }
800         }
801
802         /* Write SCTP common header */
803         if (hdr_sctp) {
804             guint32 zero = 0;
805
806             HDR_SCTP.src_port  = g_htons(hdr_sctp_src);
807             HDR_SCTP.dest_port = g_htons(hdr_sctp_dest);
808             HDR_SCTP.tag       = g_htonl(hdr_sctp_tag);
809             HDR_SCTP.checksum  = g_htonl(0);
810             HDR_SCTP.checksum  = crc32c((guint8 *)&HDR_SCTP, sizeof(HDR_SCTP), ~0L);
811             if (hdr_data_chunk) {
812                 HDR_SCTP.checksum  = crc32c((guint8 *)&HDR_DATA_CHUNK, sizeof(HDR_DATA_CHUNK), HDR_SCTP.checksum);
813                 HDR_SCTP.checksum  = crc32c((guint8 *)packet_buf + header_length, length - header_length, HDR_SCTP.checksum);
814                 HDR_SCTP.checksum  = crc32c((guint8 *)&zero, padding_length, HDR_SCTP.checksum);
815             } else {
816                 HDR_SCTP.checksum  = crc32c((guint8 *)packet_buf + header_length, length - header_length, HDR_SCTP.checksum);
817             }
818             HDR_SCTP.checksum = finalize_crc32c(HDR_SCTP.checksum);
819             HDR_SCTP.checksum  = g_htonl(HDR_SCTP.checksum);
820             write_bytes((const char *)&HDR_SCTP, sizeof(HDR_SCTP));
821         }
822
823         /* Write DATA chunk header */
824         if (hdr_data_chunk) {
825             write_bytes((const char *)&HDR_DATA_CHUNK, sizeof(HDR_DATA_CHUNK));
826         }
827
828         /* Reset curr_offset, since we now write the trailers */
829         curr_offset = length;
830
831         /* Write DATA chunk padding */
832         if (hdr_data_chunk && (padding_length > 0)) {
833             memset(tempbuf, 0, padding_length);
834             write_bytes((const char *)&tempbuf, padding_length);
835             length += padding_length;
836         }
837
838         /* Write Ethernet trailer */
839         if (hdr_ethernet && (length < 60)) {
840             memset(tempbuf, 0, 60 - length);
841             write_bytes((const char *)&tempbuf, 60 - length);
842             length = 60;
843         }
844         if (use_pcapng) {
845             success = libpcap_write_enhanced_packet_block(libpcap_write_to_file, output_file,
846                                                           NULL,
847                                                           ts_sec, ts_usec,
848                                                           length, length,
849                                                           0,
850                                                           1000000,
851                                                           packet_buf, direction,
852                                                           &bytes_written, &err);
853         } else {
854             success = libpcap_write_packet(libpcap_write_to_file, output_file,
855                                            ts_sec, ts_usec,
856                                            length, length,
857                                            packet_buf,
858                                            &bytes_written, &err);
859         }
860         if (!success) {
861             fprintf(stderr, "File write error [%s] : %s\n",
862                     output_filename, g_strerror(err));
863             exit(-1);
864         }
865         if (ts_fmt == NULL) {
866             /* fake packet counter */
867             ts_usec++;
868         }
869         if (!quiet) {
870             fprintf(stderr, "Wrote packet of %u bytes.\n", length);
871         }
872         num_packets_written ++;
873     }
874
875     packet_start += curr_offset - header_length;
876     curr_offset = header_length;
877     return;
878 }
879
880 /*----------------------------------------------------------------------
881  * Write file header and trailer
882  */
883 static void
884 write_file_header (void)
885 {
886     int err;
887     gboolean success;
888
889     if (use_pcapng) {
890 #ifdef SVNVERSION
891         const char *appname = "text2pcap (" SVNVERSION " from " SVNPATH ")";
892 #else
893         const char *appname = "text2pcap";
894 #endif
895         char comment[100];
896
897         g_snprintf(comment, sizeof(comment), "Generated from input file %s.", input_filename);
898         success = libpcap_write_session_header_block(libpcap_write_to_file, output_file,
899                                                      comment,
900                                                      NULL,
901                                                      NULL,
902                                                      appname,
903                                                      -1,
904                                                      &bytes_written,
905                                                      &err);
906         if (success) {
907             success = libpcap_write_interface_description_block(libpcap_write_to_file, output_file,
908                                                                 NULL,
909                                                                 NULL,
910                                                                 NULL,
911                                                                 "",
912                                                                 NULL,
913                                                                 pcap_link_type,
914                                                                 PCAP_SNAPLEN,
915                                                                 &bytes_written,
916                                                                 0,
917                                                                 6,
918                                                                 &err);
919         }
920     } else {
921         success = libpcap_write_file_header(libpcap_write_to_file, output_file, pcap_link_type, PCAP_SNAPLEN,
922                                             FALSE, &bytes_written, &err);
923     }
924     if (!success) {
925         fprintf(stderr, "File write error [%s] : %s\n",
926                 output_filename, g_strerror(err));
927         exit(-1);
928     }
929 }
930
931 static void
932 write_file_trailer (void)
933 {
934     int err;
935     gboolean success;
936
937     if (use_pcapng) {
938         success = libpcap_write_interface_statistics_block(libpcap_write_to_file, output_file,
939                                                            0,
940                                                            &bytes_written,
941                                                            "Counters provided by text2pcap",
942                                                            0,
943                                                            0,
944                                                            num_packets_written,
945                                                            num_packets_written - num_packets_written,
946                                                            &err);
947
948     } else {
949         success = TRUE;
950     }
951     if (!success) {
952         fprintf(stderr, "File write error [%s] : %s\n",
953                 output_filename, g_strerror(err));
954         exit(-1);
955     }
956    return;
957 }
958
959 /*----------------------------------------------------------------------
960  * Append a token to the packet preamble.
961  */
962 static void
963 append_to_preamble(char *str)
964 {
965     size_t toklen;
966
967     if (packet_preamble_len != 0) {
968         if (packet_preamble_len == PACKET_PREAMBLE_MAX_LEN)
969             return; /* no room to add more preamble */
970         /* Add a blank separator between the previous token and this token. */
971         packet_preamble[packet_preamble_len++] = ' ';
972     }
973     toklen = strlen(str);
974     if (toklen != 0) {
975         if (packet_preamble_len + toklen > PACKET_PREAMBLE_MAX_LEN)
976             return; /* no room to add the token to the preamble */
977         g_strlcpy(&packet_preamble[packet_preamble_len], str, PACKET_PREAMBLE_MAX_LEN);
978         packet_preamble_len += (int) toklen;
979         if (debug >= 2) {
980             char *c;
981             char xs[PACKET_PREAMBLE_MAX_LEN];
982             g_strlcpy(xs, packet_preamble, PACKET_PREAMBLE_MAX_LEN);
983             while ((c = strchr(xs, '\r')) != NULL) *c=' ';
984             fprintf (stderr, "[[append_to_preamble: \"%s\"]]", xs);
985         }
986     }
987 }
988
989 /*----------------------------------------------------------------------
990  * Parse the preamble to get the timecode.
991  */
992
993 static void
994 parse_preamble (void)
995 {
996     struct tm timecode;
997     char *subsecs;
998     char *p;
999     int  subseclen;
1000     int  i;
1001
1002      /*
1003      * Null-terminate the preamble.
1004      */
1005     packet_preamble[packet_preamble_len] = '\0';
1006     if (debug > 0)
1007         fprintf(stderr, "[[parse_preamble: \"%s\"]]\n", packet_preamble);
1008
1009     if (has_direction) {
1010         switch (packet_preamble[0]) {
1011         case 'i':
1012         case 'I':
1013             direction = 0x00000001;
1014             packet_preamble[0] = ' ';
1015             break;
1016         case 'o':
1017         case 'O':
1018             direction = 0x00000002;
1019             packet_preamble[0] = ' ';
1020             break;
1021         default:
1022             direction = 0x00000000;
1023             break;
1024         }
1025         i = 0;
1026         while (packet_preamble[i] == ' ' ||
1027                packet_preamble[i] == '\r' ||
1028                packet_preamble[i] == '\t') {
1029             i++;
1030         }
1031         packet_preamble_len -= i;
1032         /* Also move the trailing '\0'. */
1033         memmove(packet_preamble, packet_preamble + i, packet_preamble_len + 1);
1034     }
1035
1036
1037     /*
1038      * If no "-t" flag was specified, don't attempt to parse the packet
1039      * preamble to extract a time stamp.
1040      */
1041     if (ts_fmt == NULL) {
1042         /* Clear Preamble */
1043         packet_preamble_len = 0;
1044         return;
1045     }
1046
1047     /*
1048      * Initialize to today localtime, just in case not all fields
1049      * of the date and time are specified.
1050      */
1051
1052     timecode = timecode_default;
1053     ts_usec = 0;
1054
1055     /* Ensure preamble has more than two chars before attempting to parse.
1056      * This should cover line breaks etc that get counted.
1057      */
1058     if (strlen(packet_preamble) > 2) {
1059         /* Get Time leaving subseconds */
1060         subsecs = strptime( packet_preamble, ts_fmt, &timecode );
1061         if (subsecs != NULL) {
1062             /* Get the long time from the tm structure */
1063             /*  (will return -1 if failure)            */
1064             ts_sec  = mktime( &timecode );
1065         } else
1066             ts_sec = -1;    /* we failed to parse it */
1067
1068         /* This will ensure incorrectly parsed dates get set to zero */
1069         if (-1 == ts_sec) {
1070             /* Sanitize - remove all '\r' */
1071             char *c;
1072             while ((c = strchr(packet_preamble, '\r')) != NULL) *c=' ';
1073             fprintf (stderr, "Failure processing time \"%s\" using time format \"%s\"\n   (defaulting to Jan 1,1970 00:00:00 GMT)\n",
1074                  packet_preamble, ts_fmt);
1075             if (debug >= 2) {
1076                 fprintf(stderr, "timecode: %02d/%02d/%d %02d:%02d:%02d %d\n",
1077                     timecode.tm_mday, timecode.tm_mon, timecode.tm_year,
1078                     timecode.tm_hour, timecode.tm_min, timecode.tm_sec, timecode.tm_isdst);
1079             }
1080             ts_sec  = 0;  /* Jan 1,1970: 00:00 GMT; tshark/wireshark will display date/time as adjusted by timezone */
1081             ts_usec = 0;
1082         } else {
1083             /* Parse subseconds */
1084             ts_usec = (guint32)strtol(subsecs, &p, 10);
1085             if (subsecs == p) {
1086                 /* Error */
1087                 ts_usec = 0;
1088             } else {
1089                 /*
1090                  * Convert that number to a number
1091                  * of microseconds; if it's N digits
1092                  * long, it's in units of 10^(-N) seconds,
1093                  * so, to convert it to units of
1094                  * 10^-6 seconds, we multiply by
1095                  * 10^(6-N).
1096                  */
1097                 subseclen = (int) (p - subsecs);
1098                 if (subseclen > 6) {
1099                     /*
1100                      * *More* than 6 digits; 6-N is
1101                      * negative, so we divide by
1102                      * 10^(N-6).
1103                      */
1104                     for (i = subseclen - 6; i != 0; i--)
1105                         ts_usec /= 10;
1106                 } else if (subseclen < 6) {
1107                     for (i = 6 - subseclen; i != 0; i--)
1108                         ts_usec *= 10;
1109                 }
1110             }
1111         }
1112     }
1113     if (debug >= 2) {
1114         char *c;
1115         while ((c = strchr(packet_preamble, '\r')) != NULL) *c=' ';
1116         fprintf(stderr, "[[parse_preamble: \"%s\"]]\n", packet_preamble);
1117         fprintf(stderr, "Format(%s), time(%u), subsecs(%u)\n", ts_fmt, (guint32)ts_sec, ts_usec);
1118     }
1119
1120
1121     /* Clear Preamble */
1122     packet_preamble_len = 0;
1123 }
1124
1125 /*----------------------------------------------------------------------
1126  * Start a new packet
1127  */
1128 static void
1129 start_new_packet(gboolean cont)
1130 {
1131     if (debug >= 1)
1132         fprintf(stderr, "Start new packet (cont = %s).\n", cont ? "TRUE" : "FALSE");
1133
1134     /* Write out the current packet, if required */
1135     write_current_packet(cont);
1136     num_packets_read ++;
1137
1138     /* Ensure we parse the packet preamble as it may contain the time */
1139     parse_preamble();
1140 }
1141
1142 /*----------------------------------------------------------------------
1143  * Process a directive
1144  */
1145 static void
1146 process_directive (char *str)
1147 {
1148     fprintf(stderr, "\n--- Directive [%s] currently unsupported ---\n", str + 10);
1149 }
1150
1151 /*----------------------------------------------------------------------
1152  * Parse a single token (called from the scanner)
1153  */
1154 void
1155 parse_token (token_t token, char *str)
1156 {
1157     guint32 num;
1158     int by_eol;
1159     int rollback = 0;
1160     int line_size;
1161     int i;
1162     char* s2;
1163     char tmp_str[3];
1164
1165     /*
1166      * This is implemented as a simple state machine of five states.
1167      * State transitions are caused by tokens being received from the
1168      * scanner. The code should be self_documenting.
1169      */
1170
1171     if (debug >= 2) {
1172         /* Sanitize - remove all '\r' */
1173         char *c;
1174         if (str!=NULL) { while ((c = strchr(str, '\r')) != NULL) *c=' '; }
1175
1176         fprintf(stderr, "(%s, %s \"%s\") -> (",
1177                 state_str[state], token_str[token], str ? str : "");
1178     }
1179
1180     switch(state) {
1181
1182     /* ----- Waiting for new packet -------------------------------------------*/
1183     case INIT:
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         switch(token) {
1214         case T_TEXT:
1215             append_to_preamble(str);
1216             break;
1217         case T_DIRECTIVE:
1218             process_directive(str);
1219             break;
1220         case T_OFFSET:
1221             num = parse_num(str, TRUE);
1222             if (num == 0) {
1223                 /* New packet starts here */
1224                 start_new_packet(FALSE);
1225                 packet_start = 0;
1226                 state = READ_OFFSET;
1227             } else if ((num - packet_start) != curr_offset - header_length) {
1228                 /*
1229                  * The offset we read isn't the one we expected.
1230                  * This may only mean that we mistakenly interpreted
1231                  * some text as byte values (e.g., if the text dump
1232                  * of packet data included a number with spaces around
1233                  * it).  If the offset is less than what we expected,
1234                  * assume that's the problem, and throw away the putative
1235                  * extra byte values.
1236                  */
1237                 if (num < curr_offset) {
1238                     unwrite_bytes(curr_offset - num);
1239                     state = READ_OFFSET;
1240                 } else {
1241                     /* Bad offset; switch to INIT state */
1242                     if (debug >= 1)
1243                         fprintf(stderr, "Inconsistent offset. Expecting %0X, got %0X. Ignoring rest of packet\n",
1244                                 curr_offset, num);
1245                     write_current_packet(FALSE);
1246                     state = INIT;
1247                 }
1248             } else
1249                 state = READ_OFFSET;
1250                 pkt_lnstart = packet_buf + num;
1251             break;
1252         case T_EOL:
1253             state = START_OF_LINE;
1254             break;
1255         default:
1256             break;
1257         }
1258         break;
1259
1260     /* ----- Processing packet, read offset -----------------------------------*/
1261     case READ_OFFSET:
1262         switch(token) {
1263         case T_BYTE:
1264             /* Record the byte */
1265             state = READ_BYTE;
1266             write_byte(str);
1267             break;
1268         case T_TEXT:
1269         case T_DIRECTIVE:
1270         case T_OFFSET:
1271             state = READ_TEXT;
1272             break;
1273         case T_EOL:
1274             state = START_OF_LINE;
1275             break;
1276         default:
1277             break;
1278         }
1279         break;
1280
1281     /* ----- Processing packet, read byte -------------------------------------*/
1282     case READ_BYTE:
1283         switch(token) {
1284         case T_BYTE:
1285             /* Record the byte */
1286             write_byte(str);
1287             break;
1288         case T_TEXT:
1289         case T_DIRECTIVE:
1290         case T_OFFSET:
1291         case T_EOL:
1292             by_eol = 0;
1293             state = READ_TEXT;
1294             if (token == T_EOL) {
1295                 by_eol = 1;
1296                 state = START_OF_LINE;
1297             }
1298             if (identify_ascii) {
1299                 /* Here a line of pkt bytes reading is finished
1300                    compare the ascii and hex to avoid such situation:
1301                    "61 62 20 ab ", when ab is ascii dump then it should
1302                    not be treat as byte */
1303                 rollback = 0;
1304                 /* s2 is the ASCII string, s1 is the HEX string, e.g, when
1305                    s2 = "ab ", s1 = "616220"
1306                    we should find out the largest tail of s1 matches the head
1307                    of s2, it means the matched part in tail is the ASCII dump
1308                    of the head byte. These matched should be rollback */
1309                 line_size = curr_offset-(int)(pkt_lnstart-packet_buf);
1310                 s2 = (char*)g_malloc((line_size+1)/4+1);
1311                 /* gather the possible pattern */
1312                 for (i = 0; i < (line_size+1)/4; i++) {
1313                     tmp_str[0] = pkt_lnstart[i*3];
1314                     tmp_str[1] = pkt_lnstart[i*3+1];
1315                     tmp_str[2] = '\0';
1316                     /* it is a valid convertable string */
1317                     if (!isxdigit(tmp_str[0]) || !isxdigit(tmp_str[0])) {
1318                         break;
1319                     }
1320                     s2[i] = (char)strtoul(tmp_str, (char **)NULL, 16);
1321                     rollback++;
1322                     /* the 3rd entry is not a delimiter, so the possible byte pattern will not shown */
1323                     if (!(pkt_lnstart[i*3+2] == ' ')) {
1324                         if (by_eol != 1)
1325                             rollback--;
1326                         break;
1327                     }
1328                 }
1329                 /* If packet line start contains possible byte pattern, the line end
1330                    should contain the matched pattern if the user open the -a flag.
1331                    The packet will be possible invalid if the byte pattern cannot find
1332                    a matched one in the line of packet buffer.*/
1333                 if (rollback > 0) {
1334                     if (strncmp(pkt_lnstart+line_size-rollback, s2, rollback) == 0) {
1335                         unwrite_bytes(rollback);
1336                     }
1337                     /* Not matched. This line contains invalid packet bytes, so
1338                        discard the whole line */
1339                     else {
1340                         unwrite_bytes(line_size);
1341                     }
1342                 }
1343                 g_free(s2);
1344             }
1345             break;
1346         default:
1347             break;
1348         }
1349         break;
1350
1351     /* ----- Processing packet, read text -------------------------------------*/
1352     case READ_TEXT:
1353         switch(token) {
1354         case T_EOL:
1355             state = START_OF_LINE;
1356             break;
1357         default:
1358             break;
1359         }
1360         break;
1361
1362     default:
1363         fprintf(stderr, "FATAL ERROR: Bad state (%d)", state);
1364         exit(-1);
1365     }
1366
1367     if (debug>=2)
1368         fprintf(stderr, ", %s)\n", state_str[state]);
1369
1370 }
1371
1372 /*----------------------------------------------------------------------
1373  * Print usage string and exit
1374  */
1375 static void
1376 usage (void)
1377 {
1378     fprintf(stderr,
1379             "Text2pcap %s"
1380 #ifdef SVNVERSION
1381             " (" SVNVERSION " from " SVNPATH ")"
1382 #endif
1383             "\n"
1384             "Generate a capture file from an ASCII hexdump of packets.\n"
1385             "See http://www.wireshark.org for more information.\n"
1386             "\n"
1387             "Usage: text2pcap [options] <infile> <outfile>\n"
1388             "\n"
1389             "where  <infile> specifies input  filename (use - for standard input)\n"
1390             "      <outfile> specifies output filename (use - for standard output)\n"
1391             "\n"
1392             "Input:\n"
1393             "  -o hex|oct|dec         parse offsets as (h)ex, (o)ctal or (d)ecimal;\n"
1394             "                         default is hex.\n"
1395             "  -t <timefmt>           treat the text before the packet as a date/time code;\n"
1396             "                         the specified argument is a format string of the sort\n"
1397             "                         supported by strptime.\n"
1398             "                         Example: The time \"10:15:14.5476\" has the format code\n"
1399             "                         \"%%H:%%M:%%S.\"\n"
1400             "                         NOTE: The subsecond component delimiter, '.', must be\n"
1401             "                         given, but no pattern is required; the remaining\n"
1402             "                         number is assumed to be fractions of a second.\n"
1403             "                         NOTE: Date/time fields from the current date/time are\n"
1404             "                         used as the default for unspecified fields.\n"
1405             "  -D                     the text before the packet starts with an I or an O,\n"
1406             "                         indicating that the packet is inbound or outbound.\n"
1407             "                         This is only stored if the output format is PCAP-NG.\n"
1408             "  -a                     enable ASCII text dump identification.\n"
1409             "                         The start of the ASCII text dump can be identified\n"
1410             "                         and excluded from the packet data, even if it looks\n"
1411             "                         like a HEX dump.\n"
1412             "                         NOTE: Do not enable it if the input file does not\n"
1413             "                         contain the ASCII text dump.\n"
1414             "\n"
1415             "Output:\n"
1416             "  -l <typenum>           link-layer type number; default is 1 (Ethernet).  See\n"
1417             "                         http://www.tcpdump.org/linktypes.html for a list of\n"
1418             "                         numbers.  Use this option if your dump is a complete\n"
1419             "                         hex dump of an encapsulated packet and you wish to\n"
1420             "                         specify the exact type of encapsulation.\n"
1421             "                         Example: -l 7 for ARCNet packets.\n"
1422             "  -m <max-packet>        max packet length in output; default is %d\n"
1423             "\n"
1424             "Prepend dummy header:\n"
1425             "  -e <l3pid>             prepend dummy Ethernet II header with specified L3PID\n"
1426             "                         (in HEX).\n"
1427             "                         Example: -e 0x806 to specify an ARP packet.\n"
1428             "  -i <proto>             prepend dummy IP header with specified IP protocol\n"
1429             "                         (in DECIMAL).\n"
1430             "                         Automatically prepends Ethernet header as well.\n"
1431             "                         Example: -i 46\n"
1432             "  -4 <srcip>,<destip>    prepend dummy IPv4 header with specified\n"
1433             "                         dest and source address.\n"
1434             "                         Example: -4 10.0.0.1,10.0.0.2\n"
1435             "  -6 <srcip>,<destip>    replace IPv6 header with specified\n"
1436             "                         dest and source address.\n"
1437             "                         Example: -6 fe80:0:0:0:202:b3ff:fe1e:8329, 2001:0db8:85a3:0000:0000:8a2e:0370:7334\n"
1438             "  -u <srcp>,<destp>      prepend dummy UDP header with specified\n"
1439             "                         source and destination ports (in DECIMAL).\n"
1440             "                         Automatically prepends Ethernet & IP headers as well.\n"
1441             "                         Example: -u 1000,69 to make the packets look like\n"
1442             "                         TFTP/UDP packets.\n"
1443             "  -T <srcp>,<destp>      prepend dummy TCP header with specified\n"
1444             "                         source and destination ports (in DECIMAL).\n"
1445             "                         Automatically prepends Ethernet & IP headers as well.\n"
1446             "                         Example: -T 50,60\n"
1447             "  -s <srcp>,<dstp>,<tag> prepend dummy SCTP header with specified\n"
1448             "                         source/dest ports and verification tag (in DECIMAL).\n"
1449             "                         Automatically prepends Ethernet & IP headers as well.\n"
1450             "                         Example: -s 30,40,34\n"
1451             "  -S <srcp>,<dstp>,<ppi> prepend dummy SCTP header with specified\n"
1452             "                         source/dest ports and verification tag 0.\n"
1453             "                         Automatically prepends a dummy SCTP DATA\n"
1454             "                         chunk header with payload protocol identifier ppi.\n"
1455             "                         Example: -S 30,40,34\n"
1456             "\n"
1457             "Miscellaneous:\n"
1458             "  -h                     display this help and exit.\n"
1459             "  -d                     show detailed debug of parser states.\n"
1460             "  -q                     generate no output at all (automatically disables -d).\n"
1461             "  -n                     use PCAP-NG instead of PCAP as output format.\n"
1462             "",
1463             VERSION, MAX_PACKET);
1464
1465     exit(-1);
1466 }
1467
1468 /*----------------------------------------------------------------------
1469  * Parse CLI options
1470  */
1471 static void
1472 parse_options (int argc, char *argv[])
1473 {
1474     int c;
1475     char *p;
1476
1477 #ifdef _WIN32
1478     arg_list_utf_16to8(argc, argv);
1479     create_app_running_mutex();
1480 #endif /* _WIN32 */
1481
1482     /* Scan CLI parameters */
1483     while ((c = getopt(argc, argv, "Ddhqe:i:l:m:no:u:s:S:t:T:a:4:6:")) != -1) {
1484         switch(c) {
1485         case '?': usage(); break;
1486         case 'h': usage(); break;
1487         case 'd': if (!quiet) debug++; break;
1488         case 'D': has_direction = TRUE; break;
1489         case 'q': quiet = TRUE; debug = FALSE; break;
1490         case 'l': pcap_link_type = (guint32)strtol(optarg, NULL, 0); break;
1491         case 'm': max_offset = (guint32)strtol(optarg, NULL, 0); break;
1492         case 'n': use_pcapng = TRUE; break;
1493         case 'o':
1494             if (optarg[0]!='h' && optarg[0] != 'o' && optarg[0] != 'd') {
1495                 fprintf(stderr, "Bad argument for '-o': %s\n", optarg);
1496                 usage();
1497             }
1498             switch(optarg[0]) {
1499             case 'o': offset_base = 8; break;
1500             case 'h': offset_base = 16; break;
1501             case 'd': offset_base = 10; break;
1502             }
1503             break;
1504         case 'e':
1505             hdr_ethernet = TRUE;
1506             if (sscanf(optarg, "%x", &hdr_ethernet_proto) < 1) {
1507                 fprintf(stderr, "Bad argument for '-e': %s\n", optarg);
1508                 usage();
1509             }
1510             break;
1511
1512         case 'i':
1513             hdr_ip = TRUE;
1514             hdr_ip_proto = strtol(optarg, &p, 10);
1515             if (p == optarg || *p != '\0' || hdr_ip_proto < 0 ||
1516                   hdr_ip_proto > 255) {
1517                 fprintf(stderr, "Bad argument for '-i': %s\n", optarg);
1518                 usage();
1519             }
1520             hdr_ethernet = TRUE;
1521             hdr_ethernet_proto = 0x800;
1522             break;
1523
1524         case 's':
1525             hdr_sctp = TRUE;
1526             hdr_data_chunk = FALSE;
1527             hdr_tcp = FALSE;
1528             hdr_udp = FALSE;
1529             hdr_sctp_src   = (guint32)strtol(optarg, &p, 10);
1530             if (p == optarg || (*p != ',' && *p != '\0')) {
1531                 fprintf(stderr, "Bad src port for '-%c'\n", c);
1532                 usage();
1533             }
1534             if (*p == '\0') {
1535                 fprintf(stderr, "No dest port specified for '-%c'\n", c);
1536                 usage();
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                 usage();
1544             }
1545             if (*p == '\0') {
1546                 fprintf(stderr, "No tag specified for '-%c'\n", c);
1547                 usage();
1548             }
1549             p++;
1550             optarg = p;
1551             hdr_sctp_tag = (guint32)strtol(optarg, &p, 10);
1552             if (p == optarg || *p != '\0') {
1553                 fprintf(stderr, "Bad tag for '-%c'\n", c);
1554                 usage();
1555             }
1556
1557             hdr_ip = TRUE;
1558             hdr_ip_proto = 132;
1559             hdr_ethernet = TRUE;
1560             hdr_ethernet_proto = 0x800;
1561             break;
1562         case 'S':
1563             hdr_sctp = TRUE;
1564             hdr_data_chunk = TRUE;
1565             hdr_tcp = FALSE;
1566             hdr_udp = FALSE;
1567             hdr_sctp_src   = (guint32)strtol(optarg, &p, 10);
1568             if (p == optarg || (*p != ',' && *p != '\0')) {
1569                 fprintf(stderr, "Bad src port for '-%c'\n", c);
1570                 usage();
1571             }
1572             if (*p == '\0') {
1573                 fprintf(stderr, "No dest port specified for '-%c'\n", c);
1574                 usage();
1575             }
1576             p++;
1577             optarg = p;
1578             hdr_sctp_dest = (guint32)strtol(optarg, &p, 10);
1579             if (p == optarg || (*p != ',' && *p != '\0')) {
1580                 fprintf(stderr, "Bad dest port for '-s'\n");
1581                 usage();
1582             }
1583             if (*p == '\0') {
1584                 fprintf(stderr, "No ppi specified for '-%c'\n", c);
1585                 usage();
1586             }
1587             p++;
1588             optarg = p;
1589             hdr_data_chunk_ppid = (guint32)strtoul(optarg, &p, 10);
1590             if (p == optarg || *p != '\0') {
1591                 fprintf(stderr, "Bad ppi for '-%c'\n", c);
1592                 usage();
1593             }
1594
1595             hdr_ip = TRUE;
1596             hdr_ip_proto = 132;
1597             hdr_ethernet = TRUE;
1598             hdr_ethernet_proto = 0x800;
1599             break;
1600
1601         case 't':
1602             ts_fmt = optarg;
1603             break;
1604
1605         case 'u':
1606             hdr_udp = TRUE;
1607             hdr_tcp = FALSE;
1608             hdr_sctp = FALSE;
1609             hdr_data_chunk = FALSE;
1610             hdr_src_port = (guint32)strtol(optarg, &p, 10);
1611             if (p == optarg || (*p != ',' && *p != '\0')) {
1612                 fprintf(stderr, "Bad src port for '-u'\n");
1613                 usage();
1614             }
1615             if (*p == '\0') {
1616                 fprintf(stderr, "No dest port specified for '-u'\n");
1617                 usage();
1618             }
1619             p++;
1620             optarg = p;
1621             hdr_dest_port = (guint32)strtol(optarg, &p, 10);
1622             if (p == optarg || *p != '\0') {
1623                 fprintf(stderr, "Bad dest port for '-u'\n");
1624                 usage();
1625             }
1626             hdr_ip = TRUE;
1627             hdr_ip_proto = 17;
1628             hdr_ethernet = TRUE;
1629             hdr_ethernet_proto = 0x800;
1630             break;
1631
1632         case 'T':
1633             hdr_tcp = TRUE;
1634             hdr_udp = FALSE;
1635             hdr_sctp = FALSE;
1636             hdr_data_chunk = FALSE;
1637             hdr_src_port = (guint32)strtol(optarg, &p, 10);
1638             if (p == optarg || (*p != ',' && *p != '\0')) {
1639                 fprintf(stderr, "Bad src port for '-T'\n");
1640                 usage();
1641             }
1642             if (*p == '\0') {
1643                 fprintf(stderr, "No dest port specified for '-u'\n");
1644                 usage();
1645             }
1646             p++;
1647             optarg = p;
1648             hdr_dest_port = (guint32)strtol(optarg, &p, 10);
1649             if (p == optarg || *p != '\0') {
1650                 fprintf(stderr, "Bad dest port for '-T'\n");
1651                 usage();
1652             }
1653             hdr_ip = TRUE;
1654             hdr_ip_proto = 6;
1655             hdr_ethernet = TRUE;
1656             hdr_ethernet_proto = 0x800;
1657             break;
1658
1659         case 'a':
1660             identify_ascii = TRUE;
1661             break;
1662
1663         case '4':
1664         case '6':
1665             p = strchr(optarg, ',');
1666
1667             if (!p) {
1668                 fprintf(stderr, "Bad source param addr for '-%c'\n", c);
1669                 usage();
1670             }
1671
1672             *p = '\0';
1673             if(c == '6')
1674             {
1675                 hdr_ipv6 = TRUE;
1676                 hdr_ethernet_proto = 0x86DD;
1677             }
1678             else
1679             {
1680                 hdr_ip = TRUE;
1681                 hdr_ethernet_proto = 0x800;
1682             }
1683             hdr_ethernet = TRUE;
1684
1685             if (hdr_ipv6 == TRUE) {
1686                 if(inet_pton( AF_INET6, optarg, hdr_ipv6_src_addr) <= 0) {
1687                         fprintf(stderr, "Bad src addr -%c '%s'\n", c, p);
1688                         usage();
1689                 }
1690             } else {
1691                 if(inet_pton( AF_INET, optarg, &hdr_ip_src_addr) <= 0) {
1692                         fprintf(stderr, "Bad src addr -%c '%s'\n", c, p);
1693                         usage();
1694                 }
1695             }
1696
1697             p++;
1698             if (*p == '\0') {
1699                 fprintf(stderr, "No dest addr specified for '-%c'\n", c);
1700                 usage();
1701             }
1702
1703             if (hdr_ipv6 == TRUE) {
1704                 if(inet_pton( AF_INET6, p, hdr_ipv6_dest_addr) <= 0) {
1705                         fprintf(stderr, "Bad dest addr for -%c '%s'\n", c, p);
1706                         usage();
1707                 }
1708             } else {
1709                 if(inet_pton( AF_INET, p, &hdr_ip_dest_addr) <= 0) {
1710                         fprintf(stderr, "Bad dest addr for -%c '%s'\n", c, p);
1711                         usage();
1712                 }
1713             }
1714             break;
1715
1716
1717         default:
1718             usage();
1719         }
1720     }
1721
1722     if (optind >= argc || argc-optind < 2) {
1723         fprintf(stderr, "Must specify input and output filename\n");
1724         usage();
1725     }
1726
1727     if (strcmp(argv[optind], "-")) {
1728         input_filename = g_strdup(argv[optind]);
1729         input_file = ws_fopen(input_filename, "rb");
1730         if (!input_file) {
1731             fprintf(stderr, "Cannot open file [%s] for reading: %s\n",
1732                     input_filename, g_strerror(errno));
1733             exit(-1);
1734         }
1735     } else {
1736         input_filename = "Standard input";
1737         input_file = stdin;
1738     }
1739
1740     if (strcmp(argv[optind+1], "-")) {
1741         output_filename = g_strdup(argv[optind+1]);
1742         output_file = ws_fopen(output_filename, "wb");
1743         if (!output_file) {
1744             fprintf(stderr, "Cannot open file [%s] for writing: %s\n",
1745                     output_filename, g_strerror(errno));
1746             exit(-1);
1747         }
1748     } else {
1749         output_filename = "Standard output";
1750         output_file = stdout;
1751     }
1752
1753     /* Some validation */
1754     if (pcap_link_type != 1 && hdr_ethernet) {
1755         fprintf(stderr, "Dummy headers (-e, -i, -u, -s, -S -T) cannot be specified with link type override (-l)\n");
1756         exit(-1);
1757     }
1758
1759     /* Set up our variables */
1760     if (!input_file) {
1761         input_file = stdin;
1762         input_filename = "Standard input";
1763     }
1764     if (!output_file) {
1765         output_file = stdout;
1766         output_filename = "Standard output";
1767     }
1768
1769     ts_sec = time(0);               /* initialize to current time */
1770     timecode_default = *localtime(&ts_sec);
1771     timecode_default.tm_isdst = -1; /* Unknown for now, depends on time given to the strptime() function */
1772
1773     /* Display summary of our state */
1774     if (!quiet) {
1775         fprintf(stderr, "Input from: %s\n", input_filename);
1776         fprintf(stderr, "Output to: %s\n", output_filename);
1777         fprintf(stderr, "Output format: %s\n", use_pcapng ? "PCAP-NG" : "PCAP");
1778
1779         if (hdr_ethernet) fprintf(stderr, "Generate dummy Ethernet header: Protocol: 0x%0X\n",
1780                                   hdr_ethernet_proto);
1781         if (hdr_ip) fprintf(stderr, "Generate dummy IP header: Protocol: %ld\n",
1782                             hdr_ip_proto);
1783         if (hdr_udp) fprintf(stderr, "Generate dummy UDP header: Source port: %u. Dest port: %u\n",
1784                              hdr_src_port, hdr_dest_port);
1785         if (hdr_tcp) fprintf(stderr, "Generate dummy TCP header: Source port: %u. Dest port: %u\n",
1786                              hdr_src_port, hdr_dest_port);
1787         if (hdr_sctp) fprintf(stderr, "Generate dummy SCTP header: Source port: %u. Dest port: %u. Tag: %u\n",
1788                               hdr_sctp_src, hdr_sctp_dest, hdr_sctp_tag);
1789         if (hdr_data_chunk) fprintf(stderr, "Generate dummy DATA chunk header: TSN: %u. SID: %d. SSN: %d. PPID: %u\n",
1790                                     hdr_data_chunk_tsn, hdr_data_chunk_sid, hdr_data_chunk_ssn, hdr_data_chunk_ppid);
1791     }
1792 }
1793
1794 int
1795 main(int argc, char *argv[])
1796 {
1797     parse_options(argc, argv);
1798
1799     assert(input_file != NULL);
1800     assert(output_file != NULL);
1801
1802     write_file_header();
1803
1804     header_length = 0;
1805     if (hdr_ethernet) {
1806         header_length += (int)sizeof(HDR_ETHERNET);
1807     }
1808     if (hdr_ip) {
1809         ip_offset = header_length;
1810         header_length += (int)sizeof(HDR_IP);
1811     } else if (hdr_ipv6) {
1812         ip_offset = header_length;
1813         header_length += (int)sizeof(HDR_IPv6);
1814     }
1815     if (hdr_sctp) {
1816         header_length += (int)sizeof(HDR_SCTP);
1817     }
1818     if (hdr_data_chunk) {
1819         header_length += (int)sizeof(HDR_DATA_CHUNK);
1820     }
1821     if (hdr_tcp) {
1822         header_length += (int)sizeof(HDR_TCP);
1823     }
1824     if (hdr_udp) {
1825         header_length += (int)sizeof(HDR_UDP);
1826     }
1827     curr_offset = header_length;
1828
1829     yyin = input_file;
1830     yylex();
1831
1832     write_current_packet(FALSE);
1833     write_file_trailer();
1834     fclose(input_file);
1835     fclose(output_file);
1836     if (debug)
1837         fprintf(stderr, "\n-------------------------\n");
1838     if (!quiet) {
1839         fprintf(stderr, "Read %u potential packet%s, wrote %u packet%s (%" G_GINT64_MODIFIER "u byte%s).\n",
1840                 num_packets_read, (num_packets_read == 1) ? "" : "s",
1841                 num_packets_written, (num_packets_written == 1) ? "" : "s",
1842                 bytes_written, (bytes_written == 1) ? "" : "s");
1843     }
1844     return 0;
1845 }
1846
1847 /*
1848  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
1849  *
1850  * Local variables:
1851  * c-basic-offset: 4
1852  * tab-width: 4
1853  * indent-tabs-mode: nil
1854  * End:
1855  *
1856  * vi: set shiftwidth=4 tabstop=4 expandtab:
1857  * :indentSize=4:tabSize=4:noTabs=true:
1858  */
1859