PeeringSeeder.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. /* vim: set expandtab ts=4 sw=4: */
  2. /*
  3. * You may redistribute this program and/or modify it under the terms of
  4. * the GNU General Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. */
  15. #include "subnode/PeeringSeeder.h"
  16. #include "benc/Dict.h"
  17. #include "benc/String.h"
  18. #include "crypto/Ca.h"
  19. #include "dht/Address.h"
  20. #include "exception/Err.h"
  21. #include "memory/Allocator.h"
  22. #include "net/SwitchPinger.h"
  23. #include "rust/cjdns_sys/Rffi.h"
  24. #include "subnode/ReachabilityCollector.h"
  25. #include "util/Assert.h"
  26. #include "util/Bits.h"
  27. #include "util/Identity.h"
  28. #include "util/events/EventBase.h"
  29. #include "util/events/Time.h"
  30. #include "util/events/Timeout.h"
  31. #include "util/log/Log.h"
  32. typedef struct PeeringSeeder_pvt {
  33. PeeringSeeder_t pub;
  34. struct SwitchPinger* sp;
  35. struct ReachabilityCollector* rc;
  36. Allocator_t* alloc;
  37. Log_t* log;
  38. struct MsgCore* mc;
  39. Ca_t* ca;
  40. Rffi_Seeder* seeder;
  41. bool active;
  42. char login[24];
  43. // Our peering credentials
  44. uint16_t userNum;
  45. // 8 random bytes used to derive the password
  46. uint64_t pass;
  47. int lastPeerQueried;
  48. uint64_t lastQueryTimeSec;
  49. struct SwitchPinger_Ping* requestOutstanding;
  50. struct Address snode;
  51. uint64_t lastPostTimeSec;
  52. struct MsgCore_Promise* snodePost;
  53. Identity
  54. } PeeringSeeder_pvt_t;
  55. void* PeeringSeeder_getRsSeeder(PeeringSeeder_t* self)
  56. {
  57. PeeringSeeder_pvt_t* pq = Identity_check((PeeringSeeder_pvt_t*) self);
  58. return pq->seeder;
  59. }
  60. static void ipQueryResp(struct SwitchPinger_Response* resp, void* userData)
  61. {
  62. PeeringSeeder_pvt_t* pq = Identity_check((PeeringSeeder_pvt_t*) userData);
  63. if (resp->ping != pq->requestOutstanding) {
  64. Log_info(pq->log, "Ping does not match requestOutstanding");
  65. }
  66. pq->requestOutstanding = NULL;
  67. char* err = "";
  68. switch (resp->res) {
  69. case SwitchPinger_Result_OK:
  70. if (Rffi_Seeder_got_lladdr(pq->seeder, &resp->lladdr)) {
  71. // Since there was a change, post ASAP.
  72. pq->lastPostTimeSec = 0;
  73. }
  74. return;
  75. case SwitchPinger_Result_LABEL_MISMATCH: err = "LABEL_MISMATCH"; break;
  76. case SwitchPinger_Result_WRONG_DATA: err = "WRONG_DATA"; break;
  77. case SwitchPinger_Result_ERROR_RESPONSE: err = "ERROR_RESPONSE"; break;
  78. case SwitchPinger_Result_LOOP_ROUTE: err = "LOOP_ROUTE"; break;
  79. case SwitchPinger_Result_TIMEOUT: err = "TIMEOUT"; break;
  80. default: err = "unknown error"; break;
  81. }
  82. Log_debug(pq->log, "Error sending LLADDR query to peer [%llx] [%s]",
  83. (long long)resp->label, err);
  84. }
  85. static void publicIPQuery(PeeringSeeder_pvt_t* pq) {
  86. if (pq->requestOutstanding) {
  87. return;
  88. }
  89. uint64_t now = Time_currentTimeSeconds();
  90. if (pq->lastQueryTimeSec + 10 > now) {
  91. Log_debug(pq->log, "Last query within 10 seconds");
  92. return;
  93. }
  94. if (Rffi_Seeder_has_lladdr(pq->seeder)) {
  95. if (pq->lastQueryTimeSec + 300 > now) {
  96. Log_debug(pq->log, "Last query within 5 minutes and we have our lladdr");
  97. return;
  98. }
  99. }
  100. int peerCount = ReachabilityCollector_peerCount(pq->rc);
  101. if (!peerCount) {
  102. Log_debug(pq->log, "No peers");
  103. return;
  104. }
  105. int tryPeerN = (pq->lastPeerQueried + 1) % peerCount;
  106. pq->lastPeerQueried = tryPeerN;
  107. struct ReachabilityCollector_PeerInfo* tryPeer =
  108. ReachabilityCollector_getPeerInfo(pq->rc, tryPeerN);
  109. struct SwitchPinger_Ping* q = SwitchPinger_newPing(
  110. tryPeer->addr.path,
  111. NULL,
  112. 10000,
  113. ipQueryResp,
  114. pq->alloc,
  115. pq->sp);
  116. q->onResponseContext = pq;
  117. q->type = SwitchPinger_Type_LLADDR;
  118. pq->requestOutstanding = q;
  119. String_t* peerAddr = Address_toString(&tryPeer->addr, q->pingAlloc);
  120. Log_debug(pq->log, "Sent LlAddr query to [%s]", peerAddr->bytes);
  121. }
  122. static void snodeResp(Dict* msg, Gcc_UNUSED struct Address* src, struct MsgCore_Promise* prom)
  123. {
  124. PeeringSeeder_pvt_t* pq = Identity_check((PeeringSeeder_pvt_t*) prom->userData);
  125. String* peers = Dict_getStringC(msg, "pr");
  126. if (!peers) {
  127. Log_debug(pq->log, "Got snode reply with no peers");
  128. return;
  129. }
  130. Rffi_Seeder_got_peers(pq->seeder, peers, prom->alloc);
  131. }
  132. static void cycle(void* vpq)
  133. {
  134. PeeringSeeder_pvt_t* pq = Identity_check((PeeringSeeder_pvt_t*) vpq);
  135. if (!pq->active) {
  136. return;
  137. }
  138. // Log_debug(pq->log, "cycle()");
  139. // Try to get our IP if we can
  140. publicIPQuery(pq);
  141. uint64_t now = Time_currentTimeSeconds();
  142. if (pq->lastPostTimeSec + 5*60 > now) {
  143. // Only post to the snode every 5 minutes (or on new news)
  144. return;
  145. }
  146. if (!Rffi_Seeder_has_lladdr(pq->seeder)) {
  147. return;
  148. }
  149. if (Bits_isZero(&pq->snode, sizeof pq->snode)) {
  150. return;
  151. }
  152. struct MsgCore_Promise* snodeQuery = MsgCore_createQuery(pq->mc, 0, pq->alloc);
  153. snodeQuery->cb = snodeResp;
  154. snodeQuery->userData = pq;
  155. snodeQuery->target = Address_clone(&pq->snode, snodeQuery->alloc);
  156. String* creds = NULL;
  157. Err_assert(Rffi_Seeder_mk_creds(pq->seeder, &creds, snodeQuery->alloc));
  158. snodeQuery->msg = Dict_new(snodeQuery->alloc);
  159. Dict_putStringCC(snodeQuery->msg, "sq", "pc", snodeQuery->alloc);
  160. Dict_putStringC(snodeQuery->msg, "pc", creds, snodeQuery->alloc);
  161. pq->snodePost = snodeQuery;
  162. Log_debug(pq->log, "Posting our public IP addresses to snode");
  163. }
  164. void PeeringSeeder_setSnode(PeeringSeeder_t* self, struct Address* snode)
  165. {
  166. PeeringSeeder_pvt_t* pq = Identity_check((PeeringSeeder_pvt_t*) self);
  167. struct Address esnode = { .path = 0 };
  168. if (snode != NULL) {
  169. Bits_memcpy(&esnode, snode, sizeof esnode);
  170. }
  171. if (Bits_memcmp(&esnode, &pq->snode, sizeof esnode)) {
  172. uint8_t fromAddr[60];
  173. Address_print(fromAddr, &pq->snode);
  174. if (snode == NULL) {
  175. Log_debug(pq->log, "Snode [%s] was lost", fromAddr);
  176. } else {
  177. uint8_t toAddr[60];
  178. Address_print(toAddr, &pq->snode);
  179. if (Bits_isZero(&pq->snode, sizeof pq->snode)) {
  180. Log_debug(pq->log, "Snode discovered [%s]", toAddr);
  181. } else {
  182. Log_debug(pq->log, "Snode was changed [%s] -> [%s]", fromAddr, toAddr);
  183. }
  184. }
  185. pq->snode = esnode;
  186. }
  187. }
  188. Err_DEFUN PeeringSeeder_publicStatus(PeeringSeeder_PublicStatus_t** outP, PeeringSeeder_t* self, Allocator_t* alloc)
  189. {
  190. PeeringSeeder_pvt_t* pq = Identity_check((PeeringSeeder_pvt_t*) self);
  191. PeeringSeeder_PublicStatus_t* out = Allocator_calloc(alloc, sizeof(PeeringSeeder_PublicStatus_t), 1);
  192. out->active = pq->active;
  193. if (!Bits_isZero(&pq->snode, sizeof pq->snode)) {
  194. out->snode = Address_toString(&pq->snode, alloc);
  195. }
  196. Err(Rffi_Seeder_public_status(
  197. pq->seeder, &out->ipv4, &out->ipv6, &out->peerId, alloc));
  198. *outP = out;
  199. return NULL;
  200. }
  201. Err_DEFUN PeeringSeeder_publicPeer(PeeringSeeder_t* self, String_t* code, Allocator_t* reqAlloc)
  202. {
  203. PeeringSeeder_pvt_t* pq = Identity_check((PeeringSeeder_pvt_t*) self);
  204. if (code == NULL) {
  205. if (pq->active) {
  206. String_t* s = String_new(pq->login, reqAlloc);
  207. Ca_removeUsers(pq->ca, s);
  208. }
  209. return NULL;
  210. }
  211. if (code->len > PeeringSeeder_publicPeer_ID_MAX_LEN) {
  212. Err_raise(reqAlloc, "PeerID is too long, max length: [%d]",
  213. PeeringSeeder_publicPeer_ID_MAX_LEN);
  214. }
  215. String_t* user = NULL;
  216. String_t* pass = NULL;
  217. Err(Rffi_Seeder_public_peer(
  218. pq->seeder,
  219. &user,
  220. &pass,
  221. pq->userNum,
  222. pq->pass,
  223. code,
  224. reqAlloc));
  225. Assert_true(user->len < sizeof pq->login);
  226. Bits_memset(pq->login, 0, sizeof pq->login);
  227. Bits_memcpy(pq->login, user->bytes, user->len);
  228. Assert_true(pq->login[sizeof pq->login - 1] == 0);
  229. Ca_addUser(pass, user, pq->ca);
  230. pq->active = true;
  231. return NULL;
  232. }
  233. struct PeeringSeeder* PeeringSeeder_new(
  234. struct SwitchPinger* sp,
  235. struct ReachabilityCollector* rc,
  236. Allocator_t* alloc,
  237. Log_t* log,
  238. struct MsgCore* mc,
  239. EventBase_t* base,
  240. Ca_t* ca)
  241. {
  242. PeeringSeeder_pvt_t* out = Allocator_calloc(alloc, sizeof(PeeringSeeder_pvt_t), 1);
  243. Identity_set(out);
  244. out->sp = sp;
  245. out->rc = rc;
  246. out->alloc = alloc;
  247. out->log = log;
  248. out->mc = mc;
  249. out->ca = ca;
  250. uint8_t myPubKey[32];
  251. Ca_getPubKey(ca, myPubKey);
  252. Rffi_Seeder_new(&out->seeder, &out->pub.seederIface, myPubKey, alloc);
  253. // Random (stable across restarts) user num and passwd
  254. uint8_t secretBuf[64];
  255. Assert_true(!Ca_getSecret(ca, String_CONST("SEED_PASSWD"), secretBuf));
  256. Bits_memcpy(&out->pass, secretBuf, sizeof out->pass);
  257. Bits_memcpy(&out->userNum, &secretBuf[8], sizeof out->userNum);
  258. Timeout_setInterval(cycle, out, 3000, base, alloc);
  259. return &out->pub;
  260. }