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