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 <stdlib.h>
38#include <unistd.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(FILE *);
58void dumpppp(FILE *);
59void show_time(FILE *, int);
60
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 dumplog(f)
116    FILE *f;
117{
118    int c, n, k, col;
119    int nb, c2;
120    unsigned char buf[16];
121
122    while ((c = getc(f)) != EOF) {
123	switch (c) {
124	case 1:
125	case 2:
126	    if (reverse)
127		c = 3 - c;
128	    printf("%s %c", c==1? "sent": "rcvd", hexmode? ' ': '"');
129	    col = 6;
130	    n = getc(f);
131	    n = (n << 8) + getc(f);
132	    *(c==1? &tot_sent: &tot_rcvd) += n;
133	    nb = 0;
134	    for (; n > 0; --n) {
135		c = getc(f);
136		if (c == EOF) {
137		    printf("\nEOF\n");
138		    exit(0);
139		}
140		if (hexmode) {
141		    if (nb >= 16) {
142			printf("  ");
143			for (k = 0; k < nb; ++k) {
144			    c2 = buf[k];
145			    putchar((' ' <= c2 && c2 <= '~')? c2: '.');
146			}
147			printf("\n      ");
148			nb = 0;
149		    }
150		    buf[nb++] = c;
151		    printf(" %.2x", c);
152		} else {
153		    k = (' ' <= c && c <= '~')? (c != '\\' && c != '"')? 1: 2: 3;
154		    if ((col += k) >= 78) {
155			printf("\n      ");
156			col = 6 + k;
157		    }
158		    switch (k) {
159		    case 1:
160			putchar(c);
161			break;
162		    case 2:
163			printf("\\%c", c);
164			break;
165		    case 3:
166			printf("\\%.2x", c);
167			break;
168		    }
169		}
170	    }
171	    if (hexmode) {
172		for (k = nb; k < 16; ++k)
173		    printf("   ");
174		printf("  ");
175		for (k = 0; k < nb; ++k) {
176		    c2 = buf[k];
177		    putchar((' ' <= c2 && c2 <= '~')? c2: '.');
178		}
179	    } else
180		putchar('"');
181	    printf("\n");
182	    break;
183	case 3:
184	case 4:
185	    printf("end %s\n", c==3? "send": "recv");
186	    break;
187	case 5:
188	case 6:
189	case 7:
190	    show_time(f, c);
191	    break;
192	default:
193	    printf("?%.2x\n", c);
194	}
195    }
196}
197
198/*
199 * FCS lookup table as calculated by genfcstab.
200 */
201static u_short fcstab[256] = {
202	0x0000,	0x1189,	0x2312,	0x329b,	0x4624,	0x57ad,	0x6536,	0x74bf,
203	0x8c48,	0x9dc1,	0xaf5a,	0xbed3,	0xca6c,	0xdbe5,	0xe97e,	0xf8f7,
204	0x1081,	0x0108,	0x3393,	0x221a,	0x56a5,	0x472c,	0x75b7,	0x643e,
205	0x9cc9,	0x8d40,	0xbfdb,	0xae52,	0xdaed,	0xcb64,	0xf9ff,	0xe876,
206	0x2102,	0x308b,	0x0210,	0x1399,	0x6726,	0x76af,	0x4434,	0x55bd,
207	0xad4a,	0xbcc3,	0x8e58,	0x9fd1,	0xeb6e,	0xfae7,	0xc87c,	0xd9f5,
208	0x3183,	0x200a,	0x1291,	0x0318,	0x77a7,	0x662e,	0x54b5,	0x453c,
209	0xbdcb,	0xac42,	0x9ed9,	0x8f50,	0xfbef,	0xea66,	0xd8fd,	0xc974,
210	0x4204,	0x538d,	0x6116,	0x709f,	0x0420,	0x15a9,	0x2732,	0x36bb,
211	0xce4c,	0xdfc5,	0xed5e,	0xfcd7,	0x8868,	0x99e1,	0xab7a,	0xbaf3,
212	0x5285,	0x430c,	0x7197,	0x601e,	0x14a1,	0x0528,	0x37b3,	0x263a,
213	0xdecd,	0xcf44,	0xfddf,	0xec56,	0x98e9,	0x8960,	0xbbfb,	0xaa72,
214	0x6306,	0x728f,	0x4014,	0x519d,	0x2522,	0x34ab,	0x0630,	0x17b9,
215	0xef4e,	0xfec7,	0xcc5c,	0xddd5,	0xa96a,	0xb8e3,	0x8a78,	0x9bf1,
216	0x7387,	0x620e,	0x5095,	0x411c,	0x35a3,	0x242a,	0x16b1,	0x0738,
217	0xffcf,	0xee46,	0xdcdd,	0xcd54,	0xb9eb,	0xa862,	0x9af9,	0x8b70,
218	0x8408,	0x9581,	0xa71a,	0xb693,	0xc22c,	0xd3a5,	0xe13e,	0xf0b7,
219	0x0840,	0x19c9,	0x2b52,	0x3adb,	0x4e64,	0x5fed,	0x6d76,	0x7cff,
220	0x9489,	0x8500,	0xb79b,	0xa612,	0xd2ad,	0xc324,	0xf1bf,	0xe036,
221	0x18c1,	0x0948,	0x3bd3,	0x2a5a,	0x5ee5,	0x4f6c,	0x7df7,	0x6c7e,
222	0xa50a,	0xb483,	0x8618,	0x9791,	0xe32e,	0xf2a7,	0xc03c,	0xd1b5,
223	0x2942,	0x38cb,	0x0a50,	0x1bd9,	0x6f66,	0x7eef,	0x4c74,	0x5dfd,
224	0xb58b,	0xa402,	0x9699,	0x8710,	0xf3af,	0xe226,	0xd0bd,	0xc134,
225	0x39c3,	0x284a,	0x1ad1,	0x0b58,	0x7fe7,	0x6e6e,	0x5cf5,	0x4d7c,
226	0xc60c,	0xd785,	0xe51e,	0xf497,	0x8028,	0x91a1,	0xa33a,	0xb2b3,
227	0x4a44,	0x5bcd,	0x6956,	0x78df,	0x0c60,	0x1de9,	0x2f72,	0x3efb,
228	0xd68d,	0xc704,	0xf59f,	0xe416,	0x90a9,	0x8120,	0xb3bb,	0xa232,
229	0x5ac5,	0x4b4c,	0x79d7,	0x685e,	0x1ce1,	0x0d68,	0x3ff3,	0x2e7a,
230	0xe70e,	0xf687,	0xc41c,	0xd595,	0xa12a,	0xb0a3,	0x8238,	0x93b1,
231	0x6b46,	0x7acf,	0x4854,	0x59dd,	0x2d62,	0x3ceb,	0x0e70,	0x1ff9,
232	0xf78f,	0xe606,	0xd49d,	0xc514,	0xb1ab,	0xa022,	0x92b9,	0x8330,
233	0x7bc7,	0x6a4e,	0x58d5,	0x495c,	0x3de3,	0x2c6a,	0x1ef1,	0x0f78
234};
235
236struct pkt {
237    int	cnt;
238    int	esc;
239    int	flags;
240    struct compressor *comp;
241    void *state;
242    unsigned char buf[8192];
243} spkt, rpkt;
244
245/* Values for flags */
246#define CCP_ISUP	1
247#define CCP_ERROR	2
248#define CCP_FATALERROR	4
249#define CCP_ERR		(CCP_ERROR | CCP_FATALERROR)
250#define CCP_DECOMP_RUN	8
251
252unsigned char dbuf[8192];
253
254void handle_ccp(struct pkt *, u_char *, int);
255
256void dumpppp(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", c);
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 handle_ccp(cp, dp, len)
442    struct pkt *cp;
443    u_char *dp;
444    int len;
445{
446    int clen;
447    struct compressor **comp;
448
449    if (len < CCP_HDRLEN)
450	return;
451    clen = CCP_LENGTH(dp);
452    if (clen > len)
453	return;
454
455    switch (CCP_CODE(dp)) {
456    case CCP_CONFACK:
457	cp->flags &= ~(CCP_DECOMP_RUN | CCP_ISUP);
458	if (clen < CCP_HDRLEN + CCP_OPT_MINLEN
459	    || clen < CCP_HDRLEN + CCP_OPT_LENGTH(dp + CCP_HDRLEN))
460	    break;
461	dp += CCP_HDRLEN;
462	clen -= CCP_HDRLEN;
463	for (comp = compressors; *comp != NULL; ++comp) {
464	    if ((*comp)->compress_proto == dp[0]) {
465		if (cp->state != NULL) {
466		    (*cp->comp->decomp_free)(cp->state);
467		    cp->state = NULL;
468		}
469		cp->comp = *comp;
470		cp->state = (*comp)->decomp_alloc(dp, CCP_OPT_LENGTH(dp));
471		cp->flags |= CCP_ISUP;
472		if (cp->state != NULL
473		    && (*cp->comp->decomp_init)
474		        (cp->state, dp, clen, 0, 0, 8192, 1))
475		    cp->flags = (cp->flags & ~CCP_ERR) | CCP_DECOMP_RUN;
476		break;
477	    }
478	}
479	break;
480
481    case CCP_CONFNAK:
482    case CCP_CONFREJ:
483	cp->flags &= ~(CCP_DECOMP_RUN | CCP_ISUP);
484	break;
485
486    case CCP_RESETACK:
487	if (cp->flags & CCP_ISUP) {
488	    if (cp->state && (cp->flags & CCP_DECOMP_RUN)) {
489		(*cp->comp->decomp_reset)(cp->state);
490		cp->flags &= ~CCP_ERROR;
491	    }
492	}
493	break;
494    }
495}
496
497void show_time(f, c)
498    FILE *f;
499    int c;
500{
501    time_t t;
502    int n;
503    struct tm *tm;
504
505    if (c == 7) {
506	t = getc(f);
507	t = (t << 8) + getc(f);
508	t = (t << 8) + getc(f);
509	t = (t << 8) + getc(f);
510	printf("start %s", ctime(&t));
511	start_time = t;
512	start_time_tenths = 0;
513	tot_sent = tot_rcvd = 0;
514    } else {
515	n = getc(f);
516	if (c == 5) {
517	    for (c = 3; c > 0; --c)
518		n = (n << 8) + getc(f);
519	}
520	if (abs_times) {
521	    n += start_time_tenths;
522	    start_time += n / 10;
523	    start_time_tenths = n % 10;
524	    tm = localtime(&start_time);
525	    printf("time  %.2d:%.2d:%.2d.%d", tm->tm_hour, tm->tm_min,
526		   tm->tm_sec, start_time_tenths);
527	    printf("  (sent %d, rcvd %d)\n", tot_sent, tot_rcvd);
528	} else
529	    printf("time  %.1fs\n", (double) n / 10);
530    }
531}
532