diff --git a/Makefile.am b/Makefile.am index cb58be588b..7d04c2c433 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,7 @@ # Makefile.am # Automake file for Ethereal # -# $Id: Makefile.am,v 1.317 2001/05/11 00:39:57 guy Exp $ +# $Id: Makefile.am,v 1.318 2001/05/16 21:32:04 ashokn Exp $ # # Ethereal - Network traffic analyzer # By Gerald Combs @@ -61,11 +61,11 @@ ACLOCAL_AMFLAGS = `./aclocal-flags` # automake will arrange that the Makefile define it as the union of all # the "man{section}_MANS" variables. # -bin_PROGRAMS = @ethereal_bin@ @editcap_bin@ @tethereal_bin@ @dftest_bin@ @randpkt_bin@ +bin_PROGRAMS = @ethereal_bin@ @editcap_bin@ @tethereal_bin@ @dftest_bin@ @randpkt_bin@ @text2pcap_bin@ man1_MANS = @ethereal_man@ @editcap_man@ @tethereal_man@ man_MANS = -EXTRA_PROGRAMS = ethereal ethereal_static tethereal tethereal_static editcap dftest +EXTRA_PROGRAMS = ethereal ethereal_static tethereal tethereal_static editcap dftest text2pcap sysconf_DATA = manuf @@ -519,6 +519,9 @@ tethereal_static_LDADD = wiretap/libwiretap.a \ tethereal_LDFLAGS = -export-dynamic tethereal_static_LDFLAGS = -Wl,-static +text2pcap_SOURCES = text2pcap.c text2pcap-scanner.l +text2pcap_DEPENDENCIES = text2pcap.h + editcap_SOURCES = editcap.c # This is the automake dependency variable for the executable @@ -631,10 +634,14 @@ EXTRA_DIST = \ doc/README.tvbuff \ doc/dfilter2pod.pl \ doc/editcap.pod \ + doc/text2pcap.pod \ doc/ethereal.pod.template \ doc/randpkt.txt \ doc/tethereal.pod.template \ editcap.c \ + text2pcap.c \ + text2pcap.h \ + text2pcap-scanner.l \ getopt.c \ getopt.h \ ieee-float.h \ @@ -711,6 +718,10 @@ editcap.1: doc/editcap.pod (cd doc ; \ $(MAKE) ../editcap.1 ) +text2pcap.1: doc/text2pcap.pod + (cd doc ; \ + $(MAKE) ../text2pcap.1 ) + packet-ncp2222.c : ncp2222.py $(PYTHON) $(srcdir)/ncp2222.py > $@ diff --git a/configure.in b/configure.in index e8bbd406c6..1e41be1bfc 100644 --- a/configure.in +++ b/configure.in @@ -1,4 +1,4 @@ -# $Id: configure.in,v 1.124 2001/05/16 16:17:50 jfoster Exp $ +# $Id: configure.in,v 1.125 2001/05/16 21:32:04 ashokn Exp $ dnl dnl Process this file with autoconf 2.13 or later to produce a dnl configure script; 2.12 doesn't generate a "configure" script that @@ -272,6 +272,22 @@ AC_SUBST(editcap_bin) AC_SUBST(editcap_man) +# Enable/disable text2pcap + +AC_ARG_ENABLE(text2pcap, +[ --enable-text2pcap build text2pcap. [default=yes]],,enable_text2pcap=yes) + +if test "x$enable_text2pcap" = "xyes" ; then + text2pcap_bin="text2pcap" + text2pcap_man="text2pcap.1" +else + text2pcap_bin="" + text2pcap_man="" +fi +AC_SUBST(text2pcap_bin) +AC_SUBST(text2pcap_man) + + # Enable/disable dftest AC_ARG_ENABLE(dftest, @@ -589,6 +605,7 @@ echo "The Ethereal package has been configured with the following options." echo " Build ethereal : $enable_ethereal" echo " Build tethereal : $enable_tethereal" echo " Build editcap : $enable_editcap" +echo " Build text2pcap : $enable_text2pcap" echo " Build randpkt : $enable_randpkt" echo " Build dftest : $enable_dftest" echo "" diff --git a/doc/Makefile.am b/doc/Makefile.am index 7d184702d4..1adc2a04c0 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1,7 +1,7 @@ # Makefile.am # Automake file for Ethereal documentation # -# $Id: Makefile.am,v 1.9 2001/03/06 18:38:47 gram Exp $ +# $Id: Makefile.am,v 1.10 2001/05/16 21:32:05 ashokn Exp $ # # Ethereal - Network traffic analyzer # By Gerald Combs @@ -48,3 +48,9 @@ tethereal.pod: tethereal.pod.template ../tethereal --center="The Ethereal Network Analyzer" \ --release=$(VERSION) \ > ../editcap.1 + +../text2pcap.1: text2pcap.pod ../config.h + pod2man $(srcdir)/text2pcap.pod \ + --center="The Ethereal Network Analyzer" \ + --release=$(VERSION) \ + > ../text2pcap.1 diff --git a/doc/text2pcap.pod b/doc/text2pcap.pod new file mode 100644 index 0000000000..42c88658a3 --- /dev/null +++ b/doc/text2pcap.pod @@ -0,0 +1,141 @@ + +=head1 NAME + +Text2pcap - Generate a capture file from an ASCII hexdump of packets + +=head1 SYNOPSYS + +B +S<[ B<-d> ]> +S<[ B<-q> ]> +S<[ B<-o> hex|oct ]> +S<[ B<-l> typenum ]> +S<[ B<-e> l3pid ]> +S<[ B<-i> proto]> +S<[ B<-u> srcport destport]> +I +I + +=head1 DESCRIPTION + +B is a program that reads in an ASCII hex dump and writes +the data described into a B-style capture file. B +can read hexdumps with multiple packets in them, and build a capture +file of multiple packets. B is also capable of generating +dummy Ethernet, IP and UDP headers, in order to build fully +processable packet dumps from hexdumps of application-level data +only. + +B understands a hexdump of the form generated by I. In other words, each byte is individually displayed and +surrounded with a space. Each line begins with an offset describing +the position in the file. The offset is a hex number (can also be +octal - see B<-o>), of more than two hex digits. Here is a sample dump +that B can recognize: + + 000000 00 e0 1e a7 05 6f 00 10 ........ + 000008 5a a0 b9 12 08 00 46 00 ........ + 000010 03 68 00 00 00 00 0a 2e ........ + 000018 ee 33 0f 19 08 7f 0f 19 ........ + 000020 03 80 94 04 00 00 10 01 ........ + 000028 16 a2 0a 00 03 50 00 0c ........ + 000030 01 01 0f 19 03 80 11 01 ........ + +There is no limit on the width or number of bytes per line. Also the +text dump at the end of the line is ignored. Bytes/hex numbers can be +uppercase or lowercase. Any text before the offset is ignored, +including email forwarding characters '>'. Any lines of text between +the bytestring lines is ignored. The offsets are used to track the +bytes, so offsets must be correct. Any line which has only bytes +without a leading offset is ignored. An offset is recognized as being +a hex number longer than two characters. Any text after the bytes is +ignored (e.g. the character dump). Any hex numbers in this text are +also ignored. An offset of zero is indicative of starting a new +packet, so a single text file with a series of hexdumps can be +converted into a packet capture with multiple packets. Multiple +packets are read in with timestamps differing by one second each. In +general, short of these restrictions, B is pretty liberal +about reading in hexdumps and has been tested with a variety of +mangled outputs (including being forwarded through email multiple +times, with limited line wrap etc.) + +There are a couple of other special features to note. Any line where +the first non-whitespace character is '#' will be ignored as a +comment. Any line beginning with #TEXT2PCAP is a directive and options +can be inserted after this command to be processed by +B. Currently there are no directives implemented; in the +future, these may be used to give more fine grained control on the +dump and the way it should be processed e.g. timestamps, encapsulation +type etc. + +B also allows the user to read in dumps of +application-level data, by inserting dummy L2, L3 and L4 headers +before each packet. The user can elect to insert Ethernet headers, +Ethernet and IP, or Ethernet, IP and UDP headers before each +packet. This allows Ethereal or any other full-packet decoder to +handle these dumps. + +=head1 OPTIONS + +=over 4 + +=item -d + +Displays debugging information during the process. Can be used +multiple times to generate more debugging information. + +=item -q + +Be completely quiet during the process. + +=item -o hex|oct + +Specify the radix for the offsets (hex or octal). Defaults to +hex. This corresponds to the C<-A> option for I. + +=item -l + +Specify the link-layer type of this packet. Default is Ethernet +(1). See I for the complete list of possible +encapsulations. Note that this option should be used if your dump is a +complete hex dump of an encapsulated packet and you wish to specify +the exact type of encapsulation. Example: I<-l 7> for ARCNet packets. + +=item -e l3pid + +Include a dummy Ethernet header before each packet. Specify the L3PID +for the Ethernet header in hex. Use this option if your dump is an IP +packet with IP header and payload, but no Layer 2 +encapsulation. Example: I<-e 0x806> to specify an ARP packet. + +=item -i proto + +Include dummy IP headers before each packet. Specify the IP protocol +for the packet in decimal. Use this option if your dump is the payload +of an IP packet (i.e. has complete L4 information) but does not have +an IP header. Note that this automatically includes an appropriate +Ethernet header as well. Example: I<-i 46> to specify an RSVP packet +(IP protocol 46). + +=item -u srcport destport + +Include dummy UDP headers before each packet. Specify the source and +destination UDP ports for the packet in decimal. Use this option if +your dump is the UDP payload of a packet but does not include any UDP, +IP or Ethernet headers. Note that this automatically includes +appropriate Ethernet and IP headers with each packet. Example: I<-u +1000 69> to make the packets look like TFTP/UDP packets. + + +=head1 SEE ALSO + +L, L, L, L + +=head1 NOTES + +B is part of the B distribution. The latest version +of B can be found at B. + +=head1 AUTHORS + + Ashok Narayanan diff --git a/print.c b/print.c index 46029cf21e..42792faa4f 100644 --- a/print.c +++ b/print.c @@ -1,7 +1,7 @@ /* print.c * Routines for printing packet analysis trees. * - * $Id: print.c,v 1.32 2001/03/24 23:49:14 guy Exp $ + * $Id: print.c,v 1.33 2001/05/16 21:32:04 ashokn Exp $ * * Gilbert Ramirez * @@ -223,7 +223,7 @@ void print_hex_data_text(FILE *fh, register const u_char *cp, { register int ad, i, j, k; u_char c; - u_char line[60]; + u_char line[80]; static u_char binhex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; @@ -234,13 +234,13 @@ void print_hex_data_text(FILE *fh, register const u_char *cp, c = *cp++; line[j++] = binhex[c>>4]; line[j++] = binhex[c&0xf]; - if (i&1) j++; + j++; if (encoding == CHAR_EBCDIC) { c = EBCDIC_to_ASCII1(c); } - line[42+k++] = c >= ' ' && c < 0x7f ? c : '.'; + line[50+k++] = c >= ' ' && c < 0x7f ? c : '.'; if ((i & 15) == 15) { - fprintf (fh, "\n%4x %s", ad, line); + fprintf (fh, "\n%04x %s", ad, line); /*if (i==15) printf (" %d", length);*/ memset (line, ' ', sizeof line); line[sizeof (line)-1] = j = k = 0; @@ -248,7 +248,7 @@ void print_hex_data_text(FILE *fh, register const u_char *cp, } } - if (line[0] != ' ') fprintf (fh, "\n%4x %s", ad, line); + if (line[0] != ' ') fprintf (fh, "\n%04x %s", ad, line); fprintf(fh, "\n"); return; diff --git a/text2pcap-scanner.l b/text2pcap-scanner.l new file mode 100644 index 0000000000..63835a1e39 --- /dev/null +++ b/text2pcap-scanner.l @@ -0,0 +1,71 @@ +/* -*-mode: flex-*- */ + +%{ + +/******************************************************************************** + * + * text2pcap-scanner.l + * + * Utility to convert an ASCII hexdump into a libpcap-format capture file + * + * (c) Copyright 2001 Ashok Narayanan + * + * $Id: text2pcap-scanner.l,v 1.1 2001/05/16 21:32:04 ashokn Exp $ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + *******************************************************************************/ + +#include +#include + +#include "text2pcap.h" + +%} + +hexdigit [0-9A-Fa-f] +directive #TEXT2PCAP.* +comment #[^W].* +byte [0-9A-Fa-f][0-9A-Fa-f][ \t] +byte_eol [0-9A-Fa-f][0-9A-Fa-f]\n +offset [0-9A-Fa-f]+[ \t\n] +text [^ \n\t]+ +mailfwd > +eol \r?\n\r? + +%% + +{byte} { parse_token(T_BYTE, yytext); } +{byte_eol} { parse_token(T_BYTE, yytext); parse_token(T_EOL, NULL); } +{offset} { parse_token(T_OFFSET, yytext); } +{mailfwd}{offset} { parse_token(T_OFFSET, yytext+1); } +{eol} { parse_token(T_EOL, NULL); } +[ \t] ; /* ignore whitespace */ +{directive} { parse_token(T_DIRECTIVE, yytext); } +{comment} ; /* ignore comments */ +{text} { parse_token(T_TEXT, yytext); } + +%% + +int yywrap() +{ + return 1; +} diff --git a/text2pcap.c b/text2pcap.c new file mode 100644 index 0000000000..77e98da952 --- /dev/null +++ b/text2pcap.c @@ -0,0 +1,741 @@ +/**-*-C-*-********************************************************************** + * + * text2pcap.c + * + * Utility to convert an ASCII hexdump into a libpcap-format capture file + * + * (c) Copyright 2001 Ashok Narayanan + * + * $Id: text2pcap.c,v 1.1 2001/05/16 21:32:04 ashokn Exp $ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + *******************************************************************************/ + +/******************************************************************************* + * + * This utility reads in an ASCII hexdump of this common format: + * + * 00000000 00 E0 1E A7 05 6F 00 10 5A A0 B9 12 08 00 46 00 .....o..Z.....F. + * 00000010 03 68 00 00 00 00 0A 2E EE 33 0F 19 08 7F 0F 19 .h.......3..... + * 00000020 03 80 94 04 00 00 10 01 16 A2 0A 00 03 50 00 0C .............P.. + * 00000030 01 01 0F 19 03 80 11 01 1E 61 00 0C 03 01 0F 19 .........a...... + * + * Each bytestring line consists of an offset, one or more bytes, and + * text at the end. An offset is defined as a hex string of more than + * two characters. A byte is defined as a hex string of exactly two + * characters. The text at the end is ignored, as is any text before + * the offset. Bytes read from a bytestring line are added to the + * current packet only if all the following conditions are satisfied: + * + * - No text appears between the offset and the bytes (any bytes appearing after + * such text would be ignored) + * + * - The offset must be arithmetically correct, i.e. if the offset is 00000020, then + * exactly 32 bytes must have been read into this packet before this. If the offset + * is wrong, the packet is immediately terminated + * + * A packet start is signalled by a zero offset. + * + * Lines starting with #TEXT2PCAP are directives. These allow the user + * to embed instructions into the capture file which allows text2pcap + * to take some actions (e.g. specifying the encapsulation + * etc.). Currently no directives are implemented. + * + * Lines beginning with # which are not directives are ignored as + * comments. Currently all non-hexdump text is ignored by text2pcap; + * in the future, text processing may be added, but lines prefixed + * with '#' will still be ignored. + * + * The output is a libpcap packet containing Ethernet frames by + * default. This program takes options which allow the user to add + * dummy Ethernet, IP and UDP headers to the packets in order to allow + * dumps of L3 or higher protocols to be decoded. + * + * Considerable flexibility is built into this code to read hexdumps + * of slightly different formats. For example, any text prefixing the + * hexdump line is dropped (including mail forwarding '>'). The offset + * can be any hex number of four digits or greater. + * + * This converter cannot read a single packet greater than 64K. Packet + * snaplength is automatically set to 64K. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#include "text2pcap.h" + +/*--- Options --------------------------------------------------------------------*/ + +/* Debug level */ +int debug = 0; +/* Be quiet */ +int quiet = FALSE; + +/* Dummy Ethernet header */ +int hdr_ethernet = FALSE; +unsigned long hdr_ethernet_proto = 0; + +/* Dummy IP header */ +int hdr_ip = FALSE; +unsigned long hdr_ip_proto = 0; + +/* Dummy UDP header */ +int hdr_udp = FALSE; +unsigned long hdr_udp_dest = 0; +unsigned long hdr_udp_src = 0; + +/*--- Local date -----------------------------------------------------------------*/ + +/* This is where we store the packet currently being built */ +#define MAX_PACKET 64000 +unsigned char packet_buf[MAX_PACKET]; +unsigned long curr_offset = 0; + +/* Number of packets read and written */ +unsigned long num_packets_read = 0; +unsigned long num_packets_written = 0; + +/* Input file */ +char *input_filename; +FILE *input_file = NULL; +/* Output file */ +char *output_filename; +FILE *output_file = NULL; + +/* Offset base to parse */ +unsigned long offset_base = 16; + +FILE *yyin; + +/* ----- State machine -----------------------------------------------------------*/ + +/* Current state of parser */ +typedef enum { + INIT, /* Waiting for start of new packet */ + START_OF_LINE, /* Starting from beginning of line */ + OFFSET, /* Just read the offset */ + BYTE, /* Just read a byte */ + TEXT, /* Just read text - ignore until EOL */ +} parser_state_t; +parser_state_t state = INIT; + +const char *state_str[] = {"Init", + "Start-of-line", + "Offset", + "Byte", + "Text" +}; + +const char *token_str[] = {"", + "Byte", + "Offset", + "Directive", + "Text", + "End-of-line" +}; + +/* ----- Skeleton Packet Headers --------------------------------------------------*/ + +typedef struct { + unsigned char src_addr[6]; + unsigned char dest_addr[6]; + unsigned short l3pid; +} hdr_ethernet_t; + +hdr_ethernet_t HDR_ETHERNET = { + {0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, + {0x02, 0x02, 0x02, 0x02, 0x02, 0x02}, + 0}; + +typedef struct { + unsigned char ver_hdrlen; + unsigned char dscp; + unsigned short packet_length; + unsigned short identification; + unsigned char flags; + unsigned char fragment; + unsigned char ttl; + unsigned char protocol; + unsigned short hdr_checksum; + unsigned long src_addr; + unsigned long dest_addr; +} hdr_ip_t; + +hdr_ip_t HDR_IP = {0x45, 0, 0, 0x3412, 0, 0, 0xff, 0, 0, 0x01010101, 0x02020202}; + +typedef struct { + unsigned short source_port; + unsigned short dest_port; + unsigned short length; + unsigned short checksum; +} hdr_udp_t; + +hdr_udp_t HDR_UDP = {0, 0, 0, 0}; + +char tempbuf[64]; + +/*---------------------------------------------------------------------- + * Stuff for writing a PCap file + */ +#define PCAP_MAGIC 0xa1b2c3d4 + +/* "libpcap" file header (minus magic number). */ +struct pcap_hdr { + unsigned long magic; /* magic */ + unsigned short version_major; /* major version number */ + unsigned short version_minor; /* minor version number */ + unsigned long thiszone; /* GMT to local correction */ + unsigned long sigfigs; /* accuracy of timestamps */ + unsigned long snaplen; /* max length of captured packets, in octets */ + unsigned long network; /* data link type */ +}; + +/* "libpcap" record header. */ +struct pcaprec_hdr { + unsigned long ts_sec; /* timestamp seconds */ + unsigned long ts_usec; /* timestamp microseconds */ + unsigned long incl_len; /* number of octets of packet saved in file */ + unsigned long orig_len; /* actual length of packet */ +}; + +/* Link-layer type; see net/bpf.h for details */ +unsigned long pcap_link_type = 1; /* Default is DLT-EN10MB */ + +/*---------------------------------------------------------------------- + * Parse a single hex number + * Will abort the program if it can't parse the number + * Pass in TRUE if this is an offset, FALSE if not + */ +static unsigned long +parse_num (char *str, int offset) +{ + unsigned long num; + char *c; + + num = strtoul(str, &c, offset ? offset_base : 16); + if (c==str) { + fprintf(stderr, "FATAL ERROR: Bad hex number? [%s]\n", str); + exit(-1); + } + return num; +} + +/*---------------------------------------------------------------------- + * Write this byte into current packet + */ +static void +write_byte (char *str) +{ + unsigned long num; + + if (debug>=2) + fprintf(stderr, __FUNCTION__); + + num = parse_num(str, FALSE); + packet_buf[curr_offset] = num; + curr_offset ++; +} + +/*---------------------------------------------------------------------- + * Compute one's complement checksum (from RFC1071) + */ +static unsigned short +in_checksum (void *buf, unsigned long count) +{ + unsigned long sum = 0; + unsigned short *addr = buf; + + while( count > 1 ) { + /* This is the inner loop */ + sum += ntohs(* (unsigned short *) addr++); + count -= 2; + } + + /* Add left-over byte, if any */ + if( count > 0 ) + sum += * (unsigned char *) addr; + + /* Fold 32-bit sum to 16 bits */ + while (sum>>16) + sum = (sum & 0xffff) + (sum >> 16); + + return htons(~sum); +} + +/*---------------------------------------------------------------------- + * Write current packet out + */ +static void +write_current_packet (void) +{ + int length = 0; + int udp_length = 0; + int ip_length = 0; + int eth_trailer_length = 0; + struct pcaprec_hdr ph; + + if (curr_offset > 0) { + /* Write the packet */ + + /* Compute packet length */ + length = curr_offset; + if (hdr_udp) { length += sizeof(HDR_UDP); udp_length = length; } + if (hdr_ip) { length += sizeof(HDR_IP); ip_length = length; } + if (hdr_ethernet) { + length += sizeof(HDR_ETHERNET); + /* Pad trailer */ + if (length < 60) { + eth_trailer_length = 60 - length; + length = 60; + } + } + + /* Write PCap header */ + ph.ts_sec = num_packets_written; + ph.ts_usec = num_packets_written; + ph.incl_len = length; + ph.orig_len = length; + fwrite(&ph, sizeof(ph), 1, output_file); + + /* Write Ethernet header */ + if (hdr_ethernet) { + HDR_ETHERNET.l3pid = htons(hdr_ethernet_proto); + fwrite(&HDR_ETHERNET, sizeof(HDR_ETHERNET), 1, output_file); + } + + /* Write IP header */ + if (hdr_ip) { + HDR_IP.packet_length = htons(ip_length); + HDR_IP.protocol = hdr_ip_proto; + HDR_IP.hdr_checksum = 0; + HDR_IP.hdr_checksum = in_checksum(&HDR_IP, sizeof(HDR_IP)); + fwrite(&HDR_IP, sizeof(HDR_IP), 1, output_file); + } + + /* Write UDP header */ + if (hdr_udp) { + HDR_UDP.source_port = htons(hdr_udp_src); + HDR_UDP.dest_port = htons(hdr_udp_dest); + HDR_UDP.length = htons(udp_length); + + fwrite(&HDR_UDP, sizeof(HDR_UDP), 1, output_file); + } + + /* Write packet */ + fwrite(packet_buf, curr_offset, 1, output_file); + + /* Write Ethernet trailer */ + if (hdr_ethernet && eth_trailer_length > 0) { + memset(tempbuf, 0, eth_trailer_length); + fwrite(tempbuf, eth_trailer_length, 1, output_file); + } + + if (!quiet) + fprintf(stderr, "Wrote packet of %lu bytes\n", curr_offset); + num_packets_written ++; + } + curr_offset = 0; +} + +/*---------------------------------------------------------------------- + * Write the PCap file header + */ +static void +write_file_header (void) +{ + struct pcap_hdr fh; + + if (debug>=2) + fprintf(stderr, __FUNCTION__); + + fh.magic = PCAP_MAGIC; + fh.version_major = 2; + fh.version_minor = 4; + fh.thiszone = 0; + fh.sigfigs = 0; + fh.snaplen = 102400; + fh.network = pcap_link_type; + + fwrite(&fh, sizeof(fh), 1, output_file); +} + +/*---------------------------------------------------------------------- + * Start a new packet + */ +static void +start_new_packet (void) +{ + if (debug>=2) + fprintf(stderr, __FUNCTION__); + + if (debug>=1) + fprintf(stderr, "Start new packet\n"); + + /* Write out the current packet, if required */ + write_current_packet(); + curr_offset = 0; + num_packets_read ++; +} + +/*---------------------------------------------------------------------- + * Process a directive + */ +static void +process_directive (char *str) +{ + if (debug>=2) + fprintf(stderr, __FUNCTION__); + + fprintf(stderr, "\n--- Directive [%s] currently unsupported ---\n", str+10); + +} + +/*---------------------------------------------------------------------- + * Parse a single token (called from the scanner) + */ +void +parse_token (token_t token, char *str) +{ + unsigned long num; + + /* + * This is implemented as a simple state machine of five states. + * State transitions are caused by tokens being received from the + * scanner. The code should be self_documenting. + */ + + if (debug>=2) { + /* Sanitize - remove all '\r' */ + char *c; + if (str!=NULL) { while ((c = strchr(str, '\r')) != NULL) *c=' '; } + + fprintf(stderr, "(%s, %s \"%s\") -> (", + state_str[state], token_str[token], str ? str : ""); + } + + switch(state) { + + /* ----- Waiting for new packet -------------------------------------------*/ + case INIT: + switch(token) { + case T_DIRECTIVE: + process_directive(str); + break; + case T_OFFSET: + num = parse_num(str, TRUE); + if (num==0) { + /* New packet starts here */ + start_new_packet(); + state = OFFSET; + } + break; + default: + break; + } + break; + + /* ----- Processing packet, start of new line -----------------------------*/ + case START_OF_LINE: + switch(token) { + case T_DIRECTIVE: + process_directive(str); + break; + case T_OFFSET: + num = parse_num(str, TRUE); + if (num==0) { + /* New packet starts here */ + start_new_packet(); + state = OFFSET; + } else if (num != curr_offset) { + /* Bad offset; switch to INIT state */ + if (debug>=1) + fprintf(stderr, "Inconsistent offset. Expecting %0lX, got %0lX. Ignoring rest of packet\n", + curr_offset, num); + write_current_packet(); + state = INIT; + } else + state = OFFSET; + break; + default: + break; + } + break; + + /* ----- Processing packet, read offset -----------------------------------*/ + case OFFSET: + switch(token) { + case T_BYTE: + /* Record the byte */ + state = BYTE; + write_byte(str); + break; + case T_TEXT: + case T_DIRECTIVE: + case T_OFFSET: + state = TEXT; + break; + case T_EOL: + state = START_OF_LINE; + break; + default: + break; + } + break; + + /* ----- Processing packet, read byte -------------------------------------*/ + case BYTE: + switch(token) { + case T_BYTE: + /* Record the byte */ + write_byte(str); + break; + case T_TEXT: + case T_DIRECTIVE: + case T_OFFSET: + state = TEXT; + break; + case T_EOL: + state = START_OF_LINE; + break; + default: + break; + } + break; + + /* ----- Processing packet, read text -------------------------------------*/ + case TEXT: + switch(token) { + case T_EOL: + state = START_OF_LINE; + break; + default: + break; + } + break; + + default: + fprintf(stderr, "FATAL ERROR: Bad state (%d)", state); + exit(-1); + } + + if (debug>=2) + fprintf(stderr, ", %s)\n", state_str[state]); + +} + +/*---------------------------------------------------------------------- + * Print helpstring and exit + */ +static void +help (char *progname) +{ + fprintf(stderr, + "\n" + "Usage: %s [-d] [-q] [-o h|o] [-l typenum] [-e l3pid] [-i proto] \n" + " [-u srcp destp] \n" + "\n" + "where specifies input filename (use - for standard input)\n" + " specifies output filename (use - for standard output)\n" + "\n" + "[options] are one or more of the following \n" + "\n" + " -w filename : Write capfile to . Default is standard output\n" + " -h : Display this help message \n" + " -d : Generate detailed debug of parser states \n" + " -o hex|oct : Parse offsets as (h)ex or (o)ctal. Default is hex\n" + " -l typenum : Specify link-layer type number. Default is 1 (Ethernet). \n" + " See net/bpf.h for list of numbers.\n" + " -q : Generate no output at all (automatically turns off -d)\n" + " -e l3pid : Prepend dummy Ethernet II header with specified L3PID (in HEX)\n" + " Example: -e 0x800\n" + " -i proto : Prepend dummy IP header with specified IP protocol (in DECIMAL). \n" + " Automatically prepends Ethernet header as well. Example: -i 46\n" + " -u srcp destp: Prepend dummy UDP header with specified dest and source ports (in DECIMAL).\n" + " Automatically prepends Ethernet and IP headers as well\n" + " Example: -u 30 40" + "\n", + progname); + + exit(-1); +} + +/*---------------------------------------------------------------------- + * Parse CLI options + */ +static void +parse_options (int argc, char *argv[]) +{ + int c; + + /* Scan CLI parameters */ + while ((c = getopt(argc, argv, "dqr:w:e:i:l:o:u:")) != -1) { + switch(c) { + case '?': help(argv[0]); break; + case 'h': help(argv[0]); break; + case 'd': if (!quiet) debug++; break; + case 'q': quiet = TRUE; debug = FALSE; break; + case 'l': pcap_link_type = atoi(optarg); break; + case 'o': + if (!optarg || (optarg[0]!='h' && optarg[0] != 'o')) { + fprintf(stderr, "Bad argument for '-e': %s\n", + optarg ? optarg : ""); + help(argv[0]); + } + offset_base = (optarg[0]=='o') ? 8 : 16; + break; + case 'e': + hdr_ethernet = TRUE; + if (!optarg || sscanf(optarg, "%0lx", &hdr_ethernet_proto) < 1) { + fprintf(stderr, "Bad argument for '-e': %s\n", + optarg ? optarg : ""); + help(argv[0]); + } + break; + + case 'i': + hdr_ip = TRUE; + if (!optarg || sscanf(optarg, "%ld", &hdr_ip_proto) < 1) { + fprintf(stderr, "Bad argument for '-i': %s\n", + optarg ? optarg : ""); + help(argv[0]); + } + hdr_ethernet = TRUE; + hdr_ethernet_proto = 0x800; + break; + + case 'u': + hdr_udp = TRUE; + if (!optarg || sscanf(optarg, "%ld", &hdr_udp_src) < 1) { + fprintf(stderr, "Bad src port for '-u'\n"); + help(argv[0]); + } + if (optind >= argc || sscanf(argv[optind], "%ld", &hdr_udp_dest) < 1) { + fprintf(stderr, "Bad dest port for '-u'\n"); + help(argv[0]); + } + hdr_ip = TRUE; + hdr_ip_proto = 17; + hdr_ethernet = TRUE; + hdr_ethernet_proto = 0x800; + break; + + default: + help(argv[0]); + } + } + + if (optind >= argc || argc-optind < 2) { + fprintf(stderr, "Must specify input and output filename\n"); + help(argv[0]); + } + + if (strcmp(argv[optind], "-")) { + input_filename = strdup(argv[optind]); + input_file = fopen(input_filename, "rb"); + if (!input_file) { + fprintf(stderr, "Cannot open file [%s] for reading: %s\n", + input_filename, strerror(errno)); + exit(-1); + } + } else { + input_filename = "Standard input"; + input_file = stdin; + } + + if (strcmp(argv[optind+1], "-")) { + output_filename = strdup(argv[optind+1]); + output_file = fopen(output_filename, "wb"); + if (!output_file) { + fprintf(stderr, "Cannot open file [%s] for writing: %s\n", + output_filename, strerror(errno)); + exit(-1); + } + } else { + output_filename = "Standard output"; + output_file = stdout; + } + + /* Some validation */ + if (pcap_link_type != 1 && hdr_ethernet) { + fprintf(stderr, "Dummy headers (-e, -i, -u) cannot be specified with link type override (-l)\n"); + exit(-1); + } + + /* Set up our variables */ + if (!input_file) { + input_file = stdin; + input_filename = "Standard input"; + } + if (!output_file) { + output_file = stdout; + output_filename = "Standard output"; + } + + /* Display summary of our state */ + if (!quiet) { + fprintf(stderr, "Input from: %s\n", input_filename); + fprintf(stderr, "Output to: %s\n", output_filename); + + if (hdr_ethernet) fprintf(stderr, "Generate dummy Ethernet header: Protocol: 0x%0lX\n", + hdr_ethernet_proto); + if (hdr_ip) fprintf(stderr, "Generate dummy IP header: Protocol: %ld\n", + hdr_ip_proto); + if (hdr_udp) fprintf(stderr, "Generate dummy UDP header: Source port: %ld. Dest port: %ld\n", + hdr_udp_src, hdr_udp_dest); + } +} + +int main(int argc, char *argv[]) +{ + parse_options(argc, argv); + + assert(input_file != NULL); + assert(output_file != NULL); + + write_file_header(); + + yyin = input_file; + yylex(); + write_current_packet(); + if (debug) + fprintf(stderr, "\n-------------------------\n"); + if (!quiet) { + fprintf(stderr, "Read %ld potential packets, wrote %ld packets\n", + num_packets_read, num_packets_written); + } + return 0; +} diff --git a/text2pcap.h b/text2pcap.h new file mode 100644 index 0000000000..8ccfcc45e4 --- /dev/null +++ b/text2pcap.h @@ -0,0 +1,47 @@ +/**-*-C-*-********************************************************************** + * + * text2pcap.h + * + * Utility to convert an ASCII hexdump into a libpcap-format capture file + * + * (c) Copyright 2001 Ashok Narayanan + * + * $Id: text2pcap.h,v 1.1 2001/05/16 21:32:04 ashokn Exp $ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + *******************************************************************************/ + + +#ifndef TEXT2PCAP_H +#define TEXT2PCAP_H + +typedef enum { + T_BYTE = 1, + T_OFFSET, + T_DIRECTIVE, + T_TEXT, + T_EOL +} token_t; + +void parse_token(token_t token, char *str); + +#endif