Ethereal-dev: [ethereal-dev] Wiretap patch for "pppdump" files
Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.
From: Gilbert Ramirez <gram@xxxxxxxxxx>
Date: Sun, 17 Sep 2000 00:51:49 -0400
Here's an initial patch to the wiretap library to read "pppdump" format files, which are the binary logs from pppd. This turned out to be very difficult to code becuase the format is unlike all other packet-capture formats that are handled by wiretap. pppd logs character I/O, which is a layer lower than PPP. That's why there's a special "-p" option to pppdump; pppdump has to reassemble the various records into a single PPP packet; in this wiretap module I have to do the same as "pppdump -p"; there's a lot of state to keep track of to do so. Anyway, this first patch works only with tethereal, since tethereal just reads through the file sequentially. The random-access seeking that ethereal does will not work with this module yet; I have to keep track of even more state for that to work. That's next on my list. Secondly, I haven't even tried to do anything with timestamps in this first patch. They're all 0. For those of you who are interested in using [t]ethereal on your pppd log files, please test this patch against your log files. Take tethereal 0.8.12 (or CVS image) and apply the patch. Copy pppdump.[ch] into the ethereal/wiretap directory. You'll have to have autoconf and automake installed, since the Makefiles have to be rebuilt; but that should happen automatically, just make sure they're installed. Run: tethereal -r file > out (or "tethereal -n -r file > out" for faster runs) It should run through the whole file, and maybe at the end say that the file ended in the middle of a packet (depends on your pppd log file). It should not assert or segfault. If it does, please let me know, and send the pppd log file if possible. This code will produce reams of debugging output. Good luck! --gilbert
/* pppdump.c * * $Id$ * * Copyright (c) 2000 by Gilbert Ramirez <gram@xxxxxxxxxx> * * 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. * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "wtap-int.h" #include "buffer.h" #include "pppdump.h" #include "file_wrappers.h" #include <glib.h> #include <stdio.h> #include <stdlib.h> /* pppdump records Daniel Thompson (STMicroelectronics) <daniel.thompson@xxxxxx> +------+ | 0x07 +------+------+------+ Reset time | t3 | t2 | t1 | t0 | t = time_t +------+------+------+------+ +------+ | 0x06 | Time step (short) | ts | ts = time step (tenths) +------+ +------+ | 0x05 +------+------+------+ Time step (long) | ts3 | ts2 | ts1 | ts0 | ts = time step (tenths) +------+------+------+------+ +------+ | 0x04 | Receive deliminator (not seen in practice) +------+ +------+ | 0x03 | Send deliminator (not seen in practice) +------+ +------+ | 0x02 +------+ Received data | n1 | n0 | n = number of bytes following | data | | | +------+ | 0x01 +------+ Sent data | n1 | n0 | n = number of bytes following | data | | | */ #define PPPD_SENT_DATA 0x01 #define PPPD_RECV_DATA 0x02 #define PPPD_SEND_DELIM 0x03 #define PPPD_RECV_DELIM 0x04 #define PPPD_TIME_STEP_LONG 0x05 #define PPPD_TIME_STEP_SHORT 0x06 #define PPPD_RESET_TIME 0x07 #define PPPD_NULL 0x00 /* For my own use */ typedef enum { DIRECTION_SENT, DIRECTION_RECV } direction_enum; static gboolean pppdump_read(wtap *wth, int *err, int *data_offset); static int pppdump_seek_read(wtap *wth, int seek_off, union wtap_pseudo_header *pseudo_header, guint8 *pd, int len); typedef struct { direction_enum dir; int cnt; gboolean esc; guint8 buf[8192]; long id_offset; } pkt_t; /* Partial-record state */ typedef struct { int num_bytes; pkt_t *pkt; } prec_state; struct _pppdump_t; typedef struct _pppdump_t { time_t start_time; pkt_t spkt; pkt_t rpkt; long offset; GList *precs; struct _pppdump_t *seek_state; } pppdump_t; static int process_data(pppdump_t *state, FILE_T fh, pkt_t *pkt, int n, guint8 *pd, int *err); static gboolean collate(pppdump_t*, FILE_T fh, int *err, guint8 *pd, int *num_bytes, direction_enum *direction, long *data_offset); static void init_state(pppdump_t *state) { g_print("INITIALIZING STATE 0x%08x\n", (unsigned int) state); state->precs = NULL; state->spkt.dir = DIRECTION_SENT; state->spkt.cnt = 0; state->spkt.esc = FALSE; state->spkt.id_offset = 0; state->rpkt.dir = DIRECTION_RECV; state->rpkt.cnt = 0; state->rpkt.esc = FALSE; state->rpkt.id_offset = 0; state->seek_state = NULL; state->offset = 0x100000; /* to detect errors during development */ } static void print_hex_data_text(const u_char *cp, unsigned int length) { register int ad, i, j, k; u_char c; u_char line[60]; static u_char binhex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; memset (line, ' ', sizeof line); line[sizeof (line)-1] = 0; for (ad=i=j=k=0; i<length; i++) { c = *cp++; line[j++] = binhex[c>>4]; line[j++] = binhex[c&0xf]; if (i&1) j++; line[42+k++] = c >= ' ' && c < 0x7f ? c : '.'; if ((i & 15) == 15) { printf ("\n%4x %s", ad, line); /*if (i==15) printf (" %d", length);*/ memset (line, ' ', sizeof line); line[sizeof (line)-1] = j = k = 0; ad += 16; } } if (line[0] != ' ') printf ("\n%4x %s", ad, line); printf("\n"); return; } int pppdump_open(wtap *wth, int *err) { guint8 buffer[6]; /* Looking for: 0x07 t3 t2 t1 t0 ID */ pppdump_t *state; /* There is no file header, only packet records. Fortunately for us, * timestamp records are separated from packet records, so we should * find an "initial time stamp" (i.e., a "reset time" record, or * record type 0x07) at the beginning of the file. We'll check for * that, plus a valid record following the 0x07 and the four bytes * representing the timestamp. */ file_seek(wth->fh, 0, SEEK_SET); wtap_file_read_unknown_bytes(buffer, sizeof(buffer), wth->fh, err); if (buffer[0] == PPPD_RESET_TIME && (buffer[5] == PPPD_SENT_DATA || buffer[5] == PPPD_RECV_DATA || buffer[5] == PPPD_TIME_STEP_LONG || buffer[5] == PPPD_TIME_STEP_SHORT || buffer[5] == PPPD_RESET_TIME)) { goto my_file_type; } else { return 0; } my_file_type: state = wth->capture.generic = g_malloc(sizeof(pppdump_t)); state->start_time = pntohl(&buffer[1]); g_print("pppdump time is %lu\n", state->start_time); init_state(state); state->offset = 5; file_seek(wth->fh, 5, SEEK_SET); wth->file_encap = WTAP_ENCAP_PPP; wth->file_type = WTAP_FILE_PPPDUMP; wth->snapshot_length = 8192; /* just guessing */ wth->subtype_read = pppdump_read; wth->subtype_seek_read = pppdump_seek_read; state->seek_state = g_malloc(sizeof(pppdump_t)); return 1; } /* Find the next packet and parse it; called from wtap_loop(). */ static gboolean pppdump_read(wtap *wth, int *err, int *data_offset) { gboolean retval; int num_bytes; direction_enum direction; guint8 *buf; g_print("======================================================\n"); buffer_assure_space(wth->frame_buffer, 8192); buf = buffer_start_ptr(wth->frame_buffer); retval = collate(wth->capture.generic, wth->fh, err, buf, &num_bytes, &direction, &wth->data_offset); g_print("Record ended with wth->data_offset = 0x%lx\n", wth->data_offset); if (!retval) { return FALSE; } *data_offset = wth->data_offset; wth->phdr.len = num_bytes; wth->phdr.caplen = num_bytes; wth->phdr.ts.tv_sec = 0; /* TODO */ wth->phdr.ts.tv_usec = 0; /* TODO */ wth->phdr.pkt_encap = WTAP_ENCAP_PPP; return TRUE; } #define PKT(x) (x)->dir == DIRECTION_SENT ? "SENT" : "RECV" static gboolean save_prec_state(pppdump_t *state, int num_bytes, pkt_t *pkt) { prec_state *prec; prec = g_new(prec_state, 1); if (!prec) { return FALSE; } prec->num_bytes = num_bytes; prec->pkt = pkt; g_print("saved state of num_bytes=%d pkt=0x%08x (%s) pkt->cnt=%d\n", num_bytes, (unsigned int) pkt, PKT(pkt), pkt->cnt); state->precs = g_list_append(state->precs, prec); return TRUE; } static int process_data_from_prec_state(pppdump_t *state, FILE_T fh, guint8* pd, int *err, pkt_t **ppkt) { prec_state *prec; prec = state->precs->data; state->precs = g_list_remove(state->precs, prec); g_print("retrieved state of num_bytes=%d ", prec->num_bytes); *ppkt = prec->pkt; g_print("pkt=0x%08x (%s) pkt->cnt = %d\n", (unsigned int) prec->pkt, PKT(prec->pkt), prec->pkt->cnt); return process_data(state, fh, prec->pkt, prec->num_bytes, pd, err); } /* Returns number of bytes copied for record, -1 if failure */ static int process_data(pppdump_t *state, FILE_T fh, pkt_t *pkt, int n, guint8 *pd, int *err) { int c; int num_bytes = n; int num_written; for (; num_bytes > 0; --num_bytes) { c = file_getc(fh); g_print("PD At offset 0x%lx got %c (0x%02x)\n", state->offset, c, c); state->offset++; switch (c) { case EOF: g_print("Unexpected EOF\n"); if (*err == 0) { *err = WTAP_ERR_SHORT_READ; } return -1; break; case '~': if (pkt->cnt > 0) { pkt->esc = FALSE; num_written = pkt->cnt - 2; pkt->cnt = 0; if (num_written <= 0) { return 0; } memcpy(pd, pkt->buf, num_written); g_print("\n%s:\n", PKT(pkt)); print_hex_data_text(pd, num_written); num_bytes--; if (num_bytes > 0) { if (!save_prec_state(state, num_bytes, pkt)) { return -1; } } g_print("returning with num_bytes = %d\n", num_bytes); g_print("returning with num_written = %d\n", num_written); return num_written; } break; case '}': if (!pkt->esc) { pkt->esc = TRUE; break; } /* else fall through */ default: if (pkt->esc) { c ^= 0x20; g_print("Changed 0x%02x\t%c\n", c, c); pkt->esc = FALSE; } pkt->buf[pkt->cnt++] = c; break; } } g_print("PD returning 0; no out bytes. pkt=0x%08x (%s) pkt->cnt=%d\n", (unsigned int) pkt, PKT(pkt), pkt->cnt); /* we could have run out of bytes to read */ return 0; } /* Returns TRUE if packet data copied, FALSE if error occurred or EOF (no more records). */ static gboolean collate(pppdump_t* state, FILE_T fh, int *err, guint8 *pd, int *num_bytes, direction_enum *direction, long *data_offset) { int id; pkt_t *pkt = NULL; int n, num_written = 0; while (state->precs) { g_print("I see a saved state.\n"); num_written = process_data_from_prec_state(state, fh, pd, err, &pkt); if (num_written < 0) { return FALSE; } else if (num_written > 0) { *num_bytes = num_written; *direction = pkt->dir; *data_offset = pkt->id_offset; pkt->id_offset = 0; g_print("Returning, state->offset = 0x%lx\n", state->offset); return TRUE; } /* if 0 bytes written, keep processing */ } g_print("No saved states.\n"); while ((id = file_getc(fh)) != EOF) { g_print("CL At offset 0x%lx got %c (0x%02x)\n", state->offset, id, id); state->offset++; switch (id) { case PPPD_SENT_DATA: case PPPD_RECV_DATA: pkt = id == PPPD_SENT_DATA ? &state->spkt : &state->rpkt; if (pkt->id_offset == 0) { pkt->id_offset = state->offset - 1; } n = file_getc(fh); n = (n << 8) + file_getc(fh); state->offset += 2; g_print("ID: Going to read %d bytes for pkt=0x%08x (%s)\n", n, (unsigned int) pkt, PKT(pkt)); num_written = process_data(state, fh, pkt, n, pd, err); if (num_written < 0) { return FALSE; } else if (num_written > 0) { *num_bytes = num_written; *direction = pkt->dir; *data_offset = pkt->id_offset; pkt->id_offset = 0; g_print("Returning, state->offset = 0x%lx\n", state->offset); return TRUE; } /* if 0 bytes written, keep looping */ break; case PPPD_SEND_DELIM: case PPPD_RECV_DELIM: /* What can we do? */ g_print("GOT *_DELIM\n"); break; case PPPD_TIME_STEP_LONG: case PPPD_RESET_TIME: g_print("GOT *_TIME 32\n"); file_seek(fh, sizeof(guint32), SEEK_CUR); state->offset += sizeof(guint32); break; case PPPD_TIME_STEP_SHORT: g_print("GOT *_TIME 8\n"); file_seek(fh, sizeof(guint8), SEEK_CUR); state->offset += sizeof(guint8); break; default: g_print("BAD ID: 0x%02x\n", id); /* XXX - bad file */ g_assert_not_reached(); } } return FALSE; } /* Used to read packets in random-access fashion */ static int pppdump_seek_read (wtap *wth, int seek_off, union wtap_pseudo_header *pseudo_header, guint8 *pd, int len) { int err = 0; int num_bytes; direction_enum direction; long offset = 0; gboolean retval; pppdump_t *state; g_print(">>>>>>>>>>>> SEEKING to offset %d (0x%x)\n", seek_off, seek_off); file_seek(wth->random_fh, seek_off, SEEK_SET); state = wth->capture.generic; init_state(state->seek_state); retval = collate(state->seek_state, wth->random_fh, &err, pd, &num_bytes, &direction, &offset); if (!retval) { return -1; } if (len != num_bytes) { return -1; } g_print(">>>>>>>>>>>> COPIED %d bytes\n", num_bytes); return 0; }
/* pppdump.h * * $Id$ * * Copyright (c) 2000 by Gilbert Ramirez <gram@xxxxxxxxxx> * * 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 __PPPDUMP_H__ #define __PPPDUMP_H__ int pppdump_open(wtap *wth, int *err); #endif
? ppdc2 ? ppdc ? pppdump.c ? pppdump.h ? ppdc1 Index: Makefile.am =================================================================== RCS file: /usr/local/cvsroot/ethereal/wiretap/Makefile.am,v retrieving revision 1.30 diff -u -r1.30 Makefile.am --- Makefile.am 2000/08/08 22:16:41 1.30 +++ Makefile.am 2000/09/17 04:39:33 @@ -62,6 +62,8 @@ netxray.h \ ngsniffer.c \ ngsniffer.h \ + pppdump.c \ + pppdump.h \ radcom.c \ radcom.h \ snoop.c \ Index: file.c =================================================================== RCS file: /usr/local/cvsroot/ethereal/wiretap/file.c,v retrieving revision 1.61 diff -u -r1.61 file.c --- file.c 2000/09/15 07:52:41 1.61 +++ file.c 2000/09/17 04:39:33 @@ -58,6 +58,7 @@ #include "toshiba.h" #include "i4btrace.h" #include "csids.h" +#include "pppdump.h" /* The open_file_* routines should return: * @@ -94,6 +95,7 @@ netxray_open, radcom_open, nettl_open, + pppdump_open, /* Files whose magic headers are in text *somewhere* in the * file (usually because the trace is just a saved copy of @@ -337,6 +339,10 @@ /* WTAP_FILE_CSIDS */ { "CSIDS IPLog", NULL, + NULL, NULL }, + + /* WTAP_FILE_PPPDUMP */ + { "pppd log (pppdump format)", NULL, NULL, NULL }, }; Index: wtap-int.h =================================================================== RCS file: /usr/local/cvsroot/ethereal/wiretap/wtap-int.h,v retrieving revision 1.8 diff -u -r1.8 wtap-int.h --- wtap-int.h 2000/09/07 05:34:21 1.8 +++ wtap-int.h 2000/09/17 04:39:34 @@ -141,6 +141,7 @@ netxray_t *netxray; ascend_t *ascend; csids_t *csids; + void *generic; } capture; subtype_read_func subtype_read; @@ -266,5 +267,33 @@ (guint32)*((guint8 *)p+1)<<8| \ (guint32)*((guint8 *)p+0)<<0) #endif + + +#define wtap_file_read_unknown_bytes(target, num_bytes, fh, err) \ + G_STMT_START \ + { \ + int _bytes_read; \ + _bytes_read = file_read((target), 1, (num_bytes), (fh)); \ + if (_bytes_read != (num_bytes)) { \ + *(err) = file_error((fh)); \ + return FALSE; \ + } \ + } \ + G_STMT_END + +#define wtap_file_read_expected_bytes(target, num_bytes, fh, err) \ + G_STMT_START \ + { \ + int _bytes_read; \ + _bytes_read = file_read((target), 1, (num_bytes), (fh)); \ + if (_bytes_read != (num_bytes)) { \ + *(err) = file_error((fh)); \ + if (*(err) == 0 && _bytes_read > 0) { \ + *(err) = WTAP_ERR_SHORT_READ; \ + } \ + return FALSE; \ + } \ + } \ + G_STMT_END #endif /* __WTAP_INT_H__ */ Index: wtap.h =================================================================== RCS file: /usr/local/cvsroot/ethereal/wiretap/wtap.h,v retrieving revision 1.79 diff -u -r1.79 wtap.h --- wtap.h 2000/09/15 07:52:43 1.79 +++ wtap.h 2000/09/17 04:39:34 @@ -124,9 +124,10 @@ #define WTAP_FILE_TOSHIBA 21 #define WTAP_FILE_I4BTRACE 22 #define WTAP_FILE_CSIDS 23 +#define WTAP_FILE_PPPDUMP 24 /* last WTAP_FILE_ value + 1 */ -#define WTAP_NUM_FILE_TYPES 24 +#define WTAP_NUM_FILE_TYPES 25 /* * Maximum packet size we'll support.
- Prev by Date: Re: [ethereal-dev] ECN = Explicit Congestion Notification
- Next by Date: [ethereal-dev] Another patch to apply for the Nokia tcpdump problem
- Previous by thread: [ethereal-dev] Ethereal compile problem.
- Next by thread: [ethereal-dev] Another patch to apply for the Nokia tcpdump problem
- Index(es):