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