Home | History | Annotate | Download | only in snoop
      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