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