1 /**-*-C-*-**********************************************************************
5 * Utility to convert an ASCII hexdump into a libpcap-format capture file
7 * (c) Copyright 2001 Ashok Narayanan <ashokn@cisco.com>
9 * $Id: text2pcap.c,v 1.24 2002/10/17 20:02:00 guy Exp $
11 * Ethereal - Network traffic analyzer
12 * By Gerald Combs <gerald@ethereal.com>
13 * Copyright 1998 Gerald Combs
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.
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.
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.
29 *******************************************************************************/
31 /*******************************************************************************
33 * This utility reads in an ASCII hexdump of this common format:
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......
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:
47 * - No text appears between the offset and the bytes (any bytes appearing after
48 * such text would be ignored)
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
54 * A packet start is signalled by a zero offset.
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.
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.
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.
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.
76 * This converter cannot read a single packet greater than 64K. Packet
77 * snaplength is automatically set to 64K.
90 * Just make sure we include the prototype for strptime as well
91 * (needed for glibc 2.2)
109 #ifdef NEED_STRPTIME_H
110 # include "strptime.h"
113 #include "text2pcap.h"
115 /*--- Options --------------------------------------------------------------------*/
118 static int debug = 0;
120 static int quiet = FALSE;
122 /* Dummy Ethernet header */
123 static int hdr_ethernet = FALSE;
124 static unsigned long hdr_ethernet_proto = 0;
126 /* Dummy IP header */
127 static int hdr_ip = FALSE;
128 static unsigned long hdr_ip_proto = 0;
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;
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;
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;
151 /*--- Local date -----------------------------------------------------------------*/
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;
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;
163 /* Number of packets read and written */
164 static unsigned long num_packets_read = 0;
165 static unsigned long num_packets_written = 0;
167 /* Time code of packet, derived from packet_preamble */
168 static gint32 ts_sec = 0;
169 static guint32 ts_usec = 0;
170 static char *ts_fmt = NULL;
173 static char *input_filename;
174 static FILE *input_file = NULL;
176 static char *output_filename;
177 static FILE *output_file = NULL;
179 /* Offset base to parse */
180 static unsigned long offset_base = 16;
184 /* ----- State machine -----------------------------------------------------------*/
186 /* Current state of parser */
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 */
194 static parser_state_t state = INIT;
196 static const char *state_str[] = {"Init",
203 static const char *token_str[] = {"",
211 /* ----- Skeleton Packet Headers --------------------------------------------------*/
219 static hdr_ethernet_t HDR_ETHERNET = {
220 {0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
221 {0x02, 0x02, 0x02, 0x02, 0x02, 0x02},
227 guint16 packet_length;
228 guint16 identification;
233 guint16 hdr_checksum;
238 static hdr_ip_t HDR_IP = {0x45, 0, 0, 0x3412, 0, 0, 0xff, 0, 0, 0x01010101, 0x02020202};
247 static hdr_udp_t HDR_UDP = {0, 0, 0, 0};
256 static hdr_sctp_t HDR_SCTP = {0, 0, 0, 0};
268 static hdr_data_chunk_t HDR_DATA_CHUNK = {0, 0, 0, 0, 0, 0, 0};
270 static char tempbuf[64];
272 /*----------------------------------------------------------------------
273 * Stuff for writing a PCap file
275 #define PCAP_MAGIC 0xa1b2c3d4
277 /* "libpcap" file header (minus magic number). */
279 guint32 magic; /* magic */
280 guint16 version_major; /* major version number */
281 guint16 version_minor; /* minor version number */
282 guint32 thiszone; /* GMT to local correction */
283 guint32 sigfigs; /* accuracy of timestamps */
284 guint32 snaplen; /* max length of captured packets, in octets */
285 guint32 network; /* data link type */
288 /* "libpcap" record header. */
290 gint32 ts_sec; /* timestamp seconds */
291 guint32 ts_usec; /* timestamp microseconds */
292 guint32 incl_len; /* number of octets of packet saved in file */
293 guint32 orig_len; /* actual length of packet */
296 /* Link-layer type; see net/bpf.h for details */
297 static unsigned long pcap_link_type = 1; /* Default is DLT-EN10MB */
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
305 parse_num (char *str, int offset)
310 num = strtoul(str, &c, offset ? offset_base : 16);
312 fprintf(stderr, "FATAL ERROR: Bad hex number? [%s]\n", str);
318 /*----------------------------------------------------------------------
319 * Write this byte into current packet
322 write_byte (char *str)
326 num = parse_num(str, FALSE);
327 packet_buf[curr_offset] = num;
331 /*----------------------------------------------------------------------
332 * Remove bytes from the current packet
335 unwrite_bytes (unsigned long nbytes)
337 curr_offset -= nbytes;
340 /*----------------------------------------------------------------------
341 * Compute one's complement checksum (from RFC1071)
344 in_checksum (void *buf, unsigned long count)
346 unsigned long sum = 0;
350 /* This is the inner loop */
351 sum += g_ntohs(* (guint16 *) addr);
356 /* Add left-over byte, if any */
358 sum += * (guint8 *) addr;
360 /* Fold 32-bit sum to 16 bits */
362 sum = (sum & 0xffff) + (sum >> 16);
364 return g_htons(~sum);
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.
371 #define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF])
372 static guint32 crc_c[256] =
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,
441 crc32c(const guint8* buf, unsigned int len, guint32 crc32_init)
447 for (i = 0; i < len; i++)
448 CRC32C(crc32, buf[i]);
454 finalize_crc32c(guint32 crc32)
457 guint8 byte0,byte1,byte2,byte3;
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);
469 number_of_padding_bytes (unsigned long length)
471 unsigned long remainder;
473 remainder = length % 4;
478 return 4 - remainder;
481 /*----------------------------------------------------------------------
482 * Write current packet out
485 write_current_packet (void)
490 int eth_trailer_length = 0;
491 int i, padding_length;
492 struct pcaprec_hdr ph;
494 if (curr_offset > 0) {
495 /* Write the packet */
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; }
504 length += sizeof(HDR_ETHERNET);
507 eth_trailer_length = 60 - length;
512 /* Write PCap header */
514 ph.ts_usec = ts_usec;
515 ph.incl_len = length;
516 ph.orig_len = length;
517 fwrite(&ph, sizeof(ph), 1, output_file);
519 /* Write Ethernet header */
521 HDR_ETHERNET.l3pid = g_htons(hdr_ethernet_proto);
522 fwrite(&HDR_ETHERNET, sizeof(HDR_ETHERNET), 1, output_file);
525 /* Write IP header */
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);
534 /* Write UDP header */
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);
540 fwrite(&HDR_UDP, sizeof(HDR_UDP), 1, output_file);
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);
553 padding_length = number_of_padding_bytes(curr_offset);
554 for (i=0; i<padding_length; i++)
558 /* Write SCTP header */
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((guint8 *)&HDR_SCTP, sizeof(HDR_SCTP), ~0L);
566 HDR_SCTP.checksum = crc32c((guint8 *)&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)));
569 fwrite(&HDR_SCTP, sizeof(HDR_SCTP), 1, output_file);
572 /* Write DATA chunk header */
573 if (hdr_data_chunk) {
574 fwrite(&HDR_DATA_CHUNK, sizeof(HDR_DATA_CHUNK), 1, output_file);
577 fwrite(packet_buf, curr_offset, 1, output_file);
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);
586 fprintf(stderr, "Wrote packet of %lu bytes\n", curr_offset);
587 num_packets_written ++;
592 /*----------------------------------------------------------------------
593 * Write the PCap file header
596 write_file_header (void)
600 fh.magic = PCAP_MAGIC;
601 fh.version_major = 2;
602 fh.version_minor = 4;
606 fh.network = pcap_link_type;
608 fwrite(&fh, sizeof(fh), 1, output_file);
611 /*----------------------------------------------------------------------
612 * Append a token to the packet preamble.
615 append_to_preamble(char *str)
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++] = ' ';
625 toklen = strlen(str);
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;
634 /*----------------------------------------------------------------------
635 * Parse the preamble to get the timecode.
638 parse_preamble (void)
647 * If no "-t" flag was specified, don't attempt to parse a packet
648 * preamble to extract a time stamp.
657 * Null-terminate the preamble.
659 packet_preamble[packet_preamble_len] = '\0';
661 /* Ensure preamble has more than two chars before atempting to parse.
662 * This should cover line breaks etc that get counted.
664 if ( strlen(packet_preamble) > 2 ) {
666 * Initialize to the Epoch, just in case not all fields
667 * of the date and time are specified.
671 timecode.tm_hour = 0;
672 timecode.tm_mday = 1;
674 timecode.tm_year = 70;
675 timecode.tm_wday = 0;
676 timecode.tm_yday = 0;
677 timecode.tm_isdst = -1;
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 = (gint32)mktime( &timecode );
685 ts_sec = -1; /* we failed to parse it */
687 /* This will ensure incorrectly parsed dates get set to zero */
695 /* Parse subseconds */
696 ts_usec = strtol(subsecs, &p, 10);
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
709 subseclen = p - subsecs;
712 * *More* than 6 digits; 6-N is
713 * negative, so we divide by
716 for (i = subseclen - 6; i != 0; i--)
718 } else if (subseclen < 6) {
719 for (i = 6 - subseclen; i != 0; i--)
727 /*printf("Format(%s), time(%u), subsecs(%u)\n\n", ts_fmt, ts_sec, ts_usec);*/
730 packet_preamble_len = 0;
733 /*----------------------------------------------------------------------
737 start_new_packet (void)
740 fprintf(stderr, "Start new packet\n");
742 /* Write out the current packet, if required */
743 write_current_packet();
747 /* Ensure we parse the packet preamble as it may contain the time */
751 /*----------------------------------------------------------------------
752 * Process a directive
755 process_directive (char *str)
757 fprintf(stderr, "\n--- Directive [%s] currently unsupported ---\n", str+10);
761 /*----------------------------------------------------------------------
762 * Parse a single token (called from the scanner)
765 parse_token (token_t token, char *str)
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.
776 /* Sanitize - remove all '\r' */
778 if (str!=NULL) { while ((c = strchr(str, '\r')) != NULL) *c=' '; }
780 fprintf(stderr, "(%s, %s \"%s\") -> (",
781 state_str[state], token_str[token], str ? str : "");
786 /* ----- Waiting for new packet -------------------------------------------*/
790 append_to_preamble(str);
793 process_directive(str);
796 num = parse_num(str, TRUE);
798 /* New packet starts here */
808 /* ----- Processing packet, start of new line -----------------------------*/
812 append_to_preamble(str);
815 process_directive(str);
818 num = parse_num(str, TRUE);
820 /* New packet starts here */
823 } else if (num != curr_offset) {
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
833 if (num < curr_offset) {
834 unwrite_bytes(curr_offset - num);
837 /* Bad offset; switch to INIT state */
839 fprintf(stderr, "Inconsistent offset. Expecting %0lX, got %0lX. Ignoring rest of packet\n",
841 write_current_packet();
852 /* ----- Processing packet, read offset -----------------------------------*/
856 /* Record the byte */
866 state = START_OF_LINE;
873 /* ----- Processing packet, read byte -------------------------------------*/
877 /* Record the byte */
886 state = START_OF_LINE;
893 /* ----- Processing packet, read text -------------------------------------*/
897 state = START_OF_LINE;
905 fprintf(stderr, "FATAL ERROR: Bad state (%d)", state);
910 fprintf(stderr, ", %s)\n", state_str[state]);
914 /*----------------------------------------------------------------------
915 * Print helpstring and exit
918 help (char *progname)
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"
926 "where <input-filename> specifies input filename (use - for standard input)\n"
927 " <output-filename> specifies output filename (use - for standard output)\n"
929 "[options] are one or more of the following \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"
939 " Example: -e 0x800\n"
940 " -i proto : Prepend dummy IP header with specified IP protocol (in\n"
942 " Automatically prepends Ethernet header as well.\n"
944 " -u srcp,destp : Prepend dummy UDP header with specified dest and source ports\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"
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"
970 /*----------------------------------------------------------------------
974 parse_options (int argc, char *argv[])
979 /* Scan CLI parameters */
980 while ((c = getopt(argc, argv, "dhqe:i:l:o:u:s:S:t:")) != -1) {
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;
988 if (optarg[0]!='h' && optarg[0] != 'o') {
989 fprintf(stderr, "Bad argument for '-e': %s\n", optarg);
992 offset_base = (optarg[0]=='o') ? 8 : 16;
996 if (sscanf(optarg, "%lx", &hdr_ethernet_proto) < 1) {
997 fprintf(stderr, "Bad argument for '-e': %s\n", optarg);
1004 if (sscanf(optarg, "%ld", &hdr_ip_proto) < 1) {
1005 fprintf(stderr, "Bad argument for '-i': %s\n", optarg);
1008 hdr_ethernet = TRUE;
1009 hdr_ethernet_proto = 0x800;
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);
1020 fprintf(stderr, "No dest port specified for '-%c'\n", c);
1025 hdr_sctp_dest = strtol(optarg, &p, 10);
1026 if (p == optarg || (*p != ',' && *p != '\0')) {
1027 fprintf(stderr, "Bad dest port for '-s'\n");
1031 fprintf(stderr, "No tag specified for '-%c'\n", c);
1036 hdr_sctp_tag = strtol(optarg, &p, 10);
1037 if (p == optarg || *p != '\0') {
1038 fprintf(stderr, "Bad tag for '-%c'\n", c);
1044 hdr_ethernet = TRUE;
1045 hdr_ethernet_proto = 0x800;
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);
1056 fprintf(stderr, "No dest port specified for '-%c'\n", c);
1061 hdr_sctp_dest = strtol(optarg, &p, 10);
1062 if (p == optarg || (*p != ',' && *p != '\0')) {
1063 fprintf(stderr, "Bad dest port for '-s'\n");
1066 fprintf(stderr, "No ppi specified for '-%c'\n", c);
1071 hdr_data_chunk_ppid = strtoul(optarg, &p, 10);
1072 if (p == optarg || *p != '\0') {
1073 fprintf(stderr, "Bad ppi for '-%c'\n", c);
1079 hdr_ethernet = TRUE;
1080 hdr_ethernet_proto = 0x800;
1089 hdr_udp_src = strtol(optarg, &p, 10);
1090 if (p == optarg || (*p != ',' && *p != '\0')) {
1091 fprintf(stderr, "Bad src port for '-u'\n");
1095 fprintf(stderr, "No dest port specified for '-u'\n");
1100 hdr_udp_dest = strtol(optarg, &p, 10);
1101 if (p == optarg || *p != '\0') {
1102 fprintf(stderr, "Bad dest port for '-u'\n");
1107 hdr_ethernet = TRUE;
1108 hdr_ethernet_proto = 0x800;
1116 if (optind >= argc || argc-optind < 2) {
1117 fprintf(stderr, "Must specify input and output filename\n");
1121 if (strcmp(argv[optind], "-")) {
1122 input_filename = strdup(argv[optind]);
1123 input_file = fopen(input_filename, "rb");
1125 fprintf(stderr, "Cannot open file [%s] for reading: %s\n",
1126 input_filename, strerror(errno));
1130 input_filename = "Standard input";
1134 if (strcmp(argv[optind+1], "-")) {
1135 output_filename = strdup(argv[optind+1]);
1136 output_file = fopen(output_filename, "wb");
1138 fprintf(stderr, "Cannot open file [%s] for writing: %s\n",
1139 output_filename, strerror(errno));
1143 output_filename = "Standard output";
1144 output_file = stdout;
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");
1153 /* Set up our variables */
1156 input_filename = "Standard input";
1159 output_file = stdout;
1160 output_filename = "Standard output";
1163 /* Display summary of our state */
1165 fprintf(stderr, "Input from: %s\n", input_filename);
1166 fprintf(stderr, "Output to: %s\n", output_filename);
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",
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);
1181 int main(int argc, char *argv[])
1183 parse_options(argc, argv);
1185 assert(input_file != NULL);
1186 assert(output_file != NULL);
1188 write_file_header();
1193 write_current_packet();
1195 fprintf(stderr, "\n-------------------------\n");
1197 fprintf(stderr, "Read %ld potential packets, wrote %ld packets\n",
1198 num_packets_read, num_packets_written);