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