diff options
author | shin <shin@FreeBSD.org> | 2000-02-03 10:27:03 +0000 |
---|---|---|
committer | shin <shin@FreeBSD.org> | 2000-02-03 10:27:03 +0000 |
commit | 225d233deb08e4006d8cabd0a6572f76d729f90d (patch) | |
tree | 5e244ba219acd7cbeb17a0c5dc92b62227ab2828 /contrib/tcp_wrappers/scaffold.c | |
parent | 22aa8f5f0343020efcf93d4ebc043c5f558995d5 (diff) | |
download | FreeBSD-src-225d233deb08e4006d8cabd0a6572f76d729f90d.zip FreeBSD-src-225d233deb08e4006d8cabd0a6572f76d729f90d.tar.gz |
Missing tcp_wrapper IPv6 support seemed to be a bug, so commit it.
Now when tcp_wrapper is enabled by inetd -wW,
several accesses which should be permitted are refused only for IPv6,
if hostname is used to decide the host to be allowed.
IPv6 users will be just upset.
About security related concern.
-All extensions are wrapped by #ifdef INET6, so people can completely
disable the extension by recompile libwrap without INET6 option.
-Access via IPv6 is not enabled by default.
People need to enable IPv6 access by changing /etc/inetd.conf at first,
by adding tcp6 and/or tcp46 entries.
-The base of patches are from KAME package and are actually daily used
for more than a year in several Japanese IPv6 environments.
-Patches are reviewed by markm.
Approved by: jkh
Submitted by: Hajimu UMEMOTO <ume@mahoroba.org>
Reviewed by: markm
Obtained from: KAME project
Diffstat (limited to 'contrib/tcp_wrappers/scaffold.c')
-rw-r--r-- | contrib/tcp_wrappers/scaffold.c | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/contrib/tcp_wrappers/scaffold.c b/contrib/tcp_wrappers/scaffold.c index afce15a..ea87c5c 100644 --- a/contrib/tcp_wrappers/scaffold.c +++ b/contrib/tcp_wrappers/scaffold.c @@ -2,6 +2,8 @@ * Routines for testing only. Not really industrial strength. * * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. + * + * $FreeBSD$ */ #ifndef lint @@ -20,6 +22,7 @@ static char sccs_id[] = "@(#) scaffold.c 1.6 97/03/21 19:27:24"; #include <syslog.h> #include <setjmp.h> #include <string.h> +#include <resolv.h> #ifndef INADDR_NONE #define INADDR_NONE (-1) /* XXX should be 0xffffffff */ @@ -57,6 +60,9 @@ struct hostent *hp; /* void */ ; if ((hb = (struct hostent_block *) malloc(sizeof(struct hostent_block) +#ifdef INET6 + + strlen(hp->h_name) + 1 +#endif + (hp->h_length + sizeof(char *)) * count)) == 0) { fprintf(stderr, "Sorry, out of memory\n"); exit(1); @@ -66,6 +72,11 @@ struct hostent *hp; hb->host.h_addr_list = hb->addr_list; hb->host.h_addr_list[count] = 0; data = (char *) (hb->host.h_addr_list + count + 1); +#ifdef INET6 + hb->host.h_name = data + hp->h_length * count; + strcpy(hb->host.h_name, hp->h_name); + hb->host.h_addrtype = hp->h_addrtype; +#endif for (count = 0; (addr = hp->h_addr_list[count]) != 0; count++) { hb->host.h_addr_list[count] = data + hp->h_length * count; @@ -74,6 +85,104 @@ struct hostent *hp; return (&hb->host); } +#if defined(INET6) && !defined(USE_GETIPNODEBY) +/* merge_hostent - merge hostent in one memory block */ + +static struct hostent *merge_hostent(hp1, hp2) +struct hostent *hp1, *hp2; +{ + struct hostent_block { + struct hostent host; + char *addr_list[1]; + }; + struct hostent_block *hb; + int count, count2; + char *data; + char *addr; + + for (count = 0; hp1->h_addr_list[count] != 0; count++) + /* void */ ; + for (count2 = 0; hp2->h_addr_list[count2] != 0; count2++) + /* void */ ; + count += count2; + + if ((hb = (struct hostent_block *) malloc(sizeof(struct hostent_block) + + strlen(hp1->h_name) + 1 + + (hp1->h_length + sizeof(char *)) * count)) == 0) { + fprintf(stderr, "Sorry, out of memory\n"); + exit(1); + } + memset((char *) &hb->host, 0, sizeof(hb->host)); + hb->host.h_length = hp1->h_length; + hb->host.h_addr_list = hb->addr_list; + hb->host.h_addr_list[count] = 0; + data = (char *) (hb->host.h_addr_list + count + 1); + hb->host.h_name = data + hp1->h_length * count; + strcpy(hb->host.h_name, hp1->h_name); + hb->host.h_addrtype = hp1->h_addrtype; + + for (count = 0; (addr = hp1->h_addr_list[count]) != 0; count++) { + hb->host.h_addr_list[count] = data + hp1->h_length * count; + memcpy(hb->host.h_addr_list[count], addr, hp1->h_length); + } + for (count2 = 0; (addr = hp2->h_addr_list[count2]) != 0; count2++) { + hb->host.h_addr_list[count] = data + hp1->h_length * count; + memcpy(hb->host.h_addr_list[count], addr, hp1->h_length); + ++count; + } + return (&hb->host); +} +#endif + +static struct hostent *gethostbyname64(host) +char *host; +{ + struct hostent *hp = NULL, *hp2 = NULL; +#ifdef USE_GETIPNODEBY + int h_error; + + if ((hp = getipnodebyname(host, AF_INET6, + AI_V4MAPPED | AI_ADDRCONFIG | AI_ALL, + &h_error)) != 0) { + hp2 = dup_hostent(hp); + freehostent(hp); + return (hp2); + } +#else + struct hostent *hp1; + u_long res_options; + + if ((_res.options & RES_INIT) == 0) { + if (res_init() < 0) { + tcpd_warn("%s: res_init() failed", host); + return (NULL); + } + } + res_options = _res.options; +#ifdef INET6 + _res.options |= RES_USE_INET6; + if ((hp1 = gethostbyname2(host, AF_INET6)) != NULL) + hp1 = dup_hostent(hp1); +#endif + if ((hp2 = gethostbyname2(host, AF_INET)) != NULL) + hp2 = dup_hostent(hp2); + _res.options = res_options; +#ifdef INET6 + if (hp1 && hp2) { + hp = merge_hostent(hp1, hp2); + free((char *) hp1); + free((char *) hp2); + return (hp); + } + if (hp1) + return (hp1); +#endif + if (hp2) + return (hp2); +#endif + return (NULL); +} + /* find_inet_addr - find all addresses for this host, result to free() */ struct hostent *find_inet_addr(host) @@ -83,6 +192,7 @@ char *host; struct hostent *hp; static struct hostent h; static char *addr_list[2]; + static char hnamebuf[BUFSIZ]; /* * Host address: translate it to internal form. @@ -91,6 +201,11 @@ char *host; h.h_addr_list = addr_list; h.h_addr_list[0] = (char *) &addr; h.h_length = sizeof(addr); +#ifdef INET6 + h.h_addrtype = AF_INET; + h.h_name = hnamebuf; + strcpy(h.h_name, host); +#endif return (dup_hostent(&h)); } @@ -104,19 +219,33 @@ char *host; tcpd_warn("%s: not an internet address", host); return (0); } +#ifdef INET6 + if ((hp = gethostbyname64(host)) == 0) { +#else if ((hp = gethostbyname(host)) == 0) { +#endif tcpd_warn("%s: host not found", host); return (0); } +#ifdef INET6 + if (hp->h_addrtype != AF_INET6) { + tcpd_warn("%d: not an internet host", hp->h_addrtype); + free((char *) hp); +#else if (hp->h_addrtype != AF_INET) { tcpd_warn("%d: not an internet host", hp->h_addrtype); +#endif return (0); } if (STR_NE(host, hp->h_name)) { tcpd_warn("%s: hostname alias", host); tcpd_warn("(official name: %.*s)", STRING_LENGTH, hp->h_name); } +#ifdef INET6 + return (hp); +#else return (dup_hostent(hp)); +#endif } /* check_dns - give each address thorough workout, return address count */ @@ -125,7 +254,13 @@ int check_dns(host) char *host; { struct request_info request; +#ifdef INET6 + struct sockaddr_storage sin; + char *ap; + int alen; +#else struct sockaddr_in sin; +#endif struct hostent *hp; int count; char *addr; @@ -135,10 +270,30 @@ char *host; request_init(&request, RQ_CLIENT_SIN, &sin, 0); sock_methods(&request); memset((char *) &sin, 0, sizeof(sin)); +#ifdef INET6 + sin.ss_family = hp->h_addrtype; + switch (hp->h_addrtype) { + case AF_INET: + ap = (char *)&((struct sockaddr_in *)&sin)->sin_addr; + alen = sizeof(struct sockaddr_in); + break; + case AF_INET6: + ap = (char *)&((struct sockaddr_in6 *)&sin)->sin6_addr; + alen = sizeof(struct sockaddr_in6); + break; + default: + return (0); + } +#else sin.sin_family = AF_INET; +#endif for (count = 0; (addr = hp->h_addr_list[count]) != 0; count++) { +#ifdef INET6 + memcpy(ap, addr, alen); +#else memcpy((char *) &sin.sin_addr, addr, sizeof(sin.sin_addr)); +#endif /* * Force host name and address conversions. Use the request structure |