Skip to content

Commit 5832aef

Browse files
chopperbrianoclaude
andcommitted
IPFS::findPublicAddress: prefer plain TCP IPv4 relay (win.16)
The win.15 fix correctly picks a real relay address instead of a fabricated one, but iteration order gave it the /dns4/.../tls/ws/ variant (TLS-over-websocket relay), which isn't universally dialable by all libp2p implementations. Within the relay bucket, prefer in this order: 1. /ip4/PUBLIC/tcp/PORT/.../p2p-circuit/... — plain TCP IPv4 (most universal) 2. /ip6/PUBLIC/tcp/PORT/.../p2p-circuit/... — plain TCP IPv6 3. /dns4/.../tcp/PORT/.../p2p-circuit/... — DNS-based (may wrap TLS/WSS) 4. anything else "Plain TCP" means no /tls/, /ws/, /wss/, /quic*/, /webtransport/, or /webrtc/ segments before the /p2p-circuit/. Also widened the RFC1918 filter to cover the full 172.16/12 range and added 169.254/16 link-local. For the reporting user's /id output this will pick /ip4/45.11.56.54/tcp/4001/p2p/12D3KooWG8.../p2p-circuit/p2p/SELF which is the most broadly dialable of the available relays. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 0e3b72f commit 5832aef

2 files changed

Lines changed: 49 additions & 9 deletions

File tree

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ SET(PATCH_VERSION 0)
4040
SET(SO_VERSION 0)
4141

4242
# Windows port build number (increment for each Windows-specific release)
43-
SET(WIN_BUILD 15)
43+
SET(WIN_BUILD 16)
4444

4545
# Add source directory
4646
include_directories(src)

src/IPFS.cpp

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -282,18 +282,58 @@ string IPFS::findPublicAddress(const vector<string>& addresses, const string& ip
282282
// but IPFS has negotiated a relay — libp2p peers (including mctrivia's
283283
// server) can dial the node THROUGH the relay using this exact multiaddr.
284284
// We never fabricate these; we use them verbatim from the /id response.
285-
// Skip loopback/link-local relays.
285+
//
286+
// Preference order within relay addresses:
287+
// 1. /ip4/PUBLIC/tcp/PORT/p2p/RELAY/p2p-circuit/p2p/SELF — plain TCP, most universal
288+
// 2. /ip6/PUBLIC/tcp/PORT/... — IPv6 plain TCP
289+
// 3. /dns4/.../tcp/PORT/... — DNS-based (may use TLS/WSS)
290+
// 4. anything else with /p2p-circuit/ and /tcp/
291+
// Skip loopback, link-local, and RFC1918 relays (not routable from the internet).
292+
auto isUnroutableRelay = [](const string& addr) -> bool {
293+
if (addr.find("/127.0.0.1/") != string::npos) return true;
294+
if (addr.find("/::1/") != string::npos) return true;
295+
if (addr.find("/ip4/10.") != string::npos) return true;
296+
if (addr.find("/ip4/192.168.") != string::npos) return true;
297+
if (addr.find("/ip4/172.16.") != string::npos) return true;
298+
if (addr.find("/ip4/172.17.") != string::npos) return true;
299+
if (addr.find("/ip4/172.18.") != string::npos) return true;
300+
if (addr.find("/ip4/172.19.") != string::npos) return true;
301+
if (addr.find("/ip4/172.2") != string::npos) return true; // 172.20–172.29
302+
if (addr.find("/ip4/172.30.") != string::npos) return true;
303+
if (addr.find("/ip4/172.31.") != string::npos) return true;
304+
if (addr.find("/ip4/169.254.") != string::npos) return true; // link-local
305+
return false;
306+
};
307+
auto isPlainTcpRelay = [](const string& addr) -> bool {
308+
// Plain TCP = no /tls/, /ws/, /wss/, /quic/, /webtransport/, /webrtc/ segments before /p2p-circuit/
309+
size_t circuit = addr.find("/p2p-circuit/");
310+
if (circuit == string::npos) return false;
311+
string pre = addr.substr(0, circuit);
312+
if (pre.find("/tls/") != string::npos) return false;
313+
if (pre.find("/ws/") != string::npos) return false;
314+
if (pre.find("/wss/") != string::npos) return false;
315+
if (pre.find("/quic") != string::npos) return false;
316+
if (pre.find("/webtransport") != string::npos) return false;
317+
if (pre.find("/webrtc") != string::npos) return false;
318+
return true;
319+
};
320+
321+
vector<string> relayIp4Plain, relayIp6Plain, relayDns, relayOther;
286322
for (const auto& addr: addresses) {
287323
if (addr.find("/p2p-circuit/") == string::npos) continue;
288324
if (addr.find("/tcp/") == string::npos) continue;
289-
if (addr.find("/127.0.0.1/") != string::npos) continue;
290-
if (addr.find("/::1/") != string::npos) continue;
291-
// Also skip RFC1918 private ranges as relay IPs — those aren't routable
292-
if (addr.find("/ip4/10.") != string::npos) continue;
293-
if (addr.find("/ip4/192.168.") != string::npos) continue;
294-
if (addr.find("/ip4/172.16.") != string::npos) continue;
295-
return addr;
325+
if (isUnroutableRelay(addr)) continue;
326+
327+
bool plain = isPlainTcpRelay(addr);
328+
if (addr.rfind("/ip4/", 0) == 0 && plain) relayIp4Plain.push_back(addr);
329+
else if (addr.rfind("/ip6/", 0) == 0 && plain) relayIp6Plain.push_back(addr);
330+
else if (addr.rfind("/dns", 0) == 0) relayDns.push_back(addr);
331+
else relayOther.push_back(addr);
296332
}
333+
if (!relayIp4Plain.empty()) return relayIp4Plain.front();
334+
if (!relayIp6Plain.empty()) return relayIp6Plain.front();
335+
if (!relayDns.empty()) return relayDns.front();
336+
if (!relayOther.empty()) return relayOther.front();
297337

298338
// Priority 3: last-resort fabrication (original behavior). Substitute our
299339
// WAN IP into a local address. This only works if port 4001 is actually

0 commit comments

Comments
 (0)