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