Sorry, comment typo: - /* kernel cat return 0.0.0.0/128 host route */ + /* kernel can return ::/128 host route */
-- Best Regards, Vladislav Grishenko > -----Original Message----- > From: Vladislav Grishenko <themi...@yandex-team.ru> > Sent: Tuesday, September 8, 2020 7:54 AM > To: openvpn-devel@lists.sourceforge.net > Subject: [Openvpn-devel] [PATCH v2] Fix best gateway selection over netlink > > Netlink route request with NLM_F_DUMP flag set means to return all entries > matching criteria passed in message content - matching supplied family & dst > address in our case. > So, gateway from the first ipv4 route was always used. > > On kernels earlier than 2.6.38 default routes are the last ones, so some host/net > route w/o gateway is likely be returned as first, causing gateway to be invalid or > empty. > After refactoring in 2.6.38 kernel first routes are the default (or more specific > 0.0.0.0/n), so it's gateway is usually valid, hiding the problem. > > Fix this behavior by requesting exact route with corresponding full prefix size, > and filter dumped routes against default route /0 if dst was not set. Empty dst is > not valid address, so it's handled as default route request too. > > If there's several default routes dumped with different metrics, the first one will > be less-numbered, so we can stop w/o additional iteration for metric > comparison. > > Tested on 5.4.0, 4.1.51 and 2.6.36 kernels. > > Signed-off-by: Vladislav Grishenko <themi...@yandex-team.ru> > --- > src/openvpn/networking_sitnl.c | 47 +++++++++++++++++++++++++++++----- > 1 file changed, 41 insertions(+), 6 deletions(-) > > diff --git a/src/openvpn/networking_sitnl.c b/src/openvpn/networking_sitnl.c > index 713a213a..81d52710 100644 > --- a/src/openvpn/networking_sitnl.c > +++ b/src/openvpn/networking_sitnl.c > @@ -90,7 +90,7 @@ struct sitnl_route_req { > char buf[256]; > }; > > -typedef int (*sitnl_parse_reply_cb)(struct nlmsghdr *msg, void *arg); > +typedef int (*sitnl_parse_reply_cb)(struct nlmsghdr *req, struct > +nlmsghdr *msg, void *arg); > > /** > * Object returned by route request operation @@ -345,6 +345,13 @@ > sitnl_send(struct nlmsghdr *payload, pid_t peer, unsigned int groups, > * continue; > * } > */ > + > + if (h->nlmsg_type == NLMSG_DONE) > + { > + ret = 0; > + goto out; > + } > + > if (h->nlmsg_type == NLMSG_ERROR) > { > err = (struct nlmsgerr *)NLMSG_DATA(h); @@ -360,7 +367,11 @@ > sitnl_send(struct nlmsghdr *payload, pid_t peer, unsigned int groups, > ret = 0; > if (cb) > { > - ret = cb(h, arg_cb); > + int r = cb(payload, h, arg_cb); > + if (r <= 0) > + { > + ret = r; > + } > } > } > else > @@ -375,8 +386,12 @@ sitnl_send(struct nlmsghdr *payload, pid_t peer, > unsigned int groups, > > if (cb) > { > - ret = cb(h, arg_cb); > - goto out; > + int r = cb(payload, h, arg_cb); > + if (r <= 0) > + { > + ret = r; > + goto out; > + } > } > else > { > @@ -413,14 +428,21 @@ typedef struct { > } route_res_t; > > static int > -sitnl_route_save(struct nlmsghdr *n, void *arg) > +sitnl_route_save(struct nlmsghdr *req, struct nlmsghdr *n, void *arg) > { > route_res_t *res = arg; > + struct rtmsg *q = NLMSG_DATA(req); > struct rtmsg *r = NLMSG_DATA(n); > struct rtattr *rta = RTM_RTA(r); > int len = n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)); > unsigned int ifindex = 0; > > + /* if dumped, filter out non-default routes */ > + if (q->rtm_dst_len == 0 && r->rtm_dst_len) > + { > + return 1; > + } > + > while (RTA_OK(rta, len)) > { > switch (rta->rta_type) > @@ -477,11 +499,24 @@ 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; > + /* > + * kernel can't return 0.0.0.0/32 host route, therefore > + * need to dump all the routes and filter them in cb() > + */ > + if (!dst || dst->ipv4 == htonl(INADDR_ANY)) > + { > + req.n.nlmsg_flags |= NLM_F_DUMP; > + } > + else > + { > + req.r.rtm_dst_len = 32; > + } > break; > > case AF_INET6: > res.addr_size = sizeof(struct in6_addr); > + /* kernel cat return 0.0.0.0/128 host route */ > + req.r.rtm_dst_len = 128; > break; > > default: > -- > 2.17.1 > > > > _______________________________________________ > Openvpn-devel mailing list > Openvpn-devel@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/openvpn-devel _______________________________________________ Openvpn-devel mailing list Openvpn-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/openvpn-devel