diff options
author | Yves-Alexis Perez <corsac@corsac.net> | 2017-04-01 16:26:44 +0200 |
---|---|---|
committer | Yves-Alexis Perez <corsac@corsac.net> | 2017-04-01 16:26:44 +0200 |
commit | 05ddd767992d68bb38c7f16ece142e8c2e9ae016 (patch) | |
tree | 302c618be306d4ed3c7f9fc58a1f6aaad4dd252f /src/libcharon/plugins/kernel_pfroute | |
parent | 25663e04c3ab01ef8dc9f906608282319cfea2db (diff) | |
download | vyos-strongswan-05ddd767992d68bb38c7f16ece142e8c2e9ae016.tar.gz vyos-strongswan-05ddd767992d68bb38c7f16ece142e8c2e9ae016.zip |
New upstream version 5.5.2
Diffstat (limited to 'src/libcharon/plugins/kernel_pfroute')
-rw-r--r-- | src/libcharon/plugins/kernel_pfroute/Makefile.in | 2 | ||||
-rw-r--r-- | src/libcharon/plugins/kernel_pfroute/kernel_pfroute_net.c | 197 |
2 files changed, 197 insertions, 2 deletions
diff --git a/src/libcharon/plugins/kernel_pfroute/Makefile.in b/src/libcharon/plugins/kernel_pfroute/Makefile.in index fb1520d90..1e4b3e207 100644 --- a/src/libcharon/plugins/kernel_pfroute/Makefile.in +++ b/src/libcharon/plugins/kernel_pfroute/Makefile.in @@ -360,7 +360,6 @@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ -h_plugins = @h_plugins@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ @@ -395,6 +394,7 @@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ +p_plugins = @p_plugins@ pcsclite_CFLAGS = @pcsclite_CFLAGS@ pcsclite_LIBS = @pcsclite_LIBS@ pdfdir = @pdfdir@ diff --git a/src/libcharon/plugins/kernel_pfroute/kernel_pfroute_net.c b/src/libcharon/plugins/kernel_pfroute/kernel_pfroute_net.c index 236e3417f..efcf1c2a7 100644 --- a/src/libcharon/plugins/kernel_pfroute/kernel_pfroute_net.c +++ b/src/libcharon/plugins/kernel_pfroute/kernel_pfroute_net.c @@ -15,6 +15,7 @@ #include <sys/types.h> #include <sys/socket.h> +#include <sys/sysctl.h> #include <net/if.h> #include <net/if_dl.h> #include <ifaddrs.h> @@ -1448,7 +1449,8 @@ static status_t manage_route(private_kernel_pfroute_net_t *this, int op, } break; case RTAX_GATEWAY: - if (gateway) + if (gateway && + gateway->get_family(gateway) == dst->get_family(dst)) { add_rt_addr(&msg.hdr, RTA_GATEWAY, gateway); } @@ -1704,6 +1706,198 @@ METHOD(kernel_net_t, get_nexthop, host_t*, } /** + * Get the number of set bits in the given netmask + */ +static uint8_t sockaddr_to_netmask(sockaddr_t *sockaddr, host_t *dst) +{ + uint8_t len = 0, i, byte, mask = 0; + struct sockaddr_storage ss; + char *addr; + + /* at least some older FreeBSD versions send us shorter sockaddrs + * with the family set to -1 (255) */ + if (sockaddr->sa_family == 255) + { + memset(&ss, 0, sizeof(ss)); + memcpy(&ss, sockaddr, sockaddr->sa_len); + /* use the address family and length of the destination as hint */ + ss.ss_len = *dst->get_sockaddr_len(dst); + ss.ss_family = dst->get_family(dst); + sockaddr = (sockaddr_t*)&ss; + } + + switch (sockaddr->sa_family) + { + case AF_INET: + len = 4; + addr = (char*)&((struct sockaddr_in*)sockaddr)->sin_addr; + break; + case AF_INET6: + len = 16; + addr = (char*)&((struct sockaddr_in6*)sockaddr)->sin6_addr; + break; + default: + break; + } + + for (i = 0; i < len; i++) + { + byte = addr[i]; + + if (byte == 0x00) + { + break; + } + if (byte == 0xff) + { + mask += 8; + } + else + { + while (byte & 0x80) + { + mask++; + byte <<= 1; + } + } + } + return mask; +} + +/** enumerator over subnets */ +typedef struct { + enumerator_t public; + /** sysctl result */ + char *buf; + /** length of the complete result */ + size_t len; + /** start of the current route entry */ + char *current; + /** last subnet enumerated */ + host_t *net; + /** interface of current net */ + char *ifname; +} subnet_enumerator_t; + +METHOD(enumerator_t, destroy_subnet_enumerator, void, + subnet_enumerator_t *this) +{ + DESTROY_IF(this->net); + free(this->ifname); + free(this->buf); + free(this); +} + +METHOD(enumerator_t, enumerate_subnets, bool, + subnet_enumerator_t *this, host_t **net, uint8_t *mask, char **ifname) +{ + enumerator_t *enumerator; + struct rt_msghdr *rtm; + struct sockaddr *addr; + int type; + + if (!this->current) + { + this->current = this->buf; + } + else + { + rtm = (struct rt_msghdr*)this->current; + this->current += rtm->rtm_msglen; + DESTROY_IF(this->net); + this->net = NULL; + free(this->ifname); + this->ifname = NULL; + } + + for (; this->current < this->buf + this->len; + this->current += rtm->rtm_msglen) + { + struct sockaddr *netmask; + uint8_t netbits = 0; + + rtm = (struct rt_msghdr*)this->current; + + if (rtm->rtm_version != RTM_VERSION) + { + continue; + } + if (rtm->rtm_flags & RTF_GATEWAY || + rtm->rtm_flags & RTF_HOST || + rtm->rtm_flags & RTF_REJECT) + { + continue; + } + enumerator = create_rtmsg_enumerator(rtm); + while (enumerator->enumerate(enumerator, &type, &addr)) + { + if (type == RTAX_DST) + { + this->net = this->net ?: host_create_from_sockaddr(addr); + } + if (type == RTAX_NETMASK) + { + netmask = addr; + } + if (type == RTAX_IFP && addr->sa_family == AF_LINK) + { + struct sockaddr_dl *sdl = (struct sockaddr_dl*)addr; + free(this->ifname); + this->ifname = strndup(sdl->sdl_data, sdl->sdl_nlen); + } + } + if (this->net) + { + netbits = sockaddr_to_netmask(netmask, this->net); + } + enumerator->destroy(enumerator); + + if (this->net && this->ifname) + { + *net = this->net; + *mask = netbits ?: this->net->get_address(this->net).len * 8; + *ifname = this->ifname; + return TRUE; + } + } + return FALSE; +} + +METHOD(kernel_net_t, create_local_subnet_enumerator, enumerator_t*, + private_kernel_pfroute_net_t *this) +{ + subnet_enumerator_t *enumerator; + char *buf; + size_t len; + int mib[7] = { + CTL_NET, PF_ROUTE, 0, AF_UNSPEC, NET_RT_DUMP, 0, 0 + }; + + if (sysctl(mib, countof(mib), NULL, &len, NULL, 0) < 0) + { + DBG2(DBG_KNL, "enumerating local subnets failed"); + return enumerator_create_empty(); + } + buf = malloc(len); + if (sysctl(mib, countof(mib), buf, &len, NULL, 0) < 0) + { + DBG2(DBG_KNL, "enumerating local subnets failed"); + free(buf); + return enumerator_create_empty(); + } + + INIT(enumerator, + .public = { + .enumerate = (void*)_enumerate_subnets, + .destroy = _destroy_subnet_enumerator, + }, + .buf = buf, + .len = len, + ); + return &enumerator->public; +} + +/** * Initialize a list of local addresses. */ static status_t init_address_list(private_kernel_pfroute_net_t *this) @@ -1848,6 +2042,7 @@ kernel_pfroute_net_t *kernel_pfroute_net_create() .get_features = _get_features, .get_interface = _get_interface_name, .create_address_enumerator = _create_address_enumerator, + .create_local_subnet_enumerator = _create_local_subnet_enumerator, .get_source_addr = _get_source_addr, .get_nexthop = _get_nexthop, .add_ip = _add_ip, |