xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/masque/masque_utils.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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_utils.h"
6 
7 #include <cstdint>
8 #include <cstring>
9 #include <ostream>
10 #include <string>
11 #include <utility>
12 
13 #include "absl/strings/escaping.h"
14 #include "absl/strings/str_cat.h"
15 #include "absl/strings/string_view.h"
16 #include "quiche/quic/core/quic_config.h"
17 #include "quiche/quic/core/quic_data_writer.h"
18 #include "quiche/quic/core/quic_versions.h"
19 #include "quiche/quic/platform/api/quic_ip_address.h"
20 #include "quiche/quic/platform/api/quic_logging.h"
21 #include "quiche/common/platform/api/quiche_logging.h"
22 
23 #if defined(__linux__)
24 #include <fcntl.h>
25 #include <linux/if.h>
26 #include <linux/if_tun.h>
27 #include <sys/ioctl.h>
28 #endif  // defined(__linux__)
29 
30 #include "absl/cleanup/cleanup.h"
31 
32 namespace quic {
33 
MasqueSupportedVersions()34 ParsedQuicVersionVector MasqueSupportedVersions() {
35   ParsedQuicVersionVector versions;
36   for (const ParsedQuicVersion& version : AllSupportedVersions()) {
37     // Use all versions that support IETF QUIC except QUICv2.
38     if (version.UsesHttp3() && !version.AlpnDeferToRFCv1()) {
39       QuicEnableVersion(version);
40       versions.push_back(version);
41     }
42   }
43   QUICHE_CHECK(!versions.empty());
44   return versions;
45 }
46 
MasqueEncapsulatedConfig()47 QuicConfig MasqueEncapsulatedConfig() {
48   QuicConfig config;
49   config.SetMaxPacketSizeToSend(kMasqueMaxEncapsulatedPacketSize);
50   return config;
51 }
52 
MasqueModeToString(MasqueMode masque_mode)53 std::string MasqueModeToString(MasqueMode masque_mode) {
54   switch (masque_mode) {
55     case MasqueMode::kInvalid:
56       return "Invalid";
57     case MasqueMode::kOpen:
58       return "Open";
59     case MasqueMode::kConnectIp:
60       return "CONNECT-IP";
61     case MasqueMode::kConnectEthernet:
62       return "CONNECT-ETHERNET";
63   }
64   return absl::StrCat("Unknown(", static_cast<int>(masque_mode), ")");
65 }
66 
operator <<(std::ostream & os,const MasqueMode & masque_mode)67 std::ostream& operator<<(std::ostream& os, const MasqueMode& masque_mode) {
68   os << MasqueModeToString(masque_mode);
69   return os;
70 }
71 
72 #if defined(__linux__)
CreateTunInterface(const QuicIpAddress & client_address,bool server)73 int CreateTunInterface(const QuicIpAddress& client_address, bool server) {
74   if (!client_address.IsIPv4()) {
75     QUIC_LOG(ERROR) << "CreateTunInterface currently only supports IPv4";
76     return -1;
77   }
78   // TODO(b/281517862): add test to validate O_NONBLOCK
79   int tun_fd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
80   if (tun_fd < 0) {
81     QUIC_PLOG(ERROR) << "Failed to open clone device";
82     return -1;
83   }
84   absl::Cleanup tun_fd_closer = [tun_fd] { close(tun_fd); };
85 
86   struct ifreq ifr = {};
87   ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
88   // If we want to pick a specific device name, we can set it via
89   // ifr.ifr_name. Otherwise, the kernel will pick the next available tunX
90   // name.
91   int err = ioctl(tun_fd, TUNSETIFF, &ifr);
92   if (err < 0) {
93     QUIC_PLOG(ERROR) << "TUNSETIFF failed";
94     return -1;
95   }
96   int ip_fd = socket(AF_INET, SOCK_DGRAM, 0);
97   if (ip_fd < 0) {
98     QUIC_PLOG(ERROR) << "Failed to open IP configuration socket";
99     return -1;
100   }
101   absl::Cleanup ip_fd_closer = [ip_fd] { close(ip_fd); };
102 
103   struct sockaddr_in addr = {};
104   addr.sin_family = AF_INET;
105   // Local address, unused but needs to be set. We use the same address as the
106   // client address, but with last byte set to 1.
107   addr.sin_addr = client_address.GetIPv4();
108   if (server) {
109     addr.sin_addr.s_addr &= htonl(0xffffff00);
110     addr.sin_addr.s_addr |= htonl(0x00000001);
111   }
112   memcpy(&ifr.ifr_addr, &addr, sizeof(addr));
113   err = ioctl(ip_fd, SIOCSIFADDR, &ifr);
114   if (err < 0) {
115     QUIC_PLOG(ERROR) << "SIOCSIFADDR failed";
116     return -1;
117   }
118   // Peer address, needs to match source IP address of sent packets.
119   addr.sin_addr = client_address.GetIPv4();
120   if (!server) {
121     addr.sin_addr.s_addr &= htonl(0xffffff00);
122     addr.sin_addr.s_addr |= htonl(0x00000001);
123   }
124   memcpy(&ifr.ifr_addr, &addr, sizeof(addr));
125   err = ioctl(ip_fd, SIOCSIFDSTADDR, &ifr);
126   if (err < 0) {
127     QUIC_PLOG(ERROR) << "SIOCSIFDSTADDR failed";
128     return -1;
129   }
130   if (!server) {
131     // Set MTU, to 1280 for now which should always fit (fingers crossed)
132     ifr.ifr_mtu = 1280;
133     err = ioctl(ip_fd, SIOCSIFMTU, &ifr);
134     if (err < 0) {
135       QUIC_PLOG(ERROR) << "SIOCSIFMTU failed";
136       return -1;
137     }
138   }
139 
140   err = ioctl(ip_fd, SIOCGIFFLAGS, &ifr);
141   if (err < 0) {
142     QUIC_PLOG(ERROR) << "SIOCGIFFLAGS failed";
143     return -1;
144   }
145   ifr.ifr_flags |= (IFF_UP | IFF_RUNNING);
146   err = ioctl(ip_fd, SIOCSIFFLAGS, &ifr);
147   if (err < 0) {
148     QUIC_PLOG(ERROR) << "SIOCSIFFLAGS failed";
149     return -1;
150   }
151   close(ip_fd);
152   QUIC_DLOG(INFO) << "Successfully created TUN interface " << ifr.ifr_name
153                   << " with fd " << tun_fd;
154   std::move(tun_fd_closer).Cancel();
155   return tun_fd;
156 }
157 #else
CreateTunInterface(const QuicIpAddress &,bool)158 int CreateTunInterface(const QuicIpAddress& /*client_address*/,
159                        bool /*server*/) {
160   // Unsupported.
161   return -1;
162 }
163 #endif  // defined(__linux__)
164 
165 #if defined(__linux__)
CreateTapInterface()166 int CreateTapInterface() {
167   int tap_fd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
168   if (tap_fd < 0) {
169     QUIC_PLOG(ERROR) << "Failed to open clone device";
170     return -1;
171   }
172   absl::Cleanup tap_fd_closer = [tap_fd] { close(tap_fd); };
173 
174   struct ifreq ifr = {};
175   ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
176   // If we want to pick a specific device name, we can set it via
177   // ifr.ifr_name. Otherwise, the kernel will pick the next available tapX
178   // name.
179   int err = ioctl(tap_fd, TUNSETIFF, &ifr);
180   if (err < 0) {
181     QUIC_PLOG(ERROR) << "TUNSETIFF failed";
182     return -1;
183   }
184 
185   QUIC_DLOG(INFO) << "Successfully created TAP interface " << ifr.ifr_name
186                   << " with fd " << tap_fd;
187 
188   int sock_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
189   if (sock_fd < 0) {
190     QUIC_PLOG(ERROR) << "Error opening configuration socket";
191     return -1;
192   }
193   absl::Cleanup sock_fd_closer = [sock_fd] { close(sock_fd); };
194 
195   ifr.ifr_mtu = 1280;
196   err = ioctl(sock_fd, SIOCSIFMTU, &ifr);
197   if (err < 0) {
198     QUIC_PLOG(ERROR) << "SIOCSIFMTU failed";
199     return -1;
200   }
201 
202   err = ioctl(sock_fd, SIOCGIFFLAGS, &ifr);
203   if (err < 0) {
204     QUIC_PLOG(ERROR) << "SIOCGIFFLAGS failed";
205     return -1;
206   }
207   ifr.ifr_flags |= (IFF_UP | IFF_RUNNING);
208   err = ioctl(sock_fd, SIOCSIFFLAGS, &ifr);
209   if (err < 0) {
210     QUIC_PLOG(ERROR) << "SIOCSIFFLAGS failed";
211     return -1;
212   }
213   std::move(tap_fd_closer).Cancel();
214   return tap_fd;
215 }
216 #else
CreateTapInterface()217 int CreateTapInterface() {
218   // Unsupported.
219   return -1;
220 }
221 #endif  // defined(__linux__)
222 
ComputeSignatureAuthContext(uint16_t signature_scheme,absl::string_view key_id,absl::string_view public_key,absl::string_view scheme,absl::string_view host,uint16_t port,absl::string_view realm)223 std::string ComputeSignatureAuthContext(uint16_t signature_scheme,
224                                         absl::string_view key_id,
225                                         absl::string_view public_key,
226                                         absl::string_view scheme,
227                                         absl::string_view host, uint16_t port,
228                                         absl::string_view realm) {
229   QUIC_DVLOG(2) << "ComputeSignatureAuthContext: key_id=\"" << key_id
230                 << "\" public_key=" << absl::WebSafeBase64Escape(public_key)
231                 << " scheme=\"" << scheme << "\" host=\"" << host
232                 << "\" port=" << port << " realm=\"" << realm << "\"";
233   std::string key_exporter_context;
234   key_exporter_context.resize(
235       sizeof(signature_scheme) + QuicDataWriter::GetVarInt62Len(key_id.size()) +
236       key_id.size() + QuicDataWriter::GetVarInt62Len(public_key.size()) +
237       public_key.size() + QuicDataWriter::GetVarInt62Len(scheme.size()) +
238       scheme.size() + QuicDataWriter::GetVarInt62Len(host.size()) +
239       host.size() + sizeof(port) +
240       QuicDataWriter::GetVarInt62Len(realm.size()) + realm.size());
241   QuicDataWriter writer(key_exporter_context.size(),
242                         key_exporter_context.data());
243   if (!writer.WriteUInt16(signature_scheme) ||
244       !writer.WriteStringPieceVarInt62(key_id) ||
245       !writer.WriteStringPieceVarInt62(public_key) ||
246       !writer.WriteStringPieceVarInt62(scheme) ||
247       !writer.WriteStringPieceVarInt62(host) || !writer.WriteUInt16(port) ||
248       !writer.WriteStringPieceVarInt62(realm) || writer.remaining() != 0) {
249     QUIC_LOG(FATAL) << "ComputeSignatureAuthContext failed";
250   }
251   return key_exporter_context;
252 }
253 
SignatureAuthDataCoveredBySignature(absl::string_view signature_input)254 std::string SignatureAuthDataCoveredBySignature(
255     absl::string_view signature_input) {
256   return absl::StrCat(std::string(64, 0x20), "HTTP Signature Authentication",
257                       std::string(1, 0x00), signature_input);
258 }
259 
260 }  // namespace quic
261