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