3 @@ -11,6 +11,9 @@ static char sccsid[] = "@(#) fix_options
8 +#include <sys/socket.h>
10 #include <netinet/in.h>
11 #include <netinet/in_systm.h>
12 #include <netinet/ip.h>
13 @@ -41,6 +44,22 @@ struct request_info *request;
18 + struct sockaddr_storage ss;
22 + * check if this is AF_INET socket
26 + if (getsockname(fd, (struct sockaddr *)&ss, &sslen) < 0) {
27 + syslog(LOG_ERR, "getpeername: %m");
28 + clean_exit(request);
30 + if (ss.ss_family != AF_INET)
34 if ((ip = getprotobyname("ip")) != 0)
35 ipproto = ip->p_proto;
38 @@ -85,11 +85,18 @@ member of the specified netgroup. Netgro
39 for daemon process names or for client user names.
41 An expression of the form `n.n.n.n/m.m.m.m\' is interpreted as a
42 -`net/mask\' pair. A host address is matched if `net\' is equal to the
43 +`net/mask\' pair. An IPv4 host address is matched if `net\' is equal to the
44 bitwise AND of the address and the `mask\'. For example, the net/mask
45 pattern `131.155.72.0/255.255.254.0\' matches every address in the
46 range `131.155.72.0\' through `131.155.73.255\'.
48 +An expression of the form `[n:n:n:n:n:n:n:n]/m\' is interpreted as a
49 +`[net]/prefixlen\' pair. An IPv6 host address is matched if
50 +`prefixlen\' bits of `net\' is equal to the `prefixlen\' bits of the
51 +address. For example, the [net]/prefixlen pattern
52 +`[3ffe:505:2:1::]/64\' matches every address in the range
53 +`3ffe:505:2:1::\' through `3ffe:505:2:1:ffff:ffff:ffff:ffff\'.
55 Wildcards `*\' and `?\' can be used to match hostnames or IP addresses. This
56 method of matching cannot be used in conjunction with `net/mask\' matching,
57 hostname matching beginning with `.\' or IP address matching ending with `.\'.
60 @@ -24,7 +24,13 @@ static char sccsid[] = "@(#) hosts_acces
61 /* System libraries. */
63 #include <sys/types.h>
65 + typedef uint32_t u_int32_t;
67 #include <sys/param.h>
69 +#include <sys/socket.h>
71 #include <netinet/in.h>
72 #include <arpa/inet.h>
74 @@ -33,6 +39,9 @@ static char sccsid[] = "@(#) hosts_acces
84 @@ -83,6 +92,10 @@ static int host_match();
85 static int string_match();
86 static int masked_match();
87 static int match_pattern_ylo();
89 +static int masked_match4();
90 +static int masked_match6();
93 /* Size of logical line buffer. */
95 @@ -290,6 +303,13 @@ char *string;
100 + /* convert IPv4 mapped IPv6 address to IPv4 address */
101 + if (STRN_EQ(string, "::ffff:", 7)
102 + && dot_quad_addr(string + 7) != INADDR_NONE) {
106 #ifndef DISABLE_WILDCARD_MATCHING
107 if (strchr(tok, '*') || strchr(tok,'?')) { /* contains '*' or '?' */
108 return (match_pattern_ylo(string,tok));
109 @@ -305,20 +325,72 @@ char *string;
110 } else if (tok[(n = strlen(tok)) - 1] == '.') { /* prefix */
111 return (STRN_EQ(tok, string, n));
112 } else { /* exact match */
114 + struct addrinfo hints, *res;
115 + struct sockaddr_in6 pat, addr;
120 + if (*tok == '[' && tok[len - 1] == ']') {
122 + tok[len - 1] = '\0';
123 + memset(&hints, 0, sizeof(hints));
124 + hints.ai_family = AF_INET6;
125 + hints.ai_socktype = SOCK_STREAM;
126 + hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
127 + if ((ret = getaddrinfo(tok + 1, NULL, &hints, &res)) == 0) {
128 + memcpy(&pat, res->ai_addr, sizeof(pat));
132 + if (ret != 0 || getaddrinfo(string, NULL, &hints, &res) != 0)
134 + memcpy(&addr, res->ai_addr, sizeof(addr));
136 +#ifdef NI_WITHSCOPEID
137 + if (pat.sin6_scope_id != 0 &&
138 + addr.sin6_scope_id != pat.sin6_scope_id)
141 + return (!memcmp(&pat.sin6_addr, &addr.sin6_addr,
142 + sizeof(struct in6_addr)));
146 return (STR_EQ(tok, string));
150 /* masked_match - match address against netnumber/netmask */
153 static int masked_match(net_tok, mask_tok, string)
158 + return (masked_match4(net_tok, mask_tok, string) ||
159 + masked_match6(net_tok, mask_tok, string));
162 +static int masked_match4(net_tok, mask_tok, string)
164 +static int masked_match(net_tok, mask_tok, string)
181 * Disallow forms other than dotted quad: the treatment that inet_addr()
182 @@ -330,12 +402,78 @@ char *string;
184 if ((net = dot_quad_addr(net_tok)) == INADDR_NONE
185 || (mask = dot_quad_addr(mask_tok)) == INADDR_NONE) {
187 tcpd_warn("bad net/mask expression: %s/%s", net_tok, mask_tok);
189 return (NO); /* not tcpd_jump() */
191 return ((addr & mask) == net);
195 +static int masked_match6(net_tok, mask_tok, string)
200 + struct addrinfo hints, *res;
201 + struct sockaddr_in6 net, addr;
203 + int len, mask_len, i = 0;
206 + memset(&hints, 0, sizeof(hints));
207 + hints.ai_family = AF_INET6;
208 + hints.ai_socktype = SOCK_STREAM;
209 + hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
210 + if (getaddrinfo(string, NULL, &hints, &res) != 0)
212 + memcpy(&addr, res->ai_addr, sizeof(addr));
215 + if (IN6_IS_ADDR_V4MAPPED(&addr.sin6_addr)) {
216 + if ((*(u_int32_t *)&net.sin6_addr.s6_addr[12] = dot_quad_addr(net_tok)) == INADDR_NONE
217 + || (mask = dot_quad_addr(mask_tok)) == INADDR_NONE)
219 + return ((*(u_int32_t *)&addr.sin6_addr.s6_addr[12] & mask) == *(u_int32_t *)&net.sin6_addr.s6_addr[12]);
222 + /* match IPv6 address against netnumber/prefixlen */
223 + len = strlen(net_tok);
224 + if (*net_tok != '[' || net_tok[len - 1] != ']')
226 + ch = net_tok[len - 1];
227 + net_tok[len - 1] = '\0';
228 + if (getaddrinfo(net_tok + 1, NULL, &hints, &res) != 0) {
229 + net_tok[len - 1] = ch;
232 + memcpy(&net, res->ai_addr, sizeof(net));
234 + net_tok[len - 1] = ch;
235 + if ((mask_len = atoi(mask_tok)) < 0 || mask_len > 128)
238 +#ifdef NI_WITHSCOPEID
239 + if (net.sin6_scope_id != 0 && addr.sin6_scope_id != net.sin6_scope_id)
242 + while (mask_len > 0) {
243 + if (mask_len < 32) {
244 + mask = htonl(~(0xffffffff >> mask_len));
245 + if ((*(u_int32_t *)&addr.sin6_addr.s6_addr[i] & mask) != (*(u_int32_t *)&net.sin6_addr.s6_addr[i] & mask))
249 + if (*(u_int32_t *)&addr.sin6_addr.s6_addr[i] != *(u_int32_t *)&net.sin6_addr.s6_addr[i])
258 #ifndef DISABLE_WILDCARD_MATCHING
259 /* Note: this feature has been adapted in a pretty straightforward way
260 from Tatu Ylonen's last SSH version under free license by
263 @@ -21,7 +21,7 @@ what:
264 @echo " dynix epix esix freebsd hpux irix4 irix5 irix6 isc iunix"
265 @echo " linux machten mips(untested) ncrsvr4 netbsd next osf power_unix_211"
266 @echo " ptx-2.x ptx-generic pyramid sco sco-nis sco-od2 sco-os5 sinix sunos4"
267 - @echo " sunos40 sunos5 sysv4 tandem ultrix unicos7 unicos8 unixware1 unixware2"
268 + @echo " sunos40 sunos5 solaris8 sysv4 tandem ultrix unicos7 unicos8 unixware1 unixware2"
271 @echo "If none of these match your environment, edit the system"
272 @@ -131,20 +131,34 @@ epix:
273 NETGROUP=-DNETGROUP TLI= SYSTYPE="-systype bsd43" all
275 # Freebsd and linux by default have no NIS.
276 -386bsd netbsd bsdos:
278 @make REAL_DAEMON_DIR=$(REAL_DAEMON_DIR) STYLE=$(STYLE) \
279 LIBS= RANLIB=ranlib ARFLAGS=rv AUX_OBJ= NETGROUP= TLI= \
280 EXTRA_CFLAGS=-DSYS_ERRLIST_DEFINED VSYSLOG= all
283 @make REAL_DAEMON_DIR=$(REAL_DAEMON_DIR) STYLE=$(STYLE) \
284 + LIBS="-L/usr/local/v6/lib -linet6" \
285 LIBS= RANLIB=ranlib ARFLAGS=rv AUX_OBJ= NETGROUP= TLI= \
286 - EXTRA_CFLAGS=-DSYS_ERRLIST_DEFINED VSYSLOG= all
287 + EXTRA_CFLAGS="-DSYS_ERRLIST_DEFINED -DINET6 -Dss_family=__ss_family -Dss_len=__ss_len" \
291 + @make REAL_DAEMON_DIR=$(REAL_DAEMON_DIR) STYLE=$(STYLE) \
292 + LIBS= RANLIB=ranlib ARFLAGS=rv AUX_OBJ= NETGROUP= TLI= \
293 + EXTRA_CFLAGS="-DSYS_ERRLIST_DEFINED -DINET6 -Dss_family=__ss_family -Dss_len=__ss_len" VSYSLOG= all
296 @make REAL_DAEMON_DIR=$(REAL_DAEMON_DIR) STYLE=$(STYLE) \
297 - LIBS= RANLIB=ranlib ARFLAGS=rv AUX_OBJ=setenv.o \
298 - NETGROUP= TLI= EXTRA_CFLAGS="-DBROKEN_SO_LINGER" all
299 + LIBS=-lnsl RANLIB=ranlib ARFLAGS=rv AUX_OBJ= \
300 + NETGROUP="-DNETGROUP" TLI= VSYSLOG= BUGS= \
301 + EXTRA_CFLAGS="-DSYS_ERRLIST_DEFINED -DHAVE_STRERROR -DINET6=1 -Dss_family=__ss_family -Dss_len=__ss_len" all
304 + @make REAL_DAEMON_DIR=$(REAL_DAEMON_DIR) STYLE=$(STYLE) \
305 + LIBS=-lnsl RANLIB=ranlib ARFLAGS=rv AUX_OBJ= \
306 + NETGROUP=-DNETGROUP TLI= VSYSLOG= BUGS= \
307 + EXTRA_CFLAGS="-DSYS_ERRLIST_DEFINED -DHAVE_STRERROR -DINET6=1" all
309 # This is good for many SYSV+BSD hybrids with NIS, probably also for HP-UX 7.x.
310 hpux hpux8 hpux9 hpux10:
311 @@ -196,6 +210,13 @@ sunos5:
312 NETGROUP=-DNETGROUP AUX_OBJ=setenv.o TLI=-DTLI \
313 BUGS="$(BUGS) -DSOLARIS_24_GETHOSTBYNAME_BUG" all
315 +# SunOS 5.8 is another SYSV4 variant, but has IPv6 support
317 + @make REAL_DAEMON_DIR=$(REAL_DAEMON_DIR) STYLE=$(STYLE) \
318 + LIBS="-lsocket -lnsl" RANLIB=echo ARFLAGS=rv VSYSLOG= \
319 + NETGROUP=-DNETGROUP AUX_OBJ=setenv.o TLI=-DTLI \
320 + EXTRA_CFLAGS="-DINET6 -DNO_CLONE_DEVICE -DINT32_T" all
324 @make REAL_DAEMON_DIR=$(REAL_DAEMON_DIR) STYLE=$(STYLE) \
327 @@ -58,9 +58,31 @@ int delimiter;
334 + for (cp = string; cp && *cp; cp++) {
343 + if (bracket == 0 && *cp == delimiter) {
352 if ((cp = strchr(string, delimiter)) != 0)
358 /* dot_quad_addr - convert dotted quad to internal form */
361 @@ -25,7 +25,12 @@ static char sccsid[] = "@(#) refuse.c 1.
363 struct request_info *request;
366 + syslog(deny_severity, "refused connect from %s (%s)",
367 + eval_client(request), eval_hostaddr(request->client));
369 syslog(deny_severity, "refused connect from %s", eval_client(request));
376 @@ -68,20 +68,50 @@ int sig;
377 /* rfc931 - return remote user name, given socket structures */
379 void rfc931(rmt_sin, our_sin, dest)
381 +struct sockaddr *rmt_sin;
382 +struct sockaddr *our_sin;
384 struct sockaddr_in *rmt_sin;
385 struct sockaddr_in *our_sin;
392 + struct sockaddr_storage rmt_query_sin;
393 + struct sockaddr_storage our_query_sin;
396 struct sockaddr_in rmt_query_sin;
397 struct sockaddr_in our_query_sin;
399 char user[256]; /* XXX */
400 char buffer[512]; /* XXX */
402 char *result = unknown;
406 + /* address family must be the same */
407 + if (rmt_sin->sa_family != our_sin->sa_family) {
408 + STRN_CPY(dest, result, STRING_LENGTH);
411 + switch (our_sin->sa_family) {
413 + alen = sizeof(struct sockaddr_in);
416 + alen = sizeof(struct sockaddr_in6);
419 + STRN_CPY(dest, result, STRING_LENGTH);
425 * Use one unbuffered stdio stream for writing to and for reading from
426 * the RFC931 etc. server. This is done because of a bug in the SunOS
427 @@ -92,7 +122,11 @@ char *dest;
432 + if ((fp = fsocket(our_sin->sa_family, SOCK_STREAM, 0)) != 0) {
434 if ((fp = fsocket(AF_INET, SOCK_STREAM, 0)) != 0) {
436 setbuf(fp, (char *) 0);
439 @@ -112,6 +146,25 @@ char *dest;
440 * addresses from the query socket.
444 + memcpy(&our_query_sin, our_sin, alen);
445 + memcpy(&rmt_query_sin, rmt_sin, alen);
446 + switch (our_sin->sa_family) {
448 + ((struct sockaddr_in *)&our_query_sin)->sin_port = htons(ANY_PORT);
449 + ((struct sockaddr_in *)&rmt_query_sin)->sin_port = htons(RFC931_PORT);
452 + ((struct sockaddr_in6 *)&our_query_sin)->sin6_port = htons(ANY_PORT);
453 + ((struct sockaddr_in6 *)&rmt_query_sin)->sin6_port = htons(RFC931_PORT);
457 + if (bind(fileno(fp), (struct sockaddr *) & our_query_sin,
459 + connect(fileno(fp), (struct sockaddr *) & rmt_query_sin,
462 our_query_sin = *our_sin;
463 our_query_sin.sin_port = htons(ANY_PORT);
464 rmt_query_sin = *rmt_sin;
465 @@ -121,6 +174,7 @@ char *dest;
466 sizeof(our_query_sin)) >= 0 &&
467 connect(fileno(fp), (struct sockaddr *) & rmt_query_sin,
468 sizeof(rmt_query_sin)) >= 0) {
472 * Send query to server. Neglect the risk that a 13-byte
473 @@ -129,8 +183,13 @@ char *dest;
476 fprintf(fp, "%u,%u\r\n",
478 + ntohs(((struct sockaddr_in *)rmt_sin)->sin_port),
479 + ntohs(((struct sockaddr_in *)our_sin)->sin_port));
481 ntohs(rmt_sin->sin_port),
482 ntohs(our_sin->sin_port));
487 @@ -144,8 +203,13 @@ char *dest;
488 && ferror(fp) == 0 && feof(fp) == 0
489 && sscanf(buffer, "%u , %u : USERID :%*[^:]:%255s",
490 &rmt_port, &our_port, user) == 3
492 + && ntohs(((struct sockaddr_in *)rmt_sin)->sin_port) == rmt_port
493 + && ntohs(((struct sockaddr_in *)our_sin)->sin_port) == our_port) {
495 && ntohs(rmt_sin->sin_port) == rmt_port
496 && ntohs(our_sin->sin_port) == our_port) {
500 * Strip trailing carriage return. It is part of the
503 @@ -25,7 +25,9 @@ static char sccs_id[] = "@(#) scaffold.c
504 #define INADDR_NONE (-1) /* XXX should be 0xffffffff */
508 extern char *malloc();
511 /* Application-specific. */
513 @@ -39,6 +41,7 @@ int allow_severity = SEVERITY;
514 int deny_severity = LOG_WARNING;
515 int rfc931_timeout = RFC931_TIMEOUT;
518 /* dup_hostent - create hostent in one memory block */
520 static struct hostent *dup_hostent(hp)
521 @@ -73,9 +76,46 @@ struct hostent *hp;
527 /* find_inet_addr - find all addresses for this host, result to free() */
530 +struct addrinfo *find_inet_addr(host)
533 + struct addrinfo hints, *res;
535 + memset(&hints, 0, sizeof(hints));
536 + hints.ai_family = PF_UNSPEC;
537 + hints.ai_socktype = SOCK_STREAM;
538 + hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
539 + if (getaddrinfo(host, NULL, &hints, &res) == 0)
542 + memset(&hints, 0, sizeof(hints));
543 + hints.ai_family = PF_UNSPEC;
544 + hints.ai_socktype = SOCK_STREAM;
545 + hints.ai_flags = AI_PASSIVE | AI_CANONNAME;
546 + if (getaddrinfo(host, NULL, &hints, &res) != 0) {
547 + tcpd_warn("%s: host not found", host);
550 + if (res->ai_family != AF_INET6 && res->ai_family != AF_INET) {
551 + tcpd_warn("%d: not an internet host", res->ai_family);
555 + if (!res->ai_canonname) {
556 + tcpd_warn("%s: hostname alias", host);
557 + tcpd_warn("(cannot obtain official name)", res->ai_canonname);
558 + } else if (STR_NE(host, res->ai_canonname)) {
559 + tcpd_warn("%s: hostname alias", host);
560 + tcpd_warn("(official name: %.*s)", STRING_LENGTH, res->ai_canonname);
565 struct hostent *find_inet_addr(host)
568 @@ -118,6 +158,7 @@ char *host;
570 return (dup_hostent(hp));
574 /* check_dns - give each address thorough workout, return address count */
576 @@ -125,8 +166,13 @@ int check_dns(host)
579 struct request_info request;
581 + struct sockaddr_storage sin;
582 + struct addrinfo *hp, *res;
584 struct sockaddr_in sin;
590 @@ -134,11 +180,18 @@ char *host;
592 request_init(&request, RQ_CLIENT_SIN, &sin, 0);
593 sock_methods(&request);
595 memset((char *) &sin, 0, sizeof(sin));
596 sin.sin_family = AF_INET;
600 + for (res = hp, count = 0; res; res = res->ai_next, count++) {
601 + memcpy(&sin, res->ai_addr, res->ai_addrlen);
603 for (count = 0; (addr = hp->h_addr_list[count]) != 0; count++) {
604 memcpy((char *) &sin.sin_addr, addr, sizeof(sin.sin_addr));
608 * Force host name and address conversions. Use the request structure
609 @@ -151,7 +204,11 @@ char *host;
610 tcpd_warn("host address %s->name lookup failed",
611 eval_hostaddr(request.client));
624 * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
628 +extern struct addrinfo *find_inet_addr();
630 extern struct hostent *find_inet_addr();
632 extern int check_dns();
633 extern int check_path();
636 @@ -24,13 +24,22 @@ static char sccsid[] = "@(#) socket.c 1.
637 #include <sys/types.h>
638 #include <sys/param.h>
639 #include <sys/socket.h>
641 +typedef uint32_t u_int32_t;
643 #include <netinet/in.h>
650 +#ifndef NI_WITHSCOPEID
651 +#define NI_WITHSCOPEID 0
654 extern char *inet_ntoa();
659 @@ -79,8 +88,13 @@ char *name;
660 void sock_host(request)
661 struct request_info *request;
664 + static struct sockaddr_storage client;
665 + static struct sockaddr_storage server;
667 static struct sockaddr_in client;
668 static struct sockaddr_in server;
672 int fd = request->fd;
673 @@ -109,7 +123,11 @@ struct request_info *request;
674 memset(buf, 0 sizeof(buf));
678 + request->client->sin = (struct sockaddr *)&client;
680 request->client->sin = &client;
684 * Determine the server binding. This is used for client username
685 @@ -122,7 +140,11 @@ struct request_info *request;
686 tcpd_warn("getsockname: %m");
690 + request->server->sin = (struct sockaddr *)&server;
692 request->server->sin = &server;
696 /* sock_hostaddr - map endpoint address to printable form */
697 @@ -130,10 +152,26 @@ struct request_info *request;
698 void sock_hostaddr(host)
699 struct host_info *host;
702 + struct sockaddr *sin = host->sin;
708 + salen = sin->sa_len;
710 + salen = (sin->sa_family == AF_INET) ? sizeof(struct sockaddr_in)
711 + : sizeof(struct sockaddr_in6);
713 + getnameinfo(sin, salen, host->addr, sizeof(host->addr),
714 + NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID);
716 struct sockaddr_in *sin = host->sin;
719 STRN_CPY(host->addr, inet_ntoa(sin->sin_addr), sizeof(host->addr));
723 /* sock_hostname - map endpoint address to host name */
724 @@ -141,6 +179,160 @@ struct host_info *host;
725 void sock_hostname(host)
726 struct host_info *host;
729 + struct sockaddr *sin = host->sin;
730 + struct sockaddr_in sin4;
731 + struct addrinfo hints, *res, *res0 = NULL;
732 + int salen, alen, err = 1;
733 + char *ap = NULL, *rap, hname[NI_MAXHOST];
736 + if (sin->sa_family == AF_INET6) {
737 + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sin;
739 + if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
740 + memset(&sin4, 0, sizeof(sin4));
742 + sin4.sin_len = sizeof(sin4);
744 + sin4.sin_family = AF_INET;
745 + sin4.sin_port = sin6->sin6_port;
746 + sin4.sin_addr.s_addr = *(u_int32_t *)&sin6->sin6_addr.s6_addr[12];
747 + sin = (struct sockaddr *)&sin4;
750 + switch (sin->sa_family) {
752 + ap = (char *)&((struct sockaddr_in *)sin)->sin_addr;
753 + alen = sizeof(struct in_addr);
754 + salen = sizeof(struct sockaddr_in);
757 + ap = (char *)&((struct sockaddr_in6 *)sin)->sin6_addr;
758 + alen = sizeof(struct in6_addr);
759 + salen = sizeof(struct sockaddr_in6);
765 + err = getnameinfo(sin, salen, hname, sizeof(hname),
766 + NULL, 0, NI_WITHSCOPEID | NI_NAMEREQD);
770 + STRN_CPY(host->name, hname, sizeof(host->name));
772 + /* reject numeric addresses */
773 + memset(&hints, 0, sizeof(hints));
774 + hints.ai_family = sin->sa_family;
775 + hints.ai_socktype = SOCK_STREAM;
776 + hints.ai_flags = AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST;
777 + if ((err = getaddrinfo(host->name, NULL, &hints, &res0) == 0)) {
778 + freeaddrinfo(res0);
780 + tcpd_warn("host name/name mismatch: "
781 + "reverse lookup results in non-FQDN %s",
783 + strcpy(host->name, paranoid); /* name is bad, clobber it */
788 + /* we are now sure that this is non-numeric */
791 + * Verify that the address is a member of the address list returned
792 + * by gethostbyname(hostname).
794 + * Verify also that gethostbyaddr() and gethostbyname() return the same
795 + * hostname, or rshd and rlogind may still end up being spoofed.
797 + * On some sites, gethostbyname("localhost") returns "localhost.domain".
798 + * This is a DNS artefact. We treat it as a special case. When we
799 + * can't believe the address list from gethostbyname("localhost")
800 + * we're in big trouble anyway.
803 + memset(&hints, 0, sizeof(hints));
804 + hints.ai_family = sin->sa_family;
805 + hints.ai_socktype = SOCK_STREAM;
806 + hints.ai_flags = AI_PASSIVE | AI_CANONNAME;
807 + if (getaddrinfo(host->name, NULL, &hints, &res0) != 0) {
810 + * Unable to verify that the host name matches the address. This
811 + * may be a transient problem or a botched name server setup.
814 + tcpd_warn("can't verify hostname: getaddrinfo(%s, %s) failed",
816 + (sin->sa_family == AF_INET) ? "AF_INET" : "AF_INET6");
818 + } else if ((res0->ai_canonname == NULL
819 + || STR_NE(host->name, res0->ai_canonname))
820 + && STR_NE(host->name, "localhost")) {
823 + * The gethostbyaddr() and gethostbyname() calls did not return
824 + * the same hostname. This could be a nameserver configuration
825 + * problem. It could also be that someone is trying to spoof us.
828 + tcpd_warn("host name/name mismatch: %s != %.*s",
829 + host->name, STRING_LENGTH,
830 + (res0->ai_canonname == NULL) ? "" : res0->ai_canonname);
835 + * The address should be a member of the address list returned by
836 + * gethostbyname(). We should first verify that the h_addrtype
837 + * field is AF_INET, but this program has already caused too much
838 + * grief on systems with broken library code.
841 + for (res = res0; res; res = res->ai_next) {
842 + if (res->ai_family != sin->sa_family)
844 + switch (res->ai_family) {
846 + rap = (char *)&((struct sockaddr_in *)res->ai_addr)->sin_addr;
849 + /* need to check scope_id */
850 + if (((struct sockaddr_in6 *)sin)->sin6_scope_id !=
851 + ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id) {
854 + rap = (char *)&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
859 + if (memcmp(rap, ap, alen) == 0) {
860 + freeaddrinfo(res0);
861 + return; /* name is good, keep it */
866 + * The host name does not map to the initial address. Perhaps
867 + * someone has messed up. Perhaps someone compromised a name
871 + getnameinfo(sin, salen, hname, sizeof(hname),
872 + NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID);
873 + tcpd_warn("host name/address mismatch: %s != %.*s",
874 + hname, STRING_LENGTH,
875 + (res0->ai_canonname == NULL) ? "" : res0->ai_canonname);
877 + strcpy(host->name, paranoid); /* name is bad, clobber it */
879 + freeaddrinfo(res0);
882 struct sockaddr_in *sin = host->sin;
885 @@ -220,6 +412,7 @@ struct host_info *host;
887 strcpy(host->name, paranoid); /* name is bad, clobber it */
892 /* sock_sink - absorb unreceived IP datagram */
893 @@ -228,7 +421,11 @@ static void sock_sink(fd)
898 + struct sockaddr_storage sin;
900 struct sockaddr_in sin;
902 int size = sizeof(sin);
907 @@ -120,7 +120,12 @@ char **argv;
909 /* Report request and invoke the real daemon program. */
912 + syslog(allow_severity, "connect from %s (%s)",
913 + eval_client(&request), eval_hostaddr(request.client));
915 syslog(allow_severity, "connect from %s", eval_client(&request));
918 (void) execv(path, argv);
919 syslog(LOG_ERR, "error: cannot execute %s: %m", path);
922 @@ -22,6 +22,9 @@ static char sccsid[] = "@(#) tcpdchk.c 1
924 #include <sys/types.h>
925 #include <sys/stat.h>
927 +#include <sys/socket.h>
929 #include <netinet/in.h>
930 #include <arpa/inet.h>
932 @@ -397,6 +400,31 @@ char *pat;
937 +static int is_inet6_addr(pat)
940 + struct addrinfo hints, *res;
947 + if ((ch = pat[len - 1]) != ']')
949 + pat[len - 1] = '\0';
950 + memset(&hints, 0, sizeof(hints));
951 + hints.ai_family = AF_INET6;
952 + hints.ai_socktype = SOCK_STREAM;
953 + hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
954 + if ((ret = getaddrinfo(pat + 1, NULL, &hints, &res)) == 0)
961 /* check_host - criticize host pattern */
963 static int check_host(pat)
964 @@ -423,14 +451,27 @@ char *pat;
967 } else if (mask = split_at(pat, '/')) { /* network/netmask */
971 + if ((dot_quad_addr(pat) == INADDR_NONE
972 + || dot_quad_addr(mask) == INADDR_NONE)
973 + && (!is_inet6_addr(pat)
974 + || ((mask_len = atoi(mask)) < 0 || mask_len > 128)))
976 if (dot_quad_addr(pat) == INADDR_NONE
977 || dot_quad_addr(mask) == INADDR_NONE)
979 tcpd_warn("%s/%s: bad net/mask pattern", pat, mask);
980 } else if (STR_EQ(pat, "FAIL")) { /* obsolete */
981 tcpd_warn("FAIL is no longer recognized");
982 tcpd_warn("(use EXCEPT or DENY instead)");
983 } else if (reserved_name(pat)) { /* other reserved */
986 + } else if (is_inet6_addr(pat)) { /* IPv6 address */
989 } else if (NOT_INADDR(pat)) { /* internet name */
990 if (pat[strlen(pat) - 1] == '.') {
991 tcpd_warn("%s: domain or host name ends in dot", pat);
996 char name[STRING_LENGTH]; /* access via eval_hostname(host) */
997 char addr[STRING_LENGTH]; /* access via eval_hostaddr(host) */
999 + struct sockaddr *sin; /* socket address or 0 */
1001 struct sockaddr_in *sin; /* socket address or 0 */
1003 struct t_unitdata *unit; /* TLI transport address or 0 */
1004 struct request_info *request; /* for shared information */
1008 @@ -57,7 +57,11 @@ int main(argc, argv)
1013 + struct addrinfo hints, *hp, *res;
1017 char *myname = argv[0];
1020 @@ -68,8 +72,13 @@ char **argv;
1025 + struct sockaddr_storage server_sin;
1026 + struct sockaddr_storage client_sin;
1028 struct sockaddr_in server_sin;
1029 struct sockaddr_in client_sin;
1034 @@ -172,13 +181,20 @@ char **argv;
1035 if (NOT_INADDR(server) == 0 || HOSTNAME_KNOWN(server)) {
1036 if ((hp = find_inet_addr(server)) == 0)
1039 memset((char *) &server_sin, 0, sizeof(server_sin));
1040 server_sin.sin_family = AF_INET;
1042 request_set(&request, RQ_SERVER_SIN, &server_sin, 0);
1045 + for (res = hp, count = 0; res; res = res->ai_next, count++) {
1046 + memcpy(&server_sin, res->ai_addr, res->ai_addrlen);
1048 for (count = 0; (addr = hp->h_addr_list[count]) != 0; count++) {
1049 memcpy((char *) &server_sin.sin_addr, addr,
1050 sizeof(server_sin.sin_addr));
1054 * Force evaluation of server host name and address. Host name
1055 @@ -194,7 +210,11 @@ char **argv;
1056 fprintf(stderr, "Please specify an address instead\n");
1065 request_set(&request, RQ_SERVER_NAME, server, 0);
1067 @@ -208,6 +228,18 @@ char **argv;
1068 tcpdmatch(&request);
1072 + memset(&hints, 0, sizeof(hints));
1073 + hints.ai_family = AF_INET6;
1074 + hints.ai_socktype = SOCK_STREAM;
1075 + hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
1076 + if (getaddrinfo(client, NULL, &hints, &res) == 0) {
1077 + freeaddrinfo(res);
1078 + request_set(&request, RQ_CLIENT_ADDR, client, 0);
1079 + tcpdmatch(&request);
1085 * Perhaps they are testing special client hostname patterns that aren't
1086 @@ -229,6 +261,34 @@ char **argv;
1088 if ((hp = find_inet_addr(client)) == 0)
1091 + request_set(&request, RQ_CLIENT_SIN, &client_sin, 0);
1093 + for (res = hp, count = 0; res; res = res->ai_next, count++) {
1094 + memcpy(&client_sin, res->ai_addr, res->ai_addrlen);
1097 + * getnameinfo() doesn't do reverse lookup against link-local
1098 + * address. So, we pass through host name evaluation against
1101 + if (res->ai_family != AF_INET6 ||
1102 + !IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr)) {
1104 + * Force evaluation of client host name and address. Host name
1105 + * conflicts will be reported while eval_hostname() does its job.
1107 + request_set(&request, RQ_CLIENT_NAME, "", RQ_CLIENT_ADDR, "", 0);
1108 + if (STR_EQ(eval_hostname(request.client), unknown))
1109 + tcpd_warn("host address %s->name lookup failed",
1110 + eval_hostaddr(request.client));
1112 + tcpdmatch(&request);
1118 memset((char *) &client_sin, 0, sizeof(client_sin));
1119 client_sin.sin_family = AF_INET;
1120 request_set(&request, RQ_CLIENT_SIN, &client_sin, 0);
1121 @@ -250,6 +310,7 @@ char **argv;
1131 @@ -65,8 +65,13 @@ static void tli_sink();
1132 void tli_host(request)
1133 struct request_info *request;
1136 + static struct sockaddr_storage client;
1137 + static struct sockaddr_storage server;
1139 static struct sockaddr_in client;
1140 static struct sockaddr_in server;
1144 * If we discover that we are using an IP transport, pretend we never
1145 @@ -76,14 +81,29 @@ struct request_info *request;
1147 tli_endpoints(request);
1148 if ((request->config = tli_transport(request->fd)) != 0
1150 + && (STR_EQ(request->config->nc_protofmly, "inet") ||
1151 + STR_EQ(request->config->nc_protofmly, "inet6"))) {
1153 && STR_EQ(request->config->nc_protofmly, "inet")) {
1155 if (request->client->unit != 0) {
1157 + client = *(struct sockaddr_storage *) request->client->unit->addr.buf;
1158 + request->client->sin = (struct sockaddr *) &client;
1160 client = *(struct sockaddr_in *) request->client->unit->addr.buf;
1161 request->client->sin = &client;
1164 if (request->server->unit != 0) {
1166 + server = *(struct sockaddr_storage *) request->server->unit->addr.buf;
1167 + request->server->sin = (struct sockaddr *) &server;
1169 server = *(struct sockaddr_in *) request->server->unit->addr.buf;
1170 request->server->sin = &server;
1173 tli_cleanup(request);
1174 sock_methods(request);
1175 @@ -187,7 +207,15 @@ int fd;
1177 while (config = getnetconfig(handlep)) {
1178 if (stat(config->nc_device, &from_config) == 0) {
1179 +#ifdef NO_CLONE_DEVICE
1181 + * If the network devices are not cloned (as is the case for
1182 + * Solaris 8 Beta), we must compare the major device numbers.
1184 + if (major(from_config.st_rdev) == major(from_client.st_rdev))
1186 if (minor(from_config.st_rdev) == major(from_client.st_rdev))
1193 @@ -46,10 +46,18 @@ va_list ap;
1194 request->fd = va_arg(ap, int);
1198 + request->client->sin = va_arg(ap, struct sockaddr *);
1200 request->client->sin = va_arg(ap, struct sockaddr_in *);
1205 + request->server->sin = va_arg(ap, struct sockaddr *);
1207 request->server->sin = va_arg(ap, struct sockaddr_in *);
1214 @@ -166,11 +166,22 @@ struct sockaddr *sa;
1219 + struct sockaddr *sin = sa;
1221 struct sockaddr_in *sin = (struct sockaddr_in *) sa;
1224 if ((ret = getpeername(sock, sa, len)) >= 0
1226 + && ((sin->su_si.si_family == AF_INET6
1227 + && IN6_IS_ADDR_UNSPECIFIED(&sin->su_sin6.sin6_addr))
1228 + || (sin->su_si.si_family == AF_INET
1229 + && sin->su_sin.sin_addr.s_addr == 0))) {
1231 && sa->sa_family == AF_INET
1232 && sin->sin_addr.s_addr == 0) {