Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 1 | // Copyright 2019 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "quiche/quic/masque/masque_server_backend.h" |
bnc | ced0950 | 2022-04-13 08:33:10 -0700 | [diff] [blame] | 6 | |
asedeno | 99be906 | 2024-01-10 11:54:52 -0800 | [diff] [blame] | 7 | #include <cstdint> |
| 8 | #include <cstring> |
| 9 | #include <memory> |
| 10 | #include <string> |
| 11 | #include <utility> |
| 12 | #include <vector> |
| 13 | |
| 14 | #include "absl/strings/escaping.h" |
dschinazi | a8489d2 | 2024-01-10 07:00:12 -0800 | [diff] [blame] | 15 | #include "absl/strings/str_split.h" |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 16 | #include "absl/strings/string_view.h" |
dschinazi | a8489d2 | 2024-01-10 07:00:12 -0800 | [diff] [blame] | 17 | #include "openssl/curve25519.h" |
asedeno | 99be906 | 2024-01-10 11:54:52 -0800 | [diff] [blame] | 18 | #include "quiche/quic/core/quic_connection_id.h" |
| 19 | #include "quiche/quic/masque/masque_utils.h" |
| 20 | #include "quiche/quic/platform/api/quic_bug_tracker.h" |
| 21 | #include "quiche/quic/platform/api/quic_ip_address.h" |
| 22 | #include "quiche/quic/platform/api/quic_logging.h" |
| 23 | #include "quiche/quic/tools/quic_backend_response.h" |
| 24 | #include "quiche/quic/tools/quic_memory_cache_backend.h" |
| 25 | #include "quiche/quic/tools/quic_simple_server_backend.h" |
| 26 | #include "quiche/common/quiche_text_utils.h" |
| 27 | #include "quiche/spdy/core/http2_header_block.h" |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 28 | |
| 29 | namespace quic { |
| 30 | |
| 31 | MasqueServerBackend::MasqueServerBackend(MasqueMode masque_mode, |
| 32 | const std::string& server_authority, |
| 33 | const std::string& cache_directory) |
| 34 | : masque_mode_(masque_mode), server_authority_(server_authority) { |
dschinazi | 425f03b | 2022-11-02 07:29:15 -0700 | [diff] [blame] | 35 | // Start with client IP 10.1.1.2. |
| 36 | connect_ip_next_client_ip_[0] = 10; |
| 37 | connect_ip_next_client_ip_[1] = 1; |
| 38 | connect_ip_next_client_ip_[2] = 1; |
| 39 | connect_ip_next_client_ip_[3] = 2; |
| 40 | |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 41 | if (!cache_directory.empty()) { |
| 42 | QuicMemoryCacheBackend::InitializeBackend(cache_directory); |
| 43 | } |
| 44 | } |
| 45 | |
| 46 | bool MasqueServerBackend::MaybeHandleMasqueRequest( |
| 47 | const spdy::Http2HeaderBlock& request_headers, |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 48 | QuicSimpleServerBackend::RequestHandler* request_handler) { |
| 49 | auto method_pair = request_headers.find(":method"); |
| 50 | if (method_pair == request_headers.end()) { |
| 51 | // Request is missing a method. |
| 52 | return false; |
| 53 | } |
| 54 | absl::string_view method = method_pair->second; |
| 55 | std::string masque_path = ""; |
dschinazi | a85581e | 2022-04-17 08:09:44 -0700 | [diff] [blame] | 56 | auto protocol_pair = request_headers.find(":protocol"); |
| 57 | if (method != "CONNECT" || protocol_pair == request_headers.end() || |
dschinazi | 425f03b | 2022-11-02 07:29:15 -0700 | [diff] [blame] | 58 | (protocol_pair->second != "connect-udp" && |
asedeno | 92bbf02 | 2023-07-23 11:23:45 -0700 | [diff] [blame] | 59 | protocol_pair->second != "connect-ip" && |
| 60 | protocol_pair->second != "connect-ethernet")) { |
dschinazi | a85581e | 2022-04-17 08:09:44 -0700 | [diff] [blame] | 61 | // This is not a MASQUE request. |
dschinazi | 0e39ce0 | 2024-01-20 15:21:42 -0800 | [diff] [blame] | 62 | if (!signature_auth_on_all_requests_) { |
| 63 | return false; |
| 64 | } |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 65 | } |
| 66 | |
| 67 | if (!server_authority_.empty()) { |
| 68 | auto authority_pair = request_headers.find(":authority"); |
| 69 | if (authority_pair == request_headers.end()) { |
| 70 | // Cannot enforce missing authority. |
| 71 | return false; |
| 72 | } |
| 73 | absl::string_view authority = authority_pair->second; |
| 74 | if (server_authority_ != authority) { |
| 75 | // This request does not match server_authority. |
| 76 | return false; |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | auto it = backend_client_states_.find(request_handler->connection_id()); |
| 81 | if (it == backend_client_states_.end()) { |
bnc | ced0950 | 2022-04-13 08:33:10 -0700 | [diff] [blame] | 82 | QUIC_LOG(ERROR) << "Could not find backend client for " << masque_path |
| 83 | << request_headers.DebugString(); |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 84 | return false; |
| 85 | } |
| 86 | |
| 87 | BackendClient* backend_client = it->second.backend_client; |
| 88 | |
| 89 | std::unique_ptr<QuicBackendResponse> response = |
dschinazi | a85581e | 2022-04-17 08:09:44 -0700 | [diff] [blame] | 90 | backend_client->HandleMasqueRequest(request_headers, request_handler); |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 91 | if (response == nullptr) { |
| 92 | QUIC_LOG(ERROR) << "Backend client did not process request for " |
| 93 | << masque_path << request_headers.DebugString(); |
| 94 | return false; |
| 95 | } |
| 96 | |
| 97 | QUIC_DLOG(INFO) << "Sending MASQUE response for " |
| 98 | << request_headers.DebugString(); |
| 99 | |
| 100 | request_handler->OnResponseBackendComplete(response.get()); |
| 101 | it->second.responses.emplace_back(std::move(response)); |
| 102 | |
| 103 | return true; |
| 104 | } |
| 105 | |
| 106 | void MasqueServerBackend::FetchResponseFromBackend( |
| 107 | const spdy::Http2HeaderBlock& request_headers, |
| 108 | const std::string& request_body, |
| 109 | QuicSimpleServerBackend::RequestHandler* request_handler) { |
dschinazi | a85581e | 2022-04-17 08:09:44 -0700 | [diff] [blame] | 110 | if (MaybeHandleMasqueRequest(request_headers, request_handler)) { |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 111 | // Request was handled as a MASQUE request. |
| 112 | return; |
| 113 | } |
| 114 | QUIC_DLOG(INFO) << "Fetching non-MASQUE response for " |
| 115 | << request_headers.DebugString(); |
| 116 | QuicMemoryCacheBackend::FetchResponseFromBackend( |
| 117 | request_headers, request_body, request_handler); |
| 118 | } |
| 119 | |
dschinazi | 96f83d3 | 2022-05-17 11:18:35 -0700 | [diff] [blame] | 120 | void MasqueServerBackend::HandleConnectHeaders( |
| 121 | const spdy::Http2HeaderBlock& request_headers, |
| 122 | RequestHandler* request_handler) { |
| 123 | if (MaybeHandleMasqueRequest(request_headers, request_handler)) { |
| 124 | // Request was handled as a MASQUE request. |
| 125 | return; |
| 126 | } |
| 127 | QUIC_DLOG(INFO) << "Fetching non-MASQUE CONNECT response for " |
| 128 | << request_headers.DebugString(); |
| 129 | QuicMemoryCacheBackend::HandleConnectHeaders(request_headers, |
| 130 | request_handler); |
| 131 | } |
| 132 | |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 133 | void MasqueServerBackend::CloseBackendResponseStream( |
| 134 | QuicSimpleServerBackend::RequestHandler* request_handler) { |
| 135 | QUIC_DLOG(INFO) << "Closing response stream"; |
| 136 | QuicMemoryCacheBackend::CloseBackendResponseStream(request_handler); |
| 137 | } |
| 138 | |
| 139 | void MasqueServerBackend::RegisterBackendClient(QuicConnectionId connection_id, |
| 140 | BackendClient* backend_client) { |
| 141 | QUIC_DLOG(INFO) << "Registering backend client for " << connection_id; |
| 142 | QUIC_BUG_IF(quic_bug_12005_1, backend_client_states_.find(connection_id) != |
| 143 | backend_client_states_.end()) |
| 144 | << connection_id << " already in backend clients map"; |
| 145 | backend_client_states_[connection_id] = |
| 146 | BackendClientState{backend_client, {}}; |
| 147 | } |
| 148 | |
| 149 | void MasqueServerBackend::RemoveBackendClient(QuicConnectionId connection_id) { |
| 150 | QUIC_DLOG(INFO) << "Removing backend client for " << connection_id; |
| 151 | backend_client_states_.erase(connection_id); |
| 152 | } |
| 153 | |
dschinazi | 425f03b | 2022-11-02 07:29:15 -0700 | [diff] [blame] | 154 | QuicIpAddress MasqueServerBackend::GetNextClientIpAddress() { |
| 155 | // Makes sure all addresses are in 10.(1-254).(1-254).(2-254) |
| 156 | QuicIpAddress address; |
| 157 | address.FromPackedString( |
| 158 | reinterpret_cast<char*>(&connect_ip_next_client_ip_[0]), |
| 159 | sizeof(connect_ip_next_client_ip_)); |
| 160 | connect_ip_next_client_ip_[3]++; |
| 161 | if (connect_ip_next_client_ip_[3] >= 255) { |
| 162 | connect_ip_next_client_ip_[3] = 2; |
| 163 | connect_ip_next_client_ip_[2]++; |
| 164 | if (connect_ip_next_client_ip_[2] >= 255) { |
| 165 | connect_ip_next_client_ip_[2] = 1; |
| 166 | connect_ip_next_client_ip_[1]++; |
| 167 | if (connect_ip_next_client_ip_[1] >= 255) { |
| 168 | QUIC_LOG(FATAL) << "Ran out of IP addresses, restarting process."; |
| 169 | } |
| 170 | } |
| 171 | } |
| 172 | return address; |
| 173 | } |
| 174 | |
dschinazi | a8489d2 | 2024-01-10 07:00:12 -0800 | [diff] [blame] | 175 | void MasqueServerBackend::SetSignatureAuth(absl::string_view signature_auth) { |
| 176 | signature_auth_credentials_.clear(); |
| 177 | if (signature_auth.empty()) { |
| 178 | return; |
| 179 | } |
| 180 | for (absl::string_view sp : absl::StrSplit(signature_auth, ';')) { |
| 181 | quiche::QuicheTextUtils::RemoveLeadingAndTrailingWhitespace(&sp); |
| 182 | if (sp.empty()) { |
| 183 | continue; |
| 184 | } |
| 185 | std::vector<absl::string_view> kv = |
| 186 | absl::StrSplit(sp, absl::MaxSplits(':', 1)); |
| 187 | quiche::QuicheTextUtils::RemoveLeadingAndTrailingWhitespace(&kv[0]); |
| 188 | quiche::QuicheTextUtils::RemoveLeadingAndTrailingWhitespace(&kv[1]); |
| 189 | SignatureAuthCredential credential; |
| 190 | credential.key_id = std::string(kv[0]); |
| 191 | std::string public_key = absl::HexStringToBytes(kv[1]); |
| 192 | if (public_key.size() != sizeof(credential.public_key)) { |
| 193 | QUIC_LOG(FATAL) << "Invalid signature auth public key length " |
| 194 | << public_key.size(); |
| 195 | } |
| 196 | memcpy(credential.public_key, public_key.data(), |
| 197 | sizeof(credential.public_key)); |
| 198 | signature_auth_credentials_.push_back(credential); |
| 199 | } |
| 200 | } |
| 201 | |
| 202 | bool MasqueServerBackend::GetSignatureAuthKeyForId( |
| 203 | absl::string_view key_id, |
| 204 | uint8_t out_public_key[ED25519_PUBLIC_KEY_LEN]) const { |
| 205 | for (const auto& credential : signature_auth_credentials_) { |
| 206 | if (credential.key_id == key_id) { |
| 207 | memcpy(out_public_key, credential.public_key, |
| 208 | sizeof(credential.public_key)); |
| 209 | return true; |
| 210 | } |
| 211 | } |
| 212 | return false; |
| 213 | } |
| 214 | |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 215 | } // namespace quic |