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