upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--relay/install-bitflash-relay.sh19
-rw-r--r--src/headless.cpp2
-rw-r--r--src/net.cpp21
-rw-r--r--src/nostr.cpp32
-rw-r--r--src/nostr.h15
-rw-r--r--src/ui.cpp6
6 files changed, 81 insertions, 14 deletions
diff --git a/relay/install-bitflash-relay.sh b/relay/install-bitflash-relay.sh
index 77a46b2..fd901ac 100644
--- a/relay/install-bitflash-relay.sh
+++ b/relay/install-bitflash-relay.sh
@@ -295,6 +295,25 @@ echo ">> building bitflashd"
295g++ -std=gnu++14 -O2 -pthread bitflashd.cpp btfrv.cpp -o bitflashd 295g++ -std=gnu++14 -O2 -pthread bitflashd.cpp btfrv.cpp -o bitflashd
296echo ">> build OK: $DIR/bitflashd" 296echo ">> build OK: $DIR/bitflashd"
297 297
298# Basic anti-flood firewall rules (idempotent). These soak up single-source
299# connection floods; volumetric DDoS still needs provider-level protection.
300# Limits are generous so many users behind one CGNAT public IP aren't blocked.
301if command -v iptables >/dev/null 2>&1; then
302 echo ">> applying connection rate-limit on port $PORT"
303 # Cap concurrent connections per source IP (stops one IP hogging thousands)
304 iptables -C INPUT -p tcp --dport "$PORT" -m connlimit --connlimit-above 200 --connlimit-mask 32 -j REJECT --reject-with tcp-reset 2>/dev/null || \
305 iptables -A INPUT -p tcp --dport "$PORT" -m connlimit --connlimit-above 200 --connlimit-mask 32 -j REJECT --reject-with tcp-reset
306 # Cap NEW-connection rate per source IP (stops connection floods)
307 iptables -C INPUT -p tcp --dport "$PORT" -m conntrack --ctstate NEW -m hashlimit \
308 --hashlimit-name btfrelay --hashlimit-mode srcip --hashlimit-above 60/min --hashlimit-burst 100 -j DROP 2>/dev/null || \
309 iptables -A INPUT -p tcp --dport "$PORT" -m conntrack --ctstate NEW -m hashlimit \
310 --hashlimit-name btfrelay --hashlimit-mode srcip --hashlimit-above 60/min --hashlimit-burst 100 -j DROP
311 # Persist across reboots if the tooling is present
312 command -v netfilter-persistent >/dev/null 2>&1 && netfilter-persistent save >/dev/null 2>&1 || true
313else
314 echo ">> iptables not found; skipping rate-limit (host on a provider with anti-DDoS)"
315fi
316
298# systemd service so it survives reboots (skipped if systemd is absent) 317# systemd service so it survives reboots (skipped if systemd is absent)
299if command -v systemctl >/dev/null 2>&1 && [ -d /etc/systemd/system ]; then 318if command -v systemctl >/dev/null 2>&1 && [ -d /etc/systemd/system ]; then
300 cat > /etc/systemd/system/bitflashd.service <<EOF 319 cat > /etc/systemd/system/bitflashd.service <<EOF
diff --git a/src/headless.cpp b/src/headless.cpp
index 94597f1..646476f 100644
--- a/src/headless.cpp
+++ b/src/headless.cpp
@@ -95,7 +95,7 @@ int main(int argc, char* argv[])
95 if (mapArgs.count("/proxy")) 95 if (mapArgs.count("/proxy"))
96 addrProxy = CAddress(mapArgs["/proxy"].c_str()); 96 addrProxy = CAddress(mapArgs["/proxy"].c_str());
97 if (mapArgs.count("/rvrelay")) 97 if (mapArgs.count("/rvrelay"))
98 strBtfMeetingRelay = mapArgs["/rvrelay"]; 98 vBtfMeetingRelays = { mapArgs["/rvrelay"] };
99 if (mapArgs.count("/connectbtf")) 99 if (mapArgs.count("/connectbtf"))
100 strBtfConnect = mapArgs["/connectbtf"]; 100 strBtfConnect = mapArgs["/connectbtf"];
101 if (mapArgs.count("/debug")) 101 if (mapArgs.count("/debug"))
diff --git a/src/net.cpp b/src/net.cpp
index 8ab9ccc..659de05 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -441,15 +441,24 @@ void ThreadBtfAccept(void* parg)
441 return; 441 return;
442 Sleep(5000); 442 Sleep(5000);
443 } 443 }
444 size_t iRelay = 0;
444 loop 445 loop
445 { 446 {
446 if (fShutdown) 447 if (fShutdown)
447 return; 448 return;
448 string strMeeting = strBtfMeetingRelay; 449 if (vBtfMeetingRelays.empty())
450 {
451 Sleep(10000); // no meeting relay configured
452 continue;
453 }
454 // Stick to the current relay while it works; on failure, fail over to
455 // the next seed so a DDoS'd/blocked relay IP can't keep us offline.
456 string strMeeting = vBtfMeetingRelays[iRelay % vBtfMeetingRelays.size()];
449 size_t colon = strMeeting.rfind(':'); 457 size_t colon = strMeeting.rfind(':');
450 if (colon == string::npos) 458 if (colon == string::npos)
451 { 459 {
452 Sleep(10000); // no meeting relay configured 460 iRelay++;
461 Sleep(2000);
453 continue; 462 continue;
454 } 463 }
455 string strHost = strMeeting.substr(0, colon); 464 string strHost = strMeeting.substr(0, colon);
@@ -465,9 +474,13 @@ void ThreadBtfAccept(void* parg)
465 } 474 }
466 if (rv == btf::RV_INVALID) 475 if (rv == btf::RV_INVALID)
467 { 476 {
468 Sleep(10000); // relay unreachable; retry 477 iRelay++; // this relay is down/attacked -> try the next one
478 Sleep(3000);
469 continue; 479 continue;
470 } 480 }
481 // Registered OK: advertise THIS relay in our descriptor so clients dial
482 // us here, and keep using it (iRelay unchanged) until it fails.
483 BtfSetActiveRelay(strMeeting);
471 btf_socket_t hSocket = btf::BtfServiceWrap(rv, sk); 484 btf_socket_t hSocket = btf::BtfServiceWrap(rv, sk);
472 if (hSocket == INVALID_SOCKET) 485 if (hSocket == INVALID_SOCKET)
473 continue; 486 continue;
@@ -1146,7 +1159,7 @@ bool StartNode(string& strError)
1146 1159
1147 // Anonymous inbound: this node's .btf hidden service, reachable through the 1160 // Anonymous inbound: this node's .btf hidden service, reachable through the
1148 // meeting relay without exposing our IP or needing a public port. 1161 // meeting relay without exposing our IP or needing a public port.
1149 if (!strBtfMeetingRelay.empty()) 1162 if (!vBtfMeetingRelays.empty())
1150 if (_beginthread(ThreadBtfAccept, 0, NULL) == -1) 1163 if (_beginthread(ThreadBtfAccept, 0, NULL) == -1)
1151 printf("Error: _beginthread(ThreadBtfAccept) failed\n"); 1164 printf("Error: _beginthread(ThreadBtfAccept) failed\n");
1152 1165
diff --git a/src/nostr.cpp b/src/nostr.cpp
index 8e2a07d..59817f5 100644
--- a/src/nostr.cpp
+++ b/src/nostr.cpp
@@ -55,7 +55,32 @@ const int nNostrRelays = ARRAYLEN(pszNostrRelays);
55 55
56// Rendezvous meeting relay this node registers at (ThreadBtfAccept in net.cpp) 56// Rendezvous meeting relay this node registers at (ThreadBtfAccept in net.cpp)
57// and advertises in its .btf descriptor. Seed default; /rvrelay overrides. 57// and advertises in its .btf descriptor. Seed default; /rvrelay overrides.
58string strBtfMeetingRelay = "90.156.222.107:8434"; 58// Seed rendezvous relays. More entries = more resilience: the node fails over
59// between them (see ThreadBtfAccept), so DDoSing one relay IP can't take the
60// network down. /rvrelay overrides this list with a single entry.
61vector<string> vBtfMeetingRelays = {
62 "92.246.128.180:8434", // Sao Paulo, BR
63 "31.44.4.249:8434", // New Jersey, US
64 "90.156.222.107:8434", // Almaty, KZ
65};
66string strBtfActiveRelay;
67static CCriticalSection cs_activeRelay;
68
69string BtfActiveRelay()
70{
71 CRITICAL_BLOCK(cs_activeRelay)
72 if (!strBtfActiveRelay.empty())
73 return strBtfActiveRelay;
74 if (!vBtfMeetingRelays.empty())
75 return vBtfMeetingRelays[0];
76 return "";
77}
78
79void BtfSetActiveRelay(const string& relay)
80{
81 CRITICAL_BLOCK(cs_activeRelay)
82 strBtfActiveRelay = relay;
83}
59 84
60 85
61// 86//
@@ -519,8 +544,9 @@ static void PublishDescriptor(CWebSocket& ws, CNostrKey& key)
519{ 544{
520 // meeting_node is the rendezvous relay this node's hidden service 545 // meeting_node is the rendezvous relay this node's hidden service
521 // (ThreadBtfAccept in net.cpp) is registered at -- where clients dial us. 546 // (ThreadBtfAccept in net.cpp) is registered at -- where clients dial us.
522 string meeting_node = strBtfMeetingRelay.empty() ? "rendezvous-pending" 547 string meeting_node = BtfActiveRelay();
523 : strBtfMeetingRelay; 548 if (meeting_node.empty())
549 meeting_node = "rendezvous-pending";
524 string desc = btf::SignDescriptor(key.ctx, key.seckey, key.EncPubHex(), 550 string desc = btf::SignDescriptor(key.ctx, key.seckey, key.EncPubHex(),
525 meeting_node, (uint64_t)GetTime()); 551 meeting_node, (uint64_t)GetTime());
526 if (desc.empty()) 552 if (desc.empty())
diff --git a/src/nostr.h b/src/nostr.h
index 5ec9f65..41e59df 100644
--- a/src/nostr.h
+++ b/src/nostr.h
@@ -11,6 +11,7 @@
11#define BITFLASH_NOSTR_H 11#define BITFLASH_NOSTR_H
12 12
13#include <string> 13#include <string>
14#include <vector>
14 15
15// Thread entry point (signature compatible with _beginthread) 16// Thread entry point (signature compatible with _beginthread)
16void ThreadNostrSeed(void* parg); 17void ThreadNostrSeed(void* parg);
@@ -19,9 +20,17 @@ void ThreadNostrSeed(void* parg);
19extern const char* pszNostrRelays[]; 20extern const char* pszNostrRelays[];
20extern const int nNostrRelays; 21extern const int nNostrRelays;
21 22
22// Rendezvous meeting relay ("host:port") this node registers at and advertises 23// Rendezvous meeting relays ("host:port") this node can register its .btf
23// in its .btf descriptor. Overridable with /rvrelay=host:port. 24// service at. It registers at the first reachable one and advertises that in
24extern std::string strBtfMeetingRelay; 25// its descriptor; if the relay dies it fails over to another, so attacking a
26// single relay's IP can't take the network down. Overridable with /rvrelay.
27extern std::vector<std::string> vBtfMeetingRelays;
28// The relay this node is currently registered at (set by ThreadBtfAccept).
29extern std::string strBtfActiveRelay;
30// The active relay, or the first seed if none active yet ("" if the list is empty).
31std::string BtfActiveRelay();
32// Record the relay this node just registered its service at (thread-safe).
33void BtfSetActiveRelay(const std::string& relay);
25 34
26// Copy this node's .btf identity (lazily loading or generating it): the x-only 35// Copy this node's .btf identity (lazily loading or generating it): the x-only
27// pubkey (= the .btf address) and the x25519 secret for the end-to-end channel. 36// pubkey (= the .btf address) and the x25519 secret for the end-to-end channel.
diff --git a/src/ui.cpp b/src/ui.cpp
index 3e734a5..cb1a94d 100644
--- a/src/ui.cpp
+++ b/src/ui.cpp
@@ -2969,10 +2969,10 @@ bool CMyApp::OnInit2()
2969 if (mapArgs.count("/proxy")) 2969 if (mapArgs.count("/proxy"))
2970 addrProxy = CAddress(mapArgs["/proxy"].c_str()); 2970 addrProxy = CAddress(mapArgs["/proxy"].c_str());
2971 2971
2972 // Rendezvous meeting relay this node registers its .btf service at and 2972 // Rendezvous meeting relay override: replace the seed list with a single
2973 // advertises in its descriptor (default is the seed relay; empty disables). 2973 // relay (default keeps the built-in seed list with failover).
2974 if (mapArgs.count("/rvrelay")) 2974 if (mapArgs.count("/rvrelay"))
2975 strBtfMeetingRelay = mapArgs["/rvrelay"]; 2975 vBtfMeetingRelays = { mapArgs["/rvrelay"] };
2976 2976
2977 // Keep an anonymous outbound connection to a specific .btf peer. 2977 // Keep an anonymous outbound connection to a specific .btf peer.
2978 if (mapArgs.count("/connectbtf")) 2978 if (mapArgs.count("/connectbtf"))