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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright (c) 2017, Joyent, Inc.
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <sys/sockio.h>
34 #include <netinet/in_systm.h>
35 #include <netinet/in.h>
36 #include <netinet/if_ether.h>
37 #include <netinet/ip.h>
42 #include <arpa/inet.h>
46 static sigjmp_buf nisjmp
;
47 static hrtime_t snoop_lastwarn
; /* Last time NS warning fired */
48 static unsigned snoop_warninter
= 60; /* Time in seconds between warnings */
50 #define MAXHASH 1024 /* must be a power of 2 */
52 #define SEPARATORS " \t\n"
55 struct hostdata
*h_next
;
62 struct hostdata4
*h4_next
;
66 struct in_addr h4_addr
;
70 struct hostdata6
*h6_next
;
74 struct in6_addr h6_addr
;
77 static struct hostdata
*addhost(int, const void *, const char *, char **);
79 static struct hostdata4
*h_table4
[MAXHASH
];
80 static struct hostdata6
*h_table6
[MAXHASH
];
82 #define iphash(e) ((e) & (MAXHASH-1))
88 siglongjmp(nisjmp
, 1);
91 extern char *inet_ntoa();
96 hrtime_t now
= gethrtime();
98 if (now
- snoop_lastwarn
>= snoop_warninter
* NANOSEC
) {
100 (void) fprintf(stderr
, "snoop: warning: packets captured, but "
101 "name service lookups are timing out. Use snoop -r to "
102 "disable name service lookups\n");
106 static struct hostdata
*
107 iplookup(struct in_addr ipaddr
)
109 register struct hostdata4
*h
;
110 struct hostent
*hp
= NULL
;
113 struct hostdata
*retval
;
115 for (h
= h_table4
[iphash(ipaddr
.s_addr
)]; h
; h
= h
->h4_next
) {
116 if (h
->h4_addr
.s_addr
== ipaddr
.s_addr
)
117 return ((struct hostdata
*)h
);
120 /* not found. Put it in */
122 if (ipaddr
.s_addr
== htonl(INADDR_BROADCAST
))
123 return (addhost(AF_INET
, &ipaddr
, "BROADCAST", NULL
));
124 if (ipaddr
.s_addr
== htonl(INADDR_ANY
))
125 return (addhost(AF_INET
, &ipaddr
, "OLD-BROADCAST", NULL
));
128 * Set an alarm here so we don't get held up by
129 * an unresponsive name server.
130 * Give it 3 sec to do its work.
133 if (sigsetjmp(nisjmp
, 1) == 0) {
134 (void) snoop_alarm(3, wakeup
);
135 hp
= getipnodebyaddr((char *)&ipaddr
, sizeof (int),
136 AF_INET
, &error_num
);
137 if (hp
== NULL
&& inet_lnaof(ipaddr
) == 0) {
138 np
= getnetbyaddr(inet_netof(ipaddr
), AF_INET
);
140 return (addhost(AF_INET
, &ipaddr
,
141 np
->n_name
, np
->n_aliases
));
143 (void) snoop_alarm(0, wakeup
);
149 retval
= addhost(AF_INET
, &ipaddr
,
150 hp
? hp
->h_name
: inet_ntoa(ipaddr
),
151 hp
? hp
->h_aliases
: NULL
);
157 static struct hostdata
*
158 ip6lookup(const struct in6_addr
*ip6addr
)
161 struct hostent
*hp
= NULL
;
163 char addrstr
[INET6_ADDRSTRLEN
];
165 struct hostdata
*retval
;
167 for (h
= h_table6
[iphash(((uint32_t *)ip6addr
)[3])]; h
;
169 if (IN6_ARE_ADDR_EQUAL(&h
->h6_addr
, ip6addr
))
170 return ((struct hostdata
*)h
);
173 /* not in the hash table, put it in */
174 if (IN6_IS_ADDR_UNSPECIFIED(ip6addr
))
175 return (addhost(AF_INET6
, ip6addr
, "UNSPECIFIED", NULL
));
178 * Set an alarm here so we don't get held up by
179 * an unresponsive name server.
180 * Give it 3 sec to do its work.
183 if (sigsetjmp(nisjmp
, 1) == 0) {
184 (void) snoop_alarm(3, wakeup
);
185 hp
= getipnodebyaddr(ip6addr
, sizeof (struct in6_addr
),
186 AF_INET6
, &error_num
);
187 (void) snoop_alarm(0, wakeup
);
196 addname
= hp
->h_name
;
198 (void) inet_ntop(AF_INET6
, ip6addr
, addrstr
, INET6_ADDRSTRLEN
);
202 retval
= addhost(AF_INET6
, ip6addr
, addname
, hp
? hp
->h_aliases
: NULL
);
208 static struct hostdata
*
209 addhost(int family
, const void *ipaddr
, const char *name
, char **aliases
)
211 struct hostdata
**hp
, *n
= NULL
;
212 extern FILE *namefile
;
214 static char aname
[128];
216 static struct hostdata h
;
221 n
= (struct hostdata
*)malloc(sizeof (struct hostdata4
));
225 memset(n
, 0, sizeof (struct hostdata4
));
226 n
->h_hostname
= strdup(name
);
227 if (n
->h_hostname
== NULL
)
230 ((struct hostdata4
*)n
)->h4_addr
=
231 *(const struct in_addr
*)ipaddr
;
232 hashval
= ((struct in_addr
*)ipaddr
)->s_addr
;
233 hp
= (struct hostdata
**)&h_table4
[iphash(hashval
)];
236 n
= (struct hostdata
*)malloc(sizeof (struct hostdata6
));
240 memset(n
, 0, sizeof (struct hostdata6
));
241 n
->h_hostname
= strdup(name
);
242 if (n
->h_hostname
== NULL
)
245 memcpy(&((struct hostdata6
*)n
)->h6_addr
, ipaddr
,
246 sizeof (struct in6_addr
));
247 hashval
= ((const int *)ipaddr
)[3];
248 hp
= (struct hostdata
**)&h_table6
[iphash(hashval
)];
251 fprintf(stderr
, "snoop: ERROR: Unknown address family: %d",
259 if (namefile
!= NULL
) {
260 if (family
== AF_INET
) {
261 np
= inet_ntoa(*(const struct in_addr
*)ipaddr
);
263 (void) fprintf(namefile
, "%s\t%s", np
, name
);
266 aliases
[ind
] != NULL
;
268 (void) fprintf(namefile
, " %s",
272 (void) fprintf(namefile
, "\n");
274 } else if (family
== AF_INET6
) {
275 np
= (char *)inet_ntop(AF_INET6
, (void *)ipaddr
, aname
,
278 (void) fprintf(namefile
, "%s\t%s", np
, name
);
281 aliases
[ind
] != NULL
;
283 (void) fprintf(namefile
, " %s",
287 (void) fprintf(namefile
, "\n");
290 (void) fprintf(stderr
, "addhost: unknown family %d\n",
299 (void) fprintf(stderr
, "addhost: no mem\n");
302 memset(&h
, 0, sizeof (struct hostdata
));
303 h
.h_hostname
= aname
;
308 addrtoname(int family
, const void *ipaddr
)
312 return (iplookup(*(const struct in_addr
*)ipaddr
)->h_hostname
);
314 return (ip6lookup((const struct in6_addr
*)ipaddr
)->h_hostname
);
316 (void) fprintf(stderr
, "snoop: ERROR: unknown address family: %d\n",
323 load_names(char *fname
)
326 char *addr
, *name
, *alias
;
329 struct in6_addr addrv6
;
333 (void) fprintf(stderr
, "Loading name file %s\n", fname
);
334 f
= fopen(fname
, "r");
340 while (fgets(buf
, 1024, f
) != NULL
) {
341 addr
= strtok(buf
, SEPARATORS
);
342 if (addr
== NULL
|| *addr
== '#')
344 if (inet_pton(AF_INET6
, addr
, (void *)&addrv6
) == 1) {
346 naddr
= (void *)&addrv6
;
347 } else if ((addrv4
= inet_addr(addr
)) != (ulong_t
)-1) {
349 naddr
= (void *)&addrv4
;
351 name
= strtok(NULL
, SEPARATORS
);
354 while ((alias
= strtok(NULL
, SEPARATORS
)) != NULL
&&
356 (void) addhost(family
, naddr
, alias
, NULL
);
358 (void) addhost(family
, naddr
, name
, NULL
);
359 /* Note: certain addresses such as broadcast are skipped */
366 * lgetipnodebyname: looks up hostname in cached address data. This allows
367 * filtering on hostnames from the .names file to work properly, and
368 * avoids name clashes between domains. Note that only the first of the
369 * ipv4, ipv6, or v4mapped address will be returned, because the
370 * cache does not contain information on multi-homed hosts.
374 lgetipnodebyname(const char *name
, int af
, int flags
, int *error_num
)
378 struct hostdata6
*h6
;
379 static struct hostent he
; /* host entry */
380 static struct in6_addr h46_addr
[MAXADDRS
]; /* v4mapped address */
381 static char h_name
[MAXHOSTNAMELEN
]; /* hostname */
382 static char *list
[MAXADDRS
]; /* addr_list array */
383 struct hostent
*hp
= &he
;
386 (void) memset((char *)hp
, 0, sizeof (struct hostent
));
389 strcpy(h_name
, name
);
391 hp
->h_addrtype
= AF_INET6
;
393 hp
->h_addr_list
= list
;
394 for (i
= 0; i
< MAXADDRS
; i
++)
395 hp
->h_addr_list
[i
] = NULL
;
399 if (af
== AF_INET6
) {
400 hp
->h_length
= sizeof (struct in6_addr
);
401 for (i
= 0; i
< MAXHASH
; i
++) {
402 for (h6
= h_table6
[i
]; h6
; h6
= h6
->h6_next
) {
403 if (strcmp(name
, h6
->h6_hostname
) == 0) {
404 if (ind
>= MAXADDRS
- 1) {
405 /* too many addresses */
408 /* found ipv6 addr */
409 hp
->h_addr_list
[ind
] =
410 (char *)&h6
->h6_addr
;
416 /* ipv4 or v4mapped lookup */
417 if (af
== AF_INET
|| (flags
& AI_ALL
)) {
418 for (i
= 0; i
< MAXHASH
; i
++) {
419 for (h
= h_table4
[i
]; h
; h
= h
->h4_next
) {
420 if (strcmp(name
, h
->h4_hostname
) == 0) {
421 if (ind
>= MAXADDRS
- 1) {
422 /* too many addresses */
426 /* found ipv4 addr */
427 hp
->h_addrtype
= AF_INET
;
429 sizeof (struct in_addr
);
430 hp
->h_addr_list
[ind
] =
434 /* found v4mapped addr */
436 sizeof (struct in6_addr
);
437 hp
->h_addr_list
[ind
] =
438 (char *)&h46_addr
[ind
];
439 IN6_INADDR_TO_V4MAPPED(
448 return (ind
> 0 ? hp
: NULL
);