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