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