Skip to content

Commit

Permalink
Trigger retransmission only for fragment 1/x, otherwise each received
Browse files Browse the repository at this point in the history
fragment can trigger retransmission of the full fragment queue.

From RFC7383, 2.6.1:
"[...] that even MUST only trigger a retransmission of the response message
 (fragmented or no) if the Fragment Number field in the received
 fragments is set to 1; otherwise, it MUST be ignored."

from markus
  • Loading branch information
tobhe committed Mar 2, 2024
1 parent ca9bf0e commit 2117af4
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 12 deletions.
7 changes: 5 additions & 2 deletions sbin/iked/iked.h
@@ -1,4 +1,4 @@
/* $OpenBSD: iked.h,v 1.229 2024/02/15 20:10:45 tobhe Exp $ */
/* $OpenBSD: iked.h,v 1.230 2024/03/02 16:16:07 tobhe Exp $ */

/*
* Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de>
Expand Down Expand Up @@ -656,6 +656,7 @@ struct iked_message {
struct iked_addr *msg_cp_addr; /* requested address */
struct iked_addr *msg_cp_addr6; /* requested address */
struct iked_addr *msg_cp_dns; /* requested dns */
uint16_t msg_frag_num;

/* MOBIKE */
int msg_update_sa_addresses;
Expand Down Expand Up @@ -1130,7 +1131,7 @@ struct iked_socket *
int ikev2_msg_enqueue(struct iked *, struct iked_msgqueue *,
struct iked_message *, int);
int ikev2_msg_retransmit_response(struct iked *, struct iked_sa *,
struct iked_message *, uint8_t);
struct iked_message *, struct ike_header *);
void ikev2_msg_prevail(struct iked *, struct iked_msgqueue *,
struct iked_message *);
void ikev2_msg_dispose(struct iked *, struct iked_msgqueue *,
Expand All @@ -1143,6 +1144,8 @@ struct iked_msg_retransmit *
/* ikev2_pld.c */
int ikev2_pld_parse(struct iked *, struct ike_header *,
struct iked_message *, size_t);
int ikev2_pld_parse_quick(struct iked *, struct ike_header *,
struct iked_message *, size_t);

/* eap.c */
int eap_parse(struct iked *, const struct iked_sa *, struct iked_message*,
Expand Down
6 changes: 3 additions & 3 deletions sbin/iked/ikev2.c
@@ -1,4 +1,4 @@
/* $OpenBSD: ikev2.c,v 1.384 2024/02/15 19:11:00 tobhe Exp $ */
/* $OpenBSD: ikev2.c,v 1.385 2024/03/02 16:16:07 tobhe Exp $ */

/*
* Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de>
Expand Down Expand Up @@ -756,8 +756,8 @@ ikev2_recv(struct iked *env, struct iked_message *msg)
* See if we have responded to this request before
* For return values 0 and -1 we have.
*/
if ((r = ikev2_msg_retransmit_response(env, sa, msg,
hdr->ike_exchange)) != -2) {
if ((r = ikev2_msg_retransmit_response(env, sa, msg, hdr))
!= -2) {
if (r == -1) {
log_warn("%s: failed to retransmit a "
"response", __func__);
Expand Down
22 changes: 16 additions & 6 deletions sbin/iked/ikev2_msg.c
@@ -1,4 +1,4 @@
/* $OpenBSD: ikev2_msg.c,v 1.100 2023/08/04 19:06:25 claudio Exp $ */
/* $OpenBSD: ikev2_msg.c,v 1.101 2024/03/02 16:16:07 tobhe Exp $ */

/*
* Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de>
Expand Down Expand Up @@ -1275,15 +1275,25 @@ ikev2_msg_lookup(struct iked *env, struct iked_msgqueue *queue,

int
ikev2_msg_retransmit_response(struct iked *env, struct iked_sa *sa,
struct iked_message *msg, uint8_t exchange)
struct iked_message *msg, struct ike_header *hdr)
{
struct iked_msg_retransmit *mr = NULL;
struct iked_message *m = NULL;
struct iked_message *m = NULL;

if ((mr = ikev2_msg_lookup(env, &sa->sa_responses, msg, exchange))
== NULL)
if ((mr = ikev2_msg_lookup(env, &sa->sa_responses, msg,
hdr->ike_exchange)) == NULL)
return (-2); /* not found */

if (hdr->ike_nextpayload == IKEV2_PAYLOAD_SKF) {
/* only retransmit for fragment number one */
if (ikev2_pld_parse_quick(env, hdr, msg,
msg->msg_offset) != 0 || msg->msg_frag_num != 1) {
log_debug("%s: ignoring fragment", SPI_SA(sa, __func__));
return (0);
}
log_debug("%s: first fragment", SPI_SA(sa, __func__));
}

TAILQ_FOREACH(m, &mr->mrt_frags, msg_entry) {
if (sendtofrom(m->msg_fd, ibuf_data(m->msg_data),
ibuf_size(m->msg_data), 0,
Expand All @@ -1295,7 +1305,7 @@ ikev2_msg_retransmit_response(struct iked *env, struct iked_sa *sa,
}
log_info("%sretransmit %s res %u local %s peer %s",
SPI_SA(sa, NULL),
print_map(exchange, ikev2_exchange_map),
print_map(hdr->ike_exchange, ikev2_exchange_map),
m->msg_msgid,
print_addr(&m->msg_local),
print_addr(&m->msg_peer));
Expand Down
78 changes: 77 additions & 1 deletion sbin/iked/ikev2_pld.c
@@ -1,4 +1,4 @@
/* $OpenBSD: ikev2_pld.c,v 1.133 2023/09/02 18:36:30 tobhe Exp $ */
/* $OpenBSD: ikev2_pld.c,v 1.134 2024/03/02 16:16:07 tobhe Exp $ */

/*
* Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de>
Expand Down Expand Up @@ -2103,3 +2103,79 @@ ikev2_pld_eap(struct iked *env, struct ikev2_payload *pld,

return (0);
}

/* parser for the initial IKE_AUTH payload, does not require msg_sa */
int
ikev2_pld_parse_quick(struct iked *env, struct ike_header *hdr,
struct iked_message *msg, size_t offset)
{
struct ikev2_payload pld;
struct ikev2_frag_payload frag;
uint8_t *msgbuf = ibuf_data(msg->msg_data);
uint8_t *buf;
size_t len, total, left;
size_t length;
unsigned int payload;

log_debug("%s: header ispi %s rspi %s"
" nextpayload %s version 0x%02x exchange %s flags 0x%02x"
" msgid %d length %u response %d", __func__,
print_spi(betoh64(hdr->ike_ispi), 8),
print_spi(betoh64(hdr->ike_rspi), 8),
print_map(hdr->ike_nextpayload, ikev2_payload_map),
hdr->ike_version,
print_map(hdr->ike_exchange, ikev2_exchange_map),
hdr->ike_flags,
betoh32(hdr->ike_msgid),
betoh32(hdr->ike_length),
msg->msg_response);

length = betoh32(hdr->ike_length);

if (ibuf_size(msg->msg_data) < length) {
log_debug("%s: short message", __func__);
return (-1);
}

offset += sizeof(*hdr);

/* Bytes left in datagram. */
total = length - offset;

payload = hdr->ike_nextpayload;

while (payload != 0 && offset < length) {
if (ikev2_validate_pld(msg, offset, total, &pld))
return (-1);

log_debug("%s: %spayload %s"
" nextpayload %s critical 0x%02x length %d",
__func__, msg->msg_e ? "decrypted " : "",
print_map(payload, ikev2_payload_map),
print_map(pld.pld_nextpayload, ikev2_payload_map),
pld.pld_reserved & IKEV2_CRITICAL_PAYLOAD,
betoh16(pld.pld_length));

/* Skip over generic payload header. */
offset += sizeof(pld);
total -= sizeof(pld);
left = betoh16(pld.pld_length) - sizeof(pld);

switch (payload) {
case IKEV2_PAYLOAD_SKF:
len = left;
buf = msgbuf + offset;
if (len < sizeof(frag))
return (-1);
memcpy(&frag, buf, sizeof(frag));
msg->msg_frag_num = betoh16(frag.frag_num);
break;
}

payload = pld.pld_nextpayload;
offset += left;
total -= left;
}

return (0);
}

0 comments on commit 2117af4

Please sign in to comment.