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