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