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