With this patch OpenVPN will listen on Ipv4 as well as IPv6 when an IPv6
socket is used. Using bind ipv6only will disable this behavior
Acked-by: Gert Doering <gert@greenie.muc.de>
Message-Id: <1385382680-5912-7-git-send-email-arne@rfc2549.org>
URL: http://article.gmane.org/gmane.network.openvpn.devel/8052
Signed-off-by: Gert Doering <gert@greenie.muc.de>
... | ... |
@@ -684,7 +684,7 @@ TCP/UDP port number or name for bind. |
684 | 684 |
TCP/UDP port number or name for remote. |
685 | 685 |
.\"********************************************************* |
686 | 686 |
.TP |
687 |
-.B \-\-bind |
|
687 |
+.B \-\-bind [ipv6only] |
|
688 | 688 |
Bind to local address and port. This is the default unless any of |
689 | 689 |
.B \-\-proto tcp-client |
690 | 690 |
, |
... | ... |
@@ -692,6 +692,12 @@ Bind to local address and port. This is the default unless any of |
692 | 692 |
or |
693 | 693 |
.B \-\-socks-proxy |
694 | 694 |
are used. |
695 |
+ |
|
696 |
+If the |
|
697 |
+.B ipv6only |
|
698 |
+keyword is present OpenVPN will bind only to IPv6 (as oposed |
|
699 |
+to IPv6 and IPv4) when a IPv6 socket is opened. |
|
700 |
+ |
|
695 | 701 |
.\"********************************************************* |
696 | 702 |
.TP |
697 | 703 |
.B \-\-nobind |
... | ... |
@@ -1570,7 +1570,7 @@ man_listen (struct management *man) |
1570 | 1570 |
{ |
1571 | 1571 |
man->connection.sd_top = create_socket_tcp (AF_INET); |
1572 | 1572 |
socket_bind (man->connection.sd_top, man->settings.local, |
1573 |
- AF_INET, "MANAGEMENT"); |
|
1573 |
+ AF_INET, "MANAGEMENT", true); |
|
1574 | 1574 |
} |
1575 | 1575 |
|
1576 | 1576 |
/* |
... | ... |
@@ -779,6 +779,7 @@ init_options (struct options *o, const bool init_gc) |
779 | 779 |
o->topology = TOP_NET30; |
780 | 780 |
o->ce.proto = PROTO_UDP; |
781 | 781 |
o->ce.af = AF_UNSPEC; |
782 |
+ o->ce.bind_ipv6_only = false; |
|
782 | 783 |
o->ce.connect_retry_seconds = 5; |
783 | 784 |
o->ce.connect_timeout = 10; |
784 | 785 |
o->connect_retry_max = 0; |
... | ... |
@@ -4870,6 +4871,9 @@ add_option (struct options *options, |
4870 | 4870 |
{ |
4871 | 4871 |
VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); |
4872 | 4872 |
options->ce.bind_defined = true; |
4873 |
+ if (p[1] && streq (p[1], "ipv6only")) |
|
4874 |
+ options->ce.bind_ipv6_only=true; |
|
4875 |
+ |
|
4873 | 4876 |
} |
4874 | 4877 |
else if (streq (p[0], "nobind")) |
4875 | 4878 |
{ |
... | ... |
@@ -662,11 +662,10 @@ create_socket (struct link_socket *sock) |
662 | 662 |
{ |
663 | 663 |
/* create socket, use information carried over from getaddrinfo */ |
664 | 664 |
const int ai_proto = sock->info.lsa->actual.ai_protocol; |
665 |
- const int ai_family = sock->info.lsa->actual.ai_family; |
|
665 |
+ int ai_family = sock->info.lsa->actual.ai_family; |
|
666 | 666 |
|
667 | 667 |
ASSERT (sock->info.af == AF_UNSPEC || sock->info.af == ai_family); |
668 | 668 |
|
669 |
- |
|
670 | 669 |
if (ai_proto == IPPROTO_UDP) |
671 | 670 |
{ |
672 | 671 |
sock->sd = create_socket_udp (ai_family, sock->sockflags); |
... | ... |
@@ -880,7 +879,8 @@ void |
880 | 880 |
socket_bind (socket_descriptor_t sd, |
881 | 881 |
struct addrinfo *local, |
882 | 882 |
int ai_family, |
883 |
- const char *prefix) |
|
883 |
+ const char *prefix, |
|
884 |
+ bool ipv6only) |
|
884 | 885 |
{ |
885 | 886 |
struct gc_arena gc = gc_new (); |
886 | 887 |
|
... | ... |
@@ -891,9 +891,11 @@ socket_bind (socket_descriptor_t sd, |
891 | 891 |
* What is the correct way to deal with it? |
892 | 892 |
*/ |
893 | 893 |
|
894 |
- ASSERT(local); |
|
895 | 894 |
struct addrinfo* cur; |
896 | 895 |
|
896 |
+ ASSERT(local); |
|
897 |
+ |
|
898 |
+ |
|
897 | 899 |
/* find the first addrinfo with correct ai_family */ |
898 | 900 |
for (cur = local; cur; cur=cur->ai_next) |
899 | 901 |
{ |
... | ... |
@@ -904,6 +906,15 @@ socket_bind (socket_descriptor_t sd, |
904 | 904 |
msg (M_FATAL, "%s: Socket bind failed: Addr to bind has no %s record", |
905 | 905 |
prefix, addr_family_name(ai_family)); |
906 | 906 |
|
907 |
+ if (ai_family == AF_INET6) |
|
908 |
+ { |
|
909 |
+ int v6only = ipv6only ? 0: 1; /* setsockopt must have an "int" */ |
|
910 |
+ |
|
911 |
+ if (setsockopt(sd, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, sizeof(v6only))) |
|
912 |
+ { |
|
913 |
+ msg (M_NONFATAL|M_ERRNO, "Setting IPV6_V6ONLY=%d failed", v6only); |
|
914 |
+ } |
|
915 |
+ } |
|
907 | 916 |
if (bind (sd, cur->ai_addr, cur->ai_addrlen)) |
908 | 917 |
{ |
909 | 918 |
const int errnum = openvpn_errno (); |
... | ... |
@@ -1153,11 +1164,12 @@ static void bind_local (struct link_socket *sock) |
1153 | 1153 |
#ifdef ENABLE_SOCKS |
1154 | 1154 |
if (sock->socks_proxy && sock->info.proto == PROTO_UDP) |
1155 | 1155 |
socket_bind (sock->ctrl_sd, sock->info.lsa->bind_local, |
1156 |
- sock->info.lsa->actual.ai_family, "SOCKS"); |
|
1156 |
+ sock->info.lsa->actual.ai_family, "SOCKS", false); |
|
1157 | 1157 |
else |
1158 | 1158 |
#endif |
1159 | 1159 |
socket_bind (sock->sd, sock->info.lsa->bind_local, |
1160 |
- sock->info.lsa->actual.ai_family, "TCP/UDP"); |
|
1160 |
+ sock->info.lsa->actual.ai_family, |
|
1161 |
+ "TCP/UDP", sock->info.bind_ipv6_only); |
|
1161 | 1162 |
} |
1162 | 1163 |
} |
1163 | 1164 |
|
... | ... |
@@ -1294,11 +1306,12 @@ create_new_socket (struct link_socket* sock) |
1294 | 1294 |
resolve_bind_local (sock, sock->info.af); |
1295 | 1295 |
} |
1296 | 1296 |
resolve_remote (sock, 1, NULL, NULL); |
1297 |
+ |
|
1297 | 1298 |
/* |
1298 | 1299 |
* In P2P or server mode we must create the socket even when resolving |
1299 | 1300 |
* the remote site fails/is not specified. */ |
1300 | 1301 |
|
1301 |
- if (sock->info.af && sock->info.lsa->actual.ai_family==0 && sock->bind_local) |
|
1302 |
+ if (sock->info.lsa->actual.ai_family==0 && sock->bind_local) |
|
1302 | 1303 |
{ |
1303 | 1304 |
/* Copy sock parameters from bind addr */ |
1304 | 1305 |
set_actual_address (&sock->info.lsa->actual, sock->info.lsa->bind_local); |
... | ... |
@@ -1309,7 +1322,7 @@ create_new_socket (struct link_socket* sock) |
1309 | 1309 |
/* |
1310 | 1310 |
* Create the socket early if socket should be bound |
1311 | 1311 |
*/ |
1312 |
- if (sock->bind_local && sock->info.lsa->actual.ai_family) |
|
1312 |
+ if (sock->bind_local) |
|
1313 | 1313 |
{ |
1314 | 1314 |
create_socket (sock); |
1315 | 1315 |
|
... | ... |
@@ -1328,6 +1341,7 @@ link_socket_init_phase1 (struct link_socket *sock, |
1328 | 1328 |
const char *remote_port, |
1329 | 1329 |
int proto, |
1330 | 1330 |
sa_family_t af, |
1331 |
+ bool bind_ipv6_only, |
|
1331 | 1332 |
int mode, |
1332 | 1333 |
const struct link_socket *accept_from, |
1333 | 1334 |
#ifdef ENABLE_HTTP_PROXY |
... | ... |
@@ -1388,6 +1402,7 @@ link_socket_init_phase1 (struct link_socket *sock, |
1388 | 1388 |
sock->info.af = af; |
1389 | 1389 |
sock->info.remote_float = remote_float; |
1390 | 1390 |
sock->info.lsa = lsa; |
1391 |
+ sock->info.bind_ipv6_only = bind_ipv6_only; |
|
1391 | 1392 |
sock->info.ipchange_command = ipchange_command; |
1392 | 1393 |
sock->info.plugins = plugins; |
1393 | 1394 |
|
... | ... |
@@ -118,6 +118,7 @@ struct link_socket_info |
118 | 118 |
bool remote_float; |
119 | 119 |
int proto; /* Protocol (PROTO_x defined below) */ |
120 | 120 |
sa_family_t af; /* Address family like AF_INET, AF_INET6 or AF_UNSPEC*/ |
121 |
+ bool bind_ipv6_only; |
|
121 | 122 |
int mtu_changed; /* Set to true when mtu value is changed */ |
122 | 123 |
}; |
123 | 124 |
|
... | ... |
@@ -289,7 +290,8 @@ struct link_socket *link_socket_new (void); |
289 | 289 |
void socket_bind (socket_descriptor_t sd, |
290 | 290 |
struct addrinfo *local, |
291 | 291 |
int af_family, |
292 |
- const char *prefix); |
|
292 |
+ const char *prefix, |
|
293 |
+ bool ipv6only); |
|
293 | 294 |
|
294 | 295 |
int openvpn_connect (socket_descriptor_t sd, |
295 | 296 |
const struct sockaddr *remote, |
... | ... |
@@ -308,6 +310,7 @@ link_socket_init_phase1 (struct link_socket *sock, |
308 | 308 |
const char *remote_port, |
309 | 309 |
int proto, |
310 | 310 |
sa_family_t af, |
311 |
+ bool bind_ipv6_only, |
|
311 | 312 |
int mode, |
312 | 313 |
const struct link_socket *accept_from, |
313 | 314 |
#ifdef ENABLE_HTTP_PROXY |