Trigger retransmission only for fragment 1/x, otherwise each received
authortobhe <tobhe@openbsd.org>
Sat, 2 Mar 2024 16:16:07 +0000 (16:16 +0000)
committertobhe <tobhe@openbsd.org>
Sat, 2 Mar 2024 16:16:07 +0000 (16:16 +0000)
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

sbin/iked/iked.h
sbin/iked/ikev2.c
sbin/iked/ikev2_msg.c
sbin/iked/ikev2_pld.c

index 5b65a16..41720d3 100644 (file)
@@ -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>
@@ -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;
@@ -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 *,
@@ -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*,
index 8bbbeb3..d5cc0ed 100644 (file)
@@ -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>
@@ -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__);
index 8e0f748..15ef282 100644 (file)
@@ -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>
@@ -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,
@@ -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));
index f207fbf..1fb5f30 100644 (file)
@@ -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>
@@ -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);
+}