Line data Source code
1 : #pragma once 2 : 3 : #include "envoy/common/platform.h" 4 : #include "envoy/config/listener/v3/quic_config.pb.h" 5 : #include "envoy/http/codec.h" 6 : 7 : #include "source/common/common/assert.h" 8 : #include "source/common/http/header_map_impl.h" 9 : #include "source/common/http/header_utility.h" 10 : #include "source/common/network/address_impl.h" 11 : #include "source/common/network/connection_socket_impl.h" 12 : #include "source/common/quic/quic_io_handle_wrapper.h" 13 : 14 : #include "openssl/ssl.h" 15 : #include "quiche/quic/core/http/quic_header_list.h" 16 : #include "quiche/quic/core/quic_config.h" 17 : #include "quiche/quic/core/quic_error_codes.h" 18 : #include "quiche/quic/core/quic_types.h" 19 : #include "quiche/quic/platform/api/quic_ip_address.h" 20 : #include "quiche/quic/platform/api/quic_socket_address.h" 21 : #include "quiche/spdy/core/http2_header_block.h" 22 : 23 : namespace Envoy { 24 : namespace Quic { 25 : 26 : // Changes or additions to details should be reflected in 27 : // docs/root/configuration/http/http_conn_man/response_code_details.rst 28 : class Http3ResponseCodeDetailValues { 29 : public: 30 : // Invalid HTTP header field was received and stream is going to be 31 : // closed. 32 : static constexpr absl::string_view invalid_http_header = "http3.invalid_header_field"; 33 : // The size of headers (or trailers) exceeded the configured limits. 34 : static constexpr absl::string_view headers_too_large = "http3.headers_too_large"; 35 : // Envoy was configured to drop requests with header keys beginning with underscores. 36 : static constexpr absl::string_view invalid_underscore = "http3.unexpected_underscore"; 37 : // The peer refused the stream. 38 : static constexpr absl::string_view remote_refused = "http3.remote_refuse"; 39 : // The peer reset the stream. 40 : static constexpr absl::string_view remote_reset = "http3.remote_reset"; 41 : // Too many trailers were sent. 42 : static constexpr absl::string_view too_many_trailers = "http3.too_many_trailers"; 43 : // Too many headers were sent. 44 : static constexpr absl::string_view too_many_headers = "http3.too_many_headers"; 45 : // The payload size is different from what the content-length header indicated. 46 : static constexpr absl::string_view inconsistent_content_length = 47 : "http3.inconsistent_content_length"; 48 : }; 49 : 50 : // TODO(danzh): this is called on each write. Consider to return an address instance on the stack if 51 : // the heap allocation is too expensive. 52 : Network::Address::InstanceConstSharedPtr 53 : quicAddressToEnvoyAddressInstance(const quic::QuicSocketAddress& quic_address); 54 : 55 : quic::QuicSocketAddress envoyIpAddressToQuicSocketAddress(const Network::Address::Ip* envoy_ip); 56 : 57 : class HeaderValidator { 58 : public: 59 232 : virtual ~HeaderValidator() = default; 60 : virtual Http::HeaderUtility::HeaderValidationResult 61 : validateHeader(absl::string_view name, absl::string_view header_value) = 0; 62 : }; 63 : 64 : // The returned header map has all keys in lower case. 65 : template <class T> 66 : std::unique_ptr<T> 67 : quicHeadersToEnvoyHeaders(const quic::QuicHeaderList& header_list, HeaderValidator& validator, 68 : uint32_t max_headers_kb, uint32_t max_headers_allowed, 69 2 : absl::string_view& details, quic::QuicRstStreamErrorCode& rst) { 70 2 : auto headers = T::create(max_headers_kb, max_headers_allowed); 71 20 : for (const auto& entry : header_list) { 72 20 : if (max_headers_allowed == 0) { 73 0 : details = Http3ResponseCodeDetailValues::too_many_headers; 74 0 : rst = quic::QUIC_STREAM_EXCESSIVE_LOAD; 75 0 : return nullptr; 76 0 : } 77 20 : max_headers_allowed--; 78 20 : Http::HeaderUtility::HeaderValidationResult result = 79 20 : validator.validateHeader(entry.first, entry.second); 80 20 : switch (result) { 81 2 : case Http::HeaderUtility::HeaderValidationResult::REJECT: 82 2 : rst = quic::QUIC_BAD_APPLICATION_PAYLOAD; 83 : // The validator sets the details to Http3ResponseCodeDetailValues::invalid_underscore 84 2 : return nullptr; 85 0 : case Http::HeaderUtility::HeaderValidationResult::DROP: 86 0 : continue; 87 18 : case Http::HeaderUtility::HeaderValidationResult::ACCEPT: 88 18 : auto key = Http::LowerCaseString(entry.first); 89 18 : if (key != Http::Headers::get().Cookie) { 90 : // TODO(danzh): Avoid copy by referencing entry as header_list is already validated by QUIC. 91 18 : headers->addCopy(key, entry.second); 92 18 : } else { 93 : // QUICHE breaks "cookie" header into crumbs. Coalesce them by appending current one to 94 : // existing one if there is any. 95 0 : headers->appendCopy(key, entry.second); 96 0 : } 97 20 : } 98 20 : } 99 0 : return headers; 100 2 : } 101 : 102 : template <class T> 103 : std::unique_ptr<T> 104 : http2HeaderBlockToEnvoyTrailers(const spdy::Http2HeaderBlock& header_block, uint32_t max_headers_kb, 105 : uint32_t max_headers_allowed, HeaderValidator& validator, 106 0 : absl::string_view& details, quic::QuicRstStreamErrorCode& rst) { 107 0 : auto headers = T::create(max_headers_kb, max_headers_allowed); 108 0 : if (header_block.size() > max_headers_allowed) { 109 0 : details = Http3ResponseCodeDetailValues::too_many_trailers; 110 0 : rst = quic::QUIC_STREAM_EXCESSIVE_LOAD; 111 0 : return nullptr; 112 0 : } 113 0 : for (auto entry : header_block) { 114 : // TODO(danzh): Avoid temporary strings and addCopy() with string_view. 115 0 : std::string key(entry.first); 116 : // QUICHE coalesces multiple trailer values with the same key with '\0'. 117 0 : std::vector<absl::string_view> values = absl::StrSplit(entry.second, '\0'); 118 0 : for (const absl::string_view& value : values) { 119 0 : if (max_headers_allowed == 0) { 120 0 : details = Http3ResponseCodeDetailValues::too_many_trailers; 121 0 : rst = quic::QUIC_STREAM_EXCESSIVE_LOAD; 122 0 : return nullptr; 123 0 : } 124 0 : max_headers_allowed--; 125 0 : Http::HeaderUtility::HeaderValidationResult result = 126 0 : validator.validateHeader(entry.first, value); 127 0 : switch (result) { 128 0 : case Http::HeaderUtility::HeaderValidationResult::REJECT: 129 0 : rst = quic::QUIC_BAD_APPLICATION_PAYLOAD; 130 0 : return nullptr; 131 0 : case Http::HeaderUtility::HeaderValidationResult::DROP: 132 0 : continue; 133 0 : case Http::HeaderUtility::HeaderValidationResult::ACCEPT: 134 0 : headers->addCopy(Http::LowerCaseString(key), value); 135 0 : } 136 0 : } 137 0 : } 138 0 : return headers; 139 0 : } 140 : 141 : spdy::Http2HeaderBlock envoyHeadersToHttp2HeaderBlock(const Http::HeaderMap& headers); 142 : 143 : // Called when Envoy wants to reset the underlying QUIC stream. 144 : quic::QuicRstStreamErrorCode envoyResetReasonToQuicRstError(Http::StreamResetReason reason); 145 : 146 : // Called when a RST_STREAM frame is received. 147 : Http::StreamResetReason quicRstErrorToEnvoyLocalResetReason(quic::QuicRstStreamErrorCode rst_err); 148 : 149 : // Called when a QUIC stack reset the stream. 150 : Http::StreamResetReason quicRstErrorToEnvoyRemoteResetReason(quic::QuicRstStreamErrorCode rst_err); 151 : 152 : // Called when underlying QUIC connection is closed locally. 153 : Http::StreamResetReason quicErrorCodeToEnvoyLocalResetReason(quic::QuicErrorCode error, 154 : bool connected); 155 : 156 : // Called when underlying QUIC connection is closed by peer. 157 : Http::StreamResetReason quicErrorCodeToEnvoyRemoteResetReason(quic::QuicErrorCode error); 158 : 159 : // Create a connection socket instance and apply given socket options to the 160 : // socket. IP_PKTINFO and SO_RXQ_OVFL is always set if supported. 161 : Network::ConnectionSocketPtr 162 : createConnectionSocket(const Network::Address::InstanceConstSharedPtr& peer_addr, 163 : Network::Address::InstanceConstSharedPtr& local_addr, 164 : const Network::ConnectionSocket::OptionsSharedPtr& options); 165 : 166 : // Convert a cert in string form to X509 object. 167 : // Return nullptr if the bytes passed cannot be passed. 168 : bssl::UniquePtr<X509> parseDERCertificate(const std::string& der_bytes, std::string* error_details); 169 : 170 : // Deduce the suitable signature algorithm according to the public key. 171 : // Return the sign algorithm id works with the public key; If the public key is 172 : // not supported, return 0 with error_details populated correspondingly. 173 : int deduceSignatureAlgorithmFromPublicKey(const EVP_PKEY* public_key, std::string* error_details); 174 : 175 : // Return a connection socket which read and write via io_handle, but doesn't close it when the 176 : // socket gets closed nor set options on the socket. 177 : Network::ConnectionSocketPtr 178 : createServerConnectionSocket(Network::IoHandle& io_handle, 179 : const quic::QuicSocketAddress& self_address, 180 : const quic::QuicSocketAddress& peer_address, 181 : const std::string& hostname, absl::string_view alpn); 182 : 183 : // Alter QuicConfig based on all the options in the supplied config. 184 : void convertQuicConfig(const envoy::config::core::v3::QuicProtocolOptions& config, 185 : quic::QuicConfig& quic_config); 186 : 187 : // Set initial flow control windows in quic_config according to the given Envoy config. 188 : void configQuicInitialFlowControlWindow(const envoy::config::core::v3::QuicProtocolOptions& config, 189 : quic::QuicConfig& quic_config); 190 : 191 : // Modify new_connection_id according to given old_connection_id to make sure packets with the new 192 : // one can be routed to the same listener. 193 : void adjustNewConnectionIdForRouting(quic::QuicConnectionId& new_connection_id, 194 : const quic::QuicConnectionId& old_connection_id); 195 : 196 : } // namespace Quic 197 : } // namespace Envoy