1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1991-2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" /* SunOS */ 28 29 #include <stdio.h> 30 #include <ctype.h> 31 #include <sys/types.h> 32 #include <sys/socket.h> 33 #include <sys/sockio.h> 34 #include <net/if.h> 35 #include <netinet/in_systm.h> 36 #include <netinet/in.h> 37 #include <netinet/if_ether.h> 38 #include <netinet/ip.h> 39 #include <netdb.h> 40 #include <string.h> 41 #include <signal.h> 42 #include <setjmp.h> 43 44 sigjmp_buf nisjmp; 45 46 #define MAXHASH 1024 /* must be a power of 2 */ 47 48 #define SEPARATORS " \t\n" 49 50 struct hostdata { 51 struct hostdata *h_next; 52 char *h_hostname; 53 int h_pktsout; 54 int h_pktsin; 55 }; 56 57 struct hostdata4 { 58 struct hostdata4 *h4_next; 59 char *h4_hostname; 60 int h4_pktsout; 61 int h4_pktsin; 62 struct in_addr h4_addr; 63 }; 64 65 struct hostdata6 { 66 struct hostdata6 *h6_next; 67 char *h6_hostname; 68 int h6_pktsout; 69 int h6_pktsin; 70 struct in6_addr h6_addr; 71 }; 72 73 struct hostdata *addhost(); 74 75 struct hostdata4 *h_table4[MAXHASH]; 76 struct hostdata6 *h_table6[MAXHASH]; 77 78 #define iphash(e) ((e) & (MAXHASH-1)) 79 80 static void 81 wakeup(n) 82 int n; 83 { 84 siglongjmp(nisjmp, 1); 85 } 86 87 extern char *inet_ntoa(); 88 extern boolean_t rflg; 89 90 static struct hostdata * 91 iplookup(struct in_addr ipaddr) 92 { 93 register struct hostdata4 *h; 94 struct hostent *hp = NULL; 95 struct netent *np; 96 int error_num; 97 struct hostdata *retval; 98 99 for (h = h_table4[iphash(ipaddr.s_addr)]; h; h = h->h4_next) { 100 if (h->h4_addr.s_addr == ipaddr.s_addr) 101 return ((struct hostdata *)h); 102 } 103 104 /* not found. Put it in */ 105 106 if (ipaddr.s_addr == htonl(INADDR_BROADCAST)) 107 return (addhost(AF_INET, &ipaddr, "BROADCAST", NULL)); 108 if (ipaddr.s_addr == htonl(INADDR_ANY)) 109 return (addhost(AF_INET, &ipaddr, "OLD-BROADCAST", NULL)); 110 111 /* 112 * Set an alarm here so we don't get held up by 113 * an unresponsive name server. 114 * Give it 3 sec to do its work. 115 */ 116 if (! rflg && sigsetjmp(nisjmp, 1) == 0) { 117 (void) snoop_alarm(3, wakeup); 118 hp = getipnodebyaddr((char *)&ipaddr, sizeof (int), 119 AF_INET, &error_num); 120 if (hp == NULL && inet_lnaof(ipaddr) == 0) { 121 np = getnetbyaddr(inet_netof(ipaddr), AF_INET); 122 if (np) 123 return (addhost(AF_INET, &ipaddr, np->n_name, 124 np->n_aliases)); 125 } 126 (void) snoop_alarm(0, wakeup); 127 } 128 129 retval = addhost(AF_INET, &ipaddr, 130 hp ? hp->h_name : inet_ntoa(ipaddr), 131 hp ? hp->h_aliases : NULL); 132 if (hp != NULL) 133 freehostent(hp); 134 return (retval); 135 } 136 137 static struct hostdata * 138 ip6lookup(ip6addr) 139 struct in6_addr *ip6addr; 140 { 141 struct hostdata6 *h; 142 struct hostent *hp = NULL; 143 int error_num; 144 char addrstr[INET6_ADDRSTRLEN]; 145 const char *addname; 146 struct hostdata *retval; 147 148 for (h = h_table6[iphash(((uint32_t *)ip6addr)[3])]; h; 149 h = h->h6_next) { 150 if (IN6_ARE_ADDR_EQUAL(&h->h6_addr, ip6addr)) 151 return ((struct hostdata *)h); 152 } 153 154 /* not in the hash table, put it in */ 155 if (IN6_IS_ADDR_UNSPECIFIED(ip6addr)) 156 return (addhost(AF_INET6, ip6addr, "UNSPECIFIED", NULL)); 157 158 /* 159 * Set an alarm here so we don't get held up by 160 * an unresponsive name server. 161 * Give it 3 sec to do its work. 162 */ 163 if (! rflg && sigsetjmp(nisjmp, 1) == 0) { 164 (void) snoop_alarm(3, wakeup); 165 hp = getipnodebyaddr(ip6addr, sizeof (struct in6_addr), 166 AF_INET6, &error_num); 167 (void) snoop_alarm(0, wakeup); 168 } else { 169 hp = NULL; 170 } 171 172 if (hp != NULL) 173 addname = hp->h_name; 174 else { 175 (void) inet_ntop(AF_INET6, ip6addr, addrstr, INET6_ADDRSTRLEN); 176 addname = addrstr; 177 } 178 179 retval = addhost(AF_INET6, ip6addr, addname, hp ? hp->h_aliases : NULL); 180 if (hp != NULL) 181 freehostent(hp); 182 return (retval); 183 } 184 185 static struct hostdata * 186 addhost(family, ipaddr, name, aliases) 187 int family; 188 void *ipaddr; 189 char *name; 190 char **aliases; 191 { 192 register struct hostdata **hp, *n = NULL; 193 extern FILE *namefile; 194 int hashval; 195 static char aname[128]; 196 char *np; 197 static struct hostdata h; 198 int ind; 199 200 switch (family) { 201 case AF_INET: 202 n = (struct hostdata *)malloc(sizeof (struct hostdata4)); 203 if (n == NULL) 204 goto alloc_failed; 205 206 memset(n, 0, sizeof (struct hostdata4)); 207 n->h_hostname = strdup(name); 208 if (n->h_hostname == NULL) 209 goto alloc_failed; 210 211 ((struct hostdata4 *)n)->h4_addr = *(struct in_addr *)ipaddr; 212 hashval = ((struct in_addr *)ipaddr)->s_addr; 213 hp = (struct hostdata **)&h_table4[iphash(hashval)]; 214 break; 215 case AF_INET6: 216 n = (struct hostdata *)malloc(sizeof (struct hostdata6)); 217 if (n == NULL) 218 goto alloc_failed; 219 220 memset(n, 0, sizeof (struct hostdata6)); 221 n->h_hostname = strdup(name); 222 if (n->h_hostname == NULL) 223 goto alloc_failed; 224 225 memcpy(&((struct hostdata6 *)n)->h6_addr, ipaddr, 226 sizeof (struct in6_addr)); 227 hashval = ((int *)ipaddr)[3]; 228 hp = (struct hostdata **)&h_table6[iphash(hashval)]; 229 break; 230 default: 231 fprintf(stderr, "snoop: ERROR: Unknown address family: %d", 232 family); 233 exit(1); 234 } 235 236 n->h_next = *hp; 237 *hp = n; 238 239 if (namefile != NULL) { 240 if (family == AF_INET) { 241 np = inet_ntoa(*(struct in_addr *)ipaddr); 242 if (np) { 243 (void) fprintf(namefile, "%s\t%s", np, name); 244 if (aliases) { 245 for (ind = 0; 246 aliases[ind] != NULL; 247 ind++) { 248 (void) fprintf(namefile, " %s", 249 aliases[ind]); 250 } 251 } 252 (void) fprintf(namefile, "\n"); 253 } 254 } else if (family == AF_INET6) { 255 np = (char *)inet_ntop(AF_INET6, (void *)ipaddr, aname, 256 sizeof (aname)); 257 if (np) { 258 (void) fprintf(namefile, "%s\t%s", np, name); 259 if (aliases) { 260 for (ind = 0; 261 aliases[ind] != NULL; 262 ind++) { 263 (void) fprintf(namefile, " %s", 264 aliases[ind]); 265 } 266 } 267 (void) fprintf(namefile, "\n"); 268 } 269 } else { 270 (void) fprintf(stderr, "addhost: unknown family %d\n", 271 family); 272 } 273 } 274 return (n); 275 276 alloc_failed: 277 if (n) 278 free(n); 279 (void) fprintf(stderr, "addhost: no mem\n"); 280 281 aname[0] = '\0'; 282 memset(&h, 0, sizeof (struct hostdata)); 283 h.h_hostname = aname; 284 return (&h); 285 } 286 287 char * 288 addrtoname(family, ipaddr) 289 int family; 290 void *ipaddr; 291 { 292 switch (family) { 293 case AF_INET: 294 return (iplookup(*(struct in_addr *)ipaddr)->h_hostname); 295 case AF_INET6: 296 return (ip6lookup((struct in6_addr *)ipaddr)->h_hostname); 297 default: 298 fprintf(stderr, "snoop: ERROR: unknown address family: %d\n", 299 family); 300 exit(1); 301 } 302 } 303 304 void 305 load_names(fname) 306 char *fname; 307 { 308 char buf[1024]; 309 char *addr, *name, *alias; 310 FILE *f; 311 unsigned int addrv4; 312 struct in6_addr addrv6; 313 int family; 314 void *naddr; 315 316 (void) fprintf(stderr, "Loading name file %s\n", fname); 317 f = fopen(fname, "r"); 318 if (f == NULL) { 319 perror(fname); 320 return; 321 } 322 323 while (fgets(buf, 1024, f) != NULL) { 324 addr = strtok(buf, SEPARATORS); 325 if (addr == NULL || *addr == '#') 326 continue; 327 if (inet_pton(AF_INET6, addr, (void *)&addrv6) == 1) { 328 family = AF_INET6; 329 naddr = (void *)&addrv6; 330 } else if ((addrv4 = inet_addr(addr)) != -1) { 331 family = AF_INET; 332 naddr = (void *)&addrv4; 333 } 334 name = strtok(NULL, SEPARATORS); 335 if (name == NULL) 336 continue; 337 while ((alias = strtok(NULL, SEPARATORS)) && (*alias != '#')) { 338 (void) addhost(family, naddr, alias, NULL); 339 } 340 (void) addhost(family, naddr, name, NULL); 341 /* Note: certain addresses such as broadcast are skipped */ 342 } 343 344 (void) fclose(f); 345 } 346 347 /* 348 * lgetipnodebyname: looks up hostname in cached address data. This allows 349 * filtering on hostnames from the .names file to work properly, and 350 * avoids name clashes between domains. Note that only the first of the 351 * ipv4, ipv6, or v4mapped address will be returned, because the 352 * cache does not contain information on multi-homed hosts. 353 */ 354 /*ARGSUSED*/ 355 struct hostent * 356 lgetipnodebyname(const char *name, int af, int flags, int *error_num) 357 { 358 int i; 359 struct hostdata4 *h; 360 struct hostdata6 *h6; 361 static struct hostent he; /* host entry */ 362 static struct in6_addr h46_addr[MAXADDRS]; /* v4mapped address */ 363 static char h_name[MAXHOSTNAMELEN]; /* hostname */ 364 static char *list[MAXADDRS]; /* addr_list array */ 365 struct hostent *hp = &he; 366 int ind; 367 368 (void) memset((char *)hp, 0, sizeof (struct hostent)); 369 hp->h_name = h_name; 370 h_name[0] = '\0'; 371 strcpy(h_name, name); 372 373 hp->h_addrtype = AF_INET6; 374 375 hp->h_addr_list = list; 376 for (i = 0; i < MAXADDRS; i++) 377 hp->h_addr_list[i] = NULL; 378 ind = 0; 379 380 /* ipv6 lookup */ 381 if (af == AF_INET6) { 382 hp->h_length = sizeof (struct in6_addr); 383 for (i = 0; i < MAXHASH; i++) { 384 for (h6 = h_table6[i]; h6; h6 = h6->h6_next) { 385 if (strcmp(name, h6->h6_hostname) == 0) { 386 if (ind >= MAXADDRS - 1) { 387 /* too many addresses */ 388 return (hp); 389 } 390 /* found ipv6 addr */ 391 hp->h_addr_list[ind] = 392 (char *)&h6->h6_addr; 393 ind++; 394 } 395 } 396 } 397 } 398 /* ipv4 or v4mapped lookup */ 399 if (af == AF_INET || (flags & AI_ALL)) { 400 for (i = 0; i < MAXHASH; i++) { 401 for (h = h_table4[i]; h; h = h->h4_next) { 402 if (strcmp(name, h->h4_hostname) == 0) { 403 if (ind >= MAXADDRS - 1) { 404 /* too many addresses */ 405 return (hp); 406 } 407 if (af == AF_INET) { 408 /* found ipv4 addr */ 409 hp->h_addrtype = AF_INET; 410 hp->h_length = 411 sizeof (struct in_addr); 412 hp->h_addr_list[ind] = 413 (char *)&h->h4_addr; 414 ind++; 415 } else { 416 /* found v4mapped addr */ 417 hp->h_length = 418 sizeof (struct in6_addr); 419 hp->h_addr_list[ind] = 420 (char *)&h46_addr[ind]; 421 IN6_INADDR_TO_V4MAPPED( 422 &h->h4_addr, 423 &h46_addr[ind]); 424 ind++; 425 } 426 } 427 } 428 } 429 } 430 return (ind > 0 ? hp : NULL); 431 } 432