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 (c) 1991, 1999 by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdio.h>
30 #include <ctype.h>
31 #include <sys/types.h>
32 #include <unistd.h>
33 #include <malloc.h>
34 #include <sys/socket.h>
35 #include <sys/sockio.h>
36 #include <arpa/inet.h>
37 #include <net/if.h>
38 #include <netinet/in.h>
39 #include <netinet/in_systm.h>
40 #include <netinet/if_ether.h>
41 #include <netinet/ip.h>
42 #include <netdb.h>
43 #include <string.h>
44 #include <signal.h>
45 #include <setjmp.h>
46 
47 /*
48  * Note: If making changes to this file, check also the file
49  *	 cmd/cmd-inet/usr.sbin/snoop/snoop_ipaddr.c
50  *	 as it has the same functions there.
51  */
52 static jmp_buf nisjmp;
53 
54 #define	MAXHASH 1024  /* must be a power of 2 */
55 
56 struct hostdata {
57 	struct hostdata *h_next;
58 	char		*h_hostname;
59 	int		h_pktsout;
60 	int		h_pktsin;
61 };
62 
63 struct hostdata4 {
64 	struct hostdata4	*h4_next;
65 	char		*h4_hostname;
66 	int		h4_pktsout;
67 	int		h4_pktsin;
68 	struct in_addr	h4_addr;
69 };
70 
71 struct hostdata6 {
72 	struct hostdata6	*h6_next;
73 	char		*h6_hostname;
74 	int		h6_pktsout;
75 	int		h6_pktsin;
76 	struct in6_addr	h6_addr;
77 };
78 
79 static struct hostdata *addhost(int, void *, char *);
80 
81 static struct hostdata4 *h_table4[MAXHASH];
82 static struct hostdata6 *h_table6[MAXHASH];
83 
84 #define	iphash(e)  ((e) & (MAXHASH-1))
85 
86 /* ARGSUSED */
87 static void
88 wakeup(int n)
89 {
90 	longjmp(nisjmp, 1);
91 }
92 
93 extern char *inet_ntoa();
94 
95 static struct hostdata *
96 iplookup(ipaddr)
97 	struct in_addr *ipaddr;
98 {
99 	register struct hostdata4 *h;
100 	struct hostent *hp = NULL;
101 	struct netent *np;
102 	int error_num;
103 
104 	for (h = h_table4[iphash(ipaddr->s_addr)]; h; h = h->h4_next) {
105 		if (h->h4_addr.s_addr == ipaddr->s_addr)
106 			return ((struct hostdata *)h);
107 	}
108 
109 	/* not found.  Put it in */
110 
111 	if (ipaddr->s_addr == htonl(INADDR_BROADCAST))
112 		return (addhost(AF_INET, ipaddr, "BROADCAST"));
113 	if (ipaddr->s_addr == htonl(INADDR_ANY))
114 		return (addhost(AF_INET, ipaddr, "OLD-BROADCAST"));
115 
116 	/*
117 	 * Set an alarm here so we don't get held up by
118 	 * an unresponsive name server.
119 	 * Give it 3 sec to do its work.
120 	 */
121 	if (setjmp(nisjmp) == 0) {
122 		(void) signal(SIGALRM, wakeup);
123 		(void) alarm(3);
124 		hp = getipnodebyaddr((char *)ipaddr, sizeof (struct in_addr),
125 		    AF_INET, &error_num);
126 		if (hp == NULL && inet_lnaof(*ipaddr) == 0) {
127 			np = getnetbyaddr(inet_netof(*ipaddr), AF_INET);
128 			if (np)
129 				return (addhost(AF_INET, ipaddr, np->n_name));
130 		}
131 		(void) alarm(0);
132 	} else {
133 		hp = NULL;
134 	}
135 
136 	return (addhost(AF_INET, ipaddr, hp ? hp->h_name : inet_ntoa(*ipaddr)));
137 }
138 
139 static struct hostdata *
140 ip6lookup(ip6addr)
141 	struct in6_addr *ip6addr;
142 {
143 	struct hostdata6 *h;
144 	struct hostent *hp = NULL;
145 	int error_num;
146 	char addrstr[INET6_ADDRSTRLEN];
147 	char *addname;
148 	struct hostdata *retval;
149 
150 	for (h = h_table6[iphash(((uint32_t *)ip6addr)[3])]; h;
151 	    h = h->h6_next) {
152 		if (IN6_ARE_ADDR_EQUAL(&h->h6_addr, ip6addr))
153 			return ((struct hostdata *)h);
154 	}
155 
156 	/* not in the hash table, put it in */
157 	if (IN6_IS_ADDR_UNSPECIFIED(ip6addr))
158 		return (addhost(AF_INET6, ip6addr, "UNSPECIFIED"));
159 
160 	/*
161 	 * Set an alarm here so we don't get held up by
162 	 * an unresponsive name server.
163 	 * Give it 3 sec to do its work.
164 	 */
165 	if (setjmp(nisjmp) == 0) {
166 		(void) signal(SIGALRM, wakeup);
167 		(void) alarm(3);
168 		hp = getipnodebyaddr(ip6addr, sizeof (struct in6_addr),
169 		    AF_INET6, &error_num);
170 		(void) alarm(0);
171 	} else {
172 		hp = NULL;
173 	}
174 
175 	if (hp != NULL)
176 		addname = hp->h_name;
177 	else {
178 		(void) inet_ntop(AF_INET6, ip6addr, addrstr, INET6_ADDRSTRLEN);
179 		addname = addrstr;
180 	}
181 
182 	retval = addhost(AF_INET6, ip6addr, addname);
183 	freehostent(hp);
184 	return (retval);
185 }
186 
187 static struct hostdata *
188 addhost(family, ipaddr, name)
189 	int family;
190 	void *ipaddr;
191 	char *name;
192 {
193 	register struct hostdata **hp, *n;
194 	int hashval;
195 
196 	switch (family) {
197 	case AF_INET:
198 		n = (struct hostdata *)malloc(sizeof (struct hostdata4));
199 		if (n == NULL)
200 			goto alloc_failed;
201 
202 		(void) memset(n, 0, sizeof (struct hostdata4));
203 		n->h_hostname = strdup(name);
204 		if (n->h_hostname == NULL)
205 			goto alloc_failed;
206 
207 		((struct hostdata4 *)n)->h4_addr = *(struct in_addr *)ipaddr;
208 		hashval = ((struct in_addr *)ipaddr)->s_addr;
209 		hp = (struct hostdata **)&h_table4[iphash(hashval)];
210 		break;
211 	case AF_INET6:
212 		n = (struct hostdata *)malloc(sizeof (struct hostdata6));
213 		if (n == NULL)
214 			goto alloc_failed;
215 
216 		(void) memset(n, 0, sizeof (struct hostdata6));
217 		n->h_hostname = strdup(name);
218 		if (n->h_hostname == NULL)
219 			goto alloc_failed;
220 
221 		(void) memcpy(&((struct hostdata6 *)n)->h6_addr, ipaddr,
222 		    sizeof (struct in6_addr));
223 		hashval = ((int *)ipaddr)[3];
224 		hp = (struct hostdata **)&h_table6[iphash(hashval)];
225 		break;
226 	default:
227 		(void) fprintf(stderr,
228 			"nfslog: addhost ERROR: Unknown address family: %d",
229 			family);
230 		return (NULL);
231 	}
232 
233 	n->h_next = *hp;
234 	*hp = n;
235 
236 	return (n);
237 
238 alloc_failed:
239 	(void) fprintf(stderr, "addhost: no mem\n");
240 	if (n != NULL)
241 		free(n);
242 	return (NULL);
243 }
244 
245 char *
246 addrtoname(void *sockp)
247 {
248 	struct hostdata *hostp;
249 	int family = ((struct sockaddr_in *)sockp)->sin_family;
250 
251 	switch (family) {
252 	case AF_INET:
253 		hostp = iplookup(&((struct sockaddr_in *)sockp)->sin_addr);
254 		break;
255 	case AF_INET6:
256 		hostp = ip6lookup(&((struct sockaddr_in6 *)sockp)->sin6_addr);
257 		break;
258 	default:
259 		(void) fprintf(stderr, "nfslog: ERROR: unknown address " \
260 		    "family: %d\n", family);
261 		hostp = NULL;
262 	}
263 	return ((hostp != NULL) ? hostp->h_hostname : NULL);
264 }
265