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