summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Lamparter <equinox@diac24.net>2009-10-04 16:21:49 +0200
committerDavid Lamparter <equinox@diac24.net>2010-02-03 05:19:36 +0100
commit446e7f9de21e049d37cd2cca035355b179819237 (patch)
tree33fa8966f352bb9bc304c11145b02ba8114b3829
parente78119339da91bedf0c6f8d9adfe828c60295161 (diff)
downloadquagga-446e7f9de21e049d37cd2cca035355b179819237.tar.bz2
quagga-446e7f9de21e049d37cd2cca035355b179819237.tar.xz
lib: add sockopt helper for setting IPV6_V6ONLY and use it
getaddrinfo returns a list of socket parameters for listening. it will contain both IPv4 and IPv6 listening sockets. unless we use IPV6_V6ONLY on the IPv6 ones, only the socket listed first will work. if the IPv4 one came first, the IPv6 one would get an "Address in use" error. this functionality was already present for bgpd and its listening sockets. as it is needed for vtys as well, make it a common helper.
-rw-r--r--bgpd/bgp_network.c9
-rw-r--r--lib/sockunion.c24
-rw-r--r--lib/sockunion.h1
-rw-r--r--lib/vty.c1
4 files changed, 27 insertions, 8 deletions
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
index 9e3427d2..1a8587e9 100644
--- a/bgpd/bgp_network.c
+++ b/bgpd/bgp_network.c
@@ -383,14 +383,7 @@ bgp_listener (int sock, struct sockaddr *sa, socklen_t salen)
setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL);
#endif
-#ifdef IPV6_V6ONLY
- /* Want only IPV6 on ipv6 socket (not mapped addresses) */
- if (sa->sa_family == AF_INET6) {
- int on = 1;
- setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY,
- (void *) &on, sizeof (on));
- }
-#endif
+ sockopt_v6only (sa->sa_family, sock);
if (bgpd_privs.change (ZPRIVS_RAISE) )
zlog_err ("bgp_socket: could not raise privs");
diff --git a/lib/sockunion.c b/lib/sockunion.c
index 6a40f332..d1f6d80b 100644
--- a/lib/sockunion.c
+++ b/lib/sockunion.c
@@ -527,6 +527,30 @@ sockopt_ttl (int family, int sock, int ttl)
return 0;
}
+int
+sockopt_v6only (int family, int sock)
+{
+ int ret, on = 1;
+
+#ifdef HAVE_IPV6
+#ifdef IPV6_V6ONLY
+ if (family == AF_INET6)
+ {
+ ret = setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY,
+ (void *) &on, sizeof (int));
+ if (ret < 0)
+ {
+ zlog (NULL, LOG_WARNING, "can't set sockopt IPV6_V6ONLY "
+ "to socket %d", sock);
+ return -1;
+ }
+ return 0;
+ }
+#endif /* IPV6_V6ONLY */
+#endif /* HAVE_IPV6 */
+ return 0;
+}
+
/* If same family and same prefix return 1. */
int
sockunion_same (union sockunion *su1, union sockunion *su2)
diff --git a/lib/sockunion.h b/lib/sockunion.h
index 96b9a0d4..db145cf2 100644
--- a/lib/sockunion.h
+++ b/lib/sockunion.h
@@ -99,6 +99,7 @@ extern int sockunion_accept (int sock, union sockunion *);
extern int sockunion_stream_socket (union sockunion *);
extern int sockopt_reuseaddr (int);
extern int sockopt_reuseport (int);
+extern int sockopt_v6only (int family, int sock);
extern int sockunion_bind (int sock, union sockunion *,
unsigned short, union sockunion *);
extern int sockopt_ttl (int family, int sock, int ttl);
diff --git a/lib/vty.c b/lib/vty.c
index e4818eb6..9c58b50d 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -1816,6 +1816,7 @@ vty_serv_sock_addrinfo (const char *hostname, unsigned short port)
if (sock < 0)
continue;
+ sockopt_v6only (ainfo->ai_family, sock);
sockopt_reuseaddr (sock);
sockopt_reuseport (sock);