diff options
Diffstat (limited to 'src/libstrongswan/networking/tun_device.c')
-rw-r--r-- | src/libstrongswan/networking/tun_device.c | 124 |
1 files changed, 103 insertions, 21 deletions
diff --git a/src/libstrongswan/networking/tun_device.c b/src/libstrongswan/networking/tun_device.c index ecefdc233..ff2c4a337 100644 --- a/src/libstrongswan/networking/tun_device.c +++ b/src/libstrongswan/networking/tun_device.c @@ -16,24 +16,12 @@ * for more details. */ -#include <errno.h> -#include <fcntl.h> -#include <netinet/in.h> -#include <string.h> -#include <sys/ioctl.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <unistd.h> -#include <net/if.h> - -#if !defined(__APPLE__) && !defined(__linux__) && !defined(HAVE_NET_IF_TUN_H) - #include "tun_device.h" #include <utils/debug.h> +#include <threading/thread.h> -#warning TUN devices are not supported! +#if !defined(__APPLE__) && !defined(__linux__) && !defined(HAVE_NET_IF_TUN_H) tun_device_t *tun_device_create(const char *name_tmpl) { @@ -43,6 +31,17 @@ tun_device_t *tun_device_create(const char *name_tmpl) #else /* TUN devices supported */ +#include <errno.h> +#include <fcntl.h> +#include <netinet/in.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <unistd.h> +#include <net/if.h> + #ifdef __APPLE__ #include <net/if_utun.h> #include <netinet/in_var.h> @@ -50,15 +49,14 @@ tun_device_t *tun_device_create(const char *name_tmpl) #elif defined(__linux__) #include <linux/types.h> #include <linux/if_tun.h> +#elif __FreeBSD__ >= 10 +#include <net/if_tun.h> +#include <net/if_var.h> +#include <netinet/in_var.h> #else #include <net/if_tun.h> #endif -#include "tun_device.h" - -#include <utils/debug.h> -#include <threading/thread.h> - #define TUN_DEFAULT_MTU 1500 typedef struct private_tun_device_t private_tun_device_t; @@ -101,8 +99,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 +212,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; |