- fix uri list locking (again). - check for stale SASL credentials upon connect fail. - add "forcestart" and "forcerestart" init script options to allow use of 5.0.3 strartup behavior if required. - always read entire file map into cache to speed lookups. - make MAX_ERR_BUF and PARSE_MAX_BUF use easier to audit. - make some easy alloca replacements. - update to configure libtirpc if present. - update to provide ipv6 name and address support. - update to provide ipv6 address parsing.
1019 lines
24 KiB
Diff
1019 lines
24 KiB
Diff
autofs-5.0.4 - ipv6 name and address support
|
|
|
|
From: Ian Kent <raven@themaw.net>
|
|
|
|
For ipv6 we need to convert all ipv4 specific function calls to ipv6
|
|
compatible function calls and update the rpc code to deal with ipv6
|
|
addresses. The host proximity calculation also needes to be updated.
|
|
|
|
I'm sure this isn't completely correct yet and it will need more work
|
|
as I become more familiar with how ipv6 and subneting with it is used.
|
|
The changes so far function correctly for the current autofs
|
|
connectathon test suite maps so I hope there aren't any regressions
|
|
with current map configurations.
|
|
---
|
|
|
|
CHANGELOG | 1
|
|
include/replicated.h | 2
|
|
include/rpc_subs.h | 4
|
|
lib/rpc_subs.c | 486 +++++++++++++++++++++++++++++++++------------------
|
|
modules/cyrus-sasl.c | 17 +
|
|
modules/replicated.c | 235 +++++++++++++++++-------
|
|
6 files changed, 501 insertions(+), 244 deletions(-)
|
|
|
|
|
|
--- autofs-5.0.4.orig/include/replicated.h
|
|
+++ autofs-5.0.4/include/replicated.h
|
|
@@ -51,7 +51,7 @@
|
|
|
|
struct host {
|
|
char *name;
|
|
- char *addr;
|
|
+ struct sockaddr *addr;
|
|
size_t addr_len;
|
|
char *path;
|
|
unsigned int version;
|
|
--- autofs-5.0.4.orig/include/rpc_subs.h
|
|
+++ autofs-5.0.4/include/rpc_subs.h
|
|
@@ -46,7 +46,7 @@
|
|
|
|
struct conn_info {
|
|
const char *host;
|
|
- const char *addr;
|
|
+ struct sockaddr *addr;
|
|
size_t addr_len;
|
|
unsigned short port;
|
|
unsigned long program;
|
|
@@ -63,7 +63,7 @@ int rpc_udp_getclient(struct conn_info *
|
|
void rpc_destroy_udp_client(struct conn_info *);
|
|
int rpc_tcp_getclient(struct conn_info *, unsigned int, unsigned int);
|
|
void rpc_destroy_tcp_client(struct conn_info *);
|
|
-int rpc_portmap_getclient(struct conn_info *, const char *, const char *, size_t, const char *, unsigned int);
|
|
+int rpc_portmap_getclient(struct conn_info *, const char *, struct sockaddr *, size_t, const char *, unsigned int);
|
|
unsigned short rpc_portmap_getport(struct conn_info *, struct pmap *);
|
|
int rpc_ping_proto(struct conn_info *);
|
|
int rpc_ping(const char *, long, long, unsigned int);
|
|
--- autofs-5.0.4.orig/lib/rpc_subs.c
|
|
+++ autofs-5.0.4/lib/rpc_subs.c
|
|
@@ -17,10 +17,11 @@
|
|
#define _GNU_SOURCE
|
|
#endif
|
|
|
|
+#include "config.h"
|
|
+
|
|
#include <rpc/types.h>
|
|
#include <rpc/rpc.h>
|
|
#include <rpc/pmap_prot.h>
|
|
-
|
|
#include <sys/socket.h>
|
|
#include <netdb.h>
|
|
#include <net/if.h>
|
|
@@ -54,145 +55,76 @@
|
|
|
|
inline void dump_core(void);
|
|
|
|
-/*
|
|
- * Create a UDP RPC client
|
|
- */
|
|
-static CLIENT *create_udp_client(struct conn_info *info)
|
|
+static CLIENT *rpc_clntudp_create(struct sockaddr *addr, struct conn_info *info, int *fd)
|
|
{
|
|
- int fd, ret, ghn_errno;
|
|
- CLIENT *client;
|
|
- struct sockaddr_in laddr, raddr;
|
|
- struct hostent hp;
|
|
- struct hostent *php = &hp;
|
|
- struct hostent *result;
|
|
- char buf[HOST_ENT_BUF_SIZE];
|
|
- size_t len;
|
|
-
|
|
- if (info->proto->p_proto != IPPROTO_UDP)
|
|
- return NULL;
|
|
-
|
|
- if (info->client) {
|
|
- if (!clnt_control(info->client, CLGET_FD, (char *) &fd)) {
|
|
- fd = -1;
|
|
- clnt_destroy(info->client);
|
|
- info->client = NULL;
|
|
- } else {
|
|
- clnt_control(info->client, CLSET_FD_NCLOSE, NULL);
|
|
- clnt_destroy(info->client);
|
|
- }
|
|
- }
|
|
-
|
|
- memset(&laddr, 0, sizeof(laddr));
|
|
- memset(&raddr, 0, sizeof(raddr));
|
|
-
|
|
- raddr.sin_family = AF_INET;
|
|
- if (info->addr) {
|
|
- memcpy(&raddr.sin_addr.s_addr, info->addr, info->addr_len);
|
|
- goto got_addr;
|
|
- }
|
|
-
|
|
- if (inet_aton(info->host, &raddr.sin_addr))
|
|
- goto got_addr;
|
|
-
|
|
- memset(&hp, 0, sizeof(struct hostent));
|
|
-
|
|
- ret = gethostbyname_r(info->host, php,
|
|
- buf, HOST_ENT_BUF_SIZE, &result, &ghn_errno);
|
|
- if (ret || !result) {
|
|
- int err = ghn_errno == -1 ? errno : ghn_errno;
|
|
- char *estr = strerror_r(err, buf, HOST_ENT_BUF_SIZE);
|
|
- logerr("hostname lookup failed: %s", estr);
|
|
- goto out_close;
|
|
- }
|
|
- memcpy(&raddr.sin_addr.s_addr, php->h_addr, php->h_length);
|
|
-
|
|
-got_addr:
|
|
- raddr.sin_port = htons(info->port);
|
|
-
|
|
- if (!info->client) {
|
|
- /*
|
|
- * bind to any unused port. If we left this up to the rpc
|
|
- * layer, it would bind to a reserved port, which has been shown
|
|
- * to exhaust the reserved port range in some situations.
|
|
- */
|
|
- fd = open_sock(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
|
- if (fd < 0)
|
|
- return NULL;
|
|
-
|
|
- laddr.sin_family = AF_INET;
|
|
- laddr.sin_port = 0;
|
|
- laddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
-
|
|
- len = sizeof(struct sockaddr_in);
|
|
- if (bind(fd, (struct sockaddr *)&laddr, len) < 0) {
|
|
- close(fd);
|
|
- fd = RPC_ANYSOCK;
|
|
- /* FALLTHROUGH */
|
|
- }
|
|
- }
|
|
-
|
|
- client = clntudp_bufcreate(&raddr,
|
|
- info->program, info->version,
|
|
- info->timeout, &fd,
|
|
- info->send_sz, info->recv_sz);
|
|
+ struct sockaddr_in *in4_raddr;
|
|
+ struct sockaddr_in6 *in6_raddr;
|
|
+ CLIENT *client = NULL;
|
|
+
|
|
+ switch (addr->sa_family) {
|
|
+ case AF_INET:
|
|
+ in4_raddr = (struct sockaddr_in *) addr;
|
|
+ in4_raddr->sin_port = htons(info->port);
|
|
+ client = clntudp_bufcreate(in4_raddr,
|
|
+ info->program, info->version,
|
|
+ info->timeout, fd,
|
|
+ info->send_sz, info->recv_sz);
|
|
+ break;
|
|
|
|
- if (!client) {
|
|
- info->client = NULL;
|
|
- goto out_close;
|
|
- }
|
|
+ case AF_INET6:
|
|
+#ifndef INET6
|
|
+ /* Quiet compile warning */
|
|
+ in6_raddr = NULL;
|
|
+#else
|
|
+ in6_raddr = (struct sockaddr_in6 *) addr;
|
|
+ in6_raddr->sin6_port = htons(info->port);
|
|
+ client = clntudp6_bufcreate(in6_raddr,
|
|
+ info->program, info->version,
|
|
+ info->timeout, fd,
|
|
+ info->send_sz, info->recv_sz);
|
|
+#endif
|
|
+ break;
|
|
|
|
- /* Close socket fd on destroy, as is default for rpcowned fds */
|
|
- if (!clnt_control(client, CLSET_FD_CLOSE, NULL)) {
|
|
- clnt_destroy(client);
|
|
- info->client = NULL;
|
|
- goto out_close;
|
|
+ default:
|
|
+ break;
|
|
}
|
|
|
|
return client;
|
|
-
|
|
-out_close:
|
|
- if (fd != -1)
|
|
- close(fd);
|
|
- return NULL;
|
|
}
|
|
|
|
-int rpc_udp_getclient(struct conn_info *info,
|
|
- unsigned int program, unsigned int version)
|
|
+static CLIENT *rpc_clnttcp_create(struct sockaddr *addr, struct conn_info *info, int *fd)
|
|
{
|
|
- struct protoent *pe_proto;
|
|
- CLIENT *client;
|
|
+ struct sockaddr_in *in4_raddr;
|
|
+ struct sockaddr_in6 *in6_raddr;
|
|
+ CLIENT *client = NULL;
|
|
+
|
|
+ switch (addr->sa_family) {
|
|
+ case AF_INET:
|
|
+ in4_raddr = (struct sockaddr_in *) addr;
|
|
+ in4_raddr->sin_port = htons(info->port);
|
|
+ client = clnttcp_create(in4_raddr,
|
|
+ info->program, info->version, fd,
|
|
+ info->send_sz, info->recv_sz);
|
|
+ break;
|
|
|
|
- if (!info->client) {
|
|
- pe_proto = getprotobyname("udp");
|
|
- if (!pe_proto)
|
|
- return 0;
|
|
+ case AF_INET6:
|
|
+#ifndef INET6
|
|
+ /* Quiet compile warning */
|
|
+ in6_raddr = NULL;
|
|
+#else
|
|
+ in6_raddr = (struct sockaddr_in6 *) addr;
|
|
+ in6_raddr->sin6_port = htons(info->port);
|
|
+ client = clnttcp6_create(in6_raddr,
|
|
+ info->program, info->version, fd,
|
|
+ info->send_sz, info->recv_sz);
|
|
+#endif
|
|
+ break;
|
|
|
|
- info->proto = pe_proto;
|
|
- info->send_sz = UDPMSGSIZE;
|
|
- info->recv_sz = UDPMSGSIZE;
|
|
+ default:
|
|
+ break;
|
|
}
|
|
|
|
- info->program = program;
|
|
- info->version = version;
|
|
-
|
|
- client = create_udp_client(info);
|
|
-
|
|
- if (!client)
|
|
- return 0;
|
|
-
|
|
- info->client = client;
|
|
-
|
|
- return 1;
|
|
-}
|
|
-
|
|
-void rpc_destroy_udp_client(struct conn_info *info)
|
|
-{
|
|
- if (!info->client)
|
|
- return;
|
|
-
|
|
- clnt_destroy(info->client);
|
|
- info->client = NULL;
|
|
- return;
|
|
+ return client;
|
|
}
|
|
|
|
/*
|
|
@@ -201,12 +133,11 @@ void rpc_destroy_udp_client(struct conn_
|
|
* The input struct timeval always has tv_nsec set to zero,
|
|
* we only ever use tv_sec for timeouts.
|
|
*/
|
|
-static int connect_nb(int fd, struct sockaddr_in *addr, struct timeval *tout)
|
|
+static int connect_nb(int fd, struct sockaddr *addr, socklen_t len, struct timeval *tout)
|
|
{
|
|
struct pollfd pfd[1];
|
|
int timeout = tout->tv_sec;
|
|
int flags, ret;
|
|
- socklen_t len;
|
|
|
|
flags = fcntl(fd, F_GETFL, 0);
|
|
if (flags < 0)
|
|
@@ -221,8 +152,7 @@ static int connect_nb(int fd, struct soc
|
|
* we set ret = -errno to capture it in case we decide to
|
|
* use it later.
|
|
*/
|
|
- len = sizeof(struct sockaddr);
|
|
- ret = connect(fd, (struct sockaddr *)addr, len);
|
|
+ ret = connect(fd, addr, len);
|
|
if (ret < 0 && errno != EINPROGRESS) {
|
|
ret = -errno;
|
|
goto done;
|
|
@@ -277,26 +207,117 @@ done:
|
|
return ret;
|
|
}
|
|
|
|
+static CLIENT *rpc_do_create_client(struct sockaddr *addr, struct conn_info *info, int *fd)
|
|
+{
|
|
+ CLIENT *client = NULL;
|
|
+ struct sockaddr *laddr;
|
|
+ struct sockaddr_in in4_laddr;
|
|
+ struct sockaddr_in6 in6_laddr;
|
|
+ int type, proto;
|
|
+ socklen_t slen;
|
|
+
|
|
+ proto = info->proto->p_proto;
|
|
+ if (proto == IPPROTO_UDP)
|
|
+ type = SOCK_DGRAM;
|
|
+ else
|
|
+ type = SOCK_STREAM;
|
|
+
|
|
+ /*
|
|
+ * bind to any unused port. If we left this up to the rpc
|
|
+ * layer, it would bind to a reserved port, which has been shown
|
|
+ * to exhaust the reserved port range in some situations.
|
|
+ */
|
|
+ switch (addr->sa_family) {
|
|
+ case AF_INET:
|
|
+ in4_laddr.sin_family = AF_INET;
|
|
+ in4_laddr.sin_port = htons(0);
|
|
+ in4_laddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
+ slen = sizeof(struct sockaddr_in);
|
|
+ laddr = (struct sockaddr *) &in4_laddr;
|
|
+ break;
|
|
+
|
|
+ case AF_INET6:
|
|
+#ifndef INET6
|
|
+ /* Quiet compiler */
|
|
+ in6_laddr.sin6_family = AF_INET6;
|
|
+ return NULL;
|
|
+#else
|
|
+ in6_laddr.sin6_family = AF_INET6;
|
|
+ in6_laddr.sin6_port = htons(0);
|
|
+ in6_laddr.sin6_addr = in6addr_any;
|
|
+ slen = sizeof(struct sockaddr_in6);
|
|
+ laddr = (struct sockaddr *) &in6_laddr;
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (!info->client) {
|
|
+ *fd = open_sock(addr->sa_family, type, proto);
|
|
+ if (*fd < 0)
|
|
+ return NULL;
|
|
+
|
|
+ if (bind(*fd, laddr, slen) < 0) {
|
|
+ close(*fd);
|
|
+ return NULL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ switch (info->proto->p_proto) {
|
|
+ case IPPROTO_UDP:
|
|
+ if (!info->client) {
|
|
+ *fd = open_sock(addr->sa_family, type, proto);
|
|
+ if (*fd < 0)
|
|
+ return NULL;
|
|
+
|
|
+ if (bind(*fd, laddr, slen) < 0) {
|
|
+ close(*fd);
|
|
+ return NULL;
|
|
+ }
|
|
+ }
|
|
+ client = rpc_clntudp_create(addr, info, fd);
|
|
+ break;
|
|
+
|
|
+ case IPPROTO_TCP:
|
|
+ if (!info->client) {
|
|
+ *fd = open_sock(addr->sa_family, type, proto);
|
|
+ if (*fd < 0)
|
|
+ return NULL;
|
|
+
|
|
+ if (connect_nb(*fd, laddr, slen, &info->timeout) < 0) {
|
|
+ close(*fd);
|
|
+ return NULL;
|
|
+ }
|
|
+ }
|
|
+ client = rpc_clnttcp_create(addr, info, fd);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return client;
|
|
+}
|
|
+
|
|
/*
|
|
- * Create a TCP RPC client using non-blocking connect
|
|
+ * Create a UDP RPC client
|
|
*/
|
|
-static CLIENT *create_tcp_client(struct conn_info *info)
|
|
+static CLIENT *create_udp_client(struct conn_info *info)
|
|
{
|
|
- int fd, ghn_errno;
|
|
- CLIENT *client;
|
|
- struct sockaddr_in addr;
|
|
- struct hostent hp;
|
|
- struct hostent *php = &hp;
|
|
- struct hostent *result;
|
|
- char buf[HOST_ENT_BUF_SIZE];
|
|
- int ret;
|
|
+ CLIENT *client = NULL;
|
|
+ struct addrinfo *ai, *haddr;
|
|
+ struct addrinfo hints;
|
|
+ int fd, ret;
|
|
|
|
- if (info->proto->p_proto != IPPROTO_TCP)
|
|
+ if (info->proto->p_proto != IPPROTO_UDP)
|
|
return NULL;
|
|
|
|
+ fd = RPC_ANYSOCK;
|
|
+
|
|
if (info->client) {
|
|
if (!clnt_control(info->client, CLGET_FD, (char *) &fd)) {
|
|
- fd = -1;
|
|
+ fd = RPC_ANYSOCK;
|
|
clnt_destroy(info->client);
|
|
info->client = NULL;
|
|
} else {
|
|
@@ -305,51 +326,174 @@ static CLIENT *create_tcp_client(struct
|
|
}
|
|
}
|
|
|
|
- memset(&addr, 0, sizeof(addr));
|
|
-
|
|
- addr.sin_family = AF_INET;
|
|
if (info->addr) {
|
|
- memcpy(&addr.sin_addr.s_addr, info->addr, info->addr_len);
|
|
- goto got_addr;
|
|
+ client = rpc_do_create_client(info->addr, info, &fd);
|
|
+ if (client)
|
|
+ goto done;
|
|
+
|
|
+ if (!info->client) {
|
|
+ close(fd);
|
|
+ fd = RPC_ANYSOCK;
|
|
+ }
|
|
}
|
|
|
|
- if (inet_aton(info->host, &addr.sin_addr))
|
|
- goto got_addr;
|
|
+ memset(&hints, 0, sizeof(hints));
|
|
+ hints.ai_flags = AI_ADDRCONFIG;
|
|
+ hints.ai_family = AF_UNSPEC;
|
|
+ hints.ai_socktype = SOCK_DGRAM;
|
|
+
|
|
+ ret = getaddrinfo(info->host, NULL, &hints, &ai);
|
|
+ if (ret) {
|
|
+ error(LOGOPT_ANY,
|
|
+ "hostname lookup failed: %s", gai_strerror(ret));
|
|
+ goto out_close;
|
|
+ }
|
|
+
|
|
+ haddr = ai;
|
|
+ while (haddr) {
|
|
+ client = rpc_do_create_client(haddr->ai_addr, info, &fd);
|
|
+ if (client)
|
|
+ break;
|
|
+
|
|
+ if (!info->client) {
|
|
+ close(fd);
|
|
+ fd = RPC_ANYSOCK;
|
|
+ }
|
|
+
|
|
+ haddr = haddr->ai_next;
|
|
+ }
|
|
|
|
- memset(&hp, 0, sizeof(struct hostent));
|
|
+ freeaddrinfo(ai);
|
|
|
|
- ret = gethostbyname_r(info->host, php,
|
|
- buf, HOST_ENT_BUF_SIZE, &result, &ghn_errno);
|
|
- if (ret || !result) {
|
|
- int err = ghn_errno == -1 ? errno : ghn_errno;
|
|
- char *estr = strerror_r(err, buf, HOST_ENT_BUF_SIZE);
|
|
- logerr("hostname lookup failed: %s", estr);
|
|
+ if (!client) {
|
|
+ info->client = NULL;
|
|
+ goto out_close;
|
|
+ }
|
|
+done:
|
|
+ /* Close socket fd on destroy, as is default for rpcowned fds */
|
|
+ if (!clnt_control(client, CLSET_FD_CLOSE, NULL)) {
|
|
+ clnt_destroy(client);
|
|
+ info->client = NULL;
|
|
goto out_close;
|
|
}
|
|
- memcpy(&addr.sin_addr.s_addr, php->h_addr, php->h_length);
|
|
|
|
-got_addr:
|
|
- addr.sin_port = htons(info->port);
|
|
+ return client;
|
|
+
|
|
+out_close:
|
|
+ if (fd != -1)
|
|
+ close(fd);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+int rpc_udp_getclient(struct conn_info *info,
|
|
+ unsigned int program, unsigned int version)
|
|
+{
|
|
+ struct protoent *pe_proto;
|
|
+ CLIENT *client;
|
|
|
|
if (!info->client) {
|
|
- fd = open_sock(PF_INET, SOCK_STREAM, info->proto->p_proto);
|
|
- if (fd < 0)
|
|
- return NULL;
|
|
+ pe_proto = getprotobyname("udp");
|
|
+ if (!pe_proto)
|
|
+ return 0;
|
|
+
|
|
+ info->proto = pe_proto;
|
|
+ info->send_sz = UDPMSGSIZE;
|
|
+ info->recv_sz = UDPMSGSIZE;
|
|
+ }
|
|
+
|
|
+ info->program = program;
|
|
+ info->version = version;
|
|
+
|
|
+ client = create_udp_client(info);
|
|
+
|
|
+ if (!client)
|
|
+ return 0;
|
|
+
|
|
+ info->client = client;
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+void rpc_destroy_udp_client(struct conn_info *info)
|
|
+{
|
|
+ if (!info->client)
|
|
+ return;
|
|
+
|
|
+ clnt_destroy(info->client);
|
|
+ info->client = NULL;
|
|
+ return;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Create a TCP RPC client using non-blocking connect
|
|
+ */
|
|
+static CLIENT *create_tcp_client(struct conn_info *info)
|
|
+{
|
|
+ CLIENT *client = NULL;
|
|
+ struct addrinfo *ai, *haddr;
|
|
+ struct addrinfo hints;
|
|
+ int fd, ret;
|
|
+
|
|
+ if (info->proto->p_proto != IPPROTO_TCP)
|
|
+ return NULL;
|
|
+
|
|
+ fd = RPC_ANYSOCK;
|
|
+
|
|
+ if (info->client) {
|
|
+ if (!clnt_control(info->client, CLGET_FD, (char *) &fd)) {
|
|
+ fd = RPC_ANYSOCK;
|
|
+ clnt_destroy(info->client);
|
|
+ info->client = NULL;
|
|
+ } else {
|
|
+ clnt_control(info->client, CLSET_FD_NCLOSE, NULL);
|
|
+ clnt_destroy(info->client);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (info->addr) {
|
|
+ client = rpc_do_create_client(info->addr, info, &fd);
|
|
+ if (client)
|
|
+ goto done;
|
|
|
|
- ret = connect_nb(fd, &addr, &info->timeout);
|
|
- if (ret < 0)
|
|
- goto out_close;
|
|
+ if (!info->client) {
|
|
+ close(fd);
|
|
+ fd = RPC_ANYSOCK;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ memset(&hints, 0, sizeof(hints));
|
|
+ hints.ai_flags = AI_ADDRCONFIG;
|
|
+ hints.ai_family = AF_UNSPEC;
|
|
+ hints.ai_socktype = SOCK_STREAM;
|
|
+
|
|
+ ret = getaddrinfo(info->host, NULL, &hints, &ai);
|
|
+ if (ret) {
|
|
+ error(LOGOPT_ANY,
|
|
+ "hostname lookup failed: %s", gai_strerror(ret));
|
|
+ goto out_close;
|
|
+ }
|
|
+
|
|
+ haddr = ai;
|
|
+ while (haddr) {
|
|
+ client = rpc_do_create_client(haddr->ai_addr, info, &fd);
|
|
+ if (client)
|
|
+ break;
|
|
+
|
|
+ if (!info->client) {
|
|
+ close(fd);
|
|
+ fd = RPC_ANYSOCK;
|
|
+ }
|
|
+
|
|
+ haddr = haddr->ai_next;
|
|
}
|
|
|
|
- client = clnttcp_create(&addr,
|
|
- info->program, info->version, &fd,
|
|
- info->send_sz, info->recv_sz);
|
|
+ freeaddrinfo(ai);
|
|
|
|
if (!client) {
|
|
info->client = NULL;
|
|
goto out_close;
|
|
}
|
|
-
|
|
+done:
|
|
/* Close socket fd on destroy, as is default for rpcowned fds */
|
|
if (!clnt_control(client, CLSET_FD_CLOSE, NULL)) {
|
|
clnt_destroy(client);
|
|
@@ -420,7 +564,7 @@ void rpc_destroy_tcp_client(struct conn_
|
|
}
|
|
|
|
int rpc_portmap_getclient(struct conn_info *info,
|
|
- const char *host, const char *addr, size_t addr_len,
|
|
+ const char *host, struct sockaddr *addr, size_t addr_len,
|
|
const char *proto, unsigned int option)
|
|
{
|
|
struct protoent *pe_proto;
|
|
--- autofs-5.0.4.orig/modules/cyrus-sasl.c
|
|
+++ autofs-5.0.4/modules/cyrus-sasl.c
|
|
@@ -732,16 +732,25 @@ sasl_bind_mech(unsigned logopt, LDAP *ld
|
|
debug(logopt, "Attempting sasl bind with mechanism %s", mech);
|
|
|
|
result = ldap_get_option(ldap, LDAP_OPT_HOST_NAME, &host);
|
|
- if (result != LDAP_SUCCESS || !host) {
|
|
+ if (result != LDAP_OPT_SUCCESS || !host) {
|
|
debug(logopt, "failed to get hostname for connection");
|
|
return NULL;
|
|
}
|
|
|
|
- if ((tmp = strchr(host, ':')))
|
|
- *tmp = '\0';
|
|
+ if ((tmp = strrchr(host, ':'))) {
|
|
+ if (*(tmp - 1) != ']') {
|
|
+ *tmp = '\0';
|
|
+ tmp = host;
|
|
+ } else {
|
|
+ *(tmp - 1) = '\0';
|
|
+ tmp = host;
|
|
+ if (*tmp == '[')
|
|
+ tmp++;
|
|
+ }
|
|
+ }
|
|
|
|
/* Create a new authentication context for the service. */
|
|
- result = sasl_client_new("ldap", host, NULL, NULL, NULL, 0, &conn);
|
|
+ result = sasl_client_new("ldap", tmp, NULL, NULL, NULL, 0, &conn);
|
|
if (result != SASL_OK) {
|
|
error(logopt, "sasl_client_new failed with error %d",
|
|
result);
|
|
--- autofs-5.0.4.orig/modules/replicated.c
|
|
+++ autofs-5.0.4/modules/replicated.c
|
|
@@ -45,7 +45,7 @@
|
|
#include <stdlib.h>
|
|
#include <sys/errno.h>
|
|
#include <sys/types.h>
|
|
-#include <netinet/in.h>
|
|
+#include <stdint.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/socket.h>
|
|
#include <arpa/inet.h>
|
|
@@ -75,6 +75,20 @@ static int volatile ifc_last_len = 0;
|
|
#define max(x, y) (x >= y ? x : y)
|
|
#define mmax(x, y, z) (max(x, y) == x ? max(x, z) : max(y, z))
|
|
|
|
+unsigned int ipv6_mask_cmp(uint32_t *host, uint32_t *iface, uint32_t *mask)
|
|
+{
|
|
+ unsigned int ret = 1;
|
|
+ unsigned int i;
|
|
+
|
|
+ for (i = 0; i < 4; i++) {
|
|
+ if ((host[i] & mask[i]) != (iface[i] & mask[i])) {
|
|
+ ret = 0;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ return ret;
|
|
+}
|
|
+
|
|
void seed_random(void)
|
|
{
|
|
int fd;
|
|
@@ -136,20 +150,49 @@ static int alloc_ifreq(struct ifconf *if
|
|
return 1;
|
|
}
|
|
|
|
-static unsigned int get_proximity(const char *host_addr, int addr_len)
|
|
+static unsigned int get_proximity(struct sockaddr *host_addr)
|
|
{
|
|
- struct sockaddr_in *msk_addr, *if_addr;
|
|
+ struct sockaddr_in *addr, *msk_addr, *if_addr;
|
|
+ struct sockaddr_in6 *addr6, *msk6_addr, *if6_addr;
|
|
struct in_addr *hst_addr;
|
|
- char tmp[20], buf[MAX_ERR_BUF], *ptr;
|
|
+ struct in6_addr *hst6_addr;
|
|
+ int addr_len;
|
|
+ char buf[MAX_ERR_BUF], *ptr;
|
|
struct ifconf ifc;
|
|
struct ifreq *ifr, nmptr;
|
|
int sock, ret, i;
|
|
- uint32_t mask, ha, ia;
|
|
+ uint32_t mask, ha, ia, *mask6, *ha6, *ia6;
|
|
|
|
- memcpy(tmp, host_addr, addr_len);
|
|
- hst_addr = (struct in_addr *) tmp;
|
|
+ addr = NULL;
|
|
+ addr6 = NULL;
|
|
+ hst_addr = NULL;
|
|
+ hst6_addr = NULL;
|
|
+ mask6 = NULL;
|
|
+ ha6 = NULL;
|
|
+ ia6 = NULL;
|
|
+
|
|
+ switch (host_addr->sa_family) {
|
|
+ case AF_INET:
|
|
+ addr = (struct sockaddr_in *) host_addr;
|
|
+ hst_addr = (struct in_addr *) &addr->sin_addr;
|
|
+ ha = ntohl((uint32_t) hst_addr->s_addr);
|
|
+ addr_len = sizeof(hst_addr);
|
|
+ break;
|
|
|
|
- ha = ntohl((uint32_t) hst_addr->s_addr);
|
|
+ case AF_INET6:
|
|
+#ifndef INET6
|
|
+ return PROXIMITY_ERROR;
|
|
+#else
|
|
+ addr6 = (struct sockaddr_in6 *) host_addr;
|
|
+ hst6_addr = (struct in6_addr *) &addr6->sin6_addr;
|
|
+ ha6 = &hst6_addr->s6_addr32[0];
|
|
+ addr_len = sizeof(hst6_addr);
|
|
+ break;
|
|
+#endif
|
|
+
|
|
+ default:
|
|
+ return PROXIMITY_ERROR;
|
|
+ }
|
|
|
|
sock = open_sock(AF_INET, SOCK_DGRAM, 0);
|
|
if (sock < 0) {
|
|
@@ -174,6 +217,10 @@ static unsigned int get_proximity(const
|
|
|
|
switch (ifr->ifr_addr.sa_family) {
|
|
case AF_INET:
|
|
+#ifndef INET6
|
|
+ if (host_addr->sa_family == AF_INET6)
|
|
+ break;
|
|
+#endif
|
|
if_addr = (struct sockaddr_in *) &ifr->ifr_addr;
|
|
ret = memcmp(&if_addr->sin_addr, hst_addr, addr_len);
|
|
if (!ret) {
|
|
@@ -183,6 +230,20 @@ static unsigned int get_proximity(const
|
|
}
|
|
break;
|
|
|
|
+ case AF_INET6:
|
|
+#ifndef INET6
|
|
+ if (host_addr->sa_family == AF_INET)
|
|
+ break;
|
|
+
|
|
+ if6_addr = (struct sockaddr_in6 *) &ifr->ifr_addr;
|
|
+ ret = memcmp(&if6_addr->sin6_addr, hst6_addr, addr_len);
|
|
+ if (!ret) {
|
|
+ close(sock);
|
|
+ free(ifc.ifc_req);
|
|
+ return PROXIMITY_LOCAL;
|
|
+ }
|
|
+#endif
|
|
+
|
|
default:
|
|
break;
|
|
}
|
|
@@ -197,23 +258,27 @@ static unsigned int get_proximity(const
|
|
while (ptr < (char *) ifc.ifc_req + ifc.ifc_len) {
|
|
ifr = (struct ifreq *) ptr;
|
|
|
|
+ nmptr = *ifr;
|
|
+ ret = ioctl(sock, SIOCGIFNETMASK, &nmptr);
|
|
+ if (ret == -1) {
|
|
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
|
|
+ logerr("ioctl: %s", estr);
|
|
+ close(sock);
|
|
+ free(ifc.ifc_req);
|
|
+ return PROXIMITY_ERROR;
|
|
+ }
|
|
+
|
|
switch (ifr->ifr_addr.sa_family) {
|
|
case AF_INET:
|
|
+#ifndef INET6
|
|
+ if (host_addr->sa_family == AF_INET6)
|
|
+ break;
|
|
+#endif
|
|
if_addr = (struct sockaddr_in *) &ifr->ifr_addr;
|
|
ia = ntohl((uint32_t) if_addr->sin_addr.s_addr);
|
|
|
|
/* Is the address within a localiy attached subnet */
|
|
|
|
- nmptr = *ifr;
|
|
- ret = ioctl(sock, SIOCGIFNETMASK, &nmptr);
|
|
- if (ret == -1) {
|
|
- char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
|
|
- logerr("ioctl: %s", estr);
|
|
- close(sock);
|
|
- free(ifc.ifc_req);
|
|
- return PROXIMITY_ERROR;
|
|
- }
|
|
-
|
|
msk_addr = (struct sockaddr_in *) &nmptr.ifr_netmask;
|
|
mask = ntohl((uint32_t) msk_addr->sin_addr.s_addr);
|
|
|
|
@@ -247,6 +312,29 @@ static unsigned int get_proximity(const
|
|
}
|
|
break;
|
|
|
|
+ case AF_INET6:
|
|
+#ifndef INET6
|
|
+ if (host_addr->sa_family == AF_INET)
|
|
+ break;
|
|
+
|
|
+ if6_addr = (struct sockaddr_in6 *) &ifr->ifr_addr;
|
|
+ ia6 = &if6_addr->sin6_addr.s6_addr32[0];
|
|
+
|
|
+ /* Is the address within the network of the interface */
|
|
+
|
|
+ msk6_addr = (struct sockaddr_in6 *) &nmptr.ifr_netmask;
|
|
+ mask6 = &msk6_addr->sin6_addr.s6_addr32[0];
|
|
+
|
|
+ if (ipv6_mask_cmp(ha6, ia6, mask6)) {
|
|
+ close(sock);
|
|
+ free(ifc.ifc_req);
|
|
+ return PROXIMITY_SUBNET;
|
|
+ }
|
|
+
|
|
+ /* How do we define "local network" in ipv6? */
|
|
+#endif
|
|
+ break;
|
|
+
|
|
default:
|
|
break;
|
|
}
|
|
@@ -262,11 +350,12 @@ static unsigned int get_proximity(const
|
|
}
|
|
|
|
static struct host *new_host(const char *name,
|
|
- const char *addr, size_t addr_len,
|
|
+ struct sockaddr *addr, size_t addr_len,
|
|
unsigned int proximity, unsigned int weight)
|
|
{
|
|
struct host *new;
|
|
- char *tmp1, *tmp2;
|
|
+ struct sockaddr *tmp2;
|
|
+ char *tmp1;
|
|
|
|
if (!name || !addr)
|
|
return NULL;
|
|
@@ -950,65 +1039,78 @@ int prune_host_list(unsigned logopt, str
|
|
return 1;
|
|
}
|
|
|
|
-static int add_host_addrs(struct host **list, const char *host, unsigned int weight)
|
|
+static int add_new_host(struct host **list,
|
|
+ const char *host, unsigned int weight,
|
|
+ struct addrinfo *host_addr)
|
|
{
|
|
- struct hostent he;
|
|
- struct hostent *phe = &he;
|
|
- struct hostent *result;
|
|
- struct sockaddr_in saddr;
|
|
- char buf[MAX_IFC_BUF], **haddr;
|
|
- int ghn_errno, ret;
|
|
struct host *new;
|
|
unsigned int prx;
|
|
+ int addr_len;
|
|
|
|
- saddr.sin_family = AF_INET;
|
|
- if (inet_aton(host, &saddr.sin_addr)) {
|
|
- const char *thost = (const char *) &saddr.sin_addr;
|
|
-
|
|
- prx = get_proximity(thost, sizeof(saddr.sin_addr));
|
|
- if (prx == PROXIMITY_ERROR)
|
|
- return 0;
|
|
-
|
|
- if (!(new = new_host(host, thost, sizeof(saddr.sin_addr), prx, weight)))
|
|
- return 0;
|
|
-
|
|
- if (!add_host(list, new))
|
|
- free_host(new);
|
|
-
|
|
- return 1;
|
|
- }
|
|
+ prx = get_proximity(host_addr->ai_addr);
|
|
+ if (prx == PROXIMITY_ERROR)
|
|
+ return 0;
|
|
|
|
- memset(buf, 0, MAX_IFC_BUF);
|
|
- memset(&he, 0, sizeof(struct hostent));
|
|
+ addr_len = sizeof(struct sockaddr);
|
|
+ new = new_host(host, host_addr->ai_addr, addr_len, prx, weight);
|
|
+ if (!new)
|
|
+ return 0;
|
|
|
|
- ret = gethostbyname_r(host, phe,
|
|
- buf, MAX_IFC_BUF, &result, &ghn_errno);
|
|
- if (ret || !result) {
|
|
- if (ghn_errno == -1)
|
|
- logmsg("host %s: lookup failure %d", host, errno);
|
|
- else
|
|
- logmsg("host %s: lookup failure %d", host, ghn_errno);
|
|
+ if (!add_host(list, new)) {
|
|
+ free_host(new);
|
|
return 0;
|
|
}
|
|
|
|
- for (haddr = phe->h_addr_list; *haddr; haddr++) {
|
|
- struct in_addr tt;
|
|
+ return 1;
|
|
+}
|
|
|
|
- prx = get_proximity(*haddr, phe->h_length);
|
|
- if (prx == PROXIMITY_ERROR)
|
|
- return 0;
|
|
+static int add_host_addrs(struct host **list, const char *host, unsigned int weight)
|
|
+{
|
|
+ struct addrinfo hints, *ni, *this;
|
|
+ int ret;
|
|
|
|
- memcpy(&tt, *haddr, sizeof(struct in_addr));
|
|
- if (!(new = new_host(host, *haddr, phe->h_length, prx, weight)))
|
|
- return 0;
|
|
+ memset(&hints, 0, sizeof(hints));
|
|
+ hints.ai_flags = AI_NUMERICHOST;
|
|
+ hints.ai_family = AF_UNSPEC;
|
|
+ hints.ai_socktype = SOCK_DGRAM;
|
|
+
|
|
+ ret = getaddrinfo(host, NULL, &hints, &ni);
|
|
+ if (ret)
|
|
+ goto try_name;
|
|
|
|
- if (!add_host(list, new)) {
|
|
- free_host(new);
|
|
- continue;
|
|
- }
|
|
+ this = ni;
|
|
+ while (this) {
|
|
+ ret = add_new_host(list, host, weight, this);
|
|
+ if (!ret)
|
|
+ break;
|
|
+ this = this->ai_next;
|
|
}
|
|
+ freeaddrinfo(ni);
|
|
+ goto done;
|
|
|
|
- return 1;
|
|
+try_name:
|
|
+ memset(&hints, 0, sizeof(hints));
|
|
+ hints.ai_flags = AI_ADDRCONFIG;
|
|
+ hints.ai_family = AF_UNSPEC;
|
|
+ hints.ai_socktype = SOCK_DGRAM;
|
|
+
|
|
+ ret = getaddrinfo(host, NULL, &hints, &ni);
|
|
+ if (ret) {
|
|
+ error(LOGOPT_ANY, "hostname lookup failed: %s",
|
|
+ gai_strerror(ret));
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ this = ni;
|
|
+ while (this) {
|
|
+ ret = add_new_host(list, host, weight, this);
|
|
+ if (!ret)
|
|
+ break;
|
|
+ this = this->ai_next;
|
|
+ }
|
|
+ freeaddrinfo(ni);
|
|
+done:
|
|
+ return ret;
|
|
}
|
|
|
|
static int add_path(struct host *hosts, const char *path, int len)
|
|
@@ -1057,7 +1159,8 @@ static int add_local_path(struct host **
|
|
new->path = tmp;
|
|
new->proximity = PROXIMITY_LOCAL;
|
|
new->version = NFS_VERS_MASK;
|
|
- new->name = new->addr = NULL;
|
|
+ new->name = NULL;
|
|
+ new->addr = NULL;
|
|
new->weight = new->cost = 0;
|
|
|
|
add_host(hosts, new);
|
|
--- autofs-5.0.4.orig/CHANGELOG
|
|
+++ autofs-5.0.4/CHANGELOG
|
|
@@ -18,6 +18,7 @@
|
|
- make MAX_ERR_BUF and PARSE_MAX_BUF use easier to audit.
|
|
- make some easy alloca replacements (Valerie Aurora Henson).
|
|
- update to configure libtirpc if present.
|
|
+- update to provide ipv6 name and address support.
|
|
|
|
4/11/2008 autofs-5.0.4
|
|
-----------------------
|