diff options
Diffstat (limited to 'contrib/tcp_wrappers/hosts_access.c')
-rw-r--r-- | contrib/tcp_wrappers/hosts_access.c | 105 |
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 */ |