aboutgitcodebugslistschat
diff options
context:
space:
mode:
-rw-r--r--conf.c4
-rw-r--r--netlink.c62
2 files changed, 40 insertions, 26 deletions
diff --git a/conf.c b/conf.c
index 644752c..9e0318a 100644
--- a/conf.c
+++ b/conf.c
@@ -584,7 +584,7 @@ static unsigned int conf_ip4(unsigned int ifi,
ifi = nl_get_ext_if(nl_sock, AF_INET);
if (!ifi) {
- info("No interface with a route for IPv4: disabling IPv4");
+ info("Couldn't pick external interface: disabling IPv4");
return 0;
}
@@ -656,7 +656,7 @@ static unsigned int conf_ip6(unsigned int ifi,
ifi = nl_get_ext_if(nl_sock, AF_INET6);
if (!ifi) {
- info("No interface with a route for IPv6: disabling IPv6");
+ info("Couldn't pick external interface: disabling IPv6");
return 0;
}
diff --git a/netlink.c b/netlink.c
index 632304c..9b3dba2 100644
--- a/netlink.c
+++ b/netlink.c
@@ -254,8 +254,8 @@ 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;
+ unsigned defifi = 0, anyifi = 0;
+ unsigned ndef = 0, nany = 0;
struct nlmsghdr *nh;
struct rtattr *rta;
char buf[NLBUFSIZ];
@@ -263,7 +263,6 @@ 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.
@@ -271,46 +270,61 @@ again:
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);
+ unsigned thisifi = 0;
- if (default_only) {
- if (ifi || rtm->rtm_dst_len || rtm->rtm_family != af)
- continue;
- } else {
- if (rtm->rtm_family != af)
- continue;
- }
+ 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);
+ thisifi = *(unsigned int *)RTA_DATA(rta);
} else if (rta->rta_type == RTA_MULTIPATH) {
const struct rtnexthop *rtnh;
rtnh = (struct rtnexthop *)RTA_DATA(rta);
+ thisifi = rtnh->rtnh_ifindex;
+ }
+ }
- if (!default_only && ifi &&
- (int)ifi != rtnh->rtnh_ifindex)
- return 0;
+ if (!thisifi)
+ continue; /* No interface for this route */
- ifi = rtnh->rtnh_ifindex;
- }
+ if (rtm->rtm_dst_len == 0) {
+ /* Default route */
+ ndef++;
+ if (!defifi)
+ defifi = thisifi;
+ } else {
+ /* Non-default route */
+ nany++;
+ if (!anyifi)
+ anyifi = thisifi;
}
}
if (status < 0)
warn("netlink: RTM_GETROUTE failed: %s", strerror(-status));
- if (!ifi && default_only) {
- default_only = false;
- goto again;
+ if (defifi) {
+ if (ndef > 1)
+ info("Multiple default %s routes, picked first",
+ af == AF_INET ? "IPv4" : "IPv6");
+ return defifi;
}
- return ifi;
+ if (anyifi) {
+ if (nany == 1)
+ return anyifi;
+
+ info("Multiple interfaces with %s routes, use -i to select one",
+ af == AF_INET ? "IPv4" : "IPv6");
+ }
+
+ if (!nany)
+ info("No interfaces with %s routes", af == AF_INET ? "IPv4" : "IPv6");
+
+ return 0;
}
/**