diff options
Diffstat (limited to 'netlink.c')
-rw-r--r-- | netlink.c | 31 |
1 files changed, 28 insertions, 3 deletions
@@ -254,6 +254,7 @@ unsigned int nl_get_ext_if(int s, sa_family_t af) .rtm.rtm_type = RTN_UNICAST, .rtm.rtm_family = af, }; + bool default_only = true; unsigned int ifi = 0; struct nlmsghdr *nh; struct rtattr *rta; @@ -262,21 +263,40 @@ unsigned int nl_get_ext_if(int s, sa_family_t af) uint32_t seq; size_t na; +again: + /* Look for an interface with a default route first, failing that, look + * for any interface with a route, and pick it only if it's the only + * interface with a route. + */ seq = nl_send(s, &req, RTM_GETROUTE, NLM_F_DUMP, sizeof(req)); nl_foreach_oftype(nh, status, s, buf, seq, RTM_NEWROUTE) { struct rtmsg *rtm = (struct rtmsg *)NLMSG_DATA(nh); - if (ifi || rtm->rtm_dst_len || rtm->rtm_family != af) - continue; + if (default_only) { + if (ifi || rtm->rtm_dst_len || rtm->rtm_family != af) + continue; + } else { + if (rtm->rtm_family != af) + continue; + } for (rta = RTM_RTA(rtm), na = RTM_PAYLOAD(nh); RTA_OK(rta, na); rta = RTA_NEXT(rta, na)) { if (rta->rta_type == RTA_OIF) { + if (!default_only && ifi && + ifi != *(unsigned int *)RTA_DATA(rta)) + return 0; + ifi = *(unsigned int *)RTA_DATA(rta); } else if (rta->rta_type == RTA_MULTIPATH) { const struct rtnexthop *rtnh; rtnh = (struct rtnexthop *)RTA_DATA(rta); + + if (!default_only && ifi && + (int)ifi != rtnh->rtnh_ifindex) + return 0; + ifi = rtnh->rtnh_ifindex; } } @@ -285,6 +305,11 @@ unsigned int nl_get_ext_if(int s, sa_family_t af) if (status < 0) warn("netlink: RTM_GETROUTE failed: %s", strerror(-status)); + if (!ifi && default_only) { + default_only = false; + goto again; + } + return ifi; } @@ -332,7 +357,7 @@ bool nl_route_get_def_multipath(struct rtattr *rta, void *gw) * @af: Address family * @gw: Default gateway to fill on NL_GET * - * Return: 0 on success, negative error code on failure + * Return: error on netlink failure, or 0 (gw unset if default route not found) */ int nl_route_get_def(int s, unsigned int ifi, sa_family_t af, void *gw) { |