Line data Source code
1 : // Copyright (c) 2011-2021 The Bitcoin Core developers
2 : // Distributed under the MIT software license, see the accompanying
3 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 :
5 : #if defined(HAVE_CONFIG_H)
6 : #include <config/bitcoin-config.h>
7 : #endif
8 :
9 : #include <mapport.h>
10 :
11 : #include <clientversion.h>
12 : #include <logging.h>
13 : #include <net.h>
14 : #include <netaddress.h>
15 : #include <netbase.h>
16 : #include <util/system.h>
17 : #include <util/thread.h>
18 : #include <util/threadinterrupt.h>
19 :
20 : #ifdef USE_NATPMP
21 : #include <compat/compat.h>
22 : #include <natpmp.h>
23 : #endif // USE_NATPMP
24 :
25 : #ifdef USE_UPNP
26 : #include <miniupnpc/miniupnpc.h>
27 : #include <miniupnpc/upnpcommands.h>
28 : #include <miniupnpc/upnperrors.h>
29 : // The minimum supported miniUPnPc API version is set to 17. This excludes
30 : // versions with known vulnerabilities.
31 : static_assert(MINIUPNPC_API_VERSION >= 17, "miniUPnPc API version >= 17 assumed");
32 : #endif // USE_UPNP
33 :
34 : #include <atomic>
35 : #include <cassert>
36 : #include <chrono>
37 : #include <functional>
38 : #include <string>
39 : #include <thread>
40 :
41 : #if defined(USE_NATPMP) || defined(USE_UPNP)
42 : static CThreadInterrupt g_mapport_interrupt;
43 : static std::thread g_mapport_thread;
44 : static std::atomic_uint g_mapport_enabled_protos{MapPortProtoFlag::NONE};
45 : static std::atomic<MapPortProtoFlag> g_mapport_current_proto{MapPortProtoFlag::NONE};
46 :
47 : using namespace std::chrono_literals;
48 : static constexpr auto PORT_MAPPING_REANNOUNCE_PERIOD{20min};
49 : static constexpr auto PORT_MAPPING_RETRY_PERIOD{5min};
50 :
51 : #ifdef USE_NATPMP
52 : static uint16_t g_mapport_external_port = 0;
53 : static bool NatpmpInit(natpmp_t* natpmp)
54 : {
55 : const int r_init = initnatpmp(natpmp, /* detect gateway automatically */ 0, /* forced gateway - NOT APPLIED*/ 0);
56 : if (r_init == 0) return true;
57 : LogPrintf("natpmp: initnatpmp() failed with %d error.\n", r_init);
58 : return false;
59 : }
60 :
61 : static bool NatpmpDiscover(natpmp_t* natpmp, struct in_addr& external_ipv4_addr)
62 : {
63 : const int r_send = sendpublicaddressrequest(natpmp);
64 : if (r_send == 2 /* OK */) {
65 : int r_read;
66 : natpmpresp_t response;
67 : do {
68 : r_read = readnatpmpresponseorretry(natpmp, &response);
69 : } while (r_read == NATPMP_TRYAGAIN);
70 :
71 : if (r_read == 0) {
72 : external_ipv4_addr = response.pnu.publicaddress.addr;
73 : return true;
74 : } else if (r_read == NATPMP_ERR_NOGATEWAYSUPPORT) {
75 : LogPrintf("natpmp: The gateway does not support NAT-PMP.\n");
76 : } else {
77 : LogPrintf("natpmp: readnatpmpresponseorretry() for public address failed with %d error.\n", r_read);
78 : }
79 : } else {
80 : LogPrintf("natpmp: sendpublicaddressrequest() failed with %d error.\n", r_send);
81 : }
82 :
83 : return false;
84 : }
85 :
86 : static bool NatpmpMapping(natpmp_t* natpmp, const struct in_addr& external_ipv4_addr, uint16_t private_port, bool& external_ip_discovered)
87 : {
88 : const uint16_t suggested_external_port = g_mapport_external_port ? g_mapport_external_port : private_port;
89 : const int r_send = sendnewportmappingrequest(natpmp, NATPMP_PROTOCOL_TCP, private_port, suggested_external_port, 3600 /*seconds*/);
90 : if (r_send == 12 /* OK */) {
91 : int r_read;
92 : natpmpresp_t response;
93 : do {
94 : r_read = readnatpmpresponseorretry(natpmp, &response);
95 : } while (r_read == NATPMP_TRYAGAIN);
96 :
97 : if (r_read == 0) {
98 : auto pm = response.pnu.newportmapping;
99 : if (private_port == pm.privateport && pm.lifetime > 0) {
100 : g_mapport_external_port = pm.mappedpublicport;
101 : const CService external{external_ipv4_addr, pm.mappedpublicport};
102 : if (!external_ip_discovered && fDiscover) {
103 : AddLocal(external, LOCAL_MAPPED);
104 : external_ip_discovered = true;
105 : }
106 : LogPrintf("natpmp: Port mapping successful. External address = %s\n", external.ToStringAddrPort());
107 : return true;
108 : } else {
109 : LogPrintf("natpmp: Port mapping failed.\n");
110 : }
111 : } else if (r_read == NATPMP_ERR_NOGATEWAYSUPPORT) {
112 : LogPrintf("natpmp: The gateway does not support NAT-PMP.\n");
113 : } else {
114 : LogPrintf("natpmp: readnatpmpresponseorretry() for port mapping failed with %d error.\n", r_read);
115 : }
116 : } else {
117 : LogPrintf("natpmp: sendnewportmappingrequest() failed with %d error.\n", r_send);
118 : }
119 :
120 : return false;
121 : }
122 :
123 : static bool ProcessNatpmp()
124 : {
125 : bool ret = false;
126 : natpmp_t natpmp;
127 : struct in_addr external_ipv4_addr;
128 : if (NatpmpInit(&natpmp) && NatpmpDiscover(&natpmp, external_ipv4_addr)) {
129 : bool external_ip_discovered = false;
130 : const uint16_t private_port = GetListenPort();
131 : do {
132 : ret = NatpmpMapping(&natpmp, external_ipv4_addr, private_port, external_ip_discovered);
133 : } while (ret && g_mapport_interrupt.sleep_for(PORT_MAPPING_REANNOUNCE_PERIOD));
134 : g_mapport_interrupt.reset();
135 :
136 : const int r_send = sendnewportmappingrequest(&natpmp, NATPMP_PROTOCOL_TCP, private_port, g_mapport_external_port, /* remove a port mapping */ 0);
137 : g_mapport_external_port = 0;
138 : if (r_send == 12 /* OK */) {
139 : LogPrintf("natpmp: Port mapping removed successfully.\n");
140 : } else {
141 : LogPrintf("natpmp: sendnewportmappingrequest(0) failed with %d error.\n", r_send);
142 : }
143 : }
144 :
145 : closenatpmp(&natpmp);
146 : return ret;
147 : }
148 : #endif // USE_NATPMP
149 :
150 : #ifdef USE_UPNP
151 : static bool ProcessUpnp()
152 : {
153 : bool ret = false;
154 : std::string port = strprintf("%u", GetListenPort());
155 : const char * multicastif = nullptr;
156 : const char * minissdpdpath = nullptr;
157 : struct UPNPDev * devlist = nullptr;
158 : char lanaddr[64];
159 :
160 : int error = 0;
161 : devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, 2, &error);
162 :
163 : struct UPNPUrls urls;
164 : struct IGDdatas data;
165 : int r;
166 : #if MINIUPNPC_API_VERSION <= 17
167 : r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr));
168 : #else
169 : r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr), nullptr, 0);
170 : #endif
171 : if (r == 1)
172 : {
173 : if (fDiscover) {
174 : char externalIPAddress[40];
175 : r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress);
176 : if (r != UPNPCOMMAND_SUCCESS) {
177 : LogPrintf("UPnP: GetExternalIPAddress() returned %d\n", r);
178 : } else {
179 : if (externalIPAddress[0]) {
180 : std::optional<CNetAddr> resolved{LookupHost(externalIPAddress, false)};
181 : if (resolved.has_value()) {
182 : LogPrintf("UPnP: ExternalIPAddress = %s\n", resolved->ToStringAddr());
183 : AddLocal(resolved.value(), LOCAL_MAPPED);
184 : }
185 : } else {
186 : LogPrintf("UPnP: GetExternalIPAddress failed.\n");
187 : }
188 : }
189 : }
190 :
191 : std::string strDesc = PACKAGE_NAME " " + FormatFullVersion();
192 :
193 : do {
194 : r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", nullptr, "0");
195 :
196 : if (r != UPNPCOMMAND_SUCCESS) {
197 : ret = false;
198 : LogPrintf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", port, port, lanaddr, r, strupnperror(r));
199 : break;
200 : } else {
201 : ret = true;
202 : LogPrintf("UPnP Port Mapping successful.\n");
203 : }
204 : } while (g_mapport_interrupt.sleep_for(PORT_MAPPING_REANNOUNCE_PERIOD));
205 : g_mapport_interrupt.reset();
206 :
207 : r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port.c_str(), "TCP", nullptr);
208 : LogPrintf("UPNP_DeletePortMapping() returned: %d\n", r);
209 : freeUPNPDevlist(devlist); devlist = nullptr;
210 : FreeUPNPUrls(&urls);
211 : } else {
212 : LogPrintf("No valid UPnP IGDs found\n");
213 : freeUPNPDevlist(devlist); devlist = nullptr;
214 : if (r != 0)
215 : FreeUPNPUrls(&urls);
216 : }
217 :
218 : return ret;
219 : }
220 : #endif // USE_UPNP
221 :
222 : static void ThreadMapPort()
223 : {
224 : bool ok;
225 : do {
226 : ok = false;
227 :
228 : #ifdef USE_UPNP
229 : // High priority protocol.
230 : if (g_mapport_enabled_protos & MapPortProtoFlag::UPNP) {
231 : g_mapport_current_proto = MapPortProtoFlag::UPNP;
232 : ok = ProcessUpnp();
233 : if (ok) continue;
234 : }
235 : #endif // USE_UPNP
236 :
237 : #ifdef USE_NATPMP
238 : // Low priority protocol.
239 : if (g_mapport_enabled_protos & MapPortProtoFlag::NAT_PMP) {
240 : g_mapport_current_proto = MapPortProtoFlag::NAT_PMP;
241 : ok = ProcessNatpmp();
242 : if (ok) continue;
243 : }
244 : #endif // USE_NATPMP
245 :
246 : g_mapport_current_proto = MapPortProtoFlag::NONE;
247 : if (g_mapport_enabled_protos == MapPortProtoFlag::NONE) {
248 : return;
249 : }
250 :
251 : } while (ok || g_mapport_interrupt.sleep_for(PORT_MAPPING_RETRY_PERIOD));
252 : }
253 :
254 : void StartThreadMapPort()
255 : {
256 : if (!g_mapport_thread.joinable()) {
257 : assert(!g_mapport_interrupt);
258 : g_mapport_thread = std::thread(&util::TraceThread, "mapport", &ThreadMapPort);
259 : }
260 : }
261 :
262 : static void DispatchMapPort()
263 : {
264 : if (g_mapport_current_proto == MapPortProtoFlag::NONE && g_mapport_enabled_protos == MapPortProtoFlag::NONE) {
265 : return;
266 : }
267 :
268 : if (g_mapport_current_proto == MapPortProtoFlag::NONE && g_mapport_enabled_protos != MapPortProtoFlag::NONE) {
269 : StartThreadMapPort();
270 : return;
271 : }
272 :
273 : if (g_mapport_current_proto != MapPortProtoFlag::NONE && g_mapport_enabled_protos == MapPortProtoFlag::NONE) {
274 : InterruptMapPort();
275 : StopMapPort();
276 : return;
277 : }
278 :
279 : if (g_mapport_enabled_protos & g_mapport_current_proto) {
280 : // Enabling another protocol does not cause switching from the currently used one.
281 : return;
282 : }
283 :
284 : assert(g_mapport_thread.joinable());
285 : assert(!g_mapport_interrupt);
286 : // Interrupt a protocol-specific loop in the ThreadUpnp() or in the ThreadNatpmp()
287 : // to force trying the next protocol in the ThreadMapPort() loop.
288 : g_mapport_interrupt();
289 : }
290 :
291 : static void MapPortProtoSetEnabled(MapPortProtoFlag proto, bool enabled)
292 : {
293 : if (enabled) {
294 : g_mapport_enabled_protos |= proto;
295 : } else {
296 : g_mapport_enabled_protos &= ~proto;
297 : }
298 : }
299 :
300 : void StartMapPort(bool use_upnp, bool use_natpmp)
301 : {
302 : MapPortProtoSetEnabled(MapPortProtoFlag::UPNP, use_upnp);
303 : MapPortProtoSetEnabled(MapPortProtoFlag::NAT_PMP, use_natpmp);
304 : DispatchMapPort();
305 : }
306 :
307 : void InterruptMapPort()
308 : {
309 : g_mapport_enabled_protos = MapPortProtoFlag::NONE;
310 : if (g_mapport_thread.joinable()) {
311 : g_mapport_interrupt();
312 : }
313 : }
314 :
315 : void StopMapPort()
316 : {
317 : if (g_mapport_thread.joinable()) {
318 : g_mapport_thread.join();
319 : g_mapport_interrupt.reset();
320 : }
321 : }
322 :
323 : #else // #if defined(USE_NATPMP) || defined(USE_UPNP)
324 0 : void StartMapPort(bool use_upnp, bool use_natpmp)
325 : {
326 : // Intentionally left blank.
327 0 : }
328 0 : void InterruptMapPort()
329 : {
330 : // Intentionally left blank.
331 0 : }
332 0 : void StopMapPort()
333 : {
334 : // Intentionally left blank.
335 0 : }
336 : #endif // #if defined(USE_NATPMP) || defined(USE_UPNP)
|