Commit d53cf1fe3d for openssl.org

commit d53cf1fe3dd9a9ea6066481c6e4bb39128636c11
Author: Sashan <anedvedicky@gmail.com>
Date:   Mon Sep 21 17:11:11 2026 +0200

    Update doc/man3/BIO_s_dgram_pair.pod

    Co-authored-by: Jakub Zelenka <bukka@php.net>
    Reviewed-by: Norbert Pocs <norbertp@openssl.org>
    Reviewed-by: Neil Horman <nhorman@openssl.org>
    Merge-date: Thu Oct 29 11:29:37 2026
    Merged-from: https://github.com/openssl/openssl/pull/32266

diff --git a/.github/workflows/run-checker-ci.yml b/.github/workflows/run-checker-ci.yml
index c46561a679..89186ff03c 100644
--- a/.github/workflows/run-checker-ci.yml
+++ b/.github/workflows/run-checker-ci.yml
@@ -59,7 +59,6 @@ jobs:
           no-tls1_2,
           no-tls1_3,
           enable-trace enable-fips,
-          no-pcap,
           no-quic,
           -DOPENSSL_USE_IPV6=0
         ]
diff --git a/.github/workflows/run-checker-daily.yml b/.github/workflows/run-checker-daily.yml
index 7516a4c9ba..6ea8dc0ec1 100644
--- a/.github/workflows/run-checker-daily.yml
+++ b/.github/workflows/run-checker-daily.yml
@@ -166,6 +166,7 @@ jobs:
           no-x942kdf,
           no-x963kdf,
           enable-zlib-dynamic,
+          enable-pcap,
           -DOPENSSL_PEDANTIC_ZEROIZATION,
           -DOPENSSL_PEDANTIC_ZEROIZATION enable-fips,
           -DOPENSSL_NO_BUILTIN_OVERFLOW_CHECKING,
diff --git a/CHANGES.md b/CHANGES.md
index cb595bd69b..227f0ea594 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -33,6 +33,14 @@ OpenSSL 4.2

 ### Changes between 4.1 and 4.2 [xx XXX xxxx]

+ * Added `BIO_dgram_pair_set0_pcap_file()` which intercepts and writes UDP
+   datagrams exchanged of over `BIO_dgram_pair` bio memory object to file
+   in libpcap format. To enable `BIO_dgram_pair_set0_pcap_file()` the build
+   must be configured with `enable-pcap` option.
+   <!-- https://github.com/openssl/openssl/pull/32266 -->
+
+   *Alexandr Nedvedicky*
+
  * s390x: Disable mod-expo offloading to a crypto card for small exponents.
    Add a new keyword `cex_min_bits:<bits>` for the `OPENSSL_s390xcap`
    environment variable to specify the minimum number of bits that the
@@ -68,6 +76,7 @@ OpenSSL 4.2

    *Viktor Dukhovni*

+
  * `EVP_SKEY_get0_raw_key()` now accepts a NULL key pointer to retrieve only
    the key length.  The length is obtained from the `OSSL_SKEY_PARAM_KEY_LENGTH`
    key parameter without exporting the key, so it is also available for keys
