diff --git a/README b/README index 7f54503..bf64130 100644 --- a/README +++ b/README @@ -2,12 +2,13 @@ Experimental QUIC support for nginx ----------------------------------- 1. Introduction -2. Installing +2. Building from sources 3. Configuration -4. Clients -5. Troubleshooting -6. Contributing -7. Links +4. Directives +5. Clients +6. Troubleshooting +7. Contributing +8. Links 1. Introduction @@ -51,7 +52,16 @@ Experimental QUIC support for nginx + Lost packets are detected and retransmitted properly + Clients may migrate to new address -2. Installing +2. Building from sources + + The build is configured using the configure command. + Refer to http://nginx.org/en/docs/configure.html for details. + + When configuring nginx, it's possible to enable QUIC and HTTP/3 + using the following new configuration options: + + --with-http_v3_module - enable QUIC and HTTP/3 + --with-stream_quic_module - enable QUIC in Stream A library that provides QUIC support is required to build nginx, there are several of those available on the market: @@ -85,12 +95,6 @@ Experimental QUIC support for nginx --with-cc-opt="-I../libressl/build/include" \ --with-ld-opt="-L../libressl/build/lib" - When configuring nginx, it's possible to enable QUIC and HTTP/3 - using the following new configuration options: - - --with-http_v3_module - enable QUIC and HTTP/3 - --with-stream_quic_module - enable QUIC in Stream - 3. Configuration The HTTP "listen" directive got a new option "http3" which enables @@ -174,7 +178,129 @@ Example configuration: } } -4. Clients +4. Directives + + Syntax: quic_bpf on | off; + Default: quic_bpf off; + Context: main + + Enables routing of QUIC packets using eBPF. + When enabled, this allows to support QUIC connection migration. + The directive is only supported on Linux 5.7+. + + + Syntax: quic_retry on | off; + Default: quic_retry off; + Context: http | stream, server + + Enables the QUIC Address Validation feature. This includes: + - sending a new token in a Retry packet or a NEW_TOKEN frame + - validating a token received in the Initial packet + + + Syntax: quic_gso on | off; + Default: quic_gso off; + Context: http | stream, server + + Enables sending in optimized batch mode using segmentation offloading. + Optimized sending is only supported on Linux featuring UDP_SEGMENT. + + + Syntax: quic_mtu size; + Default: quic_mtu 65527; + Context: http | stream, server + + Sets the QUIC max_udp_payload_size transport parameter value. + This is the maximum UDP payload that we are willing to receive. + + + Syntax: quic_host_key file; + Default: - + Context: http | stream, server + + Specifies a file with the secret key used to encrypt stateless reset and + address validation tokens. By default, a randomly generated key is used. + + + Syntax: quic_active_connection_id_limit number; + Default: quic_active_connection_id_limit 2; + Context: http | stream, server + + Sets the QUIC active_connection_id_limit transport parameter value. + This is the maximum number of connection IDs we are willing to store. + + + Syntax: quic_timeout time; + Default: quic_timeout 60s; + Context: stream, server + + Defines a timeout used to negotiate the QUIC idle timeout. + In the http module, it is taken from the keepalive_timeout directive. + + + Syntax: quic_stream_buffer_size size; + Default: quic_stream_buffer_size 64k; + Context: stream, server + + Syntax: http3_stream_buffer_size size; + Default: http3_stream_buffer_size 64k; + Context: http, server + + Sets buffer size for reading and writing of the QUIC STREAM payload. + The buffer size is used to calculate initial flow control limits + in the following QUIC transport parameters: + - initial_max_data + - initial_max_stream_data_bidi_local + - initial_max_stream_data_bidi_remote + - initial_max_stream_data_uni + + + Syntax: http3_max_concurrent_pushes number; + Default: http3_max_concurrent_pushes 10; + Context: http, server + + Limits the maximum number of concurrent push requests in a connection. + + + Syntax: http3_max_concurrent_streams number; + Default: http3_max_concurrent_streams 128; + Context: http, server + + Sets the maximum number of concurrent HTTP/3 streams in a connection. + + + Syntax: http3_push uri | off; + Default: http3_push off; + Context: http, server, location + + Pre-emptively sends (pushes) a request to the specified uri along with + the response to the original request. Only relative URIs with absolute + path will be processed, for example: + + http3_push /static/css/main.css; + + The uri value can contain variables. + + Several http3_push directives can be specified on the same configuration + level. The off parameter cancels the effect of the http3_push directives + inherited from the previous configuration level. + + + Syntax: http3_push_preload on | off; + Default: http3_push_preload off; + Context: http, server, location + + Enables automatic conversion of preload links specified in the “Link” + response header fields into push requests. + + + Syntax: http3_hq on | off; + Default: http3_hq off; + Context: http, server + + Enables HTTP/0.9 protocol negotiation used in QUIC interoperability tests. + +5. Clients * Browsers @@ -201,7 +327,7 @@ Example configuration: "nghttp3/ngtcp2 client" "quic" -5. Troubleshooting +6. Troubleshooting Here are some tips that may help to identify problems: @@ -231,16 +357,16 @@ Example configuration: #define NGX_QUIC_DEBUG_ALLOC #define NGX_QUIC_DEBUG_CRYPTO -6. Contributing +7. Contributing Please refer to http://nginx.org/en/docs/contributing_changes.html -7. Links +8. Links [1] https://datatracker.ietf.org/doc/html/rfc9000 [2] https://datatracker.ietf.org/doc/html/rfc9114 - [3] https://mailman.nginx.org/mailman3/lists/nginx-devel.nginx.org/ + [3] https://mailman.nginx.org/mailman/listinfo/nginx-devel [4] https://boringssl.googlesource.com/boringssl/ [5] https://www.libressl.org/ [6] https://github.com/quictls/openssl diff --git a/lib/boringssl b/lib/boringssl index 45b8d7b..04b3a96 160000 --- a/lib/boringssl +++ b/lib/boringssl @@ -1 +1 @@ -Subproject commit 45b8d7bbd771cbf7e116db2ba1f1cc7af959497e +Subproject commit 04b3a96452b57f74f9768b1126f35b7398ddfff3 diff --git a/lib/nginx-http-flv-module b/lib/nginx-http-flv-module index f627b56..01a825c 160000 --- a/lib/nginx-http-flv-module +++ b/lib/nginx-http-flv-module @@ -1 +1 @@ -Subproject commit f627b56c311f146924768b0376afd69bd3e3e819 +Subproject commit 01a825c502c18a434a2dac307a06b711a5709ab7 diff --git a/lib/ngx-fancyindex b/lib/ngx-fancyindex index f50d7b7..cbc0d3f 160000 --- a/lib/ngx-fancyindex +++ b/lib/ngx-fancyindex @@ -1 +1 @@ -Subproject commit f50d7b799f56ba722732f0e7d70da57b455d8aa8 +Subproject commit cbc0d3fca4f06414612de441399393d4b3bbb315 diff --git a/lib/pcre b/lib/pcre index d73a949..1de7291 160000 --- a/lib/pcre +++ b/lib/pcre @@ -1 +1 @@ -Subproject commit d73a949ec126592911583ed962e879e849e05733 +Subproject commit 1de7291a8cc939e1d345131e7ac89111dd7c670d diff --git a/lib/zlib b/lib/zlib index 8856740..b37f323 160000 --- a/lib/zlib +++ b/lib/zlib @@ -1 +1 @@ -Subproject commit 885674026394870b7e7a05b7bf1ec5eb7bd8a9c0 +Subproject commit b37f323dc5bf7dc450d5c179051dc7065350af26 diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 7a84947..d447908 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -33,9 +33,6 @@ static int ngx_ssl_new_client_session(ngx_ssl_conn_t *ssl_conn, #ifdef SSL_READ_EARLY_DATA_SUCCESS static ngx_int_t ngx_ssl_try_early_data(ngx_connection_t *c); #endif -#if (NGX_DEBUG) -static void ngx_ssl_handshake_log(ngx_connection_t *c); -#endif static void ngx_ssl_handshake_handler(ngx_event_t *ev); #ifdef SSL_READ_EARLY_DATA_SUCCESS static ssize_t ngx_ssl_recv_early(ngx_connection_t *c, u_char *buf, @@ -2053,7 +2050,7 @@ ngx_ssl_try_early_data(ngx_connection_t *c) #if (NGX_DEBUG) -static void +void ngx_ssl_handshake_log(ngx_connection_t *c) { char buf[129], *s, *d; diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h index c76f201..468911b 100644 --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -323,6 +323,9 @@ ngx_int_t ngx_ssl_get_client_v_remain(ngx_connection_t *c, ngx_pool_t *pool, ngx_int_t ngx_ssl_handshake(ngx_connection_t *c); +#if (NGX_DEBUG) +void ngx_ssl_handshake_log(ngx_connection_t *c); +#endif ssize_t ngx_ssl_recv(ngx_connection_t *c, u_char *buf, size_t size); ssize_t ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size); ssize_t ngx_ssl_recv_chain(ngx_connection_t *c, ngx_chain_t *cl, off_t limit); diff --git a/src/event/quic/ngx_event_quic_output.c b/src/event/quic/ngx_event_quic_output.c index 940432a..d2ced99 100644 --- a/src/event/quic/ngx_event_quic_output.c +++ b/src/event/quic/ngx_event_quic_output.c @@ -644,7 +644,7 @@ ngx_quic_output_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, if (len < min_payload) { ngx_memset(p, NGX_QUIC_FT_PADDING, min_payload - len); len = min_payload; - } + } pkt.payload.data = src; pkt.payload.len = len; @@ -1254,7 +1254,7 @@ ngx_quic_frame_sendto(ngx_connection_t *c, ngx_quic_frame_t *frame, if (len < (ssize_t) min_payload) { ngx_memset(src + len, NGX_QUIC_FT_PADDING, min_payload - len); len = min_payload; - } + } pkt.payload.data = src; pkt.payload.len = len; diff --git a/src/event/quic/ngx_event_quic_ssl.c b/src/event/quic/ngx_event_quic_ssl.c index b3059cb..f23260d 100644 --- a/src/event/quic/ngx_event_quic_ssl.c +++ b/src/event/quic/ngx_event_quic_ssl.c @@ -190,7 +190,7 @@ ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn, SSL_get0_alpn_selected(ssl_conn, &alpn_data, &alpn_len); if (alpn_len == 0) { - qc->error = 0x100 + SSL_AD_NO_APPLICATION_PROTOCOL; + qc->error = NGX_QUIC_ERR_CRYPTO(SSL_AD_NO_APPLICATION_PROTOCOL); qc->error_reason = "unsupported protocol in ALPN extension"; ngx_log_error(NGX_LOG_INFO, c->log, 0, @@ -301,6 +301,7 @@ ngx_quic_send_alert(ngx_ssl_conn_t *ssl_conn, enum ssl_encryption_level_t level, } qc->error = NGX_QUIC_ERR_CRYPTO(alert); + qc->error_reason = "handshake failed"; return 1; } @@ -422,8 +423,15 @@ ngx_quic_crypto_input(ngx_connection_t *c, ngx_chain_t *data) sslerr); if (sslerr != SSL_ERROR_WANT_READ) { + + if (c->ssl->handshake_rejected) { + ngx_connection_error(c, 0, "handshake rejected"); + ERR_clear_error(); + + return NGX_ERROR; + } + ngx_ssl_error(NGX_LOG_ERR, c->log, 0, "SSL_do_handshake() failed"); - qc->error_reason = "handshake failed"; return NGX_ERROR; } } @@ -440,11 +448,9 @@ ngx_quic_crypto_input(ngx_connection_t *c, ngx_chain_t *data) return NGX_OK; } - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic ssl cipher:%s", SSL_get_cipher(ssl_conn)); - - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic handshake completed successfully"); +#if (NGX_DEBUG) + ngx_ssl_handshake_log(c); +#endif c->ssl->handshaked = 1; diff --git a/src/event/quic/ngx_event_quic_streams.c b/src/event/quic/ngx_event_quic_streams.c index db3208c..6f0a752 100644 --- a/src/event/quic/ngx_event_quic_streams.c +++ b/src/event/quic/ngx_event_quic_streams.c @@ -1162,7 +1162,7 @@ ngx_quic_can_shutdown(ngx_connection_t *c) return NGX_DECLINED; } } - } + } return NGX_OK; }