]> git.pld-linux.org Git - packages/autofs.git/blame - autofs-5.0.4-ipv6-name-and-address-support.patch
- updated to 5.0.5, nfy.
[packages/autofs.git] / autofs-5.0.4-ipv6-name-and-address-support.patch
CommitLineData
e5fd101c
PS
1autofs-5.0.4 - ipv6 name and address support
2
3From: Ian Kent <raven@themaw.net>
4
5For ipv6 we need to convert all ipv4 specific function calls to ipv6
6compatible function calls and update the rpc code to deal with ipv6
7addresses. The host proximity calculation also needes to be updated.
8
9I'm sure this isn't completely correct yet and it will need more work
10as I become more familiar with how ipv6 and subneting with it is used.
11The changes so far function correctly for the current autofs
12connectathon test suite maps so I hope there aren't any regressions
13with current map configurations.
14---
15
16 include/replicated.h | 2
17 include/rpc_subs.h | 4
18 lib/rpc_subs.c | 484 ++++++++++++++++++++++++++++++++------------------
19 modules/cyrus-sasl.c | 17 +-
20 modules/replicated.c | 235 +++++++++++++++++-------
21 5 files changed, 499 insertions(+), 243 deletions(-)
22
23
24diff --git a/include/replicated.h b/include/replicated.h
25index 88cd08a..e0133ff 100644
26--- a/include/replicated.h
27+++ b/include/replicated.h
28@@ -51,7 +51,7 @@
29
30 struct host {
31 char *name;
32- char *addr;
33+ struct sockaddr *addr;
34 size_t addr_len;
35 char *path;
36 unsigned int version;
37diff --git a/include/rpc_subs.h b/include/rpc_subs.h
38index e20a89d..87fd568 100644
39--- a/include/rpc_subs.h
40+++ b/include/rpc_subs.h
41@@ -46,7 +46,7 @@
42
43 struct conn_info {
44 const char *host;
45- const char *addr;
46+ struct sockaddr *addr;
47 size_t addr_len;
48 unsigned short port;
49 unsigned long program;
50@@ -63,7 +63,7 @@ int rpc_udp_getclient(struct conn_info *, unsigned int, unsigned int);
51 void rpc_destroy_udp_client(struct conn_info *);
52 int rpc_tcp_getclient(struct conn_info *, unsigned int, unsigned int);
53 void rpc_destroy_tcp_client(struct conn_info *);
54-int rpc_portmap_getclient(struct conn_info *, const char *, const char *, size_t, const char *, unsigned int);
55+int rpc_portmap_getclient(struct conn_info *, const char *, struct sockaddr *, size_t, const char *, unsigned int);
56 unsigned short rpc_portmap_getport(struct conn_info *, struct pmap *);
57 int rpc_ping_proto(struct conn_info *);
58 int rpc_ping(const char *, long, long, unsigned int);
59diff --git a/lib/rpc_subs.c b/lib/rpc_subs.c
60index 7b347a7..a822f1f 100644
61--- a/lib/rpc_subs.c
62+++ b/lib/rpc_subs.c
63@@ -17,10 +17,11 @@
64 #define _GNU_SOURCE
65 #endif
66
67+#include "config.h"
68+
69 #include <rpc/types.h>
70 #include <rpc/rpc.h>
71 #include <rpc/pmap_prot.h>
72-
73 #include <sys/socket.h>
74 #include <netdb.h>
75 #include <net/if.h>
76@@ -54,145 +55,76 @@
77
78 inline void dump_core(void);
79
80-/*
81- * Create a UDP RPC client
82- */
83-static CLIENT *create_udp_client(struct conn_info *info)
84+static CLIENT *rpc_clntudp_create(struct sockaddr *addr, struct conn_info *info, int *fd)
85 {
86- int fd, ret, ghn_errno;
87- CLIENT *client;
88- struct sockaddr_in laddr, raddr;
89- struct hostent hp;
90- struct hostent *php = &hp;
91- struct hostent *result;
92- char buf[HOST_ENT_BUF_SIZE];
93- size_t len;
94-
95- if (info->proto->p_proto != IPPROTO_UDP)
96- return NULL;
97-
98- if (info->client) {
99- if (!clnt_control(info->client, CLGET_FD, (char *) &fd)) {
100- fd = -1;
101- clnt_destroy(info->client);
102- info->client = NULL;
103- } else {
104- clnt_control(info->client, CLSET_FD_NCLOSE, NULL);
105- clnt_destroy(info->client);
106- }
107- }
108-
109- memset(&laddr, 0, sizeof(laddr));
110- memset(&raddr, 0, sizeof(raddr));
111-
112- raddr.sin_family = AF_INET;
113- if (info->addr) {
114- memcpy(&raddr.sin_addr.s_addr, info->addr, info->addr_len);
115- goto got_addr;
116- }
117-
118- if (inet_aton(info->host, &raddr.sin_addr))
119- goto got_addr;
120-
121- memset(&hp, 0, sizeof(struct hostent));
122-
123- ret = gethostbyname_r(info->host, php,
124- buf, HOST_ENT_BUF_SIZE, &result, &ghn_errno);
125- if (ret || !result) {
126- int err = ghn_errno == -1 ? errno : ghn_errno;
127- char *estr = strerror_r(err, buf, HOST_ENT_BUF_SIZE);
128- logerr("hostname lookup failed: %s", estr);
129- goto out_close;
130- }
131- memcpy(&raddr.sin_addr.s_addr, php->h_addr, php->h_length);
132-
133-got_addr:
134- raddr.sin_port = htons(info->port);
135-
136- if (!info->client) {
137- /*
138- * bind to any unused port. If we left this up to the rpc
139- * layer, it would bind to a reserved port, which has been shown
140- * to exhaust the reserved port range in some situations.
141- */
142- fd = open_sock(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
143- if (fd < 0)
144- return NULL;
145-
146- laddr.sin_family = AF_INET;
147- laddr.sin_port = 0;
148- laddr.sin_addr.s_addr = htonl(INADDR_ANY);
149-
150- len = sizeof(struct sockaddr_in);
151- if (bind(fd, (struct sockaddr *)&laddr, len) < 0) {
152- close(fd);
153- fd = RPC_ANYSOCK;
154- /* FALLTHROUGH */
155- }
156- }
157-
158- client = clntudp_bufcreate(&raddr,
159- info->program, info->version,
160- info->timeout, &fd,
161- info->send_sz, info->recv_sz);
162+ struct sockaddr_in *in4_raddr;
163+ struct sockaddr_in6 *in6_raddr;
164+ CLIENT *client = NULL;
165+
166+ switch (addr->sa_family) {
167+ case AF_INET:
168+ in4_raddr = (struct sockaddr_in *) addr;
169+ in4_raddr->sin_port = htons(info->port);
170+ client = clntudp_bufcreate(in4_raddr,
171+ info->program, info->version,
172+ info->timeout, fd,
173+ info->send_sz, info->recv_sz);
174+ break;
175
176- if (!client) {
177- info->client = NULL;
178- goto out_close;
179- }
180+ case AF_INET6:
181+#ifndef INET6
182+ /* Quiet compile warning */
183+ in6_raddr = NULL;
184+#else
185+ in6_raddr = (struct sockaddr_in6 *) addr;
186+ in6_raddr->sin6_port = htons(info->port);
187+ client = clntudp6_bufcreate(in6_raddr,
188+ info->program, info->version,
189+ info->timeout, fd,
190+ info->send_sz, info->recv_sz);
191+#endif
192+ break;
193
194- /* Close socket fd on destroy, as is default for rpcowned fds */
195- if (!clnt_control(client, CLSET_FD_CLOSE, NULL)) {
196- clnt_destroy(client);
197- info->client = NULL;
198- goto out_close;
199+ default:
200+ break;
201 }
202
203 return client;
204-
205-out_close:
206- if (fd != -1)
207- close(fd);
208- return NULL;
209 }
210
211-int rpc_udp_getclient(struct conn_info *info,
212- unsigned int program, unsigned int version)
213+static CLIENT *rpc_clnttcp_create(struct sockaddr *addr, struct conn_info *info, int *fd)
214 {
215- struct protoent *pe_proto;
216- CLIENT *client;
217+ struct sockaddr_in *in4_raddr;
218+ struct sockaddr_in6 *in6_raddr;
219+ CLIENT *client = NULL;
220+
221+ switch (addr->sa_family) {
222+ case AF_INET:
223+ in4_raddr = (struct sockaddr_in *) addr;
224+ in4_raddr->sin_port = htons(info->port);
225+ client = clnttcp_create(in4_raddr,
226+ info->program, info->version, fd,
227+ info->send_sz, info->recv_sz);
228+ break;
229
230- if (!info->client) {
231- pe_proto = getprotobyname("udp");
232- if (!pe_proto)
233- return 0;
234+ case AF_INET6:
235+#ifndef INET6
236+ /* Quiet compile warning */
237+ in6_raddr = NULL;
238+#else
239+ in6_raddr = (struct sockaddr_in6 *) addr;
240+ in6_raddr->sin6_port = htons(info->port);
241+ client = clnttcp6_create(in6_raddr,
242+ info->program, info->version, fd,
243+ info->send_sz, info->recv_sz);
244+#endif
245+ break;
246
247- info->proto = pe_proto;
248- info->send_sz = UDPMSGSIZE;
249- info->recv_sz = UDPMSGSIZE;
250+ default:
251+ break;
252 }
253
254- info->program = program;
255- info->version = version;
256-
257- client = create_udp_client(info);
258-
259- if (!client)
260- return 0;
261-
262- info->client = client;
263-
264- return 1;
265-}
266-
267-void rpc_destroy_udp_client(struct conn_info *info)
268-{
269- if (!info->client)
270- return;
271-
272- clnt_destroy(info->client);
273- info->client = NULL;
274- return;
275+ return client;
276 }
277
278 /*
279@@ -201,12 +133,11 @@ void rpc_destroy_udp_client(struct conn_info *info)
280 * The input struct timeval always has tv_nsec set to zero,
281 * we only ever use tv_sec for timeouts.
282 */
283-static int connect_nb(int fd, struct sockaddr_in *addr, struct timeval *tout)
284+static int connect_nb(int fd, struct sockaddr *addr, socklen_t len, struct timeval *tout)
285 {
286 struct pollfd pfd[1];
287 int timeout = tout->tv_sec;
288 int flags, ret;
289- socklen_t len;
290
291 flags = fcntl(fd, F_GETFL, 0);
292 if (flags < 0)
293@@ -221,8 +152,7 @@ static int connect_nb(int fd, struct sockaddr_in *addr, struct timeval *tout)
294 * we set ret = -errno to capture it in case we decide to
295 * use it later.
296 */
297- len = sizeof(struct sockaddr);
298- ret = connect(fd, (struct sockaddr *)addr, len);
299+ ret = connect(fd, addr, len);
300 if (ret < 0 && errno != EINPROGRESS) {
301 ret = -errno;
302 goto done;
303@@ -277,26 +207,241 @@ done:
304 return ret;
305 }
306
307+static CLIENT *rpc_do_create_client(struct sockaddr *addr, struct conn_info *info, int *fd)
308+{
309+ CLIENT *client = NULL;
310+ struct sockaddr *laddr;
311+ struct sockaddr_in in4_laddr;
312+ struct sockaddr_in6 in6_laddr;
313+ int type, proto;
314+ socklen_t slen;
315+
316+ proto = info->proto->p_proto;
317+ if (proto == IPPROTO_UDP)
318+ type = SOCK_DGRAM;
319+ else
320+ type = SOCK_STREAM;
321+
322+ /*
323+ * bind to any unused port. If we left this up to the rpc
324+ * layer, it would bind to a reserved port, which has been shown
325+ * to exhaust the reserved port range in some situations.
326+ */
327+ switch (addr->sa_family) {
328+ case AF_INET:
329+ in4_laddr.sin_family = AF_INET;
330+ in4_laddr.sin_port = htons(0);
331+ in4_laddr.sin_addr.s_addr = htonl(INADDR_ANY);
332+ slen = sizeof(struct sockaddr_in);
333+ laddr = (struct sockaddr *) &in4_laddr;
334+ break;
335+
336+ case AF_INET6:
337+#ifndef INET6
338+ /* Quiet compiler */
339+ in6_laddr.sin6_family = AF_INET6;
340+ return NULL;
341+#else
342+ in6_laddr.sin6_family = AF_INET6;
343+ in6_laddr.sin6_port = htons(0);
344+ in6_laddr.sin6_addr = in6addr_any;
345+ slen = sizeof(struct sockaddr_in6);
346+ laddr = (struct sockaddr *) &in6_laddr;
347+ break;
348+#endif
349+ default:
350+ return NULL;
351+ }
352+
353+ if (!info->client) {
354+ *fd = open_sock(addr->sa_family, type, proto);
355+ if (*fd < 0)
356+ return NULL;
357+
358+ if (bind(*fd, laddr, slen) < 0) {
359+ close(*fd);
360+ return NULL;
361+ }
362+ }
363+
364+ switch (info->proto->p_proto) {
365+ case IPPROTO_UDP:
366+ if (!info->client) {
367+ *fd = open_sock(addr->sa_family, type, proto);
368+ if (*fd < 0)
369+ return NULL;
370+
371+ if (bind(*fd, laddr, slen) < 0) {
372+ close(*fd);
373+ return NULL;
374+ }
375+ }
376+ client = rpc_clntudp_create(addr, info, fd);
377+ break;
378+
379+ case IPPROTO_TCP:
380+ if (!info->client) {
381+ *fd = open_sock(addr->sa_family, type, proto);
382+ if (*fd < 0)
383+ return NULL;
384+
385+ if (connect_nb(*fd, laddr, slen, &info->timeout) < 0) {
386+ close(*fd);
387+ return NULL;
388+ }
389+ }
390+ client = rpc_clnttcp_create(addr, info, fd);
391+ break;
392+
393+ default:
394+ break;
395+ }
396+
397+ return client;
398+}
399+
400+/*
401+ * Create a UDP RPC client
402+ */
403+static CLIENT *create_udp_client(struct conn_info *info)
404+{
405+ CLIENT *client = NULL;
406+ struct addrinfo *ai, *haddr;
407+ struct addrinfo hints;
408+ int fd, ret;
409+
410+ if (info->proto->p_proto != IPPROTO_UDP)
411+ return NULL;
412+
413+ fd = RPC_ANYSOCK;
414+
415+ if (info->client) {
416+ if (!clnt_control(info->client, CLGET_FD, (char *) &fd)) {
417+ fd = RPC_ANYSOCK;
418+ clnt_destroy(info->client);
419+ info->client = NULL;
420+ } else {
421+ clnt_control(info->client, CLSET_FD_NCLOSE, NULL);
422+ clnt_destroy(info->client);
423+ }
424+ }
425+
426+ if (info->addr) {
427+ client = rpc_do_create_client(info->addr, info, &fd);
428+ if (client)
429+ goto done;
430+
431+ if (!info->client) {
432+ close(fd);
433+ fd = RPC_ANYSOCK;
434+ }
435+ }
436+
437+ memset(&hints, 0, sizeof(hints));
438+ hints.ai_flags = AI_ADDRCONFIG;
439+ hints.ai_family = AF_UNSPEC;
440+ hints.ai_socktype = SOCK_DGRAM;
441+
442+ ret = getaddrinfo(info->host, NULL, &hints, &ai);
443+ if (ret) {
444+ error(LOGOPT_ANY,
445+ "hostname lookup failed: %s", gai_strerror(ret));
446+ goto out_close;
447+ }
448+
449+ haddr = ai;
450+ while (haddr) {
451+ client = rpc_do_create_client(haddr->ai_addr, info, &fd);
452+ if (client)
453+ break;
454+
455+ if (!info->client) {
456+ close(fd);
457+ fd = RPC_ANYSOCK;
458+ }
459+
460+ haddr = haddr->ai_next;
461+ }
462+
463+ freeaddrinfo(ai);
464+
465+ if (!client) {
466+ info->client = NULL;
467+ goto out_close;
468+ }
469+done:
470+ /* Close socket fd on destroy, as is default for rpcowned fds */
471+ if (!clnt_control(client, CLSET_FD_CLOSE, NULL)) {
472+ clnt_destroy(client);
473+ info->client = NULL;
474+ goto out_close;
475+ }
476+
477+ return client;
478+
479+out_close:
480+ if (fd != -1)
481+ close(fd);
482+ return NULL;
483+}
484+
485+int rpc_udp_getclient(struct conn_info *info,
486+ unsigned int program, unsigned int version)
487+{
488+ struct protoent *pe_proto;
489+ CLIENT *client;
490+
491+ if (!info->client) {
492+ pe_proto = getprotobyname("udp");
493+ if (!pe_proto)
494+ return 0;
495+
496+ info->proto = pe_proto;
497+ info->send_sz = UDPMSGSIZE;
498+ info->recv_sz = UDPMSGSIZE;
499+ }
500+
501+ info->program = program;
502+ info->version = version;
503+
504+ client = create_udp_client(info);
505+
506+ if (!client)
507+ return 0;
508+
509+ info->client = client;
510+
511+ return 1;
512+}
513+
514+void rpc_destroy_udp_client(struct conn_info *info)
515+{
516+ if (!info->client)
517+ return;
518+
519+ clnt_destroy(info->client);
520+ info->client = NULL;
521+ return;
522+}
523+
524 /*
525 * Create a TCP RPC client using non-blocking connect
526 */
527 static CLIENT *create_tcp_client(struct conn_info *info)
528 {
529- int fd, ghn_errno;
530- CLIENT *client;
531- struct sockaddr_in addr;
532- struct hostent hp;
533- struct hostent *php = &hp;
534- struct hostent *result;
535- char buf[HOST_ENT_BUF_SIZE];
536- int ret;
537+ CLIENT *client = NULL;
538+ struct addrinfo *ai, *haddr;
539+ struct addrinfo hints;
540+ int fd, ret;
541
542 if (info->proto->p_proto != IPPROTO_TCP)
543 return NULL;
544
545+ fd = RPC_ANYSOCK;
546+
547 if (info->client) {
548 if (!clnt_control(info->client, CLGET_FD, (char *) &fd)) {
549- fd = -1;
550+ fd = RPC_ANYSOCK;
551 clnt_destroy(info->client);
552 info->client = NULL;
553 } else {
554@@ -305,51 +450,50 @@ static CLIENT *create_tcp_client(struct conn_info *info)
555 }
556 }
557
558- memset(&addr, 0, sizeof(addr));
559-
560- addr.sin_family = AF_INET;
561 if (info->addr) {
562- memcpy(&addr.sin_addr.s_addr, info->addr, info->addr_len);
563- goto got_addr;
564- }
565+ client = rpc_do_create_client(info->addr, info, &fd);
566+ if (client)
567+ goto done;
568
569- if (inet_aton(info->host, &addr.sin_addr))
570- goto got_addr;
571+ if (!info->client) {
572+ close(fd);
573+ fd = RPC_ANYSOCK;
574+ }
575+ }
576
577- memset(&hp, 0, sizeof(struct hostent));
578+ memset(&hints, 0, sizeof(hints));
579+ hints.ai_flags = AI_ADDRCONFIG;
580+ hints.ai_family = AF_UNSPEC;
581+ hints.ai_socktype = SOCK_STREAM;
582
583- ret = gethostbyname_r(info->host, php,
584- buf, HOST_ENT_BUF_SIZE, &result, &ghn_errno);
585- if (ret || !result) {
586- int err = ghn_errno == -1 ? errno : ghn_errno;
587- char *estr = strerror_r(err, buf, HOST_ENT_BUF_SIZE);
588- logerr("hostname lookup failed: %s", estr);
589+ ret = getaddrinfo(info->host, NULL, &hints, &ai);
590+ if (ret) {
591+ error(LOGOPT_ANY,
592+ "hostname lookup failed: %s", gai_strerror(ret));
593 goto out_close;
594 }
595- memcpy(&addr.sin_addr.s_addr, php->h_addr, php->h_length);
596
597-got_addr:
598- addr.sin_port = htons(info->port);
599+ haddr = ai;
600+ while (haddr) {
601+ client = rpc_do_create_client(haddr->ai_addr, info, &fd);
602+ if (client)
603+ break;
604
605- if (!info->client) {
606- fd = open_sock(PF_INET, SOCK_STREAM, info->proto->p_proto);
607- if (fd < 0)
608- return NULL;
609+ if (!info->client) {
610+ close(fd);
611+ fd = RPC_ANYSOCK;
612+ }
613
614- ret = connect_nb(fd, &addr, &info->timeout);
615- if (ret < 0)
616- goto out_close;
617+ haddr = haddr->ai_next;
618 }
619
620- client = clnttcp_create(&addr,
621- info->program, info->version, &fd,
622- info->send_sz, info->recv_sz);
623+ freeaddrinfo(ai);
624
625 if (!client) {
626 info->client = NULL;
627 goto out_close;
628 }
629-
630+done:
631 /* Close socket fd on destroy, as is default for rpcowned fds */
632 if (!clnt_control(client, CLSET_FD_CLOSE, NULL)) {
633 clnt_destroy(client);
634@@ -420,7 +564,7 @@ void rpc_destroy_tcp_client(struct conn_info *info)
635 }
636
637 int rpc_portmap_getclient(struct conn_info *info,
638- const char *host, const char *addr, size_t addr_len,
639+ const char *host, struct sockaddr *addr, size_t addr_len,
640 const char *proto, unsigned int option)
641 {
642 struct protoent *pe_proto;
643diff --git a/modules/cyrus-sasl.c b/modules/cyrus-sasl.c
644index 286af15..ec2ab0c 100644
645--- a/modules/cyrus-sasl.c
646+++ b/modules/cyrus-sasl.c
647@@ -732,16 +732,25 @@ sasl_bind_mech(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt, const c
648 debug(logopt, "Attempting sasl bind with mechanism %s", mech);
649
650 result = ldap_get_option(ldap, LDAP_OPT_HOST_NAME, &host);
651- if (result != LDAP_SUCCESS || !host) {
652+ if (result != LDAP_OPT_SUCCESS || !host) {
653 debug(logopt, "failed to get hostname for connection");
654 return NULL;
655 }
656
657- if ((tmp = strchr(host, ':')))
658- *tmp = '\0';
659+ if ((tmp = strrchr(host, ':'))) {
660+ if (*(tmp - 1) != ']') {
661+ *tmp = '\0';
662+ tmp = host;
663+ } else {
664+ *(tmp - 1) = '\0';
665+ tmp = host;
666+ if (*tmp == '[')
667+ tmp++;
668+ }
669+ }
670
671 /* Create a new authentication context for the service. */
672- result = sasl_client_new("ldap", host, NULL, NULL, NULL, 0, &conn);
673+ result = sasl_client_new("ldap", tmp, NULL, NULL, NULL, 0, &conn);
674 if (result != SASL_OK) {
675 error(logopt, "sasl_client_new failed with error %d",
676 result);
677diff --git a/modules/replicated.c b/modules/replicated.c
678index 835af97..9e85c00 100644
679--- a/modules/replicated.c
680+++ b/modules/replicated.c
681@@ -45,7 +45,7 @@
682 #include <stdlib.h>
683 #include <sys/errno.h>
684 #include <sys/types.h>
685-#include <netinet/in.h>
686+#include <stdint.h>
687 #include <sys/ioctl.h>
688 #include <sys/socket.h>
689 #include <arpa/inet.h>
690@@ -75,6 +75,20 @@ static int volatile ifc_last_len = 0;
691 #define max(x, y) (x >= y ? x : y)
692 #define mmax(x, y, z) (max(x, y) == x ? max(x, z) : max(y, z))
693
694+unsigned int ipv6_mask_cmp(uint32_t *host, uint32_t *iface, uint32_t *mask)
695+{
696+ unsigned int ret = 1;
697+ unsigned int i;
698+
699+ for (i = 0; i < 4; i++) {
700+ if ((host[i] & mask[i]) != (iface[i] & mask[i])) {
701+ ret = 0;
702+ break;
703+ }
704+ }
705+ return ret;
706+}
707+
708 void seed_random(void)
709 {
710 int fd;
711@@ -136,20 +150,49 @@ static int alloc_ifreq(struct ifconf *ifc, int sock)
712 return 1;
713 }
714
715-static unsigned int get_proximity(const char *host_addr, int addr_len)
716+static unsigned int get_proximity(struct sockaddr *host_addr)
717 {
718- struct sockaddr_in *msk_addr, *if_addr;
719+ struct sockaddr_in *addr, *msk_addr, *if_addr;
720+ struct sockaddr_in6 *addr6, *msk6_addr, *if6_addr;
721 struct in_addr *hst_addr;
722- char tmp[20], buf[MAX_ERR_BUF], *ptr;
723+ struct in6_addr *hst6_addr;
724+ int addr_len;
725+ char buf[MAX_ERR_BUF], *ptr;
726 struct ifconf ifc;
727 struct ifreq *ifr, nmptr;
728 int sock, ret, i;
729- uint32_t mask, ha, ia;
730+ uint32_t mask, ha, ia, *mask6, *ha6, *ia6;
731+
732+ addr = NULL;
733+ addr6 = NULL;
734+ hst_addr = NULL;
735+ hst6_addr = NULL;
736+ mask6 = NULL;
737+ ha6 = NULL;
738+ ia6 = NULL;
739+
740+ switch (host_addr->sa_family) {
741+ case AF_INET:
742+ addr = (struct sockaddr_in *) host_addr;
743+ hst_addr = (struct in_addr *) &addr->sin_addr;
744+ ha = ntohl((uint32_t) hst_addr->s_addr);
745+ addr_len = sizeof(hst_addr);
746+ break;
747
748- memcpy(tmp, host_addr, addr_len);
749- hst_addr = (struct in_addr *) tmp;
750+ case AF_INET6:
751+#ifndef INET6
752+ return PROXIMITY_ERROR;
753+#else
754+ addr6 = (struct sockaddr_in6 *) host_addr;
755+ hst6_addr = (struct in6_addr *) &addr6->sin6_addr;
756+ ha6 = &hst6_addr->s6_addr32[0];
757+ addr_len = sizeof(hst6_addr);
758+ break;
759+#endif
760
761- ha = ntohl((uint32_t) hst_addr->s_addr);
762+ default:
763+ return PROXIMITY_ERROR;
764+ }
765
766 sock = open_sock(AF_INET, SOCK_DGRAM, 0);
767 if (sock < 0) {
768@@ -174,6 +217,10 @@ static unsigned int get_proximity(const char *host_addr, int addr_len)
769
770 switch (ifr->ifr_addr.sa_family) {
771 case AF_INET:
772+#ifndef INET6
773+ if (host_addr->sa_family == AF_INET6)
774+ break;
775+#endif
776 if_addr = (struct sockaddr_in *) &ifr->ifr_addr;
777 ret = memcmp(&if_addr->sin_addr, hst_addr, addr_len);
778 if (!ret) {
779@@ -183,6 +230,20 @@ static unsigned int get_proximity(const char *host_addr, int addr_len)
780 }
781 break;
782
783+ case AF_INET6:
784+#ifndef INET6
785+ if (host_addr->sa_family == AF_INET)
786+ break;
787+
788+ if6_addr = (struct sockaddr_in6 *) &ifr->ifr_addr;
789+ ret = memcmp(&if6_addr->sin6_addr, hst6_addr, addr_len);
790+ if (!ret) {
791+ close(sock);
792+ free(ifc.ifc_req);
793+ return PROXIMITY_LOCAL;
794+ }
795+#endif
796+
797 default:
798 break;
799 }
800@@ -197,23 +258,27 @@ static unsigned int get_proximity(const char *host_addr, int addr_len)
801 while (ptr < (char *) ifc.ifc_req + ifc.ifc_len) {
802 ifr = (struct ifreq *) ptr;
803
804+ nmptr = *ifr;
805+ ret = ioctl(sock, SIOCGIFNETMASK, &nmptr);
806+ if (ret == -1) {
807+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
808+ logerr("ioctl: %s", estr);
809+ close(sock);
810+ free(ifc.ifc_req);
811+ return PROXIMITY_ERROR;
812+ }
813+
814 switch (ifr->ifr_addr.sa_family) {
815 case AF_INET:
816+#ifndef INET6
817+ if (host_addr->sa_family == AF_INET6)
818+ break;
819+#endif
820 if_addr = (struct sockaddr_in *) &ifr->ifr_addr;
821 ia = ntohl((uint32_t) if_addr->sin_addr.s_addr);
822
823 /* Is the address within a localiy attached subnet */
824
825- nmptr = *ifr;
826- ret = ioctl(sock, SIOCGIFNETMASK, &nmptr);
827- if (ret == -1) {
828- char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
829- logerr("ioctl: %s", estr);
830- close(sock);
831- free(ifc.ifc_req);
832- return PROXIMITY_ERROR;
833- }
834-
835 msk_addr = (struct sockaddr_in *) &nmptr.ifr_netmask;
836 mask = ntohl((uint32_t) msk_addr->sin_addr.s_addr);
837
838@@ -247,6 +312,29 @@ static unsigned int get_proximity(const char *host_addr, int addr_len)
839 }
840 break;
841
842+ case AF_INET6:
843+#ifndef INET6
844+ if (host_addr->sa_family == AF_INET)
845+ break;
846+
847+ if6_addr = (struct sockaddr_in6 *) &ifr->ifr_addr;
848+ ia6 = &if6_addr->sin6_addr.s6_addr32[0];
849+
850+ /* Is the address within the network of the interface */
851+
852+ msk6_addr = (struct sockaddr_in6 *) &nmptr.ifr_netmask;
853+ mask6 = &msk6_addr->sin6_addr.s6_addr32[0];
854+
855+ if (ipv6_mask_cmp(ha6, ia6, mask6)) {
856+ close(sock);
857+ free(ifc.ifc_req);
858+ return PROXIMITY_SUBNET;
859+ }
860+
861+ /* How do we define "local network" in ipv6? */
862+#endif
863+ break;
864+
865 default:
866 break;
867 }
868@@ -262,11 +350,12 @@ static unsigned int get_proximity(const char *host_addr, int addr_len)
869 }
870
871 static struct host *new_host(const char *name,
872- const char *addr, size_t addr_len,
873+ struct sockaddr *addr, size_t addr_len,
874 unsigned int proximity, unsigned int weight)
875 {
876 struct host *new;
877- char *tmp1, *tmp2;
878+ struct sockaddr *tmp2;
879+ char *tmp1;
880
881 if (!name || !addr)
882 return NULL;
883@@ -950,65 +1039,78 @@ int prune_host_list(unsigned logopt, struct host **list,
884 return 1;
885 }
886
887-static int add_host_addrs(struct host **list, const char *host, unsigned int weight)
888+static int add_new_host(struct host **list,
889+ const char *host, unsigned int weight,
890+ struct addrinfo *host_addr)
891 {
892- struct hostent he;
893- struct hostent *phe = &he;
894- struct hostent *result;
895- struct sockaddr_in saddr;
896- char buf[MAX_IFC_BUF], **haddr;
897- int ghn_errno, ret;
898 struct host *new;
899 unsigned int prx;
900+ int addr_len;
901
902- saddr.sin_family = AF_INET;
903- if (inet_aton(host, &saddr.sin_addr)) {
904- const char *thost = (const char *) &saddr.sin_addr;
905-
906- prx = get_proximity(thost, sizeof(saddr.sin_addr));
907- if (prx == PROXIMITY_ERROR)
908- return 0;
909-
910- if (!(new = new_host(host, thost, sizeof(saddr.sin_addr), prx, weight)))
911- return 0;
912-
913- if (!add_host(list, new))
914- free_host(new);
915-
916- return 1;
917- }
918+ prx = get_proximity(host_addr->ai_addr);
919+ if (prx == PROXIMITY_ERROR)
920+ return 0;
921
922- memset(buf, 0, MAX_IFC_BUF);
923- memset(&he, 0, sizeof(struct hostent));
924+ addr_len = sizeof(struct sockaddr);
925+ new = new_host(host, host_addr->ai_addr, addr_len, prx, weight);
926+ if (!new)
927+ return 0;
928
929- ret = gethostbyname_r(host, phe,
930- buf, MAX_IFC_BUF, &result, &ghn_errno);
931- if (ret || !result) {
932- if (ghn_errno == -1)
933- logmsg("host %s: lookup failure %d", host, errno);
934- else
935- logmsg("host %s: lookup failure %d", host, ghn_errno);
936+ if (!add_host(list, new)) {
937+ free_host(new);
938 return 0;
939 }
940
941- for (haddr = phe->h_addr_list; *haddr; haddr++) {
942- struct in_addr tt;
943+ return 1;
944+}
945
946- prx = get_proximity(*haddr, phe->h_length);
947- if (prx == PROXIMITY_ERROR)
948- return 0;
949+static int add_host_addrs(struct host **list, const char *host, unsigned int weight)
950+{
951+ struct addrinfo hints, *ni, *this;
952+ int ret;
953
954- memcpy(&tt, *haddr, sizeof(struct in_addr));
955- if (!(new = new_host(host, *haddr, phe->h_length, prx, weight)))
956- return 0;
957+ memset(&hints, 0, sizeof(hints));
958+ hints.ai_flags = AI_NUMERICHOST;
959+ hints.ai_family = AF_UNSPEC;
960+ hints.ai_socktype = SOCK_DGRAM;
961
962- if (!add_host(list, new)) {
963- free_host(new);
964- continue;
965- }
966+ ret = getaddrinfo(host, NULL, &hints, &ni);
967+ if (ret)
968+ goto try_name;
969+
970+ this = ni;
971+ while (this) {
972+ ret = add_new_host(list, host, weight, this);
973+ if (!ret)
974+ break;
975+ this = this->ai_next;
976+ }
977+ freeaddrinfo(ni);
978+ goto done;
979+
980+try_name:
981+ memset(&hints, 0, sizeof(hints));
982+ hints.ai_flags = AI_ADDRCONFIG;
983+ hints.ai_family = AF_UNSPEC;
984+ hints.ai_socktype = SOCK_DGRAM;
985+
986+ ret = getaddrinfo(host, NULL, &hints, &ni);
987+ if (ret) {
988+ error(LOGOPT_ANY, "hostname lookup failed: %s",
989+ gai_strerror(ret));
990+ return 0;
991 }
992
993- return 1;
994+ this = ni;
995+ while (this) {
996+ ret = add_new_host(list, host, weight, this);
997+ if (!ret)
998+ break;
999+ this = this->ai_next;
1000+ }
1001+ freeaddrinfo(ni);
1002+done:
1003+ return ret;
1004 }
1005
1006 static int add_path(struct host *hosts, const char *path, int len)
1007@@ -1057,7 +1159,8 @@ static int add_local_path(struct host **hosts, const char *path)
1008 new->path = tmp;
1009 new->proximity = PROXIMITY_LOCAL;
1010 new->version = NFS_VERS_MASK;
1011- new->name = new->addr = NULL;
1012+ new->name = NULL;
1013+ new->addr = NULL;
1014 new->weight = new->cost = 0;
1015
1016 add_host(hosts, new);
This page took 0.210047 seconds and 4 git commands to generate.