/** * Decrypt and authenticate. * * @param nonce a 24 byte number, may be random, cannot repeat. * @param msg a message to encipher and authenticate. * @param secret a shared secret. * @return 0 if decryption is succeddful, otherwise -1. */ static inline Gcc_USE_RET int decryptRndNonce(uint8_t nonce[24], struct Message* msg, uint8_t secret[32]) { if (msg->length < 16) { return -1; } Assert_true(msg->padding >= 16); uint8_t* startAt = msg->bytes - 16; uint8_t paddingSpace[16]; Bits_memcpy(paddingSpace, startAt, 16); Bits_memset(startAt, 0, 16); if (!Defined(NSA_APPROVED)) { if (crypto_box_curve25519xsalsa20poly1305_open_afternm( startAt, startAt, msg->length + 16, nonce, secret) != 0) { return -1; } } Bits_memcpy(startAt, paddingSpace, 16); Message_shift(msg, -16, NULL); return 0; }
struct ControlHandler* ControlHandler_new(struct Allocator* allocator, struct Log* logger, struct EventEmitter* ee, uint8_t myPublicKey[32]) { struct Allocator* alloc = Allocator_child(allocator); struct ControlHandler_pvt* ch = Allocator_calloc(alloc, sizeof(struct ControlHandler_pvt), 1); ch->alloc = alloc; ch->log = logger; Bits_memcpy(ch->myPublicKey, myPublicKey, 32); ch->pub.coreIf.send = incomingFromCore; ch->pub.switchPingerIf.send = incomingFromSwitchPinger; EventEmitter_regCore(ee, &ch->eventIf, 0); Identity_set(ch); return &ch->pub; }
static Iface_DEFUN receiveMessage(struct Message* msg, struct Iface* addrIface) { struct Context* ctx = Identity_containerOf(addrIface, struct Context, addrIface); struct Sockaddr_storage source; Message_pop(msg, &source, ctx->targetAddr->addrLen, NULL); if (Bits_memcmp(&source, ctx->targetAddr, ctx->targetAddr->addrLen)) { Log_info(ctx->logger, "Got spurious message from [%s], expecting messages from [%s]", Sockaddr_print(&source.addr, msg->alloc), Sockaddr_print(ctx->targetAddr, msg->alloc)); return NULL; } // we don't yet know with which message this data belongs, // the message alloc lives the length of the message reception. struct Allocator* alloc = Allocator_child(msg->alloc); int origLen = msg->length; Dict* d = NULL; char* err = BencMessageReader_readNoExcept(msg, alloc, &d); if (err) { return NULL; } Message_shift(msg, origLen, NULL); String* txid = Dict_getString(d, String_CONST("txid")); if (!txid || txid->len != 8) { return NULL; } // look up the result uint32_t handle = ~0u; Hex_decode((uint8_t*)&handle, 4, txid->bytes, 8); int idx = Map_OfRequestByHandle_indexForHandle(handle, &ctx->outstandingRequests); if (idx < 0) { return NULL; } struct Request* req = ctx->outstandingRequests.values[idx]; // now this data will outlive the life of the message. Allocator_adopt(req->promise->alloc, alloc); req->res.responseDict = d; int len = (msg->length > AdminClient_MAX_MESSAGE_SIZE) ? AdminClient_MAX_MESSAGE_SIZE : msg->length; Bits_memset(req->res.messageBytes, 0, AdminClient_MAX_MESSAGE_SIZE); Bits_memcpy(req->res.messageBytes, msg->bytes, len); done(req, AdminClient_Error_NONE); return NULL; }
static void change0(struct ReachabilityCollector_pvt* rcp, struct Address* nodeAddr, struct Allocator* tempAlloc) { for (int i = 0; i < rcp->piList->length; i++) { struct PeerInfo_pvt* pi = ArrayList_OfPeerInfo_pvt_get(rcp->piList, i); if (Address_isSameIp(nodeAddr, &pi->pub.addr)) { if (nodeAddr->path == 0) { Log_debug(rcp->log, "Peer [%s] dropped", Address_toString(&pi->pub.addr, tempAlloc)->bytes); ArrayList_OfPeerInfo_pvt_remove(rcp->piList, i); Allocator_free(pi->alloc); } else if (nodeAddr->path != pi->pub.addr.path) { Log_debug(rcp->log, "Peer [%s] changed path", Address_toString(&pi->pub.addr, tempAlloc)->bytes); pi->pub.pathThemToUs = -1; pi->pathToCheck = 1; pi->pub.querying = true; pi->pub.addr.path = nodeAddr->path; } if (rcp->pub.onChange) { rcp->pub.onChange(&rcp->pub, nodeAddr->ip6.bytes, 0, 0, 0, 0xffff, 0xffff, 0xffff); } return; } } if (nodeAddr->path == 0) { Log_debug(rcp->log, "Nonexistant peer [%s] dropped", Address_toString(nodeAddr, tempAlloc)->bytes); return; } struct Allocator* piAlloc = Allocator_child(rcp->alloc); struct PeerInfo_pvt* pi = Allocator_calloc(piAlloc, sizeof(struct PeerInfo_pvt), 1); Identity_set(pi); Bits_memcpy(&pi->pub.addr, nodeAddr, Address_SIZE); pi->alloc = piAlloc; pi->pub.querying = true; pi->pathToCheck = 1; pi->pub.pathThemToUs = -1; pi->waitForResponse = false; ArrayList_OfPeerInfo_pvt_add(rcp->piList, pi); Log_debug(rcp->log, "Peer [%s] added", Address_toString(&pi->pub.addr, tempAlloc)->bytes); mkNextRequest(rcp); }
char* ArchInfo_describe(enum ArchInfo ai, struct Allocator* alloc) { uint8_t flagBuff[archFlags_BUFF_SZ]; archFlags(ai, flagBuff); uint8_t buff[1024]; snprintf(buff, 1024, "%s %d-bit %sEndian %s", archStr(ai), ArchInfo_getBits(ai), ArchInfo_isBigEndian(ai) ? "Big" : "Little", flagBuff); int len = CString_strlen(buff); Assert_true(len < 1024); if (buff[len-1] == ' ') { buff[--len] = '\0'; } char* out = Allocator_malloc(alloc, len+1); Bits_memcpy(out, buff, len+1); return out; }
/** @see Allocator->realloc() */ static void* allocatorRealloc(const void* original, size_t length, const struct Allocator* allocator) { if (original == NULL) { return allocatorMalloc(length, allocator); } // Need to pointer to make sure we dont copy too much. struct BufferAllocator_context* context = (struct BufferAllocator_context*) allocator->context; char* pointer = context->pointer; size_t amountToClone = length < (size_t)(pointer - (char*)original) ? length : (size_t)(pointer - (char*)original); // The likelyhood of nothing having been allocated since is almost 0 so we will always create a new // allocation and copy into it. void* newAlloc = allocator->malloc(length, allocator); Bits_memcpy(newAlloc, original, amountToClone); return newAlloc; }
int main(int argc, char** argv) { struct Allocator* alloc = MallocAllocator_new(1<<20); struct EventBase* base = EventBase_new(alloc); struct Writer* logWriter = FileWriter_new(stdout, alloc); struct Log* log = WriterLog_new(logWriter, alloc); struct Sockaddr* addrA = Sockaddr_fromBytes(testAddrA, Sockaddr_AF_INET6, alloc); char assignedIfName[TUNInterface_IFNAMSIZ]; struct Interface* tap = TUNInterface_new(NULL, assignedIfName, 1, base, log, NULL, alloc); struct TAPWrapper* tapWrapper = TAPWrapper_new(tap, log, alloc); // Now setup the NDP server so the tun will work correctly. struct NDPServer* ndp = NDPServer_new(&tapWrapper->generic, log, TAPWrapper_LOCAL_MAC, alloc); ndp->advertisePrefix[0] = 0xfd; ndp->prefixLen = 8; struct Interface* tun = &ndp->generic; NetDev_addAddress(assignedIfName, addrA, 126, log, NULL); struct Sockaddr_storage addr; Assert_true(!Sockaddr_parse("[::]", &addr)); struct AddrInterface* udp = TUNTools_setupUDP(base, &addr.addr, alloc, log); struct Sockaddr* dest = Sockaddr_clone(udp->addr, alloc); uint8_t* addrBytes; Assert_true(16 == Sockaddr_getAddress(dest, &addrBytes)); Bits_memcpy(addrBytes, testAddrB, 16); udp->generic.receiveMessage = receiveMessageUDP; udp->generic.receiverContext = alloc; tun->receiveMessage = receiveMessageTUN; TUNTools_sendHelloWorld(udp, dest, base, alloc); Timeout_setTimeout(fail, NULL, 10000000, base, alloc); EventBase_beginLoop(base); return 0; }
static Iface_DEFUN receiveMessage(struct Message* msg, struct Iface* external) { struct TAPWrapper_pvt* tw = Identity_containerOf(external, struct TAPWrapper_pvt, external); if (msg->length < Ethernet_SIZE-2) { Log_debug(tw->log, "runt"); return 0; } // wacky 14 byte headers, back off into outer-space to create the padding... Message_shift(msg, 2, NULL); struct Ethernet eth; Message_pop(msg, ð, sizeof(struct Ethernet), NULL); // Not for us and not multicast... if (Bits_memcmp(eth.destAddr, TAPWrapper_LOCAL_MAC, Ethernet_ADDRLEN) && !(eth.destAddr[0] & 0x01)) { if (Defined(Log_DEBUG)) { uint8_t printedMac[18]; AddrTools_printMac(printedMac, eth.destAddr); Log_debug(tw->log, "Packet destine for unknown ethernet MAC [%s]", printedMac); } //return 0; } if (Bits_memcmp(eth.srcAddr, tw->pub.peerAddress, Ethernet_ADDRLEN)) { if (Bits_isZero(tw->pub.peerAddress, Ethernet_ADDRLEN)) { Bits_memcpy(tw->pub.peerAddress, eth.srcAddr, Ethernet_ADDRLEN); } else { #ifdef Log_DEBUG uint8_t printedMac[18]; AddrTools_printMac(printedMac, eth.srcAddr); Log_debug(tw->log, "DROP Packet with unexpected source MAC [%s]", printedMac); #endif return 0; } } TUNMessageType_push(msg, eth.ethertype, NULL); return Iface_next(&tw->pub.internal, msg); }
int main(int argc, char** argv) { // TODO: fix TUNConfigurator_addIp4Address() for Illumos, Darwin, BSD. #if defined(Illumos) || defined(Darwin) || defined(FreeBSD) || defined(OpenBSD) return 0; #endif struct Allocator* alloc = MallocAllocator_new(1<<20); struct EventBase* base = EventBase_new(alloc); struct Writer* logWriter = FileWriter_new(stdout, alloc); struct Log* logger = WriterLog_new(logWriter, alloc); struct Sockaddr* addrA = Sockaddr_fromBytes(testAddrA, Sockaddr_AF_INET, alloc); char assignedIfName[TUNInterface_IFNAMSIZ]; struct Interface* tun = TUNInterface_new(NULL, assignedIfName, base, logger, NULL, alloc); NetDev_addAddress(assignedIfName, addrA, 30, logger, NULL); struct Sockaddr_storage ss; Assert_true(!Sockaddr_parse("0.0.0.0", &ss)); struct AddrInterface* udp = UDPAddrInterface_new(base, &ss.addr, alloc, NULL, logger); struct Sockaddr* dest = Sockaddr_clone(udp->addr, alloc); uint8_t* addr; Assert_true(4 == Sockaddr_getAddress(dest, &addr)); Bits_memcpy(addr, testAddrB, 4); struct Message* msg; Message_STACK(msg, 0, 64); Message_push(msg, "Hello World", 12); Message_push(msg, dest, dest->addrLen); udp->generic.receiveMessage = receiveMessageUDP; udp->generic.receiverContext = alloc; tun->receiveMessage = receiveMessageTUN; udp->generic.sendMessage(msg, &udp->generic); Timeout_setTimeout(fail, NULL, 1000, base, alloc); EventBase_beginLoop(base); }
static inline void hashPassword(uint8_t secretOut[32], struct CryptoHeader_Challenge* challengeOut, const String* login, const String* password, const uint8_t authType) { crypto_hash_sha256(secretOut, (uint8_t*) password->bytes, password->len); uint8_t tempBuff[32]; if (authType == 1) { crypto_hash_sha256(tempBuff, secretOut, 32); } else if (authType == 2) { crypto_hash_sha256(tempBuff, (uint8_t*) login->bytes, login->len); } else { Assert_failure("Unsupported auth type [%u]", authType); } Bits_memcpy(challengeOut, tempBuff, CryptoHeader_Challenge_SIZE); CryptoHeader_setAuthChallengeDerivations(challengeOut, 0); challengeOut->type = authType; challengeOut->additional = 0; }
static void sendMessage(struct TwoNodes* tn, char* message, struct TestFramework* from, struct TestFramework* to) { struct Message* msg; Message_STACK(msg, 64, 512); Bits_memcpy(msg->bytes, message, CString_strlen(message) + 1); msg->length = CString_strlen(message) + 1; TestFramework_craftIPHeader(msg, from->ip, to->ip); msg = Message_clone(msg, from->alloc); struct Iface* fromIf; if (from == tn->nodeA) { fromIf = &tn->tunA; } else if (from == tn->nodeB) { fromIf = &tn->tunB; } else { Assert_true(false); } TUNMessageType_push(msg, Ethernet_TYPE_IP6, NULL); Iface_send(fromIf, msg); if (to == tn->nodeA) { Assert_true(tn->messageFrom == TUNA); } else if (to == tn->nodeB) { Assert_true(tn->messageFrom == TUNB); } else { Assert_true(false); } TestFramework_assertLastMessageUnaltered(tn->nodeA); TestFramework_assertLastMessageUnaltered(tn->nodeB); tn->messageFrom = 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; }
/** * Get a shared secret. * * @param outputSecret an array to place the shared secret in. * @param myPrivateKey * @param herPublicKey * @param logger * @param passwordHash a 32 byte value known to both ends, this must be provably pseudorandom * the first 32 bytes of a sha256 output from hashing a password is ok, * whatever she happens to send me in the Auth field is NOT ok. * If this field is null, the secret will be generated without the password. */ static inline void getSharedSecret(uint8_t outputSecret[32], uint8_t myPrivateKey[32], uint8_t herPublicKey[32], uint8_t passwordHash[32], struct Log* logger) { if (passwordHash == NULL) { crypto_box_curve25519xsalsa20poly1305_beforenm(outputSecret, herPublicKey, myPrivateKey); } else { union { struct { uint8_t key[32]; uint8_t passwd[32]; } components; uint8_t bytes[64]; } buff; crypto_scalarmult_curve25519(buff.components.key, myPrivateKey, herPublicKey); Bits_memcpy(buff.components.passwd, passwordHash, 32); crypto_hash_sha256(outputSecret, buff.bytes, 64); } if (Defined(Log_KEYS)) { uint8_t myPublicKeyHex[65]; printHexPubKey(myPublicKeyHex, myPrivateKey); uint8_t herPublicKeyHex[65]; printHexKey(herPublicKeyHex, herPublicKey); uint8_t passwordHashHex[65]; printHexKey(passwordHashHex, passwordHash); uint8_t outputSecretHex[65] = "NULL"; printHexKey(outputSecretHex, outputSecret); Log_keys(logger, "Generated a shared secret:\n" " myPublicKey=%s\n" " herPublicKey=%s\n" " passwordHash=%s\n" " outputSecret=%s\n", myPublicKeyHex, herPublicKeyHex, passwordHashHex, outputSecretHex); } }
/** * Parse out a path. * * @param out a pointer to a number which will be set to the path in HOST BYTE ORDER. * @param netAddr a string representation of the path such as "0000.1111.2222.3333" in Big Endian. * @return 0 if successful, -1 if the netAddr is malformed. */ int AddrTools_parsePath(uint64_t* out, const uint8_t netAddr[20]) { if (netAddr[4] != '.' || netAddr[9] != '.' || netAddr[14] != '.' || netAddr[19] != '\0') { return -1; } uint8_t hex[16] = { netAddr[ 0], netAddr[ 1], netAddr[ 2], netAddr[ 3], netAddr[ 5], netAddr[ 6], netAddr[ 7], netAddr[ 8], netAddr[10], netAddr[11], netAddr[12], netAddr[13], netAddr[15], netAddr[16], netAddr[17], netAddr[18] }; uint8_t numberBytes[8]; if (Hex_decode(numberBytes, 8, hex, 16) != 8) { return -1; } uint64_t out_be; Bits_memcpy(&out_be, numberBytes, 8); *out = Endian_bigEndianToHost64(out_be); return 0; }
void TUNTools_echoTest(struct Sockaddr* udpBindTo, struct Sockaddr* tunDestAddr, TUNTools_Callback tunMessageHandler, struct Iface* tun, struct EventBase* base, struct Log* logger, struct Allocator* allocator) { struct Allocator* alloc = Allocator_child(allocator); struct AddrIface* udp = setupUDP(base, udpBindTo, alloc, logger); struct Sockaddr* dest = Sockaddr_clone(udp->addr, alloc); uint8_t* tunDestAddrBytes = NULL; uint8_t* udpDestPointer = NULL; int len = Sockaddr_getAddress(dest, &udpDestPointer); Assert_true(len && len == Sockaddr_getAddress(tunDestAddr, &tunDestAddrBytes)); Bits_memcpy(udpDestPointer, tunDestAddrBytes, len); struct TUNTools_pvt* ctx = Allocator_calloc(alloc, sizeof(struct TUNTools_pvt), 1); Identity_set(ctx); ctx->pub.udpIface.send = receiveMessageUDP; ctx->pub.tunIface.send = receiveMessageTUN; Iface_plumb(&ctx->pub.udpIface, &udp->iface); Iface_plumb(&ctx->pub.tunIface, tun); ctx->pub.cb = tunMessageHandler; ctx->pub.tunDestAddr = Sockaddr_clone(dest, alloc); ctx->pub.udpBindTo = Sockaddr_clone(udpBindTo, alloc); ctx->pub.alloc = alloc; ctx->pub.log = logger; ctx->pub.base = base; Timeout_setInterval(sendHello, ctx, 1000, base, alloc); Timeout_setTimeout(fail, NULL, 10000, base, alloc); EventBase_beginLoop(base); }
/** @see Allocator->clone() */ static void* allocatorClone(size_t length, const struct Allocator* allocator, const void* toClone) { void* pointer = allocator->malloc(length, allocator); Bits_memcpy(pointer, toClone, length); return pointer; }
static Iface_DEFUN incomingMsg(struct Message* msg, struct Pathfinder_pvt* pf) { struct Address addr; struct RouteHeader* hdr = (struct RouteHeader*) msg->bytes; Message_shift(msg, -(RouteHeader_SIZE + DataHeader_SIZE), NULL); Bits_memcpy(addr.ip6.bytes, hdr->ip6, 16); Bits_memcpy(addr.key, hdr->publicKey, 32); addr.protocolVersion = Endian_bigEndianToHost32(hdr->version_be); addr.padding = 0; addr.path = Endian_bigEndianToHost64(hdr->sh.label_be); //Log_debug(pf->log, "Incoming DHT"); struct DHTMessage dht = { .address = &addr, .binMessage = msg, .allocator = msg->alloc }; DHTModuleRegistry_handleIncoming(&dht, pf->registry); struct Message* nodeMsg = Message_new(0, 256, msg->alloc); Iface_CALL(sendNode, nodeMsg, &addr, 0xfffffff0u, pf); if (dht.pleaseRespond) { // what a beautiful hack, see incomingFromDHT return Iface_next(&pf->pub.eventIf, msg); } return NULL; } static Iface_DEFUN incomingFromEventIf(struct Message* msg, struct Iface* eventIf) { struct Pathfinder_pvt* pf = Identity_containerOf(eventIf, struct Pathfinder_pvt, pub.eventIf); enum PFChan_Core ev = Message_pop32(msg, NULL); if (Pathfinder_pvt_state_INITIALIZING == pf->state) { Assert_true(ev == PFChan_Core_CONNECT); return connected(pf, msg); } // Let the PF send another 128 path changes again because it's basically a new tick. pf->bestPathChanges = 0; switch (ev) { case PFChan_Core_SWITCH_ERR: return switchErr(msg, pf); case PFChan_Core_SEARCH_REQ: return searchReq(msg, pf); case PFChan_Core_PEER: return peer(msg, pf); case PFChan_Core_PEER_GONE: return peerGone(msg, pf); case PFChan_Core_SESSION: return session(msg, pf); case PFChan_Core_SESSION_ENDED: return sessionEnded(msg, pf); case PFChan_Core_DISCOVERED_PATH: return discoveredPath(msg, pf); case PFChan_Core_MSG: return incomingMsg(msg, pf); case PFChan_Core_PING: return handlePing(msg, pf); case PFChan_Core_PONG: return handlePong(msg, pf); case PFChan_Core_UNSETUP_SESSION: case PFChan_Core_LINK_STATE: case PFChan_Core_CTRL_MSG: return NULL; default:; } Assert_failure("unexpected event [%d]", ev); } static void sendEvent(struct Pathfinder_pvt* pf, enum PFChan_Pathfinder ev, void* data, int size) { struct Allocator* alloc = Allocator_child(pf->alloc); struct Message* msg = Message_new(0, 512+size, alloc); Message_push(msg, data, size, NULL); Message_push32(msg, ev, NULL); Iface_send(&pf->pub.eventIf, msg); Allocator_free(alloc); } static void init(void* vpf) { struct Pathfinder_pvt* pf = Identity_check((struct Pathfinder_pvt*) vpf); struct PFChan_Pathfinder_Connect conn = { .superiority_be = Endian_hostToBigEndian32(1), .version_be = Endian_hostToBigEndian32(Version_CURRENT_PROTOCOL) }; CString_strncpy(conn.userAgent, "Cjdns internal pathfinder", 64); sendEvent(pf, PFChan_Pathfinder_CONNECT, &conn, PFChan_Pathfinder_Connect_SIZE); } struct Pathfinder* Pathfinder_register(struct Allocator* allocator, struct Log* log, struct EventBase* base, struct Random* rand, struct Admin* admin) { struct Allocator* alloc = Allocator_child(allocator); struct Pathfinder_pvt* pf = Allocator_calloc(alloc, sizeof(struct Pathfinder_pvt), 1); Identity_set(pf); pf->alloc = alloc; pf->log = log; pf->base = base; pf->rand = rand; pf->admin = admin; pf->pub.eventIf.send = incomingFromEventIf; pf->dhtModule.context = pf; pf->dhtModule.handleOutgoing = incomingFromDHT; // This needs to be done asynchronously so the pf can be plumbed to the core Timeout_setTimeout(init, pf, 0, base, alloc); return &pf->pub; }
static Iface_DEFUN connected(struct Pathfinder_pvt* pf, struct Message* msg) { Log_debug(pf->log, "INIT"); struct PFChan_Core_Connect conn; Message_pop(msg, &conn, PFChan_Core_Connect_SIZE, NULL); Assert_true(!msg->length); Bits_memcpy(pf->myAddr.key, conn.publicKey, 32); Address_getPrefix(&pf->myAddr); pf->myAddr.path = 1; // begin pf->registry = DHTModuleRegistry_new(pf->alloc); ReplyModule_register(pf->registry, pf->alloc); pf->rumorMill = RumorMill_new(pf->alloc, &pf->myAddr, RUMORMILL_CAPACITY, pf->log, "extern"); pf->nodeStore = NodeStore_new(&pf->myAddr, pf->alloc, pf->base, pf->log, pf->rumorMill); if (pf->pub.fullVerify) { NodeStore_setFullVerify(pf->nodeStore, true); } pf->nodeStore->onBestPathChange = onBestPathChange; pf->nodeStore->onBestPathChangeCtx = pf; struct RouterModule* routerModule = RouterModule_register(pf->registry, pf->alloc, pf->myAddr.key, pf->base, pf->log, pf->rand, pf->nodeStore); pf->searchRunner = SearchRunner_new(pf->nodeStore, pf->log, pf->base, routerModule, pf->myAddr.ip6.bytes, pf->rumorMill, pf->alloc); pf->janitor = Janitor_new(routerModule, pf->nodeStore, pf->searchRunner, pf->rumorMill, pf->log, pf->alloc, pf->base, pf->rand); EncodingSchemeModule_register(pf->registry, pf->log, pf->alloc); SerializationModule_register(pf->registry, pf->log, pf->alloc); DHTModuleRegistry_register(&pf->dhtModule, pf->registry); pf->router = Router_new(routerModule, pf->nodeStore, pf->searchRunner, pf->alloc); // Now the admin stuff... if (pf->admin) { NodeStore_admin_register(pf->nodeStore, pf->admin, pf->alloc); RouterModule_admin_register(routerModule, pf->router, pf->admin, pf->alloc); SearchRunner_admin_register(pf->searchRunner, pf->admin, pf->alloc); Janitor_admin_register(pf->janitor, pf->admin, pf->alloc); } pf->state = Pathfinder_pvt_state_RUNNING; return NULL; }
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; }
static void handleRequestFromChild(struct Admin* admin, uint8_t buffer[MAX_API_REQUEST_SIZE], size_t amount, struct Allocator* allocator) { struct Reader* reader = ArrayReader_new(buffer + TXID_LEN, amount - TXID_LEN, allocator); Dict message; if (StandardBencSerializer_get()->parseDictionary(reader, allocator, &message)) { Log_info(admin->logger, "Got unparsable data from admin interface."); return; } String* query = Dict_getString(&message, CJDHTConstants_QUERY); if (!query) { Log_info(admin->logger, "Got a non-query from admin interface."); return; } // txid becomes the user supplied txid combined with the inter-process txid. String* userTxid = Dict_getString(&message, TXID); String* txid = String_newBinary((char*)buffer, ((userTxid) ? userTxid->len : 0) + TXID_LEN, allocator); if (userTxid) { Bits_memcpy(txid->bytes + TXID_LEN, userTxid->bytes, userTxid->len); } // If they're asking for a cookie then lets give them one. String* cookie = String_CONST("cookie"); if (String_equals(query, cookie)) { Dict* d = Dict_new(allocator); char bytes[32]; snprintf(bytes, 32, "%u", (uint32_t) Time_currentTimeSeconds(admin->eventBase)); String* theCookie = &(String) { .len = strlen(bytes), .bytes = bytes }; Dict_putString(d, cookie, theCookie, allocator); Admin_sendMessage(d, txid, admin); return; } // If this is a permitted query, make sure the cookie is right. String* auth = String_CONST("auth"); bool authed = false; if (String_equals(query, auth)) { if (!authValid(&message, buffer + TXID_LEN, reader->bytesRead(reader), admin)) { Dict* d = Dict_new(allocator); Dict_putString(d, String_CONST("error"), String_CONST("Auth failed."), allocator); Admin_sendMessage(d, txid, admin); return; } query = Dict_getString(&message, String_CONST("aq")); authed = true; } Dict* args = Dict_getDict(&message, String_CONST("args")); bool noFunctionsCalled = true; for (int i = 0; i < admin->functionCount; i++) { if (String_equals(query, admin->functions[i].name) && (authed || !admin->functions[i].needsAuth)) { if (checkArgs(args, &admin->functions[i], txid, admin)) { admin->functions[i].call(args, admin->functions[i].context, txid); } noFunctionsCalled = false; } } if (noFunctionsCalled) { Dict* d = Dict_new(allocator); Dict_putString(d, String_CONST("error"), String_CONST("No functions matched your request."), allocator); Dict* functions = Dict_new(allocator); for (int i = 0; i < admin->functionCount; i++) { Dict_putDict(functions, admin->functions[i].name, admin->functions[i].args, allocator); } if (functions) { Dict_putDict(d, String_CONST("availableFunctions"), functions, allocator); } Admin_sendMessage(d, txid, admin); return; } return; }
/** * 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; }
/** * 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); }
/** @return a string representing the address and port to connect to. */ static void initAngel(struct Pipe* asClientPipe, struct Interface* asCoreIface, char* asCorePipeName, struct EventBase* eventBase, struct Log* logger, struct Allocator* alloc, struct Random* rand) { Dict admin = Dict_CONST( String_CONST("bind"), String_OBJ(String_CONST("127.0.0.1")), Dict_CONST( String_CONST("corePipeName"), String_OBJ(String_CONST(asCorePipeName)), Dict_CONST( String_CONST("pass"), String_OBJ(String_CONST("abcd")), NULL ))); Dict message = Dict_CONST( String_CONST("admin"), Dict_OBJ(&admin), NULL ); struct Allocator* tempAlloc = Allocator_child(alloc); #define BUFFER_SZ 1023 uint8_t buff[BUFFER_SZ + 1] = {0}; struct Writer* w = ArrayWriter_new(buff, BUFFER_SZ, tempAlloc); StandardBencSerializer_get()->serializeDictionary(w, &message); struct Message* toAngel = Allocator_malloc(tempAlloc, sizeof(struct Message) + w->bytesWritten); toAngel->bytes = (uint8_t*) (&toAngel[1]); toAngel->length = toAngel->capacity = w->bytesWritten; toAngel->padding = 0; toAngel->alloc = tempAlloc; Bits_memcpy(toAngel->bytes, buff, toAngel->length); Log_info(logger, "Writing intial configuration to angel on [%s] config: [%s]", asClientPipe->name, buff); Interface_sendMessage(&asClientPipe->iface, toAngel); // This is client->angel->core data, we can throw this away. //struct Message* angelToCore = InterfaceWaiter_waitForData(asCoreIface, eventBase, tempAlloc, NULL); // unterminated string //Log_info(logger, "Init message from angel to core: [%s]", angelToCore->bytes); // Send response on behalf of core. char* coreToAngelResponse = " PADDING " "d" "5:error" "4:none" "e"; struct Message* m = &(struct Message) { .bytes = (uint8_t*) coreToAngelResponse, .length = strlen(coreToAngelResponse), .padding = 0, .capacity = strlen(coreToAngelResponse) }; Message_shift(m, -24, NULL); m = Message_clone(m, tempAlloc); Interface_sendMessage(asCoreIface, m); // This is angel->client data, it will tell us which port was bound. struct Message* angelToClient = InterfaceWaiter_waitForData(&asClientPipe->iface, eventBase, tempAlloc, NULL); printf("Response from angel to client: [%s]\n", angelToClient->bytes); Allocator_free(tempAlloc); return; }
// incoming message from network, pointing to the beginning of the switch header. static Iface_DEFUN messageFromControlHandler(struct Message* msg, struct Iface* iface) { struct SwitchPinger_pvt* ctx = Identity_check((struct SwitchPinger_pvt*) iface); struct SwitchHeader* switchHeader = (struct SwitchHeader*) msg->bytes; ctx->incomingLabel = Endian_bigEndianToHost64(switchHeader->label_be); ctx->incomingVersion = 0; Message_shift(msg, -SwitchHeader_SIZE, NULL); uint32_t handle = Message_pop32(msg, NULL); #ifdef Version_7_COMPAT if (handle != 0xffffffff) { Message_push32(msg, handle, NULL); handle = 0xffffffff; Assert_true(SwitchHeader_isV7Ctrl(switchHeader)); } #endif Assert_true(handle == 0xffffffff); struct Control* ctrl = (struct Control*) msg->bytes; if (ctrl->header.type_be == Control_PONG_be) { Message_shift(msg, -Control_Header_SIZE, NULL); ctx->error = Error_NONE; if (msg->length >= Control_Pong_MIN_SIZE) { struct Control_Ping* pongHeader = (struct Control_Ping*) msg->bytes; ctx->incomingVersion = Endian_bigEndianToHost32(pongHeader->version_be); if (pongHeader->magic != Control_Pong_MAGIC) { Log_debug(ctx->logger, "dropped invalid switch pong"); return NULL; } Message_shift(msg, -Control_Pong_HEADER_SIZE, NULL); } else { Log_debug(ctx->logger, "got runt pong message, length: [%d]", msg->length); return NULL; } } else if (ctrl->header.type_be == Control_KEYPONG_be) { Message_shift(msg, -Control_Header_SIZE, NULL); ctx->error = Error_NONE; if (msg->length >= Control_KeyPong_HEADER_SIZE && msg->length <= Control_KeyPong_MAX_SIZE) { struct Control_KeyPing* pongHeader = (struct Control_KeyPing*) msg->bytes; ctx->incomingVersion = Endian_bigEndianToHost32(pongHeader->version_be); if (pongHeader->magic != Control_KeyPong_MAGIC) { Log_debug(ctx->logger, "dropped invalid switch key-pong"); return NULL; } Bits_memcpy(ctx->incomingKey, pongHeader->key, 32); Message_shift(msg, -Control_KeyPong_HEADER_SIZE, NULL); } else if (msg->length > Control_KeyPong_MAX_SIZE) { Log_debug(ctx->logger, "got overlong key-pong message, length: [%d]", msg->length); return NULL; } else { Log_debug(ctx->logger, "got runt key-pong message, length: [%d]", msg->length); return NULL; } } else if (ctrl->header.type_be == Control_ERROR_be) { Message_shift(msg, -Control_Header_SIZE, NULL); Assert_true((uint8_t*)&ctrl->content.error.errorType_be == msg->bytes); if (msg->length < (Control_Error_HEADER_SIZE + SwitchHeader_SIZE + Control_Header_SIZE)) { Log_debug(ctx->logger, "runt error packet"); return NULL; } ctx->error = Message_pop32(msg, NULL); Message_push32(msg, 0, NULL); Message_shift(msg, -(Control_Error_HEADER_SIZE + SwitchHeader_SIZE), NULL); struct Control* origCtrl = (struct Control*) msg->bytes; Log_debug(ctx->logger, "error [%s] was caused by our [%s]", Error_strerror(ctx->error), Control_typeString(origCtrl->header.type_be)); int shift; if (origCtrl->header.type_be == Control_PING_be) { shift = -(Control_Header_SIZE + Control_Ping_HEADER_SIZE); } else if (origCtrl->header.type_be == Control_KEYPING_be) { shift = -(Control_Header_SIZE + Control_KeyPing_HEADER_SIZE); } else { Assert_failure("problem in Ducttape.c"); } if (msg->length < -shift) { Log_debug(ctx->logger, "runt error packet"); } Message_shift(msg, shift, NULL); } else { // If it gets here then Ducttape.c is failing. Assert_true(false); } String* msgStr = &(String) { .bytes = (char*) msg->bytes, .len = msg->length }; Pinger_pongReceived(msgStr, ctx->pinger); Bits_memset(ctx->incomingKey, 0, 32); return NULL; } static void onPingResponse(String* data, uint32_t milliseconds, void* vping) { struct Ping* p = Identity_check((struct Ping*) vping); enum SwitchPinger_Result err = SwitchPinger_Result_OK; uint64_t label = p->context->incomingLabel; if (data) { if (label != p->label) { err = SwitchPinger_Result_LABEL_MISMATCH; } else if ((p->data || data->len > 0) && !String_equals(data, p->data)) { err = SwitchPinger_Result_WRONG_DATA; } else if (p->context->error == Error_LOOP_ROUTE) { err = SwitchPinger_Result_LOOP_ROUTE; } else if (p->context->error) { err = SwitchPinger_Result_ERROR_RESPONSE; } } else { err = SwitchPinger_Result_TIMEOUT; } uint32_t version = p->context->incomingVersion; struct SwitchPinger_Response* resp = Allocator_calloc(p->pub.pingAlloc, sizeof(struct SwitchPinger_Response), 1); resp->version = p->context->incomingVersion; resp->res = err; resp->label = label; resp->data = data; resp->milliseconds = milliseconds; resp->version = version; Bits_memcpy(resp->key, p->context->incomingKey, 32); resp->ping = &p->pub; p->onResponse(resp, p->pub.onResponseContext); } static void sendPing(String* data, void* sendPingContext) { struct Ping* p = Identity_check((struct Ping*) sendPingContext); struct Message* msg = Message_new(0, data->len + 512, p->pub.pingAlloc); while (((uintptr_t)msg->bytes - data->len) % 4) { Message_push8(msg, 0, NULL); } msg->length = 0; Message_push(msg, data->bytes, data->len, NULL); Assert_true(!((uintptr_t)msg->bytes % 4) && "alignment fault"); if (p->pub.keyPing) { Message_shift(msg, Control_KeyPing_HEADER_SIZE, NULL); struct Control_KeyPing* keyPingHeader = (struct Control_KeyPing*) msg->bytes; keyPingHeader->magic = Control_KeyPing_MAGIC; keyPingHeader->version_be = Endian_hostToBigEndian32(Version_CURRENT_PROTOCOL); Bits_memcpy(keyPingHeader->key, p->context->myAddr->key, 32); } else { Message_shift(msg, Control_Ping_HEADER_SIZE, NULL); struct Control_Ping* pingHeader = (struct Control_Ping*) msg->bytes; pingHeader->magic = Control_Ping_MAGIC; pingHeader->version_be = Endian_hostToBigEndian32(Version_CURRENT_PROTOCOL); } Message_shift(msg, Control_Header_SIZE, NULL); struct Control* ctrl = (struct Control*) msg->bytes; ctrl->header.checksum_be = 0; ctrl->header.type_be = (p->pub.keyPing) ? Control_KEYPING_be : Control_PING_be; ctrl->header.checksum_be = Checksum_engine(msg->bytes, msg->length); #ifdef Version_7_COMPAT if (0) { #endif Message_push32(msg, 0xffffffff, NULL); #ifdef Version_7_COMPAT } #endif Message_shift(msg, SwitchHeader_SIZE, NULL); struct SwitchHeader* switchHeader = (struct SwitchHeader*) msg->bytes; Bits_memset(switchHeader, 0, SwitchHeader_SIZE); switchHeader->label_be = Endian_hostToBigEndian64(p->label); SwitchHeader_setVersion(switchHeader, SwitchHeader_CURRENT_VERSION); #ifdef Version_7_COMPAT // v7 detects ctrl packets by the bit which has been // re-appropriated for suppression of errors. switchHeader->congestAndSuppressErrors = 1; SwitchHeader_setVersion(switchHeader, 0); #endif Iface_send(&p->context->pub.controlHandlerIf, msg); } static String* RESULT_STRING_OK = String_CONST_SO("pong"); static String* RESULT_STRING_LABEL_MISMATCH = String_CONST_SO("diff_label"); static String* RESULT_STRING_WRONG_DATA = String_CONST_SO("diff_data"); static String* RESULT_STRING_ERROR_RESPONSE = String_CONST_SO("err_switch"); static String* RESULT_STRING_TIMEOUT = String_CONST_SO("timeout"); static String* RESULT_STRING_UNKNOWN = String_CONST_SO("err_unknown"); static String* RESULT_STRING_LOOP = String_CONST_SO("err_loop"); String* SwitchPinger_resultString(enum SwitchPinger_Result result) { switch (result) { case SwitchPinger_Result_OK: return RESULT_STRING_OK; case SwitchPinger_Result_LABEL_MISMATCH: return RESULT_STRING_LABEL_MISMATCH; case SwitchPinger_Result_WRONG_DATA: return RESULT_STRING_WRONG_DATA; case SwitchPinger_Result_ERROR_RESPONSE: return RESULT_STRING_ERROR_RESPONSE; case SwitchPinger_Result_TIMEOUT: return RESULT_STRING_TIMEOUT; case SwitchPinger_Result_LOOP_ROUTE: return RESULT_STRING_LOOP; default: return RESULT_STRING_UNKNOWN; }; } static int onPingFree(struct Allocator_OnFreeJob* job) { struct Ping* ping = Identity_check((struct Ping*)job->userData); struct SwitchPinger_pvt* ctx = Identity_check(ping->context); ctx->outstandingPings--; Assert_true(ctx->outstandingPings >= 0); return 0; } struct SwitchPinger_Ping* SwitchPinger_newPing(uint64_t label, String* data, uint32_t timeoutMilliseconds, SwitchPinger_ResponseCallback onResponse, struct Allocator* alloc, struct SwitchPinger* context) { struct SwitchPinger_pvt* ctx = Identity_check((struct SwitchPinger_pvt*)context); if (data && data->len > Control_Ping_MAX_SIZE) { return NULL; } if (ctx->outstandingPings > ctx->maxConcurrentPings) { Log_debug(ctx->logger, "Skipping switch ping because there are already [%d] outstanding", ctx->outstandingPings); return NULL; } struct Pinger_Ping* pp = Pinger_newPing(data, onPingResponse, sendPing, timeoutMilliseconds, alloc, ctx->pinger); struct Ping* ping = Allocator_clone(pp->pingAlloc, (&(struct Ping) { .pub = { .pingAlloc = pp->pingAlloc }, .label = label, .data = String_clone(data, pp->pingAlloc), .context = ctx, .onResponse = onResponse, .pingerPing = pp }));
static void testAddr(struct Context* ctx, char* addr4, int prefix4, int alloc4, char* addr6, int prefix6, int alloc6) { struct Allocator* alloc = Allocator_child(ctx->alloc); struct IpTunnel* ipTun = IpTunnel_new(ctx->log, ctx->base, alloc, ctx->rand, NULL); struct Sockaddr* sa4 = NULL; struct Sockaddr_storage ip6ToGive; struct Sockaddr_storage ip4ToGive; if (addr4) { Assert_true(!Sockaddr_parse(addr4, &ip4ToGive)); sa4 = &ip4ToGive.addr; Assert_true(Sockaddr_getFamily(sa4) == Sockaddr_AF_INET); } struct Sockaddr* sa6 = NULL; if (addr6) { Assert_true(!Sockaddr_parse(addr6, &ip6ToGive)); sa6 = &ip6ToGive.addr; Assert_true(Sockaddr_getFamily(sa6) == Sockaddr_AF_INET6); } IpTunnel_allowConnection(ctx->pubKey, sa6, prefix6, alloc6, sa4, prefix4, alloc4, ipTun); struct Message* msg = Message_new(64, 512, alloc); const char* requestForAddresses = "d" "1:q" "21:IpTunnel_getAddresses" "4:txid" "4:abcd" "e"; CString_strcpy(msg->bytes, requestForAddresses); msg->length = CString_strlen(requestForAddresses); Message_push(msg, NULL, Headers_UDPHeader_SIZE, NULL); struct Headers_UDPHeader* uh = (struct Headers_UDPHeader*) msg->bytes; uh->length_be = Endian_hostToBigEndian16(msg->length - Headers_UDPHeader_SIZE); uint16_t* checksum = &((struct Headers_UDPHeader*) msg->bytes)->checksum_be; *checksum = 0; uint32_t length = msg->length; // Because of old reasons, we need to have at least an empty IPv6 header Message_push(msg, NULL, Headers_IP6Header_SIZE, NULL); struct Headers_IP6Header* ip = (struct Headers_IP6Header*) msg->bytes; Headers_setIpVersion(ip); ip->payloadLength_be = Endian_hostToBigEndian16(msg->length - Headers_IP6Header_SIZE); ip->nextHeader = 17; *checksum = Checksum_udpIp6(ip->sourceAddr, (uint8_t*) uh, length); pushRouteDataHeaders(ctx, msg); struct IfaceContext* nodeIf = Allocator_calloc(alloc, sizeof(struct IfaceContext), 1); nodeIf->ctx = ctx; nodeIf->iface.send = responseWithIpCallback; struct IfaceContext* tunIf = Allocator_calloc(alloc, sizeof(struct IfaceContext), 1); tunIf->ctx = ctx; tunIf->iface.send = messageToTun; Iface_plumb(&nodeIf->iface, &ipTun->nodeInterface); Iface_plumb(&tunIf->iface, &ipTun->tunInterface); ctx->expectedResponse = getExpectedResponse(sa4, prefix4, alloc4, sa6, prefix6, alloc6, alloc); Iface_send(&nodeIf->iface, msg); Assert_true(ctx->called == 2); ctx->called = 0; if (sa4) { uint8_t* addrBytes = NULL; Assert_true(Sockaddr_getAddress(sa4, &addrBytes) == 4); uint32_t addr; Bits_memcpy(&addr, addrBytes, 4); addr = Endian_bigEndianToHost32(addr); // Send from the address specified Assert_true(trySend4(alloc, addr, &nodeIf->iface, ctx)); if (alloc4 < 32) { // Send from another (random) address in the prefix uint32_t flip = Random_uint32(ctx->rand) >> alloc4; if (prefix4 != 32) { Assert_true(trySend4(alloc, addr ^ flip, &nodeIf->iface, ctx)); } else { // If netSize is not specified, we do not allow multi-address Assert_true(!trySend4(alloc, addr ^ flip, &nodeIf->iface, ctx)); } } else {
static uint8_t receiveMessage(struct Message* msg, struct Iface* iface) { struct Allocator* alloc = iface->receiverContext; if (msg->length < 20) { printf("runt\n"); return 0; } // ethernet padding. Message_shift(msg, -2, NULL); uint8_t from[13]; uint8_t to[13]; Hex_encode(from, 13, msg->bytes, 6); Message_shift(msg, -6, NULL); Hex_encode(to, 13, msg->bytes, 6); Message_shift(msg, -6, NULL); uint8_t type[5]; Hex_encode(type, 5, msg->bytes, 2); Message_shift(msg, -2, NULL); int subsubtype = -1; int subtype = -1; // int typeCode = -1; if (!Bits_memcmp(type, "86dd", 4)) { Bits_memcpy(type, "ipv6", 5); subtype = msg->bytes[6]; // typeCode = 6; if (subtype == 58) { subsubtype = msg->bytes[40]; } } else if (!Bits_memcmp(type, "0800", 4)) { return 0; Bits_memcpy(type, "ipv4", 5); subtype = msg->bytes[9]; // typeCode = 4; } else { return 0; } // 6000000000183aff0000000000000000000000000000000fff0200000000000000000001ff000018 870 //6000000000201101fd000000000000000000000000000001ff020000000000000000000000010003 eee914... //6000000000083aff00000000000000000000000000000000ff020000000000000000000000000002 85007b //6000000000203aff fd000000000000000000000000000001 ff0200000000000000000001ff000002 8700. int len = msg->length * 2 + 1; uint8_t* buff = Allocator_malloc(alloc, len + 2); Hex_encode(buff, len, msg->bytes, msg->length); /* if (typeCode == 6 && len > 86) { Bits_memmove(&buff[82], &buff[81], len - 81); Bits_memmove(&buff[49], &buff[48], len - 48); Bits_memmove(&buff[17], &buff[16], len - 16); buff[80] = buff[48] = buff[16] = ' '; }*/ if (msg->length > 45) { Bits_memcpy(buff+86, "...", 4); } printf("[%s] [%s] [%s] [%02d] [%03d] [%s]\n", to, from, type, subtype, subsubtype, buff); return 0; }
int main() { struct Allocator* mainAlloc = MallocAllocator_new(1<<20); struct Log* log = FileWriterLog_new(stdout, mainAlloc); struct Random* rand = Random_new(mainAlloc, log, NULL); struct Context* ctx = Allocator_malloc(mainAlloc, sizeof(struct Context)); Identity_set(ctx); struct Interface iface = { .sendMessage = NULL }; struct Interface* fi = FramingInterface_new(4096, &iface, mainAlloc); fi->receiveMessage = messageOut; fi->receiverContext = ctx; for (int i = 0; i < CYCLES; i++) { struct Allocator* alloc = Allocator_child(mainAlloc); // max frame size must be at least 5 so that at least 1 byte of data is sent. int maxFrameSize = ( Random_uint32(rand) % (MAX_FRAME_SZ - 1) ) + 1; int maxMessageSize = ( Random_uint32(rand) % (MAX_MSG_SZ - MIN_MSG_SZ) ) + MIN_MSG_SZ; Log_debug(log, "maxFrameSize[%d] maxMessageSize[%d]", maxFrameSize, maxMessageSize); ctx->alloc = alloc; ctx->messages = NULL; ctx->messageCount = 0; ctx->currentMessage = 0; // Create one huge message, then create lots of little frames inside of it // then split it up in random places and send the sections to the framing // interface. struct Message* msg = Message_new(WORK_BUFF_SZ, 0, alloc); Assert_true(WORK_BUFF_SZ == msg->length); Random_bytes(rand, msg->bytes, msg->length); Message_shift(msg, -WORK_BUFF_SZ, NULL); for (;;) { int len = Random_uint32(rand) % maxFrameSize; if (!len) { len++; } if (msg->padding < len + 4) { break; } Message_shift(msg, len, NULL); ctx->messageCount++; ctx->messages = Allocator_realloc(alloc, ctx->messages, ctx->messageCount * sizeof(char*)); struct Message* om = ctx->messages[ctx->messageCount-1] = Message_new(len, 0, alloc); Bits_memcpy(om->bytes, msg->bytes, len); Message_push32(msg, len, NULL); } do { int nextMessageSize = Random_uint32(rand) % maxMessageSize; if (!nextMessageSize) { nextMessageSize++; } if (nextMessageSize > msg->length) { nextMessageSize = msg->length; } struct Allocator* msgAlloc = Allocator_child(alloc); struct Message* m = Message_new(nextMessageSize, 0, msgAlloc); Message_pop(msg, m->bytes, nextMessageSize, NULL); Interface_receiveMessage(&iface, m); Allocator_free(msgAlloc); } while (msg->length); Assert_true(ctx->messageCount == ctx->currentMessage); Allocator_free(alloc); } return 0; }
static void addIp6Address(const char* interfaceName, const uint8_t address[16], int prefixLen, struct Log* logger, struct Except* eh) { /* stringify our IP address */ char myIp[40]; AddrTools_printIp((uint8_t*)myIp, address); /* set up the interface ip assignment request */ struct in6_aliasreq in6_addreq; memset(&in6_addreq, 0, sizeof(in6_addreq)); in6_addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; in6_addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; /* parse the IPv6 address and add it to the request */ struct addrinfo hints, *result; bzero(&hints, sizeof(struct addrinfo)); hints.ai_family = AF_INET6; int err = getaddrinfo((const char *)myIp, NULL, &hints, &result); if (err) { // Should never happen since the address is specified as binary. Except_throw(eh, "bad IPv6 address [%s]", gai_strerror(err)); } Bits_memcpy(&in6_addreq.ifra_addr, result->ai_addr, result->ai_addrlen); /* turn the prefixlen into a mask, and add it to the request */ struct sockaddr_in6* mask = &in6_addreq.ifra_prefixmask; u_char *cp; int len = prefixLen; mask->sin6_len = sizeof(*mask); if ((prefixLen == 0) || (prefixLen == 128)) { memset(&mask->sin6_addr, 0xff, sizeof(struct in6_addr)); } else { memset((void *)&mask->sin6_addr, 0x00, sizeof(mask->sin6_addr)); for (cp = (u_char *)&mask->sin6_addr; len > 7; len -= 8) { *cp++ = 0xff; } *cp = 0xff << (8 - len); } strncpy(in6_addreq.ifra_name, interfaceName, sizeof(in6_addreq.ifra_name)); /* do the actual assignment ioctl */ int s = socket(AF_INET6, SOCK_DGRAM, 0); if (s < 0) { Except_throw(eh, "socket() [%s]", strerror(errno)); } if (ioctl(s, SIOCAIFADDR_IN6, &in6_addreq) < 0) { int err = errno; close(s); Except_throw(eh, "ioctl(SIOCAIFADDR) [%s]", strerror(err)); } Log_info(logger, "Configured IPv6 [%s/%i] for [%s]", myIp, prefixLen, interfaceName); close(s); }
static void handleRequestFromChild(struct Admin* admin, union Admin_TxidPrefix* txid_prefix, Dict* message, uint8_t* buffer, size_t amount, struct Allocator* allocator) { String* query = Dict_getString(message, CJDHTConstants_QUERY); if (!query) { Log_info(admin->logger, "Got a non-query from admin interface on channel [%u].", admin->messageHeader.channelNum); adminChannelClose(admin, admin->messageHeader.channelNum); return; } // txid becomes the user supplied txid combined with the inter-process txid. String* userTxid = Dict_getString(message, TXID); uint32_t txidlen = ((userTxid) ? userTxid->len : 0) + Admin_TxidPrefix_SIZE; String* txid = String_newBinary(NULL, txidlen, allocator); Bits_memcpyConst(txid->bytes, txid_prefix->raw, Admin_TxidPrefix_SIZE); if (userTxid) { Bits_memcpy(txid->bytes + Admin_TxidPrefix_SIZE, userTxid->bytes, userTxid->len); } // If they're asking for a cookie then lets give them one. String* cookie = String_CONST("cookie"); if (String_equals(query, cookie)) { Dict* d = Dict_new(allocator); char bytes[32]; snprintf(bytes, 32, "%u", (uint32_t) Time_currentTimeSeconds(admin->eventBase)); String* theCookie = &(String) { .len = strlen(bytes), .bytes = bytes }; Dict_putString(d, cookie, theCookie, allocator); Admin_sendMessage(d, txid, admin); return; } // If this is a permitted query, make sure the cookie is right. String* auth = String_CONST("auth"); bool authed = false; if (String_equals(query, auth)) { if (!authValid(message, buffer, amount, admin)) { Dict* d = Dict_new(allocator); Dict_putString(d, String_CONST("error"), String_CONST("Auth failed."), allocator); Admin_sendMessage(d, txid, admin); return; } query = Dict_getString(message, String_CONST("aq")); authed = true; } Dict* args = Dict_getDict(message, String_CONST("args")); bool noFunctionsCalled = true; for (int i = 0; i < admin->functionCount; i++) { if (String_equals(query, admin->functions[i].name) && (authed || !admin->functions[i].needsAuth)) { if (checkArgs(args, &admin->functions[i], txid, admin)) { admin->functions[i].call(args, admin->functions[i].context, txid); } noFunctionsCalled = false; } } if (noFunctionsCalled) { Dict* d = Dict_new(allocator); Dict_putString(d, String_CONST("error"), String_CONST("No functions matched your request."), allocator); Dict* functions = Dict_new(allocator); for (int i = 0; i < admin->functionCount; i++) { Dict_putDict(functions, admin->functions[i].name, admin->functions[i].args, allocator); } if (functions) { Dict_putDict(d, String_CONST("availableFunctions"), functions, allocator); } Admin_sendMessage(d, txid, admin); return; } return; }
void Sign_publicKeyFromKeyPair(uint8_t publicSigningKey[32], uint8_t keyPair[64]) { Bits_memcpy(publicSigningKey, &keyPair[32], 32); }