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 // This file is responsible for the masque_client binary. It allows testing
6 // our MASQUE client code by connecting to a MASQUE proxy and then sending
7 // HTTP/3 requests to web servers tunnelled over that MASQUE connection.
8 // e.g.: masque_client $PROXY_HOST:$PROXY_PORT $URL1 $URL2
9
10 #include <cstddef>
11 #include <cstdint>
12 #include <iostream>
13 #include <memory>
14 #include <string>
15 #include <utility>
16 #include <vector>
17
18 #include "absl/strings/escaping.h"
19 #include "absl/strings/match.h"
20 #include "absl/strings/str_cat.h"
21 #include "absl/strings/str_split.h"
22 #include "absl/strings/string_view.h"
23 #include "openssl/curve25519.h"
24 #include "quiche/quic/core/crypto/proof_verifier.h"
25 #include "quiche/quic/core/http/quic_spdy_client_stream.h"
26 #include "quiche/quic/core/io/quic_default_event_loop.h"
27 #include "quiche/quic/core/io/quic_event_loop.h"
28 #include "quiche/quic/core/quic_default_clock.h"
29 #include "quiche/quic/core/quic_time.h"
30 #include "quiche/quic/core/quic_udp_socket.h"
31 #include "quiche/quic/masque/masque_client.h"
32 #include "quiche/quic/masque/masque_client_session.h"
33 #include "quiche/quic/masque/masque_client_tools.h"
34 #include "quiche/quic/masque/masque_utils.h"
35 #include "quiche/quic/platform/api/quic_bug_tracker.h"
36 #include "quiche/quic/platform/api/quic_default_proof_providers.h"
37 #include "quiche/quic/platform/api/quic_ip_address.h"
38 #include "quiche/quic/platform/api/quic_logging.h"
39 #include "quiche/quic/tools/fake_proof_verifier.h"
40 #include "quiche/common/capsule.h"
41 #include "quiche/common/platform/api/quiche_command_line_flags.h"
42 #include "quiche/common/platform/api/quiche_googleurl.h"
43 #include "quiche/common/platform/api/quiche_logging.h"
44 #include "quiche/common/platform/api/quiche_system_event_loop.h"
45
46 DEFINE_QUICHE_COMMAND_LINE_FLAG(
47 bool, disable_certificate_verification, false,
48 "If true, don't verify the server certificate.");
49
50 DEFINE_QUICHE_COMMAND_LINE_FLAG(int, address_family, 0,
51 "IP address family to use. Must be 0, 4 or 6. "
52 "Defaults to 0 which means any.");
53
54 DEFINE_QUICHE_COMMAND_LINE_FLAG(
55 std::string, masque_mode, "",
56 "Allows setting MASQUE mode, currently only valid value is \"open\".");
57
58 DEFINE_QUICHE_COMMAND_LINE_FLAG(
59 std::string, proxy_headers, "",
60 "A list of HTTP headers to add to request to the MASQUE proxy. "
61 "Separated with colons and semicolons. "
62 "For example: \"name1:value1;name2:value2\".");
63
64 DEFINE_QUICHE_COMMAND_LINE_FLAG(
65 std::string, signature_auth, "",
66 "Enables HTTP Signature Authentication. Pass in the string \"new\" to "
67 "generate new keys. Otherwise, pass in the key ID in ASCII followed by a "
68 "colon and the 32-byte private key as hex. For example: \"kid:0123...f\".");
69
70 DEFINE_QUICHE_COMMAND_LINE_FLAG(
71 bool, bring_up_tun, false,
72 "If set to true, no URLs need to be specified and instead a TUN device "
73 "is brought up with the assigned IP from the MASQUE CONNECT-IP server.");
74
75 DEFINE_QUICHE_COMMAND_LINE_FLAG(
76 bool, dns_on_client, false,
77 "If set to true, masque_client will perform DNS for encapsulated URLs and "
78 "send the IP litteral in the CONNECT request. If set to false, "
79 "masque_client send the hostname in the CONNECT request.");
80
81 DEFINE_QUICHE_COMMAND_LINE_FLAG(
82 bool, bring_up_tap, false,
83 "If set to true, no URLs need to be specified and instead a TAP device "
84 "is brought up for a MASQUE CONNECT-ETHERNET session.");
85
86 namespace quic {
87
88 namespace {
89
90 using ::quiche::AddressAssignCapsule;
91 using ::quiche::AddressRequestCapsule;
92 using ::quiche::RouteAdvertisementCapsule;
93
94 class MasqueTunSession : public MasqueClientSession::EncapsulatedIpSession,
95 public QuicSocketEventListener {
96 public:
MasqueTunSession(QuicEventLoop * event_loop,MasqueClientSession * session)97 MasqueTunSession(QuicEventLoop* event_loop, MasqueClientSession* session)
98 : event_loop_(event_loop), session_(session) {}
99 ~MasqueTunSession() override = default;
100 // MasqueClientSession::EncapsulatedIpSession
ProcessIpPacket(absl::string_view packet)101 void ProcessIpPacket(absl::string_view packet) override {
102 QUIC_LOG(INFO) << " Received IP packets of length " << packet.length();
103 if (fd_ == -1) {
104 // TUN not open, early return
105 return;
106 }
107 if (write(fd_, packet.data(), packet.size()) == -1) {
108 QUIC_LOG(FATAL) << "Failed to write";
109 }
110 }
CloseIpSession(const std::string & details)111 void CloseIpSession(const std::string& details) override {
112 QUIC_LOG(ERROR) << "Was asked to close IP session: " << details;
113 }
OnAddressAssignCapsule(const AddressAssignCapsule & capsule)114 bool OnAddressAssignCapsule(const AddressAssignCapsule& capsule) override {
115 for (auto assigned_address : capsule.assigned_addresses) {
116 if (assigned_address.ip_prefix.address().IsIPv4()) {
117 QUIC_LOG(INFO) << "MasqueTunSession saving local IPv4 address "
118 << assigned_address.ip_prefix.address();
119 local_address_ = assigned_address.ip_prefix.address();
120 break;
121 }
122 }
123 // Bring up the TUN
124 QUIC_LOG(ERROR) << "Bringing up tun with address " << local_address_;
125 fd_ = CreateTunInterface(local_address_, false);
126 if (fd_ < 0) {
127 QUIC_LOG(FATAL) << "Failed to create TUN interface";
128 }
129 if (!event_loop_->RegisterSocket(fd_, kSocketEventReadable, this)) {
130 QUIC_LOG(FATAL) << "Failed to register TUN fd with the event loop";
131 }
132 return true;
133 }
OnAddressRequestCapsule(const AddressRequestCapsule &)134 bool OnAddressRequestCapsule(
135 const AddressRequestCapsule& /*capsule*/) override {
136 // Always ignore the address request capsule from the server.
137 return true;
138 }
OnRouteAdvertisementCapsule(const RouteAdvertisementCapsule &)139 bool OnRouteAdvertisementCapsule(
140 const RouteAdvertisementCapsule& /*capsule*/) override {
141 // Consider installing routes.
142 return true;
143 }
144
145 // QuicSocketEventListener
OnSocketEvent(QuicEventLoop *,QuicUdpSocketFd fd,QuicSocketEventMask events)146 void OnSocketEvent(QuicEventLoop* /*event_loop*/, QuicUdpSocketFd fd,
147 QuicSocketEventMask events) override {
148 if ((events & kSocketEventReadable) == 0) {
149 QUIC_DVLOG(1) << "Ignoring OnEvent fd " << fd << " event mask " << events;
150 return;
151 }
152 char datagram[kMasqueIpPacketBufferSize];
153 while (true) {
154 ssize_t read_size = read(fd, datagram, sizeof(datagram));
155 if (read_size < 0) {
156 break;
157 }
158 // Packet received from the TUN. Write it to the MASQUE CONNECT-IP
159 // session.
160 session_->SendIpPacket(absl::string_view(datagram, read_size), this);
161 }
162 if (!event_loop_->SupportsEdgeTriggered()) {
163 if (!event_loop_->RearmSocket(fd, kSocketEventReadable)) {
164 QUIC_BUG(MasqueServerSession_ConnectIp_OnSocketEvent_Rearm)
165 << "Failed to re-arm socket " << fd << " for reading";
166 }
167 }
168 }
169
170 private:
171 QuicEventLoop* event_loop_;
172 MasqueClientSession* session_;
173 QuicIpAddress local_address_;
174 int fd_ = -1;
175 };
176
177 class MasqueTapSession
178 : public MasqueClientSession::EncapsulatedEthernetSession,
179 public QuicSocketEventListener {
180 public:
MasqueTapSession(QuicEventLoop * event_loop,MasqueClientSession * session)181 MasqueTapSession(QuicEventLoop* event_loop, MasqueClientSession* session)
182 : event_loop_(event_loop), session_(session) {}
183 ~MasqueTapSession() override = default;
184
CreateInterface(void)185 void CreateInterface(void) {
186 QUIC_LOG(ERROR) << "Bringing up TAP";
187 fd_ = CreateTapInterface();
188 if (fd_ < 0) {
189 QUIC_LOG(FATAL) << "Failed to create TAP interface";
190 }
191 if (!event_loop_->RegisterSocket(fd_, kSocketEventReadable, this)) {
192 QUIC_LOG(FATAL) << "Failed to register TAP fd with the event loop";
193 }
194 }
195
196 // MasqueClientSession::EncapsulatedEthernetSession
ProcessEthernetFrame(absl::string_view frame)197 void ProcessEthernetFrame(absl::string_view frame) override {
198 QUIC_LOG(INFO) << " Received Ethernet frame of length " << frame.length();
199 if (fd_ == -1) {
200 // TAP not open, early return
201 return;
202 }
203 if (write(fd_, frame.data(), frame.size()) == -1) {
204 QUIC_LOG(FATAL) << "Failed to write";
205 }
206 }
CloseEthernetSession(const std::string & details)207 void CloseEthernetSession(const std::string& details) override {
208 QUIC_LOG(ERROR) << "Was asked to close Ethernet session: " << details;
209 }
210
211 // QuicSocketEventListener
OnSocketEvent(QuicEventLoop *,QuicUdpSocketFd fd,QuicSocketEventMask events)212 void OnSocketEvent(QuicEventLoop* /*event_loop*/, QuicUdpSocketFd fd,
213 QuicSocketEventMask events) override {
214 if ((events & kSocketEventReadable) == 0) {
215 QUIC_DVLOG(1) << "Ignoring OnEvent fd " << fd << " event mask " << events;
216 return;
217 }
218 char datagram[kMasqueEthernetFrameBufferSize];
219 while (true) {
220 ssize_t read_size = read(fd, datagram, sizeof(datagram));
221 if (read_size < 0) {
222 break;
223 }
224 // Frame received from the TAP. Write it to the MASQUE CONNECT-ETHERNET
225 // session.
226 session_->SendEthernetFrame(absl::string_view(datagram, read_size), this);
227 }
228 if (!event_loop_->SupportsEdgeTriggered()) {
229 if (!event_loop_->RearmSocket(fd, kSocketEventReadable)) {
230 QUIC_BUG(MasqueServerSession_ConnectIp_OnSocketEvent_Rearm)
231 << "Failed to re-arm socket " << fd << " for reading";
232 }
233 }
234 }
235
236 private:
237 QuicEventLoop* event_loop_;
238 MasqueClientSession* session_;
239 std::string local_mac_address_; // string, uint8_t[6], or new wrapper type?
240 int fd_ = -1;
241 };
242
RunMasqueClient(int argc,char * argv[])243 int RunMasqueClient(int argc, char* argv[]) {
244 const char* usage =
245 "Usage: masque_client [options] <proxy-url> <urls>..\n"
246 " <proxy-url> is the URI template of the MASQUE server,\n"
247 " or host:port to use the default template";
248
249 // The first non-flag argument is the URI template of the MASQUE server.
250 // All subsequent ones are interpreted as URLs to fetch via the MASQUE server.
251 // Note that the URI template expansion currently only supports string
252 // replacement of {target_host} and {target_port}, not
253 // {?target_host,target_port}.
254 std::vector<std::string> urls =
255 quiche::QuicheParseCommandLineFlags(usage, argc, argv);
256
257 std::string signature_auth_param =
258 quiche::GetQuicheCommandLineFlag(FLAGS_signature_auth);
259 std::string signature_auth_key_id;
260 std::string signature_auth_private_key;
261 std::string signature_auth_public_key;
262 if (!signature_auth_param.empty()) {
263 static constexpr size_t kEd25519Rfc8032PrivateKeySize = 32;
264 uint8_t public_key[ED25519_PUBLIC_KEY_LEN];
265 uint8_t private_key[ED25519_PRIVATE_KEY_LEN];
266 const bool is_new_key_pair = signature_auth_param == "new";
267 if (is_new_key_pair) {
268 ED25519_keypair(public_key, private_key);
269 QUIC_LOG(INFO) << "Generated new Signature Authentication key pair";
270 } else {
271 std::vector<absl::string_view> signature_auth_param_split =
272 absl::StrSplit(signature_auth_param, absl::MaxSplits(':', 1));
273 std::string private_key_seed;
274 if (signature_auth_param_split.size() != 2) {
275 QUIC_LOG(ERROR)
276 << "Signature authentication parameter is missing a colon";
277 return 1;
278 }
279 signature_auth_key_id = signature_auth_param_split[0];
280 if (signature_auth_key_id.empty()) {
281 QUIC_LOG(ERROR) << "Signature authentication key ID cannot be empty";
282 return 1;
283 }
284 if (!absl::HexStringToBytes(signature_auth_param_split[1],
285 &private_key_seed)) {
286 QUIC_LOG(ERROR) << "Signature authentication key hex value is invalid";
287 return 1;
288 }
289
290 if (private_key_seed.size() != kEd25519Rfc8032PrivateKeySize) {
291 QUIC_LOG(ERROR)
292 << "Invalid signature authentication private key length "
293 << private_key_seed.size();
294 return 1;
295 }
296 ED25519_keypair_from_seed(
297 public_key, private_key,
298 reinterpret_cast<uint8_t*>(private_key_seed.data()));
299 QUIC_LOG(INFO) << "Loaded Signature Authentication key pair";
300 }
301 // Note that Ed25519 private keys are 32 bytes long per RFC 8032. However,
302 // to reduce CPU costs, BoringSSL represents private keys in memory as the
303 // concatenation of the 32-byte private key and the corresponding 32-byte
304 // public key - which makes for a total of 64 bytes. The private key log
305 // below relies on this BoringSSL implementation detail to extract the
306 // RFC 8032 private key because BoringSSL does not provide a supported way
307 // to access it. This is required to allow us to print the private key in a
308 // format that can be passed back in to BoringSSL from the command-line. See
309 // curve25519.h for details. The rest of our signature authentication code
310 // uses the BoringSSL representation without relying on this implementation
311 // detail.
312 static_assert(kEd25519Rfc8032PrivateKeySize <=
313 static_cast<size_t>(ED25519_PRIVATE_KEY_LEN));
314
315 std::string private_key_hexstr = absl::BytesToHexString(absl::string_view(
316 reinterpret_cast<char*>(private_key), kEd25519Rfc8032PrivateKeySize));
317 std::string public_key_hexstr = absl::BytesToHexString(absl::string_view(
318 reinterpret_cast<char*>(public_key), ED25519_PUBLIC_KEY_LEN));
319 if (is_new_key_pair) {
320 std::cout << "Generated new Signature Authentication key pair."
321 << std::endl;
322 std::cout << "Private key: " << private_key_hexstr << std::endl;
323 std::cout << "Public key: " << public_key_hexstr << std::endl;
324 return 0;
325 }
326 QUIC_LOG(INFO) << "Private key: " << private_key_hexstr;
327 QUIC_LOG(INFO) << "Public key: " << public_key_hexstr;
328 signature_auth_private_key = std::string(
329 reinterpret_cast<char*>(private_key), ED25519_PRIVATE_KEY_LEN);
330 signature_auth_public_key = std::string(reinterpret_cast<char*>(public_key),
331 ED25519_PUBLIC_KEY_LEN);
332 }
333
334 bool bring_up_tun = quiche::GetQuicheCommandLineFlag(FLAGS_bring_up_tun);
335 bool bring_up_tap = quiche::GetQuicheCommandLineFlag(FLAGS_bring_up_tap);
336 if (urls.empty() && !bring_up_tun && !bring_up_tap) {
337 quiche::QuichePrintCommandLineFlagHelp(usage);
338 return 1;
339 }
340 if (bring_up_tun && bring_up_tap) {
341 quiche::QuichePrintCommandLineFlagHelp(usage);
342 return 1;
343 }
344
345 quiche::QuicheSystemEventLoop system_event_loop("masque_client");
346 const bool disable_certificate_verification =
347 quiche::GetQuicheCommandLineFlag(FLAGS_disable_certificate_verification);
348 std::unique_ptr<QuicEventLoop> event_loop =
349 GetDefaultEventLoop()->Create(QuicDefaultClock::Get());
350
351 std::string uri_template = urls[0];
352 if (!absl::StrContains(uri_template, '/')) {
353 // If an authority is passed in instead of a URI template, use the default
354 // URI template.
355 uri_template =
356 absl::StrCat("https://", uri_template,
357 "/.well-known/masque/udp/{target_host}/{target_port}/");
358 }
359 url::Parsed parsed_uri_template;
360 url::ParseStandardURL(uri_template.c_str(), uri_template.length(),
361 &parsed_uri_template);
362 if (!parsed_uri_template.scheme.is_nonempty() ||
363 !parsed_uri_template.host.is_nonempty() ||
364 !parsed_uri_template.path.is_nonempty()) {
365 QUIC_LOG(ERROR) << "Failed to parse MASQUE URI template \"" << urls[0]
366 << "\"";
367 return 1;
368 }
369 std::string host = uri_template.substr(parsed_uri_template.host.begin,
370 parsed_uri_template.host.len);
371 std::unique_ptr<ProofVerifier> proof_verifier;
372 if (disable_certificate_verification) {
373 proof_verifier = std::make_unique<FakeProofVerifier>();
374 } else {
375 proof_verifier = CreateDefaultProofVerifier(host);
376 }
377 MasqueMode masque_mode = MasqueMode::kOpen;
378 std::string mode_string = quiche::GetQuicheCommandLineFlag(FLAGS_masque_mode);
379 if (!mode_string.empty()) {
380 if (mode_string == "open") {
381 masque_mode = MasqueMode::kOpen;
382 } else if (mode_string == "connectip" || mode_string == "connect-ip") {
383 masque_mode = MasqueMode::kConnectIp;
384 } else if (mode_string == "connectethernet" ||
385 mode_string == "connect-ethernet") {
386 masque_mode = MasqueMode::kConnectEthernet;
387 } else {
388 QUIC_LOG(ERROR) << "Invalid masque_mode \"" << mode_string << "\"";
389 return 1;
390 }
391 }
392 const int address_family =
393 quiche::GetQuicheCommandLineFlag(FLAGS_address_family);
394 int address_family_for_lookup;
395 if (address_family == 0) {
396 address_family_for_lookup = AF_UNSPEC;
397 } else if (address_family == 4) {
398 address_family_for_lookup = AF_INET;
399 } else if (address_family == 6) {
400 address_family_for_lookup = AF_INET6;
401 } else {
402 QUIC_LOG(ERROR) << "Invalid address_family " << address_family;
403 return 1;
404 }
405 std::unique_ptr<MasqueClient> masque_client = MasqueClient::Create(
406 uri_template, masque_mode, event_loop.get(), std::move(proof_verifier));
407 if (masque_client == nullptr) {
408 return 1;
409 }
410
411 QUIC_LOG(INFO) << "MASQUE is connected " << masque_client->connection_id()
412 << " in " << masque_mode << " mode";
413
414 masque_client->masque_client_session()->set_additional_headers(
415 quiche::GetQuicheCommandLineFlag(FLAGS_proxy_headers));
416 if (!signature_auth_param.empty()) {
417 masque_client->masque_client_session()->EnableSignatureAuth(
418 signature_auth_key_id, signature_auth_private_key,
419 signature_auth_public_key);
420 }
421
422 if (bring_up_tun) {
423 QUIC_LOG(INFO) << "Bringing up tun";
424 MasqueTunSession tun_session(event_loop.get(),
425 masque_client->masque_client_session());
426 masque_client->masque_client_session()->SendIpPacket(
427 absl::string_view("asdf"), &tun_session);
428 while (true) {
429 event_loop->RunEventLoopOnce(QuicTime::Delta::FromMilliseconds(50));
430 }
431 QUICHE_NOTREACHED();
432 }
433 if (bring_up_tap) {
434 MasqueTapSession tap_session(event_loop.get(),
435 masque_client->masque_client_session());
436 tap_session.CreateInterface();
437 while (true) {
438 event_loop->RunEventLoopOnce(QuicTime::Delta::FromMilliseconds(50));
439 }
440 QUICHE_NOTREACHED();
441 }
442
443 const bool dns_on_client =
444 quiche::GetQuicheCommandLineFlag(FLAGS_dns_on_client);
445
446 for (size_t i = 1; i < urls.size(); ++i) {
447 if (absl::StartsWith(urls[i], "/")) {
448 QuicSpdyClientStream* stream =
449 masque_client->masque_client_session()->SendGetRequest(urls[i]);
450 while (stream->time_to_response_complete().IsInfinite()) {
451 event_loop->RunEventLoopOnce(QuicTime::Delta::FromMilliseconds(50));
452 }
453 // Print the response body to stdout.
454 std::cout << std::endl << stream->data() << std::endl;
455 } else if (!tools::SendEncapsulatedMasqueRequest(
456 masque_client.get(), event_loop.get(), urls[i],
457 disable_certificate_verification, address_family_for_lookup,
458 dns_on_client)) {
459 return 1;
460 }
461 }
462
463 return 0;
464 }
465
466 } // namespace
467
468 } // namespace quic
469
main(int argc,char * argv[])470 int main(int argc, char* argv[]) { return quic::RunMasqueClient(argc, argv); }
471