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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <ctype.h> 29 #include <sys/types.h> 30 #include <sys/socket.h> 31 #include <sys/sockio.h> 32 #include <net/if.h> 33 #include <netinet/in_systm.h> 34 #include <netinet/in.h> 35 #include <netinet/if_ether.h> 36 #include <netinet/ip.h> 37 #include <netdb.h> 38 #include <string.h> 39 #include <signal.h> 40 #include <setjmp.h> 41 #include <arpa/inet.h> 42 #include "snoop.h" 43 44 static 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, const void *, const char *, char **); 74 75 static struct hostdata4 *h_table4[MAXHASH]; 76 static struct hostdata6 *h_table6[MAXHASH]; 77 78 #define iphash(e) ((e) & (MAXHASH-1)) 79 80 /* ARGSUSED */ 81 static void 82 wakeup(int n) 83 { 84 siglongjmp(nisjmp, 1); 85 } 86 87 extern char *inet_ntoa(); 88 89 static struct hostdata * 90 iplookup(struct in_addr ipaddr) 91 { 92 register struct hostdata4 *h; 93 struct hostent *hp = NULL; 94 struct netent *np; 95 int error_num; 96 struct hostdata *retval; 97 98 for (h = h_table4[iphash(ipaddr.s_addr)]; h; h = h->h4_next) { 99 if (h->h4_addr.s_addr == ipaddr.s_addr) 100 return ((struct hostdata *)h); 101 } 102 103 /* not found. Put it in */ 104 105 if (ipaddr.s_addr == htonl(INADDR_BROADCAST)) 106 return (addhost(AF_INET, &ipaddr, "BROADCAST", NULL)); 107 if (ipaddr.s_addr == htonl(INADDR_ANY)) 108 return (addhost(AF_INET, &ipaddr, "OLD-BROADCAST", NULL)); 109 110 /* 111 * Set an alarm here so we don't get held up by 112 * an unresponsive name server. 113 * Give it 3 sec to do its work. 114 */ 115 if (! rflg && sigsetjmp(nisjmp, 1) == 0) { 116 (void) snoop_alarm(3, wakeup); 117 hp = getipnodebyaddr((char *)&ipaddr, sizeof (int), 118 AF_INET, &error_num); 119 if (hp == NULL && inet_lnaof(ipaddr) == 0) { 120 np = getnetbyaddr(inet_netof(ipaddr), AF_INET); 121 if (np) 122 return (addhost(AF_INET, &ipaddr, np->n_name, 123 np->n_aliases)); 124 } 125 (void) snoop_alarm(0, wakeup); 126 } 127 128 retval = addhost(AF_INET, &ipaddr, 129 hp ? hp->h_name : inet_ntoa(ipaddr), 130 hp ? hp->h_aliases : NULL); 131 if (hp != NULL) 132 freehostent(hp); 133 return (retval); 134 } 135 136 static struct hostdata * 137 ip6lookup(const struct in6_addr *ip6addr) 138 { 139 struct hostdata6 *h; 140 struct hostent *hp = NULL; 141 int error_num; 142 char addrstr[INET6_ADDRSTRLEN]; 143 char *addname; 144 struct hostdata *retval; 145 146 for (h = h_table6[iphash(((uint32_t *)ip6addr)[3])]; h; 147 h = h->h6_next) { 148 if (IN6_ARE_ADDR_EQUAL(&h->h6_addr, ip6addr)) 149 return ((struct hostdata *)h); 150 } 151 152 /* not in the hash table, put it in */ 153 if (IN6_IS_ADDR_UNSPECIFIED(ip6addr)) 154 return (addhost(AF_INET6, ip6addr, "UNSPECIFIED", NULL)); 155 156 /* 157 * Set an alarm here so we don't get held up by 158 * an unresponsive name server. 159 * Give it 3 sec to do its work. 160 */ 161 if (! rflg && sigsetjmp(nisjmp, 1) == 0) { 162 (void) snoop_alarm(3, wakeup); 163 hp = getipnodebyaddr(ip6addr, sizeof (struct in6_addr), 164 AF_INET6, &error_num); 165 (void) snoop_alarm(0, wakeup); 166 } else { 167 hp = NULL; 168 } 169 170 if (hp != NULL) 171 addname = hp->h_name; 172 else { 173 (void) inet_ntop(AF_INET6, ip6addr, addrstr, INET6_ADDRSTRLEN); 174 addname = addrstr; 175 } 176 177 retval = addhost(AF_INET6, ip6addr, addname, hp ? hp->h_aliases : NULL); 178 if (hp != NULL) 179 freehostent(hp); 180 return (retval); 181 } 182 183 static struct hostdata * 184 addhost(int family, const void *ipaddr, const char *name, char **aliases) 185 { 186 struct hostdata **hp, *n = NULL; 187 extern FILE *namefile; 188 int hashval; 189 static char aname[128]; 190 char *np; 191 static struct hostdata h; 192 int ind; 193 194 switch (family) { 195 case AF_INET: 196 n = (struct hostdata *)malloc(sizeof (struct hostdata4)); 197 if (n == NULL) 198 goto alloc_failed; 199 200 memset(n, 0, sizeof (struct hostdata4)); 201 n->h_hostname = strdup(name); 202 if (n->h_hostname == NULL) 203 goto alloc_failed; 204 205 ((struct hostdata4 *)n)->h4_addr = 206 *(const 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 = ((const 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(*(const 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(int family, const void *ipaddr) 284 { 285 switch (family) { 286 case AF_INET: 287 return (iplookup(*(const struct in_addr *)ipaddr)->h_hostname); 288 case AF_INET6: 289 return (ip6lookup((const struct in6_addr *)ipaddr)->h_hostname); 290 } 291 (void) fprintf(stderr, "snoop: ERROR: unknown address family: %d\n", 292 family); 293 exit(1); 294 /* NOTREACHED */ 295 } 296 297 void 298 load_names(fname) 299 char *fname; 300 { 301 char buf[1024]; 302 char *addr, *name, *alias; 303 FILE *f; 304 unsigned int addrv4; 305 struct in6_addr addrv6; 306 int family; 307 void *naddr; 308 309 (void) fprintf(stderr, "Loading name file %s\n", fname); 310 f = fopen(fname, "r"); 311 if (f == NULL) { 312 perror(fname); 313 return; 314 } 315 316 while (fgets(buf, 1024, f) != NULL) { 317 addr = strtok(buf, SEPARATORS); 318 if (addr == NULL || *addr == '#') 319 continue; 320 if (inet_pton(AF_INET6, addr, (void *)&addrv6) == 1) { 321 family = AF_INET6; 322 naddr = (void *)&addrv6; 323 } else if ((addrv4 = inet_addr(addr)) != (ulong_t)-1) { 324 family = AF_INET; 325 naddr = (void *)&addrv4; 326 } 327 name = strtok(NULL, SEPARATORS); 328 if (name == NULL) 329 continue; 330 while ((alias = strtok(NULL, SEPARATORS)) != NULL && 331 (*alias != '#')) { 332 (void) addhost(family, naddr, alias, NULL); 333 } 334 (void) addhost(family, naddr, name, NULL); 335 /* Note: certain addresses such as broadcast are skipped */ 336 } 337 338 (void) fclose(f); 339 } 340 341 /* 342 * lgetipnodebyname: looks up hostname in cached address data. This allows 343 * filtering on hostnames from the .names file to work properly, and 344 * avoids name clashes between domains. Note that only the first of the 345 * ipv4, ipv6, or v4mapped address will be returned, because the 346 * cache does not contain information on multi-homed hosts. 347 */ 348 /*ARGSUSED*/ 349 struct hostent * 350 lgetipnodebyname(const char *name, int af, int flags, int *error_num) 351 { 352 int i; 353 struct hostdata4 *h; 354 struct hostdata6 *h6; 355 static struct hostent he; /* host entry */ 356 static struct in6_addr h46_addr[MAXADDRS]; /* v4mapped address */ 357 static char h_name[MAXHOSTNAMELEN]; /* hostname */ 358 static char *list[MAXADDRS]; /* addr_list array */ 359 struct hostent *hp = &he; 360 int ind; 361 362 (void) memset((char *)hp, 0, sizeof (struct hostent)); 363 hp->h_name = h_name; 364 h_name[0] = '\0'; 365 strcpy(h_name, name); 366 367 hp->h_addrtype = AF_INET6; 368 369 hp->h_addr_list = list; 370 for (i = 0; i < MAXADDRS; i++) 371 hp->h_addr_list[i] = NULL; 372 ind = 0; 373 374 /* ipv6 lookup */ 375 if (af == AF_INET6) { 376 hp->h_length = sizeof (struct in6_addr); 377 for (i = 0; i < MAXHASH; i++) { 378 for (h6 = h_table6[i]; h6; h6 = h6->h6_next) { 379 if (strcmp(name, h6->h6_hostname) == 0) { 380 if (ind >= MAXADDRS - 1) { 381 /* too many addresses */ 382 return (hp); 383 } 384 /* found ipv6 addr */ 385 hp->h_addr_list[ind] = 386 (char *)&h6->h6_addr; 387 ind++; 388 } 389 } 390 } 391 } 392 /* ipv4 or v4mapped lookup */ 393 if (af == AF_INET || (flags & AI_ALL)) { 394 for (i = 0; i < MAXHASH; i++) { 395 for (h = h_table4[i]; h; h = h->h4_next) { 396 if (strcmp(name, h->h4_hostname) == 0) { 397 if (ind >= MAXADDRS - 1) { 398 /* too many addresses */ 399 return (hp); 400 } 401 if (af == AF_INET) { 402 /* found ipv4 addr */ 403 hp->h_addrtype = AF_INET; 404 hp->h_length = 405 sizeof (struct in_addr); 406 hp->h_addr_list[ind] = 407 (char *)&h->h4_addr; 408 ind++; 409 } else { 410 /* found v4mapped addr */ 411 hp->h_length = 412 sizeof (struct in6_addr); 413 hp->h_addr_list[ind] = 414 (char *)&h46_addr[ind]; 415 IN6_INADDR_TO_V4MAPPED( 416 &h->h4_addr, 417 &h46_addr[ind]); 418 ind++; 419 } 420 } 421 } 422 } 423 } 424 return (ind > 0 ? hp : NULL); 425 } 426