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