diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/main_gui.cpp | 20 | ||||
| -rw-r--r-- | src/net.cpp | 93 | ||||
| -rw-r--r-- | src/net.h | 3 |
3 files changed, 115 insertions, 1 deletions
diff --git a/src/main_gui.cpp b/src/main_gui.cpp index 63bdbb7..9f7e34e 100644 --- a/src/main_gui.cpp +++ b/src/main_gui.cpp | |||
| @@ -61,6 +61,7 @@ static void PrintUsage() | |||
| 61 | printf("\n"); | 61 | printf("\n"); |
| 62 | printf("Network:\n"); | 62 | printf("Network:\n"); |
| 63 | printf(" /port=N (P2P listen port, default 8433)\n"); | 63 | printf(" /port=N (P2P listen port, default 8433)\n"); |
| 64 | printf(" /btfseed=ADDRESS:ENCHEX (extra bootstrap peer, repeatable)\n"); | ||
| 64 | printf("\n"); | 65 | printf("\n"); |
| 65 | printf("Each option also accepts '-' instead of '/'.\n"); | 66 | printf("Each option also accepts '-' instead of '/'.\n"); |
| 66 | } | 67 | } |
| @@ -117,6 +118,25 @@ static void ParseStartupArguments(int argc, char* argv[]) | |||
| 117 | if (!announceRelay.empty()) | 118 | if (!announceRelay.empty()) |
| 118 | strBtfAnnounceRelay = announceRelay; | 119 | strBtfAnnounceRelay = announceRelay; |
| 119 | 120 | ||
| 121 | // /btfseed=ADDRESS:ENCHEX -- extra bootstrap peers, repeatable. Useful for | ||
| 122 | // testing the seed path and for private networks that ship no compiled list. | ||
| 123 | for (int i = 1; i < argc; i++) | ||
| 124 | { | ||
| 125 | string s = argv[i]; | ||
| 126 | size_t eq = s.find('='); | ||
| 127 | if (eq == string::npos) continue; | ||
| 128 | string key = s.substr(0, eq); | ||
| 129 | if (key != "/btfseed" && key != "-btfseed") continue; | ||
| 130 | string val = s.substr(eq + 1); | ||
| 131 | size_t colon = val.rfind(':'); | ||
| 132 | if (colon == string::npos || colon + 1 >= val.size()) | ||
| 133 | { | ||
| 134 | fprintf(stderr, "Ignoring %s: expected ADDRESS:ENCHEX\n", s.c_str()); | ||
| 135 | continue; | ||
| 136 | } | ||
| 137 | vBtfExtraSeeds.push_back(make_pair(val.substr(0, colon), val.substr(colon + 1))); | ||
| 138 | } | ||
| 139 | |||
| 120 | // net.cpp has described nListenPort as "tunable via /port" since it was | 140 | // net.cpp has described nListenPort as "tunable via /port" since it was |
| 121 | // written, but nothing ever read the option, so the port was fixed at 8433 | 141 | // written, but nothing ever read the option, so the port was fixed at 8433 |
| 122 | // and a second node could not start on a machine already running one. | 142 | // and a second node could not start on a machine already running one. |
diff --git a/src/net.cpp b/src/net.cpp index 1d552cf..08a3348 100644 --- a/src/net.cpp +++ b/src/net.cpp | |||
| @@ -414,6 +414,93 @@ static void RememberBtfPeer(const string& strBtfAddr, const string& strMeeting, | |||
| 414 | } | 414 | } |
| 415 | } | 415 | } |
| 416 | 416 | ||
| 417 | // | ||
| 418 | // Compiled-in bootstrap seeds. | ||
| 419 | // | ||
| 420 | // A node with no cache has nothing but the Nostr relays, and if those are down, | ||
| 421 | // blocked or simply slow, a first run has no way into the network at all. Seeds | ||
| 422 | // are the floor under that: a handful of long-lived peers baked into the binary. | ||
| 423 | // | ||
| 424 | // A seed entry is deliberately just an address and an encryption key -- no | ||
| 425 | // meeting node. The rendezvous relay pairs on the service's public key, and a | ||
| 426 | // `.btf` address *is* that key, so a client can find a seed by trying the known | ||
| 427 | // relays in turn. Recording which relay a seed was on would rot the moment it | ||
| 428 | // failed over, which is the exact failure this project spent a long time | ||
| 429 | // chasing: advertising a rendezvous somebody is not registered at. | ||
| 430 | // | ||
| 431 | // Seeds are ordinary nodes with no special authority. They hand out signed, | ||
| 432 | // self-certifying descriptors like any peer, so a hostile seed can stall a | ||
| 433 | // bootstrap but cannot forge a peer or feed a false chain. | ||
| 434 | // | ||
| 435 | struct BtfSeed | ||
| 436 | { | ||
| 437 | const char* btfAddr; | ||
| 438 | const char* encHex; // 64 hex chars, the peer's x25519 public key | ||
| 439 | }; | ||
| 440 | |||
| 441 | static const BtfSeed pszBtfSeeds[] = | ||
| 442 | { | ||
| 443 | // Dedicated bootstrap node, Almaty. Runs beside a rendezvous relay on the | ||
| 444 | // same host, holds no wallet balance and does not mine -- it exists only to | ||
| 445 | // answer a first dial. It is trusted for nothing: it serves the same signed | ||
| 446 | // descriptors any peer does. | ||
| 447 | { "ygffz37jczlmrkzicxok6chobauyratdexc7hfgwzjdabzvb2nkngqy.btf", | ||
| 448 | "de8284b9d4effa2132e7981b566c1a297c39c1857d9c128e8ae093ef511d3200" }, | ||
| 449 | }; | ||
| 450 | static const size_t nBtfSeeds = ARRAYLEN(pszBtfSeeds); | ||
| 451 | |||
| 452 | // Extra seeds from the command line (/btfseed=ADDRESS:ENCHEX, repeatable). | ||
| 453 | vector<pair<string, string> > vBtfExtraSeeds; | ||
| 454 | |||
| 455 | static int TryBtfSeeds() | ||
| 456 | { | ||
| 457 | vector<pair<string, string> > seeds; | ||
| 458 | for (size_t i = 0; i < nBtfSeeds; i++) | ||
| 459 | seeds.push_back(make_pair(string(pszBtfSeeds[i].btfAddr), | ||
| 460 | string(pszBtfSeeds[i].encHex))); | ||
| 461 | foreach(const PAIRTYPE(string, string)& s, vBtfExtraSeeds) | ||
| 462 | seeds.push_back(s); | ||
| 463 | |||
| 464 | if (seeds.empty()) | ||
| 465 | return 0; | ||
| 466 | |||
| 467 | vector<string> relays = BtfAllRelays(); | ||
| 468 | if (relays.empty()) | ||
| 469 | return 0; | ||
| 470 | |||
| 471 | LogPrint("net", "btfseed: trying %zu seed(s) across %zu relay(s)\n", | ||
| 472 | seeds.size(), relays.size()); | ||
| 473 | |||
| 474 | int nConnected = 0; | ||
| 475 | foreach(const PAIRTYPE(string, string)& s, seeds) | ||
| 476 | { | ||
| 477 | if (fShutdown) return nConnected; | ||
| 478 | unsigned char enc[32]; | ||
| 479 | if (!HexToBytes(s.second, enc, 32)) | ||
| 480 | { | ||
| 481 | LogPrint("net", "btfseed: %s has a malformed encryption key, skipped\n", | ||
| 482 | s.first.c_str()); | ||
| 483 | continue; | ||
| 484 | } | ||
| 485 | // We do not know which relay this seed is registered at, so walk them. | ||
| 486 | foreach(const string& strRelay, relays) | ||
| 487 | { | ||
| 488 | if (fShutdown) return nConnected; | ||
| 489 | if (ConnectNodeBtfResolved(s.first, strRelay, enc)) | ||
| 490 | { | ||
| 491 | LogPrint("net", "btfseed: reached %s via %s\n", | ||
| 492 | s.first.c_str(), strRelay.c_str()); | ||
| 493 | nConnected++; | ||
| 494 | break; // found it; no need to try this seed's other relays | ||
| 495 | } | ||
| 496 | } | ||
| 497 | if (nConnected >= 4) | ||
| 498 | break; // enough of a foothold; the rest comes from discovery | ||
| 499 | } | ||
| 500 | LogPrint("net", "btfseed: %d seed(s) answered\n", nConnected); | ||
| 501 | return nConnected; | ||
| 502 | } | ||
| 503 | |||
| 417 | // Dial everything we reached last time, before the relays have said anything. | 504 | // Dial everything we reached last time, before the relays have said anything. |
| 418 | void ThreadReconnectCachedBtfPeers(void* parg) | 505 | void ThreadReconnectCachedBtfPeers(void* parg) |
| 419 | { | 506 | { |
| @@ -421,7 +508,11 @@ void ThreadReconnectCachedBtfPeers(void* parg) | |||
| 421 | LoadCachedBtfPeers(peers); | 508 | LoadCachedBtfPeers(peers); |
| 422 | if (peers.empty()) | 509 | if (peers.empty()) |
| 423 | { | 510 | { |
| 424 | LogPrint("net", "btfpeers: no cache yet, waiting on relay discovery\n"); | 511 | // First run, or the cache aged out. Seeds are the only way in that does |
| 512 | // not depend on a relay answering. | ||
| 513 | LogPrint("net", "btfpeers: no cache yet, falling back to seeds\n"); | ||
| 514 | if (TryBtfSeeds() == 0) | ||
| 515 | LogPrint("net", "btfpeers: no seed answered, waiting on relay discovery\n"); | ||
| 425 | return; | 516 | return; |
| 426 | } | 517 | } |
| 427 | LogPrint("net", "btfpeers: trying %zu remembered peer(s) before discovery\n", | 518 | LogPrint("net", "btfpeers: trying %zu remembered peer(s) before discovery\n", |
| @@ -29,6 +29,9 @@ CNode* ConnectNodeBtfResolved(const string& strBtfAddr, const string& strMeeting | |||
| 29 | void ThreadBtfAccept(void* parg); | 29 | void ThreadBtfAccept(void* parg); |
| 30 | void ThreadBtfConnect(void* parg); | 30 | void ThreadBtfConnect(void* parg); |
| 31 | extern string strBtfConnect; | 31 | extern string strBtfConnect; |
| 32 | // Bootstrap seeds added at runtime with /btfseed=ADDRESS:ENCHEX (repeatable). | ||
| 33 | // The compiled-in list lives in net.cpp; these are appended to it. | ||
| 34 | extern std::vector<std::pair<std::string, std::string> > vBtfExtraSeeds; | ||
| 32 | 35 | ||
| 33 | // --- .btf peer exchange --------------------------------------------------- | 36 | // --- .btf peer exchange --------------------------------------------------- |
| 34 | // Peers gossip signed descriptors so discovery survives a relay outage. Both | 37 | // Peers gossip signed descriptors so discovery survives a relay outage. Both |