diff --git a/tcp_wrappers_7.6-ipv6-host-match.patch b/tcp_wrappers_7.6-ipv6-host-match.patch new file mode 100644 index 0000000..51a6411 --- /dev/null +++ b/tcp_wrappers_7.6-ipv6-host-match.patch @@ -0,0 +1,364 @@ +--- + hosts_access.c | 271 ++++++++++++++++++++++++++++++++++----------------------- + misc.c | 18 +++ + tcpd.h | 2 + 3 files changed, 183 insertions(+), 108 deletions(-) + +Index: tcp_wrappers_7.6/hosts_access.c +=================================================================== +--- tcp_wrappers_7.6.orig/hosts_access.c ++++ tcp_wrappers_7.6/hosts_access.c +@@ -88,6 +88,10 @@ static int server_match(); + static int client_match(); + static int host_match(); + static int string_match(); ++static int masked_match(); ++#ifdef INET6 ++static void ipv6_mask(); ++#endif + + /* Size of logical line buffer. */ + +@@ -293,6 +297,74 @@ struct hosts_info *host; + return (match); + } + ++static inline int ++host_info_ipv6addr(const struct host_info *host, struct in6_addr *addrbuf) ++{ ++ /* ++ * In some cases we don't get the sockaddr, only the addr. ++ * We use inet_pton to convert it to its binary representation ++ * and match against that. ++ */ ++ if (host->sin == NULL) { ++ if (host->addr == NULL || inet_pton(AF_INET6, host->addr, addrbuf) != 1) ++ return 0; ++ ++ return 1; ++ } else ++ if (host->sin->ss_family == AF_INET6) { ++ *addrbuf = ((struct sockaddr_in6 *) host->sin)->sin6_addr; ++ return 1; ++ } ++ return 0; ++} ++ ++static inline int ++token_ipv6addr_and_mask(char *tok, struct in6_addr *addrbuf, unsigned int *maskbits) ++{ ++ char *cbr; ++ char *slash; ++ ++ if (*tok != '[') ++ return 0; ++ ++ *maskbits = 128; ++ ++ ++tok; /* now points to the beginning of the IPv6 addr string */ ++ if ((cbr = strchr(tok, ']')) == NULL) { ++ tcpd_warn("bad IP6 address specification"); ++ return 0; ++ } ++ *cbr++ = '\0'; ++ ++ /* ++ * A /nnn prefix specifies how many bits of the address we ++ * need to check. ++ * Note, we support both [x::y/64] and [x::y]/64 ++ */ ++ if ((slash = strchr(tok, '/')) == NULL && *cbr == '/') ++ slash = cbr; ++ ++ if (slash != NULL) { ++ int mask; ++ ++ *slash++ = '\0'; ++ mask = atoi(slash); ++ if (mask < 0 || mask > 128) { ++ tcpd_warn("bad IP6 prefix specification"); ++ return 0; ++ } ++ ++ *maskbits = mask; ++ } ++ ++ if (inet_pton(AF_INET6, tok, addrbuf) != 1) { ++ tcpd_warn("bad IP6 address specification"); ++ return 0; ++ } ++ ++ return 1; ++} ++ + /* host_match - match host name and/or address against pattern */ + + static int host_match(tok, host) +@@ -328,12 +400,68 @@ struct host_info *host; + } else if (STR_EQ(tok, "LOCAL")) { /* local: no dots in name */ + char *name = eval_hostname(host); + return (strchr(name, '.') == 0 && HOSTNAME_KNOWN(name)); ++ } else if (tok[0] == '[') { /* IPv6 address */ ++#ifdef INET6 ++ struct in6_addr match_addr, host_addr; ++ unsigned int mask = 128; ++ ++ if (!host_info_ipv6addr(host, &host_addr)) ++ return (NO); ++ ++ if (!token_ipv6addr_and_mask(tok, &match_addr, &mask)) ++ return (NO); ++ ++ /* ++ * Zero the bits we're not interested in in both addresses ++ * then compare. Note that we take a copy of the host info ++ * in that case. ++ */ ++ if (mask != 128) { ++ ipv6_mask(&match_addr, mask); ++ ipv6_mask(&host_addr, mask); ++ } ++ if (memcmp(&match_addr, &host_addr, sizeof(struct in6_addr)) == 0) ++ return (YES); ++#endif ++ return (NO); ++ } else if ((mask = split_at(tok, '/')) != 0) { /* net/mask */ ++ return (masked_match(tok, mask, eval_hostaddr(host))); + } else { /* anything else */ +- return (string_match(tok, eval_hostaddr(host)) +- || (NOT_INADDR(tok) && string_match(tok, eval_hostname(host)))); ++ return (string_match(tok, eval_hostaddr(host)) ++ || (NOT_INADDR(tok) && string_match(tok, eval_hostname(host)))); + } + } + ++static int masked_match(net_tok, mask_tok, string) ++char *net_tok; ++char *mask_tok; ++char *string; ++{ ++ unsigned long net; ++ unsigned long mask; ++ unsigned long addr; ++ ++ /* ++ * Disallow forms other than dotted quad: the treatment that inet_addr() ++ * gives to forms with less than four components is inconsistent with the ++ * access control language. John P. Rouillard . ++ */ ++ ++ if ((addr = dot_quad_addr(string)) == INADDR_NONE) ++ return (NO); ++ if ((net = dot_quad_addr(net_tok)) == INADDR_NONE ++ || ((mask = dot_quad_addr(mask_tok)) == INADDR_NONE ++ && strcmp(mask_tok, "255.255.255.255") ++ && (mask = prefix_to_netmask(mask_tok)) == INADDR_NONE ++ && strcmp(mask_tok, "32"))) { ++ /* 255.255.255.255 == INADDR_NONE, separate check needed. TJ. */ ++ /* 32 == INADDR_NONE, separate check needed. philipp */ ++ tcpd_warn("bad net/mask expression: %s/%s", net_tok, mask_tok); ++ return (NO); /* not tcpd_jump() */ ++ } ++ return ((addr & mask) == net); ++} ++ + /* string_match - match string against pattern + * + * tok = data read from /etc/hosts.* +@@ -359,113 +487,14 @@ char *string; + return (YES); + } else if (STR_EQ(tok, "KNOWN")) { /* not unknown */ + return (STR_NE(string, unknown)); +- } else if (STR_EQ(tok, string)) /* exact match */ +- return (YES); +-#ifdef INET6 +- else /* IP addresses match - not needed for IPv4 */ +- { +- /* For simplicity we convert everything to IPv6 (or v4 mapped) */ +- struct in6_addr pat, addr; +- int len, ret, prefixlen=128, nof_periods = 0; +- char ch, token[INET6_ADDRSTRLEN+1], *mask, *addition; +- +- /* If prefix was given, handle it */ +- if ((mask = split_at(tok, '/')) != 0) +- { +- if (strchr(mask, '.') != NULL) /* We have something +- like 255.255.0.0 */ +- { +- int b1, b2, b3, b4; +- uint32_t netmask; +- +- if (sscanf(mask, "%d.%d.%d.%d", &b1, &b2, &b3, &b4) != 4) +- { +- tcpd_warn ("Wrong netmask in %s", tok); +- return (NO); +- } +- netmask = (((((b1 * 256) + b2) * 256) + b3) * 256) + b4; +- prefixlen = 0; +- while (netmask > 0) +- { +- ++prefixlen; +- netmask <<= 1; +- } +- } +- else if (sscanf(mask, "%d", &prefixlen) != 1 || prefixlen < 0) +- { +- tcpd_warn ("Wrong prefix length in %s", tok); +- return (NO); +- } +- +- if (is_v4_string (tok)) +- prefixlen += 96; /* extend to v4mapped */ +- +- if (prefixlen > 128) +- { +- tcpd_warn ("Prefix too long in %s", tok); +- return (NO); +- } +- } +- +- len = strlen(tok); +- if (tok[len - 1] == '.') { /* prefix */ +- char *ptok = tok; +- +- while ((ptok = strchr(ptok, '.')) != NULL){ +- nof_periods++; +- ptok++; +- } +- switch(nof_periods){ +- case 1: +- addition = "0.0.0"; +- prefixlen = 8; +- break; +- case 2: +- addition = "0.0"; +- prefixlen = 16; +- break; +- case 3: +- addition = "0"; +- prefixlen = 24; +- break; +- default: +- tcpd_warn ("Wrong prefix %s", tok); +- return (NO); +- } +- snprintf(token, sizeof(token), "%s%s", tok, addition); +- prefixlen += 96; /* extend to v4mapped */ +- } +- else if (*tok == '[' && tok[len - 1] == ']') +- { +- ch = tok[len - 1]; +- tok[len - 1] = '\0'; +- snprintf(token, sizeof(token), "%s", tok+1); +- tok[len - 1] = ch; +- } +- else +- snprintf(token, sizeof(token), "%s", tok); +- +- memset (&pat, 0, sizeof(pat)); +- memset (&addr, 0, sizeof(addr)); +- +- if (inet_pton_mapped(AF_INET6, token, &pat) != 1) +- return (NO); +- +- if (inet_pton_mapped(AF_INET6, string, &addr) != 1) +- { +- tcpd_warn("Unable to handle client address: %s", string); +- return (NO); +- } +- +- if (prefixlen < 128) +- { +- apply_v6_prefix (&pat, prefixlen); +- apply_v6_prefix (&addr, prefixlen); +- } +- +- return (!memcmp(&pat, &addr, sizeof(struct in6_addr))); ++ } else if (tok[(n = strlen(tok)) - 1] == '.') { /* prefix */ ++ return (STRN_EQ(tok, string, n)); ++ } else if ((STR_EQ(tok, "localhost") || STR_EQ(tok, "localhost.localdomain")) ++ && (STR_EQ(string, "localhost") || STR_EQ(string, "localhost.localdomain"))) { ++ return (YES); /* these localhosts are equivalent */ ++ } else { /* exact match */ ++ return (STR_EQ(tok, string)); + } +-#endif + } + + #ifndef DISABLE_WILDCARD_MATCHING +@@ -535,3 +564,29 @@ int match_pattern_ylo(const char *s, con + /*NOTREACHED*/ + } + #endif /* DISABLE_WILDCARD_MATCHING */ ++ ++#ifdef INET6 ++/* ++ * Function that zeros all but the first "maskbits" bits of the IPV6 address ++ * This function can be made generic by specifying an address length as ++ * extra parameter. (So Wietse can implement 1.2.3.4/16) ++ */ ++static void ipv6_mask(in6p, maskbits) ++struct in6_addr *in6p; ++int maskbits; ++{ ++ unsigned char *p = (unsigned char*) in6p; ++ ++ if (maskbits < 0 || maskbits >= 128) ++ return; ++ ++ p += maskbits / 8; ++ maskbits %= 8; ++ ++ if (maskbits != 0) ++ *p++ &= 0xff << (8 - maskbits); ++ ++ while (p < (((unsigned char*) in6p)) + sizeof(*in6p)) ++ *p++ = 0; ++} ++#endif +Index: tcp_wrappers_7.6/misc.c +=================================================================== +--- tcp_wrappers_7.6.orig/misc.c ++++ tcp_wrappers_7.6/misc.c +@@ -107,3 +107,21 @@ char *str; + } + return (runs == 4 ? inet_addr(str) : INADDR_NONE); + } ++ ++/* prefix_to_netmask - convert prefix (0-32) to netmask */ ++ ++unsigned long prefix_to_netmask(str) ++char *str; ++{ ++ unsigned long prefix; ++ char *endptr; ++ ++ if (!isdigit(str[0])) ++ return INADDR_NONE; ++ ++ prefix = strtoul(str, &endptr, 10); ++ if ((endptr == str) || (*endptr != '\0') || (prefix > 32)) ++ return INADDR_NONE; ++ ++ return htonl(~0UL << (32 - prefix)); ++} +Index: tcp_wrappers_7.6/tcpd.h +=================================================================== +--- tcp_wrappers_7.6.orig/tcpd.h ++++ tcp_wrappers_7.6/tcpd.h +@@ -88,6 +88,7 @@ extern void refuse(struct request_info * + extern char *xgets(char *, int, FILE *); + extern char *split_at(char *, int); + extern unsigned long dot_quad_addr(char *); ++extern char *skip_ipv6_addrs(char *); + #else + extern int hosts_access(); /* access control */ + extern void shell_cmd(); /* execute shell command */ +@@ -98,6 +99,7 @@ extern void refuse(); /* clean up and + extern char *xgets(); /* fgets() on steroids */ + extern char *split_at(); /* strchr() and split */ + extern unsigned long dot_quad_addr(); /* restricted inet_addr() */ ++extern char *skip_ipv6_addrs(); + #endif + + /* Global variables. */ diff --git a/tcp_wrappers_7.6-ipv6-mapped-v4.patch b/tcp_wrappers_7.6-ipv6-mapped-v4.patch new file mode 100644 index 0000000..e053ea6 --- /dev/null +++ b/tcp_wrappers_7.6-ipv6-mapped-v4.patch @@ -0,0 +1,56 @@ +--- + hosts_access.c | 2 +- + socket.c | 14 +++++++++----- + 2 files changed, 10 insertions(+), 6 deletions(-) + +Index: tcp_wrappers_7.6/hosts_access.c +=================================================================== +--- tcp_wrappers_7.6.orig/hosts_access.c ++++ tcp_wrappers_7.6/hosts_access.c +@@ -461,7 +461,7 @@ char *string; + } + return ((addr & mask) == net); + } +- ++ + /* string_match - match string against pattern + * + * tok = data read from /etc/hosts.* +Index: tcp_wrappers_7.6/socket.c +=================================================================== +--- tcp_wrappers_7.6.orig/socket.c ++++ tcp_wrappers_7.6/socket.c +@@ -187,24 +187,28 @@ struct host_info *host; + #ifdef INET6 + struct sockaddr *sin = (struct sockaddr *) host->sin; + char *ap; +- int alen; ++ int af; + + if (!sin) + return; +- switch (sin->sa_family) { ++ ++ af = sin->sa_family; ++ switch (af) { + case AF_INET: + ap = (char *)&((struct sockaddr_in *)sin)->sin_addr; +- alen = sizeof(struct in_addr); + break; + case AF_INET6: + ap = (char *)&((struct sockaddr_in6 *)sin)->sin6_addr; +- alen = sizeof(struct in6_addr); ++ if (IN6_IS_ADDR_V4MAPPED(ap)) { ++ ap = &((struct in6_addr *) ap)->s6_addr32[3]; ++ af = AF_INET; ++ } + break; + default: + return; + } + host->addr[0] = '\0'; +- inet_ntop(sin->sa_family, ap, host->addr, sizeof(host->addr)); ++ inet_ntop(af, ap, host->addr, sizeof(host->addr)); + #else + struct sockaddr_in *sin = host->sin; + diff --git a/tcp_wrappers_7.6-ipv6-sockaddr-storage.patch b/tcp_wrappers_7.6-ipv6-sockaddr-storage.patch new file mode 100644 index 0000000..309da68 --- /dev/null +++ b/tcp_wrappers_7.6-ipv6-sockaddr-storage.patch @@ -0,0 +1,297 @@ +--- + ip6utils.h | 2 + + rfc931.c | 101 +++++++++++++++++++++++++++++++++++++++---------------------- + scaffold.c | 9 +---- + socket.c | 14 +------- + tcpd.h | 8 +--- + update.c | 4 +- + 6 files changed, 76 insertions(+), 62 deletions(-) + +Index: tcp_wrappers_7.6/ip6utils.h +=================================================================== +--- tcp_wrappers_7.6.orig/ip6utils.h ++++ tcp_wrappers_7.6/ip6utils.h +@@ -1,6 +1,8 @@ + #ifndef IP6UTILS_H + #define IP6UTILS_H + ++#include ++ + /* inet_pton_mapped() + - works like inet_pton(3) but always returns IPv6 address + in dst - either "real" or v4mapped (::ffff:1.2.3.4) in +Index: tcp_wrappers_7.6/rfc931.c +=================================================================== +--- tcp_wrappers_7.6.orig/rfc931.c ++++ tcp_wrappers_7.6/rfc931.c +@@ -65,28 +65,69 @@ int sig; + siglongjmp(timebuf, sig); + } + ++static inline unsigned int ++sockaddr_len(const struct sockaddr_storage *ap) ++{ ++ switch (ap->ss_family) { ++ case AF_INET: ++ return sizeof(struct sockaddr_in); ++ ++ case AF_INET6: ++ return sizeof(struct sockaddr_in6); ++ ++ } ++ ++ return 0; ++} ++ ++static inline unsigned short ++sockaddr_port(const struct sockaddr_storage *ap) ++{ ++ unsigned short num; ++ ++ switch (ap->ss_family) { ++ case AF_INET: ++ num = ((const struct sockaddr_in *) ap)->sin_port; ++ break; ++ case AF_INET6: ++ num = ((const struct sockaddr_in6 *) ap)->sin6_port; ++ break; ++ default: ++ num = 0; ++ break; ++ } ++ ++ return ntohs(num); ++} ++ ++static inline void ++sockaddr_set_port(struct sockaddr_storage *ap, unsigned short port) ++{ ++ unsigned short num = htons(port); ++ ++ switch (ap->ss_family) { ++ case AF_INET: ++ ((struct sockaddr_in *) ap)->sin_port = num; ++ break; ++ case AF_INET6: ++ ((struct sockaddr_in6 *) ap)->sin6_port = num; ++ break; ++ } ++} ++ ++ + /* rfc931 - return remote user name, given socket structures */ + + void rfc931(rmt_sin, our_sin, dest) +-#ifdef INET6 +-struct sockaddr *rmt_sin; +-struct sockaddr *our_sin; +-#else +-struct sockaddr_in *rmt_sin; +-struct sockaddr_in *our_sin; +-#endif ++struct sockaddr_storage *rmt_sin; ++struct sockaddr_storage *our_sin; + char *dest; + { + unsigned rmt_port; + unsigned our_port; +-#ifdef INET6 + struct sockaddr_storage rmt_query_sin; + struct sockaddr_storage our_query_sin; + int alen; +-#else +- struct sockaddr_in rmt_query_sin; +- struct sockaddr_in our_query_sin; +-#endif + char user[256]; /* XXX */ + char buffer[512]; /* XXX */ + char *cp; +@@ -97,18 +138,13 @@ char *dest; + + #ifdef INET6 + /* address family must be the same */ +- if (rmt_sin->sa_family != our_sin->sa_family) { ++ if (rmt_sin->ss_family != our_sin->ss_family) { + STRN_CPY(dest, result, STRING_LENGTH); + return; + } +- switch (our_sin->sa_family) { +- case AF_INET: +- alen = sizeof(struct sockaddr_in); +- break; +- case AF_INET6: +- alen = sizeof(struct sockaddr_in6); +- break; +- default: ++ ++ alen = sockaddr_len(our_sin); ++ if (alen == 0) { + STRN_CPY(dest, result, STRING_LENGTH); + return; + } +@@ -125,7 +161,7 @@ char *dest; + */ + + #ifdef INET6 +- if ((fp = fsocket(our_sin->sa_family, SOCK_STREAM, 0)) != 0) { ++ if ((fp = fsocket(our_sin->ss_family, SOCK_STREAM, 0)) != 0) { + #else + if ((fp = fsocket(AF_INET, SOCK_STREAM, 0)) != 0) { + #endif +@@ -154,18 +190,11 @@ char *dest; + */ + + #ifdef INET6 +- memcpy(&our_query_sin, our_sin, alen); +- memcpy(&rmt_query_sin, rmt_sin, alen); +- switch (our_sin->sa_family) { +- case AF_INET: +- ((struct sockaddr_in *)&our_query_sin)->sin_port = htons(ANY_PORT); +- ((struct sockaddr_in *)&rmt_query_sin)->sin_port = htons(RFC931_PORT); +- break; +- case AF_INET6: +- ((struct sockaddr_in6 *)&our_query_sin)->sin6_port = htons(ANY_PORT); +- ((struct sockaddr_in6 *)&rmt_query_sin)->sin6_port = htons(RFC931_PORT); +- break; +- } ++ our_query_sin = *our_sin; ++ sockaddr_set_port(&our_query_sin, ANY_PORT); ++ ++ rmt_query_sin = *rmt_sin; ++ sockaddr_set_port(&rmt_query_sin, RFC931_PORT); + + if (bind(fileno(fp), (struct sockaddr *) & our_query_sin, + alen) >= 0 && +@@ -191,8 +220,8 @@ char *dest; + + fprintf(fp, "%u,%u\r\n", + #ifdef INET6 +- ntohs(((struct sockaddr_in *)rmt_sin)->sin_port), +- ntohs(((struct sockaddr_in *)our_sin)->sin_port)); ++ sockaddr_port(rmt_sin), ++ sockaddr_port(our_sin)); + #else + ntohs(rmt_sin->sin_port), + ntohs(our_sin->sin_port)); +Index: tcp_wrappers_7.6/scaffold.c +=================================================================== +--- tcp_wrappers_7.6.orig/scaffold.c ++++ tcp_wrappers_7.6/scaffold.c +@@ -336,13 +336,8 @@ struct request_info *request; + /* ARGSUSED */ + + void rfc931(rmt_sin, our_sin, dest) +-#ifndef INET6 +-struct sockaddr_in *rmt_sin; +-struct sockaddr_in *our_sin; +-#else +-struct sockaddr *rmt_sin; +-struct sockaddr *our_sin; +-#endif ++struct sockaddr_storage *rmt_sin; ++struct sockaddr_storage *our_sin; + char *dest; + { + strcpy(dest, unknown); +Index: tcp_wrappers_7.6/tcpd.h +=================================================================== +--- tcp_wrappers_7.6.orig/tcpd.h ++++ tcp_wrappers_7.6/tcpd.h +@@ -19,11 +19,7 @@ + struct host_info { + char name[STRING_LENGTH]; /* access via eval_hostname(host) */ + char addr[STRING_LENGTH]; /* access via eval_hostaddr(host) */ +-#ifdef INET6 +- struct sockaddr *sin; /* socket address or 0 */ +-#else +- struct sockaddr_in *sin; /* socket address or 0 */ +-#endif ++ struct sockaddr_storage *sin; /* socket address or 0 */ + struct t_unitdata *unit; /* TLI transport address or 0 */ + struct request_info *request; /* for shared information */ + }; +@@ -86,7 +82,7 @@ extern void fromhost(); /* get/validat + extern int hosts_access(struct request_info *); + extern void shell_cmd(char *); + extern char *percent_x(char *, int, char *, struct request_info *); +-extern void rfc931(struct sockaddr *, struct sockaddr *, char *); ++extern void rfc931(struct sockaddr_storage *, struct sockaddr_storage *, char *); + extern void clean_exit(struct request_info *); + extern void refuse(struct request_info *); + extern char *xgets(char *, int, FILE *); +Index: tcp_wrappers_7.6/socket.c +=================================================================== +--- tcp_wrappers_7.6.orig/socket.c ++++ tcp_wrappers_7.6/socket.c +@@ -116,11 +116,7 @@ struct request_info *request; + memset(buf, 0 sizeof(buf)); + #endif + } +-#ifdef INET6 +- request->client->sin = (struct sockaddr *)&client; +-#else + request->client->sin = &client; +-#endif + + /* + * Determine the server binding. This is used for client username +@@ -133,11 +129,7 @@ struct request_info *request; + tcpd_warn("getsockname: %m"); + return; + } +-#ifdef INET6 +- request->server->sin = (struct sockaddr *)&server; +-#else + request->server->sin = &server; +-#endif + } + + +@@ -180,7 +172,7 @@ struct request_info *request; + sock_methods(request); + + memcpy(&client, res->ai_addr, res->ai_addrlen); +- request->client->sin = (struct sockaddr *)&client; ++ request->client->sin = &client; + freeaddrinfo(res); + + request->client->name[0] = 0; +@@ -193,7 +185,7 @@ void sock_hostaddr(host) + struct host_info *host; + { + #ifdef INET6 +- struct sockaddr *sin = host->sin; ++ struct sockaddr *sin = (struct sockaddr *) host->sin; + char *ap; + int alen; + +@@ -227,7 +219,7 @@ void + sock_hostname(struct host_info *host) + { + struct addrinfo hints, *res, *resbase; +- struct sockaddr *sa = host->sin; ++ struct sockaddr *sa = (struct sockaddr *) host->sin; + struct sockaddr_in6 *sin6, sin6buf; + int errcode; + +Index: tcp_wrappers_7.6/update.c +=================================================================== +--- tcp_wrappers_7.6.orig/update.c ++++ tcp_wrappers_7.6/update.c +@@ -48,14 +48,14 @@ va_list ap; + continue; + case RQ_CLIENT_SIN: + #ifdef INET6 +- request->client->sin = va_arg(ap, struct sockaddr *); ++ request->client->sin = va_arg(ap, struct sockaddr_storage *); + #else + request->client->sin = va_arg(ap, struct sockaddr_in *); + #endif + continue; + case RQ_SERVER_SIN: + #ifdef INET6 +- request->server->sin = va_arg(ap, struct sockaddr *); ++ request->server->sin = va_arg(ap, struct sockaddr_storage *); + #else + request->server->sin = va_arg(ap, struct sockaddr_in *); + #endif diff --git a/tcp_wrappers_7.6-ipv6-subnet.diff b/tcp_wrappers_7.6-ipv6-subnet.diff new file mode 100644 index 0000000..5ed6c4a --- /dev/null +++ b/tcp_wrappers_7.6-ipv6-subnet.diff @@ -0,0 +1,101 @@ +--- hosts_access.c 2014/10/11 17:16:13 1.57 ++++ hosts_access.c 2014/10/12 16:11:45 +@@ -367,41 +367,10 @@ + /* For simplicity we convert everything to IPv6 (or v4 mapped) */ + struct in6_addr pat, addr; + int len, ret, prefixlen=128, nof_periods = 0; +- char ch, token[INET6_ADDRSTRLEN+1], *mask, *ptok = tok, *addition; +- len = strlen(tok); +- if (tok[(n = strlen(tok)) - 1] == '.') { /* prefix */ +- while ((ptok = strchr(ptok, '.')) != NULL){ +- nof_periods++; +- ptok++; +- } +- switch(nof_periods){ +- case 1: +- addition = "0.0.0/8"; +- break; +- case 2: +- addition = "0.0/16"; +- break; +- case 3: +- addition = "0/24"; +- break; +- default: +- tcpd_warn ("Wrong prefix %s", tok); +- return (NO); +- } +- snprintf(token, sizeof(token), "%s%s", tok, addition); +- } +- else if (*tok == '[' && tok[len - 1] == ']') +- { +- ch = tok[len - 1]; +- tok[len - 1] = '\0'; +- snprintf(token, sizeof(token), "%s", tok+1); +- tok[len - 1] = ch; +- } +- else +- snprintf(token, sizeof(token), "%s", tok); +- ++ char ch, token[INET6_ADDRSTRLEN+1], *mask, *addition; ++ + /* If prefix was given, handle it */ +- if ((mask = split_at(token, '/')) != 0) ++ if ((mask = split_at(tok, '/')) != 0) + { + if (strchr(mask, '.') != NULL) /* We have something + like 255.255.0.0 */ +@@ -428,7 +397,7 @@ + return (NO); + } + +- if (is_v4_string (token)) ++ if (is_v4_string (tok)) + prefixlen += 96; /* extend to v4mapped */ + + if (prefixlen > 128) +@@ -437,6 +406,44 @@ + return (NO); + } + } ++ ++ len = strlen(tok); ++ if (tok[len - 1] == '.') { /* prefix */ ++ char *ptok = tok; ++ ++ while ((ptok = strchr(ptok, '.')) != NULL){ ++ nof_periods++; ++ ptok++; ++ } ++ switch(nof_periods){ ++ case 1: ++ addition = "0.0.0"; ++ prefixlen = 8; ++ break; ++ case 2: ++ addition = "0.0"; ++ prefixlen = 16; ++ break; ++ case 3: ++ addition = "0"; ++ prefixlen = 24; ++ break; ++ default: ++ tcpd_warn ("Wrong prefix %s", tok); ++ return (NO); ++ } ++ snprintf(token, sizeof(token), "%s%s", tok, addition); ++ prefixlen += 96; /* extend to v4mapped */ ++ } ++ else if (*tok == '[' && tok[len - 1] == ']') ++ { ++ ch = tok[len - 1]; ++ tok[len - 1] = '\0'; ++ snprintf(token, sizeof(token), "%s", tok+1); ++ tok[len - 1] = ch; ++ } ++ else ++ snprintf(token, sizeof(token), "%s", tok); + + memset (&pat, 0, sizeof(pat)); + memset (&addr, 0, sizeof(addr)); diff --git a/tcpd.changes b/tcpd.changes index 0827e8d..e5f034b 100644 --- a/tcpd.changes +++ b/tcpd.changes @@ -1,3 +1,14 @@ +------------------------------------------------------------------- +Mon Jul 20 14:08:16 UTC 2015 - okir@suse.com + +- Fix breakage of IPv6 address handling [bsc#914527, bsc#899185] + Added patches: + tcp_wrappers_7.6-ipv6-sockaddr-storage.patch + tcp_wrappers_7.6-ipv6-subnet.diff + tcp_wrappers_7.6-ipv6-host-match.patch + tcp_wrappers_7.6-ipv6-mapped-v4.patch +- Re-added static library + ------------------------------------------------------------------- Fri Nov 28 13:18:37 UTC 2014 - tchvatal@suse.com diff --git a/tcpd.spec b/tcpd.spec index f2a3fac..8f9d871 100644 --- a/tcpd.spec +++ b/tcpd.spec @@ -1,7 +1,7 @@ # # spec file for package tcpd # -# Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2015 SUSE LINUX Products GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,6 +17,7 @@ %define lname libwrap0 + Name: tcpd Version: 7.6 Release: 0 @@ -56,8 +57,16 @@ Patch26: tcp_wrappers_%{version}-fedora-bug17795.diff Patch27: tcp_wrappers_%{version}-fedora-bug17847.diff Patch28: tcp_wrappers_7.6-implicit-decl.patch Patch29: tcpd-ocloexec.patch +Patch30: tcp_wrappers_%{version}-ipv6-sockaddr-storage.patch +Patch31: tcp_wrappers_%{version}-ipv6-subnet.diff +Patch32: tcp_wrappers_%{version}-ipv6-host-match.patch +Patch33: tcp_wrappers_%{version}-ipv6-mapped-v4.patch BuildRequires: linux-kernel-headers Provides: nkitb:%{_sbindir}/tcpd +# bug437293 +%ifarch ppc64 +Obsoletes: tcpd-64bit +%endif BuildRoot: %{_tmppath}/%{name}-%{version}-build %description @@ -78,6 +87,11 @@ Summary: Include Files and Libraries for the TCP wrapper library Group: Development/Languages/C and C++ Requires: %{lname} = %{version} Requires: glibc-devel +# bug437293 +%ifarch ppc64 +Obsoletes: tcpd-devel-64bit +%endif +# %description devel This package contains the library and header files, which are necessary @@ -115,9 +129,13 @@ to compile and link programs against the TCP wrapper library. %patch27 %patch28 %patch29 +%patch30 -p1 +%patch31 +%patch32 -p1 +%patch33 -p1 %build -make %{?_smp_mflags} linux CC=cc +make %{?_smp_mflags} linux CC="cc" %install install -d -m 755 %{buildroot}%{_includedir} @@ -126,6 +144,7 @@ install -d -m 755 %{buildroot}%{_sbindir} install -d -m 755 %{buildroot}%{_mandir}/man{1,3,5,8} install -d -m 755 %{buildroot}/%{_lib} install -m 644 ip6utils.h tcpd.h %{buildroot}%{_includedir} +install -m 644 libwrap.a %{buildroot}/%{_libdir} install -m 755 safe_finger tcpd tcpdchk tcpdmatch try-from %{buildroot}%{_sbindir} install -m 644 hosts_access.3 %{buildroot}%{_mandir}/man3 install -m 644 hosts_access.5 hosts_options.5 %{buildroot}%{_mandir}/man5 @@ -141,7 +160,7 @@ ln -sf /%{_lib}/libwrap.so.0.%{version} libwrap.so %postun -n %{lname} -p /sbin/ldconfig %files -%defattr(-,root,root) +%defattr(644,root,root,755) %doc BLURB CHANGES DISCLAIMER README README.ipv6 README.NIS %doc %{_mandir}/man?/* %attr(755,root,root) %{_sbindir}/* @@ -152,9 +171,10 @@ ln -sf /%{_lib}/libwrap.so.0.%{version} libwrap.so %attr(755,root,root) /%{_lib}/libwrap.so.0* %files devel -%defattr(-,root,root) +%defattr(644,root,root,755) %{_includedir}/tcpd.h %{_includedir}/ip6utils.h +%{_libdir}/libwrap.a %{_libdir}/libwrap.so %changelog