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