aboutsummaryrefslogtreecommitdiff
path: root/contrib/tcp_wrappers/scaffold.c
diff options
context:
space:
mode:
authorYoshinobu Inoue <shin@FreeBSD.org>2000-02-03 10:27:03 +0000
committerYoshinobu Inoue <shin@FreeBSD.org>2000-02-03 10:27:03 +0000
commit8053080cbc1ee98871dd7549fef2a6d80f99a00a (patch)
tree1d13c0ef63117b6a1c0d3dd248bab5d834087aea /contrib/tcp_wrappers/scaffold.c
parentab08b2ee086a17c207ad7113836a332890a46834 (diff)
downloadsrc-8053080cbc1ee98871dd7549fef2a6d80f99a00a.tar.gz
src-8053080cbc1ee98871dd7549fef2a6d80f99a00a.zip
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
Notes
Notes: svn path=/head/; revision=56977
Diffstat (limited to 'contrib/tcp_wrappers/scaffold.c')
-rw-r--r--contrib/tcp_wrappers/scaffold.c155
1 files changed, 155 insertions, 0 deletions
diff --git a/contrib/tcp_wrappers/scaffold.c b/contrib/tcp_wrappers/scaffold.c
index afce15a64e4d..ea87c5c65419 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