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