From: Hugo Landau Date: Thu, 9 Nov 2023 15:30:15 +0000 (+0000) Subject: QUIC PORT: Fix BIO_dgram usage under Winsock due to bind requirement X-Git-Tag: openssl-3.3.0-alpha1~405 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=305133988742829f49e4d552f16ef09914317bdb;p=thirdparty%2Fopenssl.git QUIC PORT: Fix BIO_dgram usage under Winsock due to bind requirement Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/22674) --- diff --git a/ssl/quic/quic_channel.c b/ssl/quic/quic_channel.c index 5bcd66c9e45..60bcc88f84c 100644 --- a/ssl/quic/quic_channel.c +++ b/ssl/quic/quic_channel.c @@ -2255,6 +2255,7 @@ static int ch_tx(QUIC_CHANNEL *ch) res = ossl_quic_tx_packetiser_generate(ch->txp, &status); if (status.sent_pkt > 0) { ch->have_sent_any_pkt = 1; /* Packet(s) were sent */ + ch->port->have_sent_any_pkt = 1; /* * RFC 9000 s. 10.1. 'An endpoint also restarts its idle timer when diff --git a/ssl/quic/quic_port.c b/ssl/quic/quic_port.c index e6dba46bf4a..46f4b34f9bd 100644 --- a/ssl/quic/quic_port.c +++ b/ssl/quic/quic_port.c @@ -323,6 +323,7 @@ QUIC_CHANNEL *ossl_quic_port_create_incoming(QUIC_PORT *port, SSL *tls) ch = port_make_channel(port, tls, /*is_server=*/1); port->tserver_ch = ch; + port->is_server = 1; return ch; } @@ -365,6 +366,25 @@ static void port_rx_pre(QUIC_PORT *port) { int ret; + /* + * Originally, this check (don't RX before we have sent anything if we are + * not a server, because there can't be anything) was just intended as a + * minor optimisation. However, it is actually required on Windows, and + * removing this check will cause Windows to break. + * + * The reason is that under Win32, recvfrom() does not work on a UDP socket + * which has not had bind() called (???). However, calling sendto() will + * automatically bind an unbound UDP socket. Therefore, if we call a Winsock + * recv-type function before calling a Winsock send-type function, that call + * will fail with WSAEINVAL, which we will regard as a permanent network + * error. + * + * Therefore, this check is essential as we do not require our API users to + * bind a socket first when using the API in client mode. + */ + if (!port->is_server && !port->have_sent_any_pkt) + return; + /* * Get DEMUX to BIO_recvmmsg from the network and queue incoming datagrams * to the appropriate QRX instances. diff --git a/ssl/quic/quic_port_local.h b/ssl/quic/quic_port_local.h index 38bb0193d8a..968a48ac420 100644 --- a/ssl/quic/quic_port_local.h +++ b/ssl/quic/quic_port_local.h @@ -87,6 +87,12 @@ struct quic_port_st { /* Inhibit tick for testing purposes? */ unsigned int inhibit_tick : 1; + + /* Has this port sent any packet of any kind yet? */ + unsigned int have_sent_any_pkt : 1; + + /* Does this port allow incoming connections? */ + unsigned int is_server : 1; }; # endif