1 /* 2 * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that: (1) source code distributions 7 * retain the above copyright notice and this paragraph in its entirety, (2) 8 * distributions including binary code include the above copyright notice and 9 * this paragraph in its entirety in the documentation or other materials 10 * provided with the distribution, and (3) all advertising materials mentioning 11 * features or use of this software display the following acknowledgement: 12 * ``This product includes software developed by the University of California, 13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 14 * the University nor the names of its contributors may be used to endorse 15 * or promote products derived from this software without specific prior 16 * written permission. 17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20 * 21 * Format and print AppleTalk packets. 22 */ 23 24 #define NETDISSECT_REWORKED 25 #ifdef HAVE_CONFIG_H 26 #include "config.h" 27 #endif 28 29 #include <tcpdump-stdinc.h> 30 31 #include <stdio.h> 32 #include <string.h> 33 34 #include "interface.h" 35 #include "addrtoname.h" 36 #include "ethertype.h" 37 #include "extract.h" /* must come after interface.h */ 38 #include "appletalk.h" 39 40 static const char tstr[] = "[|atalk]"; 41 42 static const struct tok type2str[] = { 43 { ddpRTMP, "rtmp" }, 44 { ddpRTMPrequest, "rtmpReq" }, 45 { ddpECHO, "echo" }, 46 { ddpIP, "IP" }, 47 { ddpARP, "ARP" }, 48 { ddpKLAP, "KLAP" }, 49 { 0, NULL } 50 }; 51 52 struct aarp { 53 uint16_t htype, ptype; 54 uint8_t halen, palen; 55 uint16_t op; 56 uint8_t hsaddr[6]; 57 uint8_t psaddr[4]; 58 uint8_t hdaddr[6]; 59 uint8_t pdaddr[4]; 60 }; 61 62 static void atp_print(netdissect_options *, const struct atATP *, u_int); 63 static void atp_bitmap_print(netdissect_options *, u_char); 64 static void nbp_print(netdissect_options *, const struct atNBP *, u_int, u_short, u_char, u_char); 65 static const struct atNBPtuple *nbp_tuple_print(netdissect_options *ndo, const struct atNBPtuple *, 66 const u_char *, 67 u_short, u_char, u_char); 68 static const struct atNBPtuple *nbp_name_print(netdissect_options *, const struct atNBPtuple *, 69 const u_char *); 70 static const char *ataddr_string(netdissect_options *, u_short, u_char); 71 static void ddp_print(netdissect_options *, const u_char *, u_int, int, u_short, u_char, u_char); 72 static const char *ddpskt_string(netdissect_options *, int); 73 74 /* 75 * Print LLAP packets received on a physical LocalTalk interface. 76 */ 77 u_int 78 ltalk_if_print(netdissect_options *ndo, 79 const struct pcap_pkthdr *h, const u_char *p) 80 { 81 return (llap_print(ndo, p, h->caplen)); 82 } 83 84 /* 85 * Print AppleTalk LLAP packets. 86 */ 87 u_int 88 llap_print(netdissect_options *ndo, 89 register const u_char *bp, u_int length) 90 { 91 register const struct LAP *lp; 92 register const struct atDDP *dp; 93 register const struct atShortDDP *sdp; 94 u_short snet; 95 u_int hdrlen; 96 97 if (length < sizeof(*lp)) { 98 ND_PRINT((ndo, " [|llap %u]", length)); 99 return (length); 100 } 101 lp = (const struct LAP *)bp; 102 bp += sizeof(*lp); 103 length -= sizeof(*lp); 104 hdrlen = sizeof(*lp); 105 switch (lp->type) { 106 107 case lapShortDDP: 108 if (length < ddpSSize) { 109 ND_PRINT((ndo, " [|sddp %u]", length)); 110 return (length); 111 } 112 sdp = (const struct atShortDDP *)bp; 113 ND_PRINT((ndo, "%s.%s", 114 ataddr_string(ndo, 0, lp->src), ddpskt_string(ndo, sdp->srcSkt))); 115 ND_PRINT((ndo, " > %s.%s:", 116 ataddr_string(ndo, 0, lp->dst), ddpskt_string(ndo, sdp->dstSkt))); 117 bp += ddpSSize; 118 length -= ddpSSize; 119 hdrlen += ddpSSize; 120 ddp_print(ndo, bp, length, sdp->type, 0, lp->src, sdp->srcSkt); 121 break; 122 123 case lapDDP: 124 if (length < ddpSize) { 125 ND_PRINT((ndo, " [|ddp %u]", length)); 126 return (length); 127 } 128 dp = (const struct atDDP *)bp; 129 snet = EXTRACT_16BITS(&dp->srcNet); 130 ND_PRINT((ndo, "%s.%s", ataddr_string(ndo, snet, dp->srcNode), 131 ddpskt_string(ndo, dp->srcSkt))); 132 ND_PRINT((ndo, " > %s.%s:", 133 ataddr_string(ndo, EXTRACT_16BITS(&dp->dstNet), dp->dstNode), 134 ddpskt_string(ndo, dp->dstSkt))); 135 bp += ddpSize; 136 length -= ddpSize; 137 hdrlen += ddpSize; 138 ddp_print(ndo, bp, length, dp->type, snet, dp->srcNode, dp->srcSkt); 139 break; 140 141 #ifdef notdef 142 case lapKLAP: 143 klap_print(bp, length); 144 break; 145 #endif 146 147 default: 148 ND_PRINT((ndo, "%d > %d at-lap#%d %u", 149 lp->src, lp->dst, lp->type, length)); 150 break; 151 } 152 return (hdrlen); 153 } 154 155 /* 156 * Print EtherTalk/TokenTalk packets (or FDDITalk, or whatever it's called 157 * when it runs over FDDI; yes, I've seen FDDI captures with AppleTalk 158 * packets in them). 159 */ 160 void 161 atalk_print(netdissect_options *ndo, 162 register const u_char *bp, u_int length) 163 { 164 register const struct atDDP *dp; 165 u_short snet; 166 167 if(!ndo->ndo_eflag) 168 ND_PRINT((ndo, "AT ")); 169 170 if (length < ddpSize) { 171 ND_PRINT((ndo, " [|ddp %u]", length)); 172 return; 173 } 174 dp = (const struct atDDP *)bp; 175 snet = EXTRACT_16BITS(&dp->srcNet); 176 ND_PRINT((ndo, "%s.%s", ataddr_string(ndo, snet, dp->srcNode), 177 ddpskt_string(ndo, dp->srcSkt))); 178 ND_PRINT((ndo, " > %s.%s: ", 179 ataddr_string(ndo, EXTRACT_16BITS(&dp->dstNet), dp->dstNode), 180 ddpskt_string(ndo, dp->dstSkt))); 181 bp += ddpSize; 182 length -= ddpSize; 183 ddp_print(ndo, bp, length, dp->type, snet, dp->srcNode, dp->srcSkt); 184 } 185 186 /* XXX should probably pass in the snap header and do checks like arp_print() */ 187 void 188 aarp_print(netdissect_options *ndo, 189 register const u_char *bp, u_int length) 190 { 191 register const struct aarp *ap; 192 193 #define AT(member) ataddr_string(ndo, (ap->member[1]<<8)|ap->member[2],ap->member[3]) 194 195 ND_PRINT((ndo, "aarp ")); 196 ap = (const struct aarp *)bp; 197 if (EXTRACT_16BITS(&ap->htype) == 1 && 198 EXTRACT_16BITS(&ap->ptype) == ETHERTYPE_ATALK && 199 ap->halen == 6 && ap->palen == 4 ) 200 switch (EXTRACT_16BITS(&ap->op)) { 201 202 case 1: /* request */ 203 ND_PRINT((ndo, "who-has %s tell %s", AT(pdaddr), AT(psaddr))); 204 return; 205 206 case 2: /* response */ 207 ND_PRINT((ndo, "reply %s is-at %s", AT(psaddr), etheraddr_string(ndo, ap->hsaddr))); 208 return; 209 210 case 3: /* probe (oy!) */ 211 ND_PRINT((ndo, "probe %s tell %s", AT(pdaddr), AT(psaddr))); 212 return; 213 } 214 ND_PRINT((ndo, "len %u op %u htype %u ptype %#x halen %u palen %u", 215 length, EXTRACT_16BITS(&ap->op), EXTRACT_16BITS(&ap->htype), 216 EXTRACT_16BITS(&ap->ptype), ap->halen, ap->palen)); 217 } 218 219 /* 220 * Print AppleTalk Datagram Delivery Protocol packets. 221 */ 222 static void 223 ddp_print(netdissect_options *ndo, 224 register const u_char *bp, register u_int length, register int t, 225 register u_short snet, register u_char snode, u_char skt) 226 { 227 228 switch (t) { 229 230 case ddpNBP: 231 nbp_print(ndo, (const struct atNBP *)bp, length, snet, snode, skt); 232 break; 233 234 case ddpATP: 235 atp_print(ndo, (const struct atATP *)bp, length); 236 break; 237 238 case ddpEIGRP: 239 eigrp_print(ndo, bp, length); 240 break; 241 242 default: 243 ND_PRINT((ndo, " at-%s %d", tok2str(type2str, NULL, t), length)); 244 break; 245 } 246 } 247 248 static void 249 atp_print(netdissect_options *ndo, 250 register const struct atATP *ap, u_int length) 251 { 252 char c; 253 uint32_t data; 254 255 if ((const u_char *)(ap + 1) > ndo->ndo_snapend) { 256 /* Just bail if we don't have the whole chunk. */ 257 ND_PRINT((ndo, "%s", tstr)); 258 return; 259 } 260 if (length < sizeof(*ap)) { 261 ND_PRINT((ndo, " [|atp %u]", length)); 262 return; 263 } 264 length -= sizeof(*ap); 265 switch (ap->control & 0xc0) { 266 267 case atpReqCode: 268 ND_PRINT((ndo, " atp-req%s %d", 269 ap->control & atpXO? " " : "*", 270 EXTRACT_16BITS(&ap->transID))); 271 272 atp_bitmap_print(ndo, ap->bitmap); 273 274 if (length != 0) 275 ND_PRINT((ndo, " [len=%u]", length)); 276 277 switch (ap->control & (atpEOM|atpSTS)) { 278 case atpEOM: 279 ND_PRINT((ndo, " [EOM]")); 280 break; 281 case atpSTS: 282 ND_PRINT((ndo, " [STS]")); 283 break; 284 case atpEOM|atpSTS: 285 ND_PRINT((ndo, " [EOM,STS]")); 286 break; 287 } 288 break; 289 290 case atpRspCode: 291 ND_PRINT((ndo, " atp-resp%s%d:%d (%u)", 292 ap->control & atpEOM? "*" : " ", 293 EXTRACT_16BITS(&ap->transID), ap->bitmap, length)); 294 switch (ap->control & (atpXO|atpSTS)) { 295 case atpXO: 296 ND_PRINT((ndo, " [XO]")); 297 break; 298 case atpSTS: 299 ND_PRINT((ndo, " [STS]")); 300 break; 301 case atpXO|atpSTS: 302 ND_PRINT((ndo, " [XO,STS]")); 303 break; 304 } 305 break; 306 307 case atpRelCode: 308 ND_PRINT((ndo, " atp-rel %d", EXTRACT_16BITS(&ap->transID))); 309 310 atp_bitmap_print(ndo, ap->bitmap); 311 312 /* length should be zero */ 313 if (length) 314 ND_PRINT((ndo, " [len=%u]", length)); 315 316 /* there shouldn't be any control flags */ 317 if (ap->control & (atpXO|atpEOM|atpSTS)) { 318 c = '['; 319 if (ap->control & atpXO) { 320 ND_PRINT((ndo, "%cXO", c)); 321 c = ','; 322 } 323 if (ap->control & atpEOM) { 324 ND_PRINT((ndo, "%cEOM", c)); 325 c = ','; 326 } 327 if (ap->control & atpSTS) { 328 ND_PRINT((ndo, "%cSTS", c)); 329 c = ','; 330 } 331 ND_PRINT((ndo, "]")); 332 } 333 break; 334 335 default: 336 ND_PRINT((ndo, " atp-0x%x %d (%u)", ap->control, 337 EXTRACT_16BITS(&ap->transID), length)); 338 break; 339 } 340 data = EXTRACT_32BITS(&ap->userData); 341 if (data != 0) 342 ND_PRINT((ndo, " 0x%x", data)); 343 } 344 345 static void 346 atp_bitmap_print(netdissect_options *ndo, 347 register u_char bm) 348 { 349 register char c; 350 register int i; 351 352 /* 353 * The '& 0xff' below is needed for compilers that want to sign 354 * extend a u_char, which is the case with the Ultrix compiler. 355 * (gcc is smart enough to eliminate it, at least on the Sparc). 356 */ 357 if ((bm + 1) & (bm & 0xff)) { 358 c = '<'; 359 for (i = 0; bm; ++i) { 360 if (bm & 1) { 361 ND_PRINT((ndo, "%c%d", c, i)); 362 c = ','; 363 } 364 bm >>= 1; 365 } 366 ND_PRINT((ndo, ">")); 367 } else { 368 for (i = 0; bm; ++i) 369 bm >>= 1; 370 if (i > 1) 371 ND_PRINT((ndo, "<0-%d>", i - 1)); 372 else 373 ND_PRINT((ndo, "<0>")); 374 } 375 } 376 377 static void 378 nbp_print(netdissect_options *ndo, 379 register const struct atNBP *np, u_int length, register u_short snet, 380 register u_char snode, register u_char skt) 381 { 382 register const struct atNBPtuple *tp = 383 (const struct atNBPtuple *)((u_char *)np + nbpHeaderSize); 384 int i; 385 const u_char *ep; 386 387 if (length < nbpHeaderSize) { 388 ND_PRINT((ndo, " truncated-nbp %u", length)); 389 return; 390 } 391 392 length -= nbpHeaderSize; 393 if (length < 8) { 394 /* must be room for at least one tuple */ 395 ND_PRINT((ndo, " truncated-nbp %u", length + nbpHeaderSize)); 396 return; 397 } 398 /* ep points to end of available data */ 399 ep = ndo->ndo_snapend; 400 if ((const u_char *)tp > ep) { 401 ND_PRINT((ndo, "%s", tstr)); 402 return; 403 } 404 switch (i = np->control & 0xf0) { 405 406 case nbpBrRq: 407 case nbpLkUp: 408 ND_PRINT((ndo, i == nbpLkUp? " nbp-lkup %d:":" nbp-brRq %d:", np->id)); 409 if ((const u_char *)(tp + 1) > ep) { 410 ND_PRINT((ndo, "%s", tstr)); 411 return; 412 } 413 (void)nbp_name_print(ndo, tp, ep); 414 /* 415 * look for anomalies: the spec says there can only 416 * be one tuple, the address must match the source 417 * address and the enumerator should be zero. 418 */ 419 if ((np->control & 0xf) != 1) 420 ND_PRINT((ndo, " [ntup=%d]", np->control & 0xf)); 421 if (tp->enumerator) 422 ND_PRINT((ndo, " [enum=%d]", tp->enumerator)); 423 if (EXTRACT_16BITS(&tp->net) != snet || 424 tp->node != snode || tp->skt != skt) 425 ND_PRINT((ndo, " [addr=%s.%d]", 426 ataddr_string(ndo, EXTRACT_16BITS(&tp->net), 427 tp->node), tp->skt)); 428 break; 429 430 case nbpLkUpReply: 431 ND_PRINT((ndo, " nbp-reply %d:", np->id)); 432 433 /* print each of the tuples in the reply */ 434 for (i = np->control & 0xf; --i >= 0 && tp; ) 435 tp = nbp_tuple_print(ndo, tp, ep, snet, snode, skt); 436 break; 437 438 default: 439 ND_PRINT((ndo, " nbp-0x%x %d (%u)", np->control, np->id, length)); 440 break; 441 } 442 } 443 444 /* print a counted string */ 445 static const char * 446 print_cstring(netdissect_options *ndo, 447 register const char *cp, register const u_char *ep) 448 { 449 register u_int length; 450 451 if (cp >= (const char *)ep) { 452 ND_PRINT((ndo, "%s", tstr)); 453 return (0); 454 } 455 length = *cp++; 456 457 /* Spec says string can be at most 32 bytes long */ 458 if (length > 32) { 459 ND_PRINT((ndo, "[len=%u]", length)); 460 return (0); 461 } 462 while ((int)--length >= 0) { 463 if (cp >= (const char *)ep) { 464 ND_PRINT((ndo, "%s", tstr)); 465 return (0); 466 } 467 ND_PRINT((ndo, "%c", *cp++)); 468 } 469 return (cp); 470 } 471 472 static const struct atNBPtuple * 473 nbp_tuple_print(netdissect_options *ndo, 474 register const struct atNBPtuple *tp, register const u_char *ep, 475 register u_short snet, register u_char snode, register u_char skt) 476 { 477 register const struct atNBPtuple *tpn; 478 479 if ((const u_char *)(tp + 1) > ep) { 480 ND_PRINT((ndo, "%s", tstr)); 481 return 0; 482 } 483 tpn = nbp_name_print(ndo, tp, ep); 484 485 /* if the enumerator isn't 1, print it */ 486 if (tp->enumerator != 1) 487 ND_PRINT((ndo, "(%d)", tp->enumerator)); 488 489 /* if the socket doesn't match the src socket, print it */ 490 if (tp->skt != skt) 491 ND_PRINT((ndo, " %d", tp->skt)); 492 493 /* if the address doesn't match the src address, it's an anomaly */ 494 if (EXTRACT_16BITS(&tp->net) != snet || tp->node != snode) 495 ND_PRINT((ndo, " [addr=%s]", 496 ataddr_string(ndo, EXTRACT_16BITS(&tp->net), tp->node))); 497 498 return (tpn); 499 } 500 501 static const struct atNBPtuple * 502 nbp_name_print(netdissect_options *ndo, 503 const struct atNBPtuple *tp, register const u_char *ep) 504 { 505 register const char *cp = (const char *)tp + nbpTupleSize; 506 507 ND_PRINT((ndo, " ")); 508 509 /* Object */ 510 ND_PRINT((ndo, "\"")); 511 if ((cp = print_cstring(ndo, cp, ep)) != NULL) { 512 /* Type */ 513 ND_PRINT((ndo, ":")); 514 if ((cp = print_cstring(ndo, cp, ep)) != NULL) { 515 /* Zone */ 516 ND_PRINT((ndo, "@")); 517 if ((cp = print_cstring(ndo, cp, ep)) != NULL) 518 ND_PRINT((ndo, "\"")); 519 } 520 } 521 return ((const struct atNBPtuple *)cp); 522 } 523 524 525 #define HASHNAMESIZE 4096 526 527 struct hnamemem { 528 int addr; 529 char *name; 530 struct hnamemem *nxt; 531 }; 532 533 static struct hnamemem hnametable[HASHNAMESIZE]; 534 535 static const char * 536 ataddr_string(netdissect_options *ndo, 537 u_short atnet, u_char athost) 538 { 539 register struct hnamemem *tp, *tp2; 540 register int i = (atnet << 8) | athost; 541 char nambuf[256+1]; 542 static int first = 1; 543 FILE *fp; 544 545 /* 546 * if this is the first call, see if there's an AppleTalk 547 * number to name map file. 548 */ 549 if (first && (first = 0, !ndo->ndo_nflag) 550 && (fp = fopen("/etc/atalk.names", "r"))) { 551 char line[256]; 552 int i1, i2; 553 554 while (fgets(line, sizeof(line), fp)) { 555 if (line[0] == '\n' || line[0] == 0 || line[0] == '#') 556 continue; 557 if (sscanf(line, "%d.%d %256s", &i1, &i2, nambuf) == 3) 558 /* got a hostname. */ 559 i2 |= (i1 << 8); 560 else if (sscanf(line, "%d %256s", &i1, nambuf) == 2) 561 /* got a net name */ 562 i2 = (i1 << 8) | 255; 563 else 564 continue; 565 566 for (tp = &hnametable[i2 & (HASHNAMESIZE-1)]; 567 tp->nxt; tp = tp->nxt) 568 ; 569 tp->addr = i2; 570 tp->nxt = newhnamemem(); 571 tp->name = strdup(nambuf); 572 } 573 fclose(fp); 574 } 575 576 for (tp = &hnametable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt) 577 if (tp->addr == i) 578 return (tp->name); 579 580 /* didn't have the node name -- see if we've got the net name */ 581 i |= 255; 582 for (tp2 = &hnametable[i & (HASHNAMESIZE-1)]; tp2->nxt; tp2 = tp2->nxt) 583 if (tp2->addr == i) { 584 tp->addr = (atnet << 8) | athost; 585 tp->nxt = newhnamemem(); 586 (void)snprintf(nambuf, sizeof(nambuf), "%s.%d", 587 tp2->name, athost); 588 tp->name = strdup(nambuf); 589 return (tp->name); 590 } 591 592 tp->addr = (atnet << 8) | athost; 593 tp->nxt = newhnamemem(); 594 if (athost != 255) 595 (void)snprintf(nambuf, sizeof(nambuf), "%d.%d", atnet, athost); 596 else 597 (void)snprintf(nambuf, sizeof(nambuf), "%d", atnet); 598 tp->name = strdup(nambuf); 599 600 return (tp->name); 601 } 602 603 static const struct tok skt2str[] = { 604 { rtmpSkt, "rtmp" }, /* routing table maintenance */ 605 { nbpSkt, "nis" }, /* name info socket */ 606 { echoSkt, "echo" }, /* AppleTalk echo protocol */ 607 { zipSkt, "zip" }, /* zone info protocol */ 608 { 0, NULL } 609 }; 610 611 static const char * 612 ddpskt_string(netdissect_options *ndo, 613 register int skt) 614 { 615 static char buf[8]; 616 617 if (ndo->ndo_nflag) { 618 (void)snprintf(buf, sizeof(buf), "%d", skt); 619 return (buf); 620 } 621 return (tok2str(skt2str, "%d", skt)); 622 } 623