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