change to bsd-style licence
[mpls-ppp.git] / pppdump / pppdump.c
bloba8e69d4bf731f9b8a1abb2d30feb00c859ed0267
1 /*
2 * pppdump - print out the contents of a record file generated by
3 * pppd in readable form.
5 * Copyright (C) 1999 Paul Mackerras. All rights reserved.
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.
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"
23 int hexmode;
24 int pppmode;
25 int reverse;
26 int decompress;
27 int mru = 1500;
28 int abs_times;
29 time_t start_time;
30 int start_time_tenths;
31 int tot_sent, tot_rcvd;
33 extern int optind;
34 extern char *optarg;
36 main(ac, av)
37 int ac;
38 char **av;
40 int i;
41 char *p;
42 FILE *f;
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);
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);
78 if (pppmode)
79 dumpppp(f);
80 else
81 dumplog(f);
82 fclose(f);
85 exit(0);
88 dumplog(f)
89 FILE *f;
91 int c, n, k, col;
92 int nb, c2;
93 unsigned char buf[16];
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);
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: '.');
120 printf("\n ");
121 nb = 0;
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;
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;
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: '.');
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");
172 * FCS lookup table as calculated by genfcstab.
174 static 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
209 struct 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;
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
225 unsigned char dbuf[8192];
227 dumpppp(f)
228 FILE *f;
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;
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 = " ";
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;
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++;
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;
336 } else if (pkt->state
337 && (pkt->flags & CCP_DECOMP_RUN)) {
338 pkt->comp->incomp(pkt->state, r, endp - r);
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: '.');
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);
361 break;
362 case '}':
363 if (!pkt->esc) {
364 pkt->esc = 1;
365 break;
367 /* else fall through */
368 default:
369 if (pkt->esc) {
370 c ^= 0x20;
371 pkt->esc = 0;
373 pkt->buf[pkt->cnt++] = c;
374 break;
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");
400 extern struct compressor ppp_bsd_compress, ppp_deflate;
402 struct compressor *compressors[] = {
403 #if DO_BSD_COMPRESS
404 &ppp_bsd_compress,
405 #endif
406 #if DO_DEFLATE
407 &ppp_deflate,
408 #endif
409 NULL
412 handle_ccp(cp, dp, len)
413 struct pkt *cp;
414 u_char *dp;
415 int len;
417 int clen;
418 struct compressor **comp;
420 if (len < CCP_HDRLEN)
421 return;
422 clen = CCP_LENGTH(dp);
423 if (clen > len)
424 return;
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;
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;
450 break;
452 case CCP_CONFNAK:
453 case CCP_CONFREJ:
454 cp->flags &= ~(CCP_DECOMP_RUN | CCP_ISUP);
455 break;
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;
464 break;
468 show_time(f, c)
469 FILE *f;
470 int c;
472 time_t t;
473 int n;
474 struct tm *tm;
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);
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);