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.
This commit is contained in:
@@ -50,6 +50,10 @@ tun_device_t *tun_device_create(const char *name_tmpl)
|
|||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/if_tun.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
|
#else
|
||||||
#include <net/if_tun.h>
|
#include <net/if_tun.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -101,8 +105,79 @@ struct private_tun_device_t {
|
|||||||
u_int8_t netmask;
|
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;
|
struct ifreq ifr;
|
||||||
host_t *mask;
|
host_t *mask;
|
||||||
@@ -143,6 +218,19 @@ METHOD(tun_device_t, set_address, bool,
|
|||||||
this->if_name, strerror(errno));
|
this->if_name, strerror(errno));
|
||||||
return FALSE;
|
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->address = addr->clone(addr);
|
||||||
this->netmask = netmask;
|
this->netmask = netmask;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|||||||
Reference in New Issue
Block a user