Ethereal-dev: [ethereal-dev] Drop 2 of pppdump wiretap patch
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: Tue, 19 Sep 2000 00:34:06 -0400
The patch to wiretap to read pppdump files (the pppd log files) now works with random-access packet seeking, so it now works with Ethereal instead of just tethereal. Attached are the same pppd.diff and pppdump.h from before, plus a new pppdump.c. It works on the one pppd log file I have (the one that was posted to this list last week or so). I still have to get timestamps working, and then I have to clean up all the memory I allocate. The pppd log that was posted has some PPP VJ COMPRESSED and UNCOMPRESSED packets in it. Ethereal doesn't understand those, so there are a lot of TCP packets in that trace that aren't fully dissected. I need to do a thorough reading of RFC 1144 to see what it will take to write a dissector for these protocols. Please test on your pppd logs and let me know of any problems or successes. thanks, --gilbert
? 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/19 04:25:29
@@ -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/19 04:25:29
@@ -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/19 04:25:29
@@ -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/19 04:25:30
@@ -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.
/* 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
/* 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 {
long offset;
int num_saved_states;
direction_enum dir;
} pkt_id;
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;
GPtrArray *pids;
guint pkt_cnt;
int num_saved_states;
} pppdump_t;
static int
process_data(pppdump_t *state, FILE_T fh, pkt_t *pkt, int n, guint8 *pd, int *err,
gboolean *state_saved);
static gboolean
collate(pppdump_t*, FILE_T fh, int *err, guint8 *pd, int *num_bytes,
direction_enum *direction, pkt_id *pid);
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));
state->pids = g_ptr_array_new();
state->pkt_cnt = 0;
state->num_saved_states = 0;
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;
pppdump_t *state;
pkt_id *pid;
g_print("======================================================\n");
buffer_assure_space(wth->frame_buffer, 8192);
buf = buffer_start_ptr(wth->frame_buffer);
state = wth->capture.generic;
pid = g_new(pkt_id, 1);
if (!pid) {
return FALSE;
}
pid->offset = 0;
pid->num_saved_states = 0;
retval = collate(state, wth->fh, err, buf, &num_bytes, &direction, pid);
g_print("Record %u ended with pid offset = 0x%lx num_ss = %d\n",
state->pkt_cnt, pid->offset, pid->num_saved_states);
if (!retval) {
g_free(pid);
return FALSE;
}
pid->dir = direction;
g_ptr_array_add(state->pids, pid);
/* The user's data_offset is not really an offset, but a packet number. */
*data_offset = state->pkt_cnt;
state->pkt_cnt++;
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,
gboolean *state_saved, 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, state_saved);
}
/* 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,
gboolean *state_saved)
{
int c;
int num_bytes = n;
int num_written;
*state_saved = FALSE;
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;
}
*state_saved = TRUE;
}
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, pkt_id *pid)
{
int id;
pkt_t *pkt = NULL;
int n, num_written = 0;
gboolean ss = FALSE;
if (!state->precs) {
state->num_saved_states = 0;
}
if (pid) {
pid->num_saved_states = state->num_saved_states;
}
while (state->precs) {
g_print("I see a saved state.\n");
num_written = process_data_from_prec_state(state, fh, pd, err, &ss, &pkt);
state->num_saved_states++;
if (pid) {
pid->num_saved_states++;
}
if (num_written < 0) {
return FALSE;
}
else if (num_written > 0) {
*num_bytes = num_written;
*direction = pkt->dir;
if (pid) {
pid->offset = pkt->id_offset;
}
if (!ss) {
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, &ss);
if (num_written < 0) {
return FALSE;
}
else if (num_written > 0) {
*num_bytes = num_written;
*direction = pkt->dir;
if (pid) {
pid->offset = pkt->id_offset;
}
if (!ss) {
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;
gboolean retval;
pppdump_t *state;
pkt_id *pid;
int i;
g_print(">>>>>>>>>>>> SEEKING to packet # %d\n", seek_off);
state = wth->capture.generic;
pid = g_ptr_array_index(state->pids, seek_off);
if (!pid) {
return -1;
}
g_print(">>>>>>>>>>>> SEEKING to offset %ld (0x%lx), num_ss=%d\n",
pid->offset, pid->offset, pid->num_saved_states);
file_seek(wth->random_fh, pid->offset, SEEK_SET);
init_state(state->seek_state);
for (i = 0 ; i <= pid->num_saved_states; i++) {
g_print("Loop=%d\n", i);
again:
retval = collate(state->seek_state, wth->random_fh, &err, pd, &num_bytes,
&direction, NULL);
if (!retval) {
return -1;
}
if (direction != pid->dir) {
g_print("Looping because wrong direction.\n");
goto again;
}
g_print("Got right direction.\n");
}
if (len != num_bytes) {
return -1;
}
g_print(">>>>>>>>>>>> COPIED %d bytes\n", num_bytes);
return 0;
}
- Prev by Date: [ethereal-dev] Ethereal Problem Report
- Next by Date: Re: [ethereal-dev] Ethereal Problem Report
- Previous by thread: Re: [ethereal-dev] Ethereal Problem Report
- Next by thread: [ethereal-dev] pppd log support
- Index(es):





