'-Wno-error=unused-but-set-parameter' not req'd since no such warnings in Wireshark...
[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 #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 <wsutil/unicode-utils.h>
143 #endif /* _WIN32 */
144
145 /*--- Options --------------------------------------------------------------------*/
146
147 /* Debug level */
148 static int debug = 0;
149 /* Be quiet */
150 static int quiet = FALSE;
151
152 /* Dummy Ethernet header */
153 static int hdr_ethernet = FALSE;
154 static unsigned long hdr_ethernet_proto = 0;
155
156 /* Dummy IP header */
157 static int hdr_ip = FALSE;
158 static long hdr_ip_proto = 0;
159
160 /* Dummy UDP header */
161 static int hdr_udp = FALSE;
162 static unsigned long hdr_dest_port = 0;
163 static unsigned long hdr_src_port = 0;
164
165 /* Dummy TCP header */
166 static int hdr_tcp = FALSE;
167
168 /* Dummy SCTP header */
169 static int hdr_sctp = FALSE;
170 static unsigned long hdr_sctp_src  = 0;
171 static unsigned long hdr_sctp_dest = 0;
172 static unsigned long hdr_sctp_tag  = 0;
173
174 /* Dummy DATA chunk header */
175 static int hdr_data_chunk = FALSE;
176 static unsigned char  hdr_data_chunk_type = 0;
177 static unsigned char  hdr_data_chunk_bits = 3;
178 static unsigned long  hdr_data_chunk_tsn  = 0;
179 static unsigned short hdr_data_chunk_sid  = 0;
180 static unsigned short hdr_data_chunk_ssn  = 0;
181 static unsigned long  hdr_data_chunk_ppid = 0;
182
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 /* Input file */
210 static const char *input_filename;
211 static FILE *input_file = NULL;
212 /* Output file */
213 static const char *output_filename;
214 static FILE *output_file = NULL;
215
216 /* Offset base to parse */
217 static unsigned long offset_base = 16;
218
219 extern FILE *yyin;
220
221 /* ----- State machine -----------------------------------------------------------*/
222
223 /* Current state of parser */
224 typedef enum {
225     INIT,             /* Waiting for start of new packet */
226     START_OF_LINE,    /* Starting from beginning of line */
227     READ_OFFSET,      /* Just read the offset */
228     READ_BYTE,        /* Just read a byte */
229     READ_TEXT         /* Just read text - ignore until EOL */
230 } parser_state_t;
231 static parser_state_t state = INIT;
232
233 static const char *state_str[] = {"Init",
234                            "Start-of-line",
235                            "Offset",
236                            "Byte",
237                            "Text"
238 };
239
240 static const char *token_str[] = {"",
241                            "Byte",
242                            "Offset",
243                            "Directive",
244                            "Text",
245                            "End-of-line"
246 };
247
248 /* ----- Skeleton Packet Headers --------------------------------------------------*/
249
250 typedef struct {
251     guint8  dest_addr[6];
252     guint8  src_addr[6];
253     guint16 l3pid;
254 } hdr_ethernet_t;
255
256 static hdr_ethernet_t HDR_ETHERNET = {
257     {0x0a, 0x02, 0x02, 0x02, 0x02, 0x02},
258     {0x0a, 0x01, 0x01, 0x01, 0x01, 0x01},
259     0};
260
261 typedef struct {
262     guint8  ver_hdrlen;
263     guint8  dscp;
264     guint16 packet_length;
265     guint16 identification;
266     guint8  flags;
267     guint8  fragment;
268     guint8  ttl;
269     guint8  protocol;
270     guint16 hdr_checksum;
271     guint32 src_addr;
272     guint32 dest_addr;
273 } hdr_ip_t;
274
275 static hdr_ip_t HDR_IP = {0x45, 0, 0, 0x3412, 0, 0, 0xff, 0, 0, 0x0101010a, 0x0202020a};
276
277 static struct {                 /* pseudo header for checksum calculation */
278         guint32 src_addr;
279         guint32 dest_addr;
280         guint8  zero;
281         guint8  protocol;
282         guint16 length;
283 } pseudoh;
284
285 typedef struct {
286     guint16 source_port;
287     guint16 dest_port;
288     guint16 length;
289     guint16 checksum;
290 } hdr_udp_t;
291
292 static hdr_udp_t HDR_UDP = {0, 0, 0, 0};
293
294 typedef struct {
295     guint16 source_port;
296     guint16 dest_port;
297     guint32 seq_num;
298     guint32 ack_num;
299     guint8  hdr_length;
300     guint8  flags;
301     guint16 window;
302     guint16 checksum;
303     guint16 urg;
304 } hdr_tcp_t;
305
306 static hdr_tcp_t HDR_TCP = {0, 0, 0, 0, 0x50, 0, 0, 0, 0};
307
308 typedef struct {
309     guint16 src_port;
310     guint16 dest_port;
311     guint32 tag;
312     guint32 checksum;
313 } hdr_sctp_t;
314
315 static hdr_sctp_t HDR_SCTP = {0, 0, 0, 0};
316
317 typedef struct {
318     guint8  type;
319     guint8  bits;
320     guint16 length;
321     guint32 tsn;
322     guint16 sid;
323     guint16 ssn;
324     guint32 ppid;
325 } hdr_data_chunk_t;
326
327 static hdr_data_chunk_t HDR_DATA_CHUNK = {0, 0, 0, 0, 0, 0, 0};
328
329 static char tempbuf[64];
330
331 /*----------------------------------------------------------------------
332  * Stuff for writing a PCap file
333  */
334 #define PCAP_MAGIC                      0xa1b2c3d4
335
336 /* "libpcap" file header (minus magic number). */
337 struct pcap_hdr {
338     guint32     magic;          /* magic */
339     guint16     version_major;  /* major version number */
340     guint16     version_minor;  /* minor version number */
341     guint32     thiszone;       /* GMT to local correction */
342     guint32     sigfigs;        /* accuracy of timestamps */
343     guint32     snaplen;        /* max length of captured packets, in octets */
344     guint32     network;        /* data link type */
345 };
346
347 /* "libpcap" record header. */
348 struct pcaprec_hdr {
349     guint32     ts_sec;         /* timestamp seconds */
350     guint32     ts_usec;        /* timestamp microseconds */
351     guint32     incl_len;       /* number of octets of packet saved in file */
352     guint32     orig_len;       /* actual length of packet */
353 };
354
355 /* Link-layer type; see net/bpf.h for details */
356 static unsigned long pcap_link_type = 1;   /* Default is DLT-EN10MB */
357
358 /*----------------------------------------------------------------------
359  * Parse a single hex number
360  * Will abort the program if it can't parse the number
361  * Pass in TRUE if this is an offset, FALSE if not
362  */
363 static unsigned long
364 parse_num (const char *str, int offset)
365 {
366     unsigned long num;
367     char *c;
368
369     num = strtoul(str, &c, offset ? offset_base : 16);
370     if (c==str) {
371         fprintf(stderr, "FATAL ERROR: Bad hex number? [%s]\n", str);
372         exit(-1);
373     }
374     return num;
375 }
376
377 /*----------------------------------------------------------------------
378  * Write this byte into current packet
379  */
380 static void
381 write_byte (const char *str)
382 {
383     unsigned long num;
384
385     num = parse_num(str, FALSE);
386     packet_buf[curr_offset] = (unsigned char) num;
387     curr_offset ++;
388     if (curr_offset >= max_offset) /* packet full */
389             start_new_packet();
390 }
391
392 /*----------------------------------------------------------------------
393  * Remove bytes from the current packet
394  */
395 static void
396 unwrite_bytes (unsigned long nbytes)
397 {
398     curr_offset -= nbytes;
399 }
400
401 /*----------------------------------------------------------------------
402  * Compute one's complement checksum (from RFC1071)
403  */
404 static guint16
405 in_checksum (void *buf, unsigned long count)
406 {
407     unsigned long sum = 0;
408     guint16 *addr = buf;
409
410     while( count > 1 )  {
411         /*  This is the inner loop */
412         sum += g_ntohs(* (guint16 *) addr);
413         addr++;
414         count -= 2;
415     }
416
417     /*  Add left-over byte, if any */
418     if( count > 0 )
419         sum += g_ntohs(* (guint8 *) addr);
420
421     /*  Fold 32-bit sum to 16 bits */
422     while (sum>>16)
423         sum = (sum & 0xffff) + (sum >> 16);
424
425     sum = ~sum;
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             guint16 x16;
609             HDR_UDP.source_port = g_htons(hdr_src_port);
610             HDR_UDP.dest_port = g_htons(hdr_dest_port);
611             HDR_UDP.length = g_htons(proto_length);
612
613             /* Note: g_ntohs()/g_htons() macro arg may be eval'd twice so calc value before invoking macro */
614             HDR_UDP.checksum = 0;
615             x16  = in_checksum(&pseudoh, sizeof(pseudoh));
616             u    = g_ntohs(x16);
617             x16  = in_checksum(&HDR_UDP, sizeof(HDR_UDP));
618             u   += g_ntohs(x16);
619             x16  = in_checksum(packet_buf, curr_offset);
620             u   += g_ntohs(x16);
621             x16  = (u & 0xffff) + (u>>16);
622             HDR_UDP.checksum = g_htons(x16);
623             if (HDR_UDP.checksum == 0) /* differentiate between 'none' and 0 */
624                     HDR_UDP.checksum = g_htons(1);
625
626             fwrite(&HDR_UDP, sizeof(HDR_UDP), 1, output_file);
627         }
628
629         /* Write TCP header */
630         if (hdr_tcp) {
631             guint16 x16;
632             HDR_TCP.source_port = g_htons(hdr_src_port);
633             HDR_TCP.dest_port = g_htons(hdr_dest_port);
634             /* HDR_TCP.seq_num already correct */
635             HDR_TCP.window = g_htons(0x2000);
636
637             /* Note: g_ntohs()/g_htons() macro arg may be eval'd twice so calc value before invoking macro */
638             HDR_TCP.checksum = 0;
639             x16  = in_checksum(&pseudoh, sizeof(pseudoh));
640             u    = g_ntohs(x16);
641             x16  = in_checksum(&HDR_TCP, sizeof(HDR_TCP));
642             u   += g_ntohs(x16);
643             x16  = in_checksum(packet_buf, curr_offset);
644             u   += g_ntohs(x16);
645             x16  = (u & 0xffff) + (u>>16);
646             HDR_TCP.checksum = g_htons(x16);
647             if (HDR_TCP.checksum == 0) /* differentiate between 'none' and 0 */
648                 HDR_TCP.checksum = g_htons(1);
649
650             fwrite(&HDR_TCP, sizeof(HDR_TCP), 1, output_file);
651         }
652
653         /* Compute DATA chunk header and append padding */
654         if (hdr_data_chunk) {
655             HDR_DATA_CHUNK.type   = hdr_data_chunk_type;
656             HDR_DATA_CHUNK.bits   = hdr_data_chunk_bits;
657             HDR_DATA_CHUNK.length = g_htons(curr_offset + sizeof(HDR_DATA_CHUNK));
658             HDR_DATA_CHUNK.tsn    = g_htonl(hdr_data_chunk_tsn);
659             HDR_DATA_CHUNK.sid    = g_htons(hdr_data_chunk_sid);
660             HDR_DATA_CHUNK.ssn    = g_htons(hdr_data_chunk_ssn);
661             HDR_DATA_CHUNK.ppid   = g_htonl(hdr_data_chunk_ppid);
662
663             padding_length = number_of_padding_bytes(curr_offset);
664             for (i=0; i<padding_length; i++)
665               write_byte("0");
666         }
667
668         /* Write SCTP header */
669         if (hdr_sctp) {
670             guint32 x32;
671             HDR_SCTP.src_port  = g_htons(hdr_sctp_src);
672             HDR_SCTP.dest_port = g_htons(hdr_sctp_dest);
673             HDR_SCTP.tag       = g_htonl(hdr_sctp_tag);
674             HDR_SCTP.checksum  = g_htonl(0);
675             HDR_SCTP.checksum  = crc32c((guint8 *)&HDR_SCTP, sizeof(HDR_SCTP), ~0L);
676             if (hdr_data_chunk)
677               HDR_SCTP.checksum  = crc32c((guint8 *)&HDR_DATA_CHUNK, sizeof(HDR_DATA_CHUNK), HDR_SCTP.checksum);
678             /* Note: g_ntohl() macro arg may be eval'd twice so calc value before invoking macro */
679             x32 = finalize_crc32c(crc32c(packet_buf, curr_offset, HDR_SCTP.checksum));
680             HDR_SCTP.checksum  = g_htonl(x32);
681
682             fwrite(&HDR_SCTP, sizeof(HDR_SCTP), 1, output_file);
683         }
684
685         /* Write DATA chunk header */
686         if (hdr_data_chunk) {
687             fwrite(&HDR_DATA_CHUNK, sizeof(HDR_DATA_CHUNK), 1, output_file);
688         }
689         /* Write packet */
690         fwrite(packet_buf, curr_offset, 1, output_file);
691
692         /* Write Ethernet trailer */
693         if (hdr_ethernet && eth_trailer_length > 0) {
694             memset(tempbuf, 0, eth_trailer_length);
695             fwrite(tempbuf, eth_trailer_length, 1, output_file);
696         }
697
698         if (!quiet)
699             fprintf(stderr, "Wrote packet of %lu bytes at %u\n", curr_offset, g_ntohl(HDR_TCP.seq_num));
700         num_packets_written ++;
701     }
702     HDR_TCP.seq_num = g_ntohl(HDR_TCP.seq_num) + curr_offset;
703     HDR_TCP.seq_num = g_htonl(HDR_TCP.seq_num);
704
705     packet_start += curr_offset;
706     curr_offset = 0;
707 }
708
709 /*----------------------------------------------------------------------
710  * Write the PCap file header
711  */
712 static void
713 write_file_header (void)
714 {
715     struct pcap_hdr fh;
716
717     fh.magic = PCAP_MAGIC;
718     fh.version_major = 2;
719     fh.version_minor = 4;
720     fh.thiszone = 0;
721     fh.sigfigs = 0;
722     fh.snaplen = 102400;
723     fh.network = pcap_link_type;
724
725     fwrite(&fh, sizeof(fh), 1, output_file);
726 }
727
728 /*----------------------------------------------------------------------
729  * Append a token to the packet preamble.
730  */
731 static void
732 append_to_preamble(char *str)
733 {
734     size_t toklen;
735
736     if (packet_preamble_len != 0) {
737         if (packet_preamble_len == PACKET_PREAMBLE_MAX_LEN)
738             return;     /* no room to add more preamble */
739         /* Add a blank separator between the previous token and this token. */
740         packet_preamble[packet_preamble_len++] = ' ';
741     }
742     toklen = strlen(str);
743     if (toklen != 0) {
744         if (packet_preamble_len + toklen > PACKET_PREAMBLE_MAX_LEN)
745             return;     /* no room to add the token to the preamble */
746         g_strlcpy(&packet_preamble[packet_preamble_len], str, PACKET_PREAMBLE_MAX_LEN);
747         packet_preamble_len += (int) toklen;
748         if (debug >= 2) {
749                 char *c;
750                 char xs[PACKET_PREAMBLE_MAX_LEN];
751                 g_strlcpy(xs, packet_preamble, PACKET_PREAMBLE_MAX_LEN);
752                 while ((c = strchr(xs, '\r')) != NULL) *c=' ';
753                 fprintf (stderr, "[[append_to_preamble: \"%s\"]]", xs);
754         }
755     }
756 }
757
758 /*----------------------------------------------------------------------
759  * Parse the preamble to get the timecode.
760  */
761
762 static void
763 parse_preamble (void)
764 {
765         struct tm timecode;
766         char *subsecs;
767         char *p;
768         int  subseclen;
769         int  i;
770
771         /*
772          * If no "-t" flag was specified, don't attempt to parse a packet
773          * preamble to extract a time stamp.
774          */
775         if (ts_fmt == NULL)
776             return;
777
778         /*
779          * Initialize to today localtime, just in case not all fields
780          * of the date and time are specified.
781          */
782
783         timecode = timecode_default;
784         ts_usec = 0;
785
786         /*
787          * Null-terminate the preamble.
788          */
789         packet_preamble[packet_preamble_len] = '\0';
790
791         /* Ensure preamble has more than two chars before attempting to parse.
792          * This should cover line breaks etc that get counted.
793          */
794         if ( strlen(packet_preamble) > 2 ) {
795                 /* Get Time leaving subseconds */
796                 subsecs = strptime( packet_preamble, ts_fmt, &timecode );
797                 if (subsecs != NULL) {
798                         /* Get the long time from the tm structure */
799                         /*  (will return -1 if failure)            */
800                         ts_sec  = mktime( &timecode );
801                 } else
802                         ts_sec = -1;    /* we failed to parse it */
803
804                 /* This will ensure incorrectly parsed dates get set to zero */
805                 if ( -1 == ts_sec )
806                 {
807                         /* Sanitize - remove all '\r' */
808                         char *c;
809                         while ((c = strchr(packet_preamble, '\r')) != NULL) *c=' ';
810                         fprintf (stderr, "Failure processing time \"%s\" using time format \"%s\"\n   (defaulting to Jan 1,1970 00:00:00 GMT)\n",
811                                  packet_preamble, ts_fmt);
812                         if (debug >= 2) {
813                                 fprintf(stderr, "timecode: %02d/%02d/%d %02d:%02d:%02d %d\n",
814                                         timecode.tm_mday, timecode.tm_mon, timecode.tm_year,
815                                         timecode.tm_hour, timecode.tm_min, timecode.tm_sec, timecode.tm_isdst);
816                         }
817                         ts_sec  = 0;  /* Jan 1,1970: 00:00 GMT; tshark/wireshark will display date/time as adjusted by timezone */
818                         ts_usec = 0;
819                 }
820                 else
821                 {
822                         /* Parse subseconds */
823                         ts_usec = strtol(subsecs, &p, 10);
824                         if (subsecs == p) {
825                                 /* Error */
826                                 ts_usec = 0;
827                         } else {
828                                 /*
829                                  * Convert that number to a number
830                                  * of microseconds; if it's N digits
831                                  * long, it's in units of 10^(-N) seconds,
832                                  * so, to convert it to units of
833                                  * 10^-6 seconds, we multiply by
834                                  * 10^(6-N).
835                                  */
836                                 subseclen = (int) (p - subsecs);
837                                 if (subseclen > 6) {
838                                         /*
839                                          * *More* than 6 digits; 6-N is
840                                          * negative, so we divide by
841                                          * 10^(N-6).
842                                          */
843                                         for (i = subseclen - 6; i != 0; i--)
844                                                 ts_usec /= 10;
845                                 } else if (subseclen < 6) {
846                                         for (i = 6 - subseclen; i != 0; i--)
847                                                 ts_usec *= 10;
848                                 }
849                         }
850                 }
851         }
852         if (debug >= 2) {
853                 char *c;
854                 while ((c = strchr(packet_preamble, '\r')) != NULL) *c=' ';
855                 fprintf(stderr, "[[parse_preamble: \"%s\"]]\n", packet_preamble);
856                 fprintf(stderr, "Format(%s), time(%u), subsecs(%u)\n", ts_fmt, (guint32)ts_sec, ts_usec);
857         }
858
859
860         /* Clear Preamble */
861         packet_preamble_len = 0;
862 }
863
864 /*----------------------------------------------------------------------
865  * Start a new packet
866  */
867 static void
868 start_new_packet (void)
869 {
870     if (debug>=1)
871         fprintf(stderr, "Start new packet\n");
872
873     /* Write out the current packet, if required */
874     write_current_packet();
875     num_packets_read ++;
876
877     /* Ensure we parse the packet preamble as it may contain the time */
878     parse_preamble();
879 }
880
881 /*----------------------------------------------------------------------
882  * Process a directive
883  */
884 static void
885 process_directive (char *str)
886 {
887     fprintf(stderr, "\n--- Directive [%s] currently unsupported ---\n", str+10);
888
889 }
890
891 /*----------------------------------------------------------------------
892  * Parse a single token (called from the scanner)
893  */
894 void
895 parse_token (token_t token, char *str)
896 {
897     unsigned long num;
898
899     /*
900      * This is implemented as a simple state machine of five states.
901      * State transitions are caused by tokens being received from the
902      * scanner. The code should be self_documenting.
903      */
904
905     if (debug>=2) {
906         /* Sanitize - remove all '\r' */
907         char *c;
908         if (str!=NULL) { while ((c = strchr(str, '\r')) != NULL) *c=' '; }
909
910         fprintf(stderr, "(%s, %s \"%s\") -> (",
911                 state_str[state], token_str[token], str ? str : "");
912     }
913
914     switch(state) {
915
916     /* ----- Waiting for new packet -------------------------------------------*/
917     case INIT:
918         switch(token) {
919         case T_TEXT:
920             append_to_preamble(str);
921             break;
922         case T_DIRECTIVE:
923             process_directive(str);
924             break;
925         case T_OFFSET:
926             num = parse_num(str, TRUE);
927             if (num==0) {
928                 /* New packet starts here */
929                 start_new_packet();
930                 state = READ_OFFSET;
931             }
932             break;
933         default:
934             break;
935         }
936         break;
937
938     /* ----- Processing packet, start of new line -----------------------------*/
939     case START_OF_LINE:
940         switch(token) {
941         case T_TEXT:
942             append_to_preamble(str);
943             break;
944         case T_DIRECTIVE:
945             process_directive(str);
946             break;
947         case T_OFFSET:
948             num = parse_num(str, TRUE);
949             if (num==0) {
950                 /* New packet starts here */
951                 start_new_packet();
952                 packet_start = 0;
953                 state = READ_OFFSET;
954             } else if ((num - packet_start) != curr_offset) {
955                 /*
956                  * The offset we read isn't the one we expected.
957                  * This may only mean that we mistakenly interpreted
958                  * some text as byte values (e.g., if the text dump
959                  * of packet data included a number with spaces around
960                  * it).  If the offset is less than what we expected,
961                  * assume that's the problem, and throw away the putative
962                  * extra byte values.
963                  */
964                 if (num < curr_offset) {
965                     unwrite_bytes(curr_offset - num);
966                     state = READ_OFFSET;
967                 } else {
968                     /* Bad offset; switch to INIT state */
969                     if (debug>=1)
970                         fprintf(stderr, "Inconsistent offset. Expecting %0lX, got %0lX. Ignoring rest of packet\n",
971                                 curr_offset, num);
972                     write_current_packet();
973                     state = INIT;
974                 }
975             } else
976                 state = READ_OFFSET;
977             break;
978         default:
979             break;
980         }
981         break;
982
983     /* ----- Processing packet, read offset -----------------------------------*/
984     case READ_OFFSET:
985         switch(token) {
986         case T_BYTE:
987             /* Record the byte */
988             state = READ_BYTE;
989             write_byte(str);
990             break;
991         case T_TEXT:
992         case T_DIRECTIVE:
993         case T_OFFSET:
994             state = READ_TEXT;
995             break;
996         case T_EOL:
997             state = START_OF_LINE;
998             break;
999         default:
1000             break;
1001         }
1002         break;
1003
1004     /* ----- Processing packet, read byte -------------------------------------*/
1005     case READ_BYTE:
1006         switch(token) {
1007         case T_BYTE:
1008             /* Record the byte */
1009             write_byte(str);
1010             break;
1011         case T_TEXT:
1012         case T_DIRECTIVE:
1013         case T_OFFSET:
1014             state = READ_TEXT;
1015             break;
1016         case T_EOL:
1017             state = START_OF_LINE;
1018             break;
1019         default:
1020             break;
1021         }
1022         break;
1023
1024     /* ----- Processing packet, read text -------------------------------------*/
1025     case READ_TEXT:
1026         switch(token) {
1027         case T_EOL:
1028             state = START_OF_LINE;
1029             break;
1030         default:
1031             break;
1032         }
1033         break;
1034
1035     default:
1036         fprintf(stderr, "FATAL ERROR: Bad state (%d)", state);
1037         exit(-1);
1038     }
1039
1040     if (debug>=2)
1041         fprintf(stderr, ", %s)\n", state_str[state]);
1042
1043 }
1044
1045 /*----------------------------------------------------------------------
1046  * Print usage string and exit
1047  */
1048 static void
1049 usage (void)
1050 {
1051     fprintf(stderr,
1052             "Text2pcap %s"
1053 #ifdef SVNVERSION
1054             " (" SVNVERSION " from " SVNPATH ")"
1055 #endif
1056             "\n"
1057             "Generate a capture file from an ASCII hexdump of packets.\n"
1058             "See http://www.wireshark.org for more information.\n"
1059             "\n"
1060             "Usage: text2pcap [options] <infile> <outfile>\n"
1061             "\n"
1062             "where  <infile> specifies input  filename (use - for standard input)\n"
1063             "      <outfile> specifies output filename (use - for standard output)\n"
1064             "\n"
1065             "Input:\n"
1066             "  -o hex|oct|dec         parse offsets as (h)ex, (o)ctal or (d)ecimal;\n"
1067             "                         default is hex.\n"
1068             "  -t <timefmt>           treat the text before the packet as a date/time code;\n"
1069             "                         the specified argument is a format string of the sort\n"
1070             "                         supported by strptime.\n"
1071             "                         Example: The time \"10:15:14.5476\" has the format code\n"
1072             "                         \"%%H:%%M:%%S.\"\n"
1073             "                         NOTE: The subsecond component delimiter, '.', must be\n"
1074             "                         given, but no pattern is required; the remaining\n"
1075             "                         number is assumed to be fractions of a second.\n"
1076             "                         NOTE: Date/time fields from the current date/time are\n"
1077             "                         used as the default for unspecified fields.\n"
1078             "\n"
1079             "Output:\n"
1080             "  -l <typenum>           link-layer type number; default is 1 (Ethernet).\n"
1081             "                         See the file net/bpf.h for list of numbers.\n"
1082             "                         Use this option if your dump is a complete hex dump\n"
1083             "                         of an encapsulated packet and you wish to specify\n"
1084             "                         the exact type of encapsulation.\n"
1085             "                         Example: -l 7 for ARCNet packets.\n"
1086             "  -m <max-packet>        max packet length in output; default is %d\n"
1087             "\n"
1088             "Prepend dummy header:\n"
1089             "  -e <l3pid>             prepend dummy Ethernet II header with specified L3PID\n"
1090             "                         (in HEX).\n"
1091             "                         Example: -e 0x806 to specify an ARP packet.\n"
1092             "  -i <proto>             prepend dummy IP header with specified IP protocol\n"
1093             "                         (in DECIMAL).\n"
1094             "                         Automatically prepends Ethernet header as well.\n"
1095             "                         Example: -i 46\n"
1096             "  -u <srcp>,<destp>      prepend dummy UDP header with specified\n"
1097             "                         dest and source ports (in DECIMAL).\n"
1098             "                         Automatically prepends Ethernet & IP headers as well.\n"
1099             "                         Example: -u 1000,69 to make the packets look like\n"
1100             "                         TFTP/UDP packets.\n"
1101             "  -T <srcp>,<destp>      prepend dummy TCP header with specified\n"
1102             "                         dest and source ports (in DECIMAL).\n"
1103             "                         Automatically prepends Ethernet & IP headers as well.\n"
1104             "                         Example: -T 50,60\n"
1105             "  -s <srcp>,<dstp>,<tag> prepend dummy SCTP header with specified\n"
1106             "                         dest/source ports and verification tag (in DECIMAL).\n"
1107             "                         Automatically prepends Ethernet & IP headers as well.\n"
1108             "                         Example: -s 30,40,34\n"
1109             "  -S <srcp>,<dstp>,<ppi> prepend dummy SCTP header with specified\n"
1110             "                         dest/source ports and verification tag 0.\n"
1111             "                         Automatically prepends a dummy SCTP DATA\n"
1112             "                         chunk header with payload protocol identifier ppi.\n"
1113             "                         Example: -S 30,40,34\n"
1114             "\n"
1115             "Miscellaneous:\n"
1116             "  -h                     display this help and exit.\n"
1117             "  -d                     show detailed debug of parser states.\n"
1118             "  -q                     generate no output at all (automatically turns off -d).\n"
1119             "",
1120             VERSION, MAX_PACKET);
1121
1122     exit(-1);
1123 }
1124
1125 /*----------------------------------------------------------------------
1126  * Parse CLI options
1127  */
1128 static void
1129 parse_options (int argc, char *argv[])
1130 {
1131     int c;
1132     char *p;
1133
1134 #ifdef _WIN32
1135     arg_list_utf_16to8(argc, argv);
1136 #endif /* _WIN32 */
1137
1138     /* Scan CLI parameters */
1139     while ((c = getopt(argc, argv, "dhqe:i:l:m:o:u:s:S:t:T:")) != -1) {
1140         switch(c) {
1141         case '?': usage(); break;
1142         case 'h': usage(); break;
1143         case 'd': if (!quiet) debug++; break;
1144         case 'q': quiet = TRUE; debug = FALSE; break;
1145         case 'l': pcap_link_type = strtol(optarg, NULL, 0); break;
1146         case 'm': max_offset = strtol(optarg, NULL, 0); break;
1147         case 'o':
1148             if (optarg[0]!='h' && optarg[0] != 'o' && optarg[0] != 'd') {
1149                 fprintf(stderr, "Bad argument for '-o': %s\n", optarg);
1150                 usage();
1151             }
1152                         switch(optarg[0]) {
1153                         case 'o': offset_base = 8; break;
1154                         case 'h': offset_base = 16; break;
1155                         case 'd': offset_base = 10; break;
1156                         }
1157             break;
1158         case 'e':
1159             hdr_ethernet = TRUE;
1160             if (sscanf(optarg, "%lx", &hdr_ethernet_proto) < 1) {
1161                 fprintf(stderr, "Bad argument for '-e': %s\n", optarg);
1162                 usage();
1163             }
1164             break;
1165
1166         case 'i':
1167             hdr_ip = TRUE;
1168             hdr_ip_proto = strtol(optarg, &p, 10);
1169             if (p == optarg || *p != '\0' || hdr_ip_proto < 0 ||
1170                   hdr_ip_proto > 255) {
1171                 fprintf(stderr, "Bad argument for '-i': %s\n", optarg);
1172                 usage();
1173             }
1174             hdr_ethernet = TRUE;
1175             hdr_ethernet_proto = 0x800;
1176             break;
1177
1178         case 's':
1179             hdr_sctp       = TRUE;
1180             hdr_sctp_src   = strtol(optarg, &p, 10);
1181             if (p == optarg || (*p != ',' && *p != '\0')) {
1182                 fprintf(stderr, "Bad src port for '-%c'\n", c);
1183                 usage();
1184             }
1185             if (*p == '\0') {
1186                 fprintf(stderr, "No dest port specified for '-%c'\n", c);
1187                 usage();
1188             }
1189             p++;
1190             optarg = p;
1191             hdr_sctp_dest = strtol(optarg, &p, 10);
1192             if (p == optarg || (*p != ',' && *p != '\0')) {
1193                 fprintf(stderr, "Bad dest port for '-s'\n");
1194                 usage();
1195             }
1196             if (*p == '\0') {
1197                 fprintf(stderr, "No tag specified for '-%c'\n", c);
1198                 usage();
1199             }
1200             p++;
1201             optarg = p;
1202             hdr_sctp_tag = strtol(optarg, &p, 10);
1203             if (p == optarg || *p != '\0') {
1204                 fprintf(stderr, "Bad tag for '-%c'\n", c);
1205                 usage();
1206             }
1207
1208             hdr_ip = TRUE;
1209             hdr_ip_proto = 132;
1210             hdr_ethernet = TRUE;
1211             hdr_ethernet_proto = 0x800;
1212             break;
1213         case 'S':
1214             hdr_sctp       = TRUE;
1215             hdr_data_chunk = TRUE;
1216             hdr_sctp_src   = strtol(optarg, &p, 10);
1217             if (p == optarg || (*p != ',' && *p != '\0')) {
1218                 fprintf(stderr, "Bad src port for '-%c'\n", c);
1219                 usage();
1220             }
1221             if (*p == '\0') {
1222                 fprintf(stderr, "No dest port specified for '-%c'\n", c);
1223                 usage();
1224             }
1225             p++;
1226             optarg = p;
1227             hdr_sctp_dest = strtol(optarg, &p, 10);
1228             if (p == optarg || (*p != ',' && *p != '\0')) {
1229                 fprintf(stderr, "Bad dest port for '-s'\n");
1230                 usage();
1231             }
1232             if (*p == '\0') {
1233                 fprintf(stderr, "No ppi specified for '-%c'\n", c);
1234                 usage();
1235             }
1236             p++;
1237             optarg = p;
1238             hdr_data_chunk_ppid = strtoul(optarg, &p, 10);
1239             if (p == optarg || *p != '\0') {
1240                 fprintf(stderr, "Bad ppi for '-%c'\n", c);
1241                 usage();
1242             }
1243
1244             hdr_ip = TRUE;
1245             hdr_ip_proto = 132;
1246             hdr_ethernet = TRUE;
1247             hdr_ethernet_proto = 0x800;
1248             break;
1249
1250         case 't':
1251             ts_fmt = optarg;
1252             break;
1253
1254         case 'u':
1255             hdr_udp = TRUE;
1256             hdr_tcp = FALSE;
1257             hdr_src_port = strtol(optarg, &p, 10);
1258             if (p == optarg || (*p != ',' && *p != '\0')) {
1259                 fprintf(stderr, "Bad src port for '-u'\n");
1260                 usage();
1261             }
1262             if (*p == '\0') {
1263                 fprintf(stderr, "No dest port specified for '-u'\n");
1264                 usage();
1265             }
1266             p++;
1267             optarg = p;
1268             hdr_dest_port = strtol(optarg, &p, 10);
1269             if (p == optarg || *p != '\0') {
1270                 fprintf(stderr, "Bad dest port for '-u'\n");
1271                 usage();
1272             }
1273             hdr_ip = TRUE;
1274             hdr_ip_proto = 17;
1275             hdr_ethernet = TRUE;
1276             hdr_ethernet_proto = 0x800;
1277             break;
1278
1279         case 'T':
1280             hdr_tcp = TRUE;
1281             hdr_udp = FALSE;
1282             hdr_src_port = strtol(optarg, &p, 10);
1283             if (p == optarg || (*p != ',' && *p != '\0')) {
1284                 fprintf(stderr, "Bad src port for '-T'\n");
1285                 usage();
1286             }
1287             if (*p == '\0') {
1288                 fprintf(stderr, "No dest port specified for '-u'\n");
1289                 usage();
1290             }
1291             p++;
1292             optarg = p;
1293             hdr_dest_port = strtol(optarg, &p, 10);
1294             if (p == optarg || *p != '\0') {
1295                 fprintf(stderr, "Bad dest port for '-T'\n");
1296                 usage();
1297             }
1298             hdr_ip = TRUE;
1299             hdr_ip_proto = 6;
1300             hdr_ethernet = TRUE;
1301             hdr_ethernet_proto = 0x800;
1302             break;
1303
1304         default:
1305             usage();
1306         }
1307     }
1308
1309     if (optind >= argc || argc-optind < 2) {
1310         fprintf(stderr, "Must specify input and output filename\n");
1311         usage();
1312     }
1313
1314     if (strcmp(argv[optind], "-")) {
1315         input_filename = g_strdup(argv[optind]);
1316         input_file = ws_fopen(input_filename, "rb");
1317         if (!input_file) {
1318             fprintf(stderr, "Cannot open file [%s] for reading: %s\n",
1319                     input_filename, g_strerror(errno));
1320             exit(-1);
1321         }
1322     } else {
1323         input_filename = "Standard input";
1324         input_file = stdin;
1325     }
1326
1327     if (strcmp(argv[optind+1], "-")) {
1328         output_filename = g_strdup(argv[optind+1]);
1329         output_file = ws_fopen(output_filename, "wb");
1330         if (!output_file) {
1331             fprintf(stderr, "Cannot open file [%s] for writing: %s\n",
1332                     output_filename, g_strerror(errno));
1333             exit(-1);
1334         }
1335     } else {
1336         output_filename = "Standard output";
1337         output_file = stdout;
1338     }
1339
1340     /* Some validation */
1341     if (pcap_link_type != 1 && hdr_ethernet) {
1342         fprintf(stderr, "Dummy headers (-e, -i, -u, -s, -S -T) cannot be specified with link type override (-l)\n");
1343         exit(-1);
1344     }
1345
1346     /* Set up our variables */
1347     if (!input_file) {
1348         input_file = stdin;
1349         input_filename = "Standard input";
1350     }
1351     if (!output_file) {
1352         output_file = stdout;
1353         output_filename = "Standard output";
1354     }
1355
1356     ts_sec = time(0);           /* initialize to current time */
1357     timecode_default = *localtime(&ts_sec);
1358     timecode_default.tm_isdst = -1;     /* Unknown for now, depends on time given to the strptime() function */
1359
1360     /* Display summary of our state */
1361     if (!quiet) {
1362         fprintf(stderr, "Input from: %s\n", input_filename);
1363         fprintf(stderr, "Output to: %s\n", output_filename);
1364
1365         if (hdr_ethernet) fprintf(stderr, "Generate dummy Ethernet header: Protocol: 0x%0lX\n",
1366                                   hdr_ethernet_proto);
1367         if (hdr_ip) fprintf(stderr, "Generate dummy IP header: Protocol: %ld\n",
1368                             hdr_ip_proto);
1369         if (hdr_udp) fprintf(stderr, "Generate dummy UDP header: Source port: %ld. Dest port: %ld\n",
1370                              hdr_src_port, hdr_dest_port);
1371         if (hdr_tcp) fprintf(stderr, "Generate dummy TCP header: Source port: %ld. Dest port: %ld\n",
1372                              hdr_src_port, hdr_dest_port);
1373         if (hdr_sctp) fprintf(stderr, "Generate dummy SCTP header: Source port: %ld. Dest port: %ld. Tag: %ld\n",
1374                               hdr_sctp_src, hdr_sctp_dest, hdr_sctp_tag);
1375         if (hdr_data_chunk) fprintf(stderr, "Generate dummy DATA chunk header: TSN: %lu. SID: %d. SSN: %d. PPID: %lu\n",
1376                                     hdr_data_chunk_tsn, hdr_data_chunk_sid, hdr_data_chunk_ssn, hdr_data_chunk_ppid);
1377     }
1378 }
1379
1380 int
1381 main(int argc, char *argv[])
1382 {
1383     parse_options(argc, argv);
1384
1385     assert(input_file != NULL);
1386     assert(output_file != NULL);
1387
1388     write_file_header();
1389
1390     yyin = input_file;
1391     yylex();
1392
1393     write_current_packet();
1394     if (debug)
1395         fprintf(stderr, "\n-------------------------\n");
1396     if (!quiet) {
1397     fprintf(stderr, "Read %ld potential packet%s, wrote %ld packet%s\n",
1398             num_packets_read,    (num_packets_read==1)   ?"":"s",
1399             num_packets_written, (num_packets_written==1)?"":"s");
1400     }
1401     return 0;
1402 }