void PeerLink_kbps(struct PeerLink* peerLink, struct PeerLink_Kbps* output) { struct PeerLink_pvt* pl = Identity_check((struct PeerLink_pvt*) peerLink); uint32_t now = Time_currentTimeMilliseconds(pl->base); output->recvKbps = Kbps_accumulate(&pl->recvBw, now, Kbps_accumulate_NO_PACKET); output->sendKbps = Kbps_accumulate(&pl->sendBw, now, Kbps_accumulate_NO_PACKET); }
static void notLinkedYet(struct TwoNodes* ctx) { uint64_t now = Time_currentTimeMilliseconds(ctx->base); if ((now - ctx->startTime) > 5000) { Assert_failure("Failed to link in 5 seconds"); } }
// This is directly called from SwitchCore, message is not encrypted. static uint8_t sendFromSwitch(struct Message* msg, struct Interface* switchIf) { struct IFCPeer* ep = Identity_cast((struct IFCPeer*) switchIf); // This sucks but cryptoauth trashes the content when it encrypts // and we need to be capable of sending back a coherent error message. uint8_t top[255]; uint8_t* messageBytes = msg->bytes; uint16_t padding = msg->padding; uint16_t len = (msg->length < 255) ? msg->length : 255; Bits_memcpy(top, msg->bytes, len); uint8_t ret = ep->cryptoAuthIf->sendMessage(msg, ep->cryptoAuthIf); // If this node is unresponsive then return an error. struct Context* ic = ifcontrollerForPeer(ep); uint64_t now = Time_currentTimeMilliseconds(ic->eventBase); if (ret || now - ep->timeOfLastMessage > ic->unresponsiveAfterMilliseconds) { msg->bytes = messageBytes; msg->padding = padding; msg->length = len; Bits_memcpy(msg->bytes, top, len); return ret ? ret : Error_UNDELIVERABLE; } else { /* Way way way too much noise Log_debug(ic->logger, "Sending to neighbor, last message from this node was [%u] ms ago.", (now - ep->timeOfLastMessage)); */ } return Error_NONE; }
// This is directly called from SwitchCore, message is not encrypted. static uint8_t sendFromSwitch(struct Message* msg, struct Interface* switchIf) { struct InterfaceController_Peer* ep = Identity_check((struct InterfaceController_Peer*) switchIf); ep->bytesOut += msg->length; struct InterfaceController_pvt* ic = ifcontrollerForPeer(ep); uint8_t ret; uint64_t now = Time_currentTimeMilliseconds(ic->eventBase); if (now - ep->timeOfLastMessage > ic->unresponsiveAfterMilliseconds) { // TODO(cjd): This is a hack because if the time of last message exceeds the // unresponsive time, we need to send back an error and that means // mangling the message which would otherwise be in the queue. struct Allocator* tempAlloc = Allocator_child(ic->allocator); struct Message* toSend = Message_clone(msg, tempAlloc); ret = Interface_sendMessage(ep->cryptoAuthIf, toSend); Allocator_free(tempAlloc); } else { ret = Interface_sendMessage(ep->cryptoAuthIf, msg); } // If this node is unresponsive then return an error. if (ret || now - ep->timeOfLastMessage > ic->unresponsiveAfterMilliseconds) { return ret ? ret : Error_UNDELIVERABLE; } else { /* Way way way too much noise Log_debug(ic->logger, "Sending to neighbor, last message from this node was [%u] ms ago.", (now - ep->timeOfLastMessage)); */ } return Error_NONE; }
/** * Incoming message from someone we don't know, maybe someone responding to a beacon? * expects: [ struct LLAddress ][ content ] */ static Iface_DEFUN handleUnexpectedIncoming(struct Message* msg, struct InterfaceController_Iface_pvt* ici) { struct InterfaceController_pvt* ic = ici->ic; struct Sockaddr* lladdr = (struct Sockaddr*) msg->bytes; Message_shift(msg, -lladdr->addrLen, NULL); if (msg->length < CryptoHeader_SIZE) { return NULL; } struct Allocator* epAlloc = Allocator_child(ici->alloc); lladdr = Sockaddr_clone(lladdr, epAlloc); Assert_true(!((uintptr_t)msg->bytes % 4) && "alignment fault"); struct Peer* ep = Allocator_calloc(epAlloc, sizeof(struct Peer), 1); Identity_set(ep); ep->alloc = epAlloc; ep->ici = ici; ep->lladdr = lladdr; ep->alloc = epAlloc; ep->peerLink = PeerLink_new(ic->eventBase, epAlloc); struct CryptoHeader* ch = (struct CryptoHeader*) msg->bytes; ep->caSession = CryptoAuth_newSession(ic->ca, epAlloc, ch->publicKey, true, "outer"); if (CryptoAuth_decrypt(ep->caSession, msg)) { // If the first message is a dud, drop all state for this peer. // probably some random crap that wandered in the socket. Allocator_free(epAlloc); return NULL; } Assert_true(!Bits_isZero(ep->caSession->herPublicKey, 32)); Assert_true(Map_EndpointsBySockaddr_indexForKey(&lladdr, &ici->peerMap) == -1); int index = Map_EndpointsBySockaddr_put(&lladdr, &ep, &ici->peerMap); Assert_true(index >= 0); ep->handle = ici->peerMap.handles[index]; Allocator_onFree(epAlloc, closeInterface, ep); ep->state = InterfaceController_PeerState_UNAUTHENTICATED; ep->isIncomingConnection = true; ep->switchIf.send = sendFromSwitch; if (SwitchCore_addInterface(ic->switchCore, &ep->switchIf, epAlloc, &ep->addr.path)) { Log_debug(ic->logger, "handleUnexpectedIncoming() SwitchCore out of space"); Allocator_free(epAlloc); return NULL; } // We want the node to immedietly be pinged but we don't want it to appear unresponsive because // the pinger will only ping every (PING_INTERVAL * 8) so we set timeOfLastMessage to // (now - pingAfterMilliseconds - 1) so it will be considered a "lazy node". ep->timeOfLastMessage = Time_currentTimeMilliseconds(ic->eventBase) - ic->pingAfterMilliseconds - 1; Bits_memcpy(ep->addr.key, ep->caSession->herPublicKey, 32); Bits_memcpy(ep->addr.ip6.bytes, ep->caSession->herIp6, 16); Log_info(ic->logger, "Added peer [%s] from incoming message", Address_toString(&ep->addr, msg->alloc)->bytes); return receivedPostCryptoAuth(msg, ep, ic); }
static void onPingResponse(struct SwitchPinger_Response* resp, void* onResponseContext) { if (SwitchPinger_Result_OK != resp->res) { return; } struct InterfaceController_Peer* ep = Identity_check((struct InterfaceController_Peer*) onResponseContext); struct InterfaceController_pvt* ic = ifcontrollerForPeer(ep); struct Address addr; Bits_memset(&addr, 0, sizeof(struct Address)); Bits_memcpyConst(addr.key, CryptoAuth_getHerPublicKey(ep->cryptoAuthIf), 32); addr.path = ep->switchLabel; addr.protocolVersion = resp->version; #ifdef Log_DEBUG uint8_t addrStr[60]; Address_print(addrStr, &addr); uint8_t key[56]; Base32_encode(key, 56, CryptoAuth_getHerPublicKey(ep->cryptoAuthIf), 32); #endif if (!Version_isCompatible(Version_CURRENT_PROTOCOL, resp->version)) { Log_debug(ic->logger, "got switch pong from node [%s] with incompatible version [%d]", key, resp->version); } else { Log_debug(ic->logger, "got switch pong from node [%s] with version [%d]", key, resp->version); } if (!ep->timeOfLastPing) { // We've never heard from this machine before (or we've since forgotten about it) // This is here because we want the tests to function without the janitor present. // Other than that, it just makes a slightly more synchronous/guaranteed setup. Router_sendGetPeers(ic->router, &addr, 0, 0, ic->allocator); } struct Node_Link* link = Router_linkForPath(ic->router, resp->label); if (!link || !Node_getBestParent(link->child)) { RumorMill_addNode(ic->rumorMill, &addr); } else { Log_debug(ic->logger, "link exists"); } ep->timeOfLastPing = Time_currentTimeMilliseconds(ic->eventBase); #ifdef Log_DEBUG // This will be false if it times out. //Assert_true(label == ep->switchLabel); uint8_t path[20]; AddrTools_printPath(path, resp->label); uint8_t sl[20]; AddrTools_printPath(sl, ep->switchLabel); Log_debug(ic->logger, "Received [%s] from lazy endpoint [%s] [%s]", SwitchPinger_resultString(resp->res)->bytes, path, sl); #endif }
struct Message* PeerLink_poll(struct PeerLink* peerLink) { struct PeerLink_pvt* pl = Identity_check((struct PeerLink_pvt*) peerLink); struct Message* out = ArrayList_Messages_shift(pl->queue); if (!out) { return NULL; } Allocator_disown(pl->alloc, out->alloc); Kbps_accumulate(&pl->sendBw, Time_currentTimeMilliseconds(pl->base), out->length); return out; }
// Incoming message which has passed through the cryptoauth and needs to be forwarded to the switch. static Iface_DEFUN receivedPostCryptoAuth(struct Message* msg, struct Peer* ep, struct InterfaceController_pvt* ic) { ep->bytesIn += msg->length; int caState = CryptoAuth_getState(ep->caSession); if (ep->state < InterfaceController_PeerState_ESTABLISHED) { // EP states track CryptoAuth states... ep->state = caState; SwitchCore_setInterfaceState(&ep->switchIf, SwitchCore_setInterfaceState_ifaceState_UP); Bits_memcpy(ep->addr.key, ep->caSession->herPublicKey, 32); Address_getPrefix(&ep->addr); if (caState == CryptoAuth_ESTABLISHED) { moveEndpointIfNeeded(ep); //sendPeer(0xffffffff, PFChan_Core_PEER, ep);// version is not known at this point. } else { // prevent some kinds of nasty things which could be done with packet replay. // This is checking the message switch header and will drop it unless the label // directs it to *this* router. if (msg->length < 8 || msg->bytes[7] != 1) { Log_info(ic->logger, "DROP message because CA is not established."); return 0; } else { // When a "server" gets a new connection from a "client" the router doesn't // know about that client so if the client sends a packet to the server, the // server will be unable to handle it until the client has sent inter-router // communication to the server. Here we will ping the client so when the // server gets the ping response, it will insert the client into its table // and know its version. // prevent DoS by limiting the number of times this can be called per second // limit it to 7, this will affect innocent packets but it doesn't matter much // since this is mostly just an optimization and for keeping the tests happy. if ((ep->pingCount + 1) % 7) { sendPing(ep); } } } } else if (ep->state == InterfaceController_PeerState_UNRESPONSIVE && caState == CryptoAuth_ESTABLISHED) { ep->state = InterfaceController_PeerState_ESTABLISHED; SwitchCore_setInterfaceState(&ep->switchIf, SwitchCore_setInterfaceState_ifaceState_UP); } else { ep->timeOfLastMessage = Time_currentTimeMilliseconds(ic->eventBase); } Identity_check(ep); Assert_true(!(msg->capacity % 4)); return Iface_next(&ep->switchIf, msg); }
// Incoming message which has passed through the cryptoauth and needs to be forwarded to the switch. static uint8_t receivedAfterCryptoAuth(struct Message* msg, struct Interface* cryptoAuthIf) { struct InterfaceController_Peer* ep = Identity_check((struct InterfaceController_Peer*) cryptoAuthIf->receiverContext); struct InterfaceController_pvt* ic = ifcontrollerForPeer(ep); // nonce added by the CryptoAuth session. Message_pop(msg, NULL, 4, NULL); ep->bytesIn += msg->length; int caState = CryptoAuth_getState(cryptoAuthIf); if (ep->state < InterfaceController_PeerState_ESTABLISHED) { // EP states track CryptoAuth states... ep->state = caState; if (caState == CryptoAuth_ESTABLISHED) { moveEndpointIfNeeded(ep, ic); } else { // prevent some kinds of nasty things which could be done with packet replay. // This is checking the message switch header and will drop it unless the label // directs it to *this* router. if (msg->length < 8 || msg->bytes[7] != 1) { Log_info(ic->logger, "DROP message because CA is not established."); return Error_NONE; } else { // When a "server" gets a new connection from a "client" the router doesn't // know about that client so if the client sends a packet to the server, the // server will be unable to handle it until the client has sent inter-router // communication to the server. Here we will ping the client so when the // server gets the ping response, it will insert the client into its table // and know its version. // prevent DoS by limiting the number of times this can be called per second // limit it to 7, this will affect innocent packets but it doesn't matter much // since this is mostly just an optimization and for keeping the tests happy. if ((ep->pingCount + 1) % 7) { sendPing(ep); } } } } else if (ep->state == InterfaceController_PeerState_UNRESPONSIVE && caState == CryptoAuth_ESTABLISHED) { ep->state = InterfaceController_PeerState_ESTABLISHED; } else { ep->timeOfLastMessage = Time_currentTimeMilliseconds(ic->eventBase); } Identity_check(ep); Assert_true(!(msg->capacity % 4)); return Interface_receiveMessage(&ep->switchIf, msg); }
// This is directly called from SwitchCore, message is not encrypted. static uint8_t sendFromSwitch(struct Message* msg, struct Interface* switchIf) { struct IFCPeer* ep = Identity_cast((struct IFCPeer*) switchIf); ep->bytesOut += msg->length; // This sucks but cryptoauth trashes the content when it encrypts // and we need to be capable of sending back a coherent error message. uint8_t top[255]; uint8_t* messageBytes = msg->bytes; uint16_t padding = msg->padding; uint16_t len = (msg->length < 255) ? msg->length : 255; Bits_memcpy(top, msg->bytes, len); struct Context* ic = ifcontrollerForPeer(ep); uint8_t ret; uint64_t now = Time_currentTimeMilliseconds(ic->eventBase); if (now - ep->timeOfLastMessage > ic->unresponsiveAfterMilliseconds) { // XXX: This is a hack because if the time of last message exceeds the // unresponsive time, we need to send back an error and that means // mangling the message which would otherwise be in the queue. struct Allocator* tempAlloc = Allocator_child(ic->allocator); struct Message* toSend = Message_clone(msg, tempAlloc); ret = Interface_sendMessage(ep->cryptoAuthIf, toSend); Allocator_free(tempAlloc); } else { ret = Interface_sendMessage(ep->cryptoAuthIf, msg); } // If this node is unresponsive then return an error. if (ret || now - ep->timeOfLastMessage > ic->unresponsiveAfterMilliseconds) { msg->bytes = messageBytes; msg->padding = padding; msg->length = len; Bits_memcpy(msg->bytes, top, len); return ret ? ret : Error_UNDELIVERABLE; } else { /* Way way way too much noise Log_debug(ic->logger, "Sending to neighbor, last message from this node was [%u] ms ago.", (now - ep->timeOfLastMessage)); */ } return Error_NONE; }
static uint8_t sendMessage(struct Message* msg, struct Interface* iface) { struct SessionManager_Session_pvt* ss = Identity_check((struct SessionManager_Session_pvt*)iface); uint64_t timeOfLastOut = ss->pub.timeOfLastOut; ss->pub.timeOfLastOut = Time_currentTimeMilliseconds(ss->sm->eventBase); int prevState = ss->pub.cryptoAuthState; ss->pub.cryptoAuthState = CryptoAuth_getState(ss->pub.internal); if ((ss->pub.timeOfLastOut - timeOfLastOut) > STATE_UPDATE_TIME || prevState != ss->pub.cryptoAuthState) { stateChange(ss, ss->pub.timeOfLastIn, timeOfLastOut, prevState); } return Interface_sendMessage(&ss->sm->iface, msg); }
// Called from the pingInteral timeout. static void pingCallback(void* vic) { struct Context* ic = Identity_cast((struct Context*) vic); uint64_t now = Time_currentTimeMilliseconds(ic->eventBase); ic->pingCount++; // scan for endpoints have not sent anything recently. for (uint32_t i = 0; i < ic->peerMap.count; i++) { struct IFCPeer* ep = ic->peerMap.values[i]; if (now > ep->timeOfLastMessage + ic->pingAfterMilliseconds) { #ifdef Log_DEBUG uint8_t key[56]; Base32_encode(key, 56, CryptoAuth_getHerPublicKey(ep->cryptoAuthIf), 32); #endif if (ep->transient && now > ep->timeOfLastMessage + ic->forgetAfterMilliseconds) { Log_debug(ic->logger, "Unresponsive peer [%s.k] has not responded in [%u] " "seconds, dropping connection", key, ic->forgetAfterMilliseconds / 1024); Allocator_free(ep->external->allocator); } else if (now > ep->timeOfLastMessage + ic->unresponsiveAfterMilliseconds) { // Lets skip 87% of pings when they're really down. if (ic->pingCount % 8) { continue; } ep->state = InterfaceController_PeerState_UNRESPONSIVE; uint32_t lag = ((now - ep->timeOfLastMessage) / 1024); Log_debug(ic->logger, "Pinging unresponsive peer [%s.k] lag [%u]", key, lag); } else { uint32_t lag = ((now - ep->timeOfLastMessage) / 1024); Log_debug(ic->logger, "Pinging lazy peer [%s] lag [%u]", key, lag); } struct SwitchPinger_Ping* ping = SwitchPinger_newPing(ep->switchLabel, String_CONST(""), ic->timeoutMilliseconds, onPingResponse, ic->switchPinger); ping->onResponseContext = ep; SwitchPinger_sendPing(ping); } } }
static uint8_t receiveMessage(struct Message* msg, struct Interface* iface) { struct SessionManager_Session_pvt* ss = Identity_check((struct SessionManager_Session_pvt*)iface->receiverContext); // nonce added by CryptoAuth Message_pop(msg, NULL, 4, NULL); uint64_t timeOfLastIn = ss->pub.timeOfLastIn; ss->pub.timeOfLastIn = Time_currentTimeMilliseconds(ss->sm->eventBase); int prevState = ss->pub.cryptoAuthState; ss->pub.cryptoAuthState = CryptoAuth_getState(ss->pub.internal); if ((ss->pub.timeOfLastIn - timeOfLastIn) > STATE_UPDATE_TIME || prevState != ss->pub.cryptoAuthState) { stateChange(ss, timeOfLastIn, ss->pub.timeOfLastOut, prevState); } return Interface_receiveMessage(&ss->sm->iface, msg); }
static void cleanup(void* vsm) { struct SessionManager* sm = (struct SessionManager*) vsm; uint64_t cutoffTime = Time_currentTimeMilliseconds(sm->eventBase) - (SESSION_TIMEOUT_SECONDS * 1000); for (uint32_t i = 0; i < sm->ifaceMap.count; i++) { struct SessionManager_Session* sess = &sm->ifaceMap.values[i]->pub; // Received a message since cutoff time. if (sess->timeOfLastIn > cutoffTime) { continue; } // Received a message (ever) or session is not older than cutoff time. if (sess->timeOfLastIn || sess->timeOfCreation > cutoffTime) { continue; } struct Allocator* ifAllocator = sess->external.allocator; Map_OfSessionsByIp6_remove(i, &sm->ifaceMap); Allocator_free(ifAllocator); i--; } }
/** * Send an arbitrary message to a node. * * @param message to be sent, must be prefixed with IpTunnel_PacketInfoHeader. * @param iface an interface for which receiverContext is the ducttape. */ static uint8_t sendToNode(struct Message* message, struct Interface* iface) { struct Ducttape_pvt* context = Identity_cast((struct Ducttape_pvt*)iface->receiverContext); struct Ducttape_MessageHeader* dtHeader = getDtHeader(message, true); struct IpTunnel_PacketInfoHeader* header = (struct IpTunnel_PacketInfoHeader*) message->bytes; Message_shift(message, -IpTunnel_PacketInfoHeader_SIZE); struct Node* n = RouterModule_lookup(header->nodeIp6Addr, context->routerModule); if (n) { if (!Bits_memcmp(header->nodeKey, n->address.key, 32)) { // Found the node. #ifdef Log_DEBUG uint8_t nhAddr[60]; Address_print(nhAddr, &n->address); Log_debug(context->logger, "Sending arbitrary data to [%s]", nhAddr); #endif struct SessionManager_Session* session = SessionManager_getSession(n->address.ip6.bytes, n->address.key, context->sm); n->version = session->version = (n->version > session->version) ? n->version : session->version; dtHeader->switchLabel = n->address.path; return sendToRouter(message, dtHeader, session, context); } } #ifdef Log_DEBUG uint8_t printedIp6[40]; AddrTools_printIp(printedIp6, header->nodeIp6Addr); Log_debug(context->logger, "Couldn't find node [%s] for sending to.", printedIp6); #endif // Now lets trigger a search for this node. uint64_t now = Time_currentTimeMilliseconds(context->eventBase); if (context->timeOfLastSearch + context->timeBetweenSearches < now) { context->timeOfLastSearch = now; RouterModule_search(header->nodeIp6Addr, context->routerModule, context->alloc); } return 0; }
static void onPingResponse(struct SwitchPinger_Response* resp, void* onResponseContext) { if (SwitchPinger_Result_OK != resp->res) { return; } struct Peer* ep = Identity_check((struct Peer*) onResponseContext); struct InterfaceController_pvt* ic = Identity_check(ep->ici->ic); ep->addr.protocolVersion = resp->version; if (Defined(Log_DEBUG)) { String* addr = Address_toString(&ep->addr, resp->ping->pingAlloc); if (!Version_isCompatible(Version_CURRENT_PROTOCOL, resp->version)) { Log_debug(ic->logger, "got switch pong from node [%s] with incompatible version", addr->bytes); } else if (ep->addr.path != resp->label) { uint8_t sl[20]; AddrTools_printPath(sl, resp->label); Log_debug(ic->logger, "got switch pong from node [%s] mismatch label [%s]", addr->bytes, sl); } else { Log_debug(ic->logger, "got switch pong from node [%s]", addr->bytes); } } if (!Version_isCompatible(Version_CURRENT_PROTOCOL, resp->version)) { return; } if (ep->state == InterfaceController_PeerState_ESTABLISHED) { sendPeer(0xffffffff, PFChan_Core_PEER, ep); } ep->timeOfLastPing = Time_currentTimeMilliseconds(ic->eventBase); if (Defined(Log_DEBUG)) { String* addr = Address_toString(&ep->addr, resp->ping->pingAlloc); Log_debug(ic->logger, "Received [%s] from lazy endpoint [%s]", SwitchPinger_resultString(resp->res)->bytes, addr->bytes); } }
// Incoming message which has passed through the cryptoauth and needs to be forwarded to the switch. static uint8_t receivedAfterCryptoAuth(struct Message* msg, struct Interface* cryptoAuthIf) { struct IFCPeer* ep = Identity_cast((struct IFCPeer*) cryptoAuthIf->receiverContext); struct Context* ic = ifcontrollerForPeer(ep); ep->bytesIn += msg->length; if (ep->state < InterfaceController_PeerState_ESTABLISHED) { if (CryptoAuth_getState(cryptoAuthIf) >= CryptoAuth_HANDSHAKE3) { moveEndpointIfNeeded(ep, ic); ep->state = InterfaceController_PeerState_ESTABLISHED; } else { ep->state = InterfaceController_PeerState_HANDSHAKE; // prevent some kinds of nasty things which could be done with packet replay. // This is checking the message switch header and will drop it unless the label // directs it to *this* router. if (msg->length < 8 || msg->bytes[7] != 1) { Log_info(ic->logger, "Dropping message because CA is not established."); return Error_NONE; } else { // When a "server" gets a new connection from a "client" the router doesn't // know about that client so if the client sends a packet to the server, the // server will be unable to handle it until the client has sent inter-router // communication to the server. Here we will ping the client so when the // server gets the ping response, it will insert the client into its table // and know its version. pingCallback(ic); } } } else if (ep->state == InterfaceController_PeerState_UNRESPONSIVE && CryptoAuth_getState(cryptoAuthIf) >= CryptoAuth_HANDSHAKE3) { ep->state = InterfaceController_PeerState_ESTABLISHED; } else { ep->timeOfLastMessage = Time_currentTimeMilliseconds(ic->eventBase); } return ep->switchIf.receiveMessage(msg, &ep->switchIf); }
static void start(struct Allocator* alloc, struct Log* logger, struct EventBase* base, struct Random* rand, RunTest* runTest) { struct TestFramework* a = TestFramework_setUp("\xad\x7e\xa3\x26\xaa\x01\x94\x0a\x25\xbc\x9e\x01\x26\x22\xdb\x69" "\x4f\xd9\xb4\x17\x7c\xf3\xf8\x91\x16\xf3\xcf\xe8\x5c\x80\xe1\x4a", alloc, base, rand, logger); //"publicKey": "kmzm4w0kj9bswd5qmx74nu7kusv5pj40vcsmp781j6xxgpd59z00.k", //"ipv6": "fc41:94b5:0925:7ba9:3959:11ab:a006:367a", struct TestFramework* b = TestFramework_setUp("\xd8\x54\x3e\x70\xb9\xae\x7c\x41\xbc\x18\xa4\x9a\x9c\xee\xca\x9c" "\xdc\x45\x01\x96\x6b\xbd\x7e\x76\xcf\x3a\x9f\xbc\x12\xed\x8b\xb4", alloc, base, rand, logger); //"publicKey": "vz21tg07061s8v9mckrvgtfds7j2u5lst8cwl6nqhp81njrh5wg0.k", //"ipv6": "fc1f:5b96:e1c5:625d:afde:2523:a7fa:383a", struct TwoNodes* out = Allocator_calloc(alloc, sizeof(struct TwoNodes), 1); Identity_set(out); out->tunB.send = incomingTunB; out->tunA.send = incomingTunA; Iface_plumb(&out->tunB, b->tunIf); Iface_plumb(&out->tunA, a->tunIf); out->nodeB = b; out->nodeA = a; out->logger = logger; out->checkLinkageTimeout = Timeout_setInterval(checkLinkage, out, 1, base, alloc); out->base = base; out->startTime = Time_currentTimeMilliseconds(base); out->runTest = runTest; Log_debug(a->logger, "Waiting for nodes to link asynchronously..."); }
/** * Check the table for nodes which might need to be pinged, ping a node if necessary. * If a node has not responded in unresponsiveAfterMilliseconds then mark them as unresponsive * and if the connection is incoming and the node has not responded in forgetAfterMilliseconds * then drop them entirely. * This is called every PING_INTERVAL_MILLISECONDS but pingCallback is a misleading name. */ static void pingCallback(void* vic) { struct InterfaceController_pvt* ic = Identity_check((struct InterfaceController_pvt*) vic); if (!ic->peerMap.count) { return; } uint64_t now = Time_currentTimeMilliseconds(ic->eventBase); // scan for endpoints have not sent anything recently. uint32_t startAt = Random_uint32(ic->rand) % ic->peerMap.count; for (uint32_t i = startAt, count = 0; (!count || i != startAt) && count <= ic->peerMap.count;) { i = (i + 1) % ic->peerMap.count; count++; struct InterfaceController_Peer* ep = ic->peerMap.values[i]; if (now < ep->timeOfLastMessage + ic->pingAfterMilliseconds) { if (now < ep->timeOfLastPing + ic->pingAfterMilliseconds) { // Possibly an out-of-date node which is mangling packets, don't ping too often // because it causes the RumorMill to be filled with this node over and over. continue; } struct Node_Link* link = Router_linkForPath(ic->router, ep->switchLabel); // It exists, it's parent is the self-node, and it's label is equal to the switchLabel. if (link && Node_getBestParent(link->child) && Node_getBestParent(link->child)->parent->address.path == 1 && Node_getBestParent(link->child)->cannonicalLabel == ep->switchLabel) { continue; } } #ifdef Log_DEBUG uint8_t key[56]; Base32_encode(key, 56, CryptoAuth_getHerPublicKey(ep->cryptoAuthIf), 32); #endif if (ep->isIncomingConnection && now > ep->timeOfLastMessage + ic->forgetAfterMilliseconds) { Log_debug(ic->logger, "Unresponsive peer [%s.k] has not responded in [%u] " "seconds, dropping connection", key, ic->forgetAfterMilliseconds / 1024); Allocator_free(ep->external->allocator); continue; } bool unresponsive = (now > ep->timeOfLastMessage + ic->unresponsiveAfterMilliseconds); if (unresponsive) { // our link to the peer is broken... Router_disconnectedPeer(ic->router, ep->switchLabel); // Lets skip 87% of pings when they're really down. if (ep->pingCount % 8) { ep->pingCount++; continue; } ep->state = InterfaceController_PeerState_UNRESPONSIVE; } #ifdef Log_DEBUG uint32_t lag = (now - ep->timeOfLastMessage) / 1024; Log_debug(ic->logger, "Pinging %s peer [%s.k] lag [%u]", (unresponsive ? "unresponsive" : "lazy"), key, lag); #endif sendPing(ep); // we only ping one node return; } }
static void pingCycle(void* vsn) { struct SupernodeHunter_pvt* snp = Identity_check((struct SupernodeHunter_pvt*) vsn); if (snp->pub.snodeIsReachable) { return; } if (!snp->authorizedSnodes->length) { return; } if (!snp->peers->length) { return; } Log_debug(snp->log, "\n\nping cycle\n\n"); // We're not handling replies... struct MsgCore_Promise* qp = MsgCore_createQuery(snp->msgCore, 0, snp->alloc); struct Query* q = Allocator_calloc(qp->alloc, sizeof(struct Query), 1); Identity_set(q); q->snp = snp; q->sendTime = Time_currentTimeMilliseconds(snp->base); Dict* msg = qp->msg = Dict_new(qp->alloc); qp->cb = onReply; qp->userData = q; bool isGetPeers = snp->nodeListIndex & 1; int idx = snp->nodeListIndex++ >> 1; for (;;) { if (idx < snp->peers->length) { qp->target = AddrSet_get(snp->peers, idx); break; } idx -= snp->peers->length; if (idx < snp->nodes->length) { qp->target = AddrSet_get(snp->nodes, idx); break; } snp->snodeAddrIdx++; idx -= snp->nodes->length; } struct Address* snode = AddrSet_get(snp->authorizedSnodes, snp->snodeAddrIdx % snp->authorizedSnodes->length); if (Address_isSameIp(snode, qp->target)) { // Supernode is a peer... AddrSet_add(snp->snodeCandidates, qp->target); } if (snp->snodeCandidates->length) { qp->target = AddrSet_get(snp->snodeCandidates, snp->snodeCandidates->length - 1); Log_debug(snp->log, "Sending getRoute to snode %s", Address_toString(qp->target, qp->alloc)->bytes); Dict_putStringCC(msg, "sq", "gr", qp->alloc); Dict_putStringC(msg, "src", snp->selfAddrStr, qp->alloc); String* target = String_newBinary(qp->target->ip6.bytes, 16, qp->alloc); Dict_putStringC(msg, "tar", target, qp->alloc); q->isGetRoute = true; return; } if (isGetPeers) { Log_debug(snp->log, "Sending getPeers to %s", Address_toString(qp->target, qp->alloc)->bytes); Dict_putStringCC(msg, "q", "gp", qp->alloc); Dict_putStringC(msg, "tar", String_newBinary("\0\0\0\0\0\0\0\1", 8, qp->alloc), qp->alloc); } else { q->searchTar = Address_clone(snode, qp->alloc); Log_debug(snp->log, "Sending findNode to %s", Address_toString(qp->target, qp->alloc)->bytes); Dict_putStringCC(msg, "q", "fn", qp->alloc); Dict_putStringC(msg, "tar", String_newBinary(snode->ip6.bytes, 16, qp->alloc), qp->alloc); } }
int InterfaceController_bootstrapPeer(struct InterfaceController* ifc, int interfaceNumber, uint8_t* herPublicKey, const struct Sockaddr* lladdrParm, String* password, String* login, String* user, struct Allocator* alloc) { struct InterfaceController_pvt* ic = Identity_check((struct InterfaceController_pvt*) ifc); Assert_true(herPublicKey); Assert_true(password); struct InterfaceController_Iface_pvt* ici = ArrayList_OfIfaces_get(ic->icis, interfaceNumber); if (!ici) { return InterfaceController_bootstrapPeer_BAD_IFNUM; } Log_debug(ic->logger, "bootstrapPeer total [%u]", ici->peerMap.count); uint8_t ip6[16]; AddressCalc_addressForPublicKey(ip6, herPublicKey); if (!AddressCalc_validAddress(ip6) || !Bits_memcmp(ic->ca->publicKey, herPublicKey, 32)) { return InterfaceController_bootstrapPeer_BAD_KEY; } struct Allocator* epAlloc = Allocator_child(ici->alloc); struct Sockaddr* lladdr = Sockaddr_clone(lladdrParm, epAlloc); // TODO(cjd): eps are created in 3 places, there should be a factory function. struct Peer* ep = Allocator_calloc(epAlloc, sizeof(struct Peer), 1); int index = Map_EndpointsBySockaddr_put(&lladdr, &ep, &ici->peerMap); Assert_true(index >= 0); ep->alloc = epAlloc; ep->handle = ici->peerMap.handles[index]; ep->lladdr = lladdr; ep->ici = ici; ep->isIncomingConnection = false; Bits_memcpy(ep->addr.key, herPublicKey, 32); Address_getPrefix(&ep->addr); Identity_set(ep); Allocator_onFree(epAlloc, closeInterface, ep); Allocator_onFree(alloc, freeAlloc, epAlloc); ep->peerLink = PeerLink_new(ic->eventBase, epAlloc); ep->caSession = CryptoAuth_newSession(ic->ca, epAlloc, herPublicKey, false, "outer"); CryptoAuth_setAuth(password, login, ep->caSession); if (user) { ep->caSession->displayName = String_clone(user, epAlloc); } ep->switchIf.send = sendFromSwitch; if (SwitchCore_addInterface(ic->switchCore, &ep->switchIf, epAlloc, &ep->addr.path)) { Log_debug(ic->logger, "bootstrapPeer() SwitchCore out of space"); Allocator_free(epAlloc); return InterfaceController_bootstrapPeer_OUT_OF_SPACE; } // We want the node to immedietly be pinged but we don't want it to appear unresponsive because // the pinger will only ping every (PING_INTERVAL * 8) so we set timeOfLastMessage to // (now - pingAfterMilliseconds - 1) so it will be considered a "lazy node". ep->timeOfLastMessage = Time_currentTimeMilliseconds(ic->eventBase) - ic->pingAfterMilliseconds - 1; if (Defined(Log_INFO)) { struct Allocator* tempAlloc = Allocator_child(alloc); String* addrStr = Address_toString(&ep->addr, tempAlloc); Log_info(ic->logger, "Adding peer [%s] from bootstrapPeer()", addrStr->bytes); Allocator_free(tempAlloc); } // We can't just add the node directly to the routing table because we do not know // the version. We'll send it a switch ping and when it responds, we will know it's // key (if we don't already) and version number. sendPing(ep); return 0; }
void PeerLink_recv(struct Message* msg, struct PeerLink* peerLink) { struct PeerLink_pvt* pl = Identity_check((struct PeerLink_pvt*) peerLink); Kbps_accumulate(&pl->recvBw, Time_currentTimeMilliseconds(pl->base), msg->length); }
// Called from the pingInteral timeout. static void pingCallback(void* vic) { struct Context* ic = Identity_cast((struct Context*) vic); uint64_t now = Time_currentTimeMilliseconds(ic->eventBase); ic->pingCount++; // scan for endpoints have not sent anything recently. for (uint32_t i = 0; i < ic->peerMap.count; i++) { struct IFCPeer* ep = ic->peerMap.values[i]; // This is here because of a pathological state where the connection is in ESTABLISHED // state but the *direct peer* has somehow been dropped from the routing table. // TODO: understand the cause of this issue rather than checking for it once per second. struct Node* peerNode = RouterModule_getNode(ep->switchLabel, ic->routerModule); if (now > ep->timeOfLastMessage + ic->pingAfterMilliseconds || !peerNode) { #ifdef Log_DEBUG uint8_t key[56]; Base32_encode(key, 56, CryptoAuth_getHerPublicKey(ep->cryptoAuthIf), 32); #endif if (ep->isIncomingConnection && now > ep->timeOfLastMessage + ic->forgetAfterMilliseconds) { Log_debug(ic->logger, "Unresponsive peer [%s.k] has not responded in [%u] " "seconds, dropping connection", key, ic->forgetAfterMilliseconds / 1024); Allocator_free(ep->external->allocator); return; } bool unresponsive = (now > ep->timeOfLastMessage + ic->unresponsiveAfterMilliseconds); uint32_t lag = ~0u; if (unresponsive) { // flush the peer from the table... RouterModule_brokenPath(ep->switchLabel, ic->routerModule); // Lets skip 87% of pings when they're really down. if (ic->pingCount % 8) { continue; } ep->state = InterfaceController_PeerState_UNRESPONSIVE; lag = ((now - ep->timeOfLastMessage) / 1024); } else { lag = ((now - ep->timeOfLastMessage) / 1024); } struct SwitchPinger_Ping* ping = SwitchPinger_newPing(ep->switchLabel, String_CONST(""), ic->timeoutMilliseconds, onPingResponse, ic->allocator, ic->switchPinger); if (!ping) { Log_debug(ic->logger, "Failed to ping %s peer [%s.k] lag [%u], out of ping slots.", (unresponsive ? "unresponsive" : "lazy"), key, lag); return; } ping->onResponseContext = ep; SwitchPinger_sendPing(ping); Log_debug(ic->logger, "Pinging %s peer [%s.k] lag [%u]", (unresponsive ? "unresponsive" : "lazy"), key, lag); } } }
/** * Expects [ struct LLAddress ][ beacon ] */ static Iface_DEFUN handleBeacon(struct Message* msg, struct InterfaceController_Iface_pvt* ici) { struct InterfaceController_pvt* ic = ici->ic; if (!ici->beaconState) { // accepting beacons disabled. Log_debug(ic->logger, "[%s] Dropping beacon because beaconing is disabled", ici->name->bytes); return NULL; } if (msg->length < Headers_Beacon_SIZE) { Log_debug(ic->logger, "[%s] Dropping runt beacon", ici->name->bytes); return NULL; } struct Sockaddr* lladdrInmsg = (struct Sockaddr*) msg->bytes; // clear the bcast flag lladdrInmsg->flags = 0; Message_shift(msg, -lladdrInmsg->addrLen, NULL); struct Headers_Beacon beacon; Message_pop(msg, &beacon, Headers_Beacon_SIZE, NULL); if (Defined(Log_DEBUG)) { char* content = Hex_print(&beacon, Headers_Beacon_SIZE, msg->alloc); Log_debug(ici->ic->logger, "RECV BEACON CONTENT[%s]", content); } struct Address addr; Bits_memset(&addr, 0, sizeof(struct Address)); Bits_memcpy(addr.key, beacon.publicKey, 32); addr.protocolVersion = Endian_bigEndianToHost32(beacon.version_be); Address_getPrefix(&addr); String* printedAddr = NULL; if (Defined(Log_DEBUG)) { printedAddr = Address_toString(&addr, msg->alloc); } if (addr.ip6.bytes[0] != 0xfc || !Bits_memcmp(ic->ca->publicKey, addr.key, 32)) { Log_debug(ic->logger, "handleBeacon invalid key [%s]", printedAddr->bytes); return NULL; } if (!Version_isCompatible(addr.protocolVersion, Version_CURRENT_PROTOCOL)) { if (Defined(Log_DEBUG)) { Log_debug(ic->logger, "[%s] DROP beacon from [%s] which was version [%d] " "our version is [%d] making them incompatable", ici->name->bytes, printedAddr->bytes, addr.protocolVersion, Version_CURRENT_PROTOCOL); } return NULL; } String* beaconPass = String_newBinary(beacon.password, Headers_Beacon_PASSWORD_LEN, msg->alloc); int epIndex = Map_EndpointsBySockaddr_indexForKey(&lladdrInmsg, &ici->peerMap); if (epIndex > -1) { // The password might have changed! struct Peer* ep = ici->peerMap.values[epIndex]; CryptoAuth_setAuth(beaconPass, NULL, ep->caSession); return NULL; } struct Allocator* epAlloc = Allocator_child(ici->alloc); struct Peer* ep = Allocator_calloc(epAlloc, sizeof(struct Peer), 1); struct Sockaddr* lladdr = Sockaddr_clone(lladdrInmsg, epAlloc); ep->alloc = epAlloc; ep->ici = ici; ep->lladdr = lladdr; int setIndex = Map_EndpointsBySockaddr_put(&lladdr, &ep, &ici->peerMap); ep->handle = ici->peerMap.handles[setIndex]; ep->isIncomingConnection = true; Bits_memcpy(&ep->addr, &addr, sizeof(struct Address)); Identity_set(ep); Allocator_onFree(epAlloc, closeInterface, ep); ep->peerLink = PeerLink_new(ic->eventBase, epAlloc); ep->caSession = CryptoAuth_newSession(ic->ca, epAlloc, beacon.publicKey, false, "outer"); CryptoAuth_setAuth(beaconPass, NULL, ep->caSession); ep->switchIf.send = sendFromSwitch; if (SwitchCore_addInterface(ic->switchCore, &ep->switchIf, epAlloc, &ep->addr.path)) { Log_debug(ic->logger, "handleBeacon() SwitchCore out of space"); Allocator_free(epAlloc); return NULL; } // We want the node to immedietly be pinged but we don't want it to appear unresponsive because // the pinger will only ping every (PING_INTERVAL * 8) so we set timeOfLastMessage to // (now - pingAfterMilliseconds - 1) so it will be considered a "lazy node". ep->timeOfLastMessage = Time_currentTimeMilliseconds(ic->eventBase) - ic->pingAfterMilliseconds - 1; Log_info(ic->logger, "Added peer [%s] from beacon", Address_toString(&ep->addr, msg->alloc)->bytes); // This should be safe because this is an outgoing request and we're sure the node will not // be relocated by moveEndpointIfNeeded() sendPeer(0xffffffff, PFChan_Core_PEER, ep); return NULL; }
if (ifaceIndex == -1) { struct Allocator* ifAlloc = Allocator_child(sm->allocator); struct SessionManager_Session_pvt* ss = Allocator_clone(ifAlloc, (&(struct SessionManager_Session_pvt) { .pub = { .version = Version_DEFAULT_ASSUMPTION, .external = { .sendMessage = sendMessage, .allocator = ifAlloc }, }, .sm = sm })); Identity_set(ss); ss->pub.timeOfCreation = Time_currentTimeMilliseconds(sm->eventBase); // const hack Bits_memcpyConst((void*)&ss->pub.external.senderContext, &ss, sizeof(char*)); Bits_memcpyConst(ss->pub.ip6, lookupKey, 16); ss->pub.internal = CryptoAuth_wrapInterface(&ss->pub.external, cryptoKey, lookupKey, false, "inner", sm->cryptoAuth); ss->pub.internal->receiveMessage = receiveMessage; ss->pub.internal->receiverContext = ss;
static void iciPing(struct InterfaceController_Iface_pvt* ici, struct InterfaceController_pvt* ic) { if (!ici->peerMap.count) { return; } uint64_t now = Time_currentTimeMilliseconds(ic->eventBase); // scan for endpoints have not sent anything recently. uint32_t startAt = Random_uint32(ic->rand) % ici->peerMap.count; for (uint32_t i = startAt, count = 0; count < ici->peerMap.count;) { i = (i + 1) % ici->peerMap.count; count++; struct Peer* ep = ici->peerMap.values[i]; if (now < ep->timeOfLastMessage + ic->pingAfterMilliseconds) { if (now < ep->timeOfLastPing + ic->pingAfterMilliseconds) { // Possibly an out-of-date node which is mangling packets, don't ping too often // because it causes the RumorMill to be filled with this node over and over. continue; } } uint8_t keyIfDebug[56]; if (Defined(Log_DEBUG)) { Base32_encode(keyIfDebug, 56, ep->caSession->herPublicKey, 32); } if (ep->isIncomingConnection && now > ep->timeOfLastMessage + ic->forgetAfterMilliseconds) { Log_debug(ic->logger, "Unresponsive peer [%s.k] has not responded in [%u] " "seconds, dropping connection", keyIfDebug, ic->forgetAfterMilliseconds / 1024); sendPeer(0xffffffff, PFChan_Core_PEER_GONE, ep); Allocator_free(ep->alloc); continue; } bool unresponsive = (now > ep->timeOfLastMessage + ic->unresponsiveAfterMilliseconds); if (unresponsive) { // our link to the peer is broken... // Lets skip 87% of pings when they're really down. if (ep->pingCount % 8) { ep->pingCount++; continue; } sendPeer(0xffffffff, PFChan_Core_PEER_GONE, ep); ep->state = InterfaceController_PeerState_UNRESPONSIVE; SwitchCore_setInterfaceState(&ep->switchIf, SwitchCore_setInterfaceState_ifaceState_DOWN); } Log_debug(ic->logger, "Pinging %s peer [%s.k] lag [%u]", (unresponsive ? "unresponsive" : "lazy"), keyIfDebug, (uint32_t)((now - ep->timeOfLastMessage) / 1024)); sendPing(ep); // we only ping one node return; } }
uint64_t Time_currentTimeSeconds(struct EventBase* eventBase) { return Time_currentTimeMilliseconds(eventBase) / 1024; }