diff options
author | Mike Belopuhov <mikeb@cvs.openbsd.org> | 2012-06-22 16:28:21 +0000 |
---|---|---|
committer | Mike Belopuhov <mikeb@cvs.openbsd.org> | 2012-06-22 16:28:21 +0000 |
commit | 8a9bcae3da71cb6d59e5b362f3d825f6bdbf76e8 (patch) | |
tree | 1f1b84ac3599b3b605733285a3b59fc128a1a26d | |
parent | 707f71f072ef5342a75159bb0c14b5a58fad2f8f (diff) |
Add initial support for retransmition timeouts and response retries.
This should still be considered an experimental work in progress.
-rw-r--r-- | sbin/iked/config.c | 7 | ||||
-rw-r--r-- | sbin/iked/iked.h | 34 | ||||
-rw-r--r-- | sbin/iked/ikev2.c | 155 | ||||
-rw-r--r-- | sbin/iked/ikev2_msg.c | 180 |
4 files changed, 297 insertions, 79 deletions
diff --git a/sbin/iked/config.c b/sbin/iked/config.c index b44a00eb3e0..2141b4eb37b 100644 --- a/sbin/iked/config.c +++ b/sbin/iked/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.13 2011/07/05 19:59:00 tedu Exp $ */ +/* $OpenBSD: config.c,v 1.14 2012/06/22 16:28:20 mikeb Exp $ */ /* $vantronix: config.c,v 1.30 2010/05/28 15:34:35 reyk Exp $ */ /* @@ -56,6 +56,8 @@ config_new_sa(struct iked *env, int initiator) TAILQ_INIT(&sa->sa_proposals); TAILQ_INIT(&sa->sa_childsas); TAILQ_INIT(&sa->sa_flows); + TAILQ_INIT(&sa->sa_requests); + TAILQ_INIT(&sa->sa_responses); sa->sa_hdr.sh_initiator = initiator; sa->sa_type = IKED_SATYPE_LOCAL; @@ -96,6 +98,9 @@ config_free_sa(struct iked *env, struct iked_sa *sa) policy_unref(env, sa->sa_policy); } + ikev2_msg_flushqueue(env, &sa->sa_requests); + ikev2_msg_flushqueue(env, &sa->sa_responses); + ibuf_release(sa->sa_inonce); ibuf_release(sa->sa_rnonce); diff --git a/sbin/iked/iked.h b/sbin/iked/iked.h index 3aa52867836..72f3147f6c7 100644 --- a/sbin/iked/iked.h +++ b/sbin/iked/iked.h @@ -1,4 +1,4 @@ -/* $OpenBSD: iked.h,v 1.48 2012/06/22 16:06:31 mikeb Exp $ */ +/* $OpenBSD: iked.h,v 1.49 2012/06/22 16:28:20 mikeb Exp $ */ /* $vantronix: iked.h,v 1.61 2010/06/03 07:57:33 reyk Exp $ */ /* @@ -325,6 +325,8 @@ struct iked_id { #define IKED_REQ_BITS \ "\10\01CERT\02VALID\03AUTH\04SA" +TAILQ_HEAD(iked_msgqueue, iked_message); + struct iked_sahdr { u_int64_t sh_ispi; /* Initiator SPI */ u_int64_t sh_rspi; /* Responder SPI */ @@ -398,6 +400,12 @@ struct iked_sa { struct iked_childsas sa_childsas; /* IPSec Child SAs */ struct iked_saflows sa_flows; /* IPSec flows */ + struct iked_msgqueue sa_requests; /* request queue */ +#define IKED_RETRANSMIT_TIMEOUT 2 /* 2 seconds */ + + struct iked_msgqueue sa_responses; /* response queue */ +#define IKED_RESPONSE_TIMEOUT 120 /* 2 minutes */ + RB_ENTRY(iked_sa) sa_peer_entry; RB_ENTRY(iked_sa) sa_entry; }; @@ -426,6 +434,8 @@ struct iked_message { struct iked_policy *msg_policy; struct iked_sa *msg_sa; + u_int32_t msg_msgid; + /* Parsed information */ struct iked_proposals msg_proposals; struct iked_spi msg_rekey; @@ -438,6 +448,14 @@ struct iked_message { /* Parse stack */ struct iked_proposal *msg_prop; u_int16_t msg_attrlength; + + /* Retransmit queue */ + struct iked_timer msg_timer; + TAILQ_ENTRY(iked_message) + msg_entry; + int msg_tries; /* retransmits sent */ +#define IKED_RETRANSMIT_TRIES 5 /* try 5 times */ + }; struct iked_user { @@ -691,9 +709,11 @@ struct ibuf * ikev2_msg_init(struct iked *, struct iked_message *, struct sockaddr_storage *, socklen_t, struct sockaddr_storage *, socklen_t, int); +struct iked_message * + ikev2_msg_copy(struct iked *, struct iked_message *); void ikev2_msg_cleanup(struct iked *, struct iked_message *); u_int32_t - ikev2_msg_id(struct iked *, struct iked_sa *, int); + ikev2_msg_id(struct iked *, struct iked_sa *); struct ibuf *ikev2_msg_auth(struct iked *, struct iked_sa *, int); int ikev2_msg_authsign(struct iked *, struct iked_sa *, @@ -714,6 +734,16 @@ int ikev2_msg_integr(struct iked *, struct iked_sa *, struct ibuf *); int ikev2_msg_frompeer(struct iked_message *); struct iked_socket * ikev2_msg_getsocket(struct iked *, int); +int ikev2_msg_retransmit_response(struct iked *, struct iked_sa *, + struct iked_message *); +void ikev2_msg_prevail(struct iked *, struct iked_msgqueue *, + struct iked_message *); +void ikev2_msg_dispose(struct iked *, struct iked_msgqueue *, + struct iked_message *); +void ikev2_msg_flushqueue(struct iked *, struct iked_msgqueue *); +struct iked_message * + ikev2_msg_lookup(struct iked *, struct iked_msgqueue *, + struct iked_message *); /* ikev2_pld.c */ int ikev2_pld_parse(struct iked *, struct ike_header *, diff --git a/sbin/iked/ikev2.c b/sbin/iked/ikev2.c index e3102c65746..6d56b5224c9 100644 --- a/sbin/iked/ikev2.c +++ b/sbin/iked/ikev2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2.c,v 1.66 2012/06/22 16:06:31 mikeb Exp $ */ +/* $OpenBSD: ikev2.c,v 1.67 2012/06/22 16:28:20 mikeb Exp $ */ /* $vantronix: ikev2.c,v 1.101 2010/06/03 07:57:33 reyk Exp $ */ /* @@ -340,9 +340,17 @@ ikev2_getimsgdata(struct iked *env, struct imsg *imsg, struct iked_sahdr *sh, void ikev2_recv(struct iked *env, struct iked_message *msg) { + enum { + ST_START, + ST_REQUEST, + ST_RESPONSE, + ST_FINISH + } state = ST_START; struct ike_header *hdr; + struct iked_message *m; struct iked_sa *sa; u_int initiator, flag = 0; + int ignore = 0, response = 0; hdr = ibuf_seek(msg->msg_data, msg->msg_offset, sizeof(*hdr)); @@ -354,16 +362,20 @@ ikev2_recv(struct iked *env, struct iked_message *msg) msg->msg_sa = sa_lookup(env, betoh64(hdr->ike_ispi), betoh64(hdr->ike_rspi), initiator); + msg->msg_msgid = betoh32(hdr->ike_msgid); if (policy_lookup(env, msg) != 0) return; - log_info("%s: %s from %s %s to %s policy '%s', %ld bytes", __func__, - print_map(hdr->ike_exchange, ikev2_exchange_map), + log_info("%s: %s from %s %s to %s policy '%s' id %u, %ld bytes", + __func__, print_map(hdr->ike_exchange, ikev2_exchange_map), initiator ? "responder" : "initiator", print_host(&msg->msg_peer, NULL, 0), print_host(&msg->msg_local, NULL, 0), - msg->msg_policy->pol_name, + msg->msg_policy->pol_name, msg->msg_msgid, ibuf_length(msg->msg_data)); + log_debug("%s: ispi %s rspi %s", __func__, + print_spi(betoh64(hdr->ike_ispi), 8), + print_spi(betoh64(hdr->ike_rspi), 8)); if ((sa = msg->msg_sa) == NULL) goto done; @@ -373,53 +385,77 @@ ikev2_recv(struct iked *env, struct iked_message *msg) if (msg->msg_natt) sa->sa_natt = 1; - switch (hdr->ike_exchange) { - case IKEV2_EXCHANGE_CREATE_CHILD_SA: - flag = IKED_REQ_CHILDSA; - goto xchgcommon; - - case IKEV2_EXCHANGE_INFORMATIONAL: - flag = IKED_REQ_INF; - xchgcommon: - if ((sa->sa_stateflags & flag)) { - /* response */ - if (betoh32(hdr->ike_msgid) == sa->sa_reqid - 1) - /* we initiated the exchange */ - initiator = 1; - else { - if (flag == IKED_REQ_CHILDSA) - ikev2_disable_rekeying(env, sa); - goto errout; /* unexpected id */ - } - } else { - /* request */ - if (betoh32(hdr->ike_msgid) >= sa->sa_msgid) { - /* we are responding */ + do switch (state) { + case ST_START: + if (hdr->ike_exchange == IKEV2_EXCHANGE_CREATE_CHILD_SA) + flag = IKED_REQ_CHILDSA; + if (hdr->ike_exchange == IKEV2_EXCHANGE_INFORMATIONAL) + flag = IKED_REQ_INF; + if ((flag && (sa->sa_stateflags & flag)) || + (!flag && initiator)) + state = ST_RESPONSE; + else + state = ST_REQUEST; + break; + case ST_REQUEST: + if (msg->msg_msgid >= sa->sa_msgid) { + /* Update if we've initiated this exchange */ + if (flag) initiator = 0; - sa->sa_msgid = betoh32(hdr->ike_msgid); - } else - goto errout; /* unexpected id */ + state = ST_FINISH; + } else if (flag) { + flag = 0; /* Prevent endless looping */ + state = ST_RESPONSE; + } else { + ignore = 1; + state = ST_FINISH; } break; - - default: - if (initiator) { - if (betoh32(hdr->ike_msgid) != sa->sa_reqid - 1) - goto errout; + case ST_RESPONSE: + if (msg->msg_msgid < sa->sa_reqid) { + response = 1; + /* Update if we've initiated this exchange */ + if (flag) + initiator = 1; + state = ST_FINISH; + } else if (flag) { + flag = 0; /* Prevent endless looping */ + state = ST_REQUEST; } else { - if (betoh32(hdr->ike_msgid) < sa->sa_msgid) - goto errout; - else - sa->sa_msgid = betoh32(hdr->ike_msgid); + ignore = 1; + state = ST_FINISH; } break; - errout: - sa->sa_stateflags &= ~flag; - log_debug("%s: invalid sequence number %d " - "(SA msgid %d reqid %d)", __func__, - betoh32(hdr->ike_msgid), sa->sa_msgid, - sa->sa_reqid); - return; + case ST_FINISH: + if (ignore) + return; + break; + } while (state != ST_FINISH); + + if (response) { + /* + * There's no need to keep the request around anymore + */ + if ((m = ikev2_msg_lookup(env, &sa->sa_requests, msg))) + ikev2_msg_dispose(env, &sa->sa_requests, m); + } else { + /* + * See if we have responded to this request before + */ + if ((m = ikev2_msg_lookup(env, &sa->sa_responses, msg))) { + if (ikev2_msg_retransmit_response(env, sa, m)) { + log_warn("%s: failed to retransmit a " + "response", __func__); + sa_free(env, sa); + } + return; + } + /* + * If it's a new request, make sure to update the peer's + * message ID and dispose of all previous responses + */ + sa->sa_msgid = msg->msg_msgid; + ikev2_msg_prevail(env, &sa->sa_responses, msg); } if (sa_address(sa, &sa->sa_peer, &msg->msg_peer, initiator) == -1 || @@ -590,6 +626,9 @@ ikev2_init_recv(struct iked *env, struct iked_message *msg, break; case IKEV2_EXCHANGE_IKE_AUTH: case IKEV2_EXCHANGE_CREATE_CHILD_SA: + if (ikev2_msg_valid_ike_sa(env, hdr, msg) == -1) + return; + break; case IKEV2_EXCHANGE_INFORMATIONAL: break; default: @@ -700,9 +739,10 @@ ikev2_init_ike_sa_peer(struct iked *env, struct iked_policy *pol, req.msg_fd = sock->sock_fd; req.msg_sa = sa; req.msg_sock = sock; + req.msg_msgid = ikev2_msg_id(env, sa); /* IKE header */ - if ((hdr = ikev2_add_header(buf, sa, ikev2_msg_id(env, sa, 0), + if ((hdr = ikev2_add_header(buf, sa, req.msg_msgid, IKEV2_PAYLOAD_SA, IKEV2_EXCHANGE_IKE_SA_INIT, 0)) == NULL) goto done; @@ -1695,9 +1735,10 @@ ikev2_resp_ike_sa_init(struct iked *env, struct iked_message *msg) resp.msg_sa = sa; resp.msg_fd = msg->msg_fd; + resp.msg_msgid = 0; /* IKE header */ - if ((hdr = ikev2_add_header(buf, sa, 0, + if ((hdr = ikev2_add_header(buf, sa, resp.msg_msgid, IKEV2_PAYLOAD_SA, IKEV2_EXCHANGE_IKE_SA_INIT, IKEV2_FLAG_RESPONSE)) == NULL) goto done; @@ -2053,8 +2094,8 @@ ikev2_send_ike_e(struct iked *env, struct iked_sa *sa, struct ibuf *buf, if (ikev2_next_payload(pld, ibuf_size(buf), IKEV2_PAYLOAD_NONE) == -1) goto done; - ret = ikev2_msg_send_encrypt(env, sa, &e, - exchange, firstpayload, response); + ret = ikev2_msg_send_encrypt(env, sa, &e, exchange, firstpayload, + response); done: ibuf_release(e); @@ -2536,9 +2577,10 @@ ikev2_send_informational(struct iked *env, struct iked_message *msg) goto done; if (sa != NULL && msg->msg_e) { + resp.msg_msgid = ikev2_msg_id(env, sa); + /* IKE header */ - if ((hdr = ikev2_add_header(buf, sa, - ikev2_msg_id(env, sa, 0), + if ((hdr = ikev2_add_header(buf, sa, resp.msg_msgid, IKEV2_PAYLOAD_SK, IKEV2_EXCHANGE_INFORMATIONAL, 0)) == NULL) goto done; @@ -2574,11 +2616,11 @@ ikev2_send_informational(struct iked *env, struct iked_message *msg) sah.sa_hdr.sh_ispi = betoh64(hdr->ike_ispi); sah.sa_hdr.sh_initiator = hdr->ike_flags & IKEV2_FLAG_INITIATOR ? 0 : 1; - sa = &sah; + + resp.msg_msgid = ikev2_msg_id(env, &sah); /* IKE header */ - if ((hdr = ikev2_add_header(buf, &sah, - ikev2_msg_id(env, &sah, 0), + if ((hdr = ikev2_add_header(buf, &sah, resp.msg_msgid, IKEV2_PAYLOAD_NOTIFY, IKEV2_EXCHANGE_INFORMATIONAL, 0)) == NULL) goto done; @@ -2589,14 +2631,9 @@ ikev2_send_informational(struct iked *env, struct iked_message *msg) } resp.msg_data = buf; - resp.msg_sa = sa; resp.msg_fd = msg->msg_fd; TAILQ_INIT(&resp.msg_proposals); - sa->sa_hdr.sh_initiator = sa->sa_hdr.sh_initiator ? 0 : 1; - (void)ikev2_pld_parse(env, hdr, &resp, 0); - sa->sa_hdr.sh_initiator = sa->sa_hdr.sh_initiator ? 0 : 1; - ret = ikev2_msg_send(env, &resp); done: diff --git a/sbin/iked/ikev2_msg.c b/sbin/iked/ikev2_msg.c index 43d047ac31e..43504723986 100644 --- a/sbin/iked/ikev2_msg.c +++ b/sbin/iked/ikev2_msg.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2_msg.c,v 1.15 2012/05/30 09:18:14 mikeb Exp $ */ +/* $OpenBSD: ikev2_msg.c,v 1.16 2012/06/22 16:28:20 mikeb Exp $ */ /* $vantronix: ikev2.c,v 1.101 2010/06/03 07:57:33 reyk Exp $ */ /* @@ -47,6 +47,12 @@ #include "eap.h" #include "dh.h" +void ikev2_msg_response_timeout(struct iked *, void *); +void ikev2_msg_retransmit_timeout(struct iked *, void *); +struct iked_message * + ikev2_msg_lookup_by_id(struct iked *, struct iked_msgqueue *, + u_int32_t); + void ikev2_msg_cb(int fd, short event, void *arg) { @@ -128,6 +134,26 @@ ikev2_msg_init(struct iked *env, struct iked_message *msg, return (msg->msg_data); } +struct iked_message * +ikev2_msg_copy(struct iked *env, struct iked_message *msg) +{ + struct iked_message *m = NULL; + struct ibuf *buf; + + if ((m = malloc(sizeof(*m))) == NULL || + (buf = ikev2_msg_init(env, m, &msg->msg_peer, msg->msg_peerlen, + &msg->msg_local, msg->msg_locallen, msg->msg_response)) == NULL || + ibuf_add(buf, ibuf_data(msg->msg_data), ibuf_size(msg->msg_data))) + return (NULL); + + m->msg_fd = msg->msg_fd; + m->msg_msgid = msg->msg_msgid; + m->msg_offset = msg->msg_offset; + m->msg_sa = msg->msg_sa; + + return (m); +} + void ikev2_msg_cleanup(struct iked *env, struct iked_message *msg) { @@ -190,8 +216,10 @@ ikev2_msg_valid_ike_sa(struct iked *env, struct ike_header *oldhdr, sa.sa_hdr.sh_ispi = betoh64(oldhdr->ike_ispi); sa.sa_hdr.sh_rspi = betoh64(oldhdr->ike_rspi); + resp.msg_msgid = betoh32(oldhdr->ike_msgid); + /* IKE header */ - if ((hdr = ikev2_add_header(buf, &sa, betoh32(oldhdr->ike_msgid), + if ((hdr = ikev2_add_header(buf, &sa, resp.msg_msgid, IKEV2_PAYLOAD_NOTIFY, IKEV2_EXCHANGE_INFORMATIONAL, IKEV2_FLAG_RESPONSE)) == NULL) goto done; @@ -225,9 +253,11 @@ ikev2_msg_valid_ike_sa(struct iked *env, struct ike_header *oldhdr, int ikev2_msg_send(struct iked *env, struct iked_message *msg) { + struct iked_sa *sa = msg->msg_sa; struct ibuf *buf = msg->msg_data; u_int32_t natt = 0x00000000; struct ike_header *hdr; + struct iked_message *m; if (buf == NULL || (hdr = ibuf_seek(msg->msg_data, msg->msg_offset, sizeof(*hdr))) == NULL) @@ -244,6 +274,7 @@ ikev2_msg_send(struct iked *env, struct iked_message *msg) log_debug("%s: failed to set NAT-T", __func__); return (-1); } + msg->msg_offset += sizeof(natt); } if ((sendto(msg->msg_fd, ibuf_data(buf), ibuf_size(buf), 0, @@ -252,18 +283,34 @@ ikev2_msg_send(struct iked *env, struct iked_message *msg) return (-1); } + if (!sa) + return (0); + + if ((m = ikev2_msg_copy(env, msg)) == NULL) { + log_debug("%s: failed to copy a message", __func__); + return (-1); + } + + if (hdr->ike_flags & IKEV2_FLAG_RESPONSE) { + TAILQ_INSERT_TAIL(&sa->sa_responses, m, msg_entry); + timer_initialize(env, &m->msg_timer, + ikev2_msg_response_timeout, m); + timer_register(env, &m->msg_timer, IKED_RESPONSE_TIMEOUT); + } else { + TAILQ_INSERT_TAIL(&sa->sa_requests, m, msg_entry); + timer_initialize(env, &m->msg_timer, + ikev2_msg_retransmit_timeout, m); + timer_register(env, &m->msg_timer, IKED_RETRANSMIT_TIMEOUT); + } + return (0); } u_int32_t -ikev2_msg_id(struct iked *env, struct iked_sa *sa, int response) +ikev2_msg_id(struct iked *env, struct iked_sa *sa) { - u_int32_t id; + u_int32_t id = sa->sa_reqid; - if (response) - return (sa->sa_msgid); - - id = sa->sa_reqid; if (++sa->sa_reqid == UINT32_MAX) { /* XXX we should close and renegotiate the connection now */ log_debug("%s: IKEv2 message sequence overflow", __func__); @@ -527,8 +574,8 @@ ikev2_msg_decrypt(struct iked *env, struct iked_sa *sa, } int -ikev2_msg_send_encrypt(struct iked *env, struct iked_sa *sa, - struct ibuf **ep, u_int8_t exchange, u_int8_t firstpayload, int response) +ikev2_msg_send_encrypt(struct iked *env, struct iked_sa *sa, struct ibuf **ep, + u_int8_t exchange, u_int8_t firstpayload, int response) { struct iked_message resp; struct ike_header *hdr; @@ -536,16 +583,16 @@ ikev2_msg_send_encrypt(struct iked *env, struct iked_sa *sa, struct ibuf *buf, *e = *ep; int ret = -1; - if ((buf = ikev2_msg_init(env, &resp, - &sa->sa_peer.addr, sa->sa_peer.addr.ss_len, - &sa->sa_local.addr, sa->sa_local.addr.ss_len, 1)) == NULL) + if ((buf = ikev2_msg_init(env, &resp, &sa->sa_peer.addr, + sa->sa_peer.addr.ss_len, &sa->sa_local.addr, + sa->sa_local.addr.ss_len, response)) == NULL) goto done; + resp.msg_msgid = response ? sa->sa_msgid : ikev2_msg_id(env, sa); + /* IKE header */ - if ((hdr = ikev2_add_header(buf, sa, - ikev2_msg_id(env, sa, response), - IKEV2_PAYLOAD_SK, exchange, - response ? IKEV2_FLAG_RESPONSE : 0)) == NULL) + if ((hdr = ikev2_add_header(buf, sa, resp.msg_msgid, IKEV2_PAYLOAD_SK, + exchange, response ? IKEV2_FLAG_RESPONSE : 0)) == NULL) goto done; if ((pld = ikev2_add_payload(buf)) == NULL) @@ -841,3 +888,102 @@ ikev2_msg_getsocket(struct iked *env, int af) log_debug("%s: af socket %d not available", __func__, af); return (NULL); } + +void +ikev2_msg_prevail(struct iked *env, struct iked_msgqueue *queue, + struct iked_message *msg) +{ + struct iked_message *m = NULL; + + while ((m = TAILQ_FIRST(queue)) != NULL) { + if (m->msg_msgid < msg->msg_msgid) + ikev2_msg_dispose(env, queue, m); + } +} + +void +ikev2_msg_dispose(struct iked *env, struct iked_msgqueue *queue, + struct iked_message *msg) +{ + TAILQ_REMOVE(queue, msg, msg_entry); + timer_deregister(env, &msg->msg_timer); + ikev2_msg_cleanup(env, msg); + free(msg); +} + +void +ikev2_msg_flushqueue(struct iked *env, struct iked_msgqueue *queue) +{ + struct iked_message *m = NULL; + + while ((m = TAILQ_FIRST(queue)) != NULL) + ikev2_msg_dispose(env, queue, m); +} + +struct iked_message * +ikev2_msg_lookup_by_id(struct iked *env, struct iked_msgqueue *queue, + u_int32_t msgid) +{ + struct iked_message *m = NULL; + + TAILQ_FOREACH(m, queue, msg_entry) { + if (m->msg_msgid == msgid) + break; + } + return (m); +} + +struct iked_message * +ikev2_msg_lookup(struct iked *env, struct iked_msgqueue *queue, + struct iked_message *msg) +{ + return (ikev2_msg_lookup_by_id(env, queue, msg->msg_msgid)); +} + +int +ikev2_msg_retransmit_response(struct iked *env, struct iked_sa *sa, + struct iked_message *msg) +{ + if ((sendto(msg->msg_fd, ibuf_data(msg->msg_data), + ibuf_size(msg->msg_data), 0, (struct sockaddr *)&msg->msg_peer, + msg->msg_peerlen)) == -1) { + log_warn("%s: sendto", __func__); + sa_free(env, sa); + return (-1); + } + + timer_register(env, &msg->msg_timer, IKED_RESPONSE_TIMEOUT); + return (0); +} + +void +ikev2_msg_response_timeout(struct iked *env, void *arg) +{ + struct iked_message *msg = arg; + struct iked_sa *sa = msg->msg_sa; + + ikev2_msg_dispose(env, &sa->sa_responses, msg); +} + +void +ikev2_msg_retransmit_timeout(struct iked *env, void *arg) +{ + struct iked_message *msg = arg; + struct iked_sa *sa = msg->msg_sa; + + if ((sendto(msg->msg_fd, ibuf_data(msg->msg_data), + ibuf_size(msg->msg_data), 0, + (struct sockaddr *)&msg->msg_peer, msg->msg_peerlen)) == -1) { + log_warn("%s: sendto", __func__); + sa_free(env, sa); + return; + } + + if (msg->msg_tries < IKED_RETRANSMIT_TRIES) { + TAILQ_INSERT_TAIL(&sa->sa_requests, msg, msg_entry); + /* Exponential timeout */ + timer_register(env, &msg->msg_timer, + IKED_RETRANSMIT_TIMEOUT * (2 << (msg->msg_tries++))); + } else + sa_free(env, sa); +} |