summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sbin/iked/iked.h12
-rw-r--r--sbin/iked/ikev2.c190
-rw-r--r--sbin/iked/ikev2_pld.c8
-rw-r--r--sbin/iked/pfkey.c221
-rw-r--r--sbin/iked/policy.c39
-rw-r--r--sbin/iked/types.h4
6 files changed, 389 insertions, 85 deletions
diff --git a/sbin/iked/iked.h b/sbin/iked/iked.h
index 7ce4f439465..b63a0108394 100644
--- a/sbin/iked/iked.h
+++ b/sbin/iked/iked.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: iked.h,v 1.28 2011/01/17 17:16:43 mikeb Exp $ */
+/* $OpenBSD: iked.h,v 1.29 2011/01/17 18:49:35 mikeb Exp $ */
/* $vantronix: iked.h,v 1.61 2010/06/03 07:57:33 reyk Exp $ */
/*
@@ -120,6 +120,7 @@ struct iked_flow {
u_int flow_dir; /* in/out */
u_int flow_loaded; /* pfkey done */
+ u_int flow_acquire;
u_int8_t flow_saproto;
u_int8_t flow_ipproto;
@@ -131,8 +132,10 @@ struct iked_flow {
struct iked_addr *flow_peer; /* outer dest */
struct iked_sa *flow_ikesa; /* parent SA */
+ RB_ENTRY(iked_flow) flow_acq_entry;
TAILQ_ENTRY(iked_flow) flow_entry;
};
+RB_HEAD(iked_acqflows, iked_flow);
TAILQ_HEAD(iked_flows, iked_flow);
struct iked_childsa {
@@ -147,7 +150,7 @@ struct iked_childsa {
struct iked_spi csa_spi;
- struct ibuf *csa_encrkey; /* encryption key */
+ struct ibuf *csa_encrkey; /* encryption key */
struct iked_transform *csa_encrxf; /* encryption xform */
struct ibuf *csa_integrkey; /* auth key */
@@ -443,6 +446,7 @@ struct iked {
struct iked_sas sc_sas;
struct iked_ipsecsas sc_ipsecsas;
+ struct iked_acqflows sc_acqflows;
struct iked_users sc_users;
void *sc_priv; /* per-process */
@@ -559,6 +563,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_ipsecsas, iked_childsa, csa_ipsec_entry, childsa_cmp);
+RB_PROTOTYPE(iked_acqflows, iked_flow, flow_acq_entry, acquire_flow_cmp);
/* crypto.c */
struct iked_hash *
@@ -617,7 +622,7 @@ int ikev2_policy2id(struct iked_static_id *, struct iked_id *, int);
int ikev2_childsa_enable(struct iked *, struct iked_sa *);
int ikev2_childsa_delete(struct iked *, struct iked_sa *,
u_int8_t, u_int64_t, u_int64_t *, int);
-int ikev2_flows_delete(struct iked *, struct iked_sa *, u_int8_t);
+int ikev2_flows_delete(struct iked *, struct iked_sa *, u_int8_t, int);
struct ibuf *
ikev2_prfplus(struct iked_hash *, struct ibuf *, struct ibuf *,
@@ -635,6 +640,7 @@ struct ikev2_payload *
ikev2_add_payload(struct ibuf *);
int ikev2_next_payload(struct ikev2_payload *, size_t,
u_int8_t);
+void ikev2_acquire(struct iked *, struct iked_flow *);
void ikev2_disable_rekeying(struct iked *, struct iked_sa *);
void ikev2_rekey_sa(struct iked *, struct iked_spi *);
void ikev2_drop_sa(struct iked *, struct iked_spi *);
diff --git a/sbin/iked/ikev2.c b/sbin/iked/ikev2.c
index 7c81be911d5..db5fab5e612 100644
--- a/sbin/iked/ikev2.c
+++ b/sbin/iked/ikev2.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ikev2.c,v 1.32 2011/01/12 14:26:26 mikeb Exp $ */
+/* $OpenBSD: ikev2.c,v 1.33 2011/01/17 18:49:35 mikeb Exp $ */
/* $vantronix: ikev2.c,v 1.101 2010/06/03 07:57:33 reyk Exp $ */
/*
@@ -71,8 +71,8 @@ int ikev2_resp_ike_sa_init(struct iked *, struct iked_message *);
int ikev2_resp_ike_auth(struct iked *, struct iked_sa *);
int ikev2_resp_ike_eap(struct iked *, struct iked_sa *, struct ibuf *);
-int ikev2_rekey_child_sa(struct iked *, struct iked_sa *,
- struct iked_spi *);
+int ikev2_send_create_child_sa(struct iked *, struct iked_sa *,
+ struct iked_spi *, u_int8_t);
int ikev2_init_create_child_sa(struct iked *, struct iked_message *);
int ikev2_resp_create_child_sa(struct iked *, struct iked_message *);
@@ -2015,8 +2015,8 @@ ikev2_send_ike_e(struct iked *env, struct iked_sa *sa, struct ibuf *buf,
}
int
-ikev2_rekey_child_sa(struct iked *env, struct iked_sa *sa,
- struct iked_spi *rekey)
+ikev2_send_create_child_sa(struct iked *env, struct iked_sa *sa,
+ struct iked_spi *rekey, u_int8_t protoid)
{
struct iked_childsa *csa, *csb = NULL;
struct ikev2_notify *n;
@@ -2027,15 +2027,19 @@ ikev2_rekey_child_sa(struct iked *env, struct iked_sa *sa,
ssize_t len = 0;
int initiator, ret = -1;
- log_debug("%s: rekey %s spi %s", __func__,
- print_map(rekey->spi_protoid, ikev2_saproto_map),
- print_spi(rekey->spi, rekey->spi_size));
+ if (rekey)
+ log_debug("%s: rekeying %s spi %s", __func__,
+ print_map(rekey->spi_protoid, ikev2_saproto_map),
+ print_spi(rekey->spi, rekey->spi_size));
+ else
+ log_debug("%s: creating new CHILD SAs", __func__);
initiator = sa->sa_hdr.sh_initiator ? 1 : 0;
- if ((csa = childsa_lookup(sa, rekey->spi,
+ if (rekey &&
+ ((csa = childsa_lookup(sa, rekey->spi,
rekey->spi_protoid)) == NULL ||
- (csb = csa->csa_peersa) == NULL) {
+ (csb = csa->csa_peersa) == NULL)) {
log_debug("%s: CHILD SA %s wasn't found", __func__,
print_spi(rekey->spi, rekey->spi_size));
}
@@ -2055,7 +2059,7 @@ ikev2_rekey_child_sa(struct iked *env, struct iked_sa *sa,
if ((pld = ikev2_add_payload(e)) == NULL)
goto done;
if ((len = ikev2_add_proposals(env, sa, e, &sa->sa_proposals,
- rekey->spi_protoid, 1, 0)) == -1)
+ protoid, 1, 0)) == -1)
goto done;
if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_NONCE) == -1)
@@ -2088,23 +2092,25 @@ ikev2_rekey_child_sa(struct iked *env, struct iked_sa *sa,
if ((len = ikev2_add_ts(e, IKEV2_PAYLOAD_TSr, sa)) == -1)
goto done;
- if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_NOTIFY) == -1)
- goto done;
+ if (rekey) {
+ if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_NOTIFY) == -1)
+ goto done;
- /* REKEY_SA notification */
- if ((pld = ikev2_add_payload(e)) == NULL)
- goto done;
- if ((n = ibuf_advance(e, sizeof(*n))) == NULL)
- goto done;
- n->n_type = htobe16(IKEV2_N_REKEY_SA);
- n->n_protoid = rekey->spi_protoid;
- n->n_spisize = rekey->spi_size;
- if ((ptr = ibuf_advance(e, rekey->spi_size)) == NULL)
- goto done;
- len = rekey->spi_size;
- spi = htobe32((u_int32_t)csa->csa_peerspi);
- memcpy(ptr, &spi, rekey->spi_size);
- len += sizeof(*n);
+ /* REKEY_SA notification */
+ if ((pld = ikev2_add_payload(e)) == NULL)
+ goto done;
+ if ((n = ibuf_advance(e, sizeof(*n))) == NULL)
+ goto done;
+ n->n_type = htobe16(IKEV2_N_REKEY_SA);
+ n->n_protoid = rekey->spi_protoid;
+ n->n_spisize = rekey->spi_size;
+ if ((ptr = ibuf_advance(e, rekey->spi_size)) == NULL)
+ goto done;
+ len = rekey->spi_size;
+ spi = htobe32((u_int32_t)csa->csa_peerspi);
+ memcpy(ptr, &spi, rekey->spi_size);
+ len += sizeof(*n);
+ }
if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_NONE) == -1)
goto done;
@@ -2112,8 +2118,10 @@ ikev2_rekey_child_sa(struct iked *env, struct iked_sa *sa,
ret = ikev2_msg_send_encrypt(env, sa, &e,
IKEV2_EXCHANGE_CREATE_CHILD_SA, IKEV2_PAYLOAD_SA, 0);
if (ret == 0) {
- csa->csa_rekey = 1;
- csb->csa_rekey = 1;
+ if (rekey) {
+ csa->csa_rekey = 1;
+ csb->csa_rekey = 1;
+ }
sa->sa_stateflags |= IKED_REQ_CHILDSA;
}
@@ -2129,10 +2137,10 @@ ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg)
struct iked_proposal *prop, *mprop = msg->msg_prop;
struct iked_sa *sa = msg->msg_sa;
struct ikev2_delete *del;
- struct ibuf *buf;
- u_int64_t peerspi/* , localspi */;
+ struct ibuf *buf = NULL;
+ u_int64_t peerspi;
u_int32_t spi32;
- int ret = -1;
+ int rekeying = 0, ret = -1;
if (!ikev2_msg_frompeer(msg) ||
(sa->sa_stateflags & IKED_REQ_CHILDSA) == 0)
@@ -2157,10 +2165,10 @@ ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg)
peerspi = prop->prop_peerspi.spi;
prop->prop_peerspi.spi = msg->msg_prop->prop_peerspi.spi;
- if ((csa = childsa_lookup(sa, peerspi, prop->prop_protoid)) == NULL) {
- log_debug("%s: failed to find a CHILD SA %s", __func__,
+ if ((csa = childsa_lookup(sa, peerspi, prop->prop_protoid)) != NULL) {
+ rekeying = 1;
+ log_debug("%s: rekeying CHILD SA %s", __func__,
print_spi(peerspi, prop->prop_peerspi.spi_size));
- return (-1);
}
/* Update responder's nonce */
@@ -2176,25 +2184,29 @@ ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg)
return (-1);
}
- if ((buf = ibuf_static()) == NULL)
- goto done;
+ if (rekeying) {
+ /* Child SA rekeying */
- if ((del = ibuf_advance(buf, sizeof(*del))) == NULL)
- goto done;
+ if ((buf = ibuf_static()) == NULL)
+ goto done;
- del->del_protoid = prop->prop_protoid;
- del->del_spisize = sizeof(spi32);
- del->del_nspi = htobe16(1);
+ if ((del = ibuf_advance(buf, sizeof(*del))) == NULL)
+ goto done;
- spi32 = htobe32(csa->csa_peerspi);
- if (ibuf_add(buf, &spi32, sizeof(spi32)))
- goto done;
+ del->del_protoid = prop->prop_protoid;
+ del->del_spisize = sizeof(spi32);
+ del->del_nspi = htobe16(1);
- if (ikev2_send_ike_e(env, sa, buf, IKEV2_PAYLOAD_DELETE,
- IKEV2_EXCHANGE_INFORMATIONAL, 0))
- goto done;
+ spi32 = htobe32(csa->csa_peerspi);
+ if (ibuf_add(buf, &spi32, sizeof(spi32)))
+ goto done;
- sa->sa_stateflags |= IKED_REQ_INF | IKED_REQ_DELETE;
+ if (ikev2_send_ike_e(env, sa, buf, IKEV2_PAYLOAD_DELETE,
+ IKEV2_EXCHANGE_INFORMATIONAL, 0))
+ goto done;
+
+ sa->sa_stateflags |= IKED_REQ_INF | IKED_REQ_DELETE;
+ }
ret = ikev2_childsa_enable(env, sa);
@@ -2218,7 +2230,7 @@ ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg)
struct ikev2_keyexchange *ke;
struct ikev2_notify *n;
struct ikev2_payload *pld;
- struct ibuf *buf, *e = NULL, *nonce = NULL;
+ struct ibuf *buf = NULL, *e = NULL, *nonce = NULL;
struct group *group;
ssize_t len = 0;
int initiator, protoid, rekeying = 1;
@@ -3659,7 +3671,8 @@ ikev2_childsa_delete(struct iked *env, struct iked_sa *sa, u_int8_t saproto,
}
int
-ikev2_flows_delete(struct iked *env, struct iked_sa *sa, u_int8_t saproto)
+ikev2_flows_delete(struct iked *env, struct iked_sa *sa, u_int8_t saproto,
+ int acquire)
{
struct iked_flow *flow, *nextflow;
int found = 0;
@@ -3669,16 +3682,45 @@ ikev2_flows_delete(struct iked *env, struct iked_sa *sa, u_int8_t saproto)
if (saproto && flow->flow_saproto != saproto)
continue;
- if (pfkey_flow_delete(env->sc_pfkey, flow) != 0)
- log_debug("%s: failed to delete flow %p",
- __func__, flow);
- else
- log_debug("%s: deleted flow %p",
- __func__, flow);
- found++;
- TAILQ_REMOVE(&sa->sa_flows, flow, flow_entry);
- flow_free(flow);
+ /*
+ * If we're asked to put a flow into acquire mode for
+ * the first time then remove it and add back with an
+ * appropriate configuration, otherwise there's nothing
+ * to do.
+ */
+ if (!acquire) {
+ if (flow->flow_acquire)
+ RB_REMOVE(iked_acqflows, &env->sc_acqflows,
+ flow);
+ if (pfkey_flow_delete(env->sc_pfkey, flow) != 0)
+ log_debug("%s: failed to delete flow %p",
+ __func__, flow);
+ else
+ log_debug("%s: deleted flow %p",
+ __func__, flow);
+ TAILQ_REMOVE(&sa->sa_flows, flow, flow_entry);
+ flow_free(flow);
+ } else if (!flow->flow_acquire) {
+ if (pfkey_flow_delete(env->sc_pfkey, flow) != 0)
+ log_debug("%s: failed to delete flow %p",
+ __func__, flow);
+ else
+ log_debug("%s: deleted flow %p",
+ __func__, flow);
+ flow->flow_acquire = 1;
+ if (pfkey_flow_add(env->sc_pfkey, flow) != 0)
+ log_debug("%s: failed to load acquire flow",
+ __func__);
+ else {
+ RB_INSERT(iked_acqflows, &env->sc_acqflows,
+ flow);
+ log_debug("%s: loaded acquire flow %p",
+ __func__, flow);
+ }
+ }
+
+ found++;
}
return (found ? 0 : -1);
@@ -3728,6 +3770,28 @@ ikev2_valid_proposal(struct iked_proposal *prop,
}
void
+ikev2_acquire(struct iked *env, struct iked_flow *acquire)
+{
+ struct iked_flow *flow;
+ struct iked_sa *sa;
+
+ if ((flow = RB_FIND(iked_acqflows, &env->sc_acqflows,
+ acquire)) == NULL) {
+ log_warnx("%s: flow wasn't found", __func__);
+ return;
+ }
+
+ 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))
+ log_warnx("%s: failed to initiate a CREATE_CHILD_SA exchange",
+ __func__);
+}
+
+void
ikev2_disable_rekeying(struct iked *env, struct iked_sa *sa)
{
struct iked_childsa *csa;
@@ -3768,7 +3832,7 @@ ikev2_rekey_sa(struct iked *env, struct iked_spi *rekey)
}
if (csa->csa_allocated) /* Peer SPI died first, get the local one */
rekey->spi = csa->csa_peerspi;
- if (ikev2_rekey_child_sa(env, sa, rekey))
+ if (ikev2_send_create_child_sa(env, sa, rekey, rekey->spi_protoid))
log_warnx("%s: failed to initiate a CREATE_CHILD_SA exchange",
__func__);
}
@@ -3776,11 +3840,11 @@ ikev2_rekey_sa(struct iked *env, struct iked_spi *rekey)
void
ikev2_drop_sa(struct iked *env, struct iked_spi *drop)
{
+ struct ibuf *buf = NULL;
struct iked_childsa *csa, key;
struct iked_proposal *prop;
struct iked_sa *sa;
struct ikev2_delete *del;
- struct ibuf *buf;
u_int32_t spi32;
int nprop = 0;
@@ -3834,7 +3898,7 @@ ikev2_drop_sa(struct iked *env, struct iked_spi *drop)
print_spi(csa->csa_peerspi, drop->spi_size));
/* delete flows for the specified protocol */
- if (ikev2_flows_delete(env, sa, csa->csa_saproto))
+ if (ikev2_flows_delete(env, sa, csa->csa_saproto, 0))
log_debug("%s: failed to delete flows", __func__);
/* Send PAYLOAD_DELETE */
diff --git a/sbin/iked/ikev2_pld.c b/sbin/iked/ikev2_pld.c
index a560e1d16ce..fd323c462ea 100644
--- a/sbin/iked/ikev2_pld.c
+++ b/sbin/iked/ikev2_pld.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ikev2_pld.c,v 1.19 2011/01/12 14:26:26 mikeb Exp $ */
+/* $OpenBSD: ikev2_pld.c,v 1.20 2011/01/17 18:49:35 mikeb Exp $ */
/* $vantronix: ikev2.c,v 1.101 2010/06/03 07:57:33 reyk Exp $ */
/*
@@ -852,8 +852,12 @@ ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld,
else
found++;
+ /*
+ * Change flows to acquire mode so that it would be possible
+ * to negotiate a new Child SA quickly
+ */
if (!peersas[i]->csa_rekey)
- ikev2_flows_delete(env, sa, del->del_protoid);
+ ikev2_flows_delete(env, sa, del->del_protoid, 1);
}
/* Parsed outgoing message? */
diff --git a/sbin/iked/pfkey.c b/sbin/iked/pfkey.c
index d9954db4eae..5deec8d06a0 100644
--- a/sbin/iked/pfkey.c
+++ b/sbin/iked/pfkey.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfkey.c,v 1.11 2011/01/12 14:35:45 mikeb Exp $ */
+/* $OpenBSD: pfkey.c,v 1.12 2011/01/17 18:49:35 mikeb Exp $ */
/* $vantronix: pfkey.c,v 1.11 2010/06/03 07:57:33 reyk Exp $ */
/*
@@ -266,9 +266,11 @@ pfkey_flow(int sd, u_int8_t satype, u_int8_t action, struct iked_flow *flow)
sa_flowtype.sadb_protocol_exttype = SADB_X_EXT_FLOW_TYPE;
sa_flowtype.sadb_protocol_len = sizeof(sa_flowtype) / 8;
sa_flowtype.sadb_protocol_direction = flow->flow_dir;
- sa_flowtype.sadb_protocol_proto =
- flow->flow_dir == IPSP_DIRECTION_IN ?
- SADB_X_FLOW_TYPE_USE : SADB_X_FLOW_TYPE_REQUIRE;
+ if (flow->flow_dir == IPSP_DIRECTION_IN)
+ sa_flowtype.sadb_protocol_proto = SADB_X_FLOW_TYPE_USE;
+ else
+ sa_flowtype.sadb_protocol_proto = flow->flow_acquire ?
+ SADB_X_FLOW_TYPE_ACQUIRE : SADB_X_FLOW_TYPE_REQUIRE;
bzero(&sa_protocol, sizeof(sa_protocol));
sa_protocol.sadb_protocol_exttype = SADB_X_EXT_PROTOCOL;
@@ -1197,6 +1199,8 @@ pfkey_id2ident(struct iked_id *id, u_int exttype)
int
pfkey_init(struct iked *env)
{
+ struct sadb_msg smsg;
+ struct iovec iov;
int fd;
if ((fd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) == -1)
@@ -1204,6 +1208,35 @@ pfkey_init(struct iked *env)
pfkey_flush(fd);
+ /* Register it to get ESP and AH acquires from the kernel */
+ bzero(&smsg, sizeof(smsg));
+ smsg.sadb_msg_version = PF_KEY_V2;
+ smsg.sadb_msg_seq = ++sadb_msg_seq;
+ smsg.sadb_msg_pid = getpid();
+ smsg.sadb_msg_len = sizeof(smsg) / 8;
+ smsg.sadb_msg_type = SADB_REGISTER;
+ smsg.sadb_msg_satype = SADB_SATYPE_ESP;
+
+ iov.iov_base = &smsg;
+ iov.iov_len = sizeof(smsg);
+
+ if (pfkey_write(fd, &smsg, &iov, 1, NULL, NULL))
+ fatal("pfkey_init: failed to set up ESP acquires");
+
+ bzero(&smsg, sizeof(smsg));
+ smsg.sadb_msg_version = PF_KEY_V2;
+ smsg.sadb_msg_seq = ++sadb_msg_seq;
+ smsg.sadb_msg_pid = getpid();
+ smsg.sadb_msg_len = sizeof(smsg) / 8;
+ smsg.sadb_msg_type = SADB_REGISTER;
+ smsg.sadb_msg_satype = SADB_SATYPE_AH;
+
+ iov.iov_base = &smsg;
+ iov.iov_len = sizeof(smsg);
+
+ if (pfkey_write(fd, &smsg, &iov, 1, NULL, NULL))
+ fatal("pfkey_init: failed to set up AH acquires");
+
/* Set up a timer to process messages deferred by the pfkey_reply */
pfkey_timer_tv.tv_sec = 1;
pfkey_timer_tv.tv_usec = 0;
@@ -1283,12 +1316,21 @@ pfkey_timer_cb(int unused, short event, void *arg)
void
pfkey_process(struct iked *env, struct pfkey_message *pm)
{
+ struct iked_addr peer;
+ struct iked_flow flow;
struct iked_spi spi;
- struct sadb_msg *hdr;
+ struct sadb_address *sa_addr;
+ struct sadb_msg *hdr, smsg;
struct sadb_sa *sa;
- struct sadb_lifetime *ltime;
- u_int8_t *data = pm->pm_data;
- ssize_t len = pm->pm_lenght;
+ struct sadb_lifetime *sa_ltime;
+ struct sadb_protocol *sa_proto;
+ struct sadb_x_policy sa_pol;
+ struct sockaddr_storage *ssrc, *sdst, *smask, *dmask, *speer;
+ struct iovec iov[IOV_CNT];
+ int iov_cnt, sd = env->sc_pfkey;
+ u_int8_t *reply, *data = pm->pm_data;
+ ssize_t rlen, len = pm->pm_lenght;
+ const char *errmsg = NULL;
if (!env || !data || !len)
return;
@@ -1296,16 +1338,167 @@ pfkey_process(struct iked *env, struct pfkey_message *pm)
hdr = (struct sadb_msg *)data;
switch (hdr->sadb_msg_type) {
+ case SADB_ACQUIRE:
+ bzero(&flow, sizeof(flow));
+ bzero(&peer, sizeof(peer));
+
+ if ((sa_addr = pfkey_find_ext(data, len,
+ SADB_EXT_ADDRESS_DST)) == NULL) {
+ log_debug("%s: no peer address", __func__);
+ return;
+ }
+ speer = (struct sockaddr_storage *)(sa_addr + 1);
+ peer.addr_af = speer->ss_family;
+ peer.addr_port = htons(socket_getport(speer));
+ memcpy(&peer.addr, speer, sizeof(*speer));
+ if (socket_af((struct sockaddr *)&peer.addr,
+ peer.addr_port) == -1) {
+ log_debug("%s: invalid address", __func__);
+ return;
+ }
+ flow.flow_peer = &peer;
+
+ log_debug("%s: acquire request (peer %s)", __func__,
+ print_host(speer, NULL, 0));
+
+ /* get the matching flow */
+ bzero(&smsg, sizeof(smsg));
+ smsg.sadb_msg_version = PF_KEY_V2;
+ smsg.sadb_msg_seq = ++sadb_msg_seq;
+ smsg.sadb_msg_pid = getpid();
+ smsg.sadb_msg_len = sizeof(smsg) / 8;
+ smsg.sadb_msg_type = SADB_X_ASKPOLICY;
+
+ iov_cnt = 0;
+
+ iov[iov_cnt].iov_base = &smsg;
+ iov[iov_cnt].iov_len = sizeof(smsg);
+ iov_cnt++;
+
+ bzero(&sa_pol, sizeof(sa_pol));
+ sa_pol.sadb_x_policy_exttype = SADB_X_EXT_POLICY;
+ sa_pol.sadb_x_policy_len = sizeof(sa_pol) / 8;
+ sa_pol.sadb_x_policy_seq = hdr->sadb_msg_seq;
+
+ iov[iov_cnt].iov_base = &sa_pol;
+ iov[iov_cnt].iov_len = sizeof(sa_pol);
+ smsg.sadb_msg_len += sizeof(sa_pol) / 8;
+ iov_cnt++;
+
+ if (pfkey_write(sd, &smsg, iov, iov_cnt, &reply, &rlen)) {
+ log_warnx("%s: failed to get a policy", __func__);
+ return;
+ }
+
+ if ((sa_addr = pfkey_find_ext(reply, rlen,
+ SADB_X_EXT_SRC_FLOW)) == NULL) {
+ errmsg = "flow source address";
+ goto out;
+ }
+ ssrc = (struct sockaddr_storage *)(sa_addr + 1);
+ flow.flow_src.addr_af = ssrc->ss_family;
+ flow.flow_src.addr_port = htons(socket_getport(ssrc));
+ memcpy(&flow.flow_src.addr, ssrc, sizeof(*ssrc));
+ if (socket_af((struct sockaddr *)&flow.flow_src.addr,
+ flow.flow_src.addr_port) == -1) {
+ log_debug("%s: invalid address", __func__);
+ return;
+ }
+
+ if ((sa_addr = pfkey_find_ext(reply, rlen,
+ SADB_X_EXT_DST_FLOW)) == NULL) {
+ errmsg = "flow destination address";
+ goto out;
+ }
+ sdst = (struct sockaddr_storage *)(sa_addr + 1);
+ flow.flow_dst.addr_af = sdst->ss_family;
+ flow.flow_dst.addr_port = htons(socket_getport(sdst));
+ memcpy(&flow.flow_dst.addr, sdst, sizeof(*sdst));
+ if (socket_af((struct sockaddr *)&flow.flow_dst.addr,
+ flow.flow_dst.addr_port) == -1) {
+ log_debug("%s: invalid address", __func__);
+ return;
+ }
+
+ if ((sa_addr = pfkey_find_ext(reply, rlen,
+ SADB_X_EXT_SRC_MASK)) == NULL) {
+ errmsg = "flow source mask";
+ goto out;
+ }
+ smask = (struct sockaddr_storage *)(sa_addr + 1);
+ switch (smask->ss_family) {
+ case AF_INET:
+ flow.flow_src.addr_mask =
+ mask2prefixlen((struct sockaddr *)smask);
+ if (flow.flow_src.addr_mask != 32)
+ flow.flow_src.addr_net = 1;
+ break;
+ case AF_INET6:
+ flow.flow_src.addr_mask =
+ mask2prefixlen6((struct sockaddr *)smask);
+ if (flow.flow_src.addr_mask != 128)
+ flow.flow_src.addr_net = 1;
+ break;
+ default:
+ log_debug("%s: bad address family", __func__);
+ return;
+ }
+
+ if ((sa_addr = pfkey_find_ext(reply, rlen,
+ SADB_X_EXT_DST_MASK)) == NULL) {
+ errmsg = "flow destination mask";
+ goto out;
+ }
+ dmask = (struct sockaddr_storage *)(sa_addr + 1);
+ switch (dmask->ss_family) {
+ case AF_INET:
+ flow.flow_dst.addr_mask =
+ mask2prefixlen((struct sockaddr *)dmask);
+ if (flow.flow_src.addr_mask != 32)
+ flow.flow_src.addr_net = 1;
+ break;
+ case AF_INET6:
+ flow.flow_dst.addr_mask =
+ mask2prefixlen6((struct sockaddr *)dmask);
+ if (flow.flow_src.addr_mask != 128)
+ flow.flow_src.addr_net = 1;
+ break;
+ default:
+ log_debug("%s: bad address family", __func__);
+ return;
+ }
+
+ if ((sa_proto = pfkey_find_ext(reply, rlen,
+ SADB_X_EXT_FLOW_TYPE)) == NULL) {
+ errmsg = "flow protocol";
+ goto out;
+ }
+ flow.flow_dir = sa_proto->sadb_protocol_direction;
+
+ log_debug("%s: flow %s from %s/%s to %s/%s via %s", __func__,
+ flow.flow_dir == IPSP_DIRECTION_IN ? "in" : "out",
+ print_host(ssrc, NULL, 0), print_host(smask, NULL, 0),
+ print_host(sdst, NULL, 0), print_host(dmask, NULL, 0),
+ print_host(speer, NULL, 0));
+
+ ikev2_acquire(env, &flow);
+
+out:
+ if (errmsg)
+ log_warnx("%s: %s wasn't found", __func__, errmsg);
+ free(reply);
+ break;
+
case SADB_EXPIRE:
if ((sa = pfkey_find_ext(data, len, SADB_EXT_SA)) == NULL) {
- log_warnx("%s: SADB_EXPIRE w/o SA payload", __func__);
+ log_warnx("%s: SA extension wasn't found", __func__);
return;
}
- if ((ltime = pfkey_find_ext(data, len,
+ if ((sa_ltime = pfkey_find_ext(data, len,
SADB_EXT_LIFETIME_SOFT)) == NULL &&
- (ltime = pfkey_find_ext(data, len,
+ (sa_ltime = pfkey_find_ext(data, len,
SADB_EXT_LIFETIME_HARD)) == NULL) {
- log_warnx("%s: SADB_EXPIRE w/o lifetime payload",
+ log_warnx("%s: lifetime extension wasn't found",
__func__);
return;
}
@@ -1327,10 +1520,10 @@ pfkey_process(struct iked *env, struct pfkey_message *pm)
log_debug("%s: SA %s is expired, pending %s", __func__,
print_spi(spi.spi, spi.spi_size),
- ltime->sadb_lifetime_exttype == SADB_EXT_LIFETIME_SOFT ?
+ sa_ltime->sadb_lifetime_exttype == SADB_EXT_LIFETIME_SOFT ?
"rekeying" : "deletion");
- if (ltime->sadb_lifetime_exttype == SADB_EXT_LIFETIME_SOFT)
+ if (sa_ltime->sadb_lifetime_exttype == SADB_EXT_LIFETIME_SOFT)
ikev2_rekey_sa(env, &spi);
else
ikev2_drop_sa(env, &spi);
diff --git a/sbin/iked/policy.c b/sbin/iked/policy.c
index afec36f6cf0..54ef57f1ccd 100644
--- a/sbin/iked/policy.c
+++ b/sbin/iked/policy.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: policy.c,v 1.12 2010/12/22 16:22:27 mikeb Exp $ */
+/* $OpenBSD: policy.c,v 1.13 2011/01/17 18:49:35 mikeb Exp $ */
/* $vantronix: policy.c,v 1.29 2010/05/28 15:34:35 reyk Exp $ */
/*
@@ -49,6 +49,9 @@ static __inline int
user_cmp(struct iked_user *, struct iked_user *);
static __inline int
childsa_cmp(struct iked_childsa *, struct iked_childsa *);
+static __inline int
+ flow_cmp(struct iked_flow *, struct iked_flow *);
+
void
policy_init(struct iked *env)
@@ -57,6 +60,7 @@ policy_init(struct iked *env)
RB_INIT(&env->sc_users);
RB_INIT(&env->sc_sas);
RB_INIT(&env->sc_ipsecsas);
+ RB_INIT(&env->sc_acqflows);
}
int
@@ -423,3 +427,36 @@ childsa_cmp(struct iked_childsa *a, struct iked_childsa *b)
}
RB_GENERATE(iked_ipsecsas, iked_childsa, csa_ipsec_entry, childsa_cmp);
+
+static __inline int
+addr_cmp(struct iked_addr *a, struct iked_addr *b, int useports)
+{
+ int diff = 0;
+ int prefix;
+
+ prefix = MAX(a->addr_mask, b->addr_mask);
+ diff = sockaddr_cmp((struct sockaddr *)&a->addr,
+ (struct sockaddr *)&b->addr, prefix);
+ if (!diff && useports)
+ diff = a->addr_port - b->addr_port;
+
+ return (diff);
+}
+
+static __inline int
+flow_cmp(struct iked_flow *a, struct iked_flow *b)
+{
+ int diff = 0;
+
+ 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)
+ diff = (int)a->flow_dir - (int)b->flow_dir;
+
+ return (diff);
+}
+
+RB_GENERATE(iked_acqflows, iked_flow, flow_acq_entry, flow_cmp);
diff --git a/sbin/iked/types.h b/sbin/iked/types.h
index 7e1e9f8daed..31d796aea2b 100644
--- a/sbin/iked/types.h
+++ b/sbin/iked/types.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: types.h,v 1.7 2010/12/22 16:22:27 mikeb Exp $ */
+/* $OpenBSD: types.h,v 1.8 2011/01/17 18:49:35 mikeb Exp $ */
/* $vantronix: types.h,v 1.24 2010/05/11 12:05:56 reyk Exp $ */
/*
@@ -53,7 +53,7 @@
#define IKED_MSGBUF_MAX 8192
#define IKED_CFG_MAX 16 /* maximum CP attributes */
#define IKED_TAG_SIZE 64
-#define IKED_CYCLE_BUFFERS 4 /* # of static buffers for mapping */
+#define IKED_CYCLE_BUFFERS 8 /* # of static buffers for mapping */
#define IKED_PASSWORD_SIZE 256 /* limited by most EAP types */
#define IKED_LIFETIME_BYTES 536870912 /* 512 Mb */