blob: d30aab4f13f509c361136bf01f95c59b5762d5e2 [file] [log] [blame]
/**
* @file bsd/brt.c BSD routing table code
*
* Copyright (C) 2010 Creytiv.com
*/
#include <re_types.h>
#include <re_fmt.h>
#include <re_mem.h>
#include <re_sa.h>
#include <re_net.h>
#include <sys/sysctl.h>
#include <net/route.h>
#include <net/if.h>
/*
* See https://github.com/boundary/libdnet/blob/master/src/route-bsd.c
*/
#ifdef __APPLE__
#define RT_MSGHDR_ALIGNMENT sizeof(uint32_t)
#else
#define RT_MSGHDR_ALIGNMENT sizeof(unsigned long)
#endif
#define ROUNDUP(a) \
((a) > 0 \
? (1 + (((size_t)(a) - 1) | (RT_MSGHDR_ALIGNMENT - 1))) \
: RT_MSGHDR_ALIGNMENT)
int net_rt_list(net_rt_h *rth, void *arg)
{
/* net.route.0.inet.flags.gateway */
int mib[] = {CTL_NET, PF_ROUTE, 0, AF_UNSPEC,
NET_RT_FLAGS, RTF_GATEWAY};
char ifname[IFNAMSIZ], *buf, *p;
struct rt_msghdr *rt;
struct sockaddr *sa, *sa_tab[RTAX_MAX];
struct sa dst, gw;
size_t l;
int i, err = 0;
if (sysctl(mib, sizeof(mib)/sizeof(int), 0, &l, 0, 0) < 0)
return errno;
if (!l)
return ENOENT;
buf = mem_alloc(l, NULL);
if (!buf)
return ENOMEM;
if (sysctl(mib, sizeof(mib)/sizeof(int), buf, &l, 0, 0) < 0) {
err = errno;
goto out;
}
for (p = buf; p<buf+l; p += rt->rtm_msglen) {
rt = (void *)p; /* buffer is aligned */
sa = (struct sockaddr *)(rt + 1);
if (rt->rtm_type != RTM_GET)
continue;
if (!(rt->rtm_flags & RTF_UP))
continue;
for (i=0; i<RTAX_MAX; i++) {
if (rt->rtm_addrs & (1 << i)) {
sa_tab[i] = sa;
sa = (struct sockaddr *)
((char *)sa + ROUNDUP(sa->sa_len));
}
else {
sa_tab[i] = NULL;
}
}
if ((rt->rtm_addrs & RTA_DST) == RTA_DST) {
err = sa_set_sa(&dst, sa_tab[RTAX_DST]);
if (err)
continue;
}
if ((rt->rtm_addrs & RTA_GATEWAY) == RTA_GATEWAY) {
err = sa_set_sa(&gw, sa_tab[RTAX_GATEWAY]);
if (err)
continue;
}
if_indextoname(rt->rtm_index, ifname);
if (rth(ifname, &dst, 0, &gw, arg))
break;
}
out:
mem_deref(buf);
return err;
}