rtmon_linux.c revision 1c08b0ec28ca5c600c21c0ab5a53cae73f1c821d
/* -*- indent-tabs-mode: nil; -*- */
#define LOG_GROUP LOG_GROUP_NAT_SERVICE
#include "proxy.h"
#include <linux/rtnetlink.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
/**
* Read IPv6 routing table - Linux rtnetlink version.
*
* XXX: TODO: To avoid re-reading the table we should subscribe to
* updates by binding a monitoring NETLINK_ROUTE socket to
* sockaddr_nl::nl_groups = RTMGRP_IPV6_ROUTE.
*
* But that will provide updates only. Documentation is scarce, but
* from what I've seen it seems that to get accurate routing info the
* monitoring socket needs to be created first, then full routing
* table requested (easier to do via spearate socket), then monitoring
* socket polled for input. The first update(s) of the monitoring
* socket may happen before full table is returned, so we can't just
* count the defaults, we need to keep track of their { oif, gw } to
* correctly ignore updates that are reported via monitoring socket,
* but that are already reflected in the full routing table returned
* in response to our request.
*/
int
rtmon_get_defaults(void)
{
int rtsock;
int ndefrts;
struct {
char attrbuf[512];
} rtreq;
bufsize = 1024;
for (;;) {
char *newbuf;
int recverr;
DPRINTF0(("rtmon: failed to %sallocate buffer\n",
return -1;
}
/* it's easier to reopen than to flush */
if (rtsock < 0) {
return -1;
}
if (nsent < 0) {
return -1;
}
if (ssize < 0) {
DPRINTF(("rtmon: failed to read RTM_GETROUTE response: %s",
return -1;
}
DPRINTF2(("rtmon: RTM_GETROUTE: %lu bytes\n",
(unsigned long)ssize));
break;
}
DPRINTF2(("rtmon: RTM_GETROUTE: truncated %lu to %lu bytes, retrying\n",
/* try again with larger buffer */
}
if (ndefrts == 0) {
DPRINTF(("rtmon: no IPv6 default routes found\n"));
}
else {
DPRINTF(("rtmon: %d IPv6 default route%s found\n",
}
return ndefrts;
}
/**
* Scan netlink message in the buffer for IPv6 default route changes.
*/
static int
{
int dfltdiff = 0;
{
int attrlen;
int delta = 0;
const void *gwbuf;
int oif;
DPRINTF2(("nlmsg type %d flags 0x%x\n",
break;
}
break;
}
/* shouldn't happen */
DPRINTF2(("> not an RTM message!\n"));
continue;
}
delta = +1;
}
delta = -1;
}
else {
/* shouldn't happen */
continue;
}
/*
* Is this an IPv6 default route in the main table? (Local
* table always has ::/0 reject route, hence the last check).
*/
&& rtm->rtm_dst_len == 0
{
}
else {
/* some other route change */
continue;
}
gwlen = 0;
oif = -1;
{
}
/* assert RTA_PAYLOAD(rta) == 4 */
}
}
}
return dfltdiff;
}