]> git.ozlabs.org Git - ppp.git/blob - pppdump/pppdump.c
2b815fc9b50e41fcd2ec8c0d2a0ad93120a4aaf3
[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
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", c);
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 #define PPP_FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
237
238 struct pkt {
239     int cnt;
240     int esc;
241     int flags;
242     struct compressor *comp;
243     void *state;
244     unsigned char buf[8192];
245 } spkt, rpkt;
246
247 /* Values for flags */
248 #define CCP_ISUP        1
249 #define CCP_ERROR       2
250 #define CCP_FATALERROR  4
251 #define CCP_ERR         (CCP_ERROR | CCP_FATALERROR)
252 #define CCP_DECOMP_RUN  8
253
254 unsigned char dbuf[8192];
255
256 void
257 dumpppp(f)
258     FILE *f;
259 {
260     int c, n, k;
261     int nb, nl, dn, proto, rv;
262     char *dir, *q;
263     unsigned char *p, *r, *endp;
264     unsigned char *d;
265     unsigned short fcs;
266     struct pkt *pkt;
267
268     spkt.cnt = rpkt.cnt = 0;
269     spkt.esc = rpkt.esc = 0;
270     while ((c = getc(f)) != EOF) {
271         switch (c) {
272         case 1:
273         case 2:
274             if (reverse)
275                 c = 3 - c;
276             dir = c==1? "sent": "rcvd";
277             pkt = c==1? &spkt: &rpkt;
278             n = getc(f);
279             n = (n << 8) + getc(f);
280             *(c==1? &tot_sent: &tot_rcvd) += n;
281             for (; n > 0; --n) {
282                 c = getc(f);
283                 switch (c) {
284                 case EOF:
285                     printf("\nEOF\n");
286                     if (spkt.cnt > 0)
287                         printf("[%d bytes in incomplete send packet]\n",
288                                spkt.cnt);
289                     if (rpkt.cnt > 0)
290                         printf("[%d bytes in incomplete recv packet]\n",
291                                rpkt.cnt);
292                     exit(0);
293                 case '~':
294                     if (pkt->cnt > 0) {
295                         q = dir;
296                         if (pkt->esc) {
297                             printf("%s aborted packet:\n     ", dir);
298                             q = "    ";
299                         }
300                         nb = pkt->cnt;
301                         p = pkt->buf;
302                         pkt->cnt = 0;
303                         pkt->esc = 0;
304                         if (nb <= 2) {
305                             printf("%s short packet [%d bytes]:", q, nb);
306                             for (k = 0; k < nb; ++k)
307                                 printf(" %.2x", p[k]);
308                             printf("\n");
309                             break;
310                         }
311                         fcs = PPP_INITFCS;
312                         for (k = 0; k < nb; ++k)
313                             fcs = PPP_FCS(fcs, p[k]);
314                         fcs &= 0xFFFF;
315                         nb -= 2;
316                         endp = p + nb;
317                         r = p;
318                         if (r[0] == 0xff && r[1] == 3)
319                             r += 2;
320                         if ((r[0] & 1) == 0)
321                             ++r;
322                         ++r;
323                         if (endp - r > mru)
324                             printf("     ERROR: length (%zd) > MRU (%d)\n",
325                                    endp - r, mru);
326                         if (decompress && fcs == PPP_GOODFCS) {
327                             /* See if this is a CCP or compressed packet */
328                             d = dbuf;
329                             r = p;
330                             if (r[0] == 0xff && r[1] == 3) {
331                                 *d++ = *r++;
332                                 *d++ = *r++;
333                             }
334                             proto = r[0];
335                             if ((proto & 1) == 0)
336                                 proto = (proto << 8) + r[1];
337                             if (proto == PPP_CCP) {
338                                 handle_ccp(pkt, r + 2, endp - r - 2);
339                             } else if (proto == PPP_COMP) {
340                                 if ((pkt->flags & CCP_ISUP)
341                                     && (pkt->flags & CCP_DECOMP_RUN)
342                                     && pkt->state
343                                     && (pkt->flags & CCP_ERR) == 0) {
344                                     rv = pkt->comp->decompress(pkt->state, r,
345                                                         endp - r, d, &dn);
346                                     switch (rv) {
347                                     case DECOMP_OK:
348                                         p = dbuf;
349                                         nb = d + dn - p;
350                                         if ((d[0] & 1) == 0)
351                                             --dn;
352                                         --dn;
353                                         if (dn > mru)
354                                             printf("     ERROR: decompressed length (%d) > MRU (%d)\n", dn, mru);
355                                         break;
356                                     case DECOMP_ERROR:
357                                         printf("     DECOMPRESSION ERROR\n");
358                                         pkt->flags |= CCP_ERROR;
359                                         break;
360                                     case DECOMP_FATALERROR:
361                                         printf("     FATAL DECOMPRESSION ERROR\n");
362                                         pkt->flags |= CCP_FATALERROR;
363                                         break;
364                                     }
365                                 }
366                             } else if (pkt->state
367                                        && (pkt->flags & CCP_DECOMP_RUN)) {
368                                 pkt->comp->incomp(pkt->state, r, endp - r);
369                             }
370                         }
371                         do {
372                             nl = nb < 16? nb: 16;
373                             printf("%s ", q);
374                             for (k = 0; k < nl; ++k)
375                                 printf(" %.2x", p[k]);
376                             for (; k < 16; ++k)
377                                 printf("   ");
378                             printf("  ");
379                             for (k = 0; k < nl; ++k) {
380                                 c = p[k];
381                                 putchar((' ' <= c && c <= '~')? c: '.');
382                             }
383                             printf("\n");
384                             q = "    ";
385                             p += nl;
386                             nb -= nl;
387                         } while (nb > 0);
388                         if (fcs != PPP_GOODFCS)
389                             printf("     BAD FCS: (residue = %x)\n", fcs);
390                     }
391                     break;
392                 case '}':
393                     if (!pkt->esc) {
394                         pkt->esc = 1;
395                         break;
396                     }
397                     /* else fall through */
398                 default:
399                     if (pkt->esc) {
400                         c ^= 0x20;
401                         pkt->esc = 0;
402                     }
403                     pkt->buf[pkt->cnt++] = c;
404                     break;
405                 }
406             }
407             break;
408         case 3:
409         case 4:
410             if (reverse)
411                 c = 7 - c;
412             dir = c==3? "send": "recv";
413             pkt = c==3? &spkt: &rpkt;
414             printf("end %s", dir);
415             if (pkt->cnt > 0)
416                 printf("  [%d bytes in incomplete packet]", pkt->cnt);
417             printf("\n");
418             break;
419         case 5:
420         case 6:
421         case 7:
422             show_time(f, c);
423             break;
424         default:
425             printf("?%.2x\n", c);
426         }
427     }
428 }
429
430 extern struct compressor ppp_bsd_compress, ppp_deflate;
431
432 struct compressor *compressors[] = {
433 #if DO_BSD_COMPRESS
434     &ppp_bsd_compress,
435 #endif
436 #if DO_DEFLATE
437     &ppp_deflate,
438 #endif
439     NULL
440 };
441
442 void
443 handle_ccp(cp, dp, len)
444     struct pkt *cp;
445     u_char *dp;
446     int len;
447 {
448     int clen;
449     struct compressor **comp;
450
451     if (len < CCP_HDRLEN)
452         return;
453     clen = CCP_LENGTH(dp);
454     if (clen > len)
455         return;
456
457     switch (CCP_CODE(dp)) {
458     case CCP_CONFACK:
459         cp->flags &= ~(CCP_DECOMP_RUN | CCP_ISUP);
460         if (clen < CCP_HDRLEN + CCP_OPT_MINLEN
461             || clen < CCP_HDRLEN + CCP_OPT_LENGTH(dp + CCP_HDRLEN))
462             break;
463         dp += CCP_HDRLEN;
464         clen -= CCP_HDRLEN;
465         for (comp = compressors; *comp != NULL; ++comp) {
466             if ((*comp)->compress_proto == dp[0]) {
467                 if (cp->state != NULL) {
468                     (*cp->comp->decomp_free)(cp->state);
469                     cp->state = NULL;
470                 }
471                 cp->comp = *comp;
472                 cp->state = (*comp)->decomp_alloc(dp, CCP_OPT_LENGTH(dp));
473                 cp->flags |= CCP_ISUP;
474                 if (cp->state != NULL
475                     && (*cp->comp->decomp_init)
476                         (cp->state, dp, clen, 0, 0, 8192, 1))
477                     cp->flags = (cp->flags & ~CCP_ERR) | CCP_DECOMP_RUN;
478                 break;
479             }
480         }
481         break;
482
483     case CCP_CONFNAK:
484     case CCP_CONFREJ:
485         cp->flags &= ~(CCP_DECOMP_RUN | CCP_ISUP);
486         break;
487
488     case CCP_RESETACK:
489         if (cp->flags & CCP_ISUP) {
490             if (cp->state && (cp->flags & CCP_DECOMP_RUN)) {
491                 (*cp->comp->decomp_reset)(cp->state);
492                 cp->flags &= ~CCP_ERROR;
493             }
494         }
495         break;
496     }
497 }
498
499 void
500 show_time(f, c)
501     FILE *f;
502     int c;
503 {
504     time_t t;
505     int n;
506     struct tm *tm;
507
508     if (c == 7) {
509         t = getc(f);
510         t = (t << 8) + getc(f);
511         t = (t << 8) + getc(f);
512         t = (t << 8) + getc(f);
513         printf("start %s", ctime(&t));
514         start_time = t;
515         start_time_tenths = 0;
516         tot_sent = tot_rcvd = 0;
517     } else {
518         n = getc(f);
519         if (c == 5) {
520             for (c = 3; c > 0; --c)
521                 n = (n << 8) + getc(f);
522         }
523         if (abs_times) {
524             n += start_time_tenths;
525             start_time += n / 10;
526             start_time_tenths = n % 10;
527             tm = localtime(&start_time);
528             printf("time  %.2d:%.2d:%.2d.%d", tm->tm_hour, tm->tm_min,
529                    tm->tm_sec, start_time_tenths);
530             printf("  (sent %d, rcvd %d)\n", tot_sent, tot_rcvd);
531         } else
532             printf("time  %.1fs\n", (double) n / 10);
533     }
534 }