3 * Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
5 * SPDX-License-Identifier: GPL-2.0-or-later
11 #include "file_wrappers.h"
17 #include <wsutil/array.h>
18 #include <wsutil/ws_assert.h>
22 Daniel Thompson (STMicroelectronics) <daniel.thompson@st.com>
26 +------+------+------+------+
27 | t3 | t2 | t1 | t0 | t = time_t
28 +------+------+------+------+
31 | 0x06 | Time step (short)
33 | ts | ts = time step (tenths of seconds)
37 | 0x05 | Time step (long)
38 +------+------+------+------+
39 | ts3 | ts2 | ts1 | ts0 | ts = time step (tenths of seconds)
40 +------+------+------+------+
43 | 0x04 | Receive delimiter (not seen in practice)
47 | 0x03 | Send delimiter (not seen in practice)
51 | 0x02 | Received data
53 | n1 | n0 | n = number of bytes following
61 | n1 | n0 | n = number of bytes following
67 #define PPPD_SENT_DATA 0x01
68 #define PPPD_RECV_DATA 0x02
69 #define PPPD_SEND_DELIM 0x03
70 #define PPPD_RECV_DELIM 0x04
71 #define PPPD_TIME_STEP_LONG 0x05
72 #define PPPD_TIME_STEP_SHORT 0x06
73 #define PPPD_RESET_TIME 0x07
75 /* this buffer must be at least (2*PPPD_MTU) + sizeof(ppp_header) +
76 * sizeof(lcp_header) + sizeof(ipcp_header). PPPD_MTU is *very* rarely
77 * larger than 1500 so this value is fine.
79 * It's less than WTAP_MAX_PACKET_SIZE_STANDARD, so we don't have to worry about
82 #define PPPD_BUF_SIZE 8192
89 static bool pppdump_read(wtap
*wth
, wtap_rec
*rec
, Buffer
*buf
,
90 int *err
, char **err_info
, int64_t *data_offset
);
91 static bool pppdump_seek_read(wtap
*wth
, int64_t seek_off
,
92 wtap_rec
*rec
, Buffer
*buf
, int *err
, char **err_info
);
94 static int pppdump_file_type_subtype
= -1;
96 void register_pppdump(void);
99 * Information saved about a packet, during the initial sequential pass
100 * through the file, to allow us to later re-read it when randomly
103 * "offset" is the offset in the file of the first data chunk containing data
104 * from that packet; note that it may also contain data from previous
107 * "num_bytes_to_skip" is the number of bytes from previous packets in that
110 * "dir" is the direction of the packet.
114 int64_t num_bytes_to_skip
;
119 * Information about a packet currently being processed. There is one of
120 * these for the sent packet being processed and one of these for the
121 * received packet being processed, as we could be in the middle of
122 * processing both a received packet and a sent packet.
124 * "dir" is the direction of the packet.
126 * "cnt" is the number of bytes of packet data we've accumulated.
128 * "esc" is true if the next byte we see is escaped (and thus must be XORed
129 * with 0x20 before saving it), false otherwise.
131 * "buf" is a buffer containing the packet data we've accumulated.
133 * "id_offset" is the offset in the file of the first data chunk
134 * containing data from the packet we're processing.
136 * "sd_offset" is the offset in the file of the first data byte from
137 * the packet we're processing - which isn't necessarily right after
138 * the header of the first data chunk, as we may already have assembled
139 * packets from that chunk.
141 * "cd_offset" is the offset in the file of the current data chunk we're
148 uint8_t buf
[PPPD_BUF_SIZE
];
155 * This keeps state used while processing records.
157 * "timestamp" is the seconds portion of the current time stamp value,
158 * as updated from PPPD_RESET_TIME, PPPD_TIME_STEP_LONG, and
159 * PPPD_TIME_STEP_SHORT records. "tenths" is the tenths-of-seconds
162 * "spkt" and "rpkt" are "pkt_t" structures for the sent and received
163 * packets we're currently working on.
165 * "offset" is the current offset in the file.
167 * "num_bytes" and "pkt" are information saved when we finish accumulating
168 * the data for a packet, if the data chunk we're working on still has more
171 * "num_bytes" is the number of bytes of additional data remaining
172 * in the chunk after we've finished accumulating the data for the
175 * "pkt" is the "pkt_t" for the type of packet the data chunk is for
176 * (sent or received packet).
178 * "seek_state" is another state structure used while processing records
179 * when doing a seek-and-read. (That structure doesn't itself have a
180 * "seek_state" structure.)
182 * "pids" is a GPtrArray of pointers to "pkt_id" structures for all the
183 * packets we've seen during the initial sequential pass, to allow us to
184 * later retrieve them with random accesses.
186 * "pkt_cnt" is the number of packets we've seen up to this point in the
189 typedef struct _pppdump_t
{
197 struct _pppdump_t
*seek_state
;
203 process_data(pppdump_t
*state
, FILE_T fh
, pkt_t
*pkt
, int n
, uint8_t *pd
,
204 int *err
, char **err_info
, pkt_id
*pid
);
207 collate(pppdump_t
*state
, FILE_T fh
, int *err
, char **err_info
, uint8_t *pd
,
208 int *num_bytes
, direction_enum
*direction
, pkt_id
*pid
,
209 int64_t num_bytes_to_skip
);
212 pppdump_close(wtap
*wth
);
215 init_state(pppdump_t
*state
)
218 state
->num_bytes
= 0;
221 state
->spkt
.dir
= DIRECTION_SENT
;
223 state
->spkt
.esc
= false;
224 state
->spkt
.id_offset
= 0;
225 state
->spkt
.sd_offset
= 0;
226 state
->spkt
.cd_offset
= 0;
228 state
->rpkt
.dir
= DIRECTION_RECV
;
230 state
->rpkt
.esc
= false;
231 state
->rpkt
.id_offset
= 0;
232 state
->rpkt
.sd_offset
= 0;
233 state
->rpkt
.cd_offset
= 0;
235 state
->seek_state
= NULL
;
236 state
->offset
= 0x100000; /* to detect errors during development */
241 pppdump_open(wtap
*wth
, int *err
, char **err_info
)
243 uint8_t buffer
[6]; /* Looking for: 0x07 t3 t2 t1 t0 ID */
246 /* There is no file header, only packet records. Fortunately for us,
247 * timestamp records are separated from packet records, so we should
248 * find an "initial time stamp" (i.e., a "reset time" record, or
249 * record type 0x07) at the beginning of the file. We'll check for
250 * that, plus a valid record following the 0x07 and the four bytes
251 * representing the timestamp.
254 if (!wtap_read_bytes(wth
->fh
, buffer
, sizeof(buffer
),
256 if (*err
!= WTAP_ERR_SHORT_READ
)
257 return WTAP_OPEN_ERROR
;
258 return WTAP_OPEN_NOT_MINE
;
261 if (buffer
[0] == PPPD_RESET_TIME
&&
262 (buffer
[5] == PPPD_SENT_DATA
||
263 buffer
[5] == PPPD_RECV_DATA
||
264 buffer
[5] == PPPD_TIME_STEP_LONG
||
265 buffer
[5] == PPPD_TIME_STEP_SHORT
||
266 buffer
[5] == PPPD_RESET_TIME
)) {
271 return WTAP_OPEN_NOT_MINE
;
276 if (file_seek(wth
->fh
, 5, SEEK_SET
, err
) == -1)
277 return WTAP_OPEN_ERROR
;
279 state
= g_new(pppdump_t
, 1);
280 wth
->priv
= (void *)state
;
281 state
->timestamp
= pntoh32(&buffer
[1]);
287 wth
->file_encap
= WTAP_ENCAP_PPP_WITH_PHDR
;
288 wth
->file_type_subtype
= pppdump_file_type_subtype
;
290 wth
->snapshot_length
= PPPD_BUF_SIZE
; /* just guessing */
291 wth
->subtype_read
= pppdump_read
;
292 wth
->subtype_seek_read
= pppdump_seek_read
;
293 wth
->subtype_close
= pppdump_close
;
294 wth
->file_tsprec
= WTAP_TSPREC_100_MSEC
;
296 state
->seek_state
= g_new(pppdump_t
,1);
298 /* If we have a random stream open, we're going to be reading
299 the file randomly; set up a GPtrArray of pointers to
300 information about how to retrieve the data for each packet. */
301 if (wth
->random_fh
!= NULL
)
302 state
->pids
= g_ptr_array_new();
308 * Add an IDB; we don't know how many interfaces were
309 * involved, so we just say one interface, about which
310 * we only know the link-layer type, snapshot length,
311 * and time stamp resolution.
313 wtap_add_generated_idb(wth
);
315 return WTAP_OPEN_MINE
;
318 /* Set part of the struct wtap_rec. */
320 pppdump_set_phdr(wtap_rec
*rec
, int num_bytes
,
321 direction_enum direction
)
323 rec
->rec_type
= REC_TYPE_PACKET
;
324 rec
->block
= wtap_block_create(WTAP_BLOCK_PACKET
);
325 rec
->rec_header
.packet_header
.len
= num_bytes
;
326 rec
->rec_header
.packet_header
.caplen
= num_bytes
;
327 rec
->rec_header
.packet_header
.pkt_encap
= WTAP_ENCAP_PPP_WITH_PHDR
;
329 rec
->rec_header
.packet_header
.pseudo_header
.p2p
.sent
= (direction
== DIRECTION_SENT
? true : false);
332 /* Find the next packet and parse it; called from wtap_read(). */
334 pppdump_read(wtap
*wth
, wtap_rec
*rec
, Buffer
*buf
, int *err
, char **err_info
,
335 int64_t *data_offset
)
338 direction_enum direction
;
342 state
= (pppdump_t
*)wth
->priv
;
344 /* If we have a random stream open, allocate a structure to hold
345 the information needed to read this packet's data again. */
346 if (wth
->random_fh
!= NULL
) {
347 pid
= g_new(pkt_id
, 1);
349 *err
= errno
; /* assume a malloc failed and set "errno" */
354 pid
= NULL
; /* sequential only */
356 ws_buffer_assure_space(buf
, PPPD_BUF_SIZE
);
357 if (!collate(state
, wth
->fh
, err
, err_info
, ws_buffer_start_ptr(buf
),
358 &num_bytes
, &direction
, pid
, 0)) {
364 pid
->dir
= direction
;
367 g_ptr_array_add(state
->pids
, pid
);
368 /* The user's data_offset is not really an offset, but a packet number. */
369 *data_offset
= state
->pkt_cnt
;
372 pppdump_set_phdr(rec
, num_bytes
, direction
);
373 rec
->presence_flags
= WTAP_HAS_TS
;
374 rec
->ts
.secs
= state
->timestamp
;
375 rec
->ts
.nsecs
= state
->tenths
* 100000000;
380 /* Returns number of bytes copied for record, -1 if failure.
382 * This is modeled after pppdump.c, the utility to parse pppd log files; it
383 * comes with the ppp distribution.
386 process_data(pppdump_t
*state
, FILE_T fh
, pkt_t
*pkt
, int n
, uint8_t *pd
,
387 int *err
, char **err_info
, pkt_id
*pid
)
393 for (; num_bytes
> 0; --num_bytes
) {
396 *err
= file_error(fh
, err_info
);
398 *err
= WTAP_ERR_SHORT_READ
;
406 * Flag Sequence for RFC 1662 HDLC-like
409 * As this is a raw trace of octets going
410 * over the wire, and that might include
411 * the login sequence, there is no
412 * guarantee that *only* PPP traffic
413 * appears in this file, so there is no
414 * guarantee that the first 0x7e we see is
415 * a start flag sequence, and therefore we
416 * cannot safely ignore all characters up
417 * to the first 0x7e, and therefore we
418 * might end up with some bogus PPP
423 * We've seen stuff before this,
424 * so this is the end of a frame.
425 * Make a frame out of that stuff.
429 num_written
= pkt
->cnt
;
431 if (num_written
<= 0) {
435 if (num_written
> PPPD_BUF_SIZE
) {
436 *err
= WTAP_ERR_BAD_FILE
;
437 *err_info
= ws_strdup_printf("pppdump: File has %u-byte packet, bigger than maximum of %u",
438 num_written
, PPPD_BUF_SIZE
);
442 memcpy(pd
, pkt
->buf
, num_written
);
445 * Remember the offset of the
446 * first record containing data
447 * for this packet, and how far
448 * into that record to skip to
449 * get to the beginning of the
450 * data for this packet; the number
451 * of bytes to skip into that record
452 * is the file offset of the first
453 * byte of this packet minus the
454 * file offset of the first byte of
455 * this record, minus 3 bytes for the
456 * header of this record (which, if
457 * we re-read this record, we will
458 * process, not skip).
461 pid
->offset
= pkt
->id_offset
;
462 pid
->num_bytes_to_skip
=
463 pkt
->sd_offset
- pkt
->id_offset
- 3;
464 ws_assert(pid
->num_bytes_to_skip
>= 0);
470 * There's more data in this
472 * Set the initial data offset
473 * for the next packet.
475 pkt
->id_offset
= pkt
->cd_offset
;
476 pkt
->sd_offset
= state
->offset
;
479 * There is no more data in
481 * Thus, we don't have the
482 * initial data offset for
488 state
->num_bytes
= num_bytes
;
496 * Control Escape octet for octet-stuffed
497 * RFC 1662 HDLC-like framing.
501 * Control Escape not preceded by
502 * Control Escape; discard it
503 * but XOR the next octet with
510 * Control Escape preceded by Control Escape;
511 * treat it as an ordinary character,
512 * by falling through.
519 * This character was preceded by
520 * Control Escape, so XOR it with
521 * 0x20, as per RFC 1662's octet-
522 * stuffed framing, and clear
523 * the flag saying that the
524 * character should be escaped.
530 if (pkt
->cnt
>= PPPD_BUF_SIZE
) {
531 *err
= WTAP_ERR_BAD_FILE
;
532 *err_info
= ws_strdup_printf("pppdump: File has %u-byte packet, bigger than maximum of %u",
533 pkt
->cnt
- 1, PPPD_BUF_SIZE
);
536 pkt
->buf
[pkt
->cnt
++] = c
;
541 /* we could have run out of bytes to read */
545 /* Returns true if packet data copied, false if error occurred or EOF (no more records). */
547 collate(pppdump_t
* state
, FILE_T fh
, int *err
, char **err_info
, uint8_t *pd
,
548 int *num_bytes
, direction_enum
*direction
, pkt_id
*pid
,
549 int64_t num_bytes_to_skip
)
554 int n
, num_written
= 0;
555 int64_t start_offset
;
560 * Process any data left over in the current record when doing
561 * sequential processing.
563 if (state
->num_bytes
> 0) {
564 ws_assert(num_bytes_to_skip
== 0);
566 num_written
= process_data(state
, fh
, pkt
, state
->num_bytes
,
567 pd
, err
, err_info
, pid
);
569 if (num_written
< 0) {
572 else if (num_written
> 0) {
573 *num_bytes
= num_written
;
574 *direction
= pkt
->dir
;
577 /* if 0 bytes written, keep processing */
580 * We didn't have any data left over, so the packet will
581 * start at the beginning of a record.
584 pid
->num_bytes_to_skip
= 0;
588 * That didn't get all the data for this packet, so process
589 * subsequent records.
591 start_offset
= state
->offset
;
592 while ((id
= file_getc(fh
)) != EOF
) {
597 pkt
= id
== PPPD_SENT_DATA
? &state
->spkt
: &state
->rpkt
;
600 * Save the offset of the beginning of
601 * the current record.
603 pkt
->cd_offset
= state
->offset
- 1;
606 * Get the length of the record.
608 byte0
= file_getc(fh
);
612 byte1
= file_getc(fh
);
616 n
= (byte0
<< 8) | byte1
;
618 if (pkt
->id_offset
== 0) {
620 * We don't have the initial data
621 * offset for this packet, which
622 * means this is the first
623 * data record for that packet.
624 * Save the offset of the
625 * beginning of that record and
626 * the offset of the first data
627 * byte in the packet, which is
628 * the first data byte in the
631 pkt
->id_offset
= pkt
->cd_offset
;
632 pkt
->sd_offset
= state
->offset
;
638 ws_assert(num_bytes_to_skip
< n
);
639 while (num_bytes_to_skip
) {
640 if (file_getc(fh
) == EOF
)
646 num_written
= process_data(state
, fh
, pkt
, n
,
647 pd
, err
, err_info
, pid
);
649 if (num_written
< 0) {
652 else if (num_written
> 0) {
653 *num_bytes
= num_written
;
654 *direction
= pkt
->dir
;
657 /* if 0 bytes written, keep looping */
660 case PPPD_SEND_DELIM
:
661 case PPPD_RECV_DELIM
:
662 /* What can we do? */
665 case PPPD_RESET_TIME
:
666 if (!wtap_read_bytes(fh
, &time_long
, sizeof(uint32_t), err
, err_info
))
668 state
->offset
+= sizeof(uint32_t);
669 state
->timestamp
= pntoh32(&time_long
);
673 case PPPD_TIME_STEP_LONG
:
674 if (!wtap_read_bytes(fh
, &time_long
, sizeof(uint32_t), err
, err_info
))
676 state
->offset
+= sizeof(uint32_t);
677 state
->tenths
+= pntoh32(&time_long
);
679 if (state
->tenths
>= 10) {
680 state
->timestamp
+= state
->tenths
/ 10;
681 state
->tenths
= state
->tenths
% 10;
686 case PPPD_TIME_STEP_SHORT
:
687 if (!wtap_read_bytes(fh
, &time_short
, sizeof(uint8_t), err
, err_info
))
689 state
->offset
+= sizeof(uint8_t);
690 state
->tenths
+= time_short
;
692 if (state
->tenths
>= 10) {
693 state
->timestamp
+= state
->tenths
/ 10;
694 state
->tenths
= state
->tenths
% 10;
701 *err
= WTAP_ERR_BAD_FILE
;
702 *err_info
= ws_strdup_printf("pppdump: bad ID byte 0x%02x", id
);
709 *err
= file_error(fh
, err_info
);
711 if (state
->offset
!= start_offset
) {
713 * We read at least one byte, so we were working
714 * on a record; an EOF means that record was
717 *err
= WTAP_ERR_SHORT_READ
;
725 /* Used to read packets in random-access fashion */
727 pppdump_seek_read(wtap
*wth
,
736 direction_enum direction
;
739 int64_t num_bytes_to_skip
;
741 state
= (pppdump_t
*)wth
->priv
;
743 pid
= (pkt_id
*)g_ptr_array_index(state
->pids
, seek_off
);
745 *err
= WTAP_ERR_BAD_FILE
; /* XXX - better error? */
746 *err_info
= g_strdup("pppdump: PID not found for record");
750 if (file_seek(wth
->random_fh
, pid
->offset
, SEEK_SET
, err
) == -1)
753 init_state(state
->seek_state
);
754 state
->seek_state
->offset
= pid
->offset
;
756 ws_buffer_assure_space(buf
, PPPD_BUF_SIZE
);
757 pd
= ws_buffer_start_ptr(buf
);
760 * We'll start reading at the first record containing data from
761 * this packet; however, that doesn't mean "collate()" will
762 * stop only when we've read that packet, as there might be
763 * data for packets going in the other direction as well, and
764 * we might finish processing one of those packets before we
765 * finish processing the packet we're reading.
767 * Therefore, we keep reading until we get a packet that's
768 * going in the direction we want.
770 num_bytes_to_skip
= pid
->num_bytes_to_skip
;
772 if (!collate(state
->seek_state
, wth
->random_fh
, err
, err_info
,
773 pd
, &num_bytes
, &direction
, NULL
, num_bytes_to_skip
))
775 num_bytes_to_skip
= 0;
776 } while (direction
!= pid
->dir
);
778 pppdump_set_phdr(rec
, num_bytes
, pid
->dir
);
784 pppdump_close(wtap
*wth
)
788 state
= (pppdump_t
*)wth
->priv
;
790 if (state
->seek_state
) { /* should always be true */
791 g_free(state
->seek_state
);
796 for (i
= 0; i
< g_ptr_array_len(state
->pids
); i
++) {
797 g_free(g_ptr_array_index(state
->pids
, i
));
799 g_ptr_array_free(state
->pids
, true);
803 static const struct supported_block_type pppdump_blocks_supported
[] = {
805 * We support packet blocks, with no comments or other options.
807 { WTAP_BLOCK_PACKET
, MULTIPLE_BLOCKS_SUPPORTED
, NO_OPTIONS_SUPPORTED
}
810 static const struct file_type_subtype_info pppdump_info
= {
811 "pppd log (pppdump format)", "pppd", NULL
, NULL
,
812 false, BLOCKS_SUPPORTED(pppdump_blocks_supported
),
816 void register_pppdump(void)
818 pppdump_file_type_subtype
= wtap_register_file_type_subtype(&pppdump_info
);
821 * Register name for backwards compatibility with the
822 * wtap_filetypes table in Lua.
824 wtap_register_backwards_compatibility_lua_name("PPPDUMP",
825 pppdump_file_type_subtype
);
829 * Editor modelines - https://www.wireshark.org/tools/modelines.html
834 * indent-tabs-mode: t
837 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
838 * :indentSize=8:tabSize=8:noTabs=false: