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
-/* $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>
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;
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 *,
/* 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*,
-/* $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>
* 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__);
-/* $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>
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,
}
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));
-/* $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>
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);
+}