diff --git a/genheaderfunc.py b/genheaderfunc.py index 4f342364..3f00251e 100755 --- a/genheaderfunc.py +++ b/genheaderfunc.py @@ -31,6 +31,7 @@ HEADERS = [ "user-agent", "date", "content-type", + "nghttpx-0rtt-uniq", # disallowed h1 headers 'connection', 'keep-alive', diff --git a/gennghttpxfun.py b/gennghttpxfun.py index 9cd4fcc3..c7b33270 100755 --- a/gennghttpxfun.py +++ b/gennghttpxfun.py @@ -172,6 +172,7 @@ OPTIONS = [ "tls-anti-replay-memcached-cert-file", "tls-anti-replay-memcached-private-key-file", "tls-anti-replay-memcached-address-family", + "no-strip-incoming-nghttpx-0rtt-uniq", ] LOGVARS = [ diff --git a/src/http2.cc b/src/http2.cc index d672bb46..0f966523 100644 --- a/src/http2.cc +++ b/src/http2.cc @@ -434,6 +434,11 @@ void copy_headers_to_nva_internal(std::vector &nva, kv = &(*it_via); it_via = it; break; + case HD_NGHTTPX_0RTT_UNIQ: + if (flags & HDOP_STRIP_NGHTTPX_ZERO_RTT_UNIQ) { + continue; + } + break; } nva.push_back( make_nv_internal(kv->name, kv->value, kv->no_index, nv_flags)); @@ -920,6 +925,11 @@ int lookup_token(const uint8_t *name, size_t namelen) { return HD_X_FORWARDED_PROTO; } break; + case 'q': + if (util::streq_l("nghttpx-0rtt-uni", name, 16)) { + return HD_NGHTTPX_0RTT_UNIQ; + } + break; } break; } diff --git a/src/http2.h b/src/http2.h index eb6a41d3..c5a52dfe 100644 --- a/src/http2.h +++ b/src/http2.h @@ -203,9 +203,13 @@ enum HeaderBuildOp { // Via header fields must be stripped. If this flag is not set, all // Via header fields other than last one are added. HDOP_STRIP_VIA = 1 << 3, + // nghttpx-0rtt-uniq header fields must be stripped. If this flag + // is not set, all nghttpx-0rtt-uniq header fields are added. + HDOP_STRIP_NGHTTPX_ZERO_RTT_UNIQ = 1 << 4, // Strip above all header fields. HDOP_STRIP_ALL = HDOP_STRIP_FORWARDED | HDOP_STRIP_X_FORWARDED_FOR | - HDOP_STRIP_X_FORWARDED_PROTO | HDOP_STRIP_VIA, + HDOP_STRIP_X_FORWARDED_PROTO | HDOP_STRIP_VIA | + HDOP_STRIP_NGHTTPX_ZERO_RTT_UNIQ, }; // Appends headers in |headers| to |nv|. |headers| must be indexed @@ -312,6 +316,7 @@ enum { HD_KEEP_ALIVE, HD_LINK, HD_LOCATION, + HD_NGHTTPX_0RTT_UNIQ, HD_PROXY_CONNECTION, HD_SERVER, HD_TE, diff --git a/src/shrpx.cc b/src/shrpx.cc index 427891a9..14551e27 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -1486,6 +1486,7 @@ void fill_default_config(Config *config) { httpconf.max_requests = std::numeric_limits::max(); httpconf.xfp.add = true; httpconf.xfp.strip_incoming = true; + httpconf.zero_rtt_uniq.strip_incoming = true; auto &http2conf = config->http2; { @@ -2615,6 +2616,9 @@ HTTP: Default: obfuscated --no-via Don't append to Via header field. If Via header field is received, it is left unaltered. + --no-strip-incoming-nghttpx-0rtt-uniq + Don't strip nghttpx-0rtt-uniq header field from inbound + client requests. --no-location-rewrite Don't rewrite location header field in default mode. When --http2-proxy is used, location header field will @@ -3457,6 +3461,8 @@ int main(int argc, char **argv) { required_argument, &flag, 162}, {SHRPX_OPT_TLS_ANTI_REPLAY_MEMCACHED_PRIVATE_KEY_FILE.c_str(), required_argument, &flag, 163}, + {SHRPX_OPT_NO_STRIP_INCOMING_NGHTTPX_0RTT_UNIQ.c_str(), no_argument, + &flag, 164}, {nullptr, 0, nullptr, 0}}; int option_index = 0; @@ -4239,6 +4245,11 @@ int main(int argc, char **argv) { SHRPX_OPT_TLS_ANTI_REPLAY_MEMCACHED_PRIVATE_KEY_FILE, StringRef{optarg}); break; + case 164: + // --no-strip-incoming-nghttpx-0rtt-uniq + cmdcfgs.emplace_back(SHRPX_OPT_NO_STRIP_INCOMING_NGHTTPX_0RTT_UNIQ, + StringRef::from_lit("yes")); + break; default: break; } diff --git a/src/shrpx_config.cc b/src/shrpx_config.cc index 2123de31..36ce4c15 100644 --- a/src/shrpx_config.cc +++ b/src/shrpx_config.cc @@ -2269,6 +2269,11 @@ int option_lookup_token(const char *name, size_t namelen) { return SHRPX_OPTID_NO_STRIP_INCOMING_X_FORWARDED_PROTO; } break; + case 'q': + if (util::strieq_l("no-strip-incoming-nghttpx-0rtt-uni", name, 34)) { + return SHRPX_OPTID_NO_STRIP_INCOMING_NGHTTPX_0RTT_UNIQ; + } + break; case 'r': if (util::strieq_l("frontend-http2-dump-response-heade", name, 34)) { return SHRPX_OPTID_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER; @@ -3590,6 +3595,10 @@ int parse_config(Config *config, int optid, const StringRef &opt, case SHRPX_OPTID_NO_VERIFY_OCSP: config->tls.ocsp.no_verify = util::strieq_l("yes", optarg); + return 0; + case SHRPX_OPTID_NO_STRIP_INCOMING_NGHTTPX_0RTT_UNIQ: + config->http.zero_rtt_uniq.strip_incoming = !util::strieq_l("yes", optarg); + return 0; case SHRPX_OPTID_CONF: LOG(WARN) << "conf: ignored"; diff --git a/src/shrpx_config.h b/src/shrpx_config.h index f00e10ba..c7307b96 100644 --- a/src/shrpx_config.h +++ b/src/shrpx_config.h @@ -351,6 +351,8 @@ constexpr auto SHRPX_OPT_TLS_ANTI_REPLAY_MEMCACHED_PRIVATE_KEY_FILE = StringRef::from_lit("tls-anti-replay-memcached-private-key-file"); constexpr auto SHRPX_OPT_TLS_ANTI_REPLAY_MEMCACHED_ADDRESS_FAMILY = StringRef::from_lit("tls-anti-replay-memcached-address-family"); +constexpr auto SHRPX_OPT_NO_STRIP_INCOMING_NGHTTPX_0RTT_UNIQ = + StringRef::from_lit("no-strip-incoming-nghttpx-0rtt-uniq"); constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8; @@ -704,6 +706,9 @@ struct HttpConfig { bool add; bool strip_incoming; } xfp; + struct { + bool strip_incoming; + } zero_rtt_uniq; std::vector altsvcs; std::vector error_pages; HeaderRefs add_request_headers; @@ -1096,6 +1101,7 @@ enum { SHRPX_OPTID_NO_OCSP, SHRPX_OPTID_NO_SERVER_PUSH, SHRPX_OPTID_NO_SERVER_REWRITE, + SHRPX_OPTID_NO_STRIP_INCOMING_NGHTTPX_0RTT_UNIQ, SHRPX_OPTID_NO_STRIP_INCOMING_X_FORWARDED_PROTO, SHRPX_OPTID_NO_VERIFY_OCSP, SHRPX_OPTID_NO_VIA, diff --git a/src/shrpx_connection.h b/src/shrpx_connection.h index d63d3b1f..9bba780d 100644 --- a/src/shrpx_connection.h +++ b/src/shrpx_connection.h @@ -61,6 +61,8 @@ struct TLSConnection { DefaultPeekMemchunks rbuf; // Stores TLSv1.3 early data. DefaultMemchunks earlybuf; + // Message digest of ClientHello in hex string. + StringRef ch_hex_md; SSL *ssl; SSL_SESSION *cached_session; MemcachedRequest *cached_session_lookup_req; diff --git a/src/shrpx_http2_downstream_connection.cc b/src/shrpx_http2_downstream_connection.cc index 9c10f5aa..1e5fb081 100644 --- a/src/shrpx_http2_downstream_connection.cc +++ b/src/shrpx_http2_downstream_connection.cc @@ -271,7 +271,7 @@ int Http2DownstreamConnection::push_request_headers() { num_cookies = downstream_->count_crumble_request_cookie(); } - // 9 means: + // 10 means: // 1. :method // 2. :scheme // 3. :path @@ -281,8 +281,9 @@ int Http2DownstreamConnection::push_request_headers() { // 7. x-forwarded-proto (optional) // 8. te (optional) // 9. forwarded (optional) + // 10. nghttpx-0rtt-uniq (optional) auto nva = std::vector(); - nva.reserve(req.fs.headers().size() + 9 + num_cookies + + nva.reserve(req.fs.headers().size() + 10 + num_cookies + httpconf.add_request_headers.size()); nva.push_back( @@ -311,11 +312,15 @@ int Http2DownstreamConnection::push_request_headers() { auto &fwdconf = httpconf.forwarded; auto &xffconf = httpconf.xff; auto &xfpconf = httpconf.xfp; + auto &zero_rtt_uniqconf = httpconf.zero_rtt_uniq; uint32_t build_flags = (fwdconf.strip_incoming ? http2::HDOP_STRIP_FORWARDED : 0) | (xffconf.strip_incoming ? http2::HDOP_STRIP_X_FORWARDED_FOR : 0) | - (xfpconf.strip_incoming ? http2::HDOP_STRIP_X_FORWARDED_PROTO : 0); + (xfpconf.strip_incoming ? http2::HDOP_STRIP_X_FORWARDED_PROTO : 0) | + (zero_rtt_uniqconf.strip_incoming + ? http2::HDOP_STRIP_NGHTTPX_ZERO_RTT_UNIQ + : 0); http2::copy_headers_to_nva_nocopy(nva, req.fs.headers(), build_flags); @@ -326,6 +331,15 @@ int Http2DownstreamConnection::push_request_headers() { auto upstream = downstream_->get_upstream(); auto handler = upstream->get_client_handler(); +#if OPENSSL_1_1_1_API + auto conn = handler->get_connection(); + + if (!SSL_is_init_finished(conn->tls.ssl)) { + nva.push_back( + http2::make_nv_ls_nocopy("nghttpx-0rtt-uniq", conn->tls.ch_hex_md)); + } +#endif // OPENSSL_1_1_1_API + auto fwd = fwdconf.strip_incoming ? nullptr : req.fs.header(http2::HD_FORWARDED); diff --git a/src/shrpx_http_downstream_connection.cc b/src/shrpx_http_downstream_connection.cc index 4fdcb643..7012dbbc 100644 --- a/src/shrpx_http_downstream_connection.cc +++ b/src/shrpx_http_downstream_connection.cc @@ -535,11 +535,15 @@ int HttpDownstreamConnection::push_request_headers() { auto &fwdconf = httpconf.forwarded; auto &xffconf = httpconf.xff; auto &xfpconf = httpconf.xfp; + auto &zero_rtt_uniqconf = httpconf.zero_rtt_uniq; uint32_t build_flags = (fwdconf.strip_incoming ? http2::HDOP_STRIP_FORWARDED : 0) | (xffconf.strip_incoming ? http2::HDOP_STRIP_X_FORWARDED_FOR : 0) | - (xfpconf.strip_incoming ? http2::HDOP_STRIP_X_FORWARDED_PROTO : 0); + (xfpconf.strip_incoming ? http2::HDOP_STRIP_X_FORWARDED_PROTO : 0) | + (zero_rtt_uniqconf.strip_incoming + ? http2::HDOP_STRIP_NGHTTPX_ZERO_RTT_UNIQ + : 0); http2::build_http1_headers_from_headers(buf, req.fs.headers(), build_flags); @@ -580,6 +584,16 @@ int HttpDownstreamConnection::push_request_headers() { auto upstream = downstream_->get_upstream(); auto handler = upstream->get_client_handler(); +#if OPENSSL_1_1_1_API + auto conn = handler->get_connection(); + + if (!SSL_is_init_finished(conn->tls.ssl)) { + buf->append("Nghttpx-0rtt-uniq: "); + buf->append(conn->tls.ch_hex_md); + buf->append("\r\n"); + } +#endif // OPENSSL_1_1_1_API + auto fwd = fwdconf.strip_incoming ? nullptr : req.fs.header(http2::HD_FORWARDED); diff --git a/src/shrpx_tls.cc b/src/shrpx_tls.cc index 3c7fb0df..723b5e8b 100644 --- a/src/shrpx_tls.cc +++ b/src/shrpx_tls.cc @@ -580,7 +580,7 @@ int early_cb(SSL *ssl, int *al, void *arg) { auto &tlsconf = get_config()->tls; - auto hex_md = + conn->tls.ch_hex_md = util::format_hex(balloc, StringRef{std::begin(md), std::end(md)}); if (tlsconf.anti_replay.memcached.host.empty()) { @@ -590,7 +590,7 @@ int early_cb(SSL *ssl, int *al, void *arg) { auto req = make_unique(); req->op = MEMCACHED_OP_ADD; req->key = MEMCACHED_ANTI_REPLY_KEY_PREFIX.str(); - req->key += hex_md; + req->key += conn->tls.ch_hex_md; // TODO No value at the moment