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