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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" /* SunOS */ 27 28 #include <stdio.h> 29 #include <stdlib.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 #include <arpa/inet.h> 44 #include "snoop.h" 45 46 static sigjmp_buf nisjmp; 47 48 #define MAXHASH 1024 /* must be a power of 2 */ 49 50 #define SEPARATORS " \t\n" 51 52 struct hostdata { 53 struct hostdata *h_next; 54 char *h_hostname; 55 int h_pktsout; 56 int h_pktsin; 57 }; 58 59 struct hostdata4 { 60 struct hostdata4 *h4_next; 61 char *h4_hostname; 62 int h4_pktsout; 63 int h4_pktsin; 64 struct in_addr h4_addr; 65 }; 66 67 struct hostdata6 { 68 struct hostdata6 *h6_next; 69 char *h6_hostname; 70 int h6_pktsout; 71 int h6_pktsin; 72 struct in6_addr h6_addr; 73 }; 74 75 static struct hostdata *addhost(int, const void *, const char *, char **); 76 77 static struct hostdata4 *h_table4[MAXHASH]; 78 static struct hostdata6 *h_table6[MAXHASH]; 79 80 #define iphash(e) ((e) & (MAXHASH-1)) 81 82 /* ARGSUSED */ 83 static void 84 wakeup(int n) 85 { 86 siglongjmp(nisjmp, 1); 87 } 88 89 extern char *inet_ntoa(); 90 extern boolean_t rflg; 91 92 static struct hostdata * 93 iplookup(struct in_addr ipaddr) 94 { 95 register struct hostdata4 *h; 96 struct hostent *hp = NULL; 97 struct netent *np; 98 int error_num; 99 struct hostdata *retval; 100 101 for (h = h_table4[iphash(ipaddr.s_addr)]; h; h = h->h4_next) { 102 if (h->h4_addr.s_addr == ipaddr.s_addr) 103 return ((struct hostdata *)h); 104 } 105 106 /* not found. Put it in */ 107 108 if (ipaddr.s_addr == htonl(INADDR_BROADCAST)) 109 return (addhost(AF_INET, &ipaddr, "BROADCAST", NULL)); 110 if (ipaddr.s_addr == htonl(INADDR_ANY)) 111 return (addhost(AF_INET, &ipaddr, "OLD-BROADCAST", NULL)); 112 113 /* 114 * Set an alarm here so we don't get held up by 115 * an unresponsive name server. 116 * Give it 3 sec to do its work. 117 */ 118 if (! rflg && sigsetjmp(nisjmp, 1) == 0) { 119 (void) snoop_alarm(3, wakeup); 120 hp = getipnodebyaddr((char *)&ipaddr, sizeof (int), 121 AF_INET, &error_num); 122 if (hp == NULL && inet_lnaof(ipaddr) == 0) { 123 np = getnetbyaddr(inet_netof(ipaddr), AF_INET); 124 if (np) 125 return (addhost(AF_INET, &ipaddr, np->n_name, 126 np->n_aliases)); 127 } 128 (void) snoop_alarm(0, wakeup); 129 } 130 131 retval = addhost(AF_INET, &ipaddr, 132 hp ? hp->h_name : inet_ntoa(ipaddr), 133 hp ? hp->h_aliases : NULL); 134 if (hp != NULL) 135 freehostent(hp); 136 return (retval); 137 } 138 139 static struct hostdata * 140 ip6lookup(const struct in6_addr *ip6addr) 141 { 142 struct hostdata6 *h; 143 struct hostent *hp = NULL; 144 int error_num; 145 char addrstr[INET6_ADDRSTRLEN]; 146 char *addname; 147 struct hostdata *retval; 148 149 for (h = h_table6[iphash(((uint32_t *)ip6addr)[3])]; h; 150 h = h->h6_next) { 151 if (IN6_ARE_ADDR_EQUAL(&h->h6_addr, ip6addr)) 152 return ((struct hostdata *)h); 153 } 154 155 /* not in the hash table, put it in */ 156 if (IN6_IS_ADDR_UNSPECIFIED(ip6addr)) 157 return (addhost(AF_INET6, ip6addr, "UNSPECIFIED", NULL)); 158 159 /* 160 * Set an alarm here so we don't get held up by 161 * an unresponsive name server. 162 * Give it 3 sec to do its work. 163 */ 164 if (! rflg && sigsetjmp(nisjmp, 1) == 0) { 165 (void) snoop_alarm(3, wakeup); 166 hp = getipnodebyaddr(ip6addr, sizeof (struct in6_addr), 167 AF_INET6, &error_num); 168 (void) snoop_alarm(0, wakeup); 169 } else { 170 hp = NULL; 171 } 172 173 if (hp != NULL) 174 addname = hp->h_name; 175 else { 176 (void) inet_ntop(AF_INET6, ip6addr, addrstr, INET6_ADDRSTRLEN); 177 addname = addrstr; 178 } 179 180 retval = addhost(AF_INET6, ip6addr, addname, hp ? hp->h_aliases : NULL); 181 if (hp != NULL) 182 freehostent(hp); 183 return (retval); 184 } 185 186 static struct hostdata * 187 addhost(int family, const void *ipaddr, const char *name, char **aliases) 188 { 189 struct hostdata **hp, *n = NULL; 190 extern FILE *namefile; 191 int hashval; 192 static char aname[128]; 193 char *np; 194 static struct hostdata h; 195 int ind; 196 197 switch (family) { 198 case AF_INET: 199 n = (struct hostdata *)malloc(sizeof (struct hostdata4)); 200 if (n == NULL) 201 goto alloc_failed; 202 203 memset(n, 0, sizeof (struct hostdata4)); 204 n->h_hostname = strdup(name); 205 if (n->h_hostname == NULL) 206 goto alloc_failed; 207 208 ((struct hostdata4 *)n)->h4_addr = 209 *(const struct in_addr *)ipaddr; 210 hashval = ((struct in_addr *)ipaddr)->s_addr; 211 hp = (struct hostdata **)&h_table4[iphash(hashval)]; 212 break; 213 case AF_INET6: 214 n = (struct hostdata *)malloc(sizeof (struct hostdata6)); 215 if (n == NULL) 216 goto alloc_failed; 217 218 memset(n, 0, sizeof (struct hostdata6)); 219 n->h_hostname = strdup(name); 220 if (n->h_hostname == NULL) 221 goto alloc_failed; 222 223 memcpy(&((struct hostdata6 *)n)->h6_addr, ipaddr, 224 sizeof (struct in6_addr)); 225 hashval = ((const int *)ipaddr)[3]; 226 hp = (struct hostdata **)&h_table6[iphash(hashval)]; 227 break; 228 default: 229 fprintf(stderr, "snoop: ERROR: Unknown address family: %d", 230 family); 231 exit(1); 232 } 233 234 n->h_next = *hp; 235 *hp = n; 236 237 if (namefile != NULL) { 238 if (family == AF_INET) { 239 np = inet_ntoa(*(const struct in_addr *)ipaddr); 240 if (np) { 241 (void) fprintf(namefile, "%s\t%s", np, name); 242 if (aliases) { 243 for (ind = 0; 244 aliases[ind] != NULL; 245 ind++) { 246 (void) fprintf(namefile, " %s", 247 aliases[ind]); 248 } 249 } 250 (void) fprintf(namefile, "\n"); 251 } 252 } else if (family == AF_INET6) { 253 np = (char *)inet_ntop(AF_INET6, (void *)ipaddr, aname, 254 sizeof (aname)); 255 if (np) { 256 (void) fprintf(namefile, "%s\t%s", np, name); 257 if (aliases) { 258 for (ind = 0; 259 aliases[ind] != NULL; 260 ind++) { 261 (void) fprintf(namefile, " %s", 262 aliases[ind]); 263 } 264 } 265 (void) fprintf(namefile, "\n"); 266 } 267 } else { 268 (void) fprintf(stderr, "addhost: unknown family %d\n", 269 family); 270 } 271 } 272 return (n); 273 274 alloc_failed: 275 if (n) 276 free(n); 277 (void) fprintf(stderr, "addhost: no mem\n"); 278 279 aname[0] = '\0'; 280 memset(&h, 0, sizeof (struct hostdata)); 281 h.h_hostname = aname; 282 return (&h); 283 } 284 285 char * 286 addrtoname(int family, const void *ipaddr) 287 { 288 switch (family) { 289 case AF_INET: 290 return (iplookup(*(const struct in_addr *)ipaddr)->h_hostname); 291 case AF_INET6: 292 return (ip6lookup((const struct in6_addr *)ipaddr)->h_hostname); 293 } 294 (void) fprintf(stderr, "snoop: ERROR: unknown address family: %d\n", 295 family); 296 exit(1); 297 /* NOTREACHED */ 298 } 299 300 void 301 load_names(fname) 302 char *fname; 303 { 304 char buf[1024]; 305 char *addr, *name, *alias; 306 FILE *f; 307 unsigned int addrv4; 308 struct in6_addr addrv6; 309 int family; 310 void *naddr; 311 312 (void) fprintf(stderr, "Loading name file %s\n", fname); 313 f = fopen(fname, "r"); 314 if (f == NULL) { 315 perror(fname); 316 return; 317 } 318 319 while (fgets(buf, 1024, f) != NULL) { 320 addr = strtok(buf, SEPARATORS); 321 if (addr == NULL || *addr == '#') 322 continue; 323 if (inet_pton(AF_INET6, addr, (void *)&addrv6) == 1) { 324 family = AF_INET6; 325 naddr = (void *)&addrv6; 326 } else if ((addrv4 = inet_addr(addr)) != (ulong_t)-1) { 327 family = AF_INET; 328 naddr = (void *)&addrv4; 329 } 330 name = strtok(NULL, SEPARATORS); 331 if (name == NULL) 332 continue; 333 while ((alias = strtok(NULL, SEPARATORS)) != NULL && 334 (*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