1/*
2 * pppdump - print out the contents of a record file generated by
3 * pppd in readable form.
4 *
5 * Copyright (c) 1999 Paul Mackerras. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in
16 *    the documentation and/or other materials provided with the
17 *    distribution.
18 *
19 * 3. The name(s) of the authors of this software must not be used to
20 *    endorse or promote products derived from this software without
21 *    prior written permission.
22 *
23 * 4. Redistributions of any form whatsoever must retain the following
24 *    acknowledgment:
25 *    "This product includes software developed by Paul Mackerras
26 *     <paulus@samba.org>".
27 *
28 * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
29 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
30 * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
31 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
32 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
33 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
34 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
35 */
36#include <stdio.h>
37#include <unistd.h>
38#include <stdlib.h>
39#include <time.h>
40#include <sys/types.h>
41#include "ppp_defs.h"
42#include "ppp-comp.h"
43
44int hexmode;
45int pppmode;
46int reverse;
47int decompress;
48int mru = 1500;
49int abs_times;
50time_t start_time;
51int start_time_tenths;
52int tot_sent, tot_rcvd;
53
54extern int optind;
55extern char *optarg;
56
57void dumplog();
58void dumpppp();
59void show_time();
60void handle_ccp();
61
62int
63main(ac, av)
64    int ac;
65    char **av;
66{
67    int i;
68    char *p;
69    FILE *f;
70
71    while ((i = getopt(ac, av, "hprdm:a")) != -1) {
72	switch (i) {
73	case 'h':
74	    hexmode = 1;
75	    break;
76	case 'p':
77	    pppmode = 1;
78	    break;
79	case 'r':
80	    reverse = 1;
81	    break;
82	case 'd':
83	    decompress = 1;
84	    break;
85	case 'm':
86	    mru = atoi(optarg);
87	    break;
88	case 'a':
89	    abs_times = 1;
90	    break;
91	default:
92	    fprintf(stderr, "Usage: %s [-h | -p[d]] [-r] [-m mru] [-a] [file ...]\n", av[0]);
93	    exit(1);
94	}
95    }
96    if (optind >= ac)
97	dumplog(stdin);
98    else {
99	for (i = optind; i < ac; ++i) {
100	    p = av[i];
101	    if ((f = fopen(p, "r")) == NULL) {
102		perror(p);
103		exit(1);
104	    }
105	    if (pppmode)
106		dumpppp(f);
107	    else
108		dumplog(f);
109	    fclose(f);
110	}
111    }
112    exit(0);
113}
114
115void
116dumplog(f)
117    FILE *f;
118{
119    int c, n, k, col;
120    int nb, c2;
121    unsigned char buf[16];
122
123    while ((c = getc(f)) != EOF) {
124	switch (c) {
125	case 1:
126	case 2:
127	    if (reverse)
128		c = 3 - c;
129	    printf("%s %c", c==1? "sent": "rcvd", hexmode? ' ': '"');
130	    col = 6;
131	    n = getc(f);
132	    n = (n << 8) + getc(f);
133	    *(c==1? &tot_sent: &tot_rcvd) += n;
134	    nb = 0;
135	    for (; n > 0; --n) {
136		c = getc(f);
137		if (c == EOF) {
138		    printf("\nEOF\n");
139		    exit(0);
140		}
141		if (hexmode) {
142		    if (nb >= 16) {
143			printf("  ");
144			for (k = 0; k < nb; ++k) {
145			    c2 = buf[k];
146			    putchar((' ' <= c2 && c2 <= '~')? c2: '.');
147			}
148			printf("\n      ");
149			nb = 0;
150		    }
151		    buf[nb++] = c;
152		    printf(" %.2x", c);
153		} else {
154		    k = (' ' <= c && c <= '~')? (c != '\\' && c != '"')? 1: 2: 3;
155		    if ((col += k) >= 78) {
156			printf("\n      ");
157			col = 6 + k;
158		    }
159		    switch (k) {
160		    case 1:
161			putchar(c);
162			break;
163		    case 2:
164			printf("\\%c", c);
165			break;
166		    case 3:
167			printf("\\%.2x", c);
168			break;
169		    }
170		}
171	    }
172	    if (hexmode) {
173		for (k = nb; k < 16; ++k)
174		    printf("   ");
175		printf("  ");
176		for (k = 0; k < nb; ++k) {
177		    c2 = buf[k];
178		    putchar((' ' <= c2 && c2 <= '~')? c2: '.');
179		}
180	    } else
181		putchar('"');
182	    printf("\n");
183	    break;
184	case 3:
185	case 4:
186	    printf("end %s\n", c==3? "send": "recv");
187	    break;
188	case 5:
189	case 6:
190	case 7:
191	    show_time(f, c);
192	    break;
193	default:
194	    printf("?%.2x\n");
195	}
196    }
197}
198
199/*
200 * FCS lookup table as calculated by genfcstab.
201 */
202static u_short fcstab[256] = {
203	0x0000,	0x1189,	0x2312,	0x329b,	0x4624,	0x57ad,	0x6536,	0x74bf,
204	0x8c48,	0x9dc1,	0xaf5a,	0xbed3,	0xca6c,	0xdbe5,	0xe97e,	0xf8f7,
205	0x1081,	0x0108,	0x3393,	0x221a,	0x56a5,	0x472c,	0x75b7,	0x643e,
206	0x9cc9,	0x8d40,	0xbfdb,	0xae52,	0xdaed,	0xcb64,	0xf9ff,	0xe876,
207	0x2102,	0x308b,	0x0210,	0x1399,	0x6726,	0x76af,	0x4434,	0x55bd,
208	0xad4a,	0xbcc3,	0x8e58,	0x9fd1,	0xeb6e,	0xfae7,	0xc87c,	0xd9f5,
209	0x3183,	0x200a,	0x1291,	0x0318,	0x77a7,	0x662e,	0x54b5,	0x453c,
210	0xbdcb,	0xac42,	0x9ed9,	0x8f50,	0xfbef,	0xea66,	0xd8fd,	0xc974,
211	0x4204,	0x538d,	0x6116,	0x709f,	0x0420,	0x15a9,	0x2732,	0x36bb,
212	0xce4c,	0xdfc5,	0xed5e,	0xfcd7,	0x8868,	0x99e1,	0xab7a,	0xbaf3,
213	0x5285,	0x430c,	0x7197,	0x601e,	0x14a1,	0x0528,	0x37b3,	0x263a,
214	0xdecd,	0xcf44,	0xfddf,	0xec56,	0x98e9,	0x8960,	0xbbfb,	0xaa72,
215	0x6306,	0x728f,	0x4014,	0x519d,	0x2522,	0x34ab,	0x0630,	0x17b9,
216	0xef4e,	0xfec7,	0xcc5c,	0xddd5,	0xa96a,	0xb8e3,	0x8a78,	0x9bf1,
217	0x7387,	0x620e,	0x5095,	0x411c,	0x35a3,	0x242a,	0x16b1,	0x0738,
218	0xffcf,	0xee46,	0xdcdd,	0xcd54,	0xb9eb,	0xa862,	0x9af9,	0x8b70,
219	0x8408,	0x9581,	0xa71a,	0xb693,	0xc22c,	0xd3a5,	0xe13e,	0xf0b7,
220	0x0840,	0x19c9,	0x2b52,	0x3adb,	0x4e64,	0x5fed,	0x6d76,	0x7cff,
221	0x9489,	0x8500,	0xb79b,	0xa612,	0xd2ad,	0xc324,	0xf1bf,	0xe036,
222	0x18c1,	0x0948,	0x3bd3,	0x2a5a,	0x5ee5,	0x4f6c,	0x7df7,	0x6c7e,
223	0xa50a,	0xb483,	0x8618,	0x9791,	0xe32e,	0xf2a7,	0xc03c,	0xd1b5,
224	0x2942,	0x38cb,	0x0a50,	0x1bd9,	0x6f66,	0x7eef,	0x4c74,	0x5dfd,
225	0xb58b,	0xa402,	0x9699,	0x8710,	0xf3af,	0xe226,	0xd0bd,	0xc134,
226	0x39c3,	0x284a,	0x1ad1,	0x0b58,	0x7fe7,	0x6e6e,	0x5cf5,	0x4d7c,
227	0xc60c,	0xd785,	0xe51e,	0xf497,	0x8028,	0x91a1,	0xa33a,	0xb2b3,
228	0x4a44,	0x5bcd,	0x6956,	0x78df,	0x0c60,	0x1de9,	0x2f72,	0x3efb,
229	0xd68d,	0xc704,	0xf59f,	0xe416,	0x90a9,	0x8120,	0xb3bb,	0xa232,
230	0x5ac5,	0x4b4c,	0x79d7,	0x685e,	0x1ce1,	0x0d68,	0x3ff3,	0x2e7a,
231	0xe70e,	0xf687,	0xc41c,	0xd595,	0xa12a,	0xb0a3,	0x8238,	0x93b1,
232	0x6b46,	0x7acf,	0x4854,	0x59dd,	0x2d62,	0x3ceb,	0x0e70,	0x1ff9,
233	0xf78f,	0xe606,	0xd49d,	0xc514,	0xb1ab,	0xa022,	0x92b9,	0x8330,
234	0x7bc7,	0x6a4e,	0x58d5,	0x495c,	0x3de3,	0x2c6a,	0x1ef1,	0x0f78
235};
236
237struct pkt {
238    int	cnt;
239    int	esc;
240    int	flags;
241    struct compressor *comp;
242    void *state;
243    unsigned char buf[8192];
244} spkt, rpkt;
245
246/* Values for flags */
247#define CCP_ISUP	1
248#define CCP_ERROR	2
249#define CCP_FATALERROR	4
250#define CCP_ERR		(CCP_ERROR | CCP_FATALERROR)
251#define CCP_DECOMP_RUN	8
252
253unsigned char dbuf[8192];
254
255void
256dumpppp(f)
257    FILE *f;
258{
259    int c, n, k;
260    int nb, nl, dn, proto, rv;
261    char *dir, *q;
262    unsigned char *p, *r, *endp;
263    unsigned char *d;
264    unsigned short fcs;
265    struct pkt *pkt;
266
267    spkt.cnt = rpkt.cnt = 0;
268    spkt.esc = rpkt.esc = 0;
269    while ((c = getc(f)) != EOF) {
270	switch (c) {
271	case 1:
272	case 2:
273	    if (reverse)
274		c = 3 - c;
275	    dir = c==1? "sent": "rcvd";
276	    pkt = c==1? &spkt: &rpkt;
277	    n = getc(f);
278	    n = (n << 8) + getc(f);
279	    *(c==1? &tot_sent: &tot_rcvd) += n;
280	    for (; n > 0; --n) {
281		c = getc(f);
282		switch (c) {
283		case EOF:
284		    printf("\nEOF\n");
285		    if (spkt.cnt > 0)
286			printf("[%d bytes in incomplete send packet]\n",
287			       spkt.cnt);
288		    if (rpkt.cnt > 0)
289			printf("[%d bytes in incomplete recv packet]\n",
290			       rpkt.cnt);
291		    exit(0);
292		case '~':
293		    if (pkt->cnt > 0) {
294			q = dir;
295			if (pkt->esc) {
296			    printf("%s aborted packet:\n     ", dir);
297			    q = "    ";
298			}
299			nb = pkt->cnt;
300			p = pkt->buf;
301			pkt->cnt = 0;
302			pkt->esc = 0;
303			if (nb <= 2) {
304			    printf("%s short packet [%d bytes]:", q, nb);
305			    for (k = 0; k < nb; ++k)
306				printf(" %.2x", p[k]);
307			    printf("\n");
308			    break;
309			}
310			fcs = PPP_INITFCS;
311			for (k = 0; k < nb; ++k)
312			    fcs = PPP_FCS(fcs, p[k]);
313			fcs &= 0xFFFF;
314			nb -= 2;
315			endp = p + nb;
316			r = p;
317			if (r[0] == 0xff && r[1] == 3)
318			    r += 2;
319			if ((r[0] & 1) == 0)
320			    ++r;
321			++r;
322			if (endp - r > mru)
323			    printf("     ERROR: length (%d) > MRU (%d)\n",
324				   endp - r, mru);
325			if (decompress && fcs == PPP_GOODFCS) {
326			    /* See if this is a CCP or compressed packet */
327			    d = dbuf;
328			    r = p;
329			    if (r[0] == 0xff && r[1] == 3) {
330				*d++ = *r++;
331				*d++ = *r++;
332			    }
333			    proto = r[0];
334			    if ((proto & 1) == 0)
335				proto = (proto << 8) + r[1];
336			    if (proto == PPP_CCP) {
337				handle_ccp(pkt, r + 2, endp - r - 2);
338			    } else if (proto == PPP_COMP) {
339				if ((pkt->flags & CCP_ISUP)
340				    && (pkt->flags & CCP_DECOMP_RUN)
341				    && pkt->state
342				    && (pkt->flags & CCP_ERR) == 0) {
343				    rv = pkt->comp->decompress(pkt->state, r,
344							endp - r, d, &dn);
345				    switch (rv) {
346				    case DECOMP_OK:
347					p = dbuf;
348					nb = d + dn - p;
349					if ((d[0] & 1) == 0)
350					    --dn;
351					--dn;
352					if (dn > mru)
353					    printf("     ERROR: decompressed length (%d) > MRU (%d)\n", dn, mru);
354					break;
355				    case DECOMP_ERROR:
356					printf("     DECOMPRESSION ERROR\n");
357					pkt->flags |= CCP_ERROR;
358					break;
359				    case DECOMP_FATALERROR:
360					printf("     FATAL DECOMPRESSION ERROR\n");
361					pkt->flags |= CCP_FATALERROR;
362					break;
363				    }
364				}
365			    } else if (pkt->state
366				       && (pkt->flags & CCP_DECOMP_RUN)) {
367				pkt->comp->incomp(pkt->state, r, endp - r);
368			    }
369			}
370			do {
371			    nl = nb < 16? nb: 16;
372			    printf("%s ", q);
373			    for (k = 0; k < nl; ++k)
374				printf(" %.2x", p[k]);
375			    for (; k < 16; ++k)
376				printf("   ");
377			    printf("  ");
378			    for (k = 0; k < nl; ++k) {
379				c = p[k];
380				putchar((' ' <= c && c <= '~')? c: '.');
381			    }
382			    printf("\n");
383			    q = "    ";
384			    p += nl;
385			    nb -= nl;
386			} while (nb > 0);
387			if (fcs != PPP_GOODFCS)
388			    printf("     BAD FCS: (residue = %x)\n", fcs);
389		    }
390		    break;
391		case '}':
392		    if (!pkt->esc) {
393			pkt->esc = 1;
394			break;
395		    }
396		    /* else fall through */
397		default:
398		    if (pkt->esc) {
399			c ^= 0x20;
400			pkt->esc = 0;
401		    }
402		    pkt->buf[pkt->cnt++] = c;
403		    break;
404		}
405	    }
406	    break;
407	case 3:
408	case 4:
409	    if (reverse)
410		c = 7 - c;
411	    dir = c==3? "send": "recv";
412	    pkt = c==3? &spkt: &rpkt;
413	    printf("end %s", dir);
414	    if (pkt->cnt > 0)
415		printf("  [%d bytes in incomplete packet]", pkt->cnt);
416	    printf("\n");
417	    break;
418	case 5:
419	case 6:
420	case 7:
421	    show_time(f, c);
422	    break;
423	default:
424	    printf("?%.2x\n");
425	}
426    }
427}
428
429extern struct compressor ppp_bsd_compress, ppp_deflate;
430
431struct compressor *compressors[] = {
432#if DO_BSD_COMPRESS
433    &ppp_bsd_compress,
434#endif
435#if DO_DEFLATE
436    &ppp_deflate,
437#endif
438    NULL
439};
440
441void
442handle_ccp(cp, dp, len)
443    struct pkt *cp;
444    u_char *dp;
445    int len;
446{
447    int clen;
448    struct compressor **comp;
449
450    if (len < CCP_HDRLEN)
451	return;
452    clen = CCP_LENGTH(dp);
453    if (clen > len)
454	return;
455
456    switch (CCP_CODE(dp)) {
457    case CCP_CONFACK:
458	cp->flags &= ~(CCP_DECOMP_RUN | CCP_ISUP);
459	if (clen < CCP_HDRLEN + CCP_OPT_MINLEN
460	    || clen < CCP_HDRLEN + CCP_OPT_LENGTH(dp + CCP_HDRLEN))
461	    break;
462	dp += CCP_HDRLEN;
463	clen -= CCP_HDRLEN;
464	for (comp = compressors; *comp != NULL; ++comp) {
465	    if ((*comp)->compress_proto == dp[0]) {
466		if (cp->state != NULL) {
467		    (*cp->comp->decomp_free)(cp->state);
468		    cp->state = NULL;
469		}
470		cp->comp = *comp;
471		cp->state = (*comp)->decomp_alloc(dp, CCP_OPT_LENGTH(dp));
472		cp->flags |= CCP_ISUP;
473		if (cp->state != NULL
474		    && (*cp->comp->decomp_init)
475		        (cp->state, dp, clen, 0, 0, 8192, 1))
476		    cp->flags = (cp->flags & ~CCP_ERR) | CCP_DECOMP_RUN;
477		break;
478	    }
479	}
480	break;
481
482    case CCP_CONFNAK:
483    case CCP_CONFREJ:
484	cp->flags &= ~(CCP_DECOMP_RUN | CCP_ISUP);
485	break;
486
487    case CCP_RESETACK:
488	if (cp->flags & CCP_ISUP) {
489	    if (cp->state && (cp->flags & CCP_DECOMP_RUN)) {
490		(*cp->comp->decomp_reset)(cp->state);
491		cp->flags &= ~CCP_ERROR;
492	    }
493	}
494	break;
495    }
496}
497
498void
499show_time(f, c)
500    FILE *f;
501    int c;
502{
503    time_t t;
504    int n;
505    struct tm *tm;
506
507    if (c == 7) {
508	t = getc(f);
509	t = (t << 8) + getc(f);
510	t = (t << 8) + getc(f);
511	t = (t << 8) + getc(f);
512	printf("start %s", ctime(&t));
513	start_time = t;
514	start_time_tenths = 0;
515	tot_sent = tot_rcvd = 0;
516    } else {
517	n = getc(f);
518	if (c == 5) {
519	    for (c = 3; c > 0; --c)
520		n = (n << 8) + getc(f);
521	}
522	if (abs_times) {
523	    n += start_time_tenths;
524	    start_time += n / 10;
525	    start_time_tenths = n % 10;
526	    tm = localtime(&start_time);
527	    printf("time  %.2d:%.2d:%.2d.%d", tm->tm_hour, tm->tm_min,
528		   tm->tm_sec, start_time_tenths);
529	    printf("  (sent %d, rcvd %d)\n", tot_sent, tot_rcvd);
530	} else
531	    printf("time  %.1fs\n", (double) n / 10);
532    }
533}
534