Added 'text2pcap', a utility to convert text hexdumps into pcap

files. See text2pcap.1 (built from doc/text2pcap.pod) for details.

Changed 'tethereal -x' output to match hex dump format of text2pcap,
Ethereal and others.

svn path=/trunk/; revision=3421
This commit is contained in:
Ashok Narayanan 2001-05-16 21:32:05 +00:00
parent 5aafaef6c2
commit 2914e81177
8 changed files with 1045 additions and 11 deletions

View File

@ -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 <gerald@zing.org>
@ -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 > $@

View File

@ -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 ""

View File

@ -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 <gerald@zing.org>
@ -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

141
doc/text2pcap.pod Normal file
View File

@ -0,0 +1,141 @@
=head1 NAME
Text2pcap - Generate a capture file from an ASCII hexdump of packets
=head1 SYNOPSYS
B<text2pcap>
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<infile>
I<outfile>
=head1 DESCRIPTION
B<Text2pcap> is a program that reads in an ASCII hex dump and writes
the data described into a B<libpcap>-style capture file. B<text2pcap>
can read hexdumps with multiple packets in them, and build a capture
file of multiple packets. B<text2pcap> 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<Text2pcap> understands a hexdump of the form generated by I<od -t
x1>. 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<text2pcap> 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<text2pcap> 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<text2pcap>. 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<Text2pcap> 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<od>.
=item -l
Specify the link-layer type of this packet. Default is Ethernet
(1). See I<net/bpf.h> 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<tcpdump(8)>, L<pcap(3)>, L<ethereal(1)>, L<editcap(1)>
=head1 NOTES
B<Text2pcap> is part of the B<Ethereal> distribution. The latest version
of B<Ethereal> can be found at B<http://www.ethereal.com>.
=head1 AUTHORS
Ashok Narayanan <ashokn@cisco.com>

12
print.c
View File

@ -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 <gram@xiexie.org>
*
@ -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;

71
text2pcap-scanner.l Normal file
View File

@ -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 <ashokn@cisco.com>
*
* $Id: text2pcap-scanner.l,v 1.1 2001/05/16 21:32:04 ashokn Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
* 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 <stdio.h>
#include <stdlib.h>
#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;
}

741
text2pcap.c Normal file
View File

@ -0,0 +1,741 @@
/**-*-C-*-**********************************************************************
*
* text2pcap.c
*
* Utility to convert an ASCII hexdump into a libpcap-format capture file
*
* (c) Copyright 2001 Ashok Narayanan <ashokn@cisco.com>
*
* $Id: text2pcap.c,v 1.1 2001/05/16 21:32:04 ashokn Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <netinet/in.h>
#include <errno.h>
#include <assert.h>
#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] <input-filename> <output-filename>\n"
"\n"
"where <input-filename> specifies input filename (use - for standard input)\n"
" <output-filename> specifies output filename (use - for standard output)\n"
"\n"
"[options] are one or more of the following \n"
"\n"
" -w filename : Write capfile to <filename>. 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;
}

47
text2pcap.h Normal file
View File

@ -0,0 +1,47 @@
/**-*-C-*-**********************************************************************
*
* text2pcap.h
*
* Utility to convert an ASCII hexdump into a libpcap-format capture file
*
* (c) Copyright 2001 Ashok Narayanan <ashokn@cisco.com>
*
* $Id: text2pcap.h,v 1.1 2001/05/16 21:32:04 ashokn Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
* 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