From acc042fa7b971b043ca2705a5428772299d6399f Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 25 Apr 2014 11:28:52 +0200 Subject: [PATCH] tun-device: Use SIOCAIFADDR to set IP address on FreeBSD 10 FreeBSD 10 deprecated the SIOCSIFADDR etc. commands, so we use this newer command to set the address and netmask. A destination address is now also required. Fixes #566. --- src/libstrongswan/networking/tun_device.c | 92 ++++++++++++++++++++++++++++++- 1 file changed, 90 insertions(+), 2 deletions(-) diff --git a/src/libstrongswan/networking/tun_device.c b/src/libstrongswan/networking/tun_device.c index ecefdc2..f2c7b16 100644 --- a/src/libstrongswan/networking/tun_device.c +++ b/src/libstrongswan/networking/tun_device.c @@ -50,6 +50,10 @@ tun_device_t *tun_device_create(const char *name_tmpl) #elif defined(__linux__) #include #include +#elif __FreeBSD__ >= 10 +#include +#include +#include #else #include #endif @@ -101,8 +105,79 @@ struct private_tun_device_t { u_int8_t netmask; }; -METHOD(tun_device_t, set_address, bool, - private_tun_device_t *this, host_t *addr, u_int8_t netmask) +/** + * FreeBSD 10 deprecated the SIOCSIFADDR etc. commands. + */ +#if __FreeBSD__ >= 10 + +static bool set_address_and_mask(struct in_aliasreq *ifra, host_t *addr, + u_int8_t netmask) +{ + host_t *mask; + + memcpy(&ifra->ifra_addr, addr->get_sockaddr(addr), + *addr->get_sockaddr_len(addr)); + /* set the same address as destination address */ + memcpy(&ifra->ifra_dstaddr, addr->get_sockaddr(addr), + *addr->get_sockaddr_len(addr)); + + mask = host_create_netmask(addr->get_family(addr), netmask); + if (!mask) + { + DBG1(DBG_LIB, "invalid netmask: %d", netmask); + return FALSE; + } + memcpy(&ifra->ifra_mask, mask->get_sockaddr(mask), + *mask->get_sockaddr_len(mask)); + mask->destroy(mask); + return TRUE; +} + +/** + * Set the address using the more flexible SIOCAIFADDR/SIOCDIFADDR commands + * on FreeBSD 10 an newer. + */ +static bool set_address_impl(private_tun_device_t *this, host_t *addr, + u_int8_t netmask) +{ + struct in_aliasreq ifra; + + memset(&ifra, 0, sizeof(ifra)); + strncpy(ifra.ifra_name, this->if_name, IFNAMSIZ); + + if (this->address) + { /* remove the existing address first */ + if (!set_address_and_mask(&ifra, this->address, this->netmask)) + { + return FALSE; + } + if (ioctl(this->sock, SIOCDIFADDR, &ifra) < 0) + { + DBG1(DBG_LIB, "failed to remove existing address on %s: %s", + this->if_name, strerror(errno)); + return FALSE; + } + } + if (!set_address_and_mask(&ifra, addr, netmask)) + { + return FALSE; + } + if (ioctl(this->sock, SIOCAIFADDR, &ifra) < 0) + { + DBG1(DBG_LIB, "failed to add address on %s: %s", + this->if_name, strerror(errno)); + return FALSE; + } + return TRUE; +} + +#else /* __FreeBSD__ */ + +/** + * Set the address using the classic SIOCSIFADDR etc. commands on other systems. + */ +static bool set_address_impl(private_tun_device_t *this, host_t *addr, + u_int8_t netmask) { struct ifreq ifr; host_t *mask; @@ -143,6 +218,19 @@ METHOD(tun_device_t, set_address, bool, this->if_name, strerror(errno)); return FALSE; } + return TRUE; +} + +#endif /* __FreeBSD__ */ + +METHOD(tun_device_t, set_address, bool, + private_tun_device_t *this, host_t *addr, u_int8_t netmask) +{ + if (!set_address_impl(this, addr, netmask)) + { + return FALSE; + } + DESTROY_IF(this->address); this->address = addr->clone(addr); this->netmask = netmask; return TRUE; -- 2.7.4