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