1Upstream-Status: Backport
2
3diff -ruN tcp_wrappers_7.6.orig/fix_options.c tcp_wrappers_7.6/fix_options.c
4--- tcp_wrappers_7.6.orig/fix_options.c	1997-04-08 02:29:19.000000000 +0200
5+++ tcp_wrappers_7.6/fix_options.c	2004-04-10 19:07:43.000000000 +0200
6@@ -11,6 +11,9 @@
7
8 #include <sys/types.h>
9 #include <sys/param.h>
10+#ifdef INET6
11+#include <sys/socket.h>
12+#endif
13 #include <netinet/in.h>
14 #include <netinet/in_systm.h>
15 #include <netinet/ip.h>
16@@ -41,6 +44,22 @@
17     unsigned int opt;
18     int     optlen;
19     struct in_addr dummy;
20+#ifdef INET6
21+    struct sockaddr_storage ss;
22+    int sslen;
23+
24+    /*
25+     * check if this is AF_INET socket
26+     * XXX IPv6 support?
27+     */
28+    sslen = sizeof(ss);
29+    if (getsockname(fd, (struct sockaddr *)&ss, &sslen) < 0) {
30+	syslog(LOG_ERR, "getpeername: %m");
31+	clean_exit(request);
32+    }
33+    if (ss.ss_family != AF_INET)
34+	return;
35+#endif
36
37     if ((ip = getprotobyname("ip")) != 0)
38 	ipproto = ip->p_proto;
39diff -ruN tcp_wrappers_7.6.orig/hosts_access.5 tcp_wrappers_7.6/hosts_access.5
40--- tcp_wrappers_7.6.orig/hosts_access.5	2004-04-10 19:22:58.000000000 +0200
41+++ tcp_wrappers_7.6/hosts_access.5	2004-04-10 19:07:43.000000000 +0200
42@@ -85,11 +85,18 @@
43 for daemon process names or for client user names.
44 .IP \(bu
45 An expression of the form `n.n.n.n/m.m.m.m\' is interpreted as a
46-`net/mask\' pair. A host address is matched if `net\' is equal to the
47+`net/mask\' pair. An IPv4 host address is matched if `net\' is equal to the
48 bitwise AND of the address and the `mask\'. For example, the net/mask
49 pattern `131.155.72.0/255.255.254.0\' matches every address in the
50 range `131.155.72.0\' through `131.155.73.255\'.
51 .IP \(bu
52+An expression of the form `[n:n:n:n:n:n:n:n]/m\' is interpreted as a
53+`[net]/prefixlen\' pair. An IPv6 host address is matched if
54+`prefixlen\' bits of `net\' is equal to the `prefixlen\' bits of the
55+address. For example, the [net]/prefixlen pattern
56+`[3ffe:505:2:1::]/64\' matches every address in the range
57+`3ffe:505:2:1::\' through `3ffe:505:2:1:ffff:ffff:ffff:ffff\'.
58+.IP \(bu
59 Wildcards `*\' and `?\' can be used to match hostnames or IP addresses.  This
60 method of matching cannot be used in conjunction with `net/mask\' matching,
61 hostname matching beginning with `.\' or IP address matching ending with `.\'.
62diff -ruN tcp_wrappers_7.6.orig/hosts_access.c tcp_wrappers_7.6/hosts_access.c
63--- tcp_wrappers_7.6.orig/hosts_access.c	2004-04-10 19:22:58.000000000 +0200
64+++ tcp_wrappers_7.6/hosts_access.c	2004-04-10 19:07:43.000000000 +0200
65@@ -24,7 +24,13 @@
66 /* System libraries. */
67
68 #include <sys/types.h>
69+#ifdef INT32_T
70+    typedef uint32_t u_int32_t;
71+#endif
72 #include <sys/param.h>
73+#ifdef INET6
74+#include <sys/socket.h>
75+#endif
76 #include <netinet/in.h>
77 #include <arpa/inet.h>
78 #include <stdio.h>
79@@ -33,6 +39,9 @@
80 #include <errno.h>
81 #include <setjmp.h>
82 #include <string.h>
83+#ifdef INET6
84+#include <netdb.h>
85+#endif
86
87 extern char *fgets();
88 extern int errno;
89@@ -82,6 +91,10 @@
90 static int host_match();
91 static int string_match();
92 static int masked_match();
93+#ifdef INET6
94+static int masked_match4();
95+static int masked_match6();
96+#endif
97
98 /* Size of logical line buffer. */
99
100@@ -289,6 +302,13 @@
101 {
102     int     n;
103
104+#ifdef INET6
105+    /* convert IPv4 mapped IPv6 address to IPv4 address */
106+    if (STRN_EQ(string, "::ffff:", 7)
107+      && dot_quad_addr(string + 7) != INADDR_NONE) {
108+      string += 7;
109+    }
110+#endif
111 #ifndef DISABLE_WILDCARD_MATCHING
112     if (strchr(tok, '*') || strchr(tok,'?')) {  /* contains '*' or '?' */
113         return (match_pattern_ylo(string,tok));
114@@ -304,20 +324,72 @@
115     } else if (tok[(n = strlen(tok)) - 1] == '.') {	/* prefix */
116 	return (STRN_EQ(tok, string, n));
117     } else {					/* exact match */
118+#ifdef INET6
119+	struct addrinfo hints, *res;
120+	struct sockaddr_in6 pat, addr;
121+	int len, ret;
122+	char ch;
123+
124+	len = strlen(tok);
125+	if (*tok == '[' && tok[len - 1] == ']') {
126+	    ch = tok[len - 1];
127+	    tok[len - 1] = '\0';
128+	    memset(&hints, 0, sizeof(hints));
129+	    hints.ai_family = AF_INET6;
130+	    hints.ai_socktype = SOCK_STREAM;
131+	    hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
132+	    if ((ret = getaddrinfo(tok + 1, NULL, &hints, &res)) == 0) {
133+		memcpy(&pat, res->ai_addr, sizeof(pat));
134+		freeaddrinfo(res);
135+	    }
136+	    tok[len - 1] = ch;
137+	    if (ret != 0 || getaddrinfo(string, NULL, &hints, &res) != 0)
138+		return NO;
139+	    memcpy(&addr, res->ai_addr, sizeof(addr));
140+	    freeaddrinfo(res);
141+#ifdef NI_WITHSCOPEID
142+	    if (pat.sin6_scope_id != 0 &&
143+		addr.sin6_scope_id != pat.sin6_scope_id)
144+		return NO;
145+#endif
146+	    return (!memcmp(&pat.sin6_addr, &addr.sin6_addr,
147+			    sizeof(struct in6_addr)));
148+	    return (ret);
149+	}
150+#endif
151 	return (STR_EQ(tok, string));
152     }
153 }
154
155 /* masked_match - match address against netnumber/netmask */
156
157+#ifdef INET6
158 static int masked_match(net_tok, mask_tok, string)
159 char   *net_tok;
160 char   *mask_tok;
161 char   *string;
162 {
163+    return (masked_match4(net_tok, mask_tok, string) ||
164+	    masked_match6(net_tok, mask_tok, string));
165+}
166+
167+static int masked_match4(net_tok, mask_tok, string)
168+#else
169+static int masked_match(net_tok, mask_tok, string)
170+#endif
171+char   *net_tok;
172+char   *mask_tok;
173+char   *string;
174+{
175+#ifdef INET6
176+    u_int32_t net;
177+    u_int32_t mask;
178+    u_int32_t addr;
179+#else
180     unsigned long net;
181     unsigned long mask;
182     unsigned long addr;
183+#endif
184
185     /*
186      * Disallow forms other than dotted quad: the treatment that inet_addr()
187@@ -329,12 +401,78 @@
188 	return (NO);
189     if ((net = dot_quad_addr(net_tok)) == INADDR_NONE
190 	|| (mask = dot_quad_addr(mask_tok)) == INADDR_NONE) {
191+#ifndef INET6
192 	tcpd_warn("bad net/mask expression: %s/%s", net_tok, mask_tok);
193+#endif
194 	return (NO);				/* not tcpd_jump() */
195     }
196     return ((addr & mask) == net);
197 }
198
199+#ifdef INET6
200+static int masked_match6(net_tok, mask_tok, string)
201+char   *net_tok;
202+char   *mask_tok;
203+char   *string;
204+{
205+    struct addrinfo hints, *res;
206+    struct sockaddr_in6 net, addr;
207+    u_int32_t mask;
208+    int len, mask_len, i = 0;
209+    char ch;
210+
211+    memset(&hints, 0, sizeof(hints));
212+    hints.ai_family = AF_INET6;
213+    hints.ai_socktype = SOCK_STREAM;
214+    hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
215+    if (getaddrinfo(string, NULL, &hints, &res) != 0)
216+	return NO;
217+    memcpy(&addr, res->ai_addr, sizeof(addr));
218+    freeaddrinfo(res);
219+
220+    if (IN6_IS_ADDR_V4MAPPED(&addr.sin6_addr)) {
221+	if ((*(u_int32_t *)&net.sin6_addr.s6_addr[12] = dot_quad_addr(net_tok)) == INADDR_NONE
222+	 || (mask = dot_quad_addr(mask_tok)) == INADDR_NONE)
223+	    return (NO);
224+	return ((*(u_int32_t *)&addr.sin6_addr.s6_addr[12] & mask) == *(u_int32_t *)&net.sin6_addr.s6_addr[12]);
225+    }
226+
227+    /* match IPv6 address against netnumber/prefixlen */
228+    len = strlen(net_tok);
229+    if (*net_tok != '[' || net_tok[len - 1] != ']')
230+	return NO;
231+    ch = net_tok[len - 1];
232+    net_tok[len - 1] = '\0';
233+    if (getaddrinfo(net_tok + 1, NULL, &hints, &res) != 0) {
234+	net_tok[len - 1] = ch;
235+	return NO;
236+    }
237+    memcpy(&net, res->ai_addr, sizeof(net));
238+    freeaddrinfo(res);
239+    net_tok[len - 1] = ch;
240+    if ((mask_len = atoi(mask_tok)) < 0 || mask_len > 128)
241+	return NO;
242+
243+#ifdef NI_WITHSCOPEID
244+    if (net.sin6_scope_id != 0 && addr.sin6_scope_id != net.sin6_scope_id)
245+	return NO;
246+#endif
247+    while (mask_len > 0) {
248+	if (mask_len < 32) {
249+	    mask = htonl(~(0xffffffff >> mask_len));
250+	    if ((*(u_int32_t *)&addr.sin6_addr.s6_addr[i] & mask) != (*(u_int32_t *)&net.sin6_addr.s6_addr[i] & mask))
251+		return NO;
252+	    break;
253+	}
254+	if (*(u_int32_t *)&addr.sin6_addr.s6_addr[i] != *(u_int32_t *)&net.sin6_addr.s6_addr[i])
255+	    return NO;
256+	i += 4;
257+	mask_len -= 32;
258+    }
259+    return YES;
260+}
261+#endif /* INET6 */
262+
263 #ifndef DISABLE_WILDCARD_MATCHING
264 /* Note: this feature has been adapted in a pretty straightforward way
265    from Tatu Ylonen's last SSH version under free license by
266diff -ruN tcp_wrappers_7.6.orig/Makefile tcp_wrappers_7.6/Makefile
267--- tcp_wrappers_7.6.orig/Makefile	1997-03-21 19:27:21.000000000 +0100
268+++ tcp_wrappers_7.6/Makefile	2004-04-10 19:22:44.000000000 +0200
269@@ -21,7 +21,7 @@
270 	@echo "	dynix epix esix freebsd hpux irix4 irix5 irix6 isc iunix"
271 	@echo "	linux machten mips(untested) ncrsvr4 netbsd next osf power_unix_211"
272 	@echo "	ptx-2.x ptx-generic pyramid sco sco-nis sco-od2 sco-os5 sinix sunos4"
273-	@echo "	sunos40 sunos5 sysv4 tandem ultrix unicos7 unicos8 unixware1 unixware2"
274+	@echo "	sunos40 sunos5 solaris8 sysv4 tandem ultrix unicos7 unicos8 unixware1 unixware2"
275 	@echo "	uts215 uxp"
276 	@echo
277 	@echo "If none of these match your environment, edit the system"
278@@ -131,20 +131,34 @@
279 	NETGROUP=-DNETGROUP TLI= SYSTYPE="-systype bsd43" all
280
281 # Freebsd and linux by default have no NIS.
282-386bsd netbsd bsdos:
283+386bsd bsdos:
284 	@make REAL_DAEMON_DIR=$(REAL_DAEMON_DIR) STYLE=$(STYLE) \
285 	LIBS= RANLIB=ranlib ARFLAGS=rv AUX_OBJ= NETGROUP= TLI= \
286 	EXTRA_CFLAGS=-DSYS_ERRLIST_DEFINED VSYSLOG= all
287
288 freebsd:
289 	@make REAL_DAEMON_DIR=$(REAL_DAEMON_DIR) STYLE=$(STYLE) \
290+	LIBS="-L/usr/local/v6/lib -linet6" \
291 	LIBS= RANLIB=ranlib ARFLAGS=rv AUX_OBJ= NETGROUP= TLI= \
292-	EXTRA_CFLAGS=-DSYS_ERRLIST_DEFINED VSYSLOG= all
293+	EXTRA_CFLAGS="-DSYS_ERRLIST_DEFINED -DINET6 -Dss_family=__ss_family -Dss_len=__ss_len" \
294+	VSYSLOG= all
295+
296+netbsd:
297+	@make REAL_DAEMON_DIR=$(REAL_DAEMON_DIR) STYLE=$(STYLE) \
298+	LIBS= RANLIB=ranlib ARFLAGS=rv AUX_OBJ= NETGROUP= TLI= \
299+	EXTRA_CFLAGS="-DSYS_ERRLIST_DEFINED -DINET6 -Dss_family=__ss_family -Dss_len=__ss_len" VSYSLOG= all
300
301 linux:
302 	@make REAL_DAEMON_DIR=$(REAL_DAEMON_DIR) STYLE=$(STYLE) \
303-	LIBS= RANLIB=ranlib ARFLAGS=rv AUX_OBJ=setenv.o \
304-	NETGROUP= TLI= EXTRA_CFLAGS="-DBROKEN_SO_LINGER" all
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 -Dss_family=__ss_family -Dss_len=__ss_len" all
308+
309+gnu:
310+	@make REAL_DAEMON_DIR=$(REAL_DAEMON_DIR) STYLE=$(STYLE) \
311+	LIBS=-lnsl RANLIB=ranlib ARFLAGS=rv AUX_OBJ= \
312+	NETGROUP=-DNETGROUP TLI= VSYSLOG= BUGS= \
313+	EXTRA_CFLAGS="-DSYS_ERRLIST_DEFINED -DHAVE_STRERROR" all
314
315 # This is good for many SYSV+BSD hybrids with NIS, probably also for HP-UX 7.x.
316 hpux hpux8 hpux9 hpux10:
317@@ -196,6 +210,13 @@
318 	NETGROUP=-DNETGROUP AUX_OBJ=setenv.o TLI=-DTLI \
319 	BUGS="$(BUGS) -DSOLARIS_24_GETHOSTBYNAME_BUG" all
320
321+# SunOS 5.8 is another SYSV4 variant, but has IPv6 support
322+solaris8:
323+	@make REAL_DAEMON_DIR=$(REAL_DAEMON_DIR) STYLE=$(STYLE) \
324+	LIBS="-lsocket -lnsl" RANLIB=echo ARFLAGS=rv VSYSLOG= \
325+	NETGROUP=-DNETGROUP AUX_OBJ=setenv.o TLI=-DTLI \
326+	EXTRA_CFLAGS="-DINET6 -DNO_CLONE_DEVICE -DINT32_T" all
327+
328 # Generic SYSV40
329 esix sysv4:
330 	@make REAL_DAEMON_DIR=$(REAL_DAEMON_DIR) STYLE=$(STYLE) \
331diff -ruN tcp_wrappers_7.6.orig/misc.c tcp_wrappers_7.6/misc.c
332--- tcp_wrappers_7.6.orig/misc.c	1996-02-11 17:01:30.000000000 +0100
333+++ tcp_wrappers_7.6/misc.c	2004-04-10 19:07:43.000000000 +0200
334@@ -58,9 +58,31 @@
335 {
336     char   *cp;
337
338+#ifdef INET6
339+    int bracket = 0;
340+
341+    for (cp = string; cp && *cp; cp++) {
342+	switch (*cp) {
343+	case '[':
344+	    bracket++;
345+	    break;
346+	case ']':
347+	    bracket--;
348+	    break;
349+	default:
350+	    if (bracket == 0 && *cp == delimiter) {
351+		*cp++ = 0;
352+		return cp;
353+	    }
354+	    break;
355+	}
356+    }
357+    return (NULL);
358+#else
359     if ((cp = strchr(string, delimiter)) != 0)
360 	*cp++ = 0;
361     return (cp);
362+#endif
363 }
364
365 /* dot_quad_addr - convert dotted quad to internal form */
366diff -ruN tcp_wrappers_7.6.orig/refuse.c tcp_wrappers_7.6/refuse.c
367--- tcp_wrappers_7.6.orig/refuse.c	1994-12-28 17:42:40.000000000 +0100
368+++ tcp_wrappers_7.6/refuse.c	2004-04-10 19:07:43.000000000 +0200
369@@ -25,7 +25,12 @@
370 void    refuse(request)
371 struct request_info *request;
372 {
373+#ifdef INET6
374+    syslog(deny_severity, "refused connect from %s (%s)",
375+	   eval_client(request), eval_hostaddr(request->client));
376+#else
377     syslog(deny_severity, "refused connect from %s", eval_client(request));
378+#endif
379     clean_exit(request);
380     /* NOTREACHED */
381 }
382diff -ruN tcp_wrappers_7.6.orig/rfc931.c tcp_wrappers_7.6/rfc931.c
383--- tcp_wrappers_7.6.orig/rfc931.c	1995-01-02 16:11:34.000000000 +0100
384+++ tcp_wrappers_7.6/rfc931.c	2004-04-10 19:07:43.000000000 +0200
385@@ -68,20 +68,50 @@
386 /* rfc931 - return remote user name, given socket structures */
387
388 void    rfc931(rmt_sin, our_sin, dest)
389+#ifdef INET6
390+struct sockaddr *rmt_sin;
391+struct sockaddr *our_sin;
392+#else
393 struct sockaddr_in *rmt_sin;
394 struct sockaddr_in *our_sin;
395+#endif
396 char   *dest;
397 {
398     unsigned rmt_port;
399     unsigned our_port;
400+#ifdef INET6
401+    struct sockaddr_storage rmt_query_sin;
402+    struct sockaddr_storage our_query_sin;
403+    int alen;
404+#else
405     struct sockaddr_in rmt_query_sin;
406     struct sockaddr_in our_query_sin;
407+#endif
408     char    user[256];			/* XXX */
409     char    buffer[512];		/* XXX */
410     char   *cp;
411     char   *result = unknown;
412     FILE   *fp;
413
414+#ifdef INET6
415+    /* address family must be the same */
416+    if (rmt_sin->sa_family != our_sin->sa_family) {
417+	STRN_CPY(dest, result, STRING_LENGTH);
418+	return;
419+    }
420+    switch (our_sin->sa_family) {
421+    case AF_INET:
422+	alen = sizeof(struct sockaddr_in);
423+	break;
424+    case AF_INET6:
425+	alen = sizeof(struct sockaddr_in6);
426+	break;
427+    default:
428+	STRN_CPY(dest, result, STRING_LENGTH);
429+	return;
430+    }
431+#endif
432+
433     /*
434      * Use one unbuffered stdio stream for writing to and for reading from
435      * the RFC931 etc. server. This is done because of a bug in the SunOS
436@@ -92,7 +122,11 @@
437      * sockets.
438      */
439
440+#ifdef INET6
441+    if ((fp = fsocket(our_sin->sa_family, SOCK_STREAM, 0)) != 0) {
442+#else
443     if ((fp = fsocket(AF_INET, SOCK_STREAM, 0)) != 0) {
444+#endif
445 	setbuf(fp, (char *) 0);
446
447 	/*
448@@ -112,6 +146,25 @@
449 	     * addresses from the query socket.
450 	     */
451
452+#ifdef INET6
453+	    memcpy(&our_query_sin, our_sin, alen);
454+	    memcpy(&rmt_query_sin, rmt_sin, alen);
455+	    switch (our_sin->sa_family) {
456+	    case AF_INET:
457+		((struct sockaddr_in *)&our_query_sin)->sin_port = htons(ANY_PORT);
458+		((struct sockaddr_in *)&rmt_query_sin)->sin_port = htons(RFC931_PORT);
459+		break;
460+	    case AF_INET6:
461+		((struct sockaddr_in6 *)&our_query_sin)->sin6_port = htons(ANY_PORT);
462+		((struct sockaddr_in6 *)&rmt_query_sin)->sin6_port = htons(RFC931_PORT);
463+		break;
464+	    }
465+
466+	    if (bind(fileno(fp), (struct sockaddr *) & our_query_sin,
467+		     alen) >= 0 &&
468+		connect(fileno(fp), (struct sockaddr *) & rmt_query_sin,
469+			alen) >= 0) {
470+#else
471 	    our_query_sin = *our_sin;
472 	    our_query_sin.sin_port = htons(ANY_PORT);
473 	    rmt_query_sin = *rmt_sin;
474@@ -121,6 +174,7 @@
475 		     sizeof(our_query_sin)) >= 0 &&
476 		connect(fileno(fp), (struct sockaddr *) & rmt_query_sin,
477 			sizeof(rmt_query_sin)) >= 0) {
478+#endif
479
480 		/*
481 		 * Send query to server. Neglect the risk that a 13-byte
482@@ -129,8 +183,13 @@
483 		 */
484
485 		fprintf(fp, "%u,%u\r\n",
486+#ifdef INET6
487+			ntohs(((struct sockaddr_in *)rmt_sin)->sin_port),
488+			ntohs(((struct sockaddr_in *)our_sin)->sin_port));
489+#else
490 			ntohs(rmt_sin->sin_port),
491 			ntohs(our_sin->sin_port));
492+#endif
493 		fflush(fp);
494
495 		/*
496@@ -144,8 +203,13 @@
497 		    && ferror(fp) == 0 && feof(fp) == 0
498 		    && sscanf(buffer, "%u , %u : USERID :%*[^:]:%255s",
499 			      &rmt_port, &our_port, user) == 3
500+#ifdef INET6
501+		    && ntohs(((struct sockaddr_in *)rmt_sin)->sin_port) == rmt_port
502+		    && ntohs(((struct sockaddr_in *)our_sin)->sin_port) == our_port) {
503+#else
504 		    && ntohs(rmt_sin->sin_port) == rmt_port
505 		    && ntohs(our_sin->sin_port) == our_port) {
506+#endif
507
508 		    /*
509 		     * Strip trailing carriage return. It is part of the
510diff -ruN tcp_wrappers_7.6.orig/scaffold.c tcp_wrappers_7.6/scaffold.c
511--- tcp_wrappers_7.6.orig/scaffold.c	1997-03-21 19:27:24.000000000 +0100
512+++ tcp_wrappers_7.6/scaffold.c	2004-04-10 19:07:43.000000000 +0200
513@@ -25,7 +25,9 @@
514 #define	INADDR_NONE	(-1)		/* XXX should be 0xffffffff */
515 #endif
516
517+#ifndef INET6
518 extern char *malloc();
519+#endif
520
521 /* Application-specific. */
522
523@@ -39,6 +41,7 @@
524 int     deny_severity = LOG_WARNING;
525 int     rfc931_timeout = RFC931_TIMEOUT;
526
527+#ifndef INET6
528 /* dup_hostent - create hostent in one memory block */
529
530 static struct hostent *dup_hostent(hp)
531@@ -73,9 +76,46 @@
532     }
533     return (&hb->host);
534 }
535+#endif
536
537 /* find_inet_addr - find all addresses for this host, result to free() */
538
539+#ifdef INET6
540+struct addrinfo *find_inet_addr(host)
541+char   *host;
542+{
543+    struct addrinfo hints, *res;
544+
545+    memset(&hints, 0, sizeof(hints));
546+    hints.ai_family = PF_UNSPEC;
547+    hints.ai_socktype = SOCK_STREAM;
548+    hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
549+    if (getaddrinfo(host, NULL, &hints, &res) == 0)
550+	return (res);
551+
552+    memset(&hints, 0, sizeof(hints));
553+    hints.ai_family = PF_UNSPEC;
554+    hints.ai_socktype = SOCK_STREAM;
555+    hints.ai_flags = AI_PASSIVE | AI_CANONNAME;
556+    if (getaddrinfo(host, NULL, &hints, &res) != 0) {
557+	tcpd_warn("%s: host not found", host);
558+	return (0);
559+    }
560+    if (res->ai_family != AF_INET6 && res->ai_family != AF_INET) {
561+	tcpd_warn("%d: not an internet host", res->ai_family);
562+	freeaddrinfo(res);
563+	return (0);
564+    }
565+    if (!res->ai_canonname) {
566+	tcpd_warn("%s: hostname alias", host);
567+	tcpd_warn("(cannot obtain official name)", res->ai_canonname);
568+    } else if (STR_NE(host, res->ai_canonname)) {
569+	tcpd_warn("%s: hostname alias", host);
570+	tcpd_warn("(official name: %.*s)", STRING_LENGTH, res->ai_canonname);
571+    }
572+    return (res);
573+}
574+#else
575 struct hostent *find_inet_addr(host)
576 char   *host;
577 {
578@@ -118,6 +158,7 @@
579     }
580     return (dup_hostent(hp));
581 }
582+#endif
583
584 /* check_dns - give each address thorough workout, return address count */
585
586@@ -125,8 +166,13 @@
587 char   *host;
588 {
589     struct request_info request;
590+#ifdef INET6
591+    struct sockaddr_storage sin;
592+    struct addrinfo *hp, *res;
593+#else
594     struct sockaddr_in sin;
595     struct hostent *hp;
596+#endif
597     int     count;
598     char   *addr;
599
600@@ -134,11 +180,18 @@
601 	return (0);
602     request_init(&request, RQ_CLIENT_SIN, &sin, 0);
603     sock_methods(&request);
604+#ifndef INET6
605     memset((char *) &sin, 0, sizeof(sin));
606     sin.sin_family = AF_INET;
607+#endif
608
609+#ifdef INET6
610+    for (res = hp, count = 0; res; res = res->ai_next, count++) {
611+	memcpy(&sin, res->ai_addr, res->ai_addrlen);
612+#else
613     for (count = 0; (addr = hp->h_addr_list[count]) != 0; count++) {
614 	memcpy((char *) &sin.sin_addr, addr, sizeof(sin.sin_addr));
615+#endif
616
617 	/*
618 	 * Force host name and address conversions. Use the request structure
619@@ -151,7 +204,11 @@
620 	    tcpd_warn("host address %s->name lookup failed",
621 		      eval_hostaddr(request.client));
622     }
623+#ifdef INET6
624+    freeaddrinfo(hp);
625+#else
626     free((char *) hp);
627+#endif
628     return (count);
629 }
630
631diff -ruN tcp_wrappers_7.6.orig/scaffold.h tcp_wrappers_7.6/scaffold.h
632--- tcp_wrappers_7.6.orig/scaffold.h	1994-12-31 18:19:20.000000000 +0100
633+++ tcp_wrappers_7.6/scaffold.h	2004-04-10 19:07:43.000000000 +0200
634@@ -4,6 +4,10 @@
635   * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
636   */
637
638+#ifdef INET6
639+extern struct addrinfo *find_inet_addr();
640+#else
641 extern struct hostent *find_inet_addr();
642+#endif
643 extern int check_dns();
644 extern int check_path();
645diff -ruN tcp_wrappers_7.6.orig/socket.c tcp_wrappers_7.6/socket.c
646--- tcp_wrappers_7.6.orig/socket.c	2004-04-10 19:22:58.000000000 +0200
647+++ tcp_wrappers_7.6/socket.c	2004-04-10 19:07:43.000000000 +0200
648@@ -24,13 +24,22 @@
649 #include <sys/types.h>
650 #include <sys/param.h>
651 #include <sys/socket.h>
652+#ifdef INT32_T
653+typedef uint32_t u_int32_t;
654+#endif
655 #include <netinet/in.h>
656 #include <netdb.h>
657 #include <stdio.h>
658 #include <syslog.h>
659 #include <string.h>
660
661+#ifdef INET6
662+#ifndef NI_WITHSCOPEID
663+#define NI_WITHSCOPEID	0
664+#endif
665+#else
666 extern char *inet_ntoa();
667+#endif
668
669 /* Local stuff. */
670
671@@ -79,8 +88,13 @@
672 void    sock_host(request)
673 struct request_info *request;
674 {
675+#ifdef INET6
676+    static struct sockaddr_storage client;
677+    static struct sockaddr_storage server;
678+#else
679     static struct sockaddr_in client;
680     static struct sockaddr_in server;
681+#endif
682     int     len;
683     char    buf[BUFSIZ];
684     int     fd = request->fd;
685@@ -109,7 +123,11 @@
686 	memset(buf, 0 sizeof(buf));
687 #endif
688     }
689+#ifdef INET6
690+    request->client->sin = (struct sockaddr *)&client;
691+#else
692     request->client->sin = &client;
693+#endif
694
695     /*
696      * Determine the server binding. This is used for client username
697@@ -122,7 +140,11 @@
698 	tcpd_warn("getsockname: %m");
699 	return;
700     }
701+#ifdef INET6
702+    request->server->sin = (struct sockaddr *)&server;
703+#else
704     request->server->sin = &server;
705+#endif
706 }
707
708 /* sock_hostaddr - map endpoint address to printable form */
709@@ -130,10 +152,26 @@
710 void    sock_hostaddr(host)
711 struct host_info *host;
712 {
713+#ifdef INET6
714+    struct sockaddr *sin = host->sin;
715+    int salen;
716+
717+    if (!sin)
718+	return;
719+#ifdef SIN6_LEN
720+    salen = sin->sa_len;
721+#else
722+    salen = (sin->sa_family == AF_INET) ? sizeof(struct sockaddr_in)
723+					: sizeof(struct sockaddr_in6);
724+#endif
725+    getnameinfo(sin, salen, host->addr, sizeof(host->addr),
726+		NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID);
727+#else
728     struct sockaddr_in *sin = host->sin;
729
730     if (sin != 0)
731 	STRN_CPY(host->addr, inet_ntoa(sin->sin_addr), sizeof(host->addr));
732+#endif
733 }
734
735 /* sock_hostname - map endpoint address to host name */
736@@ -141,6 +179,160 @@
737 void    sock_hostname(host)
738 struct host_info *host;
739 {
740+#ifdef INET6
741+    struct sockaddr *sin = host->sin;
742+    struct sockaddr_in sin4;
743+    struct addrinfo hints, *res, *res0 = NULL;
744+    int salen, alen, err = 1;
745+    char *ap = NULL, *rap, hname[NI_MAXHOST];
746+
747+    if (sin != NULL) {
748+	if (sin->sa_family == AF_INET6) {
749+	    struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sin;
750+
751+	    if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
752+		memset(&sin4, 0, sizeof(sin4));
753+#ifdef SIN6_LEN
754+		sin4.sin_len = sizeof(sin4);
755+#endif
756+		sin4.sin_family = AF_INET;
757+		sin4.sin_port = sin6->sin6_port;
758+		sin4.sin_addr.s_addr = *(u_int32_t *)&sin6->sin6_addr.s6_addr[12];
759+		sin = (struct sockaddr *)&sin4;
760+	    }
761+	}
762+	switch (sin->sa_family) {
763+	case AF_INET:
764+	    ap = (char *)&((struct sockaddr_in *)sin)->sin_addr;
765+	    alen = sizeof(struct in_addr);
766+	    salen = sizeof(struct sockaddr_in);
767+	    break;
768+	case AF_INET6:
769+	    ap = (char *)&((struct sockaddr_in6 *)sin)->sin6_addr;
770+	    alen = sizeof(struct in6_addr);
771+	    salen = sizeof(struct sockaddr_in6);
772+	    break;
773+	default:
774+	    break;
775+	}
776+	if (ap)
777+	    err = getnameinfo(sin, salen, hname, sizeof(hname),
778+			      NULL, 0, NI_WITHSCOPEID | NI_NAMEREQD);
779+    }
780+    if (!err) {
781+
782+	STRN_CPY(host->name, hname, sizeof(host->name));
783+
784+	/* reject numeric addresses */
785+	memset(&hints, 0, sizeof(hints));
786+	hints.ai_family = sin->sa_family;
787+	hints.ai_socktype = SOCK_STREAM;
788+	hints.ai_flags = AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST;
789+	if ((err = getaddrinfo(host->name, NULL, &hints, &res0) == 0)) {
790+	    freeaddrinfo(res0);
791+	    res0 = NULL;
792+	    tcpd_warn("host name/name mismatch: "
793+		      "reverse lookup results in non-FQDN %s",
794+		      host->name);
795+	    strcpy(host->name, paranoid);	/* name is bad, clobber it */
796+	}
797+	err = !err;
798+    }
799+    if (!err) {
800+	/* we are now sure that this is non-numeric */
801+
802+	/*
803+	 * Verify that the address is a member of the address list returned
804+	 * by gethostbyname(hostname).
805+	 *
806+	 * Verify also that gethostbyaddr() and gethostbyname() return the same
807+	 * hostname, or rshd and rlogind may still end up being spoofed.
808+	 *
809+	 * On some sites, gethostbyname("localhost") returns "localhost.domain".
810+	 * This is a DNS artefact. We treat it as a special case. When we
811+	 * can't believe the address list from gethostbyname("localhost")
812+	 * we're in big trouble anyway.
813+	 */
814+
815+	memset(&hints, 0, sizeof(hints));
816+	hints.ai_family = sin->sa_family;
817+	hints.ai_socktype = SOCK_STREAM;
818+	hints.ai_flags = AI_PASSIVE | AI_CANONNAME;
819+	if (getaddrinfo(host->name, NULL, &hints, &res0) != 0) {
820+
821+	    /*
822+	     * Unable to verify that the host name matches the address. This
823+	     * may be a transient problem or a botched name server setup.
824+	     */
825+
826+	    tcpd_warn("can't verify hostname: getaddrinfo(%s, %s) failed",
827+		      host->name,
828+		      (sin->sa_family == AF_INET) ? "AF_INET" : "AF_INET6");
829+
830+	} else if ((res0->ai_canonname == NULL
831+		    || STR_NE(host->name, res0->ai_canonname))
832+		   && STR_NE(host->name, "localhost")) {
833+
834+	    /*
835+	     * The gethostbyaddr() and gethostbyname() calls did not return
836+	     * the same hostname. This could be a nameserver configuration
837+	     * problem. It could also be that someone is trying to spoof us.
838+	     */
839+
840+	    tcpd_warn("host name/name mismatch: %s != %.*s",
841+		      host->name, STRING_LENGTH,
842+		      (res0->ai_canonname == NULL) ? "" : res0->ai_canonname);
843+
844+	} else {
845+
846+	    /*
847+	     * The address should be a member of the address list returned by
848+	     * gethostbyname(). We should first verify that the h_addrtype
849+	     * field is AF_INET, but this program has already caused too much
850+	     * grief on systems with broken library code.
851+	     */
852+
853+	    for (res = res0; res; res = res->ai_next) {
854+		if (res->ai_family != sin->sa_family)
855+		    continue;
856+		switch (res->ai_family) {
857+		case AF_INET:
858+		    rap = (char *)&((struct sockaddr_in *)res->ai_addr)->sin_addr;
859+		    break;
860+		case AF_INET6:
861+		    /* need to check scope_id */
862+		    if (((struct sockaddr_in6 *)sin)->sin6_scope_id !=
863+		        ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id) {
864+			continue;
865+		    }
866+		    rap = (char *)&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
867+		    break;
868+		default:
869+		    continue;
870+		}
871+		if (memcmp(rap, ap, alen) == 0) {
872+		    freeaddrinfo(res0);
873+		    return;			/* name is good, keep it */
874+		}
875+	    }
876+
877+	    /*
878+	     * The host name does not map to the initial address. Perhaps
879+	     * someone has messed up. Perhaps someone compromised a name
880+	     * server.
881+	     */
882+
883+	    getnameinfo(sin, salen, hname, sizeof(hname),
884+			NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID);
885+	    tcpd_warn("host name/address mismatch: %s != %.*s",
886+		      hname, STRING_LENGTH,
887+		      (res0->ai_canonname == NULL) ? "" : res0->ai_canonname);
888+	}
889+	strcpy(host->name, paranoid);		/* name is bad, clobber it */
890+	if (res0)
891+	    freeaddrinfo(res0);
892+    }
893+#else /* INET6 */
894     struct sockaddr_in *sin = host->sin;
895     struct hostent *hp;
896     int     i;
897@@ -220,6 +412,7 @@
898 	}
899 	strcpy(host->name, paranoid);		/* name is bad, clobber it */
900     }
901+#endif /* INET6 */
902 }
903
904 /* sock_sink - absorb unreceived IP datagram */
905@@ -228,7 +421,11 @@
906 int     fd;
907 {
908     char    buf[BUFSIZ];
909+#ifdef INET6
910+    struct sockaddr_storage sin;
911+#else
912     struct sockaddr_in sin;
913+#endif
914     int     size = sizeof(sin);
915
916     /*
917diff -ruN tcp_wrappers_7.6.orig/tcpd.c tcp_wrappers_7.6/tcpd.c
918--- tcp_wrappers_7.6.orig/tcpd.c	1996-02-11 17:01:33.000000000 +0100
919+++ tcp_wrappers_7.6/tcpd.c	2004-04-10 19:07:43.000000000 +0200
920@@ -120,7 +120,12 @@
921
922     /* Report request and invoke the real daemon program. */
923
924+#ifdef INET6
925+    syslog(allow_severity, "connect from %s (%s)",
926+	   eval_client(&request), eval_hostaddr(request.client));
927+#else
928     syslog(allow_severity, "connect from %s", eval_client(&request));
929+#endif
930     closelog();
931     (void) execv(path, argv);
932     syslog(LOG_ERR, "error: cannot execute %s: %m", path);
933diff -ruN tcp_wrappers_7.6.orig/tcpdchk.c tcp_wrappers_7.6/tcpdchk.c
934--- tcp_wrappers_7.6.orig/tcpdchk.c	1997-02-12 02:13:25.000000000 +0100
935+++ tcp_wrappers_7.6/tcpdchk.c	2004-04-10 19:07:43.000000000 +0200
936@@ -22,6 +22,9 @@
937
938 #include <sys/types.h>
939 #include <sys/stat.h>
940+#ifdef INET6
941+#include <sys/socket.h>
942+#endif
943 #include <netinet/in.h>
944 #include <arpa/inet.h>
945 #include <stdio.h>
946@@ -397,6 +400,31 @@
947     }
948 }
949
950+#ifdef INET6
951+static int is_inet6_addr(pat)
952+    char *pat;
953+{
954+    struct addrinfo hints, *res;
955+    int len, ret;
956+    char ch;
957+
958+    if (*pat != '[')
959+	return (0);
960+    len = strlen(pat);
961+    if ((ch = pat[len - 1]) != ']')
962+	return (0);
963+    pat[len - 1] = '\0';
964+    memset(&hints, 0, sizeof(hints));
965+    hints.ai_family = AF_INET6;
966+    hints.ai_socktype = SOCK_STREAM;
967+    hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
968+    if ((ret = getaddrinfo(pat + 1, NULL, &hints, &res)) == 0)
969+	freeaddrinfo(res);
970+    pat[len - 1] = ch;
971+    return (ret == 0);
972+}
973+#endif
974+
975 /* check_host - criticize host pattern */
976
977 static int check_host(pat)
978@@ -423,14 +451,27 @@
979 #endif
980 #endif
981     } else if (mask = split_at(pat, '/')) {	/* network/netmask */
982+#ifdef INET6
983+	int mask_len;
984+
985+	if ((dot_quad_addr(pat) == INADDR_NONE
986+	    || dot_quad_addr(mask) == INADDR_NONE)
987+	    && (!is_inet6_addr(pat)
988+		|| ((mask_len = atoi(mask)) < 0 || mask_len > 128)))
989+#else
990 	if (dot_quad_addr(pat) == INADDR_NONE
991 	    || dot_quad_addr(mask) == INADDR_NONE)
992+#endif
993 	    tcpd_warn("%s/%s: bad net/mask pattern", pat, mask);
994     } else if (STR_EQ(pat, "FAIL")) {		/* obsolete */
995 	tcpd_warn("FAIL is no longer recognized");
996 	tcpd_warn("(use EXCEPT or DENY instead)");
997     } else if (reserved_name(pat)) {		/* other reserved */
998 	 /* void */ ;
999+#ifdef INET6
1000+    } else if (is_inet6_addr(pat)) { /* IPv6 address */
1001+	addr_count = 1;
1002+#endif
1003     } else if (NOT_INADDR(pat)) {		/* internet name */
1004 	if (pat[strlen(pat) - 1] == '.') {
1005 	    tcpd_warn("%s: domain or host name ends in dot", pat);
1006diff -ruN tcp_wrappers_7.6.orig/tcpd.h tcp_wrappers_7.6/tcpd.h
1007--- tcp_wrappers_7.6.orig/tcpd.h	1996-03-19 16:22:25.000000000 +0100
1008+++ tcp_wrappers_7.6/tcpd.h	2004-04-10 19:07:43.000000000 +0200
1009@@ -11,7 +11,11 @@
1010 struct host_info {
1011     char    name[STRING_LENGTH];	/* access via eval_hostname(host) */
1012     char    addr[STRING_LENGTH];	/* access via eval_hostaddr(host) */
1013+#ifdef INET6
1014+    struct sockaddr *sin;		/* socket address or 0 */
1015+#else
1016     struct sockaddr_in *sin;		/* socket address or 0 */
1017+#endif
1018     struct t_unitdata *unit;		/* TLI transport address or 0 */
1019     struct request_info *request;	/* for shared information */
1020 };
1021diff -ruN tcp_wrappers_7.6.orig/tcpdmatch.c tcp_wrappers_7.6/tcpdmatch.c
1022--- tcp_wrappers_7.6.orig/tcpdmatch.c	1996-02-11 17:01:36.000000000 +0100
1023+++ tcp_wrappers_7.6/tcpdmatch.c	2004-04-10 19:07:43.000000000 +0200
1024@@ -57,7 +57,11 @@
1025 int     argc;
1026 char  **argv;
1027 {
1028+#ifdef INET6
1029+    struct addrinfo hints, *hp, *res;
1030+#else
1031     struct hostent *hp;
1032+#endif
1033     char   *myname = argv[0];
1034     char   *client;
1035     char   *server;
1036@@ -68,8 +72,13 @@
1037     int     ch;
1038     char   *inetcf = 0;
1039     int     count;
1040+#ifdef INET6
1041+    struct sockaddr_storage server_sin;
1042+    struct sockaddr_storage client_sin;
1043+#else
1044     struct sockaddr_in server_sin;
1045     struct sockaddr_in client_sin;
1046+#endif
1047     struct stat st;
1048
1049     /*
1050@@ -172,13 +181,20 @@
1051     if (NOT_INADDR(server) == 0 || HOSTNAME_KNOWN(server)) {
1052 	if ((hp = find_inet_addr(server)) == 0)
1053 	    exit(1);
1054+#ifndef INET6
1055 	memset((char *) &server_sin, 0, sizeof(server_sin));
1056 	server_sin.sin_family = AF_INET;
1057+#endif
1058 	request_set(&request, RQ_SERVER_SIN, &server_sin, 0);
1059
1060+#ifdef INET6
1061+	for (res = hp, count = 0; res; res = res->ai_next, count++) {
1062+	    memcpy(&server_sin, res->ai_addr, res->ai_addrlen);
1063+#else
1064 	for (count = 0; (addr = hp->h_addr_list[count]) != 0; count++) {
1065 	    memcpy((char *) &server_sin.sin_addr, addr,
1066 		   sizeof(server_sin.sin_addr));
1067+#endif
1068
1069 	    /*
1070 	     * Force evaluation of server host name and address. Host name
1071@@ -194,7 +210,11 @@
1072 	    fprintf(stderr, "Please specify an address instead\n");
1073 	    exit(1);
1074 	}
1075+#ifdef INET6
1076+	freeaddrinfo(hp);
1077+#else
1078 	free((char *) hp);
1079+#endif
1080     } else {
1081 	request_set(&request, RQ_SERVER_NAME, server, 0);
1082     }
1083@@ -208,6 +228,18 @@
1084 	tcpdmatch(&request);
1085 	exit(0);
1086     }
1087+#ifdef INET6
1088+    memset(&hints, 0, sizeof(hints));
1089+    hints.ai_family = AF_INET6;
1090+    hints.ai_socktype = SOCK_STREAM;
1091+    hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
1092+    if (getaddrinfo(client, NULL, &hints, &res) == 0) {
1093+	freeaddrinfo(res);
1094+	request_set(&request, RQ_CLIENT_ADDR, client, 0);
1095+	tcpdmatch(&request);
1096+	exit(0);
1097+    }
1098+#endif
1099
1100     /*
1101      * Perhaps they are testing special client hostname patterns that aren't
1102@@ -229,6 +261,34 @@
1103      */
1104     if ((hp = find_inet_addr(client)) == 0)
1105 	exit(1);
1106+#ifdef INET6
1107+    request_set(&request, RQ_CLIENT_SIN, &client_sin, 0);
1108+
1109+    for (res = hp, count = 0; res; res = res->ai_next, count++) {
1110+	memcpy(&client_sin, res->ai_addr, res->ai_addrlen);
1111+
1112+	/*
1113+	 * getnameinfo() doesn't do reverse lookup against link-local
1114+	 * address.  So, we pass through host name evaluation against
1115+	 * such addresses.
1116+	 */
1117+	if (res->ai_family != AF_INET6 ||
1118+	    !IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr)) {
1119+	    /*
1120+	     * Force evaluation of client host name and address. Host name
1121+	     * conflicts will be reported while eval_hostname() does its job.
1122+	     */
1123+	    request_set(&request, RQ_CLIENT_NAME, "", RQ_CLIENT_ADDR, "", 0);
1124+	    if (STR_EQ(eval_hostname(request.client), unknown))
1125+		tcpd_warn("host address %s->name lookup failed",
1126+			  eval_hostaddr(request.client));
1127+	}
1128+	tcpdmatch(&request);
1129+	if (res->ai_next)
1130+	    printf("\n");
1131+    }
1132+    freeaddrinfo(hp);
1133+#else
1134     memset((char *) &client_sin, 0, sizeof(client_sin));
1135     client_sin.sin_family = AF_INET;
1136     request_set(&request, RQ_CLIENT_SIN, &client_sin, 0);
1137@@ -250,6 +310,7 @@
1138 	    printf("\n");
1139     }
1140     free((char *) hp);
1141+#endif
1142     exit(0);
1143 }
1144
1145diff -ruN tcp_wrappers_7.6.orig/tli.c tcp_wrappers_7.6/tli.c
1146--- tcp_wrappers_7.6.orig/tli.c	1997-03-21 19:27:26.000000000 +0100
1147+++ tcp_wrappers_7.6/tli.c	2004-04-10 19:07:43.000000000 +0200
1148@@ -65,8 +65,13 @@
1149 void    tli_host(request)
1150 struct request_info *request;
1151 {
1152+#ifdef INET6
1153+    static struct sockaddr_storage client;
1154+    static struct sockaddr_storage server;
1155+#else
1156     static struct sockaddr_in client;
1157     static struct sockaddr_in server;
1158+#endif
1159
1160     /*
1161      * If we discover that we are using an IP transport, pretend we never
1162@@ -76,14 +81,29 @@
1163
1164     tli_endpoints(request);
1165     if ((request->config = tli_transport(request->fd)) != 0
1166+#ifdef INET6
1167+	&& (STR_EQ(request->config->nc_protofmly, "inet") ||
1168+	    STR_EQ(request->config->nc_protofmly, "inet6"))) {
1169+#else
1170 	&& STR_EQ(request->config->nc_protofmly, "inet")) {
1171+#endif
1172 	if (request->client->unit != 0) {
1173+#ifdef INET6
1174+	    client = *(struct sockaddr_storage *) request->client->unit->addr.buf;
1175+	    request->client->sin = (struct sockaddr *) &client;
1176+#else
1177 	    client = *(struct sockaddr_in *) request->client->unit->addr.buf;
1178 	    request->client->sin = &client;
1179+#endif
1180 	}
1181 	if (request->server->unit != 0) {
1182+#ifdef INET6
1183+	    server = *(struct sockaddr_storage *) request->server->unit->addr.buf;
1184+	    request->server->sin = (struct sockaddr *) &server;
1185+#else
1186 	    server = *(struct sockaddr_in *) request->server->unit->addr.buf;
1187 	    request->server->sin = &server;
1188+#endif
1189 	}
1190 	tli_cleanup(request);
1191 	sock_methods(request);
1192@@ -187,7 +207,15 @@
1193     }
1194     while (config = getnetconfig(handlep)) {
1195 	if (stat(config->nc_device, &from_config) == 0) {
1196+#ifdef NO_CLONE_DEVICE
1197+	/*
1198+	 * If the network devices are not cloned (as is the case for
1199+	 * Solaris 8 Beta), we must compare the major device numbers.
1200+	 */
1201+	    if (major(from_config.st_rdev) == major(from_client.st_rdev))
1202+#else
1203 	    if (minor(from_config.st_rdev) == major(from_client.st_rdev))
1204+#endif
1205 		break;
1206 	}
1207     }
1208diff -ruN tcp_wrappers_7.6.orig/update.c tcp_wrappers_7.6/update.c
1209--- tcp_wrappers_7.6.orig/update.c	1994-12-28 17:42:56.000000000 +0100
1210+++ tcp_wrappers_7.6/update.c	2004-04-10 19:07:43.000000000 +0200
1211@@ -46,10 +46,18 @@
1212 	    request->fd = va_arg(ap, int);
1213 	    continue;
1214 	case RQ_CLIENT_SIN:
1215+#ifdef INET6
1216+	    request->client->sin = va_arg(ap, struct sockaddr *);
1217+#else
1218 	    request->client->sin = va_arg(ap, struct sockaddr_in *);
1219+#endif
1220 	    continue;
1221 	case RQ_SERVER_SIN:
1222+#ifdef INET6
1223+	    request->server->sin = va_arg(ap, struct sockaddr *);
1224+#else
1225 	    request->server->sin = va_arg(ap, struct sockaddr_in *);
1226+#endif
1227 	    continue;
1228
1229 	    /*
1230diff -ruN tcp_wrappers_7.6.orig/workarounds.c tcp_wrappers_7.6/workarounds.c
1231--- tcp_wrappers_7.6.orig/workarounds.c	1996-03-19 16:22:26.000000000 +0100
1232+++ tcp_wrappers_7.6/workarounds.c	2004-04-10 19:07:43.000000000 +0200
1233@@ -166,11 +166,22 @@
1234 int    *len;
1235 {
1236     int     ret;
1237+#ifdef INET6
1238+    struct sockaddr *sin = sa;
1239+#else
1240     struct sockaddr_in *sin = (struct sockaddr_in *) sa;
1241+#endif
1242
1243     if ((ret = getpeername(sock, sa, len)) >= 0
1244+#ifdef INET6
1245+	&& ((sin->su_si.si_family == AF_INET6
1246+	     && IN6_IS_ADDR_UNSPECIFIED(&sin->su_sin6.sin6_addr))
1247+	    || (sin->su_si.si_family == AF_INET
1248+		&& sin->su_sin.sin_addr.s_addr == 0))) {
1249+#else
1250 	&& sa->sa_family == AF_INET
1251 	&& sin->sin_addr.s_addr == 0) {
1252+#endif
1253 	errno = ENOTCONN;
1254 	return (-1);
1255     } else {
1256