static String* getExpectedResponse(struct Sockaddr* sa4, int prefix4, int alloc4, struct Sockaddr* sa6, int prefix6, int alloc6, struct Allocator* allocator) { Assert_true(alloc6 >= prefix6); Assert_true(alloc4 >= prefix4); struct Allocator* alloc = Allocator_child(allocator); Dict* addresses = Dict_new(alloc); if (sa4) { uint8_t* addr = NULL; Assert_true(Sockaddr_getAddress(sa4, &addr) == 4); String* addrStr = String_newBinary(addr, 4, alloc); Dict_putString(addresses, String_new("ip4", alloc), addrStr, alloc); Dict_putInt(addresses, String_new("ip4Prefix", alloc), prefix4, alloc); Dict_putInt(addresses, String_new("ip4Alloc", alloc), alloc4, alloc); } if (sa6) { uint8_t* addr = NULL; Assert_true(Sockaddr_getAddress(sa6, &addr) == 16); String* addrStr = String_newBinary(addr, 16, alloc); Dict_putString(addresses, String_new("ip6", alloc), addrStr, alloc); Dict_putInt(addresses, String_new("ip6Prefix", alloc), prefix6, alloc); Dict_putInt(addresses, String_new("ip6Alloc", alloc), alloc6, alloc); } Dict* output = Dict_new(alloc); Dict_putDict(output, String_new("addresses", alloc), addresses, alloc); Dict_putString(output, String_new("txid", alloc), String_new("abcd", alloc), alloc); struct Message* msg = Message_new(0, 512, alloc); BencMessageWriter_write(output, msg, NULL); String* outStr = String_newBinary(msg->bytes, msg->length, allocator); Allocator_free(alloc); return outStr; }
static void dumpTable(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc) { struct Context* ctx = Identity_check((struct Context*) vcontext); int64_t* page = Dict_getInt(args, String_CONST("page")); int ctr = (page) ? *page * ENTRIES_PER_PAGE : 0; Dict* out = Dict_new(requestAlloc); List* table = List_new(requestAlloc); struct Node_Two* nn = NULL; for (int i = 0; i < ctr+ENTRIES_PER_PAGE; i++) { nn = NodeStore_getNextNode(ctx->store, nn); if (!nn) { break; } if (i < ctr) { continue; } Dict* nodeDict = Dict_new(requestAlloc); String* ip = String_newBinary(NULL, 39, requestAlloc); Address_printIp(ip->bytes, &nn->address); Dict_putString(nodeDict, String_CONST("ip"), ip, requestAlloc); String* addr = Address_toString(&nn->address, requestAlloc); Dict_putString(nodeDict, String_CONST("addr"), addr, requestAlloc); String* path = String_newBinary(NULL, 19, requestAlloc); AddrTools_printPath(path->bytes, nn->address.path); Dict_putString(nodeDict, String_CONST("path"), path, requestAlloc); Dict_putInt(nodeDict, String_CONST("link"), Node_getCost(nn), requestAlloc); Dict_putInt(nodeDict, String_CONST("version"), nn->address.protocolVersion, requestAlloc); Dict_putInt(nodeDict, String_CONST("time"), NodeStore_timeSinceLastPing(ctx->store, nn), requestAlloc); Dict_putInt(nodeDict, String_CONST("bucket"), NodeStore_bucketForAddr(ctx->store->selfAddress, &nn->address), requestAlloc); List_addDict(table, nodeDict, requestAlloc); } Dict_putList(out, String_CONST("routingTable"), table, requestAlloc); if (nn) { Dict_putInt(out, String_CONST("more"), 1, requestAlloc); } Dict_putInt(out, String_CONST("count"), ctx->store->nodeCount, requestAlloc); Dict_putInt(out, String_CONST("peers"), ctx->store->peerCount, requestAlloc); Dict_putString(out, String_CONST("deprecation"), String_CONST("ip,path,version will soon be removed"), requestAlloc); Admin_sendMessage(out, txid, ctx->admin); }
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); }
static int calculateAuth(Dict* message, String* password, String* cookieStr, struct Allocator* alloc) { // Calculate the hash of the password. String* hashHex = String_newBinary(NULL, 64, alloc); uint8_t passAndCookie[64]; uint32_t cookie = (cookieStr != NULL) ? strtoll(cookieStr->bytes, NULL, 10) : 0; snprintf((char*) passAndCookie, 64, "%s%u", password->bytes, cookie); uint8_t hash[32]; crypto_hash_sha256(hash, passAndCookie, CString_strlen((char*) passAndCookie)); Hex_encode((uint8_t*)hashHex->bytes, 64, hash, 32); Dict_putString(message, String_new("hash", alloc), hashHex, alloc); Dict_putString(message, String_new("cookie", alloc), cookieStr, alloc); // serialize the message with the password hash struct Message* msg = Message_new(0, AdminClient_MAX_MESSAGE_SIZE, alloc); BencMessageWriter_write(message, msg, NULL); // calculate the hash of the message with the password hash crypto_hash_sha256(hash, msg->bytes, msg->length); // swap the hash of the message with the password hash into the location // where the password hash was. Hex_encode((uint8_t*)hashHex->bytes, 64, hash, 32); return 0; }
String* VersionList_stringify(struct VersionList* list, struct Allocator* alloc) { uint8_t numberSize = 1; uint32_t max = 0xff; for (int i = 0; i < (int)list->length; i++) { while (list->versions[i] >= max) { numberSize++; max = max << 8 | 0xff; } } String* out = String_newBinary(NULL, (numberSize * list->length + 1), alloc); struct Writer* w = ArrayWriter_new(out->bytes, out->len, alloc); Writer_write(w, &numberSize, 1); for (int i = 0; i < (int)list->length; i++) { uint32_t ver = list->versions[i] << ((4-numberSize) * 8); ver = Endian_hostToBigEndian32(ver); Writer_write(w, (uint8_t*) &ver, numberSize); } Writer_write(w, &numberSize, 1); return out; }
static int calculateAuth(Dict* message, String* password, String* cookieStr, struct Allocator* alloc) { // Calculate the hash of the password. String* hashHex = String_newBinary(NULL, 64, alloc); uint8_t passAndCookie[64]; uint32_t cookie = (cookieStr != NULL) ? strtoll(cookieStr->bytes, NULL, 10) : 0; snprintf((char*) passAndCookie, 64, "%s%u", password->bytes, cookie); uint8_t hash[32]; crypto_hash_sha256(hash, passAndCookie, strlen((char*) passAndCookie)); Hex_encode((uint8_t*)hashHex->bytes, 64, hash, 32); Dict_putString(message, String_new("hash", alloc), hashHex, alloc); Dict_putString(message, String_new("cookie", alloc), cookieStr, alloc); // serialize the message with the password hash uint8_t buffer[AdminClient_MAX_MESSAGE_SIZE]; struct Writer* writer = ArrayWriter_new(buffer, AdminClient_MAX_MESSAGE_SIZE, alloc); if (StandardBencSerializer_get()->serializeDictionary(writer, message)) { return -1; } int length = writer->bytesWritten; // calculate the hash of the message with the password hash crypto_hash_sha256(hash, buffer, length); // swap the hash of the message with the password hash into the location // where the password hash was. Hex_encode((uint8_t*)hashHex->bytes, 64, hash, 32); return 0; }
struct SupernodeHunter* SupernodeHunter_new(struct Allocator* allocator, struct Log* log, struct EventBase* base, struct AddrSet* peers, struct MsgCore* msgCore, struct Address* myAddress) { struct Allocator* alloc = Allocator_child(allocator); struct SupernodeHunter_pvt* out = Allocator_calloc(alloc, sizeof(struct SupernodeHunter_pvt), 1); out->authorizedSnodes = AddrSet_new(alloc); out->peers = peers; out->base = base; out->nodes = AddrSet_new(alloc); //out->timeSnodeCalled = Time_currentTimeMilliseconds(base); out->snodeCandidates = AddrSet_new(alloc); out->log = log; out->alloc = alloc; out->msgCore = msgCore; out->myAddress = myAddress; out->selfAddrStr = String_newBinary(myAddress->ip6.bytes, 16, alloc); Identity_set(out); Timeout_setInterval(pingCycle, out, CYCLE_MS, base, alloc); return &out->pub; }
String* EncodingScheme_serialize(struct EncodingScheme* list, struct Allocator* alloc) { Assert_true(EncodingScheme_isSane(list)); // Create the string as the largest that is possible for the list size. String* out = String_newBinary(NULL, list->count * 6, alloc); int bits = 0; int outIndex = 0; uint64_t block = 0; for (int listIndex = 0; listIndex < (int)list->count; listIndex++) { bits += encodeForm(&list->forms[listIndex], &block, bits); while (bits > 8) { Assert_true(outIndex < (int)out->len); out->bytes[outIndex++] = (uint8_t) (block & 0xff); bits -= 8; block >>= 8; } } if (bits > 0) { out->bytes[outIndex++] = (uint8_t) (block & 0xff); } out->len = outIndex; return out; }
static inline int parseString(const struct Reader* reader, const struct Allocator* allocator, String** output) { #define BUFF_SZ (1<<8) #define BUFF_MAX (1<<20) int curSize = BUFF_SZ; struct Allocator* localAllocator = Allocator_child(allocator); uint8_t* buffer = localAllocator->malloc(curSize, localAllocator); if (readUntil('"', reader) || reader->read(buffer, 1, reader)) { printf("Unterminated string\n"); localAllocator->free(localAllocator); return OUT_OF_CONTENT_TO_READ; } for (int i = 0; i < BUFF_MAX - 1; i++) { if (buffer[i] == '\\') { // \x01 (skip the x) reader->skip(1, reader); uint8_t hex[2]; if (reader->read((char*)hex, 2, reader)) { printf("Unexpected end of input parsing escape sequence\n"); localAllocator->free(localAllocator); return OUT_OF_CONTENT_TO_READ; } int byte = Hex_decodeByte(hex[0], hex[1]); if (byte == -1) { printf("Invalid escape \"%c%c\" after \"%.*s\"\n",hex[0],hex[1],i+1,buffer); localAllocator->free(localAllocator); return UNPARSABLE; } buffer[i] = (uint8_t) byte; } else if (buffer[i] == '"') { *output = String_newBinary((char*)buffer, i, allocator); localAllocator->free(localAllocator); return 0; } if (i == curSize - 1) { curSize <<= 1; buffer = localAllocator->realloc(buffer, curSize, localAllocator); } if (reader->read(buffer + i + 1, 1, reader)) { if (i+1 <= 20) { printf("Unterminated string \"%.*s\"\n", i+1, buffer); } else { printf("Unterminated string starting with \"%.*s...\"\n", 20, buffer); } localAllocator->free(localAllocator); return OUT_OF_CONTENT_TO_READ; } } printf("Maximum string length of %d bytes exceeded.\n",BUFF_SZ); localAllocator->free(localAllocator); return UNPARSABLE; #undef BUFF_SZ #undef BUFF_MAX }
// Just make sure random crap doesn't crash it. static void fuzzTest(struct Allocator* parent, struct Random* rand) { struct Allocator* alloc = Allocator_child(parent); String* data = String_newBinary(NULL, Random_uint32(rand) % 1024, alloc); Random_bytes(rand, (uint8_t*)data->bytes, data->len); EncodingScheme_deserialize(data, alloc); Allocator_free(alloc); }
String* Key_stringify(uint8_t key[32], struct Allocator* alloc) { String* out = String_newBinary(NULL, 55, alloc); Base32_encode((uint8_t*)out->bytes, 53, key, 32); out->bytes[53] = '.'; out->bytes[54] = 'k'; return out; }
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 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); }
static void getRouteLabel(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc) { struct Context* ctx = Identity_check((struct Context*) vcontext); char* err = NULL; String* pathToParentS = Dict_getString(args, String_CONST("pathToParent")); uint64_t pathToParent = 0; if (pathToParentS->len != 19 || AddrTools_parsePath(&pathToParent, pathToParentS->bytes)) { err = "parse_pathToParent"; } String* pathParentToChildS = Dict_getString(args, String_CONST("pathParentToChild")); uint64_t pathParentToChild = 0; if (pathParentToChildS->len != 19 || AddrTools_parsePath(&pathParentToChild, pathParentToChildS->bytes)) { err = "parse_pathParentToChild"; } uint64_t label = UINT64_MAX; if (!err) { label = NodeStore_getRouteLabel(ctx->store, pathToParent, pathParentToChild); err = NodeStore_getRouteLabel_strerror(label); } Dict* response = Dict_new(requestAlloc); if (!err) { String* printedPath = String_newBinary(NULL, 19, requestAlloc); AddrTools_printPath(printedPath->bytes, label); Dict_putString(response, String_new("result", requestAlloc), printedPath, requestAlloc); Dict_putString(response, String_new("error", requestAlloc), String_new("none", requestAlloc), requestAlloc); Admin_sendMessage(response, txid, ctx->admin); } else { Dict_putString(response, String_new("error", requestAlloc), String_new(err, requestAlloc), requestAlloc); Admin_sendMessage(response, txid, ctx->admin); } }
List* EncodingScheme_asList(struct EncodingScheme* list, struct Allocator* alloc) { Assert_true(EncodingScheme_isSane(list)); String* prefixLen = String_new("prefixLen", alloc); String* bitCount = String_new("bitCount", alloc); String* prefix = String_new("prefix", alloc); List* scheme = NULL; for (int i = 0; i < (int)list->count; i++) { Dict* form = Dict_new(alloc); Dict_putInt(form, prefixLen, list->forms[i].prefixLen, alloc); Dict_putInt(form, bitCount, list->forms[i].bitCount, alloc); String* pfx = String_newBinary(NULL, 8, alloc); uint32_t prefix_be = Endian_hostToBigEndian32(list->forms[i].prefix); Hex_encode(pfx->bytes, 8, (uint8_t*)&prefix_be, 4); Dict_putString(form, prefix, pfx, alloc); scheme = List_addDict(scheme, form, alloc); } return scheme; }
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 pingResponse(struct RouterModule_Promise* promise, uint32_t lag, struct Address* from, Dict* responseDict) { struct Ping* ping = Identity_check((struct Ping*)promise->userData); struct Allocator* tempAlloc = promise->alloc; Dict* resp = Dict_new(tempAlloc); String* versionBin = Dict_getString(responseDict, CJDHTConstants_VERSION); if (versionBin && versionBin->len == 20) { String* versionStr = String_newBinary(NULL, 40, tempAlloc); Hex_encode(versionStr->bytes, 40, versionBin->bytes, 20); Dict_putString(resp, String_CONST("version"), versionStr, tempAlloc); } else { Dict_putString(resp, String_CONST("version"), String_CONST("unknown"), tempAlloc); } String* result = (responseDict) ? String_CONST("pong") : String_CONST("timeout"); Dict_putString(resp, String_CONST("result"), result, tempAlloc); int64_t* protocolVersion = Dict_getInt(responseDict, CJDHTConstants_PROTOCOL); if (protocolVersion) { Dict_putInt(resp, String_CONST("protocol"), *protocolVersion, tempAlloc); } Dict_putInt(resp, String_CONST("ms"), lag, tempAlloc); if (from) { uint8_t fromStr[60] = ""; Address_print(fromStr, from); Dict_putString(resp, String_CONST("from"), String_new(fromStr, tempAlloc), tempAlloc); } Admin_sendMessage(resp, ping->txid, ping->ctx->admin); }
struct Context* ctx, String* cookie, AdminClient_RespHandler callback) { struct Allocator* reqAlloc = Allocator_child(promise->alloc); struct Request* req = Allocator_clone(reqAlloc, (&(struct Request) { .alloc = reqAlloc, .ctx = ctx, .promise = promise })); Identity_set(req); int idx = Map_OfRequestByHandle_put(&req, &ctx->outstandingRequests); req->handle = ctx->outstandingRequests.handles[idx]; String* id = String_newBinary(NULL, 8, req->alloc); Hex_encode(id->bytes, 8, (int8_t*) &req->handle, 4); Dict_putString(messageDict, String_CONST("txid"), id, req->alloc); if (cookie) { Assert_true(!calculateAuth(messageDict, ctx->password, cookie, req->alloc)); } struct Allocator* child = Allocator_child(req->alloc); struct Message* msg = Message_new(0, AdminClient_MAX_MESSAGE_SIZE + 256, child); BencMessageWriter_write(messageDict, msg, NULL); req->timeoutAlloc = Allocator_child(req->alloc); req->timeout = Timeout_setTimeout(timeout, req, ctx->pub.millisecondsToWait,
/** * 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); }
int main(int argc, char** argv) { #ifdef Log_KEYS fprintf(stderr, "Log_LEVEL = KEYS, EXPECT TO SEE PRIVATE KEYS IN YOUR LOGS!\n"); #endif Assert_true(argc > 0); struct Except* eh = NULL; // Allow it to allocate 4MB struct Allocator* allocator = MallocAllocator_new(1<<22); struct Random* rand = Random_new(allocator, NULL, eh); struct EventBase* eventBase = EventBase_new(allocator); if (argc == 2) { // one argument if (strcmp(argv[1], "--help") == 0) { return usage(argv[0]); } else if (strcmp(argv[1], "--genconf") == 0) { return genconf(rand); } else if (strcmp(argv[1], "--pidfile") == 0) { // Performed after reading the configuration } else if (strcmp(argv[1], "--reconf") == 0) { // Performed after reading the configuration } else if (strcmp(argv[1], "--bench") == 0) { return benchmark(); } else if (strcmp(argv[1], "--version") == 0) { //printf("Version ID: %s\n", RouterModule_gitVersion()); return 0; } else { fprintf(stderr, "%s: unrecognized option '%s'\n", argv[0], argv[1]); fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]); return -1; } } else if (argc > 2) { // more than one argument? fprintf(stderr, "%s: too many arguments\n", argv[0]); fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]); return -1; } if (isatty(STDIN_FILENO)) { // We were started from a terminal // The chances an user wants to type in a configuration // bij hand are pretty slim so we show him the usage return usage(argv[0]); } else { // We assume stdin is a configuration file and that we should // start routing } struct Reader* stdinReader = FileReader_new(stdin, allocator); Dict config; if (JsonBencSerializer_get()->parseDictionary(stdinReader, allocator, &config)) { fprintf(stderr, "Failed to parse configuration.\n"); return -1; } struct Writer* logWriter = FileWriter_new(stdout, allocator); struct Log* logger = WriterLog_new(logWriter, allocator); // --------------------- Setup Pipes to Angel --------------------- // int pipeToAngel[2]; int pipeFromAngel[2]; if (Pipe_createUniPipe(pipeToAngel) || Pipe_createUniPipe(pipeFromAngel)) { Except_raise(eh, -1, "Failed to create pipes to angel [%s]", Errno_getString()); } char pipeToAngelStr[8]; snprintf(pipeToAngelStr, 8, "%d", pipeToAngel[0]); char pipeFromAngelStr[8]; snprintf(pipeFromAngelStr, 8, "%d", pipeFromAngel[1]); char* args[] = { "angel", pipeToAngelStr, pipeFromAngelStr, NULL }; // --------------------- Spawn Angel --------------------- // String* privateKey = Dict_getString(&config, String_CONST("privateKey")); String* corePath = getCorePath(allocator); if (!corePath) { Except_raise(eh, -1, "Can't find a usable cjdns core executable, " "make sure it is in the same directory as cjdroute"); } if (!privateKey) { Except_raise(eh, -1, "Need to specify privateKey."); } Log_info(logger, "Forking angel to background."); Process_spawn(corePath->bytes, args); // --------------------- Get Admin --------------------- // Dict* configAdmin = Dict_getDict(&config, String_CONST("admin")); String* adminPass = Dict_getString(configAdmin, String_CONST("password")); String* adminBind = Dict_getString(configAdmin, String_CONST("bind")); if (!adminPass) { adminPass = String_newBinary(NULL, 32, allocator); Random_base32(rand, (uint8_t*) adminPass->bytes, 32); adminPass->len = strlen(adminPass->bytes); } if (!adminBind) { adminBind = String_new("127.0.0.1:0", allocator); } // --------------------- Get user for angel to setuid() ---------------------- // String* securityUser = NULL; List* securityConf = Dict_getList(&config, String_CONST("security")); for (int i = 0; i < List_size(securityConf); i++) { securityUser = Dict_getString(List_getDict(securityConf, i), String_CONST("setuser")); if (securityUser) { int64_t* ea = Dict_getInt(List_getDict(securityConf, i), String_CONST("exemptAngel")); if (ea && *ea) { securityUser = NULL; } break; } } // --------------------- Pre-Configure Angel ------------------------- // Dict* preConf = Dict_new(allocator); Dict* adminPreConf = Dict_new(allocator); Dict_putDict(preConf, String_CONST("admin"), adminPreConf, allocator); Dict_putString(adminPreConf, String_CONST("core"), corePath, allocator); Dict_putString(preConf, String_CONST("privateKey"), privateKey, allocator); Dict_putString(adminPreConf, String_CONST("bind"), adminBind, allocator); Dict_putString(adminPreConf, String_CONST("pass"), adminPass, allocator); if (securityUser) { Dict_putString(adminPreConf, String_CONST("user"), securityUser, allocator); } #define CONFIG_BUFF_SIZE 1024 uint8_t buff[CONFIG_BUFF_SIZE] = {0}; struct Writer* toAngelWriter = ArrayWriter_new(buff, CONFIG_BUFF_SIZE - 1, allocator); if (StandardBencSerializer_get()->serializeDictionary(toAngelWriter, preConf)) { Except_raise(eh, -1, "Failed to serialize pre-configuration"); } write(pipeToAngel[1], buff, toAngelWriter->bytesWritten(toAngelWriter)); Log_keys(logger, "Sent [%s] to angel process.", buff); // --------------------- Get Response from Angel --------------------- // uint32_t amount = Waiter_getData(buff, CONFIG_BUFF_SIZE, pipeFromAngel[0], eventBase, eh); Dict responseFromAngel; struct Reader* responseFromAngelReader = ArrayReader_new(buff, amount, allocator); if (StandardBencSerializer_get()->parseDictionary(responseFromAngelReader, allocator, &responseFromAngel)) { Except_raise(eh, -1, "Failed to parse pre-configuration response [%s]", buff); } // --------------------- Get Admin Addr/Port/Passwd --------------------- // Dict* responseFromAngelAdmin = Dict_getDict(&responseFromAngel, String_CONST("admin")); adminBind = Dict_getString(responseFromAngelAdmin, String_CONST("bind")); if (!adminBind) { Except_raise(eh, -1, "didn't get address and port back from angel"); } struct Sockaddr_storage adminAddr; if (Sockaddr_parse(adminBind->bytes, &adminAddr)) { Except_raise(eh, -1, "Unable to parse [%s] as an ip address port, eg: 127.0.0.1:11234", adminBind->bytes); } // sanity check Assert_true(EventBase_eventCount(eventBase) == 0); // --------------------- Configuration ------------------------- // Configurator_config(&config, &adminAddr.addr, adminPass, eventBase, logger, allocator); return 0; }
int main(int argc, char** argv) { #ifdef Log_KEYS fprintf(stderr, "Log_LEVEL = KEYS, EXPECT TO SEE PRIVATE KEYS IN YOUR LOGS!\n"); #endif if (argc < 2) { // Fall through. } else if (!CString_strcmp("angel", argv[1])) { return AngelInit_main(argc, argv); } else if (!CString_strcmp("core", argv[1])) { return Core_main(argc, argv); } Assert_ifParanoid(argc > 0); struct Except* eh = NULL; // Allow it to allocate 8MB struct Allocator* allocator = MallocAllocator_new(1<<23); struct Random* rand = Random_new(allocator, NULL, eh); struct EventBase* eventBase = EventBase_new(allocator); if (argc == 2) { // one argument if ((CString_strcmp(argv[1], "--help") == 0) || (CString_strcmp(argv[1], "-h") == 0)) { return usage(allocator, argv[0]); } else if (CString_strcmp(argv[1], "--genconf") == 0) { return genconf(rand); } else if (CString_strcmp(argv[1], "--pidfile") == 0) { // deprecated fprintf(stderr, "'--pidfile' option is deprecated.\n"); return 0; } else if (CString_strcmp(argv[1], "--reconf") == 0) { // Performed after reading the configuration } else if (CString_strcmp(argv[1], "--bench") == 0) { return benchmark(); } else if ((CString_strcmp(argv[1], "--version") == 0) || (CString_strcmp(argv[1], "-v") == 0)) { printf("Cjdns protocol version: %d\n", Version_CURRENT_PROTOCOL); return 0; } else if (CString_strcmp(argv[1], "--cleanconf") == 0) { // Performed after reading configuration } else if (CString_strcmp(argv[1], "--nobg") == 0) { // Performed while reading configuration } else { fprintf(stderr, "%s: unrecognized option '%s'\n", argv[0], argv[1]); fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]); return -1; } } else if (argc > 2) { // more than one argument? fprintf(stderr, "%s: too many arguments [%s]\n", argv[0], argv[1]); fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]); // because of '--pidfile $filename'? if (CString_strcmp(argv[1], "--pidfile") == 0) { fprintf(stderr, "\n'--pidfile' option is deprecated.\n"); } return -1; } if (isatty(STDIN_FILENO)) { // We were started from a terminal // The chances an user wants to type in a configuration // bij hand are pretty slim so we show him the usage return usage(allocator, argv[0]); } else { // We assume stdin is a configuration file and that we should // start routing } struct Reader* stdinReader = FileReader_new(stdin, allocator); Dict config; if (JsonBencSerializer_get()->parseDictionary(stdinReader, allocator, &config)) { fprintf(stderr, "Failed to parse configuration.\n"); return -1; } if (argc == 2 && CString_strcmp(argv[1], "--cleanconf") == 0) { struct Writer* stdoutWriter = FileWriter_new(stdout, allocator); JsonBencSerializer_get()->serializeDictionary(stdoutWriter, &config); printf("\n"); return 0; } int forceNoBackground = 0; if (argc == 2 && CString_strcmp(argv[1], "--nobg") == 0) { forceNoBackground = 1; } struct Writer* logWriter = FileWriter_new(stdout, allocator); struct Log* logger = WriterLog_new(logWriter, allocator); // --------------------- Get Admin --------------------- // Dict* configAdmin = Dict_getDict(&config, String_CONST("admin")); String* adminPass = Dict_getString(configAdmin, String_CONST("password")); String* adminBind = Dict_getString(configAdmin, String_CONST("bind")); if (!adminPass) { adminPass = String_newBinary(NULL, 32, allocator); Random_base32(rand, (uint8_t*) adminPass->bytes, 32); adminPass->len = CString_strlen(adminPass->bytes); } if (!adminBind) { Except_throw(eh, "You must specify admin.bind in the cjdroute.conf file."); } // --------------------- Welcome to cjdns ---------------------- // char* archInfo = ArchInfo_describe(ArchInfo_detect(), allocator); char* sysInfo = SysInfo_describe(SysInfo_detect(), allocator); Log_info(logger, "Cjdns %s %s", archInfo, sysInfo); // --------------------- Check for running instance --------------------- // Log_info(logger, "Checking for running instance..."); checkRunningInstance(allocator, eventBase, adminBind, adminPass, logger, eh); // --------------------- Setup Pipes to Angel --------------------- // char angelPipeName[64] = "client-angel-"; Random_base32(rand, (uint8_t*)angelPipeName+13, 31); Assert_ifParanoid(EventBase_eventCount(eventBase) == 0); struct Pipe* angelPipe = Pipe_named(angelPipeName, eventBase, eh, allocator); Assert_ifParanoid(EventBase_eventCount(eventBase) == 2); angelPipe->logger = logger; char* args[] = { "angel", angelPipeName, NULL }; // --------------------- Spawn Angel --------------------- // String* privateKey = Dict_getString(&config, String_CONST("privateKey")); char* corePath = Process_getPath(allocator); if (!corePath) { Except_throw(eh, "Can't find a usable cjdns core executable, " "make sure it is in the same directory as cjdroute"); } if (!privateKey) { Except_throw(eh, "Need to specify privateKey."); } Log_info(logger, "Forking angel to background."); Process_spawn(corePath, args, eventBase, allocator); // --------------------- Get user for angel to setuid() ---------------------- // String* securityUser = NULL; List* securityConf = Dict_getList(&config, String_CONST("security")); for (int i = 0; securityConf && i < List_size(securityConf); i++) { securityUser = Dict_getString(List_getDict(securityConf, i), String_CONST("setuser")); if (securityUser) { int64_t* ea = Dict_getInt(List_getDict(securityConf, i), String_CONST("exemptAngel")); if (ea && *ea) { securityUser = NULL; } break; } } // --------------------- Pre-Configure Angel ------------------------- // Dict* preConf = Dict_new(allocator); Dict* adminPreConf = Dict_new(allocator); Dict_putDict(preConf, String_CONST("admin"), adminPreConf, allocator); Dict_putString(adminPreConf, String_CONST("core"), String_new(corePath, allocator), allocator); Dict_putString(preConf, String_CONST("privateKey"), privateKey, allocator); Dict_putString(adminPreConf, String_CONST("bind"), adminBind, allocator); Dict_putString(adminPreConf, String_CONST("pass"), adminPass, allocator); if (securityUser) { Dict_putString(adminPreConf, String_CONST("user"), securityUser, allocator); } Dict* logging = Dict_getDict(&config, String_CONST("logging")); if (logging) { Dict_putDict(preConf, String_CONST("logging"), logging, allocator); } struct Message* toAngelMsg = Message_new(0, 1024, allocator); BencMessageWriter_write(preConf, toAngelMsg, eh); Interface_sendMessage(&angelPipe->iface, toAngelMsg); Log_debug(logger, "Sent [%d] bytes to angel process", toAngelMsg->length); // --------------------- Get Response from Angel --------------------- // struct Message* fromAngelMsg = InterfaceWaiter_waitForData(&angelPipe->iface, eventBase, allocator, eh); Dict* responseFromAngel = BencMessageReader_read(fromAngelMsg, allocator, eh); // --------------------- Get Admin Addr/Port/Passwd --------------------- // Dict* responseFromAngelAdmin = Dict_getDict(responseFromAngel, String_CONST("admin")); adminBind = Dict_getString(responseFromAngelAdmin, String_CONST("bind")); if (!adminBind) { Except_throw(eh, "didn't get address and port back from angel"); } struct Sockaddr_storage adminAddr; if (Sockaddr_parse(adminBind->bytes, &adminAddr)) { Except_throw(eh, "Unable to parse [%s] as an ip address port, eg: 127.0.0.1:11234", adminBind->bytes); } // sanity check, Pipe_named() creates 2 events, see above. Assert_ifParanoid(EventBase_eventCount(eventBase) == 2); // --------------------- Configuration ------------------------- // Configurator_config(&config, &adminAddr.addr, adminPass, eventBase, logger, allocator); // --------------------- noBackground ------------------------ // int64_t* noBackground = Dict_getInt(&config, String_CONST("noBackground")); if (forceNoBackground || (noBackground && *noBackground)) { EventBase_beginLoop(eventBase); } //Allocator_free(allocator); return 0; }
static Iface_DEFUN incoming(struct Message* msg, struct Iface* interRouterIf) { struct MsgCore_pvt* mcp = Identity_containerOf(interRouterIf, struct MsgCore_pvt, pub.interRouterIf); struct Address addr = { .padding = 0 }; 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.path = Endian_bigEndianToHost64(hdr->sh.label_be); Dict* content = NULL; uint8_t* msgBytes = msg->bytes; int length = msg->length; //Log_debug(mcp->log, "Receive msg [%s] from [%s]", // Escape_getEscaped(msg->bytes, msg->length, msg->alloc), // Address_toString(&addr, msg->alloc)->bytes); // BencMessageReader_readNoExcept(msg, msg->alloc, &content); if (!content) { char* esc = Escape_getEscaped(msgBytes, length, msg->alloc); Log_debug(mcp->log, "DROP Malformed message [%s]", esc); return NULL; } int64_t* verP = Dict_getIntC(content, "p"); if (!verP) { Log_debug(mcp->log, "DROP Message without version"); return NULL; } addr.protocolVersion = *verP; String* q = Dict_getStringC(content, "q"); if (!Defined(SUBNODE)) { String* txid = Dict_getStringC(content, "txid"); Assert_true(txid); if (q) { if (txid->bytes[0] == '0') { Log_debug(mcp->log, "DROP query which begins with 0 and is for old pathfinder"); return NULL; } } else { if (txid->bytes[0] != '1') { Log_debug(mcp->log, "DROP reply which does not begin with 1"); return NULL; } String* newTxid = String_newBinary(NULL, txid->len - 1, msg->alloc); Bits_memcpy(newTxid->bytes, &txid->bytes[1], txid->len - 1); Dict_putStringC(content, "txid", newTxid, msg->alloc); txid = newTxid; } } if (q) { return queryMsg(mcp, content, &addr, msg); } else { return replyMsg(mcp, content, &addr, msg); } } struct MsgCore* MsgCore_new(struct EventBase* base, struct Random* rand, struct Allocator* allocator, struct Log* log, struct EncodingScheme* scheme) { struct Allocator* alloc = Allocator_child(allocator); struct MsgCore_pvt* mcp = Allocator_calloc(alloc, sizeof(struct MsgCore_pvt), 1); Identity_set(mcp); mcp->pub.interRouterIf.send = incoming; mcp->qh = ArrayList_OfQueryHandlers_new(alloc); mcp->pinger = Pinger_new(base, rand, log, alloc); mcp->log = log; mcp->scheme = scheme; mcp->schemeDefinition = EncodingScheme_serialize(scheme, alloc); return &mcp->pub; }
static void pingCycle(void* vsn) { struct SupernodeHunter_pvt* snp = Identity_check((struct SupernodeHunter_pvt*) vsn); if (snp->pub.snodeIsReachable) { return; } if (!snp->authorizedSnodes->length) { return; } if (!snp->peers->length) { return; } Log_debug(snp->log, "\n\nping cycle\n\n"); // We're not handling replies... struct MsgCore_Promise* qp = MsgCore_createQuery(snp->msgCore, 0, snp->alloc); struct Query* q = Allocator_calloc(qp->alloc, sizeof(struct Query), 1); Identity_set(q); q->snp = snp; q->sendTime = Time_currentTimeMilliseconds(snp->base); Dict* msg = qp->msg = Dict_new(qp->alloc); qp->cb = onReply; qp->userData = q; bool isGetPeers = snp->nodeListIndex & 1; int idx = snp->nodeListIndex++ >> 1; for (;;) { if (idx < snp->peers->length) { qp->target = AddrSet_get(snp->peers, idx); break; } idx -= snp->peers->length; if (idx < snp->nodes->length) { qp->target = AddrSet_get(snp->nodes, idx); break; } snp->snodeAddrIdx++; idx -= snp->nodes->length; } struct Address* snode = AddrSet_get(snp->authorizedSnodes, snp->snodeAddrIdx % snp->authorizedSnodes->length); if (Address_isSameIp(snode, qp->target)) { // Supernode is a peer... AddrSet_add(snp->snodeCandidates, qp->target); } if (snp->snodeCandidates->length) { qp->target = AddrSet_get(snp->snodeCandidates, snp->snodeCandidates->length - 1); Log_debug(snp->log, "Sending getRoute to snode %s", Address_toString(qp->target, qp->alloc)->bytes); Dict_putStringCC(msg, "sq", "gr", qp->alloc); Dict_putStringC(msg, "src", snp->selfAddrStr, qp->alloc); String* target = String_newBinary(qp->target->ip6.bytes, 16, qp->alloc); Dict_putStringC(msg, "tar", target, qp->alloc); q->isGetRoute = true; return; } if (isGetPeers) { Log_debug(snp->log, "Sending getPeers to %s", Address_toString(qp->target, qp->alloc)->bytes); Dict_putStringCC(msg, "q", "gp", qp->alloc); Dict_putStringC(msg, "tar", String_newBinary("\0\0\0\0\0\0\0\1", 8, qp->alloc), qp->alloc); } else { q->searchTar = Address_clone(snode, qp->alloc); Log_debug(snp->log, "Sending findNode to %s", Address_toString(qp->target, qp->alloc)->bytes); Dict_putStringCC(msg, "q", "fn", qp->alloc); Dict_putStringC(msg, "tar", String_newBinary(snode->ip6.bytes, 16, qp->alloc), qp->alloc); } }
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; }
static void getLink(Dict* args, void* vcontext, String* txid, struct Allocator* alloc) { struct Context* ctx = Identity_check((struct Context*) vcontext); Dict* ret = Dict_new(alloc); Dict* result = Dict_new(alloc); Dict_putDict(ret, String_new("result", alloc), result, alloc); Dict_putString(ret, String_new("error", alloc), String_new("none", alloc), alloc); struct Node_Link* link = NULL; struct Node_Two* node = NULL; String* ipStr = Dict_getString(args, String_new("parent", alloc)); int64_t* linkNum = Dict_getInt(args, String_new("linkNum", alloc)); if (ipStr && ipStr->len) { uint8_t ip[16]; if (AddrTools_parseIp(ip, ipStr->bytes)) { Dict_remove(ret, String_CONST("result")); Dict_putString(ret, String_new("error", alloc), String_new("parse_parent", alloc), alloc); Admin_sendMessage(ret, txid, ctx->admin); return; } else if (!(node = NodeStore_nodeForAddr(ctx->store, ip))) { Dict_putString(ret, String_new("error", alloc), String_new("not_found", alloc), alloc); Admin_sendMessage(ret, txid, ctx->admin); return; } else if (!(link = getLinkByNum(node, *linkNum))) { Dict_putString(ret, String_new("error", alloc), String_new("unknown", alloc), alloc); Admin_sendMessage(ret, txid, ctx->admin); return; } } else { for (int i = 0; i <= *linkNum; i++) { link = NodeStore_getNextLink(ctx->store, link); if (!link) { break; } } if (!link) { Dict_putString(ret, String_new("error", alloc), String_new("not_found", alloc), alloc); Admin_sendMessage(ret, txid, ctx->admin); return; } } Dict_putInt(result, String_new("inverseLinkEncodingFormNumber", alloc), link->inverseLinkEncodingFormNumber, alloc); Dict_putInt(result, String_new("linkCost", alloc), link->linkCost, alloc); Dict_putInt(result, String_new("isOneHop", alloc), Node_isOneHopLink(link), alloc); int bestParent = (Node_getBestParent(link->child) == link); Dict_putInt(result, String_new("bestParent", alloc), bestParent, alloc); String* cannonicalLabel = String_newBinary(NULL, 19, alloc); AddrTools_printPath(cannonicalLabel->bytes, link->cannonicalLabel); Dict_putString(result, String_new("cannonicalLabel", alloc), cannonicalLabel, alloc); String* parent = Address_toString(&link->parent->address, alloc); Dict_putString(result, String_new("parent", alloc), parent, alloc); String* child = Address_toString(&link->child->address, alloc); Dict_putString(result, String_new("child", alloc), child, alloc); Admin_sendMessage(ret, txid, ctx->admin); }
/** * 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; }
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; }
static void dumpTable_addEntries(struct Context* ctx, int i, int j, struct List_Item* last, String* txid) { uint8_t path[20]; uint8_t ip[40]; String* pathStr = &(String) { .len = 19, .bytes = (char*)path }; String* ipStr = &(String) { .len = 39, .bytes = (char*)ip }; Object* link = Int_OBJ(0xFFFFFFFF); Object* version = Int_OBJ(Version_DEFAULT_ASSUMPTION); Dict entry = Dict_CONST( String_CONST("ip"), String_OBJ(ipStr), Dict_CONST( String_CONST("link"), link, Dict_CONST( String_CONST("path"), String_OBJ(pathStr), Dict_CONST( String_CONST("version"), version, NULL )))); struct List_Item next = { .next = last, .elem = Dict_OBJ(&entry) }; if (i >= ctx->store->size || j >= ENTRIES_PER_PAGE) { if (i > j) { dumpTable_send(ctx, last, (j >= ENTRIES_PER_PAGE), txid); return; } Address_printIp(ip, ctx->store->selfAddress); strcpy((char*)path, "0000.0000.0000.0001"); version->as.number = Version_CURRENT_PROTOCOL; dumpTable_send(ctx, &next, (j >= ENTRIES_PER_PAGE), txid); return; } struct Node* n = NodeStore_dumpTable(ctx->store, i); link->as.number = n->reach; version->as.number = n->version; Address_printIp(ip, &n->address); AddrTools_printPath(path, n->address.path); dumpTable_addEntries(ctx, i + 1, j + 1, &next, txid); } static void dumpTable(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc) { struct Context* ctx = Identity_cast((struct Context*) vcontext); int64_t* page = Dict_getInt(args, String_CONST("page")); int i = (page) ? *page * ENTRIES_PER_PAGE : 0; dumpTable_addEntries(ctx, i, 0, NULL, txid); } static bool isOneHop(struct Node_Link* link) { struct EncodingScheme* ps = link->parent->encodingScheme; int num = EncodingScheme_getFormNum(ps, link->cannonicalLabel); Assert_always(num > -1 && num < ps->count); return EncodingScheme_formSize(&ps->forms[num]) == Bits_log2x64(link->cannonicalLabel); } static void getLink(Dict* args, void* vcontext, String* txid, struct Allocator* alloc) { struct Context* ctx = Identity_cast((struct Context*) vcontext); Dict* ret = Dict_new(alloc); Dict* result = Dict_new(alloc); Dict_putDict(ret, String_new("result", alloc), result, alloc); Dict_putString(ret, String_new("error", alloc), String_new("none", alloc), alloc); struct Node_Link* link; String* ipStr = Dict_getString(args, String_new("parent", alloc)); int64_t* linkNum = Dict_getInt(args, String_new("linkNum", alloc)); uint8_t ip[16]; if (ipStr->len != 39 || AddrTools_parseIp(ip, ipStr->bytes)) { Dict_remove(ret, String_CONST("result")); Dict_putString(ret, String_new("error", alloc), String_new("Could not parse ip", alloc), alloc); } else if ((link = NodeStore_getLink(ctx->store, ip, *linkNum))) { Dict_putInt(result, String_new("inverseLinkEncodingFormNumber", alloc), link->inverseLinkEncodingFormNumber, alloc); Dict_putInt(result, String_new("linkState", alloc), link->linkState, alloc); Dict_putInt(result, String_new("isOneHop", alloc), isOneHop(link), alloc); String* cannonicalLabel = String_newBinary(NULL, 19, alloc); AddrTools_printPath(cannonicalLabel->bytes, link->cannonicalLabel); Dict_putString(result, String_new("cannonicalLabel", alloc), cannonicalLabel, alloc); String* parent = String_newBinary(NULL, 39, alloc); AddrTools_printIp(parent->bytes, link->parent->address.ip6.bytes); Dict_putString(result, String_new("parent", alloc), parent, alloc); String* child = String_newBinary(NULL, 39, alloc); AddrTools_printIp(child->bytes, link->child->address.ip6.bytes); Dict_putString(result, String_new("child", alloc), child, alloc); } Admin_sendMessage(ret, txid, ctx->admin); } static void getNode(Dict* args, void* vcontext, String* txid, struct Allocator* alloc) { struct Context* ctx = Identity_cast((struct Context*) vcontext); Dict* ret = Dict_new(alloc); Dict* result = Dict_new(alloc); Dict_putDict(ret, String_new("result", alloc), result, alloc); Dict_putString(ret, String_new("error", alloc), String_new("none", alloc), alloc); // no ipStr specified --> return self-node struct Node_Two* node = ctx->store->selfNode; String* ipStr = Dict_getString(args, String_new("ip", alloc)); uint8_t ip[16]; while (ipStr) { if (ipStr->len != 39 || AddrTools_parseIp(ip, ipStr->bytes)) { Dict_remove(ret, String_CONST("result")); Dict_putString(ret, String_new("error", alloc), String_new("Could not parse ip", alloc), alloc); } else if (!(node = NodeStore_getNode2(ctx->store, ip))) { // not found } else { break; } Admin_sendMessage(ret, txid, ctx->admin); return; } Dict_putInt(result, String_new("protocolVersion", alloc), node->version, alloc); String* key = Key_stringify(node->address.key, alloc); Dict_putString(result, String_new("key", alloc), key, alloc); uint32_t linkCount = NodeStore_linkCount(node); Dict_putInt(result, String_new("linkCount", alloc), linkCount, alloc); List* encScheme = EncodingScheme_asList(node->encodingScheme, alloc); Dict_putList(result, String_new("encodingScheme", alloc), encScheme, alloc); Admin_sendMessage(ret, txid, ctx->admin); } static void getRouteLabel(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc) { struct Context* ctx = Identity_cast((struct Context*) vcontext); char* err = NULL; String* pathToParentS = Dict_getString(args, String_CONST("pathToParent")); uint64_t pathToParent; if (pathToParentS->len != 19) { err = "pathToParent incorrect length"; } else if (AddrTools_parsePath(&pathToParent, pathToParentS->bytes)) { err = "Failed to parse pathToParent"; } String* childAddressS = Dict_getString(args, String_CONST("childAddress")); uint8_t childAddress[16]; if (childAddressS->len != 39) { err = "childAddress of incorrect length, must be a 39 character full ipv6 address"; } else if (AddrTools_parseIp(childAddress, childAddressS->bytes)) { err = "Failed to parse childAddress"; } uint64_t label = UINT64_MAX; if (!err) { label = NodeStore_getRouteLabel(ctx->store, pathToParent, childAddress); err = NodeStore_getRouteLabel_strerror(label); } Dict* response = Dict_new(requestAlloc); if (!err) { String* printedPath = String_newBinary(NULL, 19, requestAlloc); AddrTools_printPath(printedPath->bytes, label); Dict_putString(response, String_new("result", requestAlloc), printedPath, requestAlloc); Dict_putString(response, String_new("error", requestAlloc), String_new("none", requestAlloc), requestAlloc); Admin_sendMessage(response, txid, ctx->admin); } else { Dict_putString(response, String_new("error", requestAlloc), String_new(err, requestAlloc), requestAlloc); Admin_sendMessage(response, txid, ctx->admin); } } void NodeStore_admin_register(struct NodeStore* nodeStore, struct Admin* admin, struct Allocator* alloc) { struct Context* ctx = Allocator_clone(alloc, (&(struct Context) { .admin = admin, .alloc = alloc, .store = nodeStore })); Identity_set(ctx); Admin_registerFunction("NodeStore_dumpTable", dumpTable, ctx, false, ((struct Admin_FunctionArg[]) { { .name = "page", .required = 1, .type = "Int" }, }), admin); Admin_registerFunction("NodeStore_getLink", getLink, ctx, true, ((struct Admin_FunctionArg[]) { { .name = "parent", .required = 1, .type = "String" }, { .name = "linkNum", .required = 1, .type = "Int" }, }), admin);
static void nodeForAddr(Dict* args, void* vcontext, String* txid, struct Allocator* alloc) { struct Context* ctx = Identity_check((struct Context*) vcontext); Dict* ret = Dict_new(alloc); Dict* result = Dict_new(alloc); Dict_putDict(ret, String_new("result", alloc), result, alloc); Dict_putString(ret, String_new("error", alloc), String_new("none", alloc), alloc); // no ipStr specified --> return self-node struct Node_Two* node = ctx->store->selfNode; String* ipStr = Dict_getString(args, String_new("ip", alloc)); uint8_t ip[16]; while (ipStr) { if (AddrTools_parseIp(ip, ipStr->bytes)) { Dict_remove(ret, String_CONST("result")); Dict_putString(ret, String_new("error", alloc), String_new("parse_ip", alloc), alloc); } else if (!(node = NodeStore_nodeForAddr(ctx->store, ip))) { // not found } else { break; } Admin_sendMessage(ret, txid, ctx->admin); return; } Dict_putInt(result, String_new("protocolVersion", alloc), node->address.protocolVersion, alloc); String* key = Key_stringify(node->address.key, alloc); Dict_putString(result, String_new("key", alloc), key, alloc); uint32_t count = linkCount(node); Dict_putInt(result, String_new("linkCount", alloc), count, alloc); Dict_putInt(result, String_new("cost", alloc), Node_getCost(node), alloc); List* encScheme = EncodingScheme_asList(node->encodingScheme, alloc); Dict_putList(result, String_new("encodingScheme", alloc), encScheme, alloc); Dict* bestParent = Dict_new(alloc); String* parentIp = String_newBinary(NULL, 39, alloc); AddrTools_printIp(parentIp->bytes, Node_getBestParent(node)->parent->address.ip6.bytes); Dict_putString(bestParent, String_CONST("ip"), parentIp, alloc); String* parentChildLabel = String_newBinary(NULL, 19, alloc); AddrTools_printPath(parentChildLabel->bytes, Node_getBestParent(node)->cannonicalLabel); Dict_putString(bestParent, String_CONST("parentChildLabel"), parentChildLabel, alloc); int isOneHop = Node_isOneHopLink(Node_getBestParent(node)); Dict_putInt(bestParent, String_CONST("isOneHop"), isOneHop, alloc); Dict_putDict(result, String_CONST("bestParent"), bestParent, alloc); String* bestLabel = String_newBinary(NULL, 19, alloc); AddrTools_printPath(bestLabel->bytes, node->address.path); Dict_putString(result, String_CONST("routeLabel"), bestLabel, alloc); Admin_sendMessage(ret, txid, ctx->admin); }