[Openvpn-devel] Fix best gateway selection over netlink

Message ID 20200907131734.31164-1-themiron@yandex-team.ru
State Changes Requested
Headers show
Series [Openvpn-devel] Fix best gateway selection over netlink | expand

Commit Message

Vladislav Grishenko Sept. 7, 2020, 3:17 a.m. UTC
Netlink route request with NLM_F_DUMP flag set means to
return all entries matching criteria passed in message
content - matching supplied dst address in our case.
So, gateway from the first returned route was always used
even there were more specific routes present.
By a chance, after route refactoring in ~2.6.38 first route
is the default route, so default gateway was always used,
hiding the problem.
On earlier kernels default route is the last one, so
route w/o gateway is likely be returned as first causes
gateway always to be 0.0.0.0.

Fix this behavior by requesting exact route, not dump along
with specifying correct dst perfix size.

Tested on 5.4.0, 4.1.51 and 2.6.36 kernels.

Signed-off-by: Vladislav Grishenko <themiron@yandex-team.ru>
---
 src/openvpn/networking_sitnl.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

Comments

Gert Doering Sept. 7, 2020, 5:11 a.m. UTC | #1
Hi,

On Mon, Sep 07, 2020 at 06:17:34PM +0500, Vladislav Grishenko wrote:
>      {
>          case AF_INET:
>              res.addr_size = sizeof(in_addr_t);
> -            req.n.nlmsg_flags |= NLM_F_DUMP;
> +            req.r.rtm_dst_len = 32;
>              break;

For the record, this actually doesn't work (long discussion on IRC),
so "NAK, followup patch coming".

Thanks for your work on this.

And perfectly on time to go into beta4 :-)

gert

Patch

diff --git a/src/openvpn/networking_sitnl.c b/src/openvpn/networking_sitnl.c
index 713a213a..150dfa5c 100644
--- a/src/openvpn/networking_sitnl.c
+++ b/src/openvpn/networking_sitnl.c
@@ -477,11 +477,12 @@  sitnl_route_best_gw(sa_family_t af_family, const inet_address_t *dst,
     {
         case AF_INET:
             res.addr_size = sizeof(in_addr_t);
-            req.n.nlmsg_flags |= NLM_F_DUMP;
+            req.r.rtm_dst_len = 32;
             break;
 
         case AF_INET6:
             res.addr_size = sizeof(struct in6_addr);
+            req.r.rtm_dst_len = 128;
             break;
 
         default: