diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2011-04-18 08:45:44 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2011-04-18 08:45:44 +0000 |
commit | e9e2c56254ecb6f7ae8722d89ad005d22f00c03c (patch) | |
tree | d9b6af19010e5f734966ac134436b957171fd4a2 | |
parent | 93c282487e9538a89011bf407bc81482c3e32e04 (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.c | 21 | ||||
-rw-r--r-- | sbin/iked/iked.h | 13 | ||||
-rw-r--r-- | sbin/iked/ikev2.c | 54 | ||||
-rw-r--r-- | sbin/iked/parse.y | 8 | ||||
-rw-r--r-- | sbin/iked/policy.c | 48 |
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); |