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 2005 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 static struct hostdata *addhost(int, void *, char *, char **); 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(struct in6_addr *ip6addr) 139 { 140 struct hostdata6 *h; 141 struct hostent *hp = NULL; 142 int error_num; 143 char addrstr[INET6_ADDRSTRLEN]; 144 char *addname; 145 struct hostdata *retval; 146 147 for (h = h_table6[iphash(((uint32_t *)ip6addr)[3])]; h; 148 h = h->h6_next) { 149 if (IN6_ARE_ADDR_EQUAL(&h->h6_addr, ip6addr)) 150 return ((struct hostdata *)h); 151 } 152 153 /* not in the hash table, put it in */ 154 if (IN6_IS_ADDR_UNSPECIFIED(ip6addr)) 155 return (addhost(AF_INET6, ip6addr, "UNSPECIFIED", NULL)); 156 157 /* 158 * Set an alarm here so we don't get held up by 159 * an unresponsive name server. 160 * Give it 3 sec to do its work. 161 */ 162 if (! rflg && sigsetjmp(nisjmp, 1) == 0) { 163 (void) snoop_alarm(3, wakeup); 164 hp = getipnodebyaddr(ip6addr, sizeof (struct in6_addr), 165 AF_INET6, &error_num); 166 (void) snoop_alarm(0, wakeup); 167 } else { 168 hp = NULL; 169 } 170 171 if (hp != NULL) 172 addname = hp->h_name; 173 else { 174 (void) inet_ntop(AF_INET6, ip6addr, addrstr, INET6_ADDRSTRLEN); 175 addname = addrstr; 176 } 177 178 retval = addhost(AF_INET6, ip6addr, addname, hp ? hp->h_aliases : NULL); 179 if (hp != NULL) 180 freehostent(hp); 181 return (retval); 182 } 183 184 static struct hostdata * 185 addhost(int family, void *ipaddr, char *name, char **aliases) 186 { 187 register struct hostdata **hp, *n = NULL; 188 extern FILE *namefile; 189 int hashval; 190 static char aname[128]; 191 char *np; 192 static struct hostdata h; 193 int ind; 194 195 switch (family) { 196 case AF_INET: 197 n = (struct hostdata *)malloc(sizeof (struct hostdata4)); 198 if (n == NULL) 199 goto alloc_failed; 200 201 memset(n, 0, sizeof (struct hostdata4)); 202 n->h_hostname = strdup(name); 203 if (n->h_hostname == NULL) 204 goto alloc_failed; 205 206 ((struct hostdata4 *)n)->h4_addr = *(struct in_addr *)ipaddr; 207 hashval = ((struct in_addr *)ipaddr)->s_addr; 208 hp = (struct hostdata **)&h_table4[iphash(hashval)]; 209 break; 210 case AF_INET6: 211 n = (struct hostdata *)malloc(sizeof (struct hostdata6)); 212 if (n == NULL) 213 goto alloc_failed; 214 215 memset(n, 0, sizeof (struct hostdata6)); 216 n->h_hostname = strdup(name); 217 if (n->h_hostname == NULL) 218 goto alloc_failed; 219 220 memcpy(&((struct hostdata6 *)n)->h6_addr, ipaddr, 221 sizeof (struct in6_addr)); 222 hashval = ((int *)ipaddr)[3]; 223 hp = (struct hostdata **)&h_table6[iphash(hashval)]; 224 break; 225 default: 226 fprintf(stderr, "snoop: ERROR: Unknown address family: %d", 227 family); 228 exit(1); 229 } 230 231 n->h_next = *hp; 232 *hp = n; 233 234 if (namefile != NULL) { 235 if (family == AF_INET) { 236 np = inet_ntoa(*(struct in_addr *)ipaddr); 237 if (np) { 238 (void) fprintf(namefile, "%s\t%s", np, name); 239 if (aliases) { 240 for (ind = 0; 241 aliases[ind] != NULL; 242 ind++) { 243 (void) fprintf(namefile, " %s", 244 aliases[ind]); 245 } 246 } 247 (void) fprintf(namefile, "\n"); 248 } 249 } else if (family == AF_INET6) { 250 np = (char *)inet_ntop(AF_INET6, (void *)ipaddr, aname, 251 sizeof (aname)); 252 if (np) { 253 (void) fprintf(namefile, "%s\t%s", np, name); 254 if (aliases) { 255 for (ind = 0; 256 aliases[ind] != NULL; 257 ind++) { 258 (void) fprintf(namefile, " %s", 259 aliases[ind]); 260 } 261 } 262 (void) fprintf(namefile, "\n"); 263 } 264 } else { 265 (void) fprintf(stderr, "addhost: unknown family %d\n", 266 family); 267 } 268 } 269 return (n); 270 271 alloc_failed: 272 if (n) 273 free(n); 274 (void) fprintf(stderr, "addhost: no mem\n"); 275 276 aname[0] = '\0'; 277 memset(&h, 0, sizeof (struct hostdata)); 278 h.h_hostname = aname; 279 return (&h); 280 } 281 282 char * 283 addrtoname(family, ipaddr) 284 int family; 285 void *ipaddr; 286 { 287 switch (family) { 288 case AF_INET: 289 return (iplookup(*(struct in_addr *)ipaddr)->h_hostname); 290 case AF_INET6: 291 return (ip6lookup((struct in6_addr *)ipaddr)->h_hostname); 292 default: 293 fprintf(stderr, "snoop: ERROR: unknown address family: %d\n", 294 family); 295 exit(1); 296 } 297 /* Never reached... */ 298 return (NULL); 299 } 300 301 void 302 load_names(fname) 303 char *fname; 304 { 305 char buf[1024]; 306 char *addr, *name, *alias; 307 FILE *f; 308 unsigned int addrv4; 309 struct in6_addr addrv6; 310 int family; 311 void *naddr; 312 313 (void) fprintf(stderr, "Loading name file %s\n", fname); 314 f = fopen(fname, "r"); 315 if (f == NULL) { 316 perror(fname); 317 return; 318 } 319 320 while (fgets(buf, 1024, f) != NULL) { 321 addr = strtok(buf, SEPARATORS); 322 if (addr == NULL || *addr == '#') 323 continue; 324 if (inet_pton(AF_INET6, addr, (void *)&addrv6) == 1) { 325 family = AF_INET6; 326 naddr = (void *)&addrv6; 327 } else if ((addrv4 = inet_addr(addr)) != -1) { 328 family = AF_INET; 329 naddr = (void *)&addrv4; 330 } 331 name = strtok(NULL, SEPARATORS); 332 if (name == NULL) 333 continue; 334 while ((alias = strtok(NULL, SEPARATORS)) && (*alias != '#')) { 335 (void) addhost(family, naddr, alias, NULL); 336 } 337 (void) addhost(family, naddr, name, NULL); 338 /* Note: certain addresses such as broadcast are skipped */ 339 } 340 341 (void) fclose(f); 342 } 343 344 /* 345 * lgetipnodebyname: looks up hostname in cached address data. This allows 346 * filtering on hostnames from the .names file to work properly, and 347 * avoids name clashes between domains. Note that only the first of the 348 * ipv4, ipv6, or v4mapped address will be returned, because the 349 * cache does not contain information on multi-homed hosts. 350 */ 351 /*ARGSUSED*/ 352 struct hostent * 353 lgetipnodebyname(const char *name, int af, int flags, int *error_num) 354 { 355 int i; 356 struct hostdata4 *h; 357 struct hostdata6 *h6; 358 static struct hostent he; /* host entry */ 359 static struct in6_addr h46_addr[MAXADDRS]; /* v4mapped address */ 360 static char h_name[MAXHOSTNAMELEN]; /* hostname */ 361 static char *list[MAXADDRS]; /* addr_list array */ 362 struct hostent *hp = &he; 363 int ind; 364 365 (void) memset((char *)hp, 0, sizeof (struct hostent)); 366 hp->h_name = h_name; 367 h_name[0] = '\0'; 368 strcpy(h_name, name); 369 370 hp->h_addrtype = AF_INET6; 371 372 hp->h_addr_list = list; 373 for (i = 0; i < MAXADDRS; i++) 374 hp->h_addr_list[i] = NULL; 375 ind = 0; 376 377 /* ipv6 lookup */ 378 if (af == AF_INET6) { 379 hp->h_length = sizeof (struct in6_addr); 380 for (i = 0; i < MAXHASH; i++) { 381 for (h6 = h_table6[i]; h6; h6 = h6->h6_next) { 382 if (strcmp(name, h6->h6_hostname) == 0) { 383 if (ind >= MAXADDRS - 1) { 384 /* too many addresses */ 385 return (hp); 386 } 387 /* found ipv6 addr */ 388 hp->h_addr_list[ind] = 389 (char *)&h6->h6_addr; 390 ind++; 391 } 392 } 393 } 394 } 395 /* ipv4 or v4mapped lookup */ 396 if (af == AF_INET || (flags & AI_ALL)) { 397 for (i = 0; i < MAXHASH; i++) { 398 for (h = h_table4[i]; h; h = h->h4_next) { 399 if (strcmp(name, h->h4_hostname) == 0) { 400 if (ind >= MAXADDRS - 1) { 401 /* too many addresses */ 402 return (hp); 403 } 404 if (af == AF_INET) { 405 /* found ipv4 addr */ 406 hp->h_addrtype = AF_INET; 407 hp->h_length = 408 sizeof (struct in_addr); 409 hp->h_addr_list[ind] = 410 (char *)&h->h4_addr; 411 ind++; 412 } else { 413 /* found v4mapped addr */ 414 hp->h_length = 415 sizeof (struct in6_addr); 416 hp->h_addr_list[ind] = 417 (char *)&h46_addr[ind]; 418 IN6_INADDR_TO_V4MAPPED( 419 &h->h4_addr, 420 &h46_addr[ind]); 421 ind++; 422 } 423 } 424 } 425 } 426 } 427 return (ind > 0 ? hp : NULL); 428 } 429