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/common/http/http_header_block.h"
16
#include "quiche/quic/core/http/quic_connection_migration_manager.h"
17
#include "quiche/quic/core/http/quic_header_list.h"
18
#include "quiche/quic/core/quic_config.h"
19
#include "quiche/quic/core/quic_error_codes.h"
20
#include "quiche/quic/core/quic_types.h"
21
#include "quiche/quic/platform/api/quic_ip_address.h"
22
#include "quiche/quic/platform/api/quic_socket_address.h"
23

            
24
namespace Envoy {
25
namespace Quic {
26

            
27
// Changes or additions to details should be reflected in
28
// docs/root/configuration/http/http_conn_man/response_code_details.rst
29
class Http3ResponseCodeDetailValues {
30
public:
31
  // Invalid HTTP header field was received and stream is going to be
32
  // closed.
33
  static constexpr absl::string_view invalid_http_header = "http3.invalid_header_field";
34
  // The size of headers (or trailers) exceeded the configured limits.
35
  static constexpr absl::string_view headers_too_large = "http3.headers_too_large";
36
  // Envoy was configured to drop requests with header keys beginning with underscores.
37
  static constexpr absl::string_view invalid_underscore = "http3.unexpected_underscore";
38
  // The peer refused the stream.
39
  static constexpr absl::string_view remote_refused = "http3.remote_refuse";
40
  // The peer reset the stream.
41
  static constexpr absl::string_view remote_reset = "http3.remote_reset";
42
  // Too many trailers were sent.
43
  static constexpr absl::string_view too_many_trailers = "http3.too_many_trailers";
44
  // Too many headers were sent.
45
  static constexpr absl::string_view too_many_headers = "http3.too_many_headers";
46
  // The payload size is different from what the content-length header indicated.
47
  static constexpr absl::string_view inconsistent_content_length =
48
      "http3.inconsistent_content_length";
49
};
50

            
51
221
constexpr quic::QuicConnectionMigrationConfig quicConnectionMigrationDisableAllConfig() {
52
221
  return quic::QuicConnectionMigrationConfig{
53
221
      .allow_port_migration = false,
54
221
      .migrate_session_on_network_change = false,
55
221
      .allow_server_preferred_address = false,
56
221
  };
57
221
}
58

            
59
// TODO(danzh): this is called on each write. Consider to return an address instance on the stack if
60
// the heap allocation is too expensive.
61
Network::Address::InstanceConstSharedPtr
62
quicAddressToEnvoyAddressInstance(const quic::QuicSocketAddress& quic_address);
63

            
64
quic::QuicSocketAddress envoyIpAddressToQuicSocketAddress(const Network::Address::Ip* envoy_ip);
65

            
66
class HeaderValidator {
67
public:
68
8074
  virtual ~HeaderValidator() = default;
69
  virtual void startHeaderBlock() = 0;
70
  virtual Http::HeaderUtility::HeaderValidationResult
71
  validateHeader(absl::string_view name, absl::string_view header_value) = 0;
72
  // Returns true if all required pseudo-headers and no extra pseudo-headers are
73
  // present for the given header type.
74
  virtual bool finishHeaderBlock(bool is_trailing_headers) = 0;
75
};
76

            
77
// The returned header map has all keys in lower case.
78
template <class T>
79
std::unique_ptr<T>
80
quicHeadersToEnvoyHeaders(const quic::QuicHeaderList& header_list, HeaderValidator& validator,
81
                          uint32_t max_headers_kb, uint32_t max_headers_allowed,
82
6929
                          absl::string_view& details, quic::QuicRstStreamErrorCode& rst) {
83
6929
  validator.startHeaderBlock();
84
6929
  auto headers = T::create(max_headers_kb, max_headers_allowed);
85
107921
  for (const auto& entry : header_list) {
86
107921
    if (max_headers_allowed == 0) {
87
5
      details = Http3ResponseCodeDetailValues::too_many_headers;
88
5
      rst = quic::QUIC_STREAM_EXCESSIVE_LOAD;
89
5
      return nullptr;
90
5
    }
91
107916
    max_headers_allowed--;
92
107916
    Http::HeaderUtility::HeaderValidationResult result =
93
107916
        validator.validateHeader(entry.first, entry.second);
94
107916
    switch (result) {
95
655
    case Http::HeaderUtility::HeaderValidationResult::REJECT:
96
655
      rst = quic::QUIC_BAD_APPLICATION_PAYLOAD;
97
      // The validator sets the details to Http3ResponseCodeDetailValues::invalid_underscore
98
655
      return nullptr;
99
6
    case Http::HeaderUtility::HeaderValidationResult::DROP:
100
6
      continue;
101
107255
    case Http::HeaderUtility::HeaderValidationResult::ACCEPT:
102
107255
      auto key = Http::LowerCaseString(entry.first);
103
107255
      if (key != Http::Headers::get().Cookie) {
104
        // TODO(danzh): Avoid copy by referencing entry as header_list is already validated by QUIC.
105
71140
        headers->addCopy(key, entry.second);
106
96978
      } else {
107
        // QUICHE breaks "cookie" header into crumbs. Coalesce them by appending current one to
108
        // existing one if there is any.
109
36115
        headers->appendCopy(key, entry.second);
110
36115
      }
111
107916
    }
112
107916
  }
113
6269
  if (!validator.finishHeaderBlock(/*is_trailing_headers=*/false)) {
114
    return nullptr;
115
  }
116
6269
  return headers;
117
6269
}
118

            
119
template <class T>
120
std::unique_ptr<T>
121
http2HeaderBlockToEnvoyTrailers(const quiche::HttpHeaderBlock& header_block,
122
                                uint32_t max_headers_kb, uint32_t max_headers_allowed,
123
                                HeaderValidator& validator, absl::string_view& details,
124
181
                                quic::QuicRstStreamErrorCode& rst) {
125
181
  auto headers = T::create(max_headers_kb, max_headers_allowed);
126
181
  if (header_block.size() > max_headers_allowed) {
127
    details = Http3ResponseCodeDetailValues::too_many_trailers;
128
    rst = quic::QUIC_STREAM_EXCESSIVE_LOAD;
129
    return nullptr;
130
  }
131
181
  validator.startHeaderBlock();
132
80245
  for (auto entry : header_block) {
133
    // TODO(danzh): Avoid temporary strings and addCopy() with string_view.
134
80244
    std::string key(entry.first);
135
    // QUICHE coalesces multiple trailer values with the same key with '\0'.
136
80244
    std::vector<absl::string_view> values = absl::StrSplit(entry.second, '\0');
137
80799
    for (const absl::string_view& value : values) {
138
80799
      if (max_headers_allowed == 0) {
139
3
        details = Http3ResponseCodeDetailValues::too_many_trailers;
140
3
        rst = quic::QUIC_STREAM_EXCESSIVE_LOAD;
141
3
        return nullptr;
142
3
      }
143
80796
      max_headers_allowed--;
144
80796
      Http::HeaderUtility::HeaderValidationResult result =
145
80796
          validator.validateHeader(entry.first, value);
146
80796
      switch (result) {
147
5
      case Http::HeaderUtility::HeaderValidationResult::REJECT:
148
5
        rst = quic::QUIC_BAD_APPLICATION_PAYLOAD;
149
5
        return nullptr;
150
3
      case Http::HeaderUtility::HeaderValidationResult::DROP:
151
3
        continue;
152
80788
      case Http::HeaderUtility::HeaderValidationResult::ACCEPT:
153
80788
        headers->addCopy(Http::LowerCaseString(key), value);
154
80796
      }
155
80796
    }
156
80244
  }
157
173
  if (!validator.finishHeaderBlock(/*is_trailing_headers=*/true)) {
158
    return nullptr;
159
  }
160
173
  return headers;
161
173
}
162

            
163
quiche::HttpHeaderBlock envoyHeadersToHttp2HeaderBlock(const Http::HeaderMap& headers);
164

            
165
// Called when Envoy wants to reset the underlying QUIC stream.
166
quic::QuicRstStreamErrorCode envoyResetReasonToQuicRstError(Http::StreamResetReason reason);
167

            
168
// Called when a RST_STREAM frame is received.
169
Http::StreamResetReason quicRstErrorToEnvoyLocalResetReason(quic::QuicRstStreamErrorCode rst_err);
170

            
171
// Called when a QUIC stack reset the stream.
172
Http::StreamResetReason quicRstErrorToEnvoyRemoteResetReason(quic::QuicRstStreamErrorCode rst_err);
173

            
174
// Called when underlying QUIC connection is closed locally.
175
Http::StreamResetReason quicErrorCodeToEnvoyLocalResetReason(quic::QuicErrorCode error,
176
                                                             bool connected);
177

            
178
// Called when underlying QUIC connection is closed by peer.
179
Http::StreamResetReason quicErrorCodeToEnvoyRemoteResetReason(quic::QuicErrorCode error);
180

            
181
// Create a connection socket instance on the given network and apply given socket options to the
182
// socket. IP_PKTINFO and SO_RXQ_OVFL is always set if supported.
183
// If the local_addr is not null, bind the socket to it.
184
// Otherwise if the given network is valid, bind to it using the given
185
// custom_bind_func. This is used on Android platforms which have a unique id
186
// for each network and has API to bind a socket to a specific handle.
187
// Otherwise the platform will automatically pick a network interface.
188
Network::ConnectionSocketPtr createConnectionSocket(
189
    const Network::Address::InstanceConstSharedPtr& peer_addr,
190
    Network::Address::InstanceConstSharedPtr& local_addr,
191
    const Network::ConnectionSocket::OptionsSharedPtr& options,
192
    quic::QuicNetworkHandle network = quic::kInvalidNetworkHandle,
193
    std::function<void(Network::ConnectionSocket&, quic::QuicNetworkHandle)> custom_bind_func =
194
        nullptr);
195

            
196
// Convert a cert in string form to X509 object.
197
// Return nullptr if the bytes passed cannot be passed.
198
bssl::UniquePtr<X509> parseDERCertificate(const std::string& der_bytes, std::string* error_details);
199

            
200
// Deduce the suitable signature algorithm according to the public key.
201
// Return the sign algorithm id works with the public key; If the public key is
202
// not supported, return 0 with error_details populated correspondingly.
203
int deduceSignatureAlgorithmFromPublicKey(const EVP_PKEY* public_key, std::string* error_details);
204

            
205
// Return a connection socket which read and write via io_handle, but doesn't close it when the
206
// socket gets closed nor set options on the socket.
207
Network::ConnectionSocketPtr
208
createServerConnectionSocket(Network::IoHandle& io_handle,
209
                             const quic::QuicSocketAddress& self_address,
210
                             const quic::QuicSocketAddress& peer_address,
211
                             const std::string& hostname, absl::string_view alpn);
212

            
213
// Alter QuicConfig based on all the options in the supplied config.
214
void convertQuicConfig(const envoy::config::core::v3::QuicProtocolOptions& config,
215
                       quic::QuicConfig& quic_config);
216

            
217
// Set initial flow control windows in quic_config according to the given Envoy config.
218
void configQuicInitialFlowControlWindow(const envoy::config::core::v3::QuicProtocolOptions& config,
219
                                        quic::QuicConfig& quic_config);
220

            
221
// Extract the two ECN bits from the TOS byte in the IP header.
222
quic::QuicEcnCodepoint getQuicEcnCodepointFromTosByte(uint8_t tos_byte);
223

            
224
// Register TLS certificate compression algorithms (RFC 8879) for QUIC.
225
void registerCertCompression(SSL_CTX* ssl_ctx);
226

            
227
} // namespace Quic
228
} // namespace Envoy