diff --git a/crypto/bio/bss_dgram_pair.c b/crypto/bio/bss_dgram_pair.c
index 0eeff94cd4..71146c147d 100644
--- a/crypto/bio/bss_dgram_pair.c
+++ b/crypto/bio/bss_dgram_pair.c
@@ -316,6 +316,11 @@ struct bio_dgram_peer_st {
      * indexed one per direction.
      */
     struct rbuf_map_st map[2];
+#ifndef OPENSSL_NO_PCAP
+    FILE *tcpdump_f;
+    CRYPTO_MUTEX *pcap_mutex;
+    uint16_t ip_id;
+#endif
 };

 struct bio_dgram_pair_st {
@@ -341,12 +346,6 @@ struct bio_dgram_pair_st {
     unsigned int local_addr_enable : 1; /* Can use BIO_MSG->local? */
     unsigned int role : 1; /* Determines lock order */
     unsigned int grows_on_write : 1; /* Set for BIO_s_dgram_mem only */
-#ifndef OPENSSL_NO_PCAP
-    FILE *tcpdump_f;
-    CRYPTO_MUTEX *pcap_mutex;
-    int owner;
-    uint64_t packet_num;
-#endif
 };

 /*
@@ -482,10 +481,6 @@ static int dgram_pair_free(BIO *bio)
     ring_buf_destroy(&b->rbuf);
     BIO_ADDR_free(b->local_addr);
     CRYPTO_THREAD_lock_free(b->lock);
-#ifndef OPENSSL_NO_PCAP
-    if (b->tcpdump_f != NULL)
-        fclose(b->tcpdump_f);
-#endif
     OPENSSL_free(b);
     return 1;
 }
@@ -608,7 +603,7 @@ static int dgram_pair_ctrl_set_pcap_file(BIO *bio, void *ptr)

 #ifndef OPENSSL_NO_PCAP
 #define LINKTYPE_IPV4 0x00e4 /* IANA type */
-    struct bio_dgram_pair_st *b1, *b2;
+    struct bio_dgram_pair_st *bp;
     char *filename = (char *)ptr;
     static struct {
         uint32_t pcap_magic;
@@ -628,30 +623,23 @@ static int dgram_pair_ctrl_set_pcap_file(BIO *bio, void *ptr)
         .pcap_ltype = LINKTYPE_IPV4,
     };

-    b1 = (struct bio_dgram_pair_st *)bio->ptr;
-    if (b1 == NULL)
+    bp = (struct bio_dgram_pair_st *)bio->ptr;
+    if (bp == NULL)
         return 0;

-    if (b1->peer == NULL)
-        return 0;
-
-    b2 = (struct bio_dgram_pair_st *)b1->peer->ptr;
-    if (b2 == NULL)
+    if (bp->pair == NULL || bp->pair->peer_state == PEER_STATE_ORPHANED)
         return 0;

     if (filename != NULL) {
-        if (b1->tcpdump_f == NULL) {
-            b1->pcap_mutex = ossl_crypto_mutex_new();
-            if (b1->pcap_mutex != NULL) {
-                b1->tcpdump_f = fopen(filename, "wb");
-                if (b1->tcpdump_f != NULL) {
-                    b1->owner = 1;
-                    b2->tcpdump_f = b1->tcpdump_f;
-                    b2->pcap_mutex = b1->pcap_mutex;
+        if (bp->pair->tcpdump_f == NULL) {
+            bp->pair->pcap_mutex = ossl_crypto_mutex_new();
+            if (bp->pair->pcap_mutex != NULL) {
+                bp->pair->tcpdump_f = fopen(filename, "wb");
+                if (bp->pair->tcpdump_f != NULL) {
                     ret = fwrite(&pcap_f_header, sizeof(pcap_f_header), 1,
-                        b1->tcpdump_f);
+                        bp->pair->tcpdump_f);
                 } else {
-                    ossl_crypto_mutex_free(&b1->pcap_mutex);
+                    ossl_crypto_mutex_free(&bp->pair->pcap_mutex);
                 }
             }
         }
@@ -692,26 +680,19 @@ static int dgram_pair_ctrl_destroy_bio_pair(BIO *bio1)
          * The last half of the pair is leaving, clean up the
          * shared data
          */
-#ifndef OPENSSL_NO_PCAP
-        if (b1->tcpdump_f != NULL || b2->tcpdump_f != NULL) {
-            if (b1->owner && b1->tcpdump_f) {
-                fclose(b1->tcpdump_f);
-                ossl_crypto_mutex_free(&b1->pcap_mutex);
-            }
-            if (b2->owner && b2->tcpdump_f) {
-                fclose(b2->tcpdump_f);
-                ossl_crypto_mutex_free(&b2->pcap_mutex);
-            }
-            b1->tcpdump_f = NULL;
-            b2->tcpdump_f = NULL;
-        }
-#endif
         CRYPTO_FREE_REF(&b1->pair->ref_cnt);
         CRYPTO_THREAD_lock_free(b1->pair->map[0].lock);
         CRYPTO_THREAD_lock_free(b1->pair->map[1].lock);
         CRYPTO_THREAD_lock_free(b1->pair->peerlock);
         ring_buf_destroy(&b1->pair->map[0].rbuf);
         ring_buf_destroy(&b1->pair->map[1].rbuf);
+#ifndef OPENSSL_NO_PCAP
+        if (b1->pair->tcpdump_f != NULL) {
+            fclose(b1->pair->tcpdump_f);
+            ossl_crypto_mutex_free(&b1->pair->pcap_mutex);
+            b1->pair->tcpdump_f = NULL;
+        }
+#endif
         OPENSSL_free(b1->pair);
     }
     /*
@@ -1578,7 +1559,7 @@ static void dgram_pcap(struct bio_dgram_pair_st *b, const char *buf, size_t sz)
     OSSL_TIME now;
     struct bio_dgram_pair_st *peer;

-    if (b->tcpdump_f == NULL || sz == 0)
+    if (b->pair->tcpdump_f == NULL || sz == 0)
         return;

     if ((sz + sizeof(ip_hdr) + sizeof(udp_hdr)) > 65535)
@@ -1595,15 +1576,23 @@ static void dgram_pcap(struct bio_dgram_pair_st *b, const char *buf, size_t sz)
     ip_hdr.ip_hv = 0x45;
     ip_hdr.ip_tos = 0;
     ip_hdr.ip_len = htons(len);
-    RAND_bytes((unsigned char *)&ip_hdr.ip_id, 2);
+    ip_hdr.ip_id = b->pair->ip_id++;
     ip_hdr.ip_frag = 0x40; /* don't fragment */
     ip_hdr.ip_foff = 0;
     ip_hdr.ip_ttl = 64;
     ip_hdr.ip_proto = 17;
     ip_hdr.ip_csum = 0; /* wireshark will complain with ?chksum offload? */
-    ip_hdr.ip_src = (b->local_addr == NULL) ? htonl(0x7f000001) : b->local_addr->s_in.sin_addr.s_addr;
-    peer = (struct bio_dgram_pair_st *)b->peer->ptr;
-    ip_hdr.ip_dst = (peer == NULL || peer->local_addr == NULL) ? htonl(0x7f000001) : peer->local_addr->s_in.sin_addr.s_addr;
+    ip_hdr.ip_src = (b->local_addr == NULL)
+        ? htonl(0x7f000001)
+        : b->local_addr->s_in.sin_addr.s_addr;
+    if (b->pair->map[0].self == b) {
+        peer = b->pair->map[1].self;
+    } else {
+        peer = b->pair->map[0].self;
+    }
+    ip_hdr.ip_dst = (peer == NULL || peer->local_addr == NULL)
+        ? htonl(0x7f000001)
+        : peer->local_addr->s_in.sin_addr.s_addr;

     /*
      * use some fake port numbers
@@ -1612,12 +1601,12 @@ static void dgram_pcap(struct bio_dgram_pair_st *b, const char *buf, size_t sz)
     udp_hdr.uh_dport = (peer == NULL || peer->local_addr == NULL) ? htons(4040) : peer->local_addr->s_in.sin_port;
     udp_hdr.uh_csum = 0;
     udp_hdr.uh_len = htons((uint16_t)(sz + sizeof(udp_hdr)));
-    ossl_crypto_mutex_lock(b->pcap_mutex);
-    fwrite(&pcap_hdr, sizeof(pcap_hdr), 1, b->tcpdump_f);
-    fwrite(&ip_hdr, sizeof(ip_hdr), 1, b->tcpdump_f);
-    fwrite(&udp_hdr, sizeof(udp_hdr), 1, b->tcpdump_f);
-    fwrite(buf, sz, 1, b->tcpdump_f);
-    ossl_crypto_mutex_unlock(b->pcap_mutex);
+    ossl_crypto_mutex_lock(b->pair->pcap_mutex);
+    fwrite(&pcap_hdr, sizeof(pcap_hdr), 1, b->pair->tcpdump_f);
+    fwrite(&ip_hdr, sizeof(ip_hdr), 1, b->pair->tcpdump_f);
+    fwrite(&udp_hdr, sizeof(udp_hdr), 1, b->pair->tcpdump_f);
+    fwrite(buf, sz, 1, b->pair->tcpdump_f);
+    ossl_crypto_mutex_unlock(b->pair->pcap_mutex);
 }
 #endif

diff --git a/doc/man3/BIO_s_dgram_pair.pod b/doc/man3/BIO_s_dgram_pair.pod
index 1d2893c86a..1596fd907b 100644
--- a/doc/man3/BIO_s_dgram_pair.pod
+++ b/doc/man3/BIO_s_dgram_pair.pod
@@ -5,7 +5,7 @@
 BIO_s_dgram_pair, BIO_new_bio_dgram_pair, BIO_dgram_set_no_trunc,
 BIO_dgram_get_no_trunc, BIO_dgram_get_effective_caps, BIO_dgram_get_caps,
 BIO_dgram_set_caps, BIO_dgram_set_mtu, BIO_dgram_get_mtu,
-BIO_dgram_set0_local_addr, BIO_dgram_pair_set0_pcap_file  - datagram pair BIO
+BIO_dgram_set0_local_addr, BIO_dgram_pair_set0_pcap_file - datagram pair BIO

 =head1 SYNOPSIS

@@ -242,6 +242,8 @@ BIO_dgram_set_mtu(), BIO_dgram_set_no_trunc() were added in OpenSSL 3.2.

 BIO_dgram_set0_local_addr() was added in OpenSSL 3.5.

+BIO_dgram_pair_set0_pcap_file() was added in OpenSSL 4.2
+
 =head1 COPYRIGHT

 Copyright 2022-2025 The OpenSSL Project Authors. All Rights Reserved.
diff --git a/util/other.syms b/util/other.syms
index b3ce2ecb4a..0ece2234cc 100644
--- a/util/other.syms
+++ b/util/other.syms
@@ -916,3 +916,4 @@ OPENSSL_store_u64_be                    inline
 OPENSSL_store_u64_le                    inline
 OSSL_BEGIN_ALLOW_DEPRECATED             define
 OSSL_END_ALLOW_DEPRECATED               define
+BIO_dgram_pair_set0_pcap_file           define