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 <stdlib.h> 38#include <unistd.h> 39#include <time.h> 40#include <sys/types.h> 41#include "ppp_defs.h" 42#include "ppp-comp.h" 43 44int hexmode; 45int pppmode; 46int reverse; 47int decompress; 48int mru = 1500; 49int abs_times; 50time_t start_time; 51int start_time_tenths; 52int tot_sent, tot_rcvd; 53 54extern int optind; 55extern char *optarg; 56 57void dumplog(FILE *); 58void dumpppp(FILE *); 59void show_time(FILE *, int); 60 61 62int 63main(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 115void dumplog(f) 116 FILE *f; 117{ 118 int c, n, k, col; 119 int nb, c2; 120 unsigned char buf[16]; 121 122 while ((c = getc(f)) != EOF) { 123 switch (c) { 124 case 1: 125 case 2: 126 if (reverse) 127 c = 3 - c; 128 printf("%s %c", c==1? "sent": "rcvd", hexmode? ' ': '"'); 129 col = 6; 130 n = getc(f); 131 n = (n << 8) + getc(f); 132 *(c==1? &tot_sent: &tot_rcvd) += n; 133 nb = 0; 134 for (; n > 0; --n) { 135 c = getc(f); 136 if (c == EOF) { 137 printf("\nEOF\n"); 138 exit(0); 139 } 140 if (hexmode) { 141 if (nb >= 16) { 142 printf(" "); 143 for (k = 0; k < nb; ++k) { 144 c2 = buf[k]; 145 putchar((' ' <= c2 && c2 <= '~')? c2: '.'); 146 } 147 printf("\n "); 148 nb = 0; 149 } 150 buf[nb++] = c; 151 printf(" %.2x", c); 152 } else { 153 k = (' ' <= c && c <= '~')? (c != '\\' && c != '"')? 1: 2: 3; 154 if ((col += k) >= 78) { 155 printf("\n "); 156 col = 6 + k; 157 } 158 switch (k) { 159 case 1: 160 putchar(c); 161 break; 162 case 2: 163 printf("\\%c", c); 164 break; 165 case 3: 166 printf("\\%.2x", c); 167 break; 168 } 169 } 170 } 171 if (hexmode) { 172 for (k = nb; k < 16; ++k) 173 printf(" "); 174 printf(" "); 175 for (k = 0; k < nb; ++k) { 176 c2 = buf[k]; 177 putchar((' ' <= c2 && c2 <= '~')? c2: '.'); 178 } 179 } else 180 putchar('"'); 181 printf("\n"); 182 break; 183 case 3: 184 case 4: 185 printf("end %s\n", c==3? "send": "recv"); 186 break; 187 case 5: 188 case 6: 189 case 7: 190 show_time(f, c); 191 break; 192 default: 193 printf("?%.2x\n", c); 194 } 195 } 196} 197 198/* 199 * FCS lookup table as calculated by genfcstab. 200 */ 201static u_short fcstab[256] = { 202 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 203 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 204 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 205 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 206 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 207 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 208 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 209 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 210 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 211 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 212 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 213 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 214 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 215 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 216 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 217 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 218 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 219 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 220 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 221 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 222 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 223 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 224 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 225 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 226 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 227 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 228 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 229 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 230 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 231 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 232 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 233 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 234}; 235 236struct pkt { 237 int cnt; 238 int esc; 239 int flags; 240 struct compressor *comp; 241 void *state; 242 unsigned char buf[8192]; 243} spkt, rpkt; 244 245/* Values for flags */ 246#define CCP_ISUP 1 247#define CCP_ERROR 2 248#define CCP_FATALERROR 4 249#define CCP_ERR (CCP_ERROR | CCP_FATALERROR) 250#define CCP_DECOMP_RUN 8 251 252unsigned char dbuf[8192]; 253 254void handle_ccp(struct pkt *, u_char *, int); 255 256void 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", c); 425 } 426 } 427} 428 429extern struct compressor ppp_bsd_compress, ppp_deflate; 430 431struct 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 441void handle_ccp(cp, dp, len) 442 struct pkt *cp; 443 u_char *dp; 444 int len; 445{ 446 int clen; 447 struct compressor **comp; 448 449 if (len < CCP_HDRLEN) 450 return; 451 clen = CCP_LENGTH(dp); 452 if (clen > len) 453 return; 454 455 switch (CCP_CODE(dp)) { 456 case CCP_CONFACK: 457 cp->flags &= ~(CCP_DECOMP_RUN | CCP_ISUP); 458 if (clen < CCP_HDRLEN + CCP_OPT_MINLEN 459 || clen < CCP_HDRLEN + CCP_OPT_LENGTH(dp + CCP_HDRLEN)) 460 break; 461 dp += CCP_HDRLEN; 462 clen -= CCP_HDRLEN; 463 for (comp = compressors; *comp != NULL; ++comp) { 464 if ((*comp)->compress_proto == dp[0]) { 465 if (cp->state != NULL) { 466 (*cp->comp->decomp_free)(cp->state); 467 cp->state = NULL; 468 } 469 cp->comp = *comp; 470 cp->state = (*comp)->decomp_alloc(dp, CCP_OPT_LENGTH(dp)); 471 cp->flags |= CCP_ISUP; 472 if (cp->state != NULL 473 && (*cp->comp->decomp_init) 474 (cp->state, dp, clen, 0, 0, 8192, 1)) 475 cp->flags = (cp->flags & ~CCP_ERR) | CCP_DECOMP_RUN; 476 break; 477 } 478 } 479 break; 480 481 case CCP_CONFNAK: 482 case CCP_CONFREJ: 483 cp->flags &= ~(CCP_DECOMP_RUN | CCP_ISUP); 484 break; 485 486 case CCP_RESETACK: 487 if (cp->flags & CCP_ISUP) { 488 if (cp->state && (cp->flags & CCP_DECOMP_RUN)) { 489 (*cp->comp->decomp_reset)(cp->state); 490 cp->flags &= ~CCP_ERROR; 491 } 492 } 493 break; 494 } 495} 496 497void show_time(f, c) 498 FILE *f; 499 int c; 500{ 501 time_t t; 502 int n; 503 struct tm *tm; 504 505 if (c == 7) { 506 t = getc(f); 507 t = (t << 8) + getc(f); 508 t = (t << 8) + getc(f); 509 t = (t << 8) + getc(f); 510 printf("start %s", ctime(&t)); 511 start_time = t; 512 start_time_tenths = 0; 513 tot_sent = tot_rcvd = 0; 514 } else { 515 n = getc(f); 516 if (c == 5) { 517 for (c = 3; c > 0; --c) 518 n = (n << 8) + getc(f); 519 } 520 if (abs_times) { 521 n += start_time_tenths; 522 start_time += n / 10; 523 start_time_tenths = n % 10; 524 tm = localtime(&start_time); 525 printf("time %.2d:%.2d:%.2d.%d", tm->tm_hour, tm->tm_min, 526 tm->tm_sec, start_time_tenths); 527 printf(" (sent %d, rcvd %d)\n", tot_sent, tot_rcvd); 528 } else 529 printf("time %.1fs\n", (double) n / 10); 530 } 531} 532