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