diff options
-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 */ |