summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReyk Floeter <reyk@cvs.openbsd.org>2011-04-18 08:45:44 +0000
committerReyk Floeter <reyk@cvs.openbsd.org>2011-04-18 08:45:44 +0000
commite9e2c56254ecb6f7ae8722d89ad005d22f00c03c (patch)
treed9b6af19010e5f734966ac134436b957171fd4a2
parent93c282487e9538a89011bf407bc81482c3e32e04 (diff)
When the kernel wants to acquire an SA for an unknown flow, lookup a
matching policy and init a new IKE SA. This adds support for "acquire mode" from static flows. ok mikeb@
-rw-r--r--sbin/iked/config.c21
-rw-r--r--sbin/iked/iked.h13
-rw-r--r--sbin/iked/ikev2.c54
-rw-r--r--sbin/iked/parse.y8
-rw-r--r--sbin/iked/policy.c48
5 files changed, 101 insertions, 43 deletions
diff --git a/sbin/iked/config.c b/sbin/iked/config.c
index 1fda90ac58c..eb1911acbcb 100644
--- a/sbin/iked/config.c
+++ b/sbin/iked/config.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: config.c,v 1.9 2011/01/26 16:59:23 mikeb Exp $ */
+/* $OpenBSD: config.c,v 1.10 2011/04/18 08:45:43 reyk Exp $ */
/* $vantronix: config.c,v 1.30 2010/05/28 15:34:35 reyk Exp $ */
/*
@@ -89,7 +89,7 @@ config_free_sa(struct iked *env, struct iked_sa *sa)
config_free_proposals(&sa->sa_proposals, 0);
config_free_childsas(env, &sa->sa_childsas, NULL, NULL);
- config_free_flows(env, &sa->sa_flows);
+ sa_free_flows(env, &sa->sa_flows);
if (sa->sa_policy) {
(void)RB_REMOVE(iked_sapeers, &sa->sa_policy->pol_sapeers, sa);
@@ -219,15 +219,10 @@ config_free_flows(struct iked *env, struct iked_flows *head)
{
struct iked_flow *flow, *next;
- for (flow = TAILQ_FIRST(head); flow != NULL; flow = next) {
- next = TAILQ_NEXT(flow, flow_entry);
-
+ for (flow = RB_MIN(iked_flows, head); flow != NULL; flow = next) {
+ next = RB_NEXT(iked_flows, head, flow);
log_debug("%s: free %p", __func__, flow);
-
- if (flow->flow_loaded)
- RB_REMOVE(iked_activeflows, &env->sc_activeflows, flow);
- TAILQ_REMOVE(head, flow, flow_entry);
- (void)pfkey_flow_delete(env->sc_pfkey, flow);
+ RB_REMOVE(iked_flows, head, flow);
flow_free(flow);
}
}
@@ -624,7 +619,7 @@ config_setpolicy(struct iked *env, struct iked_policy *pol,
}
}
- TAILQ_FOREACH(flow, &pol->pol_flows, flow_entry) {
+ RB_FOREACH(flow, iked_flows, &pol->pol_flows) {
iov[c].iov_base = flow;
iov[c++].iov_len = sizeof(*flow);
}
@@ -662,7 +657,7 @@ config_getpolicy(struct iked *env, struct imsg *imsg)
offset += sizeof(*pol);
TAILQ_INIT(&pol->pol_proposals);
- TAILQ_INIT(&pol->pol_flows);
+ RB_INIT(&pol->pol_flows);
for (i = 0; i < pol->pol_nproposals; i++) {
memcpy(&pp, buf + offset, sizeof(pp));
@@ -690,7 +685,7 @@ config_getpolicy(struct iked *env, struct imsg *imsg)
memcpy(flow, buf + offset, sizeof(*flow));
offset += sizeof(*flow);
- TAILQ_INSERT_TAIL(&pol->pol_flows, flow, flow_entry);
+ RB_INSERT(iked_flows, &pol->pol_flows, flow);
}
TAILQ_INSERT_TAIL(&env->sc_policies, pol, pol_entry);
diff --git a/sbin/iked/iked.h b/sbin/iked/iked.h
index ca625e89ad5..04e96e55339 100644
--- a/sbin/iked/iked.h
+++ b/sbin/iked/iked.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: iked.h,v 1.35 2011/04/15 13:10:49 reyk Exp $ */
+/* $OpenBSD: iked.h,v 1.36 2011/04/18 08:45:43 reyk Exp $ */
/* $vantronix: iked.h,v 1.61 2010/06/03 07:57:33 reyk Exp $ */
/*
@@ -144,8 +144,8 @@ struct iked_flow {
RB_ENTRY(iked_flow) flow_node;
TAILQ_ENTRY(iked_flow) flow_entry;
};
-RB_HEAD(iked_activeflows, iked_flow);
-TAILQ_HEAD(iked_flows, iked_flow);
+RB_HEAD(iked_flows, iked_flow);
+TAILQ_HEAD(iked_saflows, iked_flow);
struct iked_childsa {
u_int8_t csa_saproto; /* IPSec protocol */
@@ -387,7 +387,7 @@ struct iked_sa {
struct iked_proposals sa_proposals; /* SA proposals */
struct iked_childsas sa_childsas; /* IPSec Child SAs */
- struct iked_flows sa_flows; /* IPSec flows */
+ struct iked_saflows sa_flows; /* IPSec flows */
RB_ENTRY(iked_sa) sa_peer_entry;
RB_ENTRY(iked_sa) sa_entry;
@@ -460,7 +460,7 @@ struct iked {
struct iked_sas sc_sas;
struct iked_activesas sc_activesas;
- struct iked_activeflows sc_activeflows;
+ struct iked_flows sc_activeflows;
struct iked_users sc_users;
void *sc_priv; /* per-process */
@@ -564,6 +564,7 @@ struct iked_sa *
sa_new(struct iked *, u_int64_t, u_int64_t, u_int,
struct iked_policy *);
void sa_free(struct iked *, struct iked_sa *);
+void sa_free_flows(struct iked *, struct iked_saflows *);
int sa_address(struct iked_sa *, struct iked_addr *,
struct sockaddr_storage *);
void childsa_free(struct iked_childsa *);
@@ -580,7 +581,7 @@ RB_PROTOTYPE(iked_sas, iked_sa, sa_entry, sa_cmp);
RB_PROTOTYPE(iked_sapeers, iked_sa, sa_peer_entry, sa_peer_cmp);
RB_PROTOTYPE(iked_users, iked_user, user_entry, user_cmp);
RB_PROTOTYPE(iked_activesas, iked_childsa, csa_node, childsa_cmp);
-RB_PROTOTYPE(iked_activeflows, iked_flow, flow_node, flow_cmp);
+RB_PROTOTYPE(iked_flows, iked_flow, flow_node, flow_cmp);
/* crypto.c */
struct iked_hash *
diff --git a/sbin/iked/ikev2.c b/sbin/iked/ikev2.c
index 4cb967970dd..a9dae3cd59f 100644
--- a/sbin/iked/ikev2.c
+++ b/sbin/iked/ikev2.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ikev2.c,v 1.48 2011/04/15 13:10:49 reyk Exp $ */
+/* $OpenBSD: ikev2.c,v 1.49 2011/04/18 08:45:43 reyk Exp $ */
/* $vantronix: ikev2.c,v 1.101 2010/06/03 07:57:33 reyk Exp $ */
/*
@@ -1074,7 +1074,7 @@ ikev2_add_ts_payload(struct ibuf *buf, u_int type, struct iked_sa *sa)
tsp->tsp_count = pol->pol_nflows;
len = sizeof(*tsp);
- TAILQ_FOREACH(flow, &pol->pol_flows, flow_entry) {
+ RB_FOREACH(flow, iked_flows, &pol->pol_flows) {
if ((ts = ibuf_advance(buf, sizeof(*ts))) == NULL)
return (-1);
@@ -3378,7 +3378,7 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, int initiator)
if (ikev2_valid_proposal(prop, NULL, NULL) != 0)
continue;
- TAILQ_FOREACH(flow, &sa->sa_policy->pol_flows, flow_entry) {
+ RB_FOREACH(flow, iked_flows, &sa->sa_policy->pol_flows) {
skip = 0;
TAILQ_FOREACH(saflow, &sa->sa_flows, flow_entry) {
if (IKED_ADDR_EQ(&saflow->flow_src,
@@ -3563,7 +3563,7 @@ ikev2_childsa_enable(struct iked *env, struct iked_sa *sa)
return (-1);
}
- RB_INSERT(iked_activeflows, &env->sc_activeflows, flow);
+ RB_INSERT(iked_flows, &env->sc_activeflows, flow);
log_debug("%s: loaded flow %p", __func__, flow);
}
@@ -3662,24 +3662,48 @@ ikev2_acquire_sa(struct iked *env, struct iked_flow *acquire)
{
struct iked_flow *flow;
struct iked_sa *sa;
+ struct iked_policy pol, *p = NULL;
if (env->sc_passive)
return;
- flow = RB_FIND(iked_activeflows, &env->sc_activeflows, acquire);
+ /* First try to find an active flow with IKE SA */
+ flow = RB_FIND(iked_flows, &env->sc_activeflows, acquire);
if (!flow) {
- log_warnx("%s: flow wasn't found", __func__);
- return;
- }
+ /* Otherwise try to find a matching policy */
+ bzero(&pol, sizeof(pol));
+ pol.pol_af = acquire->flow_peer->addr_af;
+ memcpy(&pol.pol_peer, acquire->flow_peer,
+ sizeof(pol.pol_peer));
+
+ RB_INIT(&pol.pol_flows);
+ RB_INSERT(iked_flows, &pol.pol_flows, acquire);
+ pol.pol_nflows = 1;
+
+ if ((p = policy_test(env, &pol)) == NULL) {
+ log_warnx("%s: flow wasn't found", __func__);
+ return;
+ }
- if ((sa = flow->flow_ikesa) == NULL) {
- log_warnx("%s: flow without SA", __func__);
- return;
- }
+ log_debug("%s: found matching policy '%s'", __func__,
+ p->pol_name);
- if (ikev2_send_create_child_sa(env, sa, NULL, flow->flow_saproto))
- log_warnx("%s: failed to initiate a CREATE_CHILD_SA exchange",
- __func__);
+ if (ikev2_init_ike_sa(env, p) != 0)
+ log_warnx("%s: failed to initiate a "
+ "IKE_SA_INIT exchange", __func__);
+ } else {
+ log_debug("%s: found active flow", __func__);
+
+ if ((sa = flow->flow_ikesa) == NULL) {
+ log_warnx("%s: flow without SA", __func__);
+ return;
+ }
+
+ if (ikev2_send_create_child_sa(env, sa, NULL,
+ flow->flow_saproto) != 0)
+ log_warnx("%s: failed to initiate a "
+ "CREATE_CHILD_SA exchange", __func__);
+ }
}
void
diff --git a/sbin/iked/parse.y b/sbin/iked/parse.y
index ad5ff1d0ecc..e4fb5353992 100644
--- a/sbin/iked/parse.y
+++ b/sbin/iked/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.20 2011/01/21 11:56:00 reyk Exp $ */
+/* $OpenBSD: parse.y,v 1.21 2011/04/18 08:45:43 reyk Exp $ */
/* $vantronix: parse.y,v 1.22 2010/06/03 11:08:34 reyk Exp $ */
/*
@@ -2122,7 +2122,7 @@ print_policy(struct iked_policy *pol)
print_verbose(" inet6");
}
- TAILQ_FOREACH(flow, &pol->pol_flows, flow_entry) {
+ RB_FOREACH(flow, iked_flows, &pol->pol_flows) {
print_verbose(" from %s",
print_host(&flow->flow_src.addr, NULL, 0));
if (flow->flow_src.addr_af != AF_UNSPEC &&
@@ -2411,7 +2411,7 @@ create_ike(char *name, int af, u_int8_t ipproto, struct ipsec_hosts *hosts,
pol.pol_lifetime = deflifetime;
TAILQ_INIT(&pol.pol_proposals);
- TAILQ_INIT(&pol.pol_flows);
+ RB_INIT(&pol.pol_flows);
prop[0].prop_id = ++pol.pol_nproposals;
prop[0].prop_protoid = IKEV2_SAPROTO_IKE;
@@ -2505,7 +2505,7 @@ create_ike(char *name, int af, u_int8_t ipproto, struct ipsec_hosts *hosts,
flows[j].flow_dst.addr_port = hosts->dport;
pol.pol_nflows++;
- TAILQ_INSERT_TAIL(&pol.pol_flows, &flows[j], flow_entry);
+ RB_INSERT(iked_flows, &pol.pol_flows, &flows[j]);
}
for (j = 0, ipa = ikecfg; ipa; ipa = ipa->next, j++) {
diff --git a/sbin/iked/policy.c b/sbin/iked/policy.c
index 580904af98e..5f218048aab 100644
--- a/sbin/iked/policy.c
+++ b/sbin/iked/policy.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: policy.c,v 1.16 2011/01/26 16:59:24 mikeb Exp $ */
+/* $OpenBSD: policy.c,v 1.17 2011/04/18 08:45:43 reyk Exp $ */
/* $vantronix: policy.c,v 1.29 2010/05/28 15:34:35 reyk Exp $ */
/*
@@ -97,6 +97,7 @@ struct iked_policy *
policy_test(struct iked *env, struct iked_policy *key)
{
struct iked_policy *p = NULL, *pol = NULL;
+ struct iked_flow *flow = NULL, *flowkey;
u_int cnt = 0;
p = TAILQ_FIRST(&env->sc_policies);
@@ -119,13 +120,30 @@ policy_test(struct iked *env, struct iked_policy *key)
p->pol_local.addr_mask) != 0)
p = p->pol_skip[IKED_SKIP_SRC_ADDR];
else {
+ /*
+ * Check if a specific flow is requested
+ * (eg. for acquire messages from the kernel)
+ * and find a matching flow. The policy also
+ * needs to have a valid peer address specified.
+ */
+ if (key->pol_nflows &&
+ (flowkey = RB_MIN(iked_flows,
+ &key->pol_flows)) != NULL &&
+ (p->pol_peer.addr_net ||
+ p->pol_peer.addr_af == AF_UNSPEC ||
+ (flow = RB_FIND(iked_flows, &p->pol_flows,
+ flowkey)) == NULL)) {
+ p = TAILQ_NEXT(p, pol_entry);
+ continue;
+ }
+
/* Policy matched */
pol = p;
if (pol->pol_flags & IKED_POLICY_QUICK)
break;
- /* Continue to find last matchin policy */
+ /* Continue to find last matching policy */
p = TAILQ_NEXT(p, pol_entry);
}
}
@@ -329,6 +347,25 @@ sa_free(struct iked *env, struct iked_sa *sa)
config_free_sa(env, sa);
}
+void
+sa_free_flows(struct iked *env, struct iked_saflows *head)
+{
+ struct iked_flow *flow, *next;
+
+ for (flow = TAILQ_FIRST(head); flow != NULL; flow = next) {
+ next = TAILQ_NEXT(flow, flow_entry);
+
+ log_debug("%s: free %p", __func__, flow);
+
+ if (flow->flow_loaded)
+ RB_REMOVE(iked_flows, &env->sc_activeflows, flow);
+ TAILQ_REMOVE(head, flow, flow_entry);
+ (void)pfkey_flow_delete(env->sc_pfkey, flow);
+ flow_free(flow);
+ }
+}
+
+
int
sa_address(struct iked_sa *sa, struct iked_addr *addr,
struct sockaddr_storage *peer)
@@ -508,15 +545,16 @@ flow_cmp(struct iked_flow *a, struct iked_flow *b)
{
int diff = 0;
- diff = addr_cmp(a->flow_peer, b->flow_peer, 0);
+ if (a->flow_peer && b->flow_peer)
+ diff = addr_cmp(a->flow_peer, b->flow_peer, 0);
if (!diff)
diff = addr_cmp(&a->flow_dst, &b->flow_dst, 1);
if (!diff)
diff = addr_cmp(&a->flow_src, &b->flow_src, 1);
- if (!diff)
+ if (!diff && a->flow_dir && b->flow_dir)
diff = (int)a->flow_dir - (int)b->flow_dir;
return (diff);
}
-RB_GENERATE(iked_activeflows, iked_flow, flow_node, flow_cmp);
+RB_GENERATE(iked_flows, iked_flow, flow_node, flow_cmp);