From Tony Trinh:
[obnox/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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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 64K. Packet
77  * snaplength is automatically set to 64K.
78  */
79
80 #ifdef HAVE_CONFIG_H
81 # include "config.h"
82 #endif
83
84 /*
85  * Just make sure we include the prototype for strptime as well
86  * (needed for glibc 2.2) but make sure we do this only if not
87  * yet defined.
88  */
89 #ifndef __USE_XOPEN
90 #  define __USE_XOPEN
91 #endif
92 #ifndef _XOPEN_SOURCE
93 #  define _XOPEN_SOURCE 600
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 "text2pcap.h"
137 #include "svnversion.h"
138
139 #ifdef _WIN32
140 #include <wsutil/unicode-utils.h>
141 #endif /* _WIN32 */
142
143 /*--- Options --------------------------------------------------------------------*/
144
145 /* Debug level */
146 static int debug = 0;
147 /* Be quiet */
148 static int quiet = FALSE;
149
150 /* Dummy Ethernet header */
151 static int hdr_ethernet = FALSE;
152 static unsigned long hdr_ethernet_proto = 0;
153
154 /* Dummy IP header */
155 static int hdr_ip = FALSE;
156 static long hdr_ip_proto = 0;
157
158 /* Dummy UDP header */
159 static int hdr_udp = FALSE;
160 static unsigned long hdr_dest_port = 0;
161 static unsigned long hdr_src_port = 0;
162
163 /* Dummy TCP header */
164 static int hdr_tcp = FALSE;
165
166 /* Dummy SCTP header */
167 static int hdr_sctp = FALSE;
168 static unsigned long hdr_sctp_src  = 0;
169 static unsigned long hdr_sctp_dest = 0;
170 static unsigned long hdr_sctp_tag  = 0;
171
172 /* Dummy DATA chunk header */
173 static int hdr_data_chunk = FALSE;
174 static unsigned char  hdr_data_chunk_type = 0;
175 static unsigned char  hdr_data_chunk_bits = 3;
176 static unsigned long  hdr_data_chunk_tsn  = 0;
177 static unsigned short hdr_data_chunk_sid  = 0;
178 static unsigned short hdr_data_chunk_ssn  = 0;
179 static unsigned long  hdr_data_chunk_ppid = 0;
180
181 /* ASCII text dump identification */
182 static int identify_ascii = FALSE;
183
184 /*--- Local date -----------------------------------------------------------------*/
185
186 /* This is where we store the packet currently being built */
187 #define MAX_PACKET 64000
188 static unsigned char packet_buf[MAX_PACKET];
189 static unsigned long curr_offset = 0;
190 static unsigned long max_offset = MAX_PACKET;
191 static unsigned long packet_start = 0;
192 static void start_new_packet (void);
193
194 /* This buffer contains strings present before the packet offset 0 */
195 #define PACKET_PREAMBLE_MAX_LEN 2048
196 static unsigned char packet_preamble[PACKET_PREAMBLE_MAX_LEN+1];
197 static int packet_preamble_len = 0;
198
199 /* Number of packets read and written */
200 static unsigned long num_packets_read = 0;
201 static unsigned long num_packets_written = 0;
202
203 /* Time code of packet, derived from packet_preamble */
204 static time_t ts_sec  = 0;
205 static guint32 ts_usec = 0;
206 static char *ts_fmt = NULL;
207 static struct tm timecode_default;
208
209 static char new_date_fmt = 0;
210 static unsigned char* pkt_lnstart;
211
212 /* Input file */
213 static const char *input_filename;
214 static FILE *input_file = NULL;
215 /* Output file */
216 static const char *output_filename;
217 static FILE *output_file = NULL;
218
219 /* Offset base to parse */
220 static unsigned long offset_base = 16;
221
222 extern FILE *yyin;
223
224 /* ----- State machine -----------------------------------------------------------*/
225
226 /* Current state of parser */
227 typedef enum {
228     INIT,             /* Waiting for start of new packet */
229     START_OF_LINE,    /* Starting from beginning of line */
230     READ_OFFSET,      /* Just read the offset */
231     READ_BYTE,        /* Just read a byte */
232     READ_TEXT         /* Just read text - ignore until EOL */
233 } parser_state_t;
234 static parser_state_t state = INIT;
235
236 static const char *state_str[] = {"Init",
237                            "Start-of-line",
238                            "Offset",
239                            "Byte",
240                            "Text"
241 };
242
243 static const char *token_str[] = {"",
244                            "Byte",
245                            "Offset",
246                            "Directive",
247                            "Text",
248                            "End-of-line"
249 };
250
251 /* ----- Skeleton Packet Headers --------------------------------------------------*/
252
253 typedef struct {
254     guint8  dest_addr[6];
255     guint8  src_addr[6];
256     guint16 l3pid;
257 } hdr_ethernet_t;
258
259 static hdr_ethernet_t HDR_ETHERNET = {
260     {0x0a, 0x02, 0x02, 0x02, 0x02, 0x02},
261     {0x0a, 0x01, 0x01, 0x01, 0x01, 0x01},
262     0};
263
264 typedef struct {
265     guint8  ver_hdrlen;
266     guint8  dscp;
267     guint16 packet_length;
268     guint16 identification;
269     guint8  flags;
270     guint8  fragment;
271     guint8  ttl;
272     guint8  protocol;
273     guint16 hdr_checksum;
274     guint32 src_addr;
275     guint32 dest_addr;
276 } hdr_ip_t;
277
278 static hdr_ip_t HDR_IP = {0x45, 0, 0, 0x3412, 0, 0, 0xff, 0, 0,
279 #ifdef WORDS_BIGENDIAN
280 0x0a010101, 0x0a020202
281 #else
282 0x0101010a, 0x0202020a
283 #endif
284 };
285
286 static struct {                 /* pseudo header for checksum calculation */
287         guint32 src_addr;
288         guint32 dest_addr;
289         guint8  zero;
290         guint8  protocol;
291         guint16 length;
292 } pseudoh;
293
294 typedef struct {
295     guint16 source_port;
296     guint16 dest_port;
297     guint16 length;
298     guint16 checksum;
299 } hdr_udp_t;
300
301 static hdr_udp_t HDR_UDP = {0, 0, 0, 0};
302
303 typedef struct {
304     guint16 source_port;
305     guint16 dest_port;
306     guint32 seq_num;
307     guint32 ack_num;
308     guint8  hdr_length;
309     guint8  flags;
310     guint16 window;
311     guint16 checksum;
312     guint16 urg;
313 } hdr_tcp_t;
314
315 static hdr_tcp_t HDR_TCP = {0, 0, 0, 0, 0x50, 0, 0, 0, 0};
316
317 typedef struct {
318     guint16 src_port;
319     guint16 dest_port;
320     guint32 tag;
321     guint32 checksum;
322 } hdr_sctp_t;
323
324 static hdr_sctp_t HDR_SCTP = {0, 0, 0, 0};
325
326 typedef struct {
327     guint8  type;
328     guint8  bits;
329     guint16 length;
330     guint32 tsn;
331     guint16 sid;
332     guint16 ssn;
333     guint32 ppid;
334 } hdr_data_chunk_t;
335
336 static hdr_data_chunk_t HDR_DATA_CHUNK = {0, 0, 0, 0, 0, 0, 0};
337
338 static char tempbuf[64];
339
340 /*----------------------------------------------------------------------
341  * Stuff for writing a PCap file
342  */
343 #define PCAP_MAGIC                      0xa1b2c3d4
344
345 /* "libpcap" file header (minus magic number). */
346 struct pcap_hdr {
347     guint32     magic;          /* magic */
348     guint16     version_major;  /* major version number */
349     guint16     version_minor;  /* minor version number */
350     guint32     thiszone;       /* GMT to local correction */
351     guint32     sigfigs;        /* accuracy of timestamps */
352     guint32     snaplen;        /* max length of captured packets, in octets */
353     guint32     network;        /* data link type */
354 };
355
356 /* "libpcap" record header. */
357 struct pcaprec_hdr {
358     guint32     ts_sec;         /* timestamp seconds */
359     guint32     ts_usec;        /* timestamp microseconds */
360     guint32     incl_len;       /* number of octets of packet saved in file */
361     guint32     orig_len;       /* actual length of packet */
362 };
363
364 /* Link-layer type; see net/bpf.h for details */
365 static unsigned long pcap_link_type = 1;   /* Default is DLT-EN10MB */
366
367 /*----------------------------------------------------------------------
368  * Parse a single hex number
369  * Will abort the program if it can't parse the number
370  * Pass in TRUE if this is an offset, FALSE if not
371  */
372 static unsigned long
373 parse_num (const char *str, int offset)
374 {
375     unsigned long num;
376     char *c;
377
378     num = strtoul(str, &c, offset ? offset_base : 16);
379     if (c==str) {
380         fprintf(stderr, "FATAL ERROR: Bad hex number? [%s]\n", str);
381         exit(-1);
382     }
383     return num;
384 }
385
386 /*----------------------------------------------------------------------
387  * Write this byte into current packet
388  */
389 static void
390 write_byte (const char *str)
391 {
392     unsigned long num;
393
394     num = parse_num(str, FALSE);
395     packet_buf[curr_offset] = (unsigned char) num;
396     curr_offset ++;
397     if (curr_offset >= max_offset) /* packet full */
398             start_new_packet();
399 }
400
401 /*----------------------------------------------------------------------
402  * Remove bytes from the current packet
403  */
404 static void
405 unwrite_bytes (unsigned long nbytes)
406 {
407     curr_offset -= nbytes;
408 }
409
410 /*----------------------------------------------------------------------
411  * Compute one's complement checksum (from RFC1071)
412  */
413 static guint16
414 in_checksum (void *buf, unsigned long count)
415 {
416     unsigned long sum = 0;
417     guint16 *addr = buf;
418
419     while( count > 1 )  {
420         /*  This is the inner loop */
421         sum += g_ntohs(* (guint16 *) addr);
422         addr++;
423         count -= 2;
424     }
425
426     /*  Add left-over byte, if any */
427     if( count > 0 )
428         sum += g_ntohs(* (guint8 *) addr);
429
430     /*  Fold 32-bit sum to 16 bits */
431     while (sum>>16)
432         sum = (sum & 0xffff) + (sum >> 16);
433
434     sum = ~sum;
435     return g_htons(sum);
436 }
437
438 /* The CRC32C code is taken from draft-ietf-tsvwg-sctpcsum-01.txt.
439  * That code is copyrighted by D. Otis and has been modified.
440  */
441
442 #define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF])
443 static guint32 crc_c[256] =
444 {
445 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
446 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
447 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
448 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
449 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
450 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
451 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
452 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
453 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
454 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
455 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
456 0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
457 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
458 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
459 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
460 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
461 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
462 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
463 0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
464 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
465 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
466 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
467 0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
468 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
469 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
470 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
471 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
472 0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
473 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
474 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
475 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
476 0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
477 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
478 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
479 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
480 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
481 0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
482 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
483 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
484 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
485 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
486 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
487 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
488 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
489 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
490 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
491 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
492 0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
493 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
494 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
495 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
496 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
497 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
498 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
499 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
500 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
501 0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
502 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
503 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
504 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
505 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
506 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
507 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
508 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L,
509 };
510
511 static guint32
512 crc32c(const guint8* buf, unsigned int len, guint32 crc32_init)
513 {
514   unsigned int i;
515   guint32 crc32;
516
517   crc32 = crc32_init;
518   for (i = 0; i < len; i++)
519     CRC32C(crc32, buf[i]);
520
521   return ( crc32 );
522 }
523
524 static guint32
525 finalize_crc32c(guint32 crc32)
526 {
527   guint32 result;
528   guint8 byte0,byte1,byte2,byte3;
529
530   result = ~crc32;
531   byte0 = result & 0xff;
532   byte1 = (result>>8) & 0xff;
533   byte2 = (result>>16) & 0xff;
534   byte3 = (result>>24) & 0xff;
535   result = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3);
536   return ( result );
537 }
538
539 static unsigned long
540 number_of_padding_bytes (unsigned long length)
541 {
542   unsigned long remainder;
543
544   remainder = length % 4;
545
546   if (remainder == 0)
547     return 0;
548   else
549     return 4 - remainder;
550 }
551
552 /*----------------------------------------------------------------------
553  * Write current packet out
554  */
555 static void
556 write_current_packet (void)
557 {
558     int length = 0;
559     int proto_length = 0;
560     int ip_length = 0;
561     int eth_trailer_length = 0;
562     int i, padding_length;
563     guint32 u;
564     struct pcaprec_hdr ph;
565
566     if (curr_offset > 0) {
567         /* Write the packet */
568
569         /* Compute packet length */
570         length = curr_offset;
571         if (hdr_data_chunk) { length += sizeof(HDR_DATA_CHUNK) + number_of_padding_bytes(curr_offset); }
572         if (hdr_sctp) { length += sizeof(HDR_SCTP); }
573         if (hdr_udp) { length += sizeof(HDR_UDP); proto_length = length; }
574         if (hdr_tcp) { length += sizeof(HDR_TCP); proto_length = length; }
575         if (hdr_ip) { length += sizeof(HDR_IP); ip_length = length; }
576         if (hdr_ethernet) {
577             length += sizeof(HDR_ETHERNET);
578             /* Pad trailer */
579             if (length < 60) {
580                 eth_trailer_length = 60 - length;
581                 length = 60;
582             }
583         }
584
585         /* Write PCAP header */
586         ph.ts_sec = (guint32)ts_sec;
587         ph.ts_usec = ts_usec;
588         if (ts_fmt == NULL) { ts_usec++; }      /* fake packet counter */
589         ph.incl_len = length;
590         ph.orig_len = length;
591         if (fwrite(&ph, sizeof(ph), 1, output_file) != 1)
592             goto write_current_packet_err;
593
594         /* Write Ethernet header */
595         if (hdr_ethernet) {
596             HDR_ETHERNET.l3pid = g_htons(hdr_ethernet_proto);
597             if (fwrite(&HDR_ETHERNET, sizeof(HDR_ETHERNET), 1, output_file) != 1)
598                 goto write_current_packet_err;
599         }
600
601         /* Write IP header */
602         if (hdr_ip) {
603             HDR_IP.packet_length = g_htons(ip_length);
604             HDR_IP.protocol = (guint8) hdr_ip_proto;
605             HDR_IP.hdr_checksum = 0;
606             HDR_IP.hdr_checksum = in_checksum(&HDR_IP, sizeof(HDR_IP));
607             if (fwrite(&HDR_IP, sizeof(HDR_IP), 1, output_file) != 1)
608                 goto write_current_packet_err;
609         }
610
611         /* initialize pseudo header for checksum calculation */
612         pseudoh.src_addr    = HDR_IP.src_addr;
613         pseudoh.dest_addr   = HDR_IP.dest_addr;
614         pseudoh.zero        = 0;
615         pseudoh.protocol    = (guint8) hdr_ip_proto;
616         pseudoh.length      = g_htons(proto_length);
617
618         /* Write UDP header */
619         if (hdr_udp) {
620             guint16 x16;
621             HDR_UDP.source_port = g_htons(hdr_src_port);
622             HDR_UDP.dest_port = g_htons(hdr_dest_port);
623             HDR_UDP.length = g_htons(proto_length);
624
625             /* Note: g_ntohs()/g_htons() macro arg may be eval'd twice so calc value before invoking macro */
626             HDR_UDP.checksum = 0;
627             x16  = in_checksum(&pseudoh, sizeof(pseudoh));
628             u    = g_ntohs(x16);
629             x16  = in_checksum(&HDR_UDP, sizeof(HDR_UDP));
630             u   += g_ntohs(x16);
631             x16  = in_checksum(packet_buf, curr_offset);
632             u   += g_ntohs(x16);
633             x16  = (u & 0xffff) + (u>>16);
634             HDR_UDP.checksum = g_htons(x16);
635             if (HDR_UDP.checksum == 0) /* differentiate between 'none' and 0 */
636                     HDR_UDP.checksum = g_htons(1);
637
638             if (fwrite(&HDR_UDP, sizeof(HDR_UDP), 1, output_file) != 1)
639                 goto write_current_packet_err;
640         }
641
642         /* Write TCP header */
643         if (hdr_tcp) {
644             guint16 x16;
645             HDR_TCP.source_port = g_htons(hdr_src_port);
646             HDR_TCP.dest_port = g_htons(hdr_dest_port);
647             /* HDR_TCP.seq_num already correct */
648             HDR_TCP.window = g_htons(0x2000);
649
650             /* Note: g_ntohs()/g_htons() macro arg may be eval'd twice so calc value before invoking macro */
651             HDR_TCP.checksum = 0;
652             x16  = in_checksum(&pseudoh, sizeof(pseudoh));
653             u    = g_ntohs(x16);
654             x16  = in_checksum(&HDR_TCP, sizeof(HDR_TCP));
655             u   += g_ntohs(x16);
656             x16  = in_checksum(packet_buf, curr_offset);
657             u   += g_ntohs(x16);
658             x16  = (u & 0xffff) + (u>>16);
659             HDR_TCP.checksum = g_htons(x16);
660             if (HDR_TCP.checksum == 0) /* differentiate between 'none' and 0 */
661                 HDR_TCP.checksum = g_htons(1);
662
663             if (fwrite(&HDR_TCP, sizeof(HDR_TCP), 1, output_file) != 1)
664                 goto write_current_packet_err;
665         }
666
667         /* Compute DATA chunk header and append padding */
668         if (hdr_data_chunk) {
669             HDR_DATA_CHUNK.type   = hdr_data_chunk_type;
670             HDR_DATA_CHUNK.bits   = hdr_data_chunk_bits;
671             HDR_DATA_CHUNK.length = g_htons(curr_offset + sizeof(HDR_DATA_CHUNK));
672             HDR_DATA_CHUNK.tsn    = g_htonl(hdr_data_chunk_tsn);
673             HDR_DATA_CHUNK.sid    = g_htons(hdr_data_chunk_sid);
674             HDR_DATA_CHUNK.ssn    = g_htons(hdr_data_chunk_ssn);
675             HDR_DATA_CHUNK.ppid   = g_htonl(hdr_data_chunk_ppid);
676
677             padding_length = number_of_padding_bytes(curr_offset);
678             for (i=0; i<padding_length; i++)
679               write_byte("0");
680         }
681
682         /* Write SCTP header */
683         if (hdr_sctp) {
684             guint32 x32;
685             HDR_SCTP.src_port  = g_htons(hdr_sctp_src);
686             HDR_SCTP.dest_port = g_htons(hdr_sctp_dest);
687             HDR_SCTP.tag       = g_htonl(hdr_sctp_tag);
688             HDR_SCTP.checksum  = g_htonl(0);
689             HDR_SCTP.checksum  = crc32c((guint8 *)&HDR_SCTP, sizeof(HDR_SCTP), ~0L);
690             if (hdr_data_chunk)
691               HDR_SCTP.checksum  = crc32c((guint8 *)&HDR_DATA_CHUNK, sizeof(HDR_DATA_CHUNK), HDR_SCTP.checksum);
692             /* Note: g_ntohl() macro arg may be eval'd twice so calc value before invoking macro */
693             x32 = finalize_crc32c(crc32c(packet_buf, curr_offset, HDR_SCTP.checksum));
694             HDR_SCTP.checksum  = g_htonl(x32);
695
696             if (fwrite(&HDR_SCTP, sizeof(HDR_SCTP), 1, output_file) != 1)
697                 goto write_current_packet_err;
698         }
699
700         /* Write DATA chunk header */
701         if (hdr_data_chunk) {
702             if (fwrite(&HDR_DATA_CHUNK, sizeof(HDR_DATA_CHUNK), 1, output_file) != 1)
703                 goto write_current_packet_err;
704         }
705         /* Write packet */
706         if (fwrite(packet_buf, curr_offset, 1, output_file) != 1)
707             goto write_current_packet_err;
708
709         /* Write Ethernet trailer */
710         if (hdr_ethernet && eth_trailer_length > 0) {
711             memset(tempbuf, 0, eth_trailer_length);
712             if (fwrite(tempbuf, eth_trailer_length, 1, output_file) != 1)
713                 goto write_current_packet_err;
714         }
715
716         if (!quiet)
717             fprintf(stderr, "Wrote packet of %lu bytes at %u\n", curr_offset, g_ntohl(HDR_TCP.seq_num));
718         num_packets_written ++;
719     }
720     HDR_TCP.seq_num = g_ntohl(HDR_TCP.seq_num) + curr_offset;
721     HDR_TCP.seq_num = g_htonl(HDR_TCP.seq_num);
722
723     packet_start += curr_offset;
724     curr_offset = 0;
725     return;
726
727 write_current_packet_err:
728     fprintf(stderr, "File write error [%s] : %s\n",
729             output_filename, g_strerror(errno));
730     exit(-1);
731 }
732
733 /*----------------------------------------------------------------------
734  * Write the PCap file header
735  */
736 static void
737 write_file_header (void)
738 {
739     struct pcap_hdr fh;
740
741     fh.magic = PCAP_MAGIC;
742     fh.version_major = 2;
743     fh.version_minor = 4;
744     fh.thiszone = 0;
745     fh.sigfigs = 0;
746     fh.snaplen = 102400;
747     fh.network = pcap_link_type;
748
749     if (fwrite(&fh, sizeof(fh), 1, output_file) != 1) {
750         fprintf(stderr, "File write error [%s] : %s\n",
751                 output_filename, g_strerror(errno));
752         exit(-1);
753     }
754 }
755
756 /*----------------------------------------------------------------------
757  * Append a token to the packet preamble.
758  */
759 static void
760 append_to_preamble(char *str)
761 {
762     size_t toklen;
763
764     if (packet_preamble_len != 0) {
765         if (packet_preamble_len == PACKET_PREAMBLE_MAX_LEN)
766             return;     /* no room to add more preamble */
767         /* Add a blank separator between the previous token and this token. */
768         packet_preamble[packet_preamble_len++] = ' ';
769     }
770     toklen = strlen(str);
771     if (toklen != 0) {
772         if (packet_preamble_len + toklen > PACKET_PREAMBLE_MAX_LEN)
773             return;     /* no room to add the token to the preamble */
774         g_strlcpy(&packet_preamble[packet_preamble_len], str, PACKET_PREAMBLE_MAX_LEN);
775         packet_preamble_len += (int) toklen;
776         if (debug >= 2) {
777                 char *c;
778                 char xs[PACKET_PREAMBLE_MAX_LEN];
779                 g_strlcpy(xs, packet_preamble, PACKET_PREAMBLE_MAX_LEN);
780                 while ((c = strchr(xs, '\r')) != NULL) *c=' ';
781                 fprintf (stderr, "[[append_to_preamble: \"%s\"]]", xs);
782         }
783     }
784 }
785
786 /*----------------------------------------------------------------------
787  * Parse the preamble to get the timecode.
788  */
789
790 static void
791 parse_preamble (void)
792 {
793         struct tm timecode;
794         char *subsecs;
795         char *p;
796         int  subseclen;
797         int  i;
798
799         /*
800          * If no "-t" flag was specified, don't attempt to parse a packet
801          * preamble to extract a time stamp.
802          */
803         if (ts_fmt == NULL)
804             return;
805
806         /*
807          * Initialize to today localtime, just in case not all fields
808          * of the date and time are specified.
809          */
810
811         timecode = timecode_default;
812         ts_usec = 0;
813
814         /*
815          * Null-terminate the preamble.
816          */
817         packet_preamble[packet_preamble_len] = '\0';
818
819         /* Ensure preamble has more than two chars before attempting to parse.
820          * This should cover line breaks etc that get counted.
821          */
822         if ( strlen(packet_preamble) > 2 ) {
823                 /* Get Time leaving subseconds */
824                 subsecs = strptime( packet_preamble, ts_fmt, &timecode );
825                 if (subsecs != NULL) {
826                         /* Get the long time from the tm structure */
827                         /*  (will return -1 if failure)            */
828                         ts_sec  = mktime( &timecode );
829                 } else
830                         ts_sec = -1;    /* we failed to parse it */
831
832                 /* This will ensure incorrectly parsed dates get set to zero */
833                 if ( -1 == ts_sec )
834                 {
835                         /* Sanitize - remove all '\r' */
836                         char *c;
837                         while ((c = strchr(packet_preamble, '\r')) != NULL) *c=' ';
838                         fprintf (stderr, "Failure processing time \"%s\" using time format \"%s\"\n   (defaulting to Jan 1,1970 00:00:00 GMT)\n",
839                                  packet_preamble, ts_fmt);
840                         if (debug >= 2) {
841                                 fprintf(stderr, "timecode: %02d/%02d/%d %02d:%02d:%02d %d\n",
842                                         timecode.tm_mday, timecode.tm_mon, timecode.tm_year,
843                                         timecode.tm_hour, timecode.tm_min, timecode.tm_sec, timecode.tm_isdst);
844                         }
845                         ts_sec  = 0;  /* Jan 1,1970: 00:00 GMT; tshark/wireshark will display date/time as adjusted by timezone */
846                         ts_usec = 0;
847                 }
848                 else
849                 {
850                         /* Parse subseconds */
851                         ts_usec = strtol(subsecs, &p, 10);
852                         if (subsecs == p) {
853                                 /* Error */
854                                 ts_usec = 0;
855                         } else {
856                                 /*
857                                  * Convert that number to a number
858                                  * of microseconds; if it's N digits
859                                  * long, it's in units of 10^(-N) seconds,
860                                  * so, to convert it to units of
861                                  * 10^-6 seconds, we multiply by
862                                  * 10^(6-N).
863                                  */
864                                 subseclen = (int) (p - subsecs);
865                                 if (subseclen > 6) {
866                                         /*
867                                          * *More* than 6 digits; 6-N is
868                                          * negative, so we divide by
869                                          * 10^(N-6).
870                                          */
871                                         for (i = subseclen - 6; i != 0; i--)
872                                                 ts_usec /= 10;
873                                 } else if (subseclen < 6) {
874                                         for (i = 6 - subseclen; i != 0; i--)
875                                                 ts_usec *= 10;
876                                 }
877                         }
878                 }
879         }
880         if (debug >= 2) {
881                 char *c;
882                 while ((c = strchr(packet_preamble, '\r')) != NULL) *c=' ';
883                 fprintf(stderr, "[[parse_preamble: \"%s\"]]\n", packet_preamble);
884                 fprintf(stderr, "Format(%s), time(%u), subsecs(%u)\n", ts_fmt, (guint32)ts_sec, ts_usec);
885         }
886
887
888         /* Clear Preamble */
889         packet_preamble_len = 0;
890 }
891
892 /*----------------------------------------------------------------------
893  * Start a new packet
894  */
895 static void
896 start_new_packet (void)
897 {
898     if (debug>=1)
899         fprintf(stderr, "Start new packet\n");
900
901     /* Write out the current packet, if required */
902     write_current_packet();
903     num_packets_read ++;
904
905     /* Ensure we parse the packet preamble as it may contain the time */
906     parse_preamble();
907 }
908
909 /*----------------------------------------------------------------------
910  * Process a directive
911  */
912 static void
913 process_directive (char *str)
914 {
915     fprintf(stderr, "\n--- Directive [%s] currently unsupported ---\n", str+10);
916
917 }
918
919 /*----------------------------------------------------------------------
920  * Parse a single token (called from the scanner)
921  */
922 void
923 parse_token (token_t token, char *str)
924 {
925     unsigned long num;
926     int by_eol;
927     int rollback = 0;
928     int line_size;
929     int i;
930     char* s2;
931     char tmp_str[3];
932
933     /*
934      * This is implemented as a simple state machine of five states.
935      * State transitions are caused by tokens being received from the
936      * scanner. The code should be self_documenting.
937      */
938
939     if (debug>=2) {
940         /* Sanitize - remove all '\r' */
941         char *c;
942         if (str!=NULL) { while ((c = strchr(str, '\r')) != NULL) *c=' '; }
943
944         fprintf(stderr, "(%s, %s \"%s\") -> (",
945                 state_str[state], token_str[token], str ? str : "");
946     }
947
948     /* First token must be treated as a timestamp if time strip format is
949        not empty */
950     if (state == INIT || state == START_OF_LINE) {
951         if (ts_fmt != NULL && new_date_fmt) {
952             token = T_TEXT;
953         }
954     }
955
956     switch(state) {
957
958     /* ----- Waiting for new packet -------------------------------------------*/
959     case INIT:
960         switch(token) {
961         case T_TEXT:
962             append_to_preamble(str);
963             break;
964         case T_DIRECTIVE:
965             process_directive(str);
966             break;
967         case T_OFFSET:
968             num = parse_num(str, TRUE);
969             if (num==0) {
970                 /* New packet starts here */
971                 start_new_packet();
972                 state = READ_OFFSET;
973                 pkt_lnstart = packet_buf + num;
974             }
975             break;
976         case T_EOL:
977             /* Some describing text may be parsed as offset, but the invalid
978                offset will be checked in the state of START_OF_LINE, so
979                we add this transition to gain flexibility */
980             state = START_OF_LINE;
981             break;
982         default:
983             break;
984         }
985         break;
986
987     /* ----- Processing packet, start of new line -----------------------------*/
988     case START_OF_LINE:
989         switch(token) {
990         case T_TEXT:
991             append_to_preamble(str);
992             break;
993         case T_DIRECTIVE:
994             process_directive(str);
995             break;
996         case T_OFFSET:
997             num = parse_num(str, TRUE);
998             if (num==0) {
999                 /* New packet starts here */
1000                 start_new_packet();
1001                 packet_start = 0;
1002                 state = READ_OFFSET;
1003             } else if ((num - packet_start) != curr_offset) {
1004                 /*
1005                  * The offset we read isn't the one we expected.
1006                  * This may only mean that we mistakenly interpreted
1007                  * some text as byte values (e.g., if the text dump
1008                  * of packet data included a number with spaces around
1009                  * it).  If the offset is less than what we expected,
1010                  * assume that's the problem, and throw away the putative
1011                  * extra byte values.
1012                  */
1013                 if (num < curr_offset) {
1014                     unwrite_bytes(curr_offset - num);
1015                     state = READ_OFFSET;
1016                 } else {
1017                     /* Bad offset; switch to INIT state */
1018                     if (debug>=1)
1019                         fprintf(stderr, "Inconsistent offset. Expecting %0lX, got %0lX. Ignoring rest of packet\n",
1020                                 curr_offset, num);
1021                     write_current_packet();
1022                     state = INIT;
1023                 }
1024             } else
1025                 state = READ_OFFSET;
1026                 pkt_lnstart = packet_buf + num;
1027             break;
1028         case T_EOL:
1029             state = START_OF_LINE;
1030             break;
1031         default:
1032             break;
1033         }
1034         break;
1035
1036     /* ----- Processing packet, read offset -----------------------------------*/
1037     case READ_OFFSET:
1038         switch(token) {
1039         case T_BYTE:
1040             /* Record the byte */
1041             state = READ_BYTE;
1042             write_byte(str);
1043             break;
1044         case T_TEXT:
1045         case T_DIRECTIVE:
1046         case T_OFFSET:
1047             state = READ_TEXT;
1048             break;
1049         case T_EOL:
1050             state = START_OF_LINE;
1051             break;
1052         default:
1053             break;
1054         }
1055         break;
1056
1057     /* ----- Processing packet, read byte -------------------------------------*/
1058     case READ_BYTE:
1059         switch(token) {
1060         case T_BYTE:
1061             /* Record the byte */
1062             write_byte(str);
1063             break;
1064         case T_TEXT:
1065         case T_DIRECTIVE:
1066         case T_OFFSET:
1067         case T_EOL:
1068             by_eol = 0;
1069             state = READ_TEXT;
1070             if (token == T_EOL) {
1071                 by_eol = 1;
1072                 state = START_OF_LINE;
1073             }
1074             if (identify_ascii) {
1075                 /* Here a line of pkt bytes reading is finished
1076                    compare the ascii and hex to avoid such situation:
1077                    "61 62 20 ab ", when ab is ascii dump then it should
1078                    not be treat as byte */
1079                 rollback = 0;
1080                 /* s2 is the ASCII string, s1 is the HEX string, e.g, when
1081                    s2 = "ab ", s1 = "616220"
1082                    we should find out the largest tail of s1 matches the head
1083                    of s2, it means the matched part in tail is the ASCII dump
1084                    of the head byte. These matched should be rollback */
1085                 line_size = curr_offset-(int)(pkt_lnstart-packet_buf);
1086                 s2 = (char*)g_malloc((line_size+1)/4+1);
1087                 /* gather the possible pattern */
1088                 for(i=0; i<(line_size+1)/4; i++) {
1089                     tmp_str[0] = pkt_lnstart[i*3];
1090                     tmp_str[1] = pkt_lnstart[i*3+1];
1091                     tmp_str[2] = '\0';
1092                     /* it is a valid convertable string */
1093                     if (!isxdigit(tmp_str[0]) || !isxdigit(tmp_str[0])) {
1094                         break;
1095                     }
1096                     s2[i] = (char)strtoul(tmp_str, (char **)NULL, 16);
1097                     rollback++;
1098                     /* the 3rd entry is not a delimiter, so the possible byte pattern will not shown */
1099                     if (!(pkt_lnstart[i*3+2] == ' ')) {
1100                         if (by_eol != 1)
1101                             rollback--;
1102                         break;
1103                     }
1104                 }
1105                 /* If packet line start contains possible byte pattern, the line end
1106                    should contain the matched pattern if the user open the -a flag.
1107                    The packet will be possible invalid if the byte pattern cannot find
1108                    a matched one in the line of packet buffer.*/
1109                 if (rollback > 0) {
1110                     if (strncmp(pkt_lnstart+line_size-rollback, s2, rollback) == 0) {
1111                         unwrite_bytes(rollback);
1112                     }
1113                     /* Not matched. This line contains invalid packet bytes, so
1114                        discard the whole line */
1115                     else {
1116                         unwrite_bytes(line_size);
1117                     }
1118                 }
1119                 g_free(s2);
1120             }
1121             break;
1122         default:
1123             break;
1124         }
1125         break;
1126
1127     /* ----- Processing packet, read text -------------------------------------*/
1128     case READ_TEXT:
1129         switch(token) {
1130         case T_EOL:
1131             state = START_OF_LINE;
1132             break;
1133         default:
1134             break;
1135         }
1136         break;
1137
1138     default:
1139         fprintf(stderr, "FATAL ERROR: Bad state (%d)", state);
1140         exit(-1);
1141     }
1142
1143     if (debug>=2)
1144         fprintf(stderr, ", %s)\n", state_str[state]);
1145
1146 }
1147
1148 /*----------------------------------------------------------------------
1149  * Print usage string and exit
1150  */
1151 static void
1152 usage (void)
1153 {
1154     fprintf(stderr,
1155             "Text2pcap %s"
1156 #ifdef SVNVERSION
1157             " (" SVNVERSION " from " SVNPATH ")"
1158 #endif
1159             "\n"
1160             "Generate a capture file from an ASCII hexdump of packets.\n"
1161             "See http://www.wireshark.org for more information.\n"
1162             "\n"
1163             "Usage: text2pcap [options] <infile> <outfile>\n"
1164             "\n"
1165             "where  <infile> specifies input  filename (use - for standard input)\n"
1166             "      <outfile> specifies output filename (use - for standard output)\n"
1167             "\n"
1168             "Input:\n"
1169             "  -o hex|oct|dec         parse offsets as (h)ex, (o)ctal or (d)ecimal;\n"
1170             "                         default is hex.\n"
1171             "  -t <timefmt>           treat the text before the packet as a date/time code;\n"
1172             "                         the specified argument is a format string of the sort\n"
1173             "                         supported by strptime.\n"
1174             "                         Example: The time \"10:15:14.5476\" has the format code\n"
1175             "                         \"%%H:%%M:%%S.\"\n"
1176             "                         NOTE: The subsecond component delimiter, '.', must be\n"
1177             "                         given, but no pattern is required; the remaining\n"
1178             "                         number is assumed to be fractions of a second.\n"
1179             "                         NOTE: Date/time fields from the current date/time are\n"
1180             "                         used as the default for unspecified fields.\n"
1181             "  -a                     enable ASCII text dump identification.\n"
1182             "                         It allows to identify the start of the ASCII text\n"
1183             "                         dump and not include it in the packet even if it\n"
1184             "                         looks like HEX dump.\n"
1185             "                         NOTE: Do not enable it if the input file does not\n"
1186             "                         contain the ASCII text dump.\n"
1187             "\n"
1188             "Output:\n"
1189             "  -l <typenum>           link-layer type number; default is 1 (Ethernet).\n"
1190             "                         See the file net/bpf.h for list of numbers.\n"
1191             "                         Use this option if your dump is a complete hex dump\n"
1192             "                         of an encapsulated packet and you wish to specify\n"
1193             "                         the exact type of encapsulation.\n"
1194             "                         Example: -l 7 for ARCNet packets.\n"
1195             "  -m <max-packet>        max packet length in output; default is %d\n"
1196             "\n"
1197             "Prepend dummy header:\n"
1198             "  -e <l3pid>             prepend dummy Ethernet II header with specified L3PID\n"
1199             "                         (in HEX).\n"
1200             "                         Example: -e 0x806 to specify an ARP packet.\n"
1201             "  -i <proto>             prepend dummy IP header with specified IP protocol\n"
1202             "                         (in DECIMAL).\n"
1203             "                         Automatically prepends Ethernet header as well.\n"
1204             "                         Example: -i 46\n"
1205             "  -u <srcp>,<destp>      prepend dummy UDP header with specified\n"
1206             "                         dest and source ports (in DECIMAL).\n"
1207             "                         Automatically prepends Ethernet & IP headers as well.\n"
1208             "                         Example: -u 1000,69 to make the packets look like\n"
1209             "                         TFTP/UDP packets.\n"
1210             "  -T <srcp>,<destp>      prepend dummy TCP header with specified\n"
1211             "                         dest and source ports (in DECIMAL).\n"
1212             "                         Automatically prepends Ethernet & IP headers as well.\n"
1213             "                         Example: -T 50,60\n"
1214             "  -s <srcp>,<dstp>,<tag> prepend dummy SCTP header with specified\n"
1215             "                         dest/source ports and verification tag (in DECIMAL).\n"
1216             "                         Automatically prepends Ethernet & IP headers as well.\n"
1217             "                         Example: -s 30,40,34\n"
1218             "  -S <srcp>,<dstp>,<ppi> prepend dummy SCTP header with specified\n"
1219             "                         dest/source ports and verification tag 0.\n"
1220             "                         Automatically prepends a dummy SCTP DATA\n"
1221             "                         chunk header with payload protocol identifier ppi.\n"
1222             "                         Example: -S 30,40,34\n"
1223             "\n"
1224             "Miscellaneous:\n"
1225             "  -h                     display this help and exit.\n"
1226             "  -d                     show detailed debug of parser states.\n"
1227             "  -q                     generate no output at all (automatically turns off -d).\n"
1228             "",
1229             VERSION, MAX_PACKET);
1230
1231     exit(-1);
1232 }
1233
1234 /*----------------------------------------------------------------------
1235  * Parse CLI options
1236  */
1237 static void
1238 parse_options (int argc, char *argv[])
1239 {
1240     int c;
1241     char *p;
1242
1243 #ifdef _WIN32
1244     arg_list_utf_16to8(argc, argv);
1245 #endif /* _WIN32 */
1246
1247     /* Scan CLI parameters */
1248     while ((c = getopt(argc, argv, "Ddhqe:i:l:m:o:u:s:S:t:T:a")) != -1) {
1249         switch(c) {
1250         case '?': usage(); break;
1251         case 'h': usage(); break;
1252         case 'D': new_date_fmt = 1; break;
1253         case 'd': if (!quiet) debug++; break;
1254         case 'q': quiet = TRUE; debug = FALSE; break;
1255         case 'l': pcap_link_type = strtol(optarg, NULL, 0); break;
1256         case 'm': max_offset = strtol(optarg, NULL, 0); break;
1257         case 'o':
1258             if (optarg[0]!='h' && optarg[0] != 'o' && optarg[0] != 'd') {
1259                 fprintf(stderr, "Bad argument for '-o': %s\n", optarg);
1260                 usage();
1261             }
1262                         switch(optarg[0]) {
1263                         case 'o': offset_base = 8; break;
1264                         case 'h': offset_base = 16; break;
1265                         case 'd': offset_base = 10; break;
1266                         }
1267             break;
1268         case 'e':
1269             hdr_ethernet = TRUE;
1270             if (sscanf(optarg, "%lx", &hdr_ethernet_proto) < 1) {
1271                 fprintf(stderr, "Bad argument for '-e': %s\n", optarg);
1272                 usage();
1273             }
1274             break;
1275
1276         case 'i':
1277             hdr_ip = TRUE;
1278             hdr_ip_proto = strtol(optarg, &p, 10);
1279             if (p == optarg || *p != '\0' || hdr_ip_proto < 0 ||
1280                   hdr_ip_proto > 255) {
1281                 fprintf(stderr, "Bad argument for '-i': %s\n", optarg);
1282                 usage();
1283             }
1284             hdr_ethernet = TRUE;
1285             hdr_ethernet_proto = 0x800;
1286             break;
1287
1288         case 's':
1289             hdr_sctp       = TRUE;
1290             hdr_sctp_src   = strtol(optarg, &p, 10);
1291             if (p == optarg || (*p != ',' && *p != '\0')) {
1292                 fprintf(stderr, "Bad src port for '-%c'\n", c);
1293                 usage();
1294             }
1295             if (*p == '\0') {
1296                 fprintf(stderr, "No dest port specified for '-%c'\n", c);
1297                 usage();
1298             }
1299             p++;
1300             optarg = p;
1301             hdr_sctp_dest = strtol(optarg, &p, 10);
1302             if (p == optarg || (*p != ',' && *p != '\0')) {
1303                 fprintf(stderr, "Bad dest port for '-s'\n");
1304                 usage();
1305             }
1306             if (*p == '\0') {
1307                 fprintf(stderr, "No tag specified for '-%c'\n", c);
1308                 usage();
1309             }
1310             p++;
1311             optarg = p;
1312             hdr_sctp_tag = strtol(optarg, &p, 10);
1313             if (p == optarg || *p != '\0') {
1314                 fprintf(stderr, "Bad tag for '-%c'\n", c);
1315                 usage();
1316             }
1317
1318             hdr_ip = TRUE;
1319             hdr_ip_proto = 132;
1320             hdr_ethernet = TRUE;
1321             hdr_ethernet_proto = 0x800;
1322             break;
1323         case 'S':
1324             hdr_sctp       = TRUE;
1325             hdr_data_chunk = TRUE;
1326             hdr_sctp_src   = strtol(optarg, &p, 10);
1327             if (p == optarg || (*p != ',' && *p != '\0')) {
1328                 fprintf(stderr, "Bad src port for '-%c'\n", c);
1329                 usage();
1330             }
1331             if (*p == '\0') {
1332                 fprintf(stderr, "No dest port specified for '-%c'\n", c);
1333                 usage();
1334             }
1335             p++;
1336             optarg = p;
1337             hdr_sctp_dest = strtol(optarg, &p, 10);
1338             if (p == optarg || (*p != ',' && *p != '\0')) {
1339                 fprintf(stderr, "Bad dest port for '-s'\n");
1340                 usage();
1341             }
1342             if (*p == '\0') {
1343                 fprintf(stderr, "No ppi specified for '-%c'\n", c);
1344                 usage();
1345             }
1346             p++;
1347             optarg = p;
1348             hdr_data_chunk_ppid = strtoul(optarg, &p, 10);
1349             if (p == optarg || *p != '\0') {
1350                 fprintf(stderr, "Bad ppi for '-%c'\n", c);
1351                 usage();
1352             }
1353
1354             hdr_ip = TRUE;
1355             hdr_ip_proto = 132;
1356             hdr_ethernet = TRUE;
1357             hdr_ethernet_proto = 0x800;
1358             break;
1359
1360         case 't':
1361             ts_fmt = optarg;
1362             break;
1363
1364         case 'u':
1365             hdr_udp = TRUE;
1366             hdr_tcp = FALSE;
1367             hdr_src_port = strtol(optarg, &p, 10);
1368             if (p == optarg || (*p != ',' && *p != '\0')) {
1369                 fprintf(stderr, "Bad src port for '-u'\n");
1370                 usage();
1371             }
1372             if (*p == '\0') {
1373                 fprintf(stderr, "No dest port specified for '-u'\n");
1374                 usage();
1375             }
1376             p++;
1377             optarg = p;
1378             hdr_dest_port = strtol(optarg, &p, 10);
1379             if (p == optarg || *p != '\0') {
1380                 fprintf(stderr, "Bad dest port for '-u'\n");
1381                 usage();
1382             }
1383             hdr_ip = TRUE;
1384             hdr_ip_proto = 17;
1385             hdr_ethernet = TRUE;
1386             hdr_ethernet_proto = 0x800;
1387             break;
1388
1389         case 'T':
1390             hdr_tcp = TRUE;
1391             hdr_udp = FALSE;
1392             hdr_src_port = strtol(optarg, &p, 10);
1393             if (p == optarg || (*p != ',' && *p != '\0')) {
1394                 fprintf(stderr, "Bad src port for '-T'\n");
1395                 usage();
1396             }
1397             if (*p == '\0') {
1398                 fprintf(stderr, "No dest port specified for '-u'\n");
1399                 usage();
1400             }
1401             p++;
1402             optarg = p;
1403             hdr_dest_port = strtol(optarg, &p, 10);
1404             if (p == optarg || *p != '\0') {
1405                 fprintf(stderr, "Bad dest port for '-T'\n");
1406                 usage();
1407             }
1408             hdr_ip = TRUE;
1409             hdr_ip_proto = 6;
1410             hdr_ethernet = TRUE;
1411             hdr_ethernet_proto = 0x800;
1412             break;
1413
1414         case 'a':
1415             identify_ascii = TRUE;
1416                         break;
1417
1418         default:
1419             usage();
1420         }
1421     }
1422
1423     if (optind >= argc || argc-optind < 2) {
1424         fprintf(stderr, "Must specify input and output filename\n");
1425         usage();
1426     }
1427
1428     if (strcmp(argv[optind], "-")) {
1429         input_filename = g_strdup(argv[optind]);
1430         input_file = ws_fopen(input_filename, "rb");
1431         if (!input_file) {
1432             fprintf(stderr, "Cannot open file [%s] for reading: %s\n",
1433                     input_filename, g_strerror(errno));
1434             exit(-1);
1435         }
1436     } else {
1437         input_filename = "Standard input";
1438         input_file = stdin;
1439     }
1440
1441     if (strcmp(argv[optind+1], "-")) {
1442         output_filename = g_strdup(argv[optind+1]);
1443         output_file = ws_fopen(output_filename, "wb");
1444         if (!output_file) {
1445             fprintf(stderr, "Cannot open file [%s] for writing: %s\n",
1446                     output_filename, g_strerror(errno));
1447             exit(-1);
1448         }
1449     } else {
1450         output_filename = "Standard output";
1451         output_file = stdout;
1452     }
1453
1454     /* Some validation */
1455     if (pcap_link_type != 1 && hdr_ethernet) {
1456         fprintf(stderr, "Dummy headers (-e, -i, -u, -s, -S -T) cannot be specified with link type override (-l)\n");
1457         exit(-1);
1458     }
1459
1460     /* Set up our variables */
1461     if (!input_file) {
1462         input_file = stdin;
1463         input_filename = "Standard input";
1464     }
1465     if (!output_file) {
1466         output_file = stdout;
1467         output_filename = "Standard output";
1468     }
1469
1470     ts_sec = time(0);           /* initialize to current time */
1471     timecode_default = *localtime(&ts_sec);
1472     timecode_default.tm_isdst = -1;     /* Unknown for now, depends on time given to the strptime() function */
1473
1474     /* Display summary of our state */
1475     if (!quiet) {
1476         fprintf(stderr, "Input from: %s\n", input_filename);
1477         fprintf(stderr, "Output to: %s\n", output_filename);
1478
1479         if (hdr_ethernet) fprintf(stderr, "Generate dummy Ethernet header: Protocol: 0x%0lX\n",
1480                                   hdr_ethernet_proto);
1481         if (hdr_ip) fprintf(stderr, "Generate dummy IP header: Protocol: %ld\n",
1482                             hdr_ip_proto);
1483         if (hdr_udp) fprintf(stderr, "Generate dummy UDP header: Source port: %ld. Dest port: %ld\n",
1484                              hdr_src_port, hdr_dest_port);
1485         if (hdr_tcp) fprintf(stderr, "Generate dummy TCP header: Source port: %ld. Dest port: %ld\n",
1486                              hdr_src_port, hdr_dest_port);
1487         if (hdr_sctp) fprintf(stderr, "Generate dummy SCTP header: Source port: %ld. Dest port: %ld. Tag: %ld\n",
1488                               hdr_sctp_src, hdr_sctp_dest, hdr_sctp_tag);
1489         if (hdr_data_chunk) fprintf(stderr, "Generate dummy DATA chunk header: TSN: %lu. SID: %d. SSN: %d. PPID: %lu\n",
1490                                     hdr_data_chunk_tsn, hdr_data_chunk_sid, hdr_data_chunk_ssn, hdr_data_chunk_ppid);
1491     }
1492 }
1493
1494 int
1495 main(int argc, char *argv[])
1496 {
1497     parse_options(argc, argv);
1498
1499     assert(input_file != NULL);
1500     assert(output_file != NULL);
1501
1502     write_file_header();
1503
1504     yyin = input_file;
1505     yylex();
1506
1507     write_current_packet();
1508     fclose(input_file);
1509     fclose(output_file);
1510     if (debug)
1511         fprintf(stderr, "\n-------------------------\n");
1512     if (!quiet) {
1513     fprintf(stderr, "Read %ld potential packet%s, wrote %ld packet%s\n",
1514             num_packets_read,    (num_packets_read==1)   ?"":"s",
1515             num_packets_written, (num_packets_written==1)?"":"s");
1516     }
1517     return 0;
1518 }