kernel-netlink: Use address labels instead of deprecation for IPv6 virtual IPs

In order to avoid that the kernel uses virtual tunnel IPs for traffic
over physical interfaces we previously deprecated the virtual IP.  While
this is working it is not ideal.  This patch adds address labels for
virtual IPs, which should force the kernel to avoid such addresses to
reach any destination unless there is an explicit route that uses it as
source address.
This commit is contained in:
Tobias Brunner
2019-03-14 11:33:59 +01:00
parent b4a23e3cea
commit 00a953d090
@@ -41,6 +41,7 @@
#include <sys/utsname.h> #include <sys/utsname.h>
#include <linux/netlink.h> #include <linux/netlink.h>
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <linux/if_addrlabel.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#include <net/if.h> #include <net/if.h>
@@ -2335,6 +2336,46 @@ METHOD(kernel_net_t, create_local_subnet_enumerator, enumerator_t*,
return &enumerator->public; return &enumerator->public;
} }
/**
* Manages the creation and deletion of IPv6 address labels for virtual IPs.
* By setting the appropriate nlmsg_type the label is either added or removed.
*/
static status_t manage_addrlabel(private_kernel_netlink_net_t *this,
int nlmsg_type, host_t *ip)
{
netlink_buf_t request;
struct nlmsghdr *hdr;
struct ifaddrlblmsg *msg;
chunk_t chunk;
uint32_t label;
memset(&request, 0, sizeof(request));
chunk = ip->get_address(ip);
hdr = &request.hdr;
hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
if (nlmsg_type == RTM_NEWADDRLABEL)
{
hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
}
hdr->nlmsg_type = nlmsg_type;
hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrlblmsg));
msg = NLMSG_DATA(hdr);
msg->ifal_family = ip->get_family(ip);
msg->ifal_prefixlen = chunk.len * 8;
netlink_add_attribute(hdr, IFAL_ADDRESS, chunk, sizeof(request));
/* doesn't really matter as default labels are < 20 but this makes it kinda
* recognizable */
label = 220;
netlink_add_attribute(hdr, IFAL_LABEL, chunk_from_thing(label),
sizeof(request));
return this->socket->send_ack(this->socket, hdr);
}
/** /**
* Manages the creation and deletion of ip addresses on an interface. * Manages the creation and deletion of ip addresses on an interface.
* By setting the appropriate nlmsg_type, the ip will be set or unset. * By setting the appropriate nlmsg_type, the ip will be set or unset.
@@ -2372,16 +2413,24 @@ static status_t manage_ipaddr(private_kernel_netlink_net_t *this, int nlmsg_type
#endif #endif
if (this->rta_prefsrc_for_ipv6) if (this->rta_prefsrc_for_ipv6)
{ {
/* if source routes are possible we let the virtual IP get /* if source routes are possible we set a label for this virtual IP
* deprecated immediately (but mark it as valid forever) so it gets * so it gets only used if forced by our route, and not by the
* only used if forced by our route, and not by the default IPv6 * default IPv6 address selection */
* address selection */ int labelop = nlmsg_type == RTM_NEWADDR ? RTM_NEWADDRLABEL
struct ifa_cacheinfo cache = { : RTM_DELADDRLABEL;
.ifa_valid = 0xFFFFFFFF, if (manage_addrlabel(this, labelop, ip) != SUCCESS)
.ifa_prefered = 0, {
}; /* if we can't use address labels we let the virtual IP get
netlink_add_attribute(hdr, IFA_CACHEINFO, chunk_from_thing(cache), * deprecated immediately (but mark it as valid forever), which
sizeof(request)); * should also avoid that it gets used by the default address
* selection */
struct ifa_cacheinfo cache = {
.ifa_valid = 0xFFFFFFFF,
.ifa_prefered = 0,
};
netlink_add_attribute(hdr, IFA_CACHEINFO,
chunk_from_thing(cache), sizeof(request));
}
} }
} }
return this->socket->send_ack(this->socket, hdr); return this->socket->send_ack(this->socket, hdr);