Implement GetDefaultRoute on Linux
This commit is contained in:
parent
f8bf85219b
commit
1a7ba8683e
1 changed files with 92 additions and 3 deletions
|
@ -38,6 +38,7 @@
|
||||||
#include <linux/if.h>
|
#include <linux/if.h>
|
||||||
#include <linux/if_tun.h>
|
#include <linux/if_tun.h>
|
||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
|
#include <linux/rtnetlink.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void SetThreadName(const char *name) {
|
void SetThreadName(const char *name) {
|
||||||
|
@ -149,8 +150,94 @@ static bool GetDefaultRoute(char *iface, size_t iface_size, uint32 *gw_addr) {
|
||||||
#endif // defined(OS_MACOSX) || defined(OS_FREEBSD)
|
#endif // defined(OS_MACOSX) || defined(OS_FREEBSD)
|
||||||
|
|
||||||
#if defined(OS_LINUX)
|
#if defined(OS_LINUX)
|
||||||
|
struct LinuxParsedRoute {
|
||||||
|
int has;
|
||||||
|
struct in_addr dst, gateway;
|
||||||
|
char ifname[IF_NAMESIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool ParseLinuxRoutes(struct nlmsghdr *nl, struct LinuxParsedRoute *result) {
|
||||||
|
struct rtmsg *rt = (struct rtmsg *)NLMSG_DATA(nl);
|
||||||
|
if (rt->rtm_family != AF_INET || rt->rtm_table != RT_TABLE_MAIN)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
struct rtattr *attr = (struct rtattr *)RTM_RTA(rt);
|
||||||
|
int len = RTM_PAYLOAD(nl);
|
||||||
|
int has = 0;
|
||||||
|
for(; RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) {
|
||||||
|
switch(attr->rta_type) {
|
||||||
|
case RTA_OIF:
|
||||||
|
has |= 1;
|
||||||
|
if_indextoname(*(int *)RTA_DATA(attr), result->ifname);
|
||||||
|
break;
|
||||||
|
case RTA_GATEWAY:
|
||||||
|
has |= 2;
|
||||||
|
memcpy(&result->gateway, RTA_DATA(attr), sizeof(result->gateway));
|
||||||
|
break;
|
||||||
|
case RTA_DST:
|
||||||
|
has |= 4;
|
||||||
|
memcpy(&result->dst, RTA_DATA(attr), sizeof(result->dst));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result->has = has;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool GetDefaultRoute(char *iface, size_t iface_size, uint32 *gw_addr) {
|
static bool GetDefaultRoute(char *iface, size_t iface_size, uint32 *gw_addr) {
|
||||||
return false;
|
enum {BUFSIZE = 8192};
|
||||||
|
struct nlmsghdr *nl;
|
||||||
|
struct rtmsg *rt;
|
||||||
|
struct LinuxParsedRoute parsed_route;
|
||||||
|
char buffer[BUFSIZE];
|
||||||
|
int fd, len, pid = getpid();
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
if ((fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
size_t msg_size = NLMSG_SPACE(sizeof(struct rtmsg));
|
||||||
|
memset(buffer, 0, msg_size);
|
||||||
|
nl = (struct nlmsghdr *)buffer;
|
||||||
|
nl->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
||||||
|
nl->nlmsg_type = RTM_GETROUTE;
|
||||||
|
nl->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
|
||||||
|
nl->nlmsg_seq = 1;
|
||||||
|
nl->nlmsg_pid = pid;
|
||||||
|
rt = (struct rtmsg *)NLMSG_DATA(nl);
|
||||||
|
rt->rtm_family = AF_INET;
|
||||||
|
rt->rtm_table = RT_TABLE_MAIN;
|
||||||
|
if (send(fd, nl, msg_size, 0) != msg_size) {
|
||||||
|
RERROR("write to route socket failed");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
if ((len = recv(fd, buffer, BUFSIZE, 0)) < 0) {
|
||||||
|
RERROR("read from route socket failed");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
for (nl = (struct nlmsghdr *)buffer; NLMSG_OK(nl, len); nl = NLMSG_NEXT(nl, len)) {
|
||||||
|
if (nl->nlmsg_seq != 1 || nl->nlmsg_pid != pid)
|
||||||
|
continue;
|
||||||
|
if (nl->nlmsg_type == NLMSG_DONE)
|
||||||
|
goto done;
|
||||||
|
if (nl->nlmsg_type == NLMSG_ERROR) {
|
||||||
|
RERROR("Error in recieved packet");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (ParseLinuxRoutes(nl, &parsed_route) && (parsed_route.has & (1+2+4)) == (1+2)) {
|
||||||
|
size_t l = strlen(parsed_route.ifname);
|
||||||
|
if (l < iface_size) {
|
||||||
|
*gw_addr = ReadBE32(&parsed_route.gateway);
|
||||||
|
memcpy(iface, parsed_route.ifname, l + 1);
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while ((nl->nlmsg_flags & NLM_F_MULTI) != 0);
|
||||||
|
done:
|
||||||
|
close(fd);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
#endif // defined(OS_LINUX)
|
#endif // defined(OS_LINUX)
|
||||||
|
|
||||||
|
@ -367,9 +454,11 @@ static void AddOrRemoveRoute(const RouteInfo &cd, bool remove) {
|
||||||
#if defined(OS_LINUX)
|
#if defined(OS_LINUX)
|
||||||
const char *cmd = remove ? "delete" : "add";
|
const char *cmd = remove ? "delete" : "add";
|
||||||
if (cd.family == AF_INET) {
|
if (cd.family == AF_INET) {
|
||||||
RunCommand("/sbin/route %s -net %s gw %s", cmd, buf1, buf2);
|
const char *net_or_host = (cd.cidr == 32) ? "-host" : "-net";
|
||||||
|
RunCommand("/sbin/route %s %s %s gw %s", cmd, net_or_host, buf1, buf2);
|
||||||
} else {
|
} else {
|
||||||
RunCommand("/sbin/route %s -net inet6 %s gw %s", cmd, buf1, buf2);
|
const char *net_or_host = (cd.cidr == 128) ? "-host" : "-net";
|
||||||
|
RunCommand("/sbin/route %s %s inet6 %s gw %s", cmd, net_or_host, buf1, buf2);
|
||||||
}
|
}
|
||||||
#elif defined(OS_MACOSX) || defined(OS_FREEBSD)
|
#elif defined(OS_MACOSX) || defined(OS_FREEBSD)
|
||||||
const char *cmd = remove ? "delete" : "add";
|
const char *cmd = remove ? "delete" : "add";
|
||||||
|
|
Loading…
Reference in a new issue