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