static bool trySend6(struct Allocator* alloc, uint64_t addrHigh, uint64_t addrLow, struct Iface* sendTo, struct Context* ctx) { struct Message* msg6 = Message_new(0, 512, alloc); Message_push(msg6, "hello world", 12, NULL); Message_push(msg6, NULL, Headers_IP6Header_SIZE, NULL); struct Headers_IP6Header* iph = (struct Headers_IP6Header*) msg6->bytes; Headers_setIpVersion(iph); uint64_t addrHigh_be = Endian_hostToBigEndian64(addrHigh); uint64_t addrLow_be = Endian_hostToBigEndian64(addrLow); Bits_memcpy(iph->sourceAddr, &addrHigh_be, 8); Bits_memcpy(&iph->sourceAddr[8], &addrLow_be, 8); Bits_memcpy(ctx->sendingAddress, iph->sourceAddr, 16); uint8_t destAddr[16] = { 20, 01 }; destAddr[15] = 1; Bits_memcpy(iph->destinationAddr, destAddr, 16); pushRouteDataHeaders(ctx, msg6); Iface_send(sendTo, msg6); if (ctx->called == 4) { ctx->called = 0; return true; } Assert_true(ctx->called == 0); return false; }
int main() { printInfo(); volatile uint64_t b = 0x0123456789abcdef; volatile uint64_t sb = 0xefcdab8967452301; volatile uint32_t a = 0x01234567; volatile uint32_t sa = 0x67452301; volatile uint16_t c = 0xcabe; volatile uint16_t sc = 0xbeca; if (!Endian_isBigEndian()) { Assert_true(c == Endian_bigEndianToHost16(sc)); Assert_true(c == Endian_hostToBigEndian16(sc)); Assert_true(c == Endian_hostToLittleEndian16(c)); Assert_true(c == Endian_littleEndianToHost16(c)); Assert_true(a == Endian_bigEndianToHost32(sa)); Assert_true(a == Endian_hostToBigEndian32(sa)); Assert_true(a == Endian_hostToLittleEndian32(a)); Assert_true(a == Endian_littleEndianToHost32(a)); Assert_true(b == Endian_bigEndianToHost64(sb)); Assert_true(b == Endian_hostToBigEndian64(sb)); Assert_true(b == Endian_hostToLittleEndian64(b)); Assert_true(b == Endian_littleEndianToHost64(b)); } else { Assert_true(c == Endian_bigEndianToHost16(c)); Assert_true(c == Endian_hostToBigEndian16(c)); Assert_true(c == Endian_hostToLittleEndian16(sc)); Assert_true(c == Endian_littleEndianToHost16(sc)); Assert_true(a == Endian_bigEndianToHost32(a)); Assert_true(a == Endian_hostToBigEndian32(a)); Assert_true(a == Endian_hostToLittleEndian32(sa)); Assert_true(a == Endian_littleEndianToHost32(sa)); Assert_true(b == Endian_bigEndianToHost64(b)); Assert_true(b == Endian_hostToBigEndian64(b)); Assert_true(b == Endian_hostToLittleEndian64(sb)); Assert_true(b == Endian_littleEndianToHost64(sb)); } Assert_true(b == Endian_byteSwap64(sb)); Assert_true(a == Endian_byteSwap32(sa)); Assert_true(c == Endian_byteSwap16(sc)); return 0; }
/** Takes the path in host byte order. */ void AddrTools_printPath(uint8_t out[20], uint64_t path) { uint64_t path_be = Endian_hostToBigEndian64(path); uint8_t bytes[16]; Hex_encode(bytes, 16, (uint8_t*) &path_be, 8); out[ 0] = bytes[ 0]; out[ 1] = bytes[ 1]; out[ 2] = bytes[ 2]; out[ 3] = bytes[ 3]; out[ 4] = '.'; out[ 5] = bytes[ 4]; out[ 6] = bytes[ 5]; out[ 7] = bytes[ 6]; out[ 8] = bytes[ 7]; out[ 9] = '.'; out[10] = bytes[ 8]; out[11] = bytes[ 9]; out[12] = bytes[10]; out[13] = bytes[11]; out[14] = '.'; out[15] = bytes[12]; out[16] = bytes[13]; out[17] = bytes[14]; out[18] = bytes[15]; out[19] = '\0'; }
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'; 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(addr->ip6.bytes[0] == 0xfc); 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); }
static inline uint8_t incomingDHT(struct Message* message, struct Address* addr, struct Ducttape_pvt* context) { struct DHTMessage dht = { .address = addr, .binMessage = message, .allocator = message->alloc }; DHTModuleRegistry_handleIncoming(&dht, context->registry); // TODO(cjd): return something meaningful. return Error_NONE; } /** Header must not be encrypted and must be aligned on the beginning of the ipv6 header. */ static inline uint8_t sendToRouter(struct Message* message, struct Ducttape_MessageHeader* dtHeader, struct SessionManager_Session* session, struct Ducttape_pvt* context) { int safeDistance = SwitchHeader_SIZE; CryptoAuth_resetIfTimeout(session->internal); if (CryptoAuth_getState(session->internal) < CryptoAuth_HANDSHAKE3) { // Put the handle into the message so that it's authenticated. // see: sendToSwitch() //Log_debug(context->logger, "Sending receive handle under CryptoAuth"); Message_push(message, &session->receiveHandle_be, 4, NULL); safeDistance += CryptoHeader_SIZE; } else { // 16 for the authenticator, 4 for the nonce and 4 for the handle safeDistance += 24; } Message_shift(message, safeDistance, NULL); if (dtHeader->switchHeader) { if (message->bytes != (uint8_t*)dtHeader->switchHeader) { Bits_memmoveConst(message->bytes, dtHeader->switchHeader, SwitchHeader_SIZE); dtHeader->switchHeader = (struct SwitchHeader*) message->bytes; } } else { dtHeader->switchHeader = (struct SwitchHeader*) message->bytes; Bits_memset(dtHeader->switchHeader, 0, SwitchHeader_SIZE); } Message_shift(message, -safeDistance, NULL); SwitchHeader_setVersion(dtHeader->switchHeader, SwitchHeader_CURRENT_VERSION); SwitchHeader_setLabelShift(dtHeader->switchHeader, 0); dtHeader->switchHeader->label_be = Endian_hostToBigEndian64(dtHeader->switchLabel); // This comes out in outgoingFromCryptoAuth() then sendToSwitch() dtHeader->receiveHandle = Endian_bigEndianToHost32(session->receiveHandle_be); dtHeader->layer = Ducttape_SessionLayer_OUTER; return Interface_sendMessage(session->internal, message); }
static void nodeForAddress(struct PFChan_Node* nodeOut, struct Address* addr, uint32_t metric) { Bits_memset(nodeOut, 0, PFChan_Node_SIZE); nodeOut->version_be = Endian_hostToBigEndian32(addr->protocolVersion); nodeOut->metric_be = Endian_hostToBigEndian32(metric | 0xffff0000); nodeOut->path_be = Endian_hostToBigEndian64(addr->path); Bits_memcpy(nodeOut->publicKey, addr->key, 32); Bits_memcpy(nodeOut->ip6, addr->ip6.bytes, 16); }
/** * Splice a label and a label fragment together. * */ uint64_t LabelSplicer_splice(uint64_t goHere_be, uint64_t viaHere_be) { uint64_t goHere = Endian_bigEndianToHost64(goHere_be); uint64_t viaHere = Endian_bigEndianToHost64(viaHere_be); uint64_t log2ViaHere = Bits_log2x64(viaHere); if (Bits_log2x64(goHere) + log2ViaHere > 61) { // Too big, can't splice. return UINT64_MAX; } return Endian_hostToBigEndian64(((goHere ^ 1) << log2ViaHere) ^ viaHere); }
int main() { char* pingBenc = "d1:q4:ping4:txid4:abcde"; struct Allocator* alloc = MallocAllocator_new(1<<22); struct TestFramework* tf = TestFramework_setUp("0123456789abcdefghijklmnopqrstuv", alloc, NULL); struct Ducttape_pvt* dt = Identity_cast((struct Ducttape_pvt*) tf->ducttape); struct Allocator* allocator = MallocAllocator_new(85000); uint16_t buffLen = sizeof(struct Ducttape_IncomingForMe) + 8 + strlen(pingBenc); uint8_t* buff = allocator->calloc(buffLen, 1, allocator); struct Headers_SwitchHeader* sh = (struct Headers_SwitchHeader*) buff; sh->label_be = Endian_hostToBigEndian64(4); struct Headers_IP6Header* ip6 = (struct Headers_IP6Header*) &sh[1]; uint8_t herPublicKey[32]; Base32_decode(herPublicKey, 32, (uint8_t*) "0z5tscp8td1sc6cv4htp7jbls79ltqxw9pbg190x0kbm1lguqtx0", 52); AddressCalc_addressForPublicKey(ip6->sourceAddr, herPublicKey); struct Headers_UDPHeader* udp = (struct Headers_UDPHeader*) &ip6[1]; ip6->hopLimit = 0; ip6->nextHeader = 17; udp->sourceAndDestPorts = 0; udp->length_be = Endian_hostToBigEndian16(strlen(pingBenc)); strncpy((char*)(udp + 1), pingBenc, strlen(pingBenc)); dt->switchInterface.receiveMessage = catchResponse; dt->switchInterface.receiverContext = NULL; // bad checksum udp->checksum_be = 1; struct Message m = { .bytes = buff, .length = buffLen, .padding = 0 }; Ducttape_injectIncomingForMe(&m, &dt->public, herPublicKey); Assert_always(!dt->switchInterface.receiverContext); // zero checksum udp->checksum_be = 0; struct Message m2 = { .bytes = buff, .length = buffLen, .padding = 0 }; Ducttape_injectIncomingForMe(&m2, &dt->public, herPublicKey); Assert_always(dt->switchInterface.receiverContext); // good checksum udp->checksum_be = Checksum_udpIp6(ip6->sourceAddr, (uint8_t*) udp, strlen(pingBenc) + Headers_UDPHeader_SIZE); struct Message m3 = { .bytes = buff, .length = buffLen, .padding = 0 }; Ducttape_injectIncomingForMe(&m3, &dt->public, herPublicKey); Assert_always(dt->switchInterface.receiverContext); }
static void traceStep(struct RouteTracer_Trace* trace, struct Node* next) { struct RouteTracer_pvt* ctx = Identity_cast((struct RouteTracer_pvt*)trace->tracer); if (!next) { // can't find a next node, stalled. Timeout_setTimeout(noPeers, trace, 0, trace->tracer->eventBase, trace->pub.alloc); return; } Assert_true(LabelSplicer_routesThrough(trace->target, next->address.path)); trace->lastNodeAsked = next->address.path; struct RouterModule_Promise* rp = RouterModule_newMessage(next, 0, ctx->router, trace->pub.alloc); Dict* message = Dict_new(rp->alloc); #ifdef Version_4_COMPAT if (next->version < 5) { // The node doesn't support the new API so try running a search for // the bitwise complement of their address to get some peers. Dict_putString(message, CJDHTConstants_QUERY, CJDHTConstants_QUERY_FN, rp->alloc); String* notAddr = String_newBinary((char*)next->address.ip6.bytes, 16, rp->alloc); for (int i = 0; i < 16; i++) { notAddr->bytes[i] ^= 0xff; } Dict_putString(message, CJDHTConstants_TARGET, notAddr, rp->alloc); log(ctx->logger, trace, "Sending legacy search method because getpeers is unavailable"); } else { #endif Dict_putString(message, CJDHTConstants_QUERY, CJDHTConstants_QUERY_GP, rp->alloc); uint64_t labelForThem = LabelSplicer_unsplice(trace->target, next->address.path); labelForThem = Endian_hostToBigEndian64(labelForThem); String* target = String_newBinary((char*)&labelForThem, 8, rp->alloc); Dict_putString(message, CJDHTConstants_TARGET, target, rp->alloc); log(ctx->logger, trace, "Sending getpeers request"); #ifdef Version_4_COMPAT } #endif rp->userData = trace; rp->callback = responseCallback; RouterModule_sendMessage(rp, message); }
/** Header must not be encrypted and must be aligned on the beginning of the ipv6 header. */ static inline uint8_t sendToRouter(struct Message* message, struct Ducttape_MessageHeader* dtHeader, struct SessionManager_Session* session, struct Ducttape_pvt* context) { int safeDistance = Headers_SwitchHeader_SIZE; if (CryptoAuth_getState(&session->iface) < CryptoAuth_HANDSHAKE3) { // Bug 104, see Version.h #ifdef Version_2_COMPAT if (session->version >= 3) { #endif // Put the handle into the message so that it's authenticated. // see: sendToSwitch() Log_debug(context->logger, "Sending receive handle under CryptoAuth"); Message_push(message, &session->receiveHandle_be, 4); #ifdef Version_2_COMPAT } else { // Otherwise it will be added on the other side. safeDistance += 4; } #endif safeDistance += Headers_CryptoAuth_SIZE; } else { // 16 for the authenticator, 4 for the nonce and 4 for the handle safeDistance += 24; } Message_shift(message, safeDistance); if (dtHeader->switchHeader) { if (message->bytes != (uint8_t*)dtHeader->switchHeader) { Bits_memmoveConst(message->bytes, dtHeader->switchHeader, Headers_SwitchHeader_SIZE); dtHeader->switchHeader = (struct Headers_SwitchHeader*) message->bytes; } } else { dtHeader->switchHeader = (struct Headers_SwitchHeader*) message->bytes; Bits_memset(dtHeader->switchHeader, 0, Headers_SwitchHeader_SIZE); } Message_shift(message, -safeDistance); dtHeader->switchHeader->label_be = Endian_hostToBigEndian64(dtHeader->switchLabel); // This comes out in outgoingFromCryptoAuth() then sendToSwitch() dtHeader->receiveHandle = Endian_bigEndianToHost32(session->receiveHandle_be); dtHeader->layer = Ducttape_SessionLayer_OUTER; return session->iface.sendMessage(message, &session->iface); }
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; }
static void sendPeer(uint32_t pathfinderId, enum PFChan_Core ev, struct Peer* peer) { struct InterfaceController_pvt* ic = Identity_check(peer->ici->ic); struct Allocator* alloc = Allocator_child(ic->alloc); struct Message* msg = Message_new(PFChan_Node_SIZE, 512, alloc); struct PFChan_Node* node = (struct PFChan_Node*) msg->bytes; Bits_memcpyConst(node->ip6, peer->addr.ip6.bytes, 16); Bits_memcpyConst(node->publicKey, peer->addr.key, 32); node->path_be = Endian_hostToBigEndian64(peer->addr.path); node->metric_be = 0xffffffff; node->version_be = Endian_hostToBigEndian32(peer->addr.protocolVersion); Message_push32(msg, pathfinderId, NULL); Message_push32(msg, ev, NULL); Iface_send(&ic->eventEmitterIf, msg); Allocator_free(alloc); }
/** * Get the label for a particular destination from a given source. * This needs to be called before handing out a label because if a source interface is * represented using more bits than the destination interface, the destination interface * must be padded out so that the switch will find the source and destination labels compatable. * * @param target_be the label for the location to send to in big endian. * @param whoIsAsking_be the label for the node which we are sending the target to in big endian. * @return the modified target for that node in big endian. */ uint64_t LabelSplicer_getLabelFor(uint64_t target_be, uint64_t whoIsAsking_be) { uint64_t target = Endian_bigEndianToHost64(target_be); uint64_t whoIsAsking = Endian_bigEndianToHost64(whoIsAsking_be); uint32_t targetBits = NumberCompress_bitsUsedForLabel(target); uint32_t whoIsAskingBits = NumberCompress_bitsUsedForLabel(whoIsAsking); if (targetBits >= whoIsAskingBits) { return target_be; } uint32_t targetIfaceNum = NumberCompress_getDecompressed(target, targetBits); uint64_t out = ((target & (UINT64_MAX << targetBits)) << (whoIsAskingBits - targetBits)) | NumberCompress_getCompressed(targetIfaceNum, whoIsAskingBits); return Endian_hostToBigEndian64(out); }
static void mkNextRequest(struct ReachabilityCollector_pvt* rcp) { struct PeerInfo* pi = NULL; for (int i = 0; i < rcp->piList->length; i++) { pi = ArrayList_OfPeerInfo_get(rcp->piList, i); if (!pi->querying) { continue; } } if (!pi || !pi->querying) { return; } rcp->msgOnWire = MsgCore_createQuery(rcp->msgCore, TIMEOUT_MILLISECONDS, rcp->alloc); rcp->msgOnWire->userData = rcp; rcp->msgOnWire->cb = onReply; rcp->msgOnWire->target = Address_clone(&pi->addr, rcp->msgOnWire->alloc); Dict* d = rcp->msgOnWire->msg = Dict_new(rcp->msgOnWire->alloc); Dict_putStringCC(d, "q", "gp", rcp->msgOnWire->alloc); uint64_t label_be = Endian_hostToBigEndian64(pi->pathToCheck); Dict_putStringC(d, "tar", String_newBinary((uint8_t*) &label_be, 8, rcp->msgOnWire->alloc), rcp->msgOnWire->alloc); BoilerplateResponder_addBoilerplate(rcp->br, d, &pi->addr, rcp->msgOnWire->alloc); }
/** Header must not be encrypted and must be aligned on the beginning of the ipv6 header. */ static inline uint8_t sendToRouter(struct Address* sendTo, struct Message* message, struct Ducttape* context) { // We have to copy out the switch header because it // will probably be clobbered by the crypto headers. struct Headers_SwitchHeader header; if (context->switchHeader) { Bits_memcpyConst(&header, context->switchHeader, Headers_SwitchHeader_SIZE); } else { memset(&header, 0, Headers_SwitchHeader_SIZE); } header.label_be = Endian_hostToBigEndian64(sendTo->path); context->switchHeader = &header; struct Interface* session = SessionManager_getSession(sendTo->ip6.bytes, sendTo->key, context->sm); // This comes out in outgoingFromCryptoAuth() then sendToSwitch() context->layer = OUTER_LAYER; return session->sendMessage(message, session); }
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; }
static void switching(struct Context* ctx) { Log_info(ctx->log, "Setting up salsa20/poly1305 benchmark (encryption and decryption only)"); struct Allocator* alloc = Allocator_child(ctx->alloc);; struct SwitchingContext* sc = Allocator_calloc(alloc, sizeof(struct SwitchingContext), 1); Identity_set(sc); sc->benchmarkCtx = ctx; sc->aliceIf.send = aliceToBob; sc->bobIf.send = bobToAlice; sc->aliceCtrlIf.send = aliceCtrlRecv; struct NetCore* alice = NetCore_new(SECRETA, alloc, ctx->base, ctx->rand, ctx->log); struct InterfaceController_Iface* aliceIci = InterfaceController_newIface(alice->ifController, String_CONST("alice"), alloc); Iface_plumb(&sc->aliceIf, &aliceIci->addrIf); struct NetCore* bob = NetCore_new(SECRETB, alloc, ctx->base, ctx->rand, ctx->log); struct InterfaceController_Iface* bobIci = InterfaceController_newIface(bob->ifController, String_CONST("bob"), alloc); Iface_plumb(&sc->bobIf, &bobIci->addrIf); CryptoAuth_addUser(String_CONST("abcdefg123"), 1, String_CONST("TEST"), bob->ca); // Client has pubKey and passwd for the server. int ret = InterfaceController_bootstrapPeer(alice->ifController, aliceIci->ifNum, bob->ca->publicKey, Sockaddr_LOOPBACK, String_CONST("abcdefg123"), alloc); Assert_true(!ret); Iface_unplumb(alice->switchAdapter->controlIf.connectedIf, &alice->switchAdapter->controlIf); Iface_plumb(&alice->switchAdapter->controlIf, &sc->aliceCtrlIf); struct Message* msg = Message_new(Control_Ping_MIN_SIZE + Control_Header_SIZE, 256, alloc); struct Control_Header* ch = (struct Control_Header*) msg->bytes; struct Control_Ping* ping = (struct Control_Ping*) &ch[1]; ping->version_be = Endian_hostToBigEndian32(Version_CURRENT_PROTOCOL); Message_push32(msg, 0xffffffff, NULL); uint32_t* handle_be = (uint32_t*)msg->bytes; Message_push(msg, NULL, SwitchHeader_SIZE, NULL); struct SwitchHeader* sh = (struct SwitchHeader*) msg->bytes; // TODO(cjd): this will fail with a different encoding scheme sh->label_be = Endian_hostToBigEndian64(0x13); for (int i = 1; i < 6; i++) { ping->magic = Control_Ping_MAGIC; ch->type_be = Control_PING_be; ch->checksum_be = 0; ch->checksum_be = Checksum_engine((void*)ch, Control_Ping_MIN_SIZE + Control_Header_SIZE); Iface_send(&sc->aliceCtrlIf, msg); Assert_true(sc->msgCount == i); Assert_true(msg->bytes == (void*)sh); Assert_true(ping->magic == Control_Pong_MAGIC); Assert_true(ch->type_be = Control_PONG_be); Assert_true(!Checksum_engine((void*)ch, Control_Ping_MIN_SIZE + Control_Header_SIZE)); } *handle_be = 0xfffffff0; int count = 1000000; begin(ctx, "Switching", count, "packets"); for (int i = 0; i < count; i++) { sh->versionAndLabelShift = SwitchHeader_CURRENT_VERSION << 6; Iface_send(&sc->aliceCtrlIf, msg); Assert_true(msg->bytes == (void*)sh); } done(ctx); Log_info(ctx->log, "DONE"); Allocator_free(alloc); }
// incoming message from network, pointing to the beginning of the switch header. static uint8_t receiveMessage(struct Message* msg, struct Interface* iface) { struct SwitchPinger* ctx = Identity_check((struct SwitchPinger*) iface->receiverContext); 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->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 Error_INVALID; } Message_shift(msg, -Control_Pong_HEADER_SIZE, NULL); } else { Log_debug(ctx->logger, "got runt pong message, length: [%d]", msg->length); return Error_INVALID; } } else if (ctrl->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 Error_INVALID; } Bits_memcpyConst(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 Error_INVALID; } else { Log_debug(ctx->logger, "got runt key-pong message, length: [%d]", msg->length); return Error_INVALID; } } else if (ctrl->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 Error_NONE; } 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->type_be)); int shift; if (origCtrl->type_be == Control_PING_be) { shift = -(Control_HEADER_SIZE + Control_Ping_HEADER_SIZE); } else if (origCtrl->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 Error_NONE; } 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_memcpyConst(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_memcpyConst(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->checksum_be = 0; ctrl->type_be = (p->pub.keyPing) ? Control_KEYPING_be : Control_PING_be; ctrl->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; switchHeader->label_be = Endian_hostToBigEndian64(p->label); SwitchHeader_setVersion(switchHeader, SwitchHeader_CURRENT_VERSION); SwitchHeader_setPenalty(switchHeader, 0); SwitchHeader_setCongestion(switchHeader, 0); #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 p->context->iface->sendMessage(msg, p->context->iface); } 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* 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* ctx) { 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 Iface_DEFUN handlePing(struct Message* msg, struct ControlHandler_pvt* ch, uint64_t label, uint8_t* labelStr, uint16_t messageType_be) { if (msg->length < handlePing_MIN_SIZE) { Log_info(ch->log, "DROP runt ping"); return NULL; } struct Control* ctrl = (struct Control*) msg->bytes; Message_shift(msg, -Control_Header_SIZE, NULL); // Ping and keyPing share version location struct Control_Ping* ping = (struct Control_Ping*) msg->bytes; uint32_t herVersion = Endian_bigEndianToHost32(ping->version_be); if (!Version_isCompatible(Version_CURRENT_PROTOCOL, herVersion)) { Log_debug(ch->log, "DROP ping from incompatible version [%d]", herVersion); return NULL; } if (messageType_be == Control_KEYPING_be) { Log_debug(ch->log, "got switch keyPing from [%s]", labelStr); if (msg->length < Control_KeyPing_HEADER_SIZE) { // min keyPing size is longer Log_debug(ch->log, "DROP runt keyPing"); return NULL; } if (msg->length > Control_KeyPing_MAX_SIZE) { Log_debug(ch->log, "DROP long keyPing"); return NULL; } if (ping->magic != Control_KeyPing_MAGIC) { Log_debug(ch->log, "DROP keyPing (bad magic)"); return NULL; } struct Control_KeyPing* keyPing = (struct Control_KeyPing*) msg->bytes; keyPing->magic = Control_KeyPong_MAGIC; ctrl->header.type_be = Control_KEYPONG_be; Bits_memcpy(keyPing->key, ch->myPublicKey, 32); } else if (messageType_be == Control_PING_be) { // Happens in benchmark. //Log_debug(ch->log, "got switch ping from [%s]", labelStr); if (ping->magic != Control_Ping_MAGIC) { Log_debug(ch->log, "DROP ping (bad magic)"); return NULL; } ping->magic = Control_Pong_MAGIC; ctrl->header.type_be = Control_PONG_be; } else { Assert_failure("2+2=5"); } ping->version_be = Endian_hostToBigEndian32(Version_CURRENT_PROTOCOL); Message_shift(msg, Control_Header_SIZE, NULL); ctrl->header.checksum_be = 0; ctrl->header.checksum_be = Checksum_engine(msg->bytes, msg->length); Message_shift(msg, RouteHeader_SIZE, NULL); struct RouteHeader* routeHeader = (struct RouteHeader*) msg->bytes; Bits_memset(routeHeader, 0, RouteHeader_SIZE); SwitchHeader_setVersion(&routeHeader->sh, SwitchHeader_CURRENT_VERSION); routeHeader->sh.label_be = Endian_hostToBigEndian64(label); routeHeader->flags |= RouteHeader_flags_CTRLMSG; return Iface_next(&ch->pub.coreIf, msg); }