Pass sockets to bypass to kernel interface, allowing us to register them dynamically

This commit is contained in:
Martin Willi
2010-02-26 11:44:33 +01:00
parent 3e631491a0
commit 54f818590e
11 changed files with 141 additions and 274 deletions
@@ -2556,6 +2556,13 @@ static status_t register_pfkey_socket(private_kernel_klips_ipsec_t *this, u_int8
return SUCCESS;
}
METHOD(kernel_ipsec_t, bypass_socket, bool,
private_kernel_klips_ipsec_t *this, int fd, int family)
{
/* KLIPS does not need a bypass policy for IKE */
return TRUE;
}
METHOD(kernel_ipsec_t, destroy, void,
private_kernel_klips_ipsec_t *this)
{
@@ -2589,6 +2596,7 @@ kernel_klips_ipsec_t *kernel_klips_ipsec_create()
.add_policy = _add_policy,
.query_policy = _query_policy,
.del_policy = _del_policy,
.bypass_socket = _bypass_socket,
.destroy = _destroy,
},
.policies = linked_list_create(),
@@ -1892,6 +1892,47 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
return SUCCESS;
}
METHOD(kernel_ipsec_t, bypass_socket, bool,
private_kernel_netlink_ipsec_t *this, int fd, int family)
{
struct xfrm_userpolicy_info policy;
u_int sol, ipsec_policy;
switch (family)
{
case AF_INET:
sol = SOL_IP;
ipsec_policy = IP_XFRM_POLICY;
break;
case AF_INET6:
sol = SOL_IPV6;
ipsec_policy = IPV6_XFRM_POLICY;
break;
default:
return FALSE;
}
memset(&policy, 0, sizeof(policy));
policy.action = XFRM_POLICY_ALLOW;
policy.sel.family = family;
policy.dir = XFRM_POLICY_OUT;
if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
{
DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s",
strerror(errno));
return FALSE;
}
policy.dir = XFRM_POLICY_IN;
if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
{
DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s",
strerror(errno));
return FALSE;
}
return TRUE;
}
METHOD(kernel_ipsec_t, destroy, void,
private_kernel_netlink_ipsec_t *this)
{
@@ -1912,60 +1953,6 @@ METHOD(kernel_ipsec_t, destroy, void,
free(this);
}
/**
* Add bypass policies for IKE on the sockets used by charon
*/
static bool add_bypass_policies()
{
int fd, family, port;
enumerator_t *sockets;
bool status = TRUE;
sockets = charon->socket->create_enumerator(charon->socket);
while (sockets->enumerate(sockets, &fd, &family, &port))
{
struct xfrm_userpolicy_info policy;
u_int sol, ipsec_policy;
switch (family)
{
case AF_INET:
sol = SOL_IP;
ipsec_policy = IP_XFRM_POLICY;
break;
case AF_INET6:
sol = SOL_IPV6;
ipsec_policy = IPV6_XFRM_POLICY;
break;
default:
continue;
}
memset(&policy, 0, sizeof(policy));
policy.action = XFRM_POLICY_ALLOW;
policy.sel.family = family;
policy.dir = XFRM_POLICY_OUT;
if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
{
DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s",
strerror(errno));
status = FALSE;
break;
}
policy.dir = XFRM_POLICY_IN;
if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
{
DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s",
strerror(errno));
status = FALSE;
break;
}
}
sockets->destroy(sockets);
return status;
}
/*
* Described in header.
*/
@@ -1986,6 +1973,7 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()
.add_policy = _add_policy,
.query_policy = _query_policy,
.del_policy = _del_policy,
.bypass_socket = _bypass_socket,
.destroy = _destroy,
},
.policies = hashtable_create((hashtable_hash_t)policy_hash,
@@ -2020,13 +2008,6 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()
{
charon->kill(charon, "unable to bind XFRM event socket");
}
/* add bypass policies on the sockets used by charon */
if (!add_bypass_policies())
{
charon->kill(charon, "unable to add bypass policies on sockets");
}
this->job = callback_job_create((callback_job_cb_t)receive_events,
this, NULL, NULL);
charon->processor->queue_job(charon->processor, (job_t*)this->job);
@@ -2044,6 +2044,52 @@ static status_t register_pfkey_socket(private_kernel_pfkey_ipsec_t *this,
return SUCCESS;
}
METHOD(kernel_ipsec_t, bypass_socket, bool,
private_kernel_pfkey_ipsec_t *this, int fd, int family)
{
struct sadb_x_policy policy;
u_int sol, ipsec_policy;
switch (family)
{
case AF_INET:
{
sol = SOL_IP;
ipsec_policy = IP_IPSEC_POLICY;
break;
}
case AF_INET6:
{
sol = SOL_IPV6;
ipsec_policy = IPV6_IPSEC_POLICY;
break;
}
default:
return FALSE;
}
memset(&policy, 0, sizeof(policy));
policy.sadb_x_policy_len = sizeof(policy) / sizeof(u_int64_t);
policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY;
policy.sadb_x_policy_type = IPSEC_POLICY_BYPASS;
policy.sadb_x_policy_dir = IPSEC_DIR_OUTBOUND;
if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
{
DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s",
strerror(errno));
return FALSE;
}
policy.sadb_x_policy_dir = IPSEC_DIR_INBOUND;
if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
{
DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s",
strerror(errno));
return FALSE;
}
return TRUE;
}
METHOD(kernel_ipsec_t, destroy, void,
private_kernel_pfkey_ipsec_t *this)
{
@@ -2056,65 +2102,6 @@ METHOD(kernel_ipsec_t, destroy, void,
free(this);
}
/**
* Add bypass policies for IKE on the sockets of charon
*/
static bool add_bypass_policies(private_kernel_pfkey_ipsec_t *this)
{
int fd, family, port;
enumerator_t *sockets;
bool status = TRUE;
sockets = charon->socket->create_enumerator(charon->socket);
while (sockets->enumerate(sockets, &fd, &family, &port))
{
struct sadb_x_policy policy;
u_int sol, ipsec_policy;
switch (family)
{
case AF_INET:
{
sol = SOL_IP;
ipsec_policy = IP_IPSEC_POLICY;
break;
}
case AF_INET6:
{
sol = SOL_IPV6;
ipsec_policy = IPV6_IPSEC_POLICY;
break;
}
default:
continue;
}
memset(&policy, 0, sizeof(policy));
policy.sadb_x_policy_len = sizeof(policy) / sizeof(u_int64_t);
policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY;
policy.sadb_x_policy_type = IPSEC_POLICY_BYPASS;
policy.sadb_x_policy_dir = IPSEC_DIR_OUTBOUND;
if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
{
DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s",
strerror(errno));
status = FALSE;
break;
}
policy.sadb_x_policy_dir = IPSEC_DIR_INBOUND;
if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
{
DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s",
strerror(errno));
status = FALSE;
break;
}
}
sockets->destroy(sockets);
return status;
}
/*
* Described in header.
*/
@@ -2133,6 +2120,7 @@ kernel_pfkey_ipsec_t *kernel_pfkey_ipsec_create()
.add_policy = _add_policy,
.query_policy = _query_policy,
.del_policy = _del_policy,
.bypass_socket = _bypass_socket,
.destroy = _destroy,
},
.policies = linked_list_create(),
@@ -2156,12 +2144,6 @@ kernel_pfkey_ipsec_t *kernel_pfkey_ipsec_create()
charon->kill(charon, "unable to create PF_KEY event socket");
}
/* add bypass policies on the sockets used by charon */
if (!add_bypass_policies(this))
{
charon->kill(charon, "unable to add bypass policies on sockets");
}
/* register the event socket */
if (register_pfkey_socket(this, SADB_SATYPE_ESP) != SUCCESS ||
register_pfkey_socket(this, SADB_SATYPE_AH) != SUCCESS)
@@ -521,6 +521,12 @@ static int open_socket(private_socket_default_socket_t *this,
}
}
if (!charon->kernel_interface->bypass_socket(charon->kernel_interface,
skt, family))
{
DBG1(DBG_NET, "installing IKE bypass policy failed");
}
#ifndef __APPLE__
{
/* enable UDP decapsulation globally, only for one socket needed */
@@ -535,66 +541,6 @@ static int open_socket(private_socket_default_socket_t *this,
return skt;
}
/**
* enumerator for underlying sockets
*/
typedef struct {
/** implements enumerator_t */
enumerator_t public;
/** sockets we enumerate */
private_socket_default_socket_t *socket;
/** counter */
int index;
} socket_enumerator_t;
/**
* enumerate function for socket_enumerator_t
*/
static bool enumerate(socket_enumerator_t *this, int *fd, int *family, int *port)
{
static const struct {
int fd_offset;
int family;
int port;
} sockets[] = {
{ offsetof(private_socket_default_socket_t, ipv4),
AF_INET, IKEV2_UDP_PORT },
{ offsetof(private_socket_default_socket_t, ipv6),
AF_INET6, IKEV2_UDP_PORT },
{ offsetof(private_socket_default_socket_t, ipv4_natt),
AF_INET, IKEV2_NATT_PORT },
{ offsetof(private_socket_default_socket_t, ipv6_natt),
AF_INET6, IKEV2_NATT_PORT }
};
while(++this->index < countof(sockets))
{
int sock = *(int*)((char*)this->socket + sockets[this->index].fd_offset);
if (!sock)
{
continue;
}
*fd = sock;
*family = sockets[this->index].family;
*port = sockets[this->index].port;
return TRUE;
}
return FALSE;
}
METHOD(socket_t, create_enumerator, enumerator_t*,
private_socket_default_socket_t *this)
{
socket_enumerator_t *enumerator;
enumerator = malloc_thing(socket_enumerator_t);
enumerator->index = -1;
enumerator->socket = this;
enumerator->public.enumerate = (void*)enumerate;
enumerator->public.destroy = (void*)free;
return &enumerator->public;
}
METHOD(socket_default_socket_t, destroy, void,
private_socket_default_socket_t *this)
{
@@ -629,7 +575,6 @@ socket_default_socket_t *socket_default_socket_create()
.socket = {
.send = _sender,
.receive = _receiver,
.create_enumerator = _create_enumerator,
},
.destroy = _destroy,
},
@@ -492,6 +492,12 @@ static int open_send_socket(private_socket_raw_socket_t *this,
}
}
if (!charon->kernel_interface->bypass_socket(charon->kernel_interface,
skt, family))
{
DBG1(DBG_NET, "installing bypass policy on send socket failed");
}
return skt;
}
@@ -590,65 +596,13 @@ static int open_recv_socket(private_socket_raw_socket_t *this, int family)
return 0;
}
return skt;
}
/**
* enumerator for underlying sockets
*/
typedef struct {
/** implements enumerator_t */
enumerator_t public;
/** sockets we enumerate */
private_socket_raw_socket_t *socket;
/** counter */
int index;
} socket_enumerator_t;
/**
* enumerate function for socket_enumerator_t
*/
static bool enumerate(socket_enumerator_t *this, int *fd, int *family, int *port)
{
static const struct {
int fd_offset;
int family;
int port;
} sockets[] = {
{ offsetof(private_socket_raw_socket_t, recv4), AF_INET, IKEV2_UDP_PORT },
{ offsetof(private_socket_raw_socket_t, recv6), AF_INET6, IKEV2_UDP_PORT },
{ offsetof(private_socket_raw_socket_t, send4), AF_INET, IKEV2_UDP_PORT },
{ offsetof(private_socket_raw_socket_t, send6), AF_INET6, IKEV2_UDP_PORT },
{ offsetof(private_socket_raw_socket_t, send4_natt), AF_INET, IKEV2_NATT_PORT },
{ offsetof(private_socket_raw_socket_t, send6_natt), AF_INET6, IKEV2_NATT_PORT }
};
while(++this->index < countof(sockets))
if (!charon->kernel_interface->bypass_socket(charon->kernel_interface,
skt, family))
{
int sock = *(int*)((char*)this->socket + sockets[this->index].fd_offset);
if (!sock)
{
continue;
}
*fd = sock;
*family = sockets[this->index].family;
*port = sockets[this->index].port;
return TRUE;
DBG1(DBG_NET, "installing bypass policy on receive socket failed");
}
return FALSE;
}
METHOD(socket_t, create_enumerator, enumerator_t*,
private_socket_raw_socket_t *this)
{
socket_enumerator_t *enumerator;
enumerator = malloc_thing(socket_enumerator_t);
enumerator->index = -1;
enumerator->socket = this;
enumerator->public.enumerate = (void*)enumerate;
enumerator->public.destroy = (void*)free;
return &enumerator->public;
return skt;
}
METHOD(socket_raw_socket_t, destroy, void,
@@ -693,7 +647,6 @@ socket_raw_socket_t *socket_raw_socket_create()
.socket = {
.send = _sender,
.receive = _receiver,
.create_enumerator = _create_enumerator,
},
.destroy = _destroy,
},