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