QUIC APL: Introduce addressed v. non-addressed mode handling
authorHugo Landau <hlandau@openssl.org>
Wed, 9 Aug 2023 16:46:33 +0000 (17:46 +0100)
committerHugo Landau <hlandau@openssl.org>
Fri, 1 Sep 2023 09:45:34 +0000 (10:45 +0100)
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/21715)

ssl/quic/quic_impl.c
ssl/quic/quic_local.h

index d56c64f97f9bf644c82e716ff8a42e9c711715e6..49133f0ca7e38cb8c81a60f3a0be79f264904477 100644 (file)
@@ -816,7 +816,7 @@ uint64_t ossl_quic_get_options(const SSL *ssl)
  */
 static int csm_analyse_init_peer_addr(BIO *net_wbio, BIO_ADDR *peer)
 {
-    if (BIO_dgram_get_peer(net_wbio, peer) <= 0)
+    if (BIO_dgram_detect_peer_addr(net_wbio, peer) <= 0)
         return 0;
 
     return 1;
@@ -1518,12 +1518,6 @@ static int quic_do_handshake(QCTX *ctx)
     if (!quic_mutation_allowed(qc, /*req_active=*/0))
         return QUIC_RAISE_NON_NORMAL_ERROR(ctx, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL);
 
-    if (BIO_ADDR_family(&qc->init_peer_addr) == AF_UNSPEC) {
-        /* Peer address must have been set. */
-        QUIC_RAISE_NON_NORMAL_ERROR(ctx, SSL_R_REMOTE_PEER_ADDRESS_NOT_SET, NULL);
-        return -1; /* Non-protocol error */
-    }
-
     if (qc->as_server != qc->as_server_state) {
         QUIC_RAISE_NON_NORMAL_ERROR(ctx, ERR_R_PASSED_INVALID_ARGUMENT, NULL);
         return -1; /* Non-protocol error */
@@ -1535,6 +1529,82 @@ static int quic_do_handshake(QCTX *ctx)
         return -1; /* Non-protocol error */
     }
 
+    /*
+     * We need to determine our addressing mode. There are basically two
+     * ways we can use L4 addresses:
+     *
+     *   - Addressed mode, in which our BIO_sendmmsg calls have destination
+     *     addresses attached to them which we expect the underlying network BIO
+     *     to handle;
+     *
+     *   - Unaddressed mode, in which the BIO provided to us on the
+     *     network side neither provides us with L4 addresses nor is capable of
+     *     honouring ones we provide. We don't know where the QUIC traffic we
+     *     send ends up exactly and trust the application to know what it is
+     *     doing.
+     *
+     * Addressed mode is preferred because it enables support for connection
+     * migration, multipath, etc. in the future. Addressed mode is automatically
+     * enabled if we are using e.g. BIO_s_datagram, with or without
+     * BIO_s_connect.
+     *
+     * If we are passed a BIO_s_dgram_pair (or some custom BIO) we may have to
+     * use unaddressed mode unless that BIO supports capability flags indicating
+     * it can provide and honour L4 addresses.
+     *
+     * Our strategy for determining address mode is simple: we probe the
+     * underlying network BIOs for their capabilities. If the network BIOs
+     * support what we need, we use addressed mode. Otherwise, we use
+     * unaddressed mode.
+     *
+     * If addressed mode is chosen, we require an initial peer address to be
+     * set. If this is not set, we fail. If unaddressed mode is used, we do not
+     * require this, as such an address is superfluous, though it can be set if
+     * desired.
+     */
+    if (!qc->started && !qc->addressing_probe_done) {
+        long rcaps = BIO_dgram_get_effective_caps(qc->net_rbio);
+        long wcaps = BIO_dgram_get_effective_caps(qc->net_wbio);
+        int can_use_addressed =
+            (wcaps & BIO_DGRAM_CAP_HANDLES_DST_ADDR) != 0
+            && (rcaps & BIO_DGRAM_CAP_PROVIDES_SRC_ADDR) != 0;
+
+        qc->addressed_mode          = can_use_addressed;
+        qc->addressing_probe_done   = 1;
+    }
+
+    if (!qc->started && qc->addressed_mode
+        && BIO_ADDR_family(&qc->init_peer_addr) == AF_UNSPEC) {
+        /*
+         * We are trying to connect and are using addressed mode, which means we
+         * need an initial peer address; if we do not have a peer address yet,
+         * we should try to autodetect one.
+         *
+         * We do this as late as possible because some BIOs (e.g. BIO_s_connect)
+         * may not be able to provide us with a peer address until they have
+         * finished their own processing. They may not be able to perform this
+         * processing until an application has figured configuring that BIO
+         * (e.g. with setter calls), which might happen after SSL_set_bio is
+         * called.
+         */
+        if (!csm_analyse_init_peer_addr(qc->net_wbio, &qc->init_peer_addr))
+            /* best effort */
+            BIO_ADDR_clear(&qc->init_peer_addr);
+        else
+            ossl_quic_channel_set_peer_addr(qc->ch, &qc->init_peer_addr);
+    }
+
+    if (!qc->started
+        && qc->addressed_mode
+        && BIO_ADDR_family(&qc->init_peer_addr) == AF_UNSPEC) {
+        /*
+         * If we still don't have a peer address in addressed mode, we can't do
+         * anything.
+         */
+        QUIC_RAISE_NON_NORMAL_ERROR(ctx, SSL_R_REMOTE_PEER_ADDRESS_NOT_SET, NULL);
+        return -1; /* Non-protocol error */
+    }
+
     /*
      * Start connection process. Note we may come here multiple times in
      * non-blocking mode, which is fine.
index d194563c2375c3640cf0dda84af8f0338a69e1c0..aaaab128aa271e4d9e184f0c2b864dc1fd9c7317 100644 (file)
@@ -195,6 +195,12 @@ struct quic_conn_st {
      */
     unsigned int                    shutting_down           : 1;
 
+    /* Have we probed the BIOs for addressing support? */
+    unsigned int                    addressing_probe_done   : 1;
+
+    /* Are we using addressed mode (BIO_sendmmsg with non-NULL peer)? */
+    unsigned int                    addressed_mode          : 1;
+
     /* Default stream type. Defaults to SSL_DEFAULT_STREAM_MODE_AUTO_BIDI. */
     uint32_t                        default_stream_mode;