diff options
author | Mike Belopuhov <mikeb@cvs.openbsd.org> | 2011-01-17 18:49:36 +0000 |
---|---|---|
committer | Mike Belopuhov <mikeb@cvs.openbsd.org> | 2011-01-17 18:49:36 +0000 |
commit | 57107c37ade4d0a2c3efb8a2adf6409acbfeaa6f (patch) | |
tree | 722fdcb18403b4b39edba75f2a0e3c202848704c /sbin/iked | |
parent | c63d84a110ac0f93cc9270920c9ea2d9630910ad (diff) |
Add initial acquire mode support and use it whenever Windows peers decide
to drop Child SA based on the inactivity timer. In this case we instruct
the kernel to send us an acquire message upon receiving a packet for those
hosts and initiate a Child SA creation exchange ourselves.
ok reyk
Diffstat (limited to 'sbin/iked')
-rw-r--r-- | sbin/iked/iked.h | 12 | ||||
-rw-r--r-- | sbin/iked/ikev2.c | 190 | ||||
-rw-r--r-- | sbin/iked/ikev2_pld.c | 8 | ||||
-rw-r--r-- | sbin/iked/pfkey.c | 221 | ||||
-rw-r--r-- | sbin/iked/policy.c | 39 | ||||
-rw-r--r-- | sbin/iked/types.h | 4 |
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 */ |