Allow OpenVPN to communicate to peers via a Linux VRF
Hi,
I'm rolling out Linux VRFs[0] in my network and pushed all my external connections in a VRF, so nothing bad[tm] can happen.
Doing so broke my OpenVPN connections between network nodes, as I kind of expected.
I tried using the --bind option to let OpenVPN bind to the external IP for make a connection, but that doesn't work as the IP isn't resolvable via the main kernel routing table, as it's only visible within the VRFs routing table.
So I tried pushing the OpenVPN socket into the VRF and that worked fine.
I massaged that into a --outer-vrf option where a user could specify the VRF device. This can be found in
https://github.com/OpenVPN/openvpn/pull/64
The rational why the option is called outer-vrf is that, one might want to add one for the inner-vrf, when the tun/tap interface should be part of a VRF. As this could be easily done in an ifup-script I didn't bother adding this for now.
I'd be glad if this would be accepted.
Best
Max
Signature · 2 lines
They that give up essential liberty to obtain temporary safety, deserve neither liberty nor safety. (Ben Franklin)
Anno domini 2016 Maximilian Wilhelm scripsit:
Hi again,
Quoted 11 lines
I'm rolling out Linux VRFs[0] in my network and pushed all my external connections in a VRF, so nothing bad[tm] can happen.
Doing so broke my OpenVPN connections between network nodes, as I kind of expected.
I tried using the --bind option to let OpenVPN bind to the external IP for make a connection, but that doesn't work as the IP isn't resolvable via the main kernel routing table, as it's only visible within the VRFs routing table.
Quoted 7 lines
So I tried pushing the OpenVPN socket into the VRF and that worked fine.
I massaged that into a --outer-vrf option where a user could specify the VRF device. This can be found in
I just learned that it would be easy to make this more generic and that the socket option isn't only used/useful for VRFs and created a new PR for this.
See https://github.com/OpenVPN/openvpn/pull/65
This basicly does the same thing - specify the bind-device and allows implementing this for more platforms. I added code for FreeBSD but I couldn't test this as I don't have a BSD machine available.
Quoted 6 lines
The rational why the option is called outer-vrf is that, one might want to add one for the inner-vrf, when the tun/tap interface should be part of a VRF. As this could be easily done in an ifup-script I didn't bother adding this for now.
I'd be glad if this would be accepted.
Best
Max
Signature · 3 lines
The real problem with C++ for kernel modules is: the language just sucks. -- Linus Torvalds
PATCH 1/1 Allow to specify bind interface for outbound/inbound connections
Anno domini 2016 Maximilian Wilhelm scripsit:
Quoted 27 lines
Anno domini 2016 Maximilian Wilhelm scripsit:
Hi again,
Quoted 11 lines
I'm rolling out Linux VRFs[0] in my network and pushed all my external connections in a VRF, so nothing bad[tm] can happen.
Doing so broke my OpenVPN connections between network nodes, as I kind of expected.
I tried using the --bind option to let OpenVPN bind to the external IP for make a connection, but that doesn't work as the IP isn't resolvable via the main kernel routing table, as it's only visible within the VRFs routing table.
Quoted 7 lines
So I tried pushing the OpenVPN socket into the VRF and that worked fine.
I massaged that into a --outer-vrf option where a user could specify the VRF device. This can be found in
I just learned that it would be easy to make this more generic and that the socket option isn't only used/useful for VRFs and created a new PR for this.
Quoted 12 lines
See https://github.com/OpenVPN/openvpn/pull/65
This basicly does the same thing - specify the bind-device and allows implementing this for more platforms. I added code for FreeBSD but I couldn't test this as I don't have a BSD machine available.
Quoted 6 lines
The rational why the option is called outer-vrf is that, one might want to add one for the inner-vrf, when the tun/tap interface should be part of a VRF. As this could be easily done in an ifup-script I didn't bother adding this for now.
I'd be glad if this would be accepted.
This has been in production use for some time now and there don't seem to be any problems :)
Can I motivate anyone on commenting on or applying this? :)
Best
Max
commit 1baa7e6782b39ed664eedb9b006728d31e22c07e
Author: Maximilian Wilhelm <[email protected]...> Date: Fri Oct 21 17:05:25 2016 +0200
Add --bind-dev option.
This options allows the user to specify a network device the OpenVPN process should use when making a connection or binding to an address. This translates in setting the SO_BINDTODEVICE option to the corresponding socket (on Linux).
When for example using VRFs on Linux [0] this allows making connections using the non-default VRF and having the tun/tap interface in the default VRF.
It seems FreeBSD does not support the SO_BINDTODEVICE socket option, but has a similar one called IP_SENDIF. As I don't have any BSD running, this part is untested.
Thanks to David Ahern (Cumulus Networks) for insights on this.
src/openvpn/init.c +2 -1
@@ -2856,7 +2856,8 @@ do_init_socket_1 (struct context *c, const int mode) c->options.sndbuf, c->options.mark, &c->c2.server_poll_interval, - sockflags); + sockflags, + c->options.bind_dev); }/*
src/openvpn/options.c +9 -0
@@ -167,6 +167,8 @@ static const char usage_message[] =" or --socks-proxy" " is used).\n" "--nobind : Do not bind to local address and port.\n" +"--bind-dev dev : Bind to the given device when making connection to a peer or\n" +" listening for connections\n" "--dev tunX|tapX : tun/tap device (X can be omitted for dynamic device.\n" "--dev-type dt : Which device type are we using? (dt = tun or tap) Use\n" " this option only if the tun/tap device used with --dev\n"
@@ -5128,6 +5130,13 @@ add_option (struct options *options,msg (msglevel,"unknown socket flag: %s" , p[j]); } } +#ifdef TARGET_LINUX + else if (streq (p[0], "bind-dev") && p[1]) + { +VERIFY_PERMISSION (OPT_P_SOCKFLAGS ); + options->bind_dev = p[1 ]; + } +#endif else if (streq (p[0], "txqueuelen") && p[1] && !p[2]) {VERIFY_PERMISSION (OPT_P_GENERAL );
src/openvpn/options.h +1 -0
@@ -325,6 +325,7 @@ struct options/* socket flags */ unsigned int sockflags; +char *bind_dev;/* route management */ const char *route_script;
src/openvpn/socket.c +12 -1
@@ -868,6 +868,15 @@ create_socket (struct link_socket* sock, struct addrinfo* addr)/* set socket to --mark packets with given value */ socket_set_mark (sock->sd, sock->mark); +if (sock->bind_dev) + { +#if defined(TARGET_LINUX ) +setsockopt (sock->sd,SOL_SOCKET ,SO_BINDTODEVICE , sock->bind_dev,strlen (sock->bind_dev) +1 ); +#elif defined(TARGET_FREEBSD ) +setsockopt (fd,SOL_SOCKET ,IP_SENDIF , sock->bind_dev,strlen (sock->bind_dev) +1 ); +#endif + } +bind_local (sock, addr->ai_family); }
@@ -1525,7 +1534,8 @@ link_socket_init_phase1 (struct link_socket *sock,int sndbuf, int mark, struct event_timeout* server_poll_timeout, - unsigned int sockflags) + unsigned int sockflags, + const char *bind_dev) {ASSERT (sock );
@@ -1550,6 +1560,7 @@ link_socket_init_phase1 (struct link_socket *sock, sock->sockflags = sockflags; sock->mark = mark; + sock->bind_dev = bind_dev; sock->info.proto = proto; sock->info.af = af;
src/openvpn/socket.h +3 -1
@@ -213,6 +213,7 @@ struct link_socket# define SF_GETADDRINFO_DGRAM (1<<4)unsigned int sockflags;int mark; +char *bind_dev;/* for stream sockets */ struct stream_buf stream_buf;
@@ -327,7 +328,8 @@ link_socket_init_phase1 (struct link_socket *sock,int sndbuf, int mark, struct event_timeout* server_poll_timeout, - unsigned int sockflags); + unsigned int sockflags, + const char *bind_dev); void link_socket_init_phase2 (struct link_socket *sock, const struct frame *frame,
Signature · 4 lines
"First they ignore you, then they laugh at you, then they fight you, then you win." -- Mahatma Gandhi
Re: [Openvpn-devel] [PATCH] Allow to specify bind interface for outbound/inbound connections
Hi,
Quoted 1 line · Maximilian Wilhelm
Can I motivate anyone on commenting on or applying this? :)
You're keeping me busy on multiple fronts :-9 - and since this is networking, it's mostly me who gets to review this.
What's complicating this is that it's also "infrastructure work" (as in lying the groundworks for a new class of system-dependent features) so we should get it right. "Bug fix" is much easier to review ("reproduce, apply, see it fixes the bug, done").
Not forgotten, though.
gert
Signature · 4 lines
USENET is *not* the non-clickable part of WWW!
//www.muc.de/~gert/
Gert Doering - Munich, Germany [email protected]...
fax: +49-89-35655025 [email protected]...Re: [Openvpn-devel] [PATCH] Allow to specify bind interface for outbound/inbound connections
Anno domini 2016 Gert Doering scripsit:
Hi Gert, *
Quoted 6 lines · Maximilian Wilhelm
Quoted 1 line
Can I motivate anyone on commenting on or applying this? :)
You're keeping me busy on multiple fronts :-9 - and since this is networking, it's mostly me who gets to review this.
Quoted 6 lines
What's complicating this is that it's also "infrastructure work" (as in lying the groundworks for a new class of system-dependent features) so we should get it right. "Bug fix" is much easier to review ("reproduce, apply, see it fixes the bug, done").
Not forgotten, though.
Any thoughs on this in the meantime? :-)
Best
Max
Signature · 3 lines
"I have to admit I've always suspected that MTBWTF would be a more useful metric of real-world performance." -- Valdis Kletnieks on NANOG
Re: [Openvpn-devel] [PATCH] Allow to specify bind interface for outbound/inbound connections
In reply to Maximilian WilhelmA quick from me.
Quoted 37 lines
This has been in production use for some time now and there don't seem to be any problems :)
Can I motivate anyone on commenting on or applying this? :)
Best
Maxcommit
1baa7e6782b39ed664eedb9b006728d31e22c07eAuthor: Maximilian Wilhelm <[email protected]...> Date: Fri Oct 21 17:05:25 2016 +0200Add --bind-dev option.
This options allows the user to specify a network device the OpenVPN process should use when making a connection or binding to an address. This translates in setting the
SO_BINDTODEVICEoption to the corresponding socket (on Linux).When for example using VRFs on Linux [0] this allows making connections using the non-default VRF and having the tun/tap interface in the default VRF.
It seems FreeBSD does not support the
SO_BINDTODEVICEsocket option, but has a similar one calledIP_SENDIF. As I don't have any BSD running, this part is untested.Thanks to David Ahern (Cumulus Networks) for insights on this.
Signed-off-by Maximilian Wilhelm <[email protected]...>src/openvpn/init.c +0
-0
src/openvpn/init.c do_init_socket_1 (struct context *c, const int mode) · line 2861
Quoted 7 lines
src/openvpn/init.c +2
-1@@ -2856,7 +2856,8 @@ do_init_socket_1 (struct context *c, const int mode) c->options.sndbuf, c->options.mark, &c->c2.server_poll_interval, - sockflags); + sockflags, + c->options.bind_dev); }
Should be after the after c->options options.
Quoted 16 lines
src/openvpn/init.c +0
-0/* src/openvpn/options.c +2
-0@@ -167,6 +167,8 @@ static const char usage_message[] =" or --socks-proxy" " is used).\n" "--nobind : Do not bind to local address and port.\n" +"--bind-dev dev : Bind to the given device when making connection to a peer or\n" +" listening for connections\n" "--dev tunX|tapX : tun/tap device (X can be omitted for dynamic device.\n" "--dev-type dt : Which device type are we using? (dt = tun or tap) Use\n" " this option only if the tun/tap device used with --dev\n"
src/openvpn/options.c add_option (struct options *options, · line 5139
Quoted 10 lines
src/openvpn/options.c +7
-0@@ -5128,6 +5130,13 @@ add_option (struct options *options,msg (msglevel,"unknown socket flag: %s" , p[j]); } } +#ifdef TARGET_LINUX + else if (streq (p[0], "bind-dev") && p[1]) + { +VERIFY_PERMISSION (OPT_P_SOCKFLAGS ); + options->bind_dev = p[1 ]; + } +#endif
Better use something like HAVE_BIND_TO_DEVICE or similar. Your define also misses FREEBSD here.
Quoted 22 lines
src/openvpn/options.c +0
-0else if (streq (p[0 ],"txqueuelen" ) && p[1 ] && !p[2 ]) {VERIFY_PERMISSION (OPT_P_GENERAL );src/openvpn/options.h +1
-0@@ -325,6 +325,7 @@ struct options/* socket flags */ unsigned int sockflags; +char *bind_dev;/* route management */ const char *route_script;src/openvpn/socket.c +0
-0@@ -868,6 +868,15 @@ create_socket (struct link_socket* sock, struct addrinfo* addr)/* set socket to --mark packets with given value */ socket_set_mark (sock->sd, sock->mark);
src/openvpn/socket.c create_socket (struct link_socket* sock, struct addrinfo* addr) · line 879
Quoted 10 lines
src/openvpn/socket.c +9
-0+if (sock->bind_dev) + { +#if defined(TARGET_LINUX ) +setsockopt (sock->sd,SOL_SOCKET ,SO_BINDTODEVICE , sock->bind_dev,strlen (sock->bind_dev) +1 ); +#elif defined(TARGET_FREEBSD ) +setsockopt (fd,SOL_SOCKET ,IP_SENDIF , sock->bind_dev,strlen (sock->bind_dev) +1 ); +#endif + } +
The +1 looks strange. A comment why this has to be +1.
I cannot find that IP_SENDIF in any freebsd man page or /usr/include on a 10.3 system. I don't think this option exists.
Quoted 44 lines
src/openvpn/socket.c +3
-1bind_local (sock, addr->ai_family); }@@ -1525,7 +1534,8 @@ link_socket_init_phase1 (struct link_socket *sock,int sndbuf, int mark, struct event_timeout* server_poll_timeout, - unsigned int sockflags) + unsigned int sockflags, + const char *bind_dev) {ASSERT (sock );@@ -1550,6 +1560,7 @@ link_socket_init_phase1 (struct link_socket *sock, sock->sockflags = sockflags; sock->mark = mark; + sock->bind_dev = bind_dev; sock->info.proto = proto; sock->info.af = af;src/openvpn/socket.h +3
-1@@ -213,6 +213,7 @@ struct link_socket# define SF_GETADDRINFO_DGRAM (1<<4)unsigned int sockflags;int mark; +char *bind_dev;/* for stream sockets */ struct stream_buf stream_buf;@@ -327,7 +328,8 @@ link_socket_init_phase1 (struct link_socket *sock,int sndbuf, int mark, struct event_timeout* server_poll_timeout, - unsigned int sockflags); + unsigned int sockflags, + const char *bind_dev); void link_socket_init_phase2 (struct link_socket *sock, const struct frame *frame,
Re: [Openvpn-devel] [PATCH] Allow to specify bind interface for outbound/inbound connections
Anno domini 2017 Arne Schwabe scripsit:
Quoted 1 line
A quick from me.
Cool, thanks.
Quoted 6 lines
Quoted 6 lines
src/openvpn/init.c +0
-0@@ -2856,7 +2856,8 @@ do_init_socket_1 (struct context *c, const int mode) c->options.sndbuf,
Quoted 8 lines
src/openvpn/init.c do_init_socket_1 (struct context *c, const int mode) · line 2861
Quoted 6 lines
src/openvpn/init.c +2
-1c->options.mark, &c->c2.server_poll_interval, - sockflags); + sockflags, + c->options.bind_dev); }Should be after the after
c->optionsoptions.
Ok, will reorder.
Quoted 19 lines
Quoted 19 lines
src/openvpn/init.c +0
-0/* src/openvpn/options.c +3
-0@@ -167,6 +167,8 @@ static const char usage_message[] =" or --socks-proxy" " is used).\n" "--nobind : Do not bind to local address and port.\n" +"--bind-dev dev : Bind to the given device when making connection to a peer or\n" +" listening for connections\n" "--dev tunX|tapX : tun/tap device (X can be omitted for dynamic device.\n" "--dev-type dt : Which device type are we using? (dt = tun or tap) Use\n" " this option only if the tun/tap device used with --dev\n" @@ -5128,6 +5130,13 @@ add_option (struct options *options,msg (msglevel,"unknown socket flag: %s" , p[j]); } } +#ifdef TARGET_LINUX
Quoted 8 lines
src/openvpn/options.c add_option (struct options *options, · line 5139
Quoted 6 lines
src/openvpn/options.c +6
-0+ else if (streq (p[0], "bind-dev") && p[1]) + { +VERIFY_PERMISSION (OPT_P_SOCKFLAGS ); + options->bind_dev = p[1 ]; + } +#endif Better use something like
HAVE_BIND_TO_DEVICEor similar. Your define also misses FREEBSD here.
Should this really get an extra define for this feature? I see the FREEBSD point, though.
Quoted 23 lines
Quoted 23 lines
src/openvpn/options.c +0
-0else if (streq (p[0 ],"txqueuelen" ) && p[1 ] && !p[2 ]) {VERIFY_PERMISSION (OPT_P_GENERAL );src/openvpn/options.h +1
-0@@ -325,6 +325,7 @@ struct options/* socket flags */ unsigned int sockflags; +char *bind_dev;/* route management */ const char *route_script;src/openvpn/socket.c +0
-0@@ -868,6 +868,15 @@ create_socket (struct link_socket* sock, struct addrinfo* addr)/* set socket to --mark packets with given value */ socket_set_mark (sock->sd, sock->mark);
Quoted 10 lines
src/openvpn/socket.c create_socket (struct link_socket* sock, struct addrinfo* addr) · line 879
Quoted 9 lines
src/openvpn/socket.c +9
-0+if (sock->bind_dev) + { +#if defined(TARGET_LINUX ) +setsockopt (sock->sd,SOL_SOCKET ,SO_BINDTODEVICE , sock->bind_dev,strlen (sock->bind_dev) +1 ); +#elif defined(TARGET_FREEBSD ) +setsockopt (fd,SOL_SOCKET ,IP_SENDIF , sock->bind_dev,strlen (sock->bind_dev) +1 ); +#endif + } +The +1 looks strange. A comment why this has to be +1.
That's stolen from the upstream documentation:
Quoted 2 lines
I cannot find that
IP_SENDIFin any freebsd man page or/usr/includeon a 10.3 system. I don't think this option exists.
I just googled for this part as I don't have any BSD-ish machines here. That part is purely theoretical, that's why I asked for testers :)
If this turns out to be wrong I'd just remove this. My understanding on what I found on the net was that this would have the same effect as the Linux version so I considered it worth a try.
Best
Max
Signature · 1 line
Friends are relatives you make for yourself.
Re: [Openvpn-devel] [PATCH] Allow to specify bind interface for outbound/inbound connections
Anno domini 2017 Maximilian Wilhelm scripsit:
Hi,
for the record:
I've updated the PR on github and addressed the issues raised here before.
-> https://github.com/OpenVPN/openvpn/pull/65#issuecomment-330715591
The point remaining is the support for FreeBSD:
[...]
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
src/openvpn/socket.c +8
-0+if (sock->bind_dev) + { +#if defined(TARGET_LINUX ) +setsockopt (sock->sd,SOL_SOCKET ,SO_BINDTODEVICE , sock->bind_dev,strlen (sock->bind_dev) +1 ); +#elif defined(TARGET_FREEBSD ) +setsockopt (fd,SOL_SOCKET ,IP_SENDIF , sock->bind_dev,strlen (sock->bind_dev) +1 ); +#endif + }
[...]
Quoted 9 lines
Quoted 2 lines
I cannot find that
IP_SENDIFin any freebsd man page or/usr/includeon a 10.3 system. I don't think this option exists.I just googled for this part as I don't have any BSD-ish machines here. That part is purely theoretical, that's why I asked for testers :)
If this turns out to be wrong I'd just remove this. My understanding on what I found on the net was that this would have the same effect as the Linux version so I considered it worth a try.
As discussed within the PR, https://wiki.freebsd.org/Networking still references IP_SENDIF, so it seems to at least have existed some time in the past.
Can anyone shed some more light on this part?
Best
Max
Signature · 3 lines
"I have to admit I've always suspected that MTBWTF would be a more useful metric of real-world performance." -- Valdis Kletnieks on NANOG