1/* 2 * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996 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 * Internet, ethernet, port, and protocol string to address 22 * and address to string conversion routines 23 */ 24#ifndef lint 25static char rcsid[] = 26 "@(#) $Header: addrtoname.c,v 1.49 96/07/02 00:19:35 leres Exp $ (LBL)"; 27#endif 28 29#include <sys/types.h> 30#include <sys/socket.h> 31#include <sys/time.h> 32 33#if __STDC__ 34struct mbuf; 35struct rtentry; 36#endif 37#include <net/if.h> 38 39#include <netinet/in.h> 40#include <netinet/if_ether.h> 41 42#include <arpa/inet.h> 43 44#include <ctype.h> 45#include <netdb.h> 46#include <pcap.h> 47#include <pcap-namedb.h> 48#include <signal.h> 49#include <stdio.h> 50#include <string.h> 51#include <stdlib.h> 52#include <unistd.h> 53 54#include "interface.h" 55#include "addrtoname.h" 56#include "llc.h" 57 58/* Forwards */ 59static RETSIGTYPE nohostname(int); 60 61/* 62 * hash tables for whatever-to-name translations 63 */ 64 65#define HASHNAMESIZE 4096 66 67struct hnamemem { 68 u_int32_t addr; 69 char *name; 70 struct hnamemem *nxt; 71}; 72 73struct hnamemem hnametable[HASHNAMESIZE]; 74struct hnamemem tporttable[HASHNAMESIZE]; 75struct hnamemem uporttable[HASHNAMESIZE]; 76struct hnamemem eprototable[HASHNAMESIZE]; 77struct hnamemem dnaddrtable[HASHNAMESIZE]; 78struct hnamemem llcsaptable[HASHNAMESIZE]; 79 80struct enamemem { 81 u_short e_addr0; 82 u_short e_addr1; 83 u_short e_addr2; 84 char *e_name; 85 u_char *e_nsap; /* used only for nsaptable[] */ 86 struct enamemem *e_nxt; 87}; 88 89struct enamemem enametable[HASHNAMESIZE]; 90struct enamemem nsaptable[HASHNAMESIZE]; 91 92struct protoidmem { 93 u_int32_t p_oui; 94 u_short p_proto; 95 char *p_name; 96 struct protoidmem *p_nxt; 97}; 98 99struct protoidmem protoidtable[HASHNAMESIZE]; 100 101/* 102 * A faster replacement for inet_ntoa(). 103 */ 104char * 105intoa(u_int32_t addr) 106{ 107 register char *cp; 108 register u_int byte; 109 register int n; 110 static char buf[sizeof(".xxx.xxx.xxx.xxx")]; 111 112 NTOHL(addr); 113 cp = &buf[sizeof buf]; 114 *--cp = '\0'; 115 116 n = 4; 117 do { 118 byte = addr & 0xff; 119 *--cp = byte % 10 + '0'; 120 byte /= 10; 121 if (byte > 0) { 122 *--cp = byte % 10 + '0'; 123 byte /= 10; 124 if (byte > 0) 125 *--cp = byte + '0'; 126 } 127 *--cp = '.'; 128 addr >>= 8; 129 } while (--n > 0); 130 131 return cp + 1; 132} 133 134static u_int32_t f_netmask; 135static u_int32_t f_localnet; 136static u_int32_t netmask; 137 138/* 139 * "getname" is written in this atrocious way to make sure we don't 140 * wait forever while trying to get hostnames from yp. 141 */ 142#include <setjmp.h> 143 144jmp_buf getname_env; 145 146static RETSIGTYPE 147nohostname(int signo) 148{ 149 longjmp(getname_env, 1); 150} 151 152/* 153 * Return a name for the IP address pointed to by ap. This address 154 * is assumed to be in network byte order. 155 */ 156char * 157getname(const u_char *ap) 158{ 159 register struct hostent *hp; 160 u_int32_t addr; 161 static struct hnamemem *p; /* static for longjmp() */ 162 163#ifndef LBL_ALIGN 164 addr = *(const u_int32_t *)ap; 165#else 166 /* 167 * Deal with alignment. 168 */ 169 switch ((long)ap & 3) { 170 171 case 0: 172 addr = *(u_int32_t *)ap; 173 break; 174 175 case 2: 176#if BYTE_ORDER == LITTLE_ENDIAN 177 addr = ((u_int32_t)*(u_short *)(ap + 2) << 16) | 178 (u_int32_t)*(u_short *)ap; 179#else 180 addr = ((u_int32_t)*(u_short *)ap << 16) | 181 (u_int32_t)*(u_short *)(ap + 2); 182#endif 183 break; 184 185 default: 186#if BYTE_ORDER == LITTLE_ENDIAN 187 addr = ((u_int32_t)ap[3] << 24) | 188 ((u_int32_t)ap[2] << 16) | 189 ((u_int32_t)ap[1] << 8) | 190 (u_int32_t)ap[0]; 191#else 192 addr = ((u_int32_t)ap[0] << 24) | 193 ((u_int32_t)ap[1] << 16) | 194 ((u_int32_t)ap[2] << 8) | 195 (u_int32_t)ap[3]; 196#endif 197 break; 198 } 199#endif 200 p = &hnametable[addr & (HASHNAMESIZE-1)]; 201 for (; p->nxt; p = p->nxt) { 202 if (p->addr == addr) 203 return (p->name); 204 } 205 p->addr = addr; 206 p->nxt = newhnamemem(); 207 208 /* 209 * Only print names when: 210 * (1) -n was not given. 211 * (2) Address is foreign and -f was given. If -f was not 212 * present, f_netmask and f_local are 0 and the second 213 * test will succeed. 214 * (3) The host portion is not 0 (i.e., a network address). 215 * (4) The host portion is not broadcast. 216 */ 217 if (!nflag && (addr & f_netmask) == f_localnet 218 && (addr &~ netmask) != 0 && (addr | netmask) != 0xffffffff) { 219 if (!setjmp(getname_env)) { 220 (void)signal(SIGALRM, nohostname); 221 (void)alarm(20); 222 hp = gethostbyaddr((char *)&addr, 4, AF_INET); 223 (void)alarm(0); 224 if (hp) { 225 char *dotp; 226 227 p->name = savestr(hp->h_name); 228 if (Nflag) { 229 /* Remove domain qualifications */ 230 dotp = strchr(p->name, '.'); 231 if (dotp) 232 *dotp = '\0'; 233 } 234 return (p->name); 235 } 236 } 237 } 238 p->name = savestr(intoa(addr)); 239 return (p->name); 240} 241 242static char hex[] = "0123456789abcdef"; 243 244 245/* Find the hash node that corresponds the ether address 'ep' */ 246 247static inline struct enamemem * 248lookup_emem(const u_char *ep) 249{ 250 register u_int i, j, k; 251 struct enamemem *tp; 252 253 k = (ep[0] << 8) | ep[1]; 254 j = (ep[2] << 8) | ep[3]; 255 i = (ep[4] << 8) | ep[5]; 256 257 tp = &enametable[(i ^ j) & (HASHNAMESIZE-1)]; 258 while (tp->e_nxt) 259 if (tp->e_addr0 == i && 260 tp->e_addr1 == j && 261 tp->e_addr2 == k) 262 return tp; 263 else 264 tp = tp->e_nxt; 265 tp->e_addr0 = i; 266 tp->e_addr1 = j; 267 tp->e_addr2 = k; 268 tp->e_nxt = (struct enamemem *)calloc(1, sizeof(*tp)); 269 if (tp->e_nxt == NULL) 270 error("lookup_emem: calloc"); 271 272 return tp; 273} 274 275/* Find the hash node that corresponds the NSAP 'nsap' */ 276 277static inline struct enamemem * 278lookup_nsap(register const u_char *nsap) 279{ 280 register u_int i, j, k; 281 int nlen = *nsap; 282 struct enamemem *tp; 283 const u_char *ensap = nsap + nlen - 6; 284 285 if (nlen > 6) { 286 k = (ensap[0] << 8) | ensap[1]; 287 j = (ensap[2] << 8) | ensap[3]; 288 i = (ensap[4] << 8) | ensap[5]; 289 } 290 else 291 i = j = k = 0; 292 293 tp = &nsaptable[(i ^ j) & (HASHNAMESIZE-1)]; 294 while (tp->e_nxt) 295 if (tp->e_addr0 == i && 296 tp->e_addr1 == j && 297 tp->e_addr2 == k && 298 tp->e_nsap[0] == nlen && 299 memcmp((char *)&(nsap[1]), 300 (char *)&(tp->e_nsap[1]), nlen) == 0) 301 return tp; 302 else 303 tp = tp->e_nxt; 304 tp->e_addr0 = i; 305 tp->e_addr1 = j; 306 tp->e_addr2 = k; 307 tp->e_nsap = (u_char *)malloc(nlen + 1); 308 if (tp->e_nsap == NULL) 309 error("lookup_nsap: malloc"); 310 memcpy(tp->e_nsap, nsap, nlen + 1); 311 tp->e_nxt = (struct enamemem *)calloc(1, sizeof(*tp)); 312 if (tp->e_nxt == NULL) 313 error("lookup_nsap: calloc"); 314 315 return tp; 316} 317 318/* Find the hash node that corresponds the protoid 'pi'. */ 319 320static inline struct protoidmem * 321lookup_protoid(const u_char *pi) 322{ 323 register u_int i, j; 324 struct protoidmem *tp; 325 326 /* 5 octets won't be aligned */ 327 i = (((pi[0] << 8) + pi[1]) << 8) + pi[2]; 328 j = (pi[3] << 8) + pi[4]; 329 /* XXX should be endian-insensitive, but do big-endian testing XXX */ 330 331 tp = &protoidtable[(i ^ j) & (HASHNAMESIZE-1)]; 332 while (tp->p_nxt) 333 if (tp->p_oui == i && tp->p_proto == j) 334 return tp; 335 else 336 tp = tp->p_nxt; 337 tp->p_oui = i; 338 tp->p_proto = j; 339 tp->p_nxt = (struct protoidmem *)calloc(1, sizeof(*tp)); 340 if (tp->p_nxt == NULL) 341 error("lookup_protoid: calloc"); 342 343 return tp; 344} 345 346char * 347etheraddr_string(register const u_char *ep) 348{ 349 register u_int i, j; 350 register char *cp; 351 register struct enamemem *tp; 352 char buf[sizeof("00:00:00:00:00:00")]; 353 354 tp = lookup_emem(ep); 355 if (tp->e_name) 356 return (tp->e_name); 357#ifdef HAVE_ETHER_NTOHOST 358 if (!nflag) { 359 char buf[128]; 360 if (ether_ntohost(buf, (struct ether_addr *)ep) == 0) { 361 tp->e_name = savestr(buf); 362 return (tp->e_name); 363 } 364 } 365#endif 366 cp = buf; 367 if ((j = *ep >> 4) != 0) 368 *cp++ = hex[j]; 369 *cp++ = hex[*ep++ & 0xf]; 370 for (i = 5; (int)--i >= 0;) { 371 *cp++ = ':'; 372 if ((j = *ep >> 4) != 0) 373 *cp++ = hex[j]; 374 *cp++ = hex[*ep++ & 0xf]; 375 } 376 *cp = '\0'; 377 tp->e_name = savestr(buf); 378 return (tp->e_name); 379} 380 381char * 382etherproto_string(u_short port) 383{ 384 register char *cp; 385 register struct hnamemem *tp; 386 register u_int32_t i = port; 387 char buf[sizeof("0000")]; 388 389 for (tp = &eprototable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt) 390 if (tp->addr == i) 391 return (tp->name); 392 393 tp->addr = i; 394 tp->nxt = newhnamemem(); 395 396 cp = buf; 397 NTOHS(port); 398 *cp++ = hex[port >> 12 & 0xf]; 399 *cp++ = hex[port >> 8 & 0xf]; 400 *cp++ = hex[port >> 4 & 0xf]; 401 *cp++ = hex[port & 0xf]; 402 *cp++ = '\0'; 403 tp->name = savestr(buf); 404 return (tp->name); 405} 406 407char * 408protoid_string(register const u_char *pi) 409{ 410 register u_int i, j; 411 register char *cp; 412 register struct protoidmem *tp; 413 char buf[sizeof("00:00:00:00:00")]; 414 415 tp = lookup_protoid(pi); 416 if (tp->p_name) 417 return tp->p_name; 418 419 cp = buf; 420 if ((j = *pi >> 4) != 0) 421 *cp++ = hex[j]; 422 *cp++ = hex[*pi++ & 0xf]; 423 for (i = 4; (int)--i >= 0;) { 424 *cp++ = ':'; 425 if ((j = *pi >> 4) != 0) 426 *cp++ = hex[j]; 427 *cp++ = hex[*pi++ & 0xf]; 428 } 429 *cp = '\0'; 430 tp->p_name = savestr(buf); 431 return (tp->p_name); 432} 433 434char * 435llcsap_string(u_char sap) 436{ 437 register char *cp; 438 register struct hnamemem *tp; 439 register u_int32_t i = sap; 440 char buf[sizeof("sap 00")]; 441 442 for (tp = &llcsaptable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt) 443 if (tp->addr == i) 444 return (tp->name); 445 446 tp->addr = i; 447 tp->nxt = newhnamemem(); 448 449 cp = buf; 450 (void)strcpy(cp, "sap "); 451 cp += strlen(cp); 452 *cp++ = hex[sap >> 4 & 0xf]; 453 *cp++ = hex[sap & 0xf]; 454 *cp++ = '\0'; 455 tp->name = savestr(buf); 456 return (tp->name); 457} 458 459char * 460isonsap_string(const u_char *nsap) 461{ 462 register u_int i, nlen = nsap[0]; 463 register char *cp; 464 register struct enamemem *tp; 465 466 tp = lookup_nsap(nsap); 467 if (tp->e_name) 468 return tp->e_name; 469
|
470 tp->e_name = cp = (char *)malloc(nlen * 2 + 2);
|
470 tp->e_name = cp = (char *)malloc(nlen * 2 + 2 + (nlen>>1)); |
471 if (cp == NULL) 472 error("isonsap_string: malloc"); 473 474 nsap++;
|
475 *cp++ = '/';
476 for (i = nlen; (int)--i >= 0;) {
|
475 for (i = 0; i < nlen; i++) { |
476 *cp++ = hex[*nsap >> 4]; 477 *cp++ = hex[*nsap++ & 0xf];
|
478 if (((i & 1) == 0) && (i + 1 < nlen)) 479 *cp++ = '.'; |
480 } 481 *cp = '\0'; 482 return (tp->e_name); 483} 484 485char * 486tcpport_string(u_short port) 487{ 488 register struct hnamemem *tp; 489 register u_int32_t i = port; 490 char buf[sizeof("00000")]; 491 492 for (tp = &tporttable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt) 493 if (tp->addr == i) 494 return (tp->name); 495 496 tp->addr = i; 497 tp->nxt = newhnamemem(); 498 499 (void)sprintf(buf, "%u", i); 500 tp->name = savestr(buf); 501 return (tp->name); 502} 503 504char * 505udpport_string(register u_short port) 506{ 507 register struct hnamemem *tp; 508 register u_int32_t i = port; 509 char buf[sizeof("00000")]; 510 511 for (tp = &uporttable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt) 512 if (tp->addr == i) 513 return (tp->name); 514 515 tp->addr = i; 516 tp->nxt = newhnamemem(); 517 518 (void)sprintf(buf, "%u", i); 519 tp->name = savestr(buf); 520 return (tp->name); 521} 522 523static void 524init_servarray(void) 525{ 526 struct servent *sv; 527 register struct hnamemem *table; 528 register int i; 529 char buf[sizeof("0000000000")]; 530 531 while ((sv = getservent()) != NULL) { 532 int port = ntohs(sv->s_port); 533 i = port & (HASHNAMESIZE-1); 534 if (strcmp(sv->s_proto, "tcp") == 0) 535 table = &tporttable[i]; 536 else if (strcmp(sv->s_proto, "udp") == 0) 537 table = &uporttable[i]; 538 else 539 continue; 540 541 while (table->name) 542 table = table->nxt; 543 if (nflag) { 544 (void)sprintf(buf, "%d", port); 545 table->name = savestr(buf); 546 } else 547 table->name = savestr(sv->s_name); 548 table->addr = port; 549 table->nxt = newhnamemem(); 550 } 551 endservent(); 552} 553 554/*XXX from libbpfc.a */ 555extern struct eproto { 556 char *s; 557 u_short p; 558} eproto_db[]; 559 560static void 561init_eprotoarray(void) 562{ 563 register int i; 564 register struct hnamemem *table; 565 566 for (i = 0; eproto_db[i].s; i++) { 567 int j = ntohs(eproto_db[i].p) & (HASHNAMESIZE-1); 568 table = &eprototable[j]; 569 while (table->name) 570 table = table->nxt; 571 table->name = eproto_db[i].s; 572 table->addr = ntohs(eproto_db[i].p); 573 table->nxt = newhnamemem(); 574 } 575} 576 577/* 578 * SNAP proto IDs with org code 0:0:0 are actually encapsulated Ethernet 579 * types. 580 */ 581static void 582init_protoidarray(void) 583{ 584 register int i; 585 register struct protoidmem *tp; 586 u_char protoid[5]; 587 588 protoid[0] = 0; 589 protoid[1] = 0; 590 protoid[2] = 0; 591 for (i = 0; eproto_db[i].s; i++) { 592 u_short etype = htons(eproto_db[i].p); 593 594 memcpy((char *)&protoid[3], (char *)&etype, 2); 595 tp = lookup_protoid(protoid); 596 tp->p_name = savestr(eproto_db[i].s); 597 } 598} 599 600static struct etherlist { 601 u_char addr[6]; 602 char *name; 603} etherlist[] = { 604 {{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, "Broadcast" }, 605 {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, NULL } 606}; 607 608/* 609 * Initialize the ethers hash table. We take two different approaches 610 * depending on whether or not the system provides the ethers name 611 * service. If it does, we just wire in a few names at startup, 612 * and etheraddr_string() fills in the table on demand. If it doesn't, 613 * then we suck in the entire /etc/ethers file at startup. The idea 614 * is that parsing the local file will be fast, but spinning through 615 * all the ethers entries via NIS & next_etherent might be very slow. 616 * 617 * XXX pcap_next_etherent doesn't belong in the pcap interface, but 618 * since the pcap module already does name-to-address translation, 619 * it's already does most of the work for the ethernet address-to-name 620 * translation, so we just pcap_next_etherent as a convenience. 621 */ 622static void 623init_etherarray(void) 624{ 625 register struct etherlist *el; 626 register struct enamemem *tp; 627#ifdef HAVE_ETHER_NTOHOST 628 char name[256]; 629#else 630 register struct pcap_etherent *ep; 631 register FILE *fp; 632 633 /* Suck in entire ethers file */ 634 fp = fopen(PCAP_ETHERS_FILE, "r"); 635 if (fp != NULL) { 636 while ((ep = pcap_next_etherent(fp)) != NULL) { 637 tp = lookup_emem(ep->addr); 638 tp->e_name = savestr(ep->name); 639 } 640 (void)fclose(fp); 641 } 642#endif 643 644 /* Hardwire some ethernet names */ 645 for (el = etherlist; el->name != NULL; ++el) { 646 tp = lookup_emem(el->addr); 647 /* Don't override existing name */ 648 if (tp->e_name != NULL) 649 continue; 650 651#ifdef HAVE_ETHER_NTOHOST 652 /* Use yp/nis version of name if available */ 653 if (ether_ntohost(name, (struct ether_addr *)el->addr) == 0) { 654 tp->e_name = savestr(name); 655 continue; 656 } 657#endif 658 tp->e_name = el->name; 659 } 660} 661 662static struct tok llcsap_db[] = { 663 { LLCSAP_NULL, "null" }, 664 { LLCSAP_8021B_I, "802.1b-gsap" }, 665 { LLCSAP_8021B_G, "802.1b-isap" }, 666 { LLCSAP_IP, "ip-sap" }, 667 { LLCSAP_PROWAYNM, "proway-nm" }, 668 { LLCSAP_8021D, "802.1d" }, 669 { LLCSAP_RS511, "eia-rs511" }, 670 { LLCSAP_ISO8208, "x.25/llc2" }, 671 { LLCSAP_PROWAY, "proway" }, 672 { LLCSAP_ISONS, "iso-clns" }, 673 { LLCSAP_GLOBAL, "global" }, 674 { 0, NULL } 675}; 676 677static void 678init_llcsaparray(void) 679{ 680 register int i; 681 register struct hnamemem *table; 682 683 for (i = 0; llcsap_db[i].s != NULL; i++) { 684 table = &llcsaptable[llcsap_db[i].v]; 685 while (table->name) 686 table = table->nxt; 687 table->name = llcsap_db[i].s; 688 table->addr = llcsap_db[i].v; 689 table->nxt = newhnamemem(); 690 } 691} 692 693/* 694 * Initialize the address to name translation machinery. We map all 695 * non-local IP addresses to numeric addresses if fflag is true (i.e., 696 * to prevent blocking on the nameserver). localnet is the IP address 697 * of the local network. mask is its subnet mask. 698 */ 699void 700init_addrtoname(int fflag, u_int32_t localnet, u_int32_t mask) 701{ 702 netmask = mask; 703 if (fflag) { 704 f_localnet = localnet; 705 f_netmask = mask; 706 } 707 if (nflag) 708 /* 709 * Simplest way to suppress names. 710 */ 711 return; 712 713 init_etherarray(); 714 init_servarray(); 715 init_eprotoarray(); 716 init_llcsaparray(); 717 init_protoidarray(); 718} 719 720char * 721dnaddr_string(u_short dnaddr) 722{ 723 register struct hnamemem *tp; 724 725 for (tp = &dnaddrtable[dnaddr & (HASHNAMESIZE-1)]; tp->nxt != 0; 726 tp = tp->nxt) 727 if (tp->addr == dnaddr) 728 return (tp->name); 729 730 tp->addr = dnaddr; 731 tp->nxt = newhnamemem(); 732 if (nflag) 733 tp->name = dnnum_string(dnaddr); 734 else 735 tp->name = dnname_string(dnaddr); 736 737 return(tp->name); 738} 739 740/* Return a zero'ed hnamemem struct and cuts down on calloc() overhead */ 741struct hnamemem * 742newhnamemem() 743{ 744 register struct hnamemem *p; 745 static struct hnamemem *ptr = NULL; 746 static u_int num = 0; 747 748 if (num <= 0) { 749 num = 64; 750 ptr = (struct hnamemem *)calloc(num, sizeof (*ptr)); 751 if (ptr == NULL) 752 error("newhnamemem: calloc"); 753 } 754 --num; 755 p = ptr++; 756 return (p); 757}
|