aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Willi <martin@strongswan.org>2006-09-12 13:50:14 +0000
committerMartin Willi <martin@strongswan.org>2006-09-12 13:50:14 +0000
commitd7934d0cfc84805bebc59f866c4af2f6e9687370 (patch)
tree25d99a2f178383e28996186a1d56de682f5eb503
parenta095243f604ea0dd3023acbef3622a0d53200dd3 (diff)
downloadstrongswan-d7934d0cfc84805bebc59f866c4af2f6e9687370.tar.bz2
strongswan-d7934d0cfc84805bebc59f866c4af2f6e9687370.tar.xz
implemented updown script to handle firewalling
-rw-r--r--src/charon/config/traffic_selector.c10
-rw-r--r--src/charon/network/socket.c9
-rw-r--r--src/charon/network/socket.h6
-rw-r--r--src/charon/sa/child_sa.c175
-rw-r--r--src/charon/sa/child_sa.h8
-rw-r--r--src/charon/sa/ike_sa.c5
-rw-r--r--src/charon/sa/transactions/create_child_sa.c14
-rw-r--r--src/charon/sa/transactions/ike_auth.c8
-rwxr-xr-xsrc/charon/threads/stroke_interface.c4
9 files changed, 207 insertions, 32 deletions
diff --git a/src/charon/config/traffic_selector.c b/src/charon/config/traffic_selector.c
index e567c6eca..ba6803156 100644
--- a/src/charon/config/traffic_selector.c
+++ b/src/charon/config/traffic_selector.c
@@ -177,10 +177,7 @@ static void update_string(private_traffic_selector_t *this)
/* build network mask string */
mask = calc_netbits(this);
- if (mask != 32)
- {
- snprintf(mask_str, sizeof(mask_str), "/%d", mask);
- }
+ snprintf(mask_str, sizeof(mask_str), "/%d", mask);
}
else
{
@@ -191,10 +188,7 @@ static void update_string(private_traffic_selector_t *this)
/* build network mask string */
mask = calc_netbits(this);
- if (mask != 128)
- {
- snprintf(mask_str, sizeof(mask_str), "/%d", mask);
- }
+ snprintf(mask_str, sizeof(mask_str), "/%d", mask);
}
/* build protocol string */
diff --git a/src/charon/network/socket.c b/src/charon/network/socket.c
index 81d9d63a8..adac63979 100644
--- a/src/charon/network/socket.c
+++ b/src/charon/network/socket.c
@@ -398,7 +398,7 @@ status_t sender(private_socket_t *this, packet_t *packet)
/**
* implements socket_t.is_local_address
*/
-static bool is_local_address(private_socket_t *this, host_t *host)
+static bool is_local_address(private_socket_t *this, host_t *host, char **dev)
{
struct ifaddrs *list;
struct ifaddrs *cur;
@@ -455,6 +455,11 @@ static bool is_local_address(private_socket_t *this, host_t *host)
if (found)
{
+ if (dev && cur->ifa_name)
+ {
+ /* return interface name, if requested */
+ *dev = strdup(cur->ifa_name);
+ }
break;
}
}
@@ -768,7 +773,7 @@ socket_t *socket_create(u_int16_t port, u_int16_t natt_port)
/* public functions */
this->public.send = (status_t(*)(socket_t*, packet_t*))sender;
this->public.receive = (status_t(*)(socket_t*, packet_t**))receiver;
- this->public.is_local_address = (bool(*)(socket_t*, host_t*))is_local_address;
+ this->public.is_local_address = (bool(*)(socket_t*, host_t*,char**))is_local_address;
this->public.create_local_address_list = (linked_list_t*(*)(socket_t*))create_local_address_list;
this->public.destroy = (void(*)(socket_t*)) destroy;
diff --git a/src/charon/network/socket.h b/src/charon/network/socket.h
index 34a06c0bb..431d9f2eb 100644
--- a/src/charon/network/socket.h
+++ b/src/charon/network/socket.h
@@ -93,11 +93,15 @@ struct socket_t {
/**
* @brief Check if an address is an address of this host.
*
+ * If the name parameter is not NULL, a string is allocated which
+ * holds the interfaces name.
+ *
* @param this socket_t object to work on
* @param host address to check
+ * @param name[out] interface name on which address is used
* @return TRUE if local address, FALSE otherwise
*/
- bool (*is_local_address) (socket_t *this, host_t *host);
+ bool (*is_local_address) (socket_t *this, host_t *host, char **name);
/**
* @brief Create a list of hosts with all local addresses.
diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c
index 79cff7ae1..b1335fa27 100644
--- a/src/charon/sa/child_sa.c
+++ b/src/charon/sa/child_sa.c
@@ -80,6 +80,8 @@ struct private_child_sa_t {
struct {
/** address of peer */
host_t *addr;
+ /** id of peer */
+ identification_t *id;
/** actual used SPI, 0 if unused */
u_int32_t spi;
} me, other;
@@ -155,14 +157,14 @@ struct private_child_sa_t {
void *rekeying_transaction;
/**
- * Specifies if NAT traversal is used
+ * Updown script
*/
- bool use_natt;
+ char *script;
/**
- * Specifies if CHILD_SA goes to ROUTED state if DPD detected
+ * Specifies if NAT traversal is used
*/
- bool stays_routed;
+ bool use_natt;
/**
* CHILD_SAs own logger
@@ -230,11 +232,156 @@ static child_sa_state_t get_state(private_child_sa_t *this)
}
/**
+ * Run the up/down script
+ */
+static void updown(private_child_sa_t *this, bool up)
+{
+ iterator_t *iterator;
+
+ if (this->script == NULL)
+ {
+ return;
+ }
+
+ iterator = this->policies->create_iterator(this->policies, TRUE);
+ while (iterator->has_next(iterator))
+ {
+ sa_policy_t *policy;
+ char command[1024];
+ char *ifname = NULL;
+ char *my_str, *other_str;
+ char *my_client, *other_client, *my_client_mask, *other_client_mask;
+ char *pos;
+ FILE *shell;
+
+ /* get ts strings */
+ iterator->current(iterator, (void**)&policy);
+ my_str = policy->my_ts->get_string(policy->my_ts);
+ other_str = policy->other_ts->get_string(policy->other_ts);
+
+ /* get subnet/bits from string */
+ my_client = strdup(my_str);
+ pos = strchr(my_client, '/');
+ *pos = '\0';
+ my_client_mask = pos + 1;
+ pos = strchr(my_client_mask, '[');
+ if (pos)
+ {
+ *pos = '\0';
+ }
+ other_client = strdup(other_str);
+ pos = strchr(other_client, '/');
+ *pos = '\0';
+ other_client_mask = pos + 1;
+ pos = strchr(other_client_mask, '[');
+ if (pos)
+ {
+ *pos = '\0';
+ }
+
+ charon->socket->is_local_address(charon->socket, this->me.addr, &ifname);
+
+ /* build the command with all env variables.
+ * TODO: PLUTO_MY_SRCIP, PLUTO_PEER_CA and PLUTO_NEXT_HOP
+ * are currently missing */
+ snprintf(command, sizeof(command),
+ "2>&1 "
+ "PLUTO_VERSION='1.1' "
+ "PLUTO_VERB='%s%s%s' "
+ "PLUTO_CONNECTION='%s' "
+ "PLUTO_INTERFACE='%s' "
+ "PLUTO_REQID='%u' "
+ "PLUTO_ME='%s' "
+ "PLUTO_MY_ID='%s' "
+ "PLUTO_MY_CLIENT='%s/%s' "
+ "PLUTO_MY_CLIENT_NET='%s' "
+ "PLUTO_MY_CLIENT_MASK='%s' "
+ "PLUTO_MY_PORT='%u' "
+ "PLUTO_MY_PROTOCOL='%u' "
+ "PLUTO_PEER='%s' "
+ "PLUTO_PEER_ID='%s' "
+ "PLUTO_PEER_CLIENT='%s/%s' "
+ "PLUTO_PEER_CLIENT_NET='%s' "
+ "PLUTO_PEER_CLIENT_MASK='%s' "
+ "PLUTO_PEER_PORT='%u' "
+ "PLUTO_PEER_PROTOCOL='%u' "
+ "%s",
+ up ? "up" : "down",
+ streq(this->me.addr->get_string(this->me.addr),
+ my_client) ? "-host" : "-client",
+ this->me.addr->get_family(this->me.addr) == AF_INET ? "" : "-ipv6",
+ this->name,
+ ifname,
+ this->reqid,
+ this->me.addr->get_string(this->me.addr),
+ this->me.id->get_string(this->me.id),
+ my_client, my_client_mask,
+ my_client, my_client_mask,
+ policy->my_ts->get_from_port(policy->my_ts),
+ policy->my_ts->get_protocol(policy->my_ts),
+ this->other.addr->get_string(this->other.addr),
+ this->other.id->get_string(this->other.id),
+ other_client, other_client_mask,
+ other_client, other_client_mask,
+ policy->other_ts->get_from_port(policy->other_ts),
+ policy->other_ts->get_protocol(policy->other_ts),
+ this->script);
+ free(ifname);
+ free(my_client);
+ free(other_client);
+
+ shell = popen(command, "r");
+
+ if (shell == NULL)
+ {
+ this->logger->log(this->logger, ERROR,
+ "could not execute updown script '%s'",
+ this->script);
+ return;
+ }
+
+ while (TRUE)
+ {
+ char resp[128];
+
+ if (fgets(resp, sizeof(resp), shell) == NULL)
+ {
+ if (ferror(shell))
+ {
+ this->logger->log(this->logger, ERROR,
+ "error reading output from updown script");
+ return;
+ }
+ else
+ {
+ break;
+ }
+ }
+ else
+ {
+ char *e = resp + strlen(resp);
+ if (e > resp && e[-1] == '\n')
+ { /* trim trailing '\n' */
+ e[-1] = '\0';
+ }
+ this->logger->log(this->logger, ERROR, "updown: %s", resp);
+ }
+ }
+ pclose(shell);
+ }
+ iterator->destroy(iterator);
+}
+
+/**
* Implements child_sa_t.set_state
*/
static void set_state(private_child_sa_t *this, child_sa_state_t state)
{
this->state = state;
+ if (state == CHILD_INSTALLED)
+ {
+ updown(this, TRUE);
+ }
}
/**
@@ -440,8 +587,6 @@ static status_t add(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *
}
proposal->set_spi(proposal, inbound_spi);
- this->state = CHILD_INSTALLED;
-
return SUCCESS;
}
@@ -466,8 +611,6 @@ static status_t update(private_child_sa_t *this, proposal_t *proposal, prf_plus_
return FAILED;
}
- this->state = CHILD_INSTALLED;
-
return SUCCESS;
}
@@ -903,6 +1046,11 @@ static void destroy(private_child_sa_t *this)
{
sa_policy_t *policy;
+ if (this->state == CHILD_DELETING || this->state == CHILD_INSTALLED)
+ {
+ updown(this, FALSE);
+ }
+
/* delete SAs in the kernel, if they are set up */
if (this->me.spi)
{
@@ -950,16 +1098,20 @@ static void destroy(private_child_sa_t *this)
this->other_ts->destroy(this->other_ts);
this->me.addr->destroy(this->me.addr);
this->other.addr->destroy(this->other.addr);
+ this->me.id->destroy(this->me.id);
+ this->other.id->destroy(this->other.id);
free(this->name);
+ free(this->script);
free(this);
}
/*
* Described in header.
*/
-child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other,
+child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other,
+ identification_t *my_id, identification_t *other_id,
u_int32_t soft_lifetime, u_int32_t hard_lifetime,
- bool use_natt)
+ char *script, bool use_natt)
{
static u_int32_t reqid = REQID_START;
private_child_sa_t *this = malloc_thing(private_child_sa_t);
@@ -990,10 +1142,13 @@ child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other,
this->name = strdup("(uninitialized)");
this->me.addr = me->clone(me);
this->other.addr = other->clone(other);
+ this->me.id = my_id->clone(my_id);
+ this->other.id = other_id->clone(other_id);
this->me.spi = 0;
this->other.spi = 0;
this->alloc_ah_spi = 0;
this->alloc_esp_spi = 0;
+ this->script = script ? strdup(script) : NULL;
this->use_natt = use_natt;
this->soft_lifetime = soft_lifetime;
this->hard_lifetime = hard_lifetime;
diff --git a/src/charon/sa/child_sa.h b/src/charon/sa/child_sa.h
index 5129ffe6a..e8e97c607 100644
--- a/src/charon/sa/child_sa.h
+++ b/src/charon/sa/child_sa.h
@@ -306,15 +306,19 @@ struct child_sa_t {
* @param rekey_reqid reqid of old CHILD_SA when rekeying, 0 otherwise
* @param me own address
* @param other remote address
+ * @param my_id id of own peer
+ * @param other_id id of remote peer
* @param soft_lifetime time before rekeying
* @param hard_lifteime time before delete
+ * @param script updown script to use when calling child_sa_t.script()
* @param use_natt TRUE if NAT traversal is used
* @return child_sa_t object
*
* @ingroup sa
*/
-child_sa_t * child_sa_create(u_int32_t rekey_reqid, host_t *me, host_t *other,
+child_sa_t * child_sa_create(u_int32_t rekey_reqid, host_t *me, host_t *other,
+ identification_t *my_id, identification_t* other_id,
u_int32_t soft_lifetime, u_int32_t hard_lifetime,
- bool use_natt);
+ char *script, bool use_natt);
#endif /*CHILD_SA_H_*/
diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c
index 55c3302ca..f8299863d 100644
--- a/src/charon/sa/ike_sa.c
+++ b/src/charon/sa/ike_sa.c
@@ -993,7 +993,6 @@ static status_t acquire(private_ike_sa_t *this, u_int32_t reqid)
{
if (current->get_reqid(current) == reqid)
{
- //iterator->remove(iterator);
child_sa = current;
break;
}
@@ -1013,7 +1012,6 @@ static status_t acquire(private_ike_sa_t *this, u_int32_t reqid)
this->my_id, this->other_id,
my_ts, other_ts,
this->my_host, this->other_host);
- //child_sa->destroy(child_sa);
if (policy == NULL)
{
this->logger->log(this->logger, ERROR,
@@ -1200,7 +1198,8 @@ static status_t route(private_ike_sa_t *this, connection_t *connection, policy_t
}
child_sa = child_sa_create(0, this->my_host, this->other_host,
- 0, 0, FALSE);
+ this->my_id, this->other_id,
+ 0, 0, NULL, FALSE);
child_sa->set_name(child_sa, policy->get_name(policy));
my_ts = policy->get_my_traffic_selectors(policy, this->my_host);
other_ts = policy->get_other_traffic_selectors(policy, this->other_host);
diff --git a/src/charon/sa/transactions/create_child_sa.c b/src/charon/sa/transactions/create_child_sa.c
index d88c2341b..154a8e800 100644
--- a/src/charon/sa/transactions/create_child_sa.c
+++ b/src/charon/sa/transactions/create_child_sa.c
@@ -221,6 +221,7 @@ static status_t get_request(private_create_child_sa_t *this, message_t **result)
{
message_t *request;
host_t *me, *other;
+ identification_t *my_id, *other_id;
/* check if we already have built a message (retransmission) */
if (this->message)
@@ -250,6 +251,8 @@ static status_t get_request(private_create_child_sa_t *this, message_t **result)
me = this->ike_sa->get_my_host(this->ike_sa);
other = this->ike_sa->get_other_host(this->ike_sa);
+ my_id = this->ike_sa->get_my_id(this->ike_sa);
+ other_id = this->ike_sa->get_other_id(this->ike_sa);
/* build the request */
request = message_create();
@@ -295,9 +298,10 @@ static status_t get_request(private_create_child_sa_t *this, message_t **result)
proposals = this->policy->get_proposals(this->policy);
use_natt = this->ike_sa->is_natt_enabled(this->ike_sa);
- this->child_sa = child_sa_create(this->reqid, me, other,
+ this->child_sa = child_sa_create(this->reqid, me, other, my_id, other_id,
this->policy->get_soft_lifetime(this->policy),
this->policy->get_hard_lifetime(this->policy),
+ this->policy->get_updown(this->policy),
use_natt);
this->child_sa->set_name(this->child_sa, this->policy->get_name(this->policy));
if (this->child_sa->alloc(this->child_sa, proposals) != SUCCESS)
@@ -501,7 +505,9 @@ static status_t install_child_sa(private_create_child_sa_t *this, bool initiator
{
return DESTROY_ME;
}
+
/* add to IKE_SA, and remove from transaction */
+ this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
this->child_sa = NULL;
return SUCCESS;
@@ -514,6 +520,7 @@ static status_t get_response(private_create_child_sa_t *this, message_t *request
message_t **result, transaction_t **next)
{
host_t *me, *other;
+ identification_t *my_id, *other_id;
message_t *response;
status_t status;
iterator_t *payloads;
@@ -532,6 +539,8 @@ static status_t get_response(private_create_child_sa_t *this, message_t *request
me = this->ike_sa->get_my_host(this->ike_sa);
other = this->ike_sa->get_other_host(this->ike_sa);
+ my_id = this->ike_sa->get_my_id(this->ike_sa);
+ other_id = this->ike_sa->get_other_id(this->ike_sa);
this->message_id = request->get_message_id(request);
/* set up response */
@@ -705,8 +714,9 @@ static status_t get_response(private_create_child_sa_t *this, message_t *request
soft_lifetime = this->policy->get_soft_lifetime(this->policy);
hard_lifetime = this->policy->get_hard_lifetime(this->policy);
use_natt = this->ike_sa->is_natt_enabled(this->ike_sa);
- this->child_sa = child_sa_create(this->reqid, me, other,
+ this->child_sa = child_sa_create(this->reqid, me, other, my_id, other_id,
soft_lifetime, hard_lifetime,
+ this->policy->get_updown(this->policy),
use_natt);
this->child_sa->set_name(this->child_sa, this->policy->get_name(this->policy));
if (install_child_sa(this, FALSE) != SUCCESS)
diff --git a/src/charon/sa/transactions/ike_auth.c b/src/charon/sa/transactions/ike_auth.c
index 0632fe421..c30dde2a4 100644
--- a/src/charon/sa/transactions/ike_auth.c
+++ b/src/charon/sa/transactions/ike_auth.c
@@ -318,8 +318,9 @@ static status_t get_request(private_ike_auth_t *this, message_t **result)
soft_lifetime = this->policy->get_soft_lifetime(this->policy);
hard_lifetime = this->policy->get_hard_lifetime(this->policy);
enable_natt = this->ike_sa->is_natt_enabled(this->ike_sa);
- this->child_sa = child_sa_create(this->reqid, me, other,
+ this->child_sa = child_sa_create(this->reqid, me, other, my_id, other_id,
soft_lifetime, hard_lifetime,
+ this->policy->get_updown(this->policy),
enable_natt);
this->child_sa->set_name(this->child_sa, this->policy->get_name(this->policy));
if (this->child_sa->alloc(this->child_sa, proposal_list) != SUCCESS)
@@ -519,7 +520,9 @@ static status_t install_child_sa(private_ike_auth_t *this, bool initiator)
{
return DESTROY_ME;
}
+
/* add to IKE_SA, and remove from transaction */
+ this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
this->child_sa = NULL;
return SUCCESS;
@@ -784,8 +787,9 @@ static status_t get_response(private_ike_auth_t *this, message_t *request,
soft_lifetime = this->policy->get_soft_lifetime(this->policy);
hard_lifetime = this->policy->get_hard_lifetime(this->policy);
use_natt = this->ike_sa->is_natt_enabled(this->ike_sa);
- this->child_sa = child_sa_create(this->reqid, me, other,
+ this->child_sa = child_sa_create(this->reqid, me, other, my_id, other_id,
soft_lifetime, hard_lifetime,
+ this->policy->get_updown(this->policy),
use_natt);
this->child_sa->set_name(this->child_sa, this->policy->get_name(this->policy));
if (install_child_sa(this, FALSE) != SUCCESS)
diff --git a/src/charon/threads/stroke_interface.c b/src/charon/threads/stroke_interface.c
index 3a39990a9..3c84415f4 100755
--- a/src/charon/threads/stroke_interface.c
+++ b/src/charon/threads/stroke_interface.c
@@ -222,7 +222,7 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg)
return;
}
- if (charon->socket->is_local_address(charon->socket, other_host))
+ if (charon->socket->is_local_address(charon->socket, other_host, NULL))
{
stroke_end_t tmp_end;
host_t *tmp_host;
@@ -238,7 +238,7 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg)
msg->add_conn.me = msg->add_conn.other;
msg->add_conn.other = tmp_end;
}
- else if (!charon->socket->is_local_address(charon->socket, my_host))
+ else if (!charon->socket->is_local_address(charon->socket, my_host, NULL))
{
this->stroke_logger->log(this->stroke_logger, ERROR,
"left nor right host is our side, aborting");