Line | Count | Source |
1 | | // Copyright (c) 2009-2010 Satoshi Nakamoto |
2 | | // Copyright (c) 2009-present The Bitcoin Core developers |
3 | | // Distributed under the MIT software license, see the accompanying |
4 | | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
5 | | |
6 | | #include <bitcoin-build-config.h> // IWYU pragma: keep |
7 | | |
8 | | #include <netbase.h> |
9 | | |
10 | | #include <compat/compat.h> |
11 | | #include <sync.h> |
12 | | #include <tinyformat.h> |
13 | | #include <util/log.h> |
14 | | #include <util/sock.h> |
15 | | #include <util/strencodings.h> |
16 | | #include <util/string.h> |
17 | | #include <util/time.h> |
18 | | |
19 | | #include <atomic> |
20 | | #include <chrono> |
21 | | #include <cstdint> |
22 | | #include <functional> |
23 | | #include <limits> |
24 | | #include <memory> |
25 | | |
26 | | #ifdef HAVE_SOCKADDR_UN |
27 | | #include <sys/un.h> |
28 | | #endif |
29 | | |
30 | | using util::ContainsNoNUL; |
31 | | |
32 | | // Settings |
33 | | static GlobalMutex g_proxyinfo_mutex; |
34 | | static Proxy proxyInfo[NET_MAX] GUARDED_BY(g_proxyinfo_mutex); |
35 | | static Proxy nameProxy GUARDED_BY(g_proxyinfo_mutex); |
36 | | int nConnectTimeout = DEFAULT_CONNECT_TIMEOUT; |
37 | | bool fNameLookup = DEFAULT_NAME_LOOKUP; |
38 | | |
39 | | // Need ample time for negotiation for very slow proxies such as Tor |
40 | | std::chrono::milliseconds g_socks5_recv_timeout = 20s; |
41 | | CThreadInterrupt g_socks5_interrupt; |
42 | | |
43 | | ReachableNets g_reachable_nets; |
44 | | |
45 | | std::vector<CNetAddr> WrappedGetAddrInfo(const std::string& name, bool allow_lookup) |
46 | 0 | { |
47 | 0 | addrinfo ai_hint{}; |
48 | | // We want a TCP port, which is a streaming socket type |
49 | 0 | ai_hint.ai_socktype = SOCK_STREAM; |
50 | 0 | ai_hint.ai_protocol = IPPROTO_TCP; |
51 | | // We don't care which address family (IPv4 or IPv6) is returned |
52 | 0 | ai_hint.ai_family = AF_UNSPEC; |
53 | | |
54 | | // If we allow lookups of hostnames, use the AI_ADDRCONFIG flag to only |
55 | | // return addresses whose family we have an address configured for. |
56 | | // |
57 | | // If we don't allow lookups, then use the AI_NUMERICHOST flag for |
58 | | // getaddrinfo to only decode numerical network addresses and suppress |
59 | | // hostname lookups. |
60 | 0 | ai_hint.ai_flags = allow_lookup ? AI_ADDRCONFIG : AI_NUMERICHOST; Branch (60:24): [True: 0, False: 0]
|
61 | |
|
62 | 0 | addrinfo* ai_res{nullptr}; |
63 | 0 | const int n_err{getaddrinfo(name.c_str(), nullptr, &ai_hint, &ai_res)}; |
64 | 0 | if (n_err != 0) { Branch (64:9): [True: 0, False: 0]
|
65 | 0 | if ((ai_hint.ai_flags & AI_ADDRCONFIG) == AI_ADDRCONFIG) { Branch (65:13): [True: 0, False: 0]
|
66 | | // AI_ADDRCONFIG on some systems may exclude loopback-only addresses |
67 | | // If first lookup failed we perform a second lookup without AI_ADDRCONFIG |
68 | 0 | ai_hint.ai_flags = (ai_hint.ai_flags & ~AI_ADDRCONFIG); |
69 | 0 | const int n_err_retry{getaddrinfo(name.c_str(), nullptr, &ai_hint, &ai_res)}; |
70 | 0 | if (n_err_retry != 0) { Branch (70:17): [True: 0, False: 0]
|
71 | 0 | return {}; |
72 | 0 | } |
73 | 0 | } else { |
74 | 0 | return {}; |
75 | 0 | } |
76 | 0 | } |
77 | | |
78 | | // Traverse the linked list starting with ai_trav. |
79 | 0 | addrinfo* ai_trav{ai_res}; |
80 | 0 | std::vector<CNetAddr> resolved_addresses; |
81 | 0 | while (ai_trav != nullptr) { Branch (81:12): [True: 0, False: 0]
|
82 | 0 | if (ai_trav->ai_family == AF_INET) { Branch (82:13): [True: 0, False: 0]
|
83 | 0 | assert(ai_trav->ai_addrlen >= sizeof(sockaddr_in)); Branch (83:13): [True: 0, False: 0]
|
84 | 0 | resolved_addresses.emplace_back(reinterpret_cast<sockaddr_in*>(ai_trav->ai_addr)->sin_addr); |
85 | 0 | } |
86 | 0 | if (ai_trav->ai_family == AF_INET6) { Branch (86:13): [True: 0, False: 0]
|
87 | 0 | assert(ai_trav->ai_addrlen >= sizeof(sockaddr_in6)); Branch (87:13): [True: 0, False: 0]
|
88 | 0 | const sockaddr_in6* s6{reinterpret_cast<sockaddr_in6*>(ai_trav->ai_addr)}; |
89 | 0 | resolved_addresses.emplace_back(s6->sin6_addr, s6->sin6_scope_id); |
90 | 0 | } |
91 | 0 | ai_trav = ai_trav->ai_next; |
92 | 0 | } |
93 | 0 | freeaddrinfo(ai_res); |
94 | |
|
95 | 0 | return resolved_addresses; |
96 | 0 | } |
97 | | |
98 | | DNSLookupFn g_dns_lookup{WrappedGetAddrInfo}; |
99 | | |
100 | 0 | enum Network ParseNetwork(const std::string& net_in) { |
101 | 0 | std::string net = ToLower(net_in); |
102 | 0 | if (net == "ipv4") return NET_IPV4; Branch (102:9): [True: 0, False: 0]
|
103 | 0 | if (net == "ipv6") return NET_IPV6; Branch (103:9): [True: 0, False: 0]
|
104 | 0 | if (net == "onion") return NET_ONION; Branch (104:9): [True: 0, False: 0]
|
105 | 0 | if (net == "i2p") { Branch (105:9): [True: 0, False: 0]
|
106 | 0 | return NET_I2P; |
107 | 0 | } |
108 | 0 | if (net == "cjdns") { Branch (108:9): [True: 0, False: 0]
|
109 | 0 | return NET_CJDNS; |
110 | 0 | } |
111 | 0 | return NET_UNROUTABLE; |
112 | 0 | } |
113 | | |
114 | | std::string GetNetworkName(enum Network net) |
115 | 0 | { |
116 | 0 | switch (net) { Branch (116:13): [True: 0, False: 0]
|
117 | 0 | case NET_UNROUTABLE: return "not_publicly_routable"; Branch (117:5): [True: 0, False: 0]
|
118 | 0 | case NET_IPV4: return "ipv4"; Branch (118:5): [True: 0, False: 0]
|
119 | 0 | case NET_IPV6: return "ipv6"; Branch (119:5): [True: 0, False: 0]
|
120 | 0 | case NET_ONION: return "onion"; Branch (120:5): [True: 0, False: 0]
|
121 | 0 | case NET_I2P: return "i2p"; Branch (121:5): [True: 0, False: 0]
|
122 | 0 | case NET_CJDNS: return "cjdns"; Branch (122:5): [True: 0, False: 0]
|
123 | 0 | case NET_INTERNAL: return "internal"; Branch (123:5): [True: 0, False: 0]
|
124 | 0 | case NET_MAX: assert(false); Branch (124:5): [True: 0, False: 0]
Branch (124:19): [Folded - Ignored]
|
125 | 0 | } // no default case, so the compiler can warn about missing cases |
126 | | |
127 | 0 | assert(false); Branch (127:5): [Folded - Ignored]
|
128 | 0 | } |
129 | | |
130 | | std::vector<std::string> GetNetworkNames(bool append_unroutable) |
131 | 0 | { |
132 | 0 | std::vector<std::string> names; |
133 | 0 | for (int n = 0; n < NET_MAX; ++n) { Branch (133:21): [True: 0, False: 0]
|
134 | 0 | const enum Network network{static_cast<Network>(n)}; |
135 | 0 | if (network == NET_UNROUTABLE || network == NET_INTERNAL) continue; Branch (135:13): [True: 0, False: 0]
Branch (135:42): [True: 0, False: 0]
|
136 | 0 | names.emplace_back(GetNetworkName(network)); |
137 | 0 | } |
138 | 0 | if (append_unroutable) { Branch (138:9): [True: 0, False: 0]
|
139 | 0 | names.emplace_back(GetNetworkName(NET_UNROUTABLE)); |
140 | 0 | } |
141 | 0 | return names; |
142 | 0 | } |
143 | | |
144 | | static std::vector<CNetAddr> LookupIntern(const std::string& name, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function) |
145 | 0 | { |
146 | 0 | if (!ContainsNoNUL(name)) return {}; Branch (146:9): [True: 0, False: 0]
|
147 | 0 | { |
148 | 0 | CNetAddr addr; |
149 | | // From our perspective, onion addresses are not hostnames but rather |
150 | | // direct encodings of CNetAddr much like IPv4 dotted-decimal notation |
151 | | // or IPv6 colon-separated hextet notation. Since we can't use |
152 | | // getaddrinfo to decode them and it wouldn't make sense to resolve |
153 | | // them, we return a network address representing it instead. See |
154 | | // CNetAddr::SetSpecial(const std::string&) for more details. |
155 | 0 | if (addr.SetSpecial(name)) return {addr}; Branch (155:13): [True: 0, False: 0]
|
156 | 0 | } |
157 | | |
158 | 0 | std::vector<CNetAddr> addresses; |
159 | |
|
160 | 0 | for (const CNetAddr& resolved : dns_lookup_function(name, fAllowLookup)) { Branch (160:35): [True: 0, False: 0]
|
161 | 0 | if (nMaxSolutions > 0 && addresses.size() >= nMaxSolutions) { Branch (161:13): [True: 0, False: 0]
Branch (161:34): [True: 0, False: 0]
|
162 | 0 | break; |
163 | 0 | } |
164 | | /* Never allow resolving to an internal address. Consider any such result invalid */ |
165 | 0 | if (!resolved.IsInternal()) { Branch (165:13): [True: 0, False: 0]
|
166 | 0 | addresses.push_back(resolved); |
167 | 0 | } |
168 | 0 | } |
169 | |
|
170 | 0 | return addresses; |
171 | 0 | } |
172 | | |
173 | | std::vector<CNetAddr> LookupHost(const std::string& name, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function) |
174 | 0 | { |
175 | 0 | if (!ContainsNoNUL(name)) return {}; Branch (175:9): [True: 0, False: 0]
|
176 | 0 | std::string strHost = name; |
177 | 0 | if (strHost.empty()) return {}; Branch (177:9): [True: 0, False: 0]
|
178 | 0 | if (strHost.front() == '[' && strHost.back() == ']') { Branch (178:9): [True: 0, False: 0]
Branch (178:35): [True: 0, False: 0]
|
179 | 0 | strHost = strHost.substr(1, strHost.size() - 2); |
180 | 0 | } |
181 | |
|
182 | 0 | return LookupIntern(strHost, nMaxSolutions, fAllowLookup, dns_lookup_function); |
183 | 0 | } |
184 | | |
185 | | std::optional<CNetAddr> LookupHost(const std::string& name, bool fAllowLookup, DNSLookupFn dns_lookup_function) |
186 | 0 | { |
187 | 0 | const std::vector<CNetAddr> addresses{LookupHost(name, 1, fAllowLookup, dns_lookup_function)}; |
188 | 0 | return addresses.empty() ? std::nullopt : std::make_optional(addresses.front()); Branch (188:12): [True: 0, False: 0]
|
189 | 0 | } |
190 | | |
191 | | std::vector<CService> Lookup(const std::string& name, uint16_t portDefault, bool fAllowLookup, unsigned int nMaxSolutions, DNSLookupFn dns_lookup_function) |
192 | 0 | { |
193 | 0 | if (name.empty() || !ContainsNoNUL(name)) { Branch (193:9): [True: 0, False: 0]
Branch (193:25): [True: 0, False: 0]
|
194 | 0 | return {}; |
195 | 0 | } |
196 | 0 | uint16_t port{portDefault}; |
197 | 0 | std::string hostname; |
198 | 0 | SplitHostPort(name, port, hostname); |
199 | |
|
200 | 0 | const std::vector<CNetAddr> addresses{LookupIntern(hostname, nMaxSolutions, fAllowLookup, dns_lookup_function)}; |
201 | 0 | if (addresses.empty()) return {}; Branch (201:9): [True: 0, False: 0]
|
202 | 0 | std::vector<CService> services; |
203 | 0 | services.reserve(addresses.size()); |
204 | 0 | for (const auto& addr : addresses) Branch (204:27): [True: 0, False: 0]
|
205 | 0 | services.emplace_back(addr, port); |
206 | 0 | return services; |
207 | 0 | } |
208 | | |
209 | | std::optional<CService> Lookup(const std::string& name, uint16_t portDefault, bool fAllowLookup, DNSLookupFn dns_lookup_function) |
210 | 0 | { |
211 | 0 | const std::vector<CService> services{Lookup(name, portDefault, fAllowLookup, 1, dns_lookup_function)}; |
212 | |
|
213 | 0 | return services.empty() ? std::nullopt : std::make_optional(services.front()); Branch (213:12): [True: 0, False: 0]
|
214 | 0 | } |
215 | | |
216 | | CService LookupNumeric(const std::string& name, uint16_t portDefault, DNSLookupFn dns_lookup_function) |
217 | 0 | { |
218 | 0 | if (!ContainsNoNUL(name)) { Branch (218:9): [True: 0, False: 0]
|
219 | 0 | return {}; |
220 | 0 | } |
221 | | // "1.2:345" will fail to resolve the ip, but will still set the port. |
222 | | // If the ip fails to resolve, re-init the result. |
223 | 0 | return Lookup(name, portDefault, /*fAllowLookup=*/false, dns_lookup_function).value_or(CService{}); |
224 | 0 | } |
225 | | |
226 | | bool IsUnixSocketPath(const std::string& name) |
227 | 0 | { |
228 | 0 | #ifdef HAVE_SOCKADDR_UN |
229 | 0 | if (!name.starts_with(ADDR_PREFIX_UNIX)) return false; Branch (229:9): [True: 0, False: 0]
|
230 | | |
231 | | // Split off "unix:" prefix |
232 | 0 | std::string str{name.substr(ADDR_PREFIX_UNIX.length())}; |
233 | | |
234 | | // Path size limit is platform-dependent |
235 | | // see https://manpages.ubuntu.com/manpages/xenial/en/man7/unix.7.html |
236 | 0 | if (str.size() + 1 > sizeof(((sockaddr_un*)nullptr)->sun_path)) return false; Branch (236:9): [True: 0, False: 0]
|
237 | | |
238 | 0 | return true; |
239 | | #else |
240 | | return false; |
241 | | #endif |
242 | 0 | } |
243 | | |
244 | | /** SOCKS version */ |
245 | | enum SOCKSVersion: uint8_t { |
246 | | SOCKS4 = 0x04, |
247 | | SOCKS5 = 0x05 |
248 | | }; |
249 | | |
250 | | /** Values defined for METHOD in RFC1928 */ |
251 | | enum SOCKS5Method: uint8_t { |
252 | | NOAUTH = 0x00, //!< No authentication required |
253 | | GSSAPI = 0x01, //!< GSSAPI |
254 | | USER_PASS = 0x02, //!< Username/password |
255 | | NO_ACCEPTABLE = 0xff, //!< No acceptable methods |
256 | | }; |
257 | | |
258 | | /** Values defined for CMD in RFC1928 */ |
259 | | enum SOCKS5Command: uint8_t { |
260 | | CONNECT = 0x01, |
261 | | BIND = 0x02, |
262 | | UDP_ASSOCIATE = 0x03 |
263 | | }; |
264 | | |
265 | | /** Values defined for REP in RFC1928 and https://spec.torproject.org/socks-extensions.html */ |
266 | | enum SOCKS5Reply: uint8_t { |
267 | | SUCCEEDED = 0x00, //!< RFC1928: Succeeded |
268 | | GENFAILURE = 0x01, //!< RFC1928: General failure |
269 | | NOTALLOWED = 0x02, //!< RFC1928: Connection not allowed by ruleset |
270 | | NETUNREACHABLE = 0x03, //!< RFC1928: Network unreachable |
271 | | HOSTUNREACHABLE = 0x04, //!< RFC1928: Network unreachable |
272 | | CONNREFUSED = 0x05, //!< RFC1928: Connection refused |
273 | | TTLEXPIRED = 0x06, //!< RFC1928: TTL expired |
274 | | CMDUNSUPPORTED = 0x07, //!< RFC1928: Command not supported |
275 | | ATYPEUNSUPPORTED = 0x08, //!< RFC1928: Address type not supported |
276 | | TOR_HS_DESC_NOT_FOUND = 0xf0, //!< Tor: Onion service descriptor can not be found |
277 | | TOR_HS_DESC_INVALID = 0xf1, //!< Tor: Onion service descriptor is invalid |
278 | | TOR_HS_INTRO_FAILED = 0xf2, //!< Tor: Onion service introduction failed |
279 | | TOR_HS_REND_FAILED = 0xf3, //!< Tor: Onion service rendezvous failed |
280 | | TOR_HS_MISSING_CLIENT_AUTH = 0xf4, //!< Tor: Onion service missing client authorization |
281 | | TOR_HS_WRONG_CLIENT_AUTH = 0xf5, //!< Tor: Onion service wrong client authorization |
282 | | TOR_HS_BAD_ADDRESS = 0xf6, //!< Tor: Onion service invalid address |
283 | | TOR_HS_INTRO_TIMEOUT = 0xf7, //!< Tor: Onion service introduction timed out |
284 | | }; |
285 | | |
286 | | /** Values defined for ATYPE in RFC1928 */ |
287 | | enum SOCKS5Atyp: uint8_t { |
288 | | IPV4 = 0x01, |
289 | | DOMAINNAME = 0x03, |
290 | | IPV6 = 0x04, |
291 | | }; |
292 | | |
293 | | /** Status codes that can be returned by InterruptibleRecv */ |
294 | | enum class IntrRecvError { |
295 | | OK, |
296 | | Timeout, |
297 | | Disconnected, |
298 | | NetworkError, |
299 | | Interrupted |
300 | | }; |
301 | | |
302 | | /** |
303 | | * Try to read a specified number of bytes from a socket. Please read the "see |
304 | | * also" section for more detail. |
305 | | * |
306 | | * @param data The buffer where the read bytes should be stored. |
307 | | * @param len The number of bytes to read into the specified buffer. |
308 | | * @param timeout The total timeout for this read. |
309 | | * @param sock The socket (has to be in non-blocking mode) from which to read bytes. |
310 | | * |
311 | | * @returns An IntrRecvError indicating the resulting status of this read. |
312 | | * IntrRecvError::OK only if all of the specified number of bytes were |
313 | | * read. |
314 | | * |
315 | | * @see This function can be interrupted by calling g_socks5_interrupt(). |
316 | | * Sockets can be made non-blocking with Sock::SetNonBlocking(). |
317 | | */ |
318 | | static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, std::chrono::milliseconds timeout, const Sock& sock) |
319 | 0 | { |
320 | 0 | auto curTime{Now<SteadyMilliseconds>()}; |
321 | 0 | const auto endTime{curTime + timeout}; |
322 | 0 | while (len > 0 && curTime < endTime) { Branch (322:12): [True: 0, False: 0]
Branch (322:23): [True: 0, False: 0]
|
323 | 0 | ssize_t ret = sock.Recv(data, len, 0); // Optimistically try the recv first |
324 | 0 | if (ret > 0) { Branch (324:13): [True: 0, False: 0]
|
325 | 0 | len -= ret; |
326 | 0 | data += ret; |
327 | 0 | } else if (ret == 0) { // Unexpected disconnection Branch (327:20): [True: 0, False: 0]
|
328 | 0 | return IntrRecvError::Disconnected; |
329 | 0 | } else { // Other error or blocking |
330 | 0 | int nErr = WSAGetLastError(); |
331 | 0 | if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) { Branch (331:17): [True: 0, False: 0]
Branch (331:43): [True: 0, False: 0]
Branch (331:69): [True: 0, False: 0]
|
332 | | // Only wait at most MAX_WAIT_FOR_IO at a time, unless |
333 | | // we're approaching the end of the specified total timeout |
334 | 0 | const auto remaining = std::chrono::milliseconds{endTime - curTime}; |
335 | 0 | const auto timeout = std::min(remaining, std::chrono::milliseconds{MAX_WAIT_FOR_IO}); |
336 | 0 | if (!sock.Wait(timeout, Sock::RECV)) { Branch (336:21): [True: 0, False: 0]
|
337 | 0 | return IntrRecvError::NetworkError; |
338 | 0 | } |
339 | 0 | } else { |
340 | 0 | return IntrRecvError::NetworkError; |
341 | 0 | } |
342 | 0 | } |
343 | 0 | if (g_socks5_interrupt) { Branch (343:13): [True: 0, False: 0]
|
344 | 0 | return IntrRecvError::Interrupted; |
345 | 0 | } |
346 | 0 | curTime = Now<SteadyMilliseconds>(); |
347 | 0 | } |
348 | 0 | return len == 0 ? IntrRecvError::OK : IntrRecvError::Timeout; Branch (348:12): [True: 0, False: 0]
|
349 | 0 | } |
350 | | |
351 | | /** Convert SOCKS5 reply to an error message */ |
352 | | static std::string Socks5ErrorString(uint8_t err) |
353 | 0 | { |
354 | 0 | switch(err) { |
355 | 0 | case SOCKS5Reply::GENFAILURE: Branch (355:9): [True: 0, False: 0]
|
356 | 0 | return "general failure"; |
357 | 0 | case SOCKS5Reply::NOTALLOWED: Branch (357:9): [True: 0, False: 0]
|
358 | 0 | return "connection not allowed"; |
359 | 0 | case SOCKS5Reply::NETUNREACHABLE: Branch (359:9): [True: 0, False: 0]
|
360 | 0 | return "network unreachable"; |
361 | 0 | case SOCKS5Reply::HOSTUNREACHABLE: Branch (361:9): [True: 0, False: 0]
|
362 | 0 | return "host unreachable"; |
363 | 0 | case SOCKS5Reply::CONNREFUSED: Branch (363:9): [True: 0, False: 0]
|
364 | 0 | return "connection refused"; |
365 | 0 | case SOCKS5Reply::TTLEXPIRED: Branch (365:9): [True: 0, False: 0]
|
366 | 0 | return "TTL expired"; |
367 | 0 | case SOCKS5Reply::CMDUNSUPPORTED: Branch (367:9): [True: 0, False: 0]
|
368 | 0 | return "protocol error"; |
369 | 0 | case SOCKS5Reply::ATYPEUNSUPPORTED: Branch (369:9): [True: 0, False: 0]
|
370 | 0 | return "address type not supported"; |
371 | 0 | case SOCKS5Reply::TOR_HS_DESC_NOT_FOUND: Branch (371:9): [True: 0, False: 0]
|
372 | 0 | return "onion service descriptor can not be found"; |
373 | 0 | case SOCKS5Reply::TOR_HS_DESC_INVALID: Branch (373:9): [True: 0, False: 0]
|
374 | 0 | return "onion service descriptor is invalid"; |
375 | 0 | case SOCKS5Reply::TOR_HS_INTRO_FAILED: Branch (375:9): [True: 0, False: 0]
|
376 | 0 | return "onion service introduction failed"; |
377 | 0 | case SOCKS5Reply::TOR_HS_REND_FAILED: Branch (377:9): [True: 0, False: 0]
|
378 | 0 | return "onion service rendezvous failed"; |
379 | 0 | case SOCKS5Reply::TOR_HS_MISSING_CLIENT_AUTH: Branch (379:9): [True: 0, False: 0]
|
380 | 0 | return "onion service missing client authorization"; |
381 | 0 | case SOCKS5Reply::TOR_HS_WRONG_CLIENT_AUTH: Branch (381:9): [True: 0, False: 0]
|
382 | 0 | return "onion service wrong client authorization"; |
383 | 0 | case SOCKS5Reply::TOR_HS_BAD_ADDRESS: Branch (383:9): [True: 0, False: 0]
|
384 | 0 | return "onion service invalid address"; |
385 | 0 | case SOCKS5Reply::TOR_HS_INTRO_TIMEOUT: Branch (385:9): [True: 0, False: 0]
|
386 | 0 | return "onion service introduction timed out"; |
387 | 0 | default: Branch (387:9): [True: 0, False: 0]
|
388 | 0 | return strprintf("unknown (0x%02x)", err); |
389 | 0 | } |
390 | 0 | } |
391 | | |
392 | | bool Socks5(const std::string& strDest, uint16_t port, const ProxyCredentials* auth, const Sock& sock) |
393 | 0 | { |
394 | 0 | try { |
395 | 0 | IntrRecvError recvr; |
396 | 0 | LogDebug(BCLog::NET, "SOCKS5 connecting %s\n", strDest); |
397 | 0 | if (strDest.size() > 255) { Branch (397:13): [True: 0, False: 0]
|
398 | 0 | LogError("Hostname too long\n"); |
399 | 0 | return false; |
400 | 0 | } |
401 | | // Construct the version identifier/method selection message |
402 | 0 | std::vector<uint8_t> vSocks5Init; |
403 | 0 | vSocks5Init.push_back(SOCKSVersion::SOCKS5); // We want the SOCK5 protocol |
404 | 0 | if (auth) { Branch (404:13): [True: 0, False: 0]
|
405 | 0 | vSocks5Init.push_back(0x02); // 2 method identifiers follow... |
406 | 0 | vSocks5Init.push_back(SOCKS5Method::NOAUTH); |
407 | 0 | vSocks5Init.push_back(SOCKS5Method::USER_PASS); |
408 | 0 | } else { |
409 | 0 | vSocks5Init.push_back(0x01); // 1 method identifier follows... |
410 | 0 | vSocks5Init.push_back(SOCKS5Method::NOAUTH); |
411 | 0 | } |
412 | 0 | sock.SendComplete(vSocks5Init, g_socks5_recv_timeout, g_socks5_interrupt); |
413 | 0 | uint8_t pchRet1[2]; |
414 | 0 | if (InterruptibleRecv(pchRet1, 2, g_socks5_recv_timeout, sock) != IntrRecvError::OK) { Branch (414:13): [True: 0, False: 0]
|
415 | 0 | LogInfo("Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\n", strDest, port); |
416 | 0 | return false; |
417 | 0 | } |
418 | 0 | if (pchRet1[0] != SOCKSVersion::SOCKS5) { Branch (418:13): [True: 0, False: 0]
|
419 | 0 | LogError("Proxy failed to initialize\n"); |
420 | 0 | return false; |
421 | 0 | } |
422 | 0 | if (pchRet1[1] == SOCKS5Method::USER_PASS && auth) { Branch (422:13): [True: 0, False: 0]
Branch (422:54): [True: 0, False: 0]
|
423 | | // Perform username/password authentication (as described in RFC1929) |
424 | 0 | std::vector<uint8_t> vAuth; |
425 | 0 | vAuth.push_back(0x01); // Current (and only) version of user/pass subnegotiation |
426 | 0 | if (auth->username.size() > 255 || auth->password.size() > 255) { Branch (426:17): [True: 0, False: 0]
Branch (426:48): [True: 0, False: 0]
|
427 | 0 | LogError("Proxy username or password too long\n"); |
428 | 0 | return false; |
429 | 0 | } |
430 | 0 | vAuth.push_back(auth->username.size()); |
431 | 0 | vAuth.insert(vAuth.end(), auth->username.begin(), auth->username.end()); |
432 | 0 | vAuth.push_back(auth->password.size()); |
433 | 0 | vAuth.insert(vAuth.end(), auth->password.begin(), auth->password.end()); |
434 | 0 | LogDebug(BCLog::PROXY, "SOCKS5 sending username/password authentication\n"); |
435 | 0 | sock.SendComplete(vAuth, g_socks5_recv_timeout, g_socks5_interrupt); |
436 | 0 | uint8_t pchRetA[2]; |
437 | 0 | if (InterruptibleRecv(pchRetA, 2, g_socks5_recv_timeout, sock) != IntrRecvError::OK) { Branch (437:17): [True: 0, False: 0]
|
438 | 0 | LogError("Error reading proxy authentication response\n"); |
439 | 0 | return false; |
440 | 0 | } |
441 | 0 | if (pchRetA[0] != 0x01 || pchRetA[1] != 0x00) { Branch (441:17): [True: 0, False: 0]
Branch (441:39): [True: 0, False: 0]
|
442 | 0 | LogError("Proxy authentication unsuccessful\n"); |
443 | 0 | return false; |
444 | 0 | } |
445 | 0 | } else if (pchRet1[1] == SOCKS5Method::NOAUTH) { Branch (445:20): [True: 0, False: 0]
|
446 | | // Perform no authentication |
447 | 0 | } else { |
448 | 0 | LogError("Proxy requested wrong authentication method %02x\n", pchRet1[1]); |
449 | 0 | return false; |
450 | 0 | } |
451 | 0 | std::vector<uint8_t> vSocks5; |
452 | 0 | vSocks5.push_back(SOCKSVersion::SOCKS5); // VER protocol version |
453 | 0 | vSocks5.push_back(SOCKS5Command::CONNECT); // CMD CONNECT |
454 | 0 | vSocks5.push_back(0x00); // RSV Reserved must be 0 |
455 | 0 | vSocks5.push_back(SOCKS5Atyp::DOMAINNAME); // ATYP DOMAINNAME |
456 | 0 | vSocks5.push_back(strDest.size()); // Length<=255 is checked at beginning of function |
457 | 0 | vSocks5.insert(vSocks5.end(), strDest.begin(), strDest.end()); |
458 | 0 | vSocks5.push_back((port >> 8) & 0xFF); |
459 | 0 | vSocks5.push_back((port >> 0) & 0xFF); |
460 | 0 | sock.SendComplete(vSocks5, g_socks5_recv_timeout, g_socks5_interrupt); |
461 | 0 | uint8_t pchRet2[4]; |
462 | 0 | if ((recvr = InterruptibleRecv(pchRet2, 4, g_socks5_recv_timeout, sock)) != IntrRecvError::OK) { Branch (462:13): [True: 0, False: 0]
|
463 | 0 | if (recvr == IntrRecvError::Timeout) { Branch (463:17): [True: 0, False: 0]
|
464 | | /* If a timeout happens here, this effectively means we timed out while connecting |
465 | | * to the remote node. This is very common for Tor, so do not print an |
466 | | * error message. */ |
467 | 0 | return false; |
468 | 0 | } else { |
469 | 0 | LogError("Error while reading proxy response\n"); |
470 | 0 | return false; |
471 | 0 | } |
472 | 0 | } |
473 | 0 | if (pchRet2[0] != SOCKSVersion::SOCKS5) { Branch (473:13): [True: 0, False: 0]
|
474 | 0 | LogError("Proxy failed to accept request\n"); |
475 | 0 | return false; |
476 | 0 | } |
477 | 0 | if (pchRet2[1] != SOCKS5Reply::SUCCEEDED) { Branch (477:13): [True: 0, False: 0]
|
478 | | // Failures to connect to a peer that are not proxy errors |
479 | 0 | LogDebug(BCLog::NET, |
480 | 0 | "Socks5() connect to %s:%d failed: %s\n", strDest, port, Socks5ErrorString(pchRet2[1])); |
481 | 0 | return false; |
482 | 0 | } |
483 | 0 | if (pchRet2[2] != 0x00) { // Reserved field must be 0 Branch (483:13): [True: 0, False: 0]
|
484 | 0 | LogError("Error: malformed proxy response\n"); |
485 | 0 | return false; |
486 | 0 | } |
487 | 0 | uint8_t pchRet3[256]; |
488 | 0 | switch (pchRet2[3]) { |
489 | 0 | case SOCKS5Atyp::IPV4: recvr = InterruptibleRecv(pchRet3, 4, g_socks5_recv_timeout, sock); break; Branch (489:9): [True: 0, False: 0]
|
490 | 0 | case SOCKS5Atyp::IPV6: recvr = InterruptibleRecv(pchRet3, 16, g_socks5_recv_timeout, sock); break; Branch (490:9): [True: 0, False: 0]
|
491 | 0 | case SOCKS5Atyp::DOMAINNAME: { Branch (491:9): [True: 0, False: 0]
|
492 | 0 | recvr = InterruptibleRecv(pchRet3, 1, g_socks5_recv_timeout, sock); |
493 | 0 | if (recvr != IntrRecvError::OK) { Branch (493:17): [True: 0, False: 0]
|
494 | 0 | LogError("Error reading from proxy\n"); |
495 | 0 | return false; |
496 | 0 | } |
497 | 0 | int nRecv = pchRet3[0]; |
498 | 0 | recvr = InterruptibleRecv(pchRet3, nRecv, g_socks5_recv_timeout, sock); |
499 | 0 | break; |
500 | 0 | } |
501 | 0 | default: { Branch (501:9): [True: 0, False: 0]
|
502 | 0 | LogError("Error: malformed proxy response\n"); |
503 | 0 | return false; |
504 | 0 | } |
505 | 0 | } |
506 | 0 | if (recvr != IntrRecvError::OK) { Branch (506:13): [True: 0, False: 0]
|
507 | 0 | LogError("Error reading from proxy\n"); |
508 | 0 | return false; |
509 | 0 | } |
510 | 0 | if (InterruptibleRecv(pchRet3, 2, g_socks5_recv_timeout, sock) != IntrRecvError::OK) { Branch (510:13): [True: 0, False: 0]
|
511 | 0 | LogError("Error reading from proxy\n"); |
512 | 0 | return false; |
513 | 0 | } |
514 | 0 | LogDebug(BCLog::NET, "SOCKS5 connected %s\n", strDest); |
515 | 0 | return true; |
516 | 0 | } catch (const std::runtime_error& e) { |
517 | 0 | LogError("Error during SOCKS5 proxy handshake: %s\n", e.what()); |
518 | 0 | return false; |
519 | 0 | } |
520 | 0 | } |
521 | | |
522 | | std::unique_ptr<Sock> CreateSockOS(int domain, int type, int protocol) |
523 | 0 | { |
524 | | // Not IPv4, IPv6 or UNIX |
525 | 0 | if (domain == AF_UNSPEC) return nullptr; Branch (525:9): [True: 0, False: 0]
|
526 | | |
527 | | // Create a socket in the specified address family. |
528 | 0 | SOCKET hSocket = socket(domain, type, protocol); |
529 | 0 | if (hSocket == INVALID_SOCKET) { Branch (529:9): [True: 0, False: 0]
|
530 | 0 | return nullptr; |
531 | 0 | } |
532 | | |
533 | 0 | auto sock = std::make_unique<Sock>(hSocket); |
534 | |
|
535 | 0 | if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNIX) { Branch (535:9): [True: 0, False: 0]
Branch (535:30): [True: 0, False: 0]
Branch (535:52): [True: 0, False: 0]
|
536 | 0 | return sock; |
537 | 0 | } |
538 | | |
539 | | // Ensure that waiting for I/O on this socket won't result in undefined |
540 | | // behavior. |
541 | 0 | if (!sock->IsSelectable()) { Branch (541:9): [True: 0, False: 0]
|
542 | 0 | LogInfo("Cannot create connection: non-selectable socket created (fd >= FD_SETSIZE ?)\n"); |
543 | 0 | return nullptr; |
544 | 0 | } |
545 | | |
546 | | #ifdef SO_NOSIGPIPE |
547 | | int set = 1; |
548 | | // Set the no-sigpipe option on the socket for BSD systems, other UNIXes |
549 | | // should use the MSG_NOSIGNAL flag for every send. |
550 | | if (sock->SetSockOpt(SOL_SOCKET, SO_NOSIGPIPE, &set, sizeof(int)) == SOCKET_ERROR) { |
551 | | LogInfo("Error setting SO_NOSIGPIPE on socket: %s, continuing anyway\n", |
552 | | NetworkErrorString(WSAGetLastError())); |
553 | | } |
554 | | #endif |
555 | | |
556 | | // Set the non-blocking option on the socket. |
557 | 0 | if (!sock->SetNonBlocking()) { Branch (557:9): [True: 0, False: 0]
|
558 | 0 | LogInfo("Error setting socket to non-blocking: %s\n", NetworkErrorString(WSAGetLastError())); |
559 | 0 | return nullptr; |
560 | 0 | } |
561 | | |
562 | 0 | #ifdef HAVE_SOCKADDR_UN |
563 | 0 | if (domain == AF_UNIX) return sock; Branch (563:9): [True: 0, False: 0]
|
564 | 0 | #endif |
565 | | |
566 | 0 | if (protocol == IPPROTO_TCP) { Branch (566:9): [True: 0, False: 0]
|
567 | | // Set the no-delay option (disable Nagle's algorithm) on the TCP socket. |
568 | 0 | const int on{1}; |
569 | 0 | if (sock->SetSockOpt(IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) == SOCKET_ERROR) { Branch (569:13): [True: 0, False: 0]
|
570 | 0 | LogDebug(BCLog::NET, "Unable to set TCP_NODELAY on a newly created socket, continuing anyway\n"); |
571 | 0 | } |
572 | 0 | } |
573 | |
|
574 | 0 | return sock; |
575 | 0 | } |
576 | | |
577 | | std::function<std::unique_ptr<Sock>(int, int, int)> CreateSock = CreateSockOS; |
578 | | |
579 | | template<typename... Args> |
580 | | static void LogConnectFailure(bool manual_connection, util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args) |
581 | 0 | { |
582 | 0 | std::string error_message = tfm::format(fmt, args...); |
583 | 0 | if (manual_connection) { Branch (583:9): [True: 0, False: 0]
|
584 | 0 | LogInfo("%s\n", error_message); |
585 | 0 | } else { |
586 | 0 | LogDebug(BCLog::NET, "%s\n", error_message); |
587 | 0 | } |
588 | 0 | } |
589 | | |
590 | | static bool ConnectToSocket(const Sock& sock, |
591 | | struct sockaddr* sockaddr, |
592 | | socklen_t len, |
593 | | const std::string& dest_str, |
594 | | bool manual_connection, |
595 | | std::chrono::milliseconds timeout) |
596 | 0 | { |
597 | | // Connect to `sockaddr` using `sock`. |
598 | 0 | if (sock.Connect(sockaddr, len) == SOCKET_ERROR) { Branch (598:9): [True: 0, False: 0]
|
599 | 0 | int nErr = WSAGetLastError(); |
600 | | // WSAEINVAL is here because some legacy version of winsock uses it |
601 | 0 | if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) Branch (601:13): [True: 0, False: 0]
Branch (601:39): [True: 0, False: 0]
Branch (601:65): [True: 0, False: 0]
|
602 | 0 | { |
603 | | // Connection didn't actually fail, but is being established |
604 | | // asynchronously. Thus, use async I/O api (select/poll) |
605 | | // synchronously to check for successful connection with a timeout. |
606 | 0 | const Sock::Event requested = Sock::RECV | Sock::SEND; |
607 | 0 | Sock::Event occurred; |
608 | 0 | if (!sock.Wait(timeout, requested, &occurred)) { Branch (608:17): [True: 0, False: 0]
|
609 | 0 | LogInfo("wait for connect to %s failed: %s\n", |
610 | 0 | dest_str, |
611 | 0 | NetworkErrorString(WSAGetLastError())); |
612 | 0 | return false; |
613 | 0 | } else if (occurred == 0) { Branch (613:24): [True: 0, False: 0]
|
614 | 0 | LogDebug(BCLog::NET, "connection attempt to %s timed out\n", dest_str); |
615 | 0 | return false; |
616 | 0 | } |
617 | | |
618 | | // Even if the wait was successful, the connect might not |
619 | | // have been successful. The reason for this failure is hidden away |
620 | | // in the SO_ERROR for the socket in modern systems. We read it into |
621 | | // sockerr here. |
622 | 0 | int sockerr; |
623 | 0 | socklen_t sockerr_len = sizeof(sockerr); |
624 | 0 | if (sock.GetSockOpt(SOL_SOCKET, SO_ERROR, &sockerr, &sockerr_len) == Branch (624:17): [True: 0, False: 0]
|
625 | 0 | SOCKET_ERROR) { |
626 | 0 | LogInfo("getsockopt() for %s failed: %s\n", dest_str, NetworkErrorString(WSAGetLastError())); |
627 | 0 | return false; |
628 | 0 | } |
629 | 0 | if (sockerr != 0) { Branch (629:17): [True: 0, False: 0]
|
630 | 0 | LogConnectFailure(manual_connection, |
631 | 0 | "connect() to %s failed after wait: %s", |
632 | 0 | dest_str, |
633 | 0 | NetworkErrorString(sockerr)); |
634 | 0 | return false; |
635 | 0 | } |
636 | 0 | } |
637 | | #ifdef WIN32 |
638 | | else if (WSAGetLastError() != WSAEISCONN) |
639 | | #else |
640 | 0 | else |
641 | 0 | #endif |
642 | 0 | { |
643 | 0 | LogConnectFailure(manual_connection, "connect() to %s failed: %s", dest_str, NetworkErrorString(WSAGetLastError())); |
644 | 0 | return false; |
645 | 0 | } |
646 | 0 | } |
647 | 0 | return true; |
648 | 0 | } |
649 | | |
650 | | std::unique_ptr<Sock> ConnectDirectly(const CService& dest, bool manual_connection) |
651 | 0 | { |
652 | 0 | return ConnectDirectly(dest, manual_connection, std::chrono::milliseconds{nConnectTimeout}); |
653 | 0 | } |
654 | | |
655 | | std::unique_ptr<Sock> ConnectDirectly(const CService& dest, |
656 | | bool manual_connection, |
657 | | std::chrono::milliseconds timeout) |
658 | 0 | { |
659 | 0 | auto sock = CreateSock(dest.GetSAFamily(), SOCK_STREAM, IPPROTO_TCP); |
660 | 0 | if (!sock) { Branch (660:9): [True: 0, False: 0]
|
661 | 0 | LogError("Cannot create a socket for connecting to %s\n", dest.ToStringAddrPort()); |
662 | 0 | return {}; |
663 | 0 | } |
664 | | |
665 | | // Create a sockaddr from the specified service. |
666 | 0 | struct sockaddr_storage sockaddr; |
667 | 0 | socklen_t len = sizeof(sockaddr); |
668 | 0 | if (!dest.GetSockAddr((struct sockaddr*)&sockaddr, &len)) { Branch (668:9): [True: 0, False: 0]
|
669 | 0 | LogInfo("Cannot get sockaddr for %s: unsupported network\n", dest.ToStringAddrPort()); |
670 | 0 | return {}; |
671 | 0 | } |
672 | | |
673 | 0 | if (!ConnectToSocket(*sock, (struct sockaddr*)&sockaddr, len, dest.ToStringAddrPort(), manual_connection, timeout)) { Branch (673:9): [True: 0, False: 0]
|
674 | 0 | return {}; |
675 | 0 | } |
676 | | |
677 | 0 | return sock; |
678 | 0 | } |
679 | | |
680 | | std::unique_ptr<Sock> Proxy::Connect() const |
681 | 0 | { |
682 | 0 | if (!IsValid()) return {}; Branch (682:9): [True: 0, False: 0]
|
683 | | |
684 | 0 | if (!m_is_unix_socket) return ConnectDirectly(proxy, /*manual_connection=*/true); Branch (684:9): [True: 0, False: 0]
|
685 | | |
686 | 0 | #ifdef HAVE_SOCKADDR_UN |
687 | 0 | auto sock = CreateSock(AF_UNIX, SOCK_STREAM, 0); |
688 | 0 | if (!sock) { Branch (688:9): [True: 0, False: 0]
|
689 | 0 | LogError("Cannot create a socket for connecting to %s\n", m_unix_socket_path); |
690 | 0 | return {}; |
691 | 0 | } |
692 | | |
693 | 0 | const std::string path{m_unix_socket_path.substr(ADDR_PREFIX_UNIX.length())}; |
694 | |
|
695 | 0 | struct sockaddr_un addrun; |
696 | 0 | memset(&addrun, 0, sizeof(addrun)); |
697 | 0 | addrun.sun_family = AF_UNIX; |
698 | | // leave the last char in addrun.sun_path[] to be always '\0' |
699 | 0 | memcpy(addrun.sun_path, path.c_str(), std::min(sizeof(addrun.sun_path) - 1, path.length())); |
700 | 0 | socklen_t len = sizeof(addrun); |
701 | |
|
702 | 0 | if (!ConnectToSocket(*sock, Branch (702:9): [True: 0, False: 0]
|
703 | 0 | (struct sockaddr*)&addrun, |
704 | 0 | len, |
705 | 0 | path, |
706 | 0 | /*manual_connection=*/true, |
707 | 0 | std::chrono::milliseconds{nConnectTimeout})) { |
708 | 0 | return {}; |
709 | 0 | } |
710 | | |
711 | 0 | return sock; |
712 | | #else |
713 | | return {}; |
714 | | #endif |
715 | 0 | } |
716 | | |
717 | 0 | bool SetProxy(enum Network net, const Proxy &addrProxy) { |
718 | 0 | assert(net >= 0 && net < NET_MAX); Branch (718:5): [True: 0, False: 0]
Branch (718:5): [True: 0, False: 0]
Branch (718:5): [True: 0, False: 0]
|
719 | 0 | if (!addrProxy.IsValid()) Branch (719:9): [True: 0, False: 0]
|
720 | 0 | return false; |
721 | 0 | LOCK(g_proxyinfo_mutex); |
722 | 0 | proxyInfo[net] = addrProxy; |
723 | 0 | return true; |
724 | 0 | } |
725 | | |
726 | | std::optional<Proxy> GetProxy(enum Network net) |
727 | 0 | { |
728 | 0 | assert(net >= 0 && net < NET_MAX); Branch (728:5): [True: 0, False: 0]
Branch (728:5): [True: 0, False: 0]
Branch (728:5): [True: 0, False: 0]
|
729 | 0 | LOCK(g_proxyinfo_mutex); |
730 | 0 | if (!proxyInfo[net].IsValid()) { Branch (730:9): [True: 0, False: 0]
|
731 | 0 | return std::nullopt; |
732 | 0 | } |
733 | 0 | return proxyInfo[net]; |
734 | 0 | } |
735 | | |
736 | 0 | bool SetNameProxy(const Proxy &addrProxy) { |
737 | 0 | if (!addrProxy.IsValid()) Branch (737:9): [True: 0, False: 0]
|
738 | 0 | return false; |
739 | 0 | LOCK(g_proxyinfo_mutex); |
740 | 0 | nameProxy = addrProxy; |
741 | 0 | return true; |
742 | 0 | } |
743 | | |
744 | | std::optional<Proxy> GetNameProxy() |
745 | 0 | { |
746 | 0 | LOCK(g_proxyinfo_mutex); |
747 | 0 | if (!nameProxy.IsValid()) { Branch (747:9): [True: 0, False: 0]
|
748 | 0 | return std::nullopt; |
749 | 0 | } |
750 | 0 | return nameProxy; |
751 | 0 | } |
752 | | |
753 | 0 | bool HaveNameProxy() { |
754 | 0 | LOCK(g_proxyinfo_mutex); |
755 | 0 | return nameProxy.IsValid(); |
756 | 0 | } |
757 | | |
758 | 0 | bool IsProxy(const CNetAddr &addr) { |
759 | 0 | LOCK(g_proxyinfo_mutex); |
760 | 0 | for (int i = 0; i < NET_MAX; i++) { Branch (760:21): [True: 0, False: 0]
|
761 | 0 | if (addr == static_cast<CNetAddr>(proxyInfo[i].proxy)) Branch (761:13): [True: 0, False: 0]
|
762 | 0 | return true; |
763 | 0 | } |
764 | 0 | return false; |
765 | 0 | } |
766 | | |
767 | | /** |
768 | | * Generate unique credentials for Tor stream isolation. Tor will create |
769 | | * separate circuits for SOCKS5 proxy connections with different credentials, which |
770 | | * makes it harder to correlate the connections. |
771 | | */ |
772 | | class TorStreamIsolationCredentialsGenerator |
773 | | { |
774 | | public: |
775 | | TorStreamIsolationCredentialsGenerator(): |
776 | 0 | m_prefix(GenerateUniquePrefix()) { |
777 | 0 | } |
778 | | |
779 | | /** Return the next unique proxy credentials. */ |
780 | 0 | ProxyCredentials Generate() { |
781 | 0 | ProxyCredentials auth; |
782 | 0 | auth.username = auth.password = strprintf("%s%i", m_prefix, m_counter); |
783 | 0 | ++m_counter; |
784 | 0 | return auth; |
785 | 0 | } |
786 | | |
787 | | /** Size of session prefix in bytes. */ |
788 | | static constexpr size_t PREFIX_BYTE_LENGTH = 8; |
789 | | private: |
790 | | const std::string m_prefix; |
791 | | std::atomic<uint64_t> m_counter; |
792 | | |
793 | | /** Generate a random prefix for each of the credentials returned by this generator. |
794 | | * This makes sure that different launches of the application (either successively or in parallel) |
795 | | * will not share the same circuits, as would be the case with a bare counter. |
796 | | */ |
797 | 0 | static std::string GenerateUniquePrefix() { |
798 | 0 | std::array<uint8_t, PREFIX_BYTE_LENGTH> prefix_bytes; |
799 | 0 | GetRandBytes(prefix_bytes); |
800 | 0 | return HexStr(prefix_bytes) + "-"; |
801 | 0 | } |
802 | | }; |
803 | | |
804 | | std::unique_ptr<Sock> ConnectThroughProxy(const Proxy& proxy, |
805 | | const std::string& dest, |
806 | | uint16_t port, |
807 | | bool& proxy_connection_failed) |
808 | 0 | { |
809 | | // first connect to proxy server |
810 | 0 | auto sock = proxy.Connect(); |
811 | 0 | if (!sock) { Branch (811:9): [True: 0, False: 0]
|
812 | 0 | proxy_connection_failed = true; |
813 | 0 | return {}; |
814 | 0 | } |
815 | | |
816 | | // do socks negotiation |
817 | 0 | if (proxy.m_tor_stream_isolation) { Branch (817:9): [True: 0, False: 0]
|
818 | 0 | static TorStreamIsolationCredentialsGenerator generator; |
819 | 0 | ProxyCredentials random_auth{generator.Generate()}; |
820 | 0 | if (!Socks5(dest, port, &random_auth, *sock)) { Branch (820:13): [True: 0, False: 0]
|
821 | 0 | return {}; |
822 | 0 | } |
823 | 0 | } else { |
824 | 0 | if (!Socks5(dest, port, nullptr, *sock)) { Branch (824:13): [True: 0, False: 0]
|
825 | 0 | return {}; |
826 | 0 | } |
827 | 0 | } |
828 | 0 | return sock; |
829 | 0 | } |
830 | | |
831 | | CSubNet LookupSubNet(const std::string& subnet_str) |
832 | 0 | { |
833 | 0 | CSubNet subnet; |
834 | 0 | assert(!subnet.IsValid()); Branch (834:5): [True: 0, False: 0]
|
835 | 0 | if (!ContainsNoNUL(subnet_str)) { Branch (835:9): [True: 0, False: 0]
|
836 | 0 | return subnet; |
837 | 0 | } |
838 | | |
839 | 0 | const size_t slash_pos{subnet_str.find_last_of('/')}; |
840 | 0 | const std::string str_addr{subnet_str.substr(0, slash_pos)}; |
841 | 0 | std::optional<CNetAddr> addr{LookupHost(str_addr, /*fAllowLookup=*/false)}; |
842 | |
|
843 | 0 | if (addr.has_value()) { Branch (843:9): [True: 0, False: 0]
|
844 | 0 | addr = static_cast<CNetAddr>(MaybeFlipIPv6toCJDNS(CService{addr.value(), /*port=*/0})); |
845 | 0 | if (slash_pos != subnet_str.npos) { Branch (845:13): [True: 0, False: 0]
|
846 | 0 | const std::string netmask_str{subnet_str.substr(slash_pos + 1)}; |
847 | 0 | if (const auto netmask{ToIntegral<uint8_t>(netmask_str)}) { Branch (847:28): [True: 0, False: 0]
|
848 | | // Valid number; assume CIDR variable-length subnet masking. |
849 | 0 | subnet = CSubNet{addr.value(), *netmask}; |
850 | 0 | } else { |
851 | | // Invalid number; try full netmask syntax. Never allow lookup for netmask. |
852 | 0 | const std::optional<CNetAddr> full_netmask{LookupHost(netmask_str, /*fAllowLookup=*/false)}; |
853 | 0 | if (full_netmask.has_value()) { Branch (853:21): [True: 0, False: 0]
|
854 | 0 | subnet = CSubNet{addr.value(), full_netmask.value()}; |
855 | 0 | } |
856 | 0 | } |
857 | 0 | } else { |
858 | | // Single IP subnet (<ipv4>/32 or <ipv6>/128). |
859 | 0 | subnet = CSubNet{addr.value()}; |
860 | 0 | } |
861 | 0 | } |
862 | |
|
863 | 0 | return subnet; |
864 | 0 | } |
865 | | |
866 | | bool IsBadPort(uint16_t port) |
867 | 0 | { |
868 | | /* Don't forget to update doc/p2p-bad-ports.md if you change this list. */ |
869 | |
|
870 | 0 | switch (port) { Branch (870:13): [True: 0, False: 0]
|
871 | 0 | case 1: // tcpmux Branch (871:5): [True: 0, False: 0]
|
872 | 0 | case 7: // echo Branch (872:5): [True: 0, False: 0]
|
873 | 0 | case 9: // discard Branch (873:5): [True: 0, False: 0]
|
874 | 0 | case 11: // systat Branch (874:5): [True: 0, False: 0]
|
875 | 0 | case 13: // daytime Branch (875:5): [True: 0, False: 0]
|
876 | 0 | case 15: // netstat Branch (876:5): [True: 0, False: 0]
|
877 | 0 | case 17: // qotd Branch (877:5): [True: 0, False: 0]
|
878 | 0 | case 19: // chargen Branch (878:5): [True: 0, False: 0]
|
879 | 0 | case 20: // ftp data Branch (879:5): [True: 0, False: 0]
|
880 | 0 | case 21: // ftp access Branch (880:5): [True: 0, False: 0]
|
881 | 0 | case 22: // ssh Branch (881:5): [True: 0, False: 0]
|
882 | 0 | case 23: // telnet Branch (882:5): [True: 0, False: 0]
|
883 | 0 | case 25: // smtp Branch (883:5): [True: 0, False: 0]
|
884 | 0 | case 37: // time Branch (884:5): [True: 0, False: 0]
|
885 | 0 | case 42: // name Branch (885:5): [True: 0, False: 0]
|
886 | 0 | case 43: // nicname Branch (886:5): [True: 0, False: 0]
|
887 | 0 | case 53: // domain Branch (887:5): [True: 0, False: 0]
|
888 | 0 | case 69: // tftp Branch (888:5): [True: 0, False: 0]
|
889 | 0 | case 77: // priv-rjs Branch (889:5): [True: 0, False: 0]
|
890 | 0 | case 79: // finger Branch (890:5): [True: 0, False: 0]
|
891 | 0 | case 87: // ttylink Branch (891:5): [True: 0, False: 0]
|
892 | 0 | case 95: // supdup Branch (892:5): [True: 0, False: 0]
|
893 | 0 | case 101: // hostname Branch (893:5): [True: 0, False: 0]
|
894 | 0 | case 102: // iso-tsap Branch (894:5): [True: 0, False: 0]
|
895 | 0 | case 103: // gppitnp Branch (895:5): [True: 0, False: 0]
|
896 | 0 | case 104: // acr-nema Branch (896:5): [True: 0, False: 0]
|
897 | 0 | case 109: // pop2 Branch (897:5): [True: 0, False: 0]
|
898 | 0 | case 110: // pop3 Branch (898:5): [True: 0, False: 0]
|
899 | 0 | case 111: // sunrpc Branch (899:5): [True: 0, False: 0]
|
900 | 0 | case 113: // auth Branch (900:5): [True: 0, False: 0]
|
901 | 0 | case 115: // sftp Branch (901:5): [True: 0, False: 0]
|
902 | 0 | case 117: // uucp-path Branch (902:5): [True: 0, False: 0]
|
903 | 0 | case 119: // nntp Branch (903:5): [True: 0, False: 0]
|
904 | 0 | case 123: // NTP Branch (904:5): [True: 0, False: 0]
|
905 | 0 | case 135: // loc-srv /epmap Branch (905:5): [True: 0, False: 0]
|
906 | 0 | case 137: // netbios Branch (906:5): [True: 0, False: 0]
|
907 | 0 | case 139: // netbios Branch (907:5): [True: 0, False: 0]
|
908 | 0 | case 143: // imap2 Branch (908:5): [True: 0, False: 0]
|
909 | 0 | case 161: // snmp Branch (909:5): [True: 0, False: 0]
|
910 | 0 | case 179: // BGP Branch (910:5): [True: 0, False: 0]
|
911 | 0 | case 389: // ldap Branch (911:5): [True: 0, False: 0]
|
912 | 0 | case 427: // SLP (Also used by Apple Filing Protocol) Branch (912:5): [True: 0, False: 0]
|
913 | 0 | case 465: // smtp+ssl Branch (913:5): [True: 0, False: 0]
|
914 | 0 | case 512: // print / exec Branch (914:5): [True: 0, False: 0]
|
915 | 0 | case 513: // login Branch (915:5): [True: 0, False: 0]
|
916 | 0 | case 514: // shell Branch (916:5): [True: 0, False: 0]
|
917 | 0 | case 515: // printer Branch (917:5): [True: 0, False: 0]
|
918 | 0 | case 526: // tempo Branch (918:5): [True: 0, False: 0]
|
919 | 0 | case 530: // courier Branch (919:5): [True: 0, False: 0]
|
920 | 0 | case 531: // chat Branch (920:5): [True: 0, False: 0]
|
921 | 0 | case 532: // netnews Branch (921:5): [True: 0, False: 0]
|
922 | 0 | case 540: // uucp Branch (922:5): [True: 0, False: 0]
|
923 | 0 | case 548: // AFP (Apple Filing Protocol) Branch (923:5): [True: 0, False: 0]
|
924 | 0 | case 554: // rtsp Branch (924:5): [True: 0, False: 0]
|
925 | 0 | case 556: // remotefs Branch (925:5): [True: 0, False: 0]
|
926 | 0 | case 563: // nntp+ssl Branch (926:5): [True: 0, False: 0]
|
927 | 0 | case 587: // smtp (rfc6409) Branch (927:5): [True: 0, False: 0]
|
928 | 0 | case 601: // syslog-conn (rfc3195) Branch (928:5): [True: 0, False: 0]
|
929 | 0 | case 636: // ldap+ssl Branch (929:5): [True: 0, False: 0]
|
930 | 0 | case 989: // ftps-data Branch (930:5): [True: 0, False: 0]
|
931 | 0 | case 990: // ftps Branch (931:5): [True: 0, False: 0]
|
932 | 0 | case 993: // ldap+ssl Branch (932:5): [True: 0, False: 0]
|
933 | 0 | case 995: // pop3+ssl Branch (933:5): [True: 0, False: 0]
|
934 | 0 | case 1719: // h323gatestat Branch (934:5): [True: 0, False: 0]
|
935 | 0 | case 1720: // h323hostcall Branch (935:5): [True: 0, False: 0]
|
936 | 0 | case 1723: // pptp Branch (936:5): [True: 0, False: 0]
|
937 | 0 | case 2049: // nfs Branch (937:5): [True: 0, False: 0]
|
938 | 0 | case 3306: // MySQL Branch (938:5): [True: 0, False: 0]
|
939 | 0 | case 3389: // RDP / Windows Remote Desktop Branch (939:5): [True: 0, False: 0]
|
940 | 0 | case 3659: // apple-sasl / PasswordServer Branch (940:5): [True: 0, False: 0]
|
941 | 0 | case 4045: // lockd Branch (941:5): [True: 0, False: 0]
|
942 | 0 | case 5060: // sip Branch (942:5): [True: 0, False: 0]
|
943 | 0 | case 5061: // sips Branch (943:5): [True: 0, False: 0]
|
944 | 0 | case 5432: // PostgreSQL Branch (944:5): [True: 0, False: 0]
|
945 | 0 | case 5900: // VNC Branch (945:5): [True: 0, False: 0]
|
946 | 0 | case 6000: // X11 Branch (946:5): [True: 0, False: 0]
|
947 | 0 | case 6566: // sane-port Branch (947:5): [True: 0, False: 0]
|
948 | 0 | case 6665: // Alternate IRC Branch (948:5): [True: 0, False: 0]
|
949 | 0 | case 6666: // Alternate IRC Branch (949:5): [True: 0, False: 0]
|
950 | 0 | case 6667: // Standard IRC Branch (950:5): [True: 0, False: 0]
|
951 | 0 | case 6668: // Alternate IRC Branch (951:5): [True: 0, False: 0]
|
952 | 0 | case 6669: // Alternate IRC Branch (952:5): [True: 0, False: 0]
|
953 | 0 | case 6697: // IRC + TLS Branch (953:5): [True: 0, False: 0]
|
954 | 0 | case 10080: // Amanda Branch (954:5): [True: 0, False: 0]
|
955 | 0 | case 27017: // MongoDB Branch (955:5): [True: 0, False: 0]
|
956 | 0 | return true; |
957 | 0 | } |
958 | 0 | return false; |
959 | 0 | } |
960 | | |
961 | | CService MaybeFlipIPv6toCJDNS(const CService& service) |
962 | 0 | { |
963 | 0 | CService ret{service}; |
964 | 0 | if (ret.IsIPv6() && ret.HasCJDNSPrefix() && g_reachable_nets.Contains(NET_CJDNS)) { Branch (964:9): [True: 0, False: 0]
Branch (964:25): [True: 0, False: 0]
Branch (964:49): [True: 0, False: 0]
|
965 | 0 | ret.m_net = NET_CJDNS; |
966 | 0 | } |
967 | 0 | return ret; |
968 | 0 | } |
969 | | |
970 | | CService GetBindAddress(const Sock& sock) |
971 | 0 | { |
972 | 0 | CService addr_bind; |
973 | 0 | sockaddr_storage storage; |
974 | 0 | socklen_t len = sizeof(storage); |
975 | |
|
976 | 0 | auto sa = reinterpret_cast<sockaddr*>(&storage); |
977 | |
|
978 | 0 | if (sock.GetSockName(sa, &len) == 0) { Branch (978:9): [True: 0, False: 0]
|
979 | 0 | addr_bind.SetSockAddr(sa, len); |
980 | 0 | } else { |
981 | 0 | LogWarning("getsockname failed\n"); |
982 | 0 | } |
983 | 0 | return addr_bind; |
984 | 0 | } |