static inline bool validEncryptedIP6(struct Message* message) { struct Headers_IP6Header* header = (struct Headers_IP6Header*) message->bytes; // Empty ipv6 headers are tolerated at this stage but dropped later. return message->length >= Headers_IP6Header_SIZE && AddressCalc_validAddress(header->sourceAddr) && AddressCalc_validAddress(header->destinationAddr); }
static int incomingFromDHT(struct DHTMessage* dmessage, void* vpf) { struct Pathfinder_pvt* pf = Identity_check((struct Pathfinder_pvt*) vpf); struct Message* msg = dmessage->binMessage; struct Address* addr = dmessage->address; if (addr->path == 1) { // Message to myself, can't handle this later because encrypting a message to yourself // causes problems. DHTModuleRegistry_handleIncoming(dmessage, pf->registry); return 0; } // Sanity check (make sure the addr was actually calculated) Assert_true(AddressCalc_validAddress(addr->ip6.bytes)); Message_shift(msg, PFChan_Msg_MIN_SIZE, NULL); struct PFChan_Msg* emsg = (struct PFChan_Msg*) msg->bytes; Bits_memset(emsg, 0, PFChan_Msg_MIN_SIZE); DataHeader_setVersion(&emsg->data, DataHeader_CURRENT_VERSION); DataHeader_setContentType(&emsg->data, ContentType_CJDHT); Bits_memcpy(emsg->route.ip6, addr->ip6.bytes, 16); emsg->route.version_be = Endian_hostToBigEndian32(addr->protocolVersion); emsg->route.sh.label_be = Endian_hostToBigEndian64(addr->path); emsg->route.flags |= RouteHeader_flags_PATHFINDER; SwitchHeader_setVersion(&emsg->route.sh, SwitchHeader_CURRENT_VERSION); Bits_memcpy(emsg->route.publicKey, addr->key, 32); Assert_true(!Bits_isZero(emsg->route.publicKey, 32)); Assert_true(emsg->route.sh.label_be); Assert_true(emsg->route.version_be); Message_push32(msg, PFChan_Pathfinder_SENDMSG, NULL); if (dmessage->replyTo) { // see incomingMsg dmessage->replyTo->pleaseRespond = true; //Log_debug(pf->log, "send DHT reply"); return 0; } //Log_debug(pf->log, "send DHT request"); Iface_send(&pf->pub.eventIf, msg); return 0; }
int Key_parse(String* key, uint8_t keyBytesOut[32], uint8_t ip6Out[16]) { if (!key || key->len < 52) { return Key_parse_TOO_SHORT; } if (key->bytes[52] != '.' || key->bytes[53] != 'k') { return Key_parse_MALFORMED; } if (Base32_decode(keyBytesOut, 32, (uint8_t*)key->bytes, 52) != 32) { return Key_parse_DECODE_FAILED; } if (ip6Out) { AddressCalc_addressForPublicKey(ip6Out, keyBytesOut); if (!AddressCalc_validAddress(ip6Out)) { return Key_parse_INVALID; } } return 0; }
static void mkNextRequest(struct ReachabilityCollector_pvt* rcp) { struct PeerInfo_pvt* pi = NULL; for (int i = 0; i < rcp->piList->length; i++) { pi = ArrayList_OfPeerInfo_pvt_get(rcp->piList, i); if (pi->pub.querying && !pi->waitForResponse) { break; } } if (!pi || !pi->pub.querying) { Log_debug(rcp->log, "All [%u] peers have been queried", rcp->piList->length); return; } if (pi->waitForResponse) { Log_debug(rcp->log, "Peer is waiting for response."); return; } struct MsgCore_Promise* query = MsgCore_createQuery(rcp->msgCore, TIMEOUT_MILLISECONDS, rcp->alloc); struct Query* q = Allocator_calloc(query->alloc, sizeof(struct Query), 1); q->rcp = rcp; q->addr = Address_toString(&pi->pub.addr, query->alloc); query->userData = q; query->cb = onReply; Assert_true(AddressCalc_validAddress(pi->pub.addr.ip6.bytes)); query->target = Address_clone(&pi->pub.addr, query->alloc); Dict* d = query->msg = Dict_new(query->alloc); Dict_putStringCC(d, "q", "gp", query->alloc); uint64_t label_be = Endian_hostToBigEndian64(pi->pathToCheck); uint8_t nearbyLabelBytes[8]; Bits_memcpy(nearbyLabelBytes, &label_be, 8); AddrTools_printPath(q->targetPath, pi->pathToCheck); Log_debug(rcp->log, "Getting peers for peer [%s] tar [%s]", q->addr->bytes, q->targetPath); Dict_putStringC(d, "tar", String_newBinary(nearbyLabelBytes, 8, query->alloc), query->alloc); BoilerplateResponder_addBoilerplate(rcp->br, d, &pi->pub.addr, query->alloc); pi->waitForResponse = true; }
int InterfaceController_registerPeer(struct InterfaceController* ifController, uint8_t herPublicKey[32], String* password, bool requireAuth, bool isIncomingConnection, struct Interface* externalInterface) { // This function is overridden by some tests... if (ifController->registerPeer) { return ifController->registerPeer(ifController, herPublicKey, password, requireAuth, isIncomingConnection, externalInterface); } struct InterfaceController_pvt* ic = Identity_check((struct InterfaceController_pvt*) ifController); if (Map_OfIFCPeerByExernalIf_indexForKey(&externalInterface, &ic->peerMap) > -1) { return 0; } Log_debug(ic->logger, "registerPeer [%p] total [%u]", (void*)externalInterface, ic->peerMap.count); uint8_t ip6[16]; if (herPublicKey) { AddressCalc_addressForPublicKey(ip6, herPublicKey); if (!AddressCalc_validAddress(ip6)) { return InterfaceController_registerPeer_BAD_KEY; } if (!Bits_memcmp(ic->ca->publicKey, herPublicKey, 32)) { // can't link with yourself, wiseguy return InterfaceController_registerPeer_BAD_KEY; } } else { Assert_true(requireAuth); } struct Allocator* epAllocator = externalInterface->allocator; struct InterfaceController_Peer* ep = Allocator_calloc(epAllocator, sizeof(struct InterfaceController_Peer), 1); ep->bytesOut = 0; ep->bytesIn = 0; ep->external = externalInterface; int setIndex = Map_OfIFCPeerByExernalIf_put(&externalInterface, &ep, &ic->peerMap); ep->handle = ic->peerMap.handles[setIndex]; Identity_set(ep); Allocator_onFree(epAllocator, closeInterface, ep); // If the other end need needs to supply a valid password to connect // we will set the connection state to UNAUTHENTICATED so that if the // packet is invalid, the connection will be dropped right away. if (requireAuth) { ep->state = InterfaceController_PeerState_UNAUTHENTICATED; } ep->cryptoAuthIf = CryptoAuth_wrapInterface(externalInterface, herPublicKey, NULL, requireAuth, "outer", ic->ca); ep->cryptoAuthIf->receiveMessage = receivedAfterCryptoAuth; ep->cryptoAuthIf->receiverContext = ep; // Always use authType 1 until something else comes along, then we'll have to refactor. if (password) { CryptoAuth_setAuth(password, 1, ep->cryptoAuthIf); } ep->isIncomingConnection = isIncomingConnection; Bits_memcpyConst(&ep->switchIf, (&(struct Interface) { .sendMessage = sendFromSwitch, // ifcontrollerForPeer uses this. // sendFromSwitch relies on the fact that the // switchIf is the same memory location as the Peer. .senderContext = ic, .allocator = epAllocator }), sizeof(struct Interface));
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; }
/** * For serializing and parsing responses to getPeers and search requests. */ struct Address_List* ReplySerializer_parse(struct Address* fromNode, Dict* result, struct Log* log, bool splicePath, struct Allocator* alloc) { String* nodes = Dict_getString(result, CJDHTConstants_NODES); if (!nodes) { return NULL; } if (nodes->len == 0 || nodes->len % Address_SERIALIZED_SIZE != 0) { Log_debug(log, "Dropping unrecognized reply"); return NULL; } struct VersionList* versions = NULL; String* versionsStr = Dict_getString(result, CJDHTConstants_NODE_PROTOCOLS); if (versionsStr) { versions = VersionList_parse(versionsStr, alloc); } if (!versions || versions->length != (nodes->len / Address_SERIALIZED_SIZE)) { Log_debug(log, "Reply with missing or invalid versions"); return NULL; } struct Address_List* out = Address_List_new(versions->length, alloc); uint32_t j = 0; for (uint32_t i = 0; nodes && i < nodes->len; i += Address_SERIALIZED_SIZE) { struct Address addr = { .path = 0 }; Address_parse(&addr, (uint8_t*) &nodes->bytes[i]); addr.protocolVersion = versions->versions[i / Address_SERIALIZED_SIZE]; // calculate the ipv6 Address_getPrefix(&addr); if (splicePath) { // We need to splice the given address on to the end of the // address of the node which gave it to us. uint64_t path = LabelSplicer_splice(addr.path, fromNode->path); if (path == UINT64_MAX) { /* common, lots of noise uint8_t discovered[60]; uint8_t fromAddr[60]; Address_print(discovered, &addr); Address_print(fromAddr, fromNode); Log_debug(log, "Dropping response [%s] from [%s] because route could not be spliced", discovered, fromAddr);*/ continue; } addr.path = path; } /*#ifdef Log_DEBUG uint8_t printedAddr[60]; Address_print(printedAddr, &addr); Log_debug(log, "discovered node [%s]", printedAddr); #endif*/ Address_getPrefix(&addr); if (!AddressCalc_validAddress(addr.ip6.bytes)) { struct Allocator* tmpAlloc = Allocator_child(alloc); String* printed = Address_toString(&addr, tmpAlloc); uint8_t ipPrinted[40]; Address_printIp(ipPrinted, &addr); Log_debug(log, "Was told garbage addr [%s] [%s]", printed->bytes, ipPrinted); Allocator_free(tmpAlloc); // This should never happen, badnode. continue; } Bits_memcpy(&out->elems[j++], &addr, sizeof(struct Address)); } out->length = j; return out; } void ReplySerializer_serialize(struct Address_List* addrs, Dict* out, struct Address* convertDirectorFor, struct Allocator* alloc) { if (!addrs->length) { return; } String* nodes = String_newBinary(NULL, addrs->length * Address_SERIALIZED_SIZE, alloc); struct VersionList* versions = VersionList_new(addrs->length, alloc); for (int i = 0; i < addrs->length; i++) { versions->versions[i] = addrs->elems[i].protocolVersion; if (!convertDirectorFor) { Address_serialize(&nodes->bytes[i * Address_SERIALIZED_SIZE], &addrs->elems[i]); } else { struct Address addr; Bits_memcpy(&addr, &addrs->elems[i], sizeof(struct Address)); addr.path = NumberCompress_getLabelFor(addr.path, convertDirectorFor->path); Address_serialize(&nodes->bytes[i * Address_SERIALIZED_SIZE], &addr); } } Dict_putStringC(out, "n", nodes, alloc); Dict_putStringC(out, "np", VersionList_stringify(versions, alloc), alloc); }
static Iface_DEFUN incomingFromTunIf(struct Message* msg, struct Iface* tunIf) { struct TUNAdapter_pvt* ud = Identity_containerOf(tunIf, struct TUNAdapter_pvt, pub.tunIf); uint16_t ethertype = TUNMessageType_pop(msg, NULL); int version = Headers_getIpVersion(msg->bytes); if ((ethertype == Ethernet_TYPE_IP4 && version != 4) || (ethertype == Ethernet_TYPE_IP6 && version != 6)) { Log_debug(ud->log, "DROP packet because ip version [%d] " "doesn't match ethertype [%u].", version, Endian_bigEndianToHost16(ethertype)); return NULL; } if (ethertype == Ethernet_TYPE_IP4) { return Iface_next(&ud->pub.ipTunnelIf, msg); } if (ethertype != Ethernet_TYPE_IP6) { Log_debug(ud->log, "DROP packet unknown ethertype [%u]", Endian_bigEndianToHost16(ethertype)); return NULL; } if (msg->length < Headers_IP6Header_SIZE) { Log_debug(ud->log, "DROP runt"); return NULL; } struct Headers_IP6Header* header = (struct Headers_IP6Header*) msg->bytes; if (!AddressCalc_validAddress(header->destinationAddr)) { return Iface_next(&ud->pub.ipTunnelIf, msg); } if (Bits_memcmp(header->sourceAddr, ud->myIp6, 16)) { if (Defined(Log_DEBUG)) { uint8_t expectedSource[40]; AddrTools_printIp(expectedSource, ud->myIp6); uint8_t packetSource[40]; AddrTools_printIp(packetSource, header->sourceAddr); Log_debug(ud->log, "DROP packet from [%s] because all messages must have source address [%s]", packetSource, expectedSource); } return NULL; } if (!Bits_memcmp(header->destinationAddr, ud->myIp6, 16)) { // I'm Gonna Sit Right Down and Write Myself a Letter TUNMessageType_push(msg, ethertype, NULL); return Iface_next(tunIf, msg); } if (!Bits_memcmp(header->destinationAddr, "\xfc\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01", 16)) { return Iface_next(&ud->pub.magicIf, msg); } // first move the dest addr to the right place. Bits_memmoveConst(&header->destinationAddr[-DataHeader_SIZE], header->destinationAddr, 16); Message_shift(msg, DataHeader_SIZE + RouteHeader_SIZE - Headers_IP6Header_SIZE, NULL); struct RouteHeader* rh = (struct RouteHeader*) msg->bytes; struct DataHeader* dh = (struct DataHeader*) &rh[1]; Bits_memset(dh, 0, DataHeader_SIZE); DataHeader_setContentType(dh, header->nextHeader); DataHeader_setVersion(dh, DataHeader_CURRENT_VERSION); // Other than the ipv6 addr at the end, everything is zeros right down the line. Bits_memset(rh, 0, RouteHeader_SIZE - 16); return Iface_next(&ud->pub.upperDistributorIf, msg); }
// Called by the TUN device. static inline uint8_t incomingFromTun(struct Message* message, struct Interface* iface) { struct Ducttape_pvt* context = Identity_cast((struct Ducttape_pvt*) iface->receiverContext); uint16_t ethertype = TUNMessageType_pop(message); struct Headers_IP6Header* header = (struct Headers_IP6Header*) message->bytes; int version = Headers_getIpVersion(message->bytes); if ((ethertype == Ethernet_TYPE_IP4 && version != 4) || (ethertype == Ethernet_TYPE_IP6 && version != 6)) { Log_warn(context->logger, "dropped packet because ip version [%d] " "doesn't match ethertype [%u].", version, Endian_bigEndianToHost16(ethertype)); return Error_INVALID; } if (ethertype != Ethernet_TYPE_IP6 || !AddressCalc_validAddress(header->sourceAddr)) { return context->ipTunnel->tunInterface.sendMessage(message, &context->ipTunnel->tunInterface); } if (Bits_memcmp(header->sourceAddr, context->myAddr.ip6.bytes, 16)) { uint8_t expectedSource[40]; AddrTools_printIp(expectedSource, context->myAddr.ip6.bytes); uint8_t packetSource[40]; AddrTools_printIp(packetSource, header->sourceAddr); Log_warn(context->logger, "dropped packet from [%s] because all messages must have source address [%s]", (char*) packetSource, (char*) expectedSource); return Error_INVALID; } if (!Bits_memcmp(header->destinationAddr, context->myAddr.ip6.bytes, 16)) { // I'm Gonna Sit Right Down and Write Myself a Letter TUNMessageType_push(message, ethertype); iface->sendMessage(message, iface); return Error_NONE; } struct Ducttape_MessageHeader* dtHeader = getDtHeader(message, true); struct Node* bestNext = RouterModule_lookup(header->destinationAddr, context->routerModule); struct SessionManager_Session* nextHopSession; if (bestNext) { nextHopSession = SessionManager_getSession(bestNext->address.ip6.bytes, bestNext->address.key, context->sm); bestNext->version = nextHopSession->version = (bestNext->version > nextHopSession->version) ? bestNext->version : nextHopSession->version; dtHeader->switchLabel = bestNext->address.path; dtHeader->nextHopReceiveHandle = Endian_bigEndianToHost32(nextHopSession->receiveHandle_be); if (!Bits_memcmp(header->destinationAddr, bestNext->address.ip6.bytes, 16)) { // Direct send, skip the innermost layer of encryption. #ifdef Log_DEBUG uint8_t nhAddr[60]; Address_print(nhAddr, &bestNext->address); Log_debug(context->logger, "Forwarding data to %s (last hop)\n", nhAddr); #endif return sendToRouter(message, dtHeader, nextHopSession, context); } // else { the message will need to be 3 layer encrypted but since we already did a lookup // of the best node to forward to, we can skip doing another lookup by storing a pointer // to that node in the context (bestNext). } else { #ifdef Log_WARN uint8_t thisAddr[40]; uint8_t destAddr[40]; AddrTools_printIp(thisAddr, context->myAddr.ip6.bytes); AddrTools_printIp(destAddr, header->destinationAddr); Log_warn(context->logger, "Dropped message from TUN because this node [%s] is closest to dest [%s]", thisAddr, destAddr); #endif return Error_UNDELIVERABLE; } #ifdef Log_DEBUG uint8_t destAddr[40]; AddrTools_printIp(destAddr, header->destinationAddr); uint8_t nhAddr[60]; Address_print(nhAddr, &bestNext->address); Log_debug(context->logger, "Sending to [%s] via [%s]", destAddr, nhAddr); #endif struct SessionManager_Session* session = SessionManager_getSession(header->destinationAddr, NULL, context->sm); // Copy the IP6 header back from where the CA header will be placed. // this is a mess. // We can't just copy the header to a safe place because the CryptoAuth // might buffer the message and send a connect-to-me packet and when the // hello packet comes in return, the CA will send the message and the header // needs to be in the message buffer. // // The CryptoAuth may send a 120 byte CA header and it might only send a 4 byte // nonce and 16 byte authenticator depending on its state. if (CryptoAuth_getState(&session->iface) < CryptoAuth_HANDSHAKE3) { // shift, copy, shift because shifting asserts that there is enough buffer space. Message_shift(message, Headers_CryptoAuth_SIZE + 4); Bits_memcpyConst(message->bytes, header, Headers_IP6Header_SIZE); Message_shift(message, -(Headers_IP6Header_SIZE + Headers_CryptoAuth_SIZE + 4)); // now push the receive handle *under* the CA header. Message_push(message, &session->receiveHandle_be, 4); debugHandles0(context->logger, session, "layer3 sending start message"); } else { // shift, copy, shift because shifting asserts that there is enough buffer space. Message_shift(message, 20); Bits_memmoveConst(message->bytes, header, Headers_IP6Header_SIZE); Message_shift(message, -(20 + Headers_IP6Header_SIZE)); debugHandles0(context->logger, session, "layer3 sending run message"); } // This comes out at outgoingFromCryptoAuth() then outgoingFromMe() dtHeader->receiveHandle = Endian_bigEndianToHost32(session->receiveHandle_be); dtHeader->layer = Ducttape_SessionLayer_INNER; return session->iface.sendMessage(message, &session->iface); }
/** * This is called as sendMessage() by the switch. * There is only one switch interface which sends all traffic. * message is aligned on the beginning of the switch header. */ static uint8_t incomingFromSwitch(struct Message* message, struct Interface* switchIf) { struct Ducttape_pvt* context = Identity_cast((struct Ducttape_pvt*)switchIf->senderContext); struct Ducttape_MessageHeader* dtHeader = getDtHeader(message, true); struct Headers_SwitchHeader* switchHeader = (struct Headers_SwitchHeader*) message->bytes; Message_shift(message, -Headers_SwitchHeader_SIZE); // The label comes in reversed from the switch because the switch doesn't know that we aren't // another switch ready to parse more bits, bit reversing the label yields the source address. switchHeader->label_be = Bits_bitReverse64(switchHeader->label_be); if (Headers_getMessageType(switchHeader) == Headers_SwitchHeader_TYPE_CONTROL) { return handleControlMessage(context, message, switchHeader, switchIf); } if (message->length < 8) { Log_info(context->logger, "runt"); return Error_INVALID; } #ifdef Version_2_COMPAT translateVersion2(message, dtHeader); #endif // #1 try to get the session using the handle. uint32_t nonceOrHandle = Endian_bigEndianToHost32(((uint32_t*)message->bytes)[0]); struct SessionManager_Session* session = NULL; if (nonceOrHandle > 3) { // Run message, it's a handle. session = SessionManager_sessionForHandle(nonceOrHandle, context->sm); Message_shift(message, -4); if (session) { uint32_t nonce = Endian_bigEndianToHost32(((uint32_t*)message->bytes)[0]); if (nonce == ~0u) { Log_debug(context->logger, "Got connectToMe packet at switch layer"); return 0; } debugHandlesAndLabel(context->logger, session, Endian_bigEndianToHost64(switchHeader->label_be), "running session nonce[%u]", nonce); dtHeader->receiveHandle = nonceOrHandle; } else { Log_debug(context->logger, "Got message with unrecognized handle"); } } else if (message->length >= Headers_CryptoAuth_SIZE) { union Headers_CryptoAuth* caHeader = (union Headers_CryptoAuth*) message->bytes; uint8_t ip6[16]; uint8_t* herKey = caHeader->handshake.publicKey; AddressCalc_addressForPublicKey(ip6, herKey); // a packet which claims to be "from us" causes problems if (AddressCalc_validAddress(ip6) && Bits_memcmp(ip6, &context->myAddr, 16)) { session = SessionManager_getSession(ip6, herKey, context->sm); debugHandlesAndLabel(context->logger, session, Endian_bigEndianToHost64(switchHeader->label_be), "new session nonce[%d]", nonceOrHandle); dtHeader->receiveHandle = Endian_bigEndianToHost32(session->receiveHandle_be); } else { Log_debug(context->logger, "Got message with invalid ip addr"); } } if (!session) { #ifdef Log_INFO uint8_t path[20]; AddrTools_printPath(path, Endian_bigEndianToHost64(switchHeader->label_be)); Log_info(context->logger, "Dropped traffic packet from unknown node. [%s]", path); #endif return 0; } // This is needed so that the priority and other information // from the switch header can be passed on properly. dtHeader->switchHeader = switchHeader; // This goes to incomingFromCryptoAuth() // then incomingFromRouter() then core() dtHeader->layer = Ducttape_SessionLayer_OUTER; if (session->iface.receiveMessage(message, &session->iface) == Error_AUTHENTICATION) { debugHandlesAndLabel(context->logger, session, Endian_bigEndianToHost64(switchHeader->label_be), "Failed decrypting message NoH[%d] state[%d]", nonceOrHandle, CryptoAuth_getState(&session->iface)); return Error_AUTHENTICATION; } return 0; }
static int registerPeer(struct InterfaceController* ifController, uint8_t herPublicKey[32], String* password, bool requireAuth, bool transient, struct Interface* externalInterface) { struct Context* ic = Identity_cast((struct Context*) ifController); Log_debug(ic->logger, "registerPeer [%p] total [%u]", (void*)externalInterface, ic->peerMap.count); if (Map_OfIFCPeerByExernalIf_indexForKey(&externalInterface, &ic->peerMap) > -1) { Log_debug(ic->logger, "Skipping registerPeer [%p] because peer is already registered", (void*)externalInterface); return 0; } uint8_t ip6[16]; if (herPublicKey) { AddressCalc_addressForPublicKey(ip6, herPublicKey); if (!AddressCalc_validAddress(ip6)) { return InterfaceController_registerPeer_BAD_KEY; } } struct Allocator* epAllocator = externalInterface->allocator; struct IFCPeer* ep = Allocator_calloc(epAllocator, sizeof(struct IFCPeer), 1); ep->external = externalInterface; int setIndex = Map_OfIFCPeerByExernalIf_put(&externalInterface, &ep, &ic->peerMap); ep->handle = ic->peerMap.handles[setIndex]; Identity_set(ep); Allocator_onFree(epAllocator, closeInterface, ep); // If the other end need not supply a valid password to connect // we will set the connection state to HANDSHAKE because we don't // want the connection to be trashed after the first invalid packet. if (!requireAuth) { ep->state = InterfaceController_PeerState_HANDSHAKE; } ep->cryptoAuthIf = CryptoAuth_wrapInterface(externalInterface, herPublicKey, requireAuth, true, ic->ca); ep->cryptoAuthIf->receiveMessage = receivedAfterCryptoAuth; ep->cryptoAuthIf->receiverContext = ep; // Always use authType 1 until something else comes along, then we'll have to refactor. if (password) { CryptoAuth_setAuth(password, 1, ep->cryptoAuthIf); } ep->transient = transient; Bits_memcpyConst(&ep->switchIf, (&(struct Interface) { .sendMessage = sendFromSwitch, // ifcontrollerForPeer uses this. // sendFromSwitch relies on the fact that the // switchIf is the same memory location as the Peer. .senderContext = ic, .allocator = epAllocator }), sizeof(struct Interface));
static void responseCallback(struct RouterModule_Promise* promise, uint32_t lagMilliseconds, struct Node* fromNode, Dict* result) { struct RouteTracer_Trace* trace = Identity_cast((struct RouteTracer_Trace*)promise->userData); struct RouteTracer_pvt* ctx = Identity_cast((struct RouteTracer_pvt*)trace->tracer); if (!fromNode) { // trace has stalled. log(ctx->logger, trace, "STALLED request timed out"); noPeers(trace); return; } if (trace->pub.callback) { trace->pub.callback(&trace->pub, lagMilliseconds, fromNode, result); } String* nodes = Dict_getString(result, CJDHTConstants_NODES); if (nodes && (nodes->len == 0 || nodes->len % Address_SERIALIZED_SIZE != 0)) { log(ctx->logger, trace, "STALLED dropping unrecognized reply"); noPeers(trace); return; } struct VersionList* versions = NULL; String* versionsStr = Dict_getString(result, CJDHTConstants_NODE_PROTOCOLS); if (versionsStr) { versions = VersionList_parse(versionsStr, promise->alloc); #ifdef Version_1_COMPAT // Version 1 lies about the versions of other nodes, assume they're all v1. if (fromNode->version < 2) { for (int i = 0; i < (int)versions->length; i++) { versions->versions[i] = 1; } } #endif } struct Node* next = NULL; for (uint32_t i = 0; nodes && i < nodes->len; i += Address_SERIALIZED_SIZE) { struct Address addr; Address_parse(&addr, (uint8_t*) &nodes->bytes[i]); // calculate the ipv6 Address_getPrefix(&addr); // We need to splice the given address on to the end of the // address of the node which gave it to us. addr.path = LabelSplicer_splice(addr.path, fromNode->address.path); if (addr.path == UINT64_MAX) { log(ctx->logger, trace, "dropping node because route could not be spliced"); continue; } /*#ifdef Log_DEBUG uint8_t printedAddr[60]; Address_print(printedAddr, &addr); Log_debug(ctx->logger, "discovered node [%s]", printedAddr); #endif*/ if (!Bits_memcmp(ctx->myAddress, addr.ip6.bytes, 16)) { // Any path which loops back through us is necessarily a dead route. uint8_t printedAddr[60]; Address_print(printedAddr, &addr); Log_debug(ctx->logger, "Loop route [%s]", printedAddr); NodeStore_brokenPath(addr.path, ctx->nodeStore); continue; } if (!AddressCalc_validAddress(addr.ip6.bytes)) { log(ctx->logger, trace, "was told garbage"); // This should never happen, badnode. break; } // Nodes we are told about are inserted with 0 reach and assumed version 1. uint32_t version = (versions) ? versions->versions[i / Address_SERIALIZED_SIZE] : 1; struct Node* n = NodeStore_addNode(ctx->nodeStore, &addr, 0, version); if (!n) { // incompatible version, introduced to ourselves... } else if (!LabelSplicer_routesThrough(trace->target, n->address.path)) { // not on the way } else if (n->address.path <= fromNode->address.path) { // losing ground } else if (next && n->address.path >= next->address.path) { // not better than the one we have } else { next = n; } } if (fromNode->address.path == trace->target) { log(ctx->logger, trace, "Trace completed successfully"); noPeers(trace); return; } if (!nodes) { log(ctx->logger, trace, "No nodes in trace response"); } if (!next) { log(ctx->logger, trace, "STALLED no suitable peers in reply"); noPeers(trace); return; } if (!LabelSplicer_routesThrough(trace->target, next->address.path)) { log(ctx->logger, trace, "STALLED Nodestore broke the path of the best option"); noPeers(trace); return; } traceStep(trace, next); }
static void sendMsg(struct MsgCore_pvt* mcp, Dict* msgDict, struct Address* addr, struct Allocator* allocator) { struct Allocator* alloc = Allocator_child(allocator); // Send the encoding scheme definition Dict_putString(msgDict, CJDHTConstants_ENC_SCHEME, mcp->schemeDefinition, allocator); // And tell the asker which interface the message came from int encIdx = EncodingScheme_getFormNum(mcp->scheme, addr->path); Assert_true(encIdx != EncodingScheme_getFormNum_INVALID); Dict_putInt(msgDict, CJDHTConstants_ENC_INDEX, encIdx, allocator); // send the protocol version Dict_putInt(msgDict, CJDHTConstants_PROTOCOL, Version_CURRENT_PROTOCOL, allocator); if (!Defined(SUBNODE)) { String* q = Dict_getStringC(msgDict, "q"); String* sq = Dict_getStringC(msgDict, "sq"); if (q || sq) { Log_debug(mcp->log, "Send query [%s] to [%s]", ((q) ? q->bytes : sq->bytes), Address_toString(addr, alloc)->bytes); String* txid = Dict_getStringC(msgDict, "txid"); Assert_true(txid); String* newTxid = String_newBinary(NULL, txid->len + 1, alloc); Bits_memcpy(&newTxid->bytes[1], txid->bytes, txid->len); newTxid->bytes[0] = '1'; if (String_equals(q, String_CONST("gp"))) { // direct all GP requests to the old system because the new one is broken :( newTxid->bytes[0] = '0'; } Dict_putStringC(msgDict, "txid", newTxid, alloc); } } struct Message* msg = Message_new(0, 2048, alloc); BencMessageWriter_write(msgDict, msg, NULL); //Log_debug(mcp->log, "Sending msg [%s]", Escape_getEscaped(msg->bytes, msg->length, alloc)); // Sanity check (make sure the addr was actually calculated) Assert_true(AddressCalc_validAddress(addr->ip6.bytes)); struct DataHeader data; Bits_memset(&data, 0, sizeof(struct DataHeader)); DataHeader_setVersion(&data, DataHeader_CURRENT_VERSION); DataHeader_setContentType(&data, ContentType_CJDHT); Message_push(msg, &data, sizeof(struct DataHeader), NULL); struct RouteHeader route; Bits_memset(&route, 0, sizeof(struct RouteHeader)); Bits_memcpy(route.ip6, addr->ip6.bytes, 16); route.version_be = Endian_hostToBigEndian32(addr->protocolVersion); route.sh.label_be = Endian_hostToBigEndian64(addr->path); Bits_memcpy(route.publicKey, addr->key, 32); Message_push(msg, &route, sizeof(struct RouteHeader), NULL); Iface_send(&mcp->pub.interRouterIf, msg); }