/** Called when the request allocator is freed. */ static int removeReqFromSet(struct Allocator_OnFreeJob* job) { struct Request* req = Identity_cast((struct Request*) job->userData); struct Hermes* h = Identity_cast(req->hermes); int index = Map_RequestSet_indexForHandle(req->handle, &h->requestSet); if (index > -1) { Map_RequestSet_remove(index, &h->requestSet); } else { Log_error(h->logger, "request with handle [%u] missing from set", req->handle); } return 0; }
int EventBase_eventCount(struct EventBase* eventBase) { int eventCount = 0; struct EventBase_pvt* ctx = Identity_cast((struct EventBase_pvt*) eventBase); uv_walk(ctx->loop, countCallback, &eventCount); return eventCount; }
/** @see Allocator->onFree() */ static void* addOnFreeJob(void (* callback)(void* callbackContext), void* callbackContext, const struct Allocator* allocator) { struct CanaryAllocator_pvt* ctx = Identity_cast((struct CanaryAllocator_pvt*) allocator); return ctx->alloc->onFree(callback, callbackContext, ctx->alloc); }
/** @see Allocator_child() */ static struct Allocator* childAllocator(const struct Allocator* allocator, const char* identFile, int identLine) { struct CanaryAllocator_pvt* ctx = Identity_cast((struct CanaryAllocator_pvt*) allocator); return CanaryAllocator_new(ctx->alloc->child(ctx->alloc, identFile, identLine), ctx->rand); }
int32_t CryptoAuth_addUser(String* password, uint8_t authType, void* user, struct CryptoAuth* ca) { struct CryptoAuth_pvt* context = Identity_cast((struct CryptoAuth_pvt*) ca); if (authType != 1) { return CryptoAuth_addUser_INVALID_AUTHTYPE; } if (context->passwordCount == context->passwordCapacity) { // TODO: realloc password space and increase buffer. return CryptoAuth_addUser_OUT_OF_SPACE; } struct CryptoAuth_Auth a; hashPassword_sha256(&a, password); for (uint32_t i = 0; i < context->passwordCount; i++) { if (!Bits_memcmp(a.secret, context->passwords[i].secret, 32)) { return CryptoAuth_addUser_DUPLICATE; } } a.user = user; Bits_memcpyConst(&context->passwords[context->passwordCount], &a, sizeof(struct CryptoAuth_Auth)); context->passwordCount++; return 0; }
static uint8_t sendMessage(struct Message* message, struct Interface* iface) { struct UDPAddrInterface_pvt* context = Identity_cast((struct UDPAddrInterface_pvt*) iface->senderContext); struct Sockaddr_storage addrStore; Message_pop(message, &addrStore, context->pub.addr->addrLen); Assert_true(addrStore.addr.addrLen == context->pub.addr->addrLen); if (Socket_sendto(context->socket, message->bytes, message->length, 0, &addrStore.addr) < 0) { switch (Errno_get()) { case Errno_EMSGSIZE: return Error_OVERSIZE_MESSAGE; case Errno_ENOBUFS: case Errno_EAGAIN: return Error_LINK_LIMIT_EXCEEDED; default:; Log_info(context->logger, "Got error sending to socket [%s]", Errno_getString()); } } return 0; }
static void onPingResponse(enum SwitchPinger_Result result, uint64_t label, String* data, uint32_t millisecondsLag, uint32_t version, void* onResponseContext) { if (SwitchPinger_Result_OK != result) { return; } struct IFCPeer* ep = Identity_cast((struct IFCPeer*) onResponseContext); struct Context* ic = ifcontrollerForPeer(ep); struct Address addr; Bits_memset(&addr, 0, sizeof(struct Address)); Bits_memcpyConst(addr.key, CryptoAuth_getHerPublicKey(ep->cryptoAuthIf), 32); addr.path = ep->switchLabel; Log_debug(ic->logger, "got switch pong from node with version [%d]", version); RouterModule_addNode(ic->routerModule, &addr, version); #ifdef Log_DEBUG // This will be false if it times out. //Assert_true(label == ep->switchLabel); uint8_t path[20]; AddrTools_printPath(path, label); uint8_t sl[20]; AddrTools_printPath(sl, ep->switchLabel); Log_debug(ic->logger, "Received [%s] from lazy endpoint [%s] [%s]", SwitchPinger_resultString(result)->bytes, path, sl); #endif }
// This is directly called from SwitchCore, message is not encrypted. static uint8_t sendFromSwitch(struct Message* msg, struct Interface* switchIf) { struct IFCPeer* ep = Identity_cast((struct IFCPeer*) switchIf); // This sucks but cryptoauth trashes the content when it encrypts // and we need to be capable of sending back a coherent error message. uint8_t top[255]; uint8_t* messageBytes = msg->bytes; uint16_t padding = msg->padding; uint16_t len = (msg->length < 255) ? msg->length : 255; Bits_memcpy(top, msg->bytes, len); uint8_t ret = ep->cryptoAuthIf->sendMessage(msg, ep->cryptoAuthIf); // If this node is unresponsive then return an error. struct Context* ic = ifcontrollerForPeer(ep); uint64_t now = Time_currentTimeMilliseconds(ic->eventBase); if (ret || now - ep->timeOfLastMessage > ic->unresponsiveAfterMilliseconds) { msg->bytes = messageBytes; msg->padding = padding; msg->length = len; Bits_memcpy(msg->bytes, top, len); return ret ? ret : Error_UNDELIVERABLE; } else { /* Way way way too much noise Log_debug(ic->logger, "Sending to neighbor, last message from this node was [%u] ms ago.", (now - ep->timeOfLastMessage)); */ } return Error_NONE; }
static uint8_t sendTo(struct Message* msg, struct Interface* iface) { struct TestFramework_Link* link = Identity_cast((struct TestFramework_Link*)iface->senderContext); struct Interface* dest; struct TestFramework* srcTf; if (&link->destIf == iface) { dest = &link->srcIf; srcTf = link->dest; } else if (&link->srcIf == iface) { dest = &link->destIf; srcTf = link->src; } else { Assert_always(false); } printf("Transferring message to [%p] - message length [%d]\n", (void*)dest, msg->length); // Store the original message and a copy of the original so they can be compared later. srcTf->lastMsgBackup = Message_clone(msg, srcTf->alloc); srcTf->lastMsg = msg; if (msg->alloc) { // If it's a message which was buffered inside of CryptoAuth then it will be freed // so by adopting the allocator we can hold it in memory. Allocator_adopt(srcTf->alloc, msg->alloc); } // Copy the original and send that to the other end. struct Message* sendMsg = Message_clone(msg, dest->allocator); return dest->receiveMessage(sendMsg, dest); }
/** @see Allocator->malloc() */ static void* allocatorMalloc(size_t size, const struct Allocator* allocator) { struct CanaryAllocator_pvt* ctx = Identity_cast((struct CanaryAllocator_pvt*) allocator); // get it on an even number of ints. uint32_t* out = ctx->alloc->malloc(SIZE_BYTES(size), ctx->alloc); return newAllocation(ctx, out, SIZE_INTS(size)); }
// This is directly called from SwitchCore, message is not encrypted. static uint8_t sendFromSwitch(struct Message* msg, struct Interface* switchIf) { struct IFCPeer* ep = Identity_cast((struct IFCPeer*) switchIf); ep->bytesOut += msg->length; struct Context* ic = ifcontrollerForPeer(ep); uint8_t ret; uint64_t now = Time_currentTimeMilliseconds(ic->eventBase); if (now - ep->timeOfLastMessage > ic->unresponsiveAfterMilliseconds) { // XXX: This is a hack because if the time of last message exceeds the // unresponsive time, we need to send back an error and that means // mangling the message which would otherwise be in the queue. struct Allocator* tempAlloc = Allocator_child(ic->allocator); struct Message* toSend = Message_clone(msg, tempAlloc); ret = Interface_sendMessage(ep->cryptoAuthIf, toSend); Allocator_free(tempAlloc); } else { ret = Interface_sendMessage(ep->cryptoAuthIf, msg); } // If this node is unresponsive then return an error. if (ret || now - ep->timeOfLastMessage > ic->unresponsiveAfterMilliseconds) { return ret ? ret : Error_UNDELIVERABLE; } else { /* Way way way too much noise Log_debug(ic->logger, "Sending to neighbor, last message from this node was [%u] ms ago.", (now - ep->timeOfLastMessage)); */ } return Error_NONE; }
static void timeout(void* vrequest) { struct Request* req = Identity_cast((struct Request*) vrequest); Dict resp = Dict_CONST(String_CONST("error"), String_OBJ(String_CONST("timeout")), NULL); req->onResponse(&resp, req->onResponseContext); Allocator_free(req->alloc); }
static uint8_t sendMessage(struct Message* message, struct Interface* iface) { struct AddrInterfaceAdapter_pvt* context = Identity_cast((struct AddrInterfaceAdapter_pvt*) iface); Message_shift(message, -(context->pub.addr->addrLen), NULL); return Interface_sendMessage(context->wrapped, message); }
/** * Send an arbitrary message to the tun device. * * @param message to be sent, must be prefixed with IpTunnel_PacketInfoHeader. * @param iface an interface for which receiverContext is the ducttape. */ static uint8_t sendToTun(struct Message* message, struct Interface* iface) { struct Ducttape_pvt* context = Identity_cast((struct Ducttape_pvt*)iface->receiverContext); if (context->userIf) { return context->userIf->sendMessage(message, context->userIf); } return 0; }
static uint8_t receiveMessage(struct Message* message, struct Interface* iface) { struct AddrInterfaceAdapter_pvt* context = Identity_cast((struct AddrInterfaceAdapter_pvt*) iface->receiverContext); Message_push(message, context->pub.addr, context->pub.addr->addrLen, NULL); return Interface_receiveMessage(&context->pub.generic, message); }
static uint8_t receiveMessage(struct Message* msg, struct Interface* iface) { struct Hermes* hermes = Identity_cast((struct Hermes*) iface->receiverContext); struct Allocator* alloc = Allocator_child(hermes->alloc); receiveMessage2(msg, hermes, alloc); Allocator_free(alloc); return 0; }
static int requestOnFree(struct Allocator_OnFreeJob* job) { struct Request* req = Identity_cast((struct Request*) job->userData); int idx = Map_OfRequestByHandle_indexForHandle(req->handle, &req->ctx->outstandingRequests); if (idx > -1) { Map_OfRequestByHandle_remove(idx, &req->ctx->outstandingRequests); } return 0; }
static void noPeers(void* vtrace) { struct RouteTracer_Trace* trace = Identity_cast((struct RouteTracer_Trace*)vtrace); // trace has stalled. if (trace->pub.callback) { trace->pub.callback(&trace->pub, 0, NULL, NULL); } Allocator_free(trace->pub.alloc); }
static uint8_t receiveMessage(struct Message* received, struct Interface* interface) { struct CryptoAuth_Wrapper* wrapper = Identity_cast((struct CryptoAuth_Wrapper*) interface->receiverContext); union Headers_CryptoAuth* header = (union Headers_CryptoAuth*) received->bytes; if (received->length < (wrapper->authenticatePackets ? 20 : 4)) { cryptoAuthDebug0(wrapper, "Dropped runt"); return Error_UNDERSIZE_MESSAGE; } Assert_true(received->padding >= 12 || "need at least 12 bytes of padding in incoming message"); #ifdef Log_DEBUG Assert_true(!((uintptr_t)received->bytes % 4) || !"alignment fault"); #endif Message_shift(received, -4); uint32_t nonce = Endian_bigEndianToHost32(header->nonce); if (wrapper->nextNonce < 5) { if (nonce > 3 && nonce != UINT32_MAX && knowHerKey(wrapper)) { cryptoAuthDebug(wrapper, "Trying final handshake step, nonce=%u\n", nonce); uint8_t secret[32]; getSharedSecret(secret, wrapper->secret, wrapper->tempKey, NULL, wrapper->context->logger); // We'll optimistically advance the nextNonce value because decryptMessage() // passes the message on to the upper level and if this message causes a // response, we want the CA to be in ESTABLISHED state. // if the decryptMessage() call fails, we CryptoAuth_reset() it back. wrapper->nextNonce += 3; if (decryptMessage(wrapper, nonce, received, secret)) { cryptoAuthDebug0(wrapper, "Final handshake step succeeded"); Bits_memcpyConst(wrapper->secret, secret, 32); return callReceivedMessage(wrapper, received); } CryptoAuth_reset(&wrapper->externalInterface); cryptoAuthDebug0(wrapper, "Final handshake step failed"); return Error_UNDELIVERABLE; } } else if (nonce > 4) { if (decryptMessage(wrapper, nonce, received, wrapper->secret)) { return callReceivedMessage(wrapper, received); } else { cryptoAuthDebug0(wrapper, "Failed to decrypt message"); return Error_UNDELIVERABLE; } } else { cryptoAuthDebug0(wrapper, "Received handshake message during established connection"); } Message_shift(received, 4); return decryptHandshake(wrapper, nonce, received, header); }
static void closeInterface(void* vendpoint) { struct IFCPeer* toClose = Identity_cast((struct IFCPeer*) vendpoint); struct Context* ic = ifcontrollerForPeer(toClose); int index = Map_OfIFCPeerByExernalIf_indexForHandle(toClose->handle, &ic->peerMap); Assert_true(index >= 0); Map_OfIFCPeerByExernalIf_remove(index, &ic->peerMap); }
static int closeInterface(struct Allocator_OnFreeJob* job) { struct IFCPeer* toClose = Identity_cast((struct IFCPeer*) job->userData); struct Context* ic = ifcontrollerForPeer(toClose); int index = Map_OfIFCPeerByExernalIf_indexForHandle(toClose->handle, &ic->peerMap); Assert_true(index >= 0); Map_OfIFCPeerByExernalIf_remove(index, &ic->peerMap); return 0; }
static void sendMessageCallback(uv_write_t* uvReq, int error) { struct Pipe_WriteRequest_pvt* req = Identity_cast((struct Pipe_WriteRequest_pvt*) uvReq); if (error) { Log_info(req->pipe->pub.logger, "Failed to write to pipe [%s] [%s]", req->pipe->pub.fullName, uv_strerror(error) ); } req->pipe->queueLen -= req->msg->length; Assert_true(req->pipe->queueLen >= 0); Allocator_free(req->alloc); }
static int onFree(struct Allocator_OnFreeJob* job) { struct EventBase_pvt* ctx = Identity_cast((struct EventBase_pvt*) job->userData); if (ctx->running) { // The job will be completed in EventLoop_beginLoop() ctx->onFree = job; EventBase_endLoop((struct EventBase*) ctx); return Allocator_ONFREE_ASYNC; } else { uv_loop_delete(ctx->loop); return 0; } }
struct RouterModule_Promise* RouteTracer_trace(uint64_t route, struct RouteTracer* routeTracer, struct Allocator* allocator) { struct RouteTracer_pvt* tracer = Identity_cast((struct RouteTracer_pvt*)routeTracer); struct Allocator* alloc = Allocator_child(allocator); struct RouteTracer_Trace* trace = Allocator_clone(alloc, (&(struct RouteTracer_Trace) { .target = route, .tracer = tracer, .pub = { .alloc = alloc } }));
static uint8_t sendMessage(struct Message* message, struct Interface* ethIf) { struct ETHInterface* context = Identity_cast((struct ETHInterface*) ethIf); struct sockaddr_ll addr; Bits_memcpyConst(&addr, &context->addrBase, sizeof(struct sockaddr_ll)); Message_pop(message, addr.sll_addr, 8); /* Cut down on the noise uint8_t buff[sizeof(addr) * 2 + 1] = {0}; Hex_encode(buff, sizeof(buff), (uint8_t*)&addr, sizeof(addr)); Log_debug(context->logger, "Sending ethernet frame to [%s]", buff); */ // Check if we will have to pad the message and pad if necessary. int pad = 0; for (int length = message->length; length+2 < MIN_PACKET_SIZE; length += 8) { pad++; } if (pad > 0) { int length = message->length; Message_shift(message, pad*8); Bits_memset(message->bytes, 0, pad*8); Bits_memmove(message->bytes, &message->bytes[pad*8], length); } Assert_true(pad < 8); uint16_t padAndId_be = Endian_hostToBigEndian16((context->id << 3) | pad); Message_push(message, &padAndId_be, 2); if (sendto(context->socket, message->bytes, message->length, 0, (struct sockaddr*) &addr, sizeof(struct sockaddr_ll)) < 0) { switch (errno) { case EMSGSIZE: return Error_OVERSIZE_MESSAGE; case ENOBUFS: case EAGAIN: return Error_LINK_LIMIT_EXCEEDED; default:; Log_info(context->logger, "Got error sending to socket [%s]", strerror(errno)); } } return 0; }
static int closeInterface(struct Allocator_OnFreeJob* job) { struct IFCPeer* toClose = Identity_cast((struct IFCPeer*) job->userData); struct Context* ic = ifcontrollerForPeer(toClose); // flush the peer from the table... RouterModule_brokenPath(toClose->switchLabel, ic->routerModule); int index = Map_OfIFCPeerByExernalIf_indexForHandle(toClose->handle, &ic->peerMap); Assert_true(index >= 0); Map_OfIFCPeerByExernalIf_remove(index, &ic->peerMap); return 0; }
static uint8_t receiveMessage(struct Message* msg, struct Interface* iface) { struct Context* ctx = Identity_cast((struct Context*) iface->receiverContext); 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 0; } // 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); struct Reader* reader = ArrayReader_new(msg->bytes, msg->length, alloc); Dict* d = Dict_new(alloc); if (StandardBencSerializer_get()->parseDictionary(reader, alloc, d)) { return 0; } String* txid = Dict_getString(d, String_CONST("txid")); if (!txid || txid->len != 8) { return 0; } // 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 0; } 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 0; }
List* CryptoAuth_getUsers(struct CryptoAuth* context, struct Allocator* alloc) { struct CryptoAuth_pvt* ctx = Identity_cast((struct CryptoAuth_pvt*) context); uint32_t count = ctx->passwordCount; List* users = NULL; for (uint32_t i = 0; i < count; i++ ) { users = List_addString(users, String_clone(ctx->passwords[i].user, alloc), alloc); } return users; }
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); }