aboutsummaryrefslogtreecommitdiff
path: root/contrib/tcp_wrappers/hosts_access.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/tcp_wrappers/hosts_access.c')
-rw-r--r--contrib/tcp_wrappers/hosts_access.c105
1 files changed, 105 insertions, 0 deletions
diff --git a/contrib/tcp_wrappers/hosts_access.c b/contrib/tcp_wrappers/hosts_access.c
index 27dd81db4565..2b4dcee9ef9a 100644
--- a/contrib/tcp_wrappers/hosts_access.c
+++ b/contrib/tcp_wrappers/hosts_access.c
@@ -26,7 +26,13 @@ static char sccsid[] = "@(#) hosts_access.c 1.21 97/02/12 02:13:22";
/* System libraries. */
#include <sys/types.h>
+#ifdef INT32_T
+ typedef uint32_t u_int32_t;
+#endif
#include <sys/param.h>
+#ifdef INET6
+#include <sys/socket.h>
+#endif
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
@@ -84,6 +90,10 @@ static int client_match();
static int host_match();
static int string_match();
static int masked_match();
+#ifdef INET6
+static int masked_match4();
+static int masked_match6();
+#endif
/* Size of logical line buffer. */
@@ -313,6 +323,13 @@ char *string;
{
int n;
+#ifdef INET6
+ /* convert IPv4 mapped IPv6 address to IPv4 address */
+ if (STRN_EQ(string, "::ffff:", 7)
+ && dot_quad_addr(string + 7) != INADDR_NONE) {
+ string += 7;
+ }
+#endif
if (tok[0] == '.') { /* suffix */
n = strlen(string) - strlen(tok);
return (n > 0 && STR_EQ(tok, string + n));
@@ -323,20 +340,55 @@ char *string;
} else if (tok[(n = strlen(tok)) - 1] == '.') { /* prefix */
return (STRN_EQ(tok, string, n));
} else { /* exact match */
+#ifdef INET6
+ struct in6_addr pat, addr;
+ int len, ret;
+ char ch;
+
+ len = strlen(tok);
+ if (*tok == '[' && tok[len - 1] == ']') {
+ ch = tok[len - 1];
+ tok[len - 1] = '\0';
+ ret = inet_pton(AF_INET6, tok + 1, pat.s6_addr);
+ tok[len - 1] = ch;
+ if (ret != 1 || inet_pton(AF_INET6, string, addr.s6_addr) != 1)
+ return NO;
+ return (!memcmp(&pat, &addr, sizeof(struct in6_addr)));
+ }
+#endif
return (STR_EQ(tok, string));
}
}
/* masked_match - match address against netnumber/netmask */
+#ifdef INET6
static int masked_match(net_tok, mask_tok, string)
char *net_tok;
char *mask_tok;
char *string;
{
+ return (masked_match4(net_tok, mask_tok, string) ||
+ masked_match6(net_tok, mask_tok, string));
+}
+
+static int masked_match4(net_tok, mask_tok, string)
+#else
+static int masked_match(net_tok, mask_tok, string)
+#endif
+char *net_tok;
+char *mask_tok;
+char *string;
+{
+#ifdef INET6
+ u_int32_t net;
+ u_int32_t mask;
+ u_int32_t addr;
+#else
unsigned long net;
unsigned long mask;
unsigned long addr;
+#endif
/*
* Disallow forms other than dotted quad: the treatment that inet_addr()
@@ -348,8 +400,61 @@ char *string;
return (NO);
if ((net = dot_quad_addr(net_tok)) == INADDR_NONE
|| (mask = dot_quad_addr(mask_tok)) == INADDR_NONE) {
+#ifndef INET6
tcpd_warn("bad net/mask expression: %s/%s", net_tok, mask_tok);
+#endif
return (NO); /* not tcpd_jump() */
}
return ((addr & mask) == net);
}
+
+#ifdef INET6
+static int masked_match6(net_tok, mask_tok, string)
+char *net_tok;
+char *mask_tok;
+char *string;
+{
+ struct in6_addr net, addr;
+ u_int32_t mask;
+ int len, mask_len, i = 0;
+ char ch;
+
+ if (inet_pton(AF_INET6, string, addr.s6_addr) != 1)
+ return NO;
+
+ if (IN6_IS_ADDR_V4MAPPED(&addr)) {
+ if ((*(u_int32_t *)&net.s6_addr[12] = dot_quad_addr(net_tok)) == INADDR_NONE
+ || (mask = dot_quad_addr(mask_tok)) == INADDR_NONE)
+ return (NO);
+ return ((*(u_int32_t *)&addr.s6_addr[12] & mask) == *(u_int32_t *)&net.s6_addr[12]);
+ }
+
+ /* match IPv6 address against netnumber/prefixlen */
+ len = strlen(net_tok);
+ if (*net_tok != '[' || net_tok[len - 1] != ']')
+ return NO;
+ ch = net_tok[len - 1];
+ net_tok[len - 1] = '\0';
+ if (inet_pton(AF_INET6, net_tok + 1, net.s6_addr) != 1) {
+ net_tok[len - 1] = ch;
+ return NO;
+ }
+ net_tok[len - 1] = ch;
+ if ((mask_len = atoi(mask_tok)) < 0 || mask_len > 128)
+ return NO;
+
+ while (mask_len > 0) {
+ if (mask_len < 32) {
+ mask = htonl(~(0xffffffff >> mask_len));
+ if ((*(u_int32_t *)&addr.s6_addr[i] & mask) != (*(u_int32_t *)&net.s6_addr[i] & mask))
+ return NO;
+ break;
+ }
+ if (*(u_int32_t *)&addr.s6_addr[i] != *(u_int32_t *)&net.s6_addr[i])
+ return NO;
+ i += 4;
+ mask_len -= 32;
+ }
+ return YES;
+}
+#endif /* INET6 */