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