static void tunInterface(Dict* ifaceConf, struct Allocator* tempAlloc, struct Context* ctx) { String* ifaceType = Dict_getString(ifaceConf, String_CONST("type")); if (!String_equals(ifaceType, String_CONST("TUNInterface"))) { return; } // Setup the interface. String* tunfd = Dict_getString(ifaceConf, String_CONST("tunfd")); String* device = Dict_getString(ifaceConf, String_CONST("tunDevice")); Dict* args = Dict_new(tempAlloc); if (tunfd && device) { Dict_putString(args, String_CONST("path"), device, tempAlloc); Dict_putString(args, String_CONST("type"), String_new(tunfd->bytes, tempAlloc), tempAlloc); Dict* res = NULL; rpcCall0(String_CONST("FileNo_import"), args, ctx, tempAlloc, &res, false); if (res) { Dict* args = Dict_new(tempAlloc); int64_t* tunfd = Dict_getInt(res, String_CONST("tunfd")); int64_t* type = Dict_getInt(res, String_CONST("type")); Dict_putInt(args, String_CONST("tunfd"), *tunfd, tempAlloc); Dict_putInt(args, String_CONST("type"), *type, tempAlloc); rpcCall0(String_CONST("Core_initTunfd"), args, ctx, tempAlloc, NULL, false); } } else { if (device) { Dict_putString(args, String_CONST("desiredTunName"), device, tempAlloc); } rpcCall0(String_CONST("Core_initTunnel"), args, ctx, tempAlloc, NULL, false); } }
static void initTunfd(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc) { struct Context* ctx = Identity_check((struct Context*) vcontext); struct Jmp jmp; Jmp_try(jmp) { int64_t* tunfd = Dict_getInt(args, String_CONST("tunfd")); int64_t* tuntype = Dict_getInt(args, String_CONST("type")); if (!tunfd || *tunfd < 0) { String* error = String_printf(requestAlloc, "Invalid tunfd"); sendResponse(error, ctx->admin, txid, requestAlloc); return; } int fileno = *tunfd; int type = (*tuntype) ? *tuntype : FileNo_Type_NORMAL; struct Pipe* p = Pipe_forFiles(fileno, fileno, ctx->base, &jmp.handler, ctx->alloc); p->logger = ctx->logger; if (type == FileNo_Type_ANDROID) { struct AndroidWrapper* aw = AndroidWrapper_new(ctx->alloc, ctx->logger); Iface_plumb(&aw->externalIf, &p->iface); Iface_plumb(&aw->internalIf, &ctx->nc->tunAdapt->tunIf); } else { Iface_plumb(&p->iface, &ctx->nc->tunAdapt->tunIf); } sendResponse(String_CONST("none"), ctx->admin, txid, requestAlloc); } Jmp_catch { String* error = String_printf(requestAlloc, "Failed to configure tunnel [%s]", jmp.message); sendResponse(error, ctx->admin, txid, requestAlloc); return; } }
static void adminPing(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc) { struct Context* context = vcontext; String* pathStr = Dict_getString(args, String_CONST("path")); int64_t* timeoutPtr = Dict_getInt(args, String_CONST("timeout")); String* data = Dict_getString(args, String_CONST("data")); int64_t* keyPing = Dict_getInt(args, String_CONST("keyPing")); uint32_t timeout = (timeoutPtr) ? *timeoutPtr : DEFAULT_TIMEOUT; uint64_t path; String* err = NULL; if (pathStr->len != 19 || AddrTools_parsePath(&path, (uint8_t*) pathStr->bytes)) { err = String_CONST("path was not parsable."); } else { struct SwitchPinger_Ping* ping = SwitchPinger_newPing(path, data, timeout, adminPingOnResponse, context->alloc, context->switchPinger); if (keyPing && *keyPing) { ping->keyPing = true; } if (!ping) { err = String_CONST("no open slots to store ping, try later."); } else { ping->onResponseContext = Allocator_clone(ping->pingAlloc, (&(struct Ping) { .context = context, .txid = String_clone(txid, ping->pingAlloc), .path = String_clone(pathStr, ping->pingAlloc) })); } }
struct EncodingScheme* EncodingScheme_fromList(List* scheme, struct Allocator* alloc) { struct EncodingScheme* list = Allocator_malloc(alloc, sizeof(struct EncodingScheme)); list->count = List_size(scheme); list->forms = Allocator_malloc(alloc, sizeof(struct EncodingScheme_Form) * list->count); for (int i = 0; i < (int)list->count; i++) { Dict* form = List_getDict(scheme, i); uint64_t* prefixLen = Dict_getInt(form, String_CONST("prefixLen")); uint64_t* bitCount = Dict_getInt(form, String_CONST("bitCount")); String* prefixStr = Dict_getString(form, String_CONST("prefix")); if (!prefixLen || !bitCount || !prefixStr || prefixStr->len != 8) { return NULL; } uint32_t prefix_be; if (Hex_decode((uint8_t*)&prefix_be, 4, prefixStr->bytes, 8) != 4) { return NULL; } list->forms[i].prefixLen = *prefixLen; list->forms[i].bitCount = *bitCount; list->forms[i].prefix = Endian_bigEndianToHost32(prefix_be); } if (!EncodingScheme_isSane(list)) { return NULL; } return list; }
static bool checkArgs(Dict* args, struct Function* func, String* txid, struct Admin* admin) { struct Dict_Entry* entry = *func->args; String* error = NULL; uint8_t buffer[1024]; struct Allocator* alloc = BufferAllocator_new(buffer, 1024); while (entry != NULL) { String* key = (String*) entry->key; Assert_true(entry->val->type == Object_DICT); Dict* value = entry->val->as.dictionary; entry = entry->next; if (*Dict_getInt(value, String_CONST("required")) == 0) { continue; } String* type = Dict_getString(value, String_CONST("type")); if ((type == STRING && !Dict_getString(args, key)) || (type == DICT && !Dict_getDict(args, key)) || (type == INTEGER && !Dict_getInt(args, key)) || (type == LIST && !Dict_getList(args, key))) { error = String_printf(alloc, "Entry [%s] is required and must be of type [%s]", key->bytes, type->bytes); break; } } if (error) { Dict d = Dict_CONST(String_CONST("error"), String_OBJ(error), NULL); Admin_sendMessage(&d, txid, admin); } return !error; }
static void allowConnection(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc) { struct Context* context = (struct Context*) vcontext; String* publicKeyOfAuthorizedNode = Dict_getString(args, String_CONST("publicKeyOfAuthorizedNode")); String* ip6Address = Dict_getString(args, String_CONST("ip6Address")); int64_t* ip6Prefix = Dict_getInt(args, String_CONST("ip6Prefix")); String* ip4Address = Dict_getString(args, String_CONST("ip4Address")); int64_t* ip4Prefix = Dict_getInt(args, String_CONST("ip4Prefix")); uint8_t pubKey[32]; uint8_t ip6Addr[16]; struct Sockaddr_storage ip6ToGive; struct Sockaddr_storage ip4ToGive; char* error; int ret; if (!ip6Address && !ip4Address) { error = "Must specify ip6Address or ip4Address"; } else if ((ret = Key_parse(publicKeyOfAuthorizedNode, pubKey, ip6Addr)) != 0) { error = Key_parse_strerror(ret); } else if (ip6Prefix && !ip6Address) { error = "Must specify ip6Address with ip6Prefix"; } else if (ip6Prefix && (*ip6Prefix > 128 || *ip6Prefix < 0)) { error = "ip6Prefix out of range: must be 0 to 128"; } else if (ip4Prefix && (*ip4Prefix > 32 || *ip4Prefix < 0)) { error = "ip4Prefix out of range: must be 0 to 32"; } else if (ip4Prefix && !ip4Address) { error = "Must specify ip4Address with ip4Prefix"; } else if (ip6Address && (Sockaddr_parse(ip6Address->bytes, &ip6ToGive) || Sockaddr_getFamily(&ip6ToGive.addr) != Sockaddr_AF_INET6)) { error = "malformed ip6Address"; } else if (ip4Address && (Sockaddr_parse(ip4Address->bytes, &ip4ToGive) || Sockaddr_getFamily(&ip4ToGive.addr) != Sockaddr_AF_INET)) { error = "malformed ip4Address"; } else { int conn = IpTunnel_allowConnection(pubKey, (ip6Address) ? &ip6ToGive.addr : NULL, (ip6Prefix) ? (uint8_t) (*ip6Prefix) : 0, (ip4Address) ? &ip4ToGive.addr : NULL, (ip4Prefix) ? (uint8_t) (*ip4Prefix) : 0, context->ipTun); sendResponse(conn, txid, context->admin); return; } sendError(error, txid, context->admin); }
static void authorizedPasswords(List* list, struct Context* ctx) { uint32_t count = List_size(list); for (uint32_t i = 0; i < count; i++) { Dict* d = List_getDict(list, i); if (!d) { fprintf(stderr, "authorizedPasswords[%u] is not a dictionary type.\n", i); exit(-1); } String* passwd = Dict_getString(d, BSTR("password")); int64_t* authType = Dict_getInt(d, BSTR("authType")); int64_t* trust = Dict_getInt(d, BSTR("trust")); authorizedPassword(passwd, authType, trust, i, ctx); } }
static void dns(Dict* dns, struct Context* ctx, struct Except* eh) { List* servers = Dict_getList(dns, String_CONST("servers")); int count = List_size(servers); for (int i = 0; i < count; i++) { String* server = List_getString(servers, i); if (!server) { Except_throw(eh, "dns.servers[%d] is not a string", i); } Dict* d = Dict_new(ctx->alloc); Dict_putString(d, String_CONST("addr"), server, ctx->alloc); rpcCall(String_CONST("RainflyClient_addServer"), d, ctx, ctx->alloc); } List* keys = Dict_getList(dns, String_CONST("keys")); count = List_size(keys); for (int i = 0; i < count; i++) { String* key = List_getString(keys, i); if (!key) { Except_throw(eh, "dns.keys[%d] is not a string", i); } Dict* d = Dict_new(ctx->alloc); Dict_putString(d, String_CONST("ident"), key, ctx->alloc); rpcCall(String_CONST("RainflyClient_addKey"), d, ctx, ctx->alloc); } int64_t* minSigs = Dict_getInt(dns, String_CONST("minSignatures")); if (minSigs) { Dict* d = Dict_new(ctx->alloc); Dict_putInt(d, String_CONST("count"), *minSigs, ctx->alloc); rpcCall(String_CONST("RainflyClient_minSignatures"), d, ctx, ctx->alloc); } }
static void add(Dict* args, void* vcontext, String* txid) { struct Context* context = (struct Context*) vcontext; String* passwd = Dict_getString(args, String_CONST("password")); int64_t* authType = Dict_getInt(args, String_CONST("authType")); int64_t one = 1; if (!authType) { authType = &one; } else if (*authType < 1 || *authType > 255) { sendResponse(String_CONST("Specified auth type is not supported."), context->admin, txid); return; } int32_t ret = CryptoAuth_addUser(passwd, *authType, context, context->ca); switch (ret) { case 0: sendResponse(String_CONST("none"), context->admin, txid); break; case CryptoAuth_addUser_INVALID_AUTHTYPE: sendResponse(String_CONST("Specified auth type is not supported."), context->admin, txid); break; case CryptoAuth_addUser_OUT_OF_SPACE: sendResponse(String_CONST("Out of memory to store password."), context->admin, txid); break; case CryptoAuth_addUser_DUPLICATE: sendResponse(String_CONST("Password already added."), context->admin, txid); break; default: sendResponse(String_CONST("Unknown error."), context->admin, txid); } }
static void dumpRumorMill(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc) { struct Context* ctx = Identity_check((struct Context*) vcontext); Dict* out = Dict_new(requestAlloc); struct RumorMill* rm = getRumorMill(ctx, Dict_getString(args, String_CONST("mill"))); if (!rm) { Dict_putString(out, String_CONST("error"), String_CONST("mill must be one of " "[externalMill,linkMill,nodeMill,dhtMill,splitMill]"), requestAlloc); Admin_sendMessage(out, txid, ctx->admin); return; } int64_t* page = Dict_getInt(args, String_CONST("page")); int ctr = (page) ? *page * ENTRIES_PER_PAGE : 0; List* table = List_new(requestAlloc); for (int i = 0; i < ENTRIES_PER_PAGE && ctr < rm->count; i++) { String* addr = Address_toString(&rm->addresses[ctr++], requestAlloc); List_addString(table, addr, requestAlloc); } Dict_putList(out, String_CONST("addresses"), table, requestAlloc); Dict_putInt(out, String_CONST("total"), rm->count, requestAlloc); Admin_sendMessage(out, txid, ctx->admin); }
static void getHandles(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc) { struct Context* context = Identity_check((struct Context*) vcontext); struct Allocator* alloc = Allocator_child(context->alloc); int64_t* page = Dict_getInt(args, String_CONST("page")); int i = (page) ? *page * ENTRIES_PER_PAGE : 0; struct SessionManager_HandleList* hList = SessionManager_getHandleList(context->sm, alloc); List* list = List_new(alloc); for (int counter = 0; i < hList->length && counter++ < ENTRIES_PER_PAGE; i++) { List_addInt(list, hList->handles[i], alloc); } Dict* r = Dict_new(alloc); Dict_putList(r, String_CONST("handles"), list, alloc); Dict_putInt(r, String_CONST("total"), hList->length, alloc); String* more = String_CONST("more"); if (i < hList->length) { Dict_putInt(r, more, 1, alloc); } Admin_sendMessage(r, txid, context->admin); Allocator_free(alloc); }
static void setUser(Dict* args, void* vctx, String* txid, struct Allocator* requestAlloc) { struct Context* const ctx = Identity_check((struct Context*) vctx); struct Jmp jmp; Jmp_try(jmp) { int64_t* user = Dict_getInt(args, String_CONST("uid")); int64_t* group = Dict_getInt(args, String_CONST("gid")); int gid = group ? (int)*group : 0; int64_t* keepNetAdmin = Dict_getInt(args, String_CONST("keepNetAdmin")); Security_setUser(*user, gid, *keepNetAdmin, ctx->logger, &jmp.handler, requestAlloc); } Jmp_catch { sendError(jmp.message, txid, ctx->admin); return; } sendError("none", txid, ctx->admin); }
static inline bool authValid(Dict* message, uint8_t* buffer, uint32_t length, struct Admin* admin) { String* cookieStr = Dict_getString(message, String_CONST("cookie")); uint32_t cookie = (cookieStr != NULL) ? strtoll(cookieStr->bytes, NULL, 10) : 0; if (!cookie) { int64_t* cookieInt = Dict_getInt(message, String_CONST("cookie")); cookie = (cookieInt) ? *cookieInt : 0; } uint64_t nowSecs = Time_currentTimeSeconds(admin->eventBase); String* submittedHash = Dict_getString(message, String_CONST("hash")); if (cookie > nowSecs || cookie < nowSecs - 20 || !submittedHash || submittedHash->len != 64) { return false; } uint8_t* hashPtr = (uint8_t*) strstr((char*) buffer, submittedHash->bytes); if (!hashPtr || !admin->password) { return false; } uint8_t passAndCookie[64]; snprintf((char*) passAndCookie, 64, "%s%u", admin->password->bytes, cookie); uint8_t hash[32]; crypto_hash_sha256(hash, passAndCookie, strlen((char*) passAndCookie)); Hex_encode(hashPtr, 64, hash, 32); crypto_hash_sha256(hash, buffer, length); Hex_encode(hashPtr, 64, hash, 32); return memcmp(hashPtr, submittedHash->bytes, 64) == 0; }
static void standardClientCallback(struct AdminClient_Promise* p, struct AdminClient_Result* res) { struct Context* ctx = p->userData; //printf("%d\n", res->err); Assert_always(!res->err); Assert_always(Dict_getInt(res->responseDict, String_CONST("called!"))); Assert_always(ctx->called); EventBase_endLoop(ctx->framework->eventBase); }
static void adminPeerStats(Dict* args, void* vcontext, String* txid) { struct Context* context = vcontext; struct Allocator* alloc = Allocator_child(context->alloc); struct InterfaceController_peerStats* stats = NULL; int64_t* page = Dict_getInt(args, String_CONST("page")); int i = (page) ? *page * ENTRIES_PER_PAGE : 0; int count = context->ic->getPeerStats(context->ic, alloc, &stats); String* bytesIn = String_CONST("bytesIn"); String* bytesOut = String_CONST("bytesOut"); String* pubKey = String_CONST("publicKey"); String* state = String_CONST("state"); String* last = String_CONST("last"); String* switchLabel = String_CONST("switchLabel"); String* isIncoming = String_CONST("isIncoming"); List* list = NULL; for (int counter=0; i < count && counter++ < ENTRIES_PER_PAGE; i++) { Dict* d = Dict_new(alloc); Dict_putInt(d, bytesIn, stats[i].bytesIn, alloc); Dict_putInt(d, bytesOut, stats[i].bytesOut, alloc); Dict_putString(d, pubKey, Key_stringify(stats[i].pubKey, alloc), alloc); String* stateString = String_new(InterfaceController_stateString(stats[i].state), alloc); Dict_putString(d, state, stateString, alloc); Dict_putInt(d, last, stats[i].timeOfLastMessage, alloc); uint8_t labelStack[20]; AddrTools_printPath(labelStack, stats[i].switchLabel); Dict_putString(d, switchLabel, String_new((char*)labelStack, alloc), alloc); Dict_putInt(d, isIncoming, stats[i].isIncomingConnection, alloc); list = List_addDict(list, d, alloc); } Dict response = Dict_CONST( String_CONST("peers"), List_OBJ(list), Dict_CONST( String_CONST("total"), Int_OBJ(count), NULL )); if (i < count) { response = Dict_CONST( String_CONST("more"), Int_OBJ(1), response ); } Admin_sendMessage(&response, txid, context->admin); Allocator_free(alloc); }
static void removeConnection(Dict* args, void* vcontext, String* txid) { struct Context* context = vcontext; int conn = (int) *(Dict_getInt(args, String_CONST("connection"))); char* error = "none"; if (IpTunnel_removeConnection_NOT_FOUND == IpTunnel_removeConnection(conn, context->ipTun)) { error = "not found"; } sendError(error, txid, context->admin); }
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 beginConnection(Dict* args, void* vcontext, String* txid) { struct Context* ctx = vcontext; String* password = Dict_getString(args, String_CONST("password")); String* publicKey = Dict_getString(args, String_CONST("publicKey")); String* address = Dict_getString(args, String_CONST("address")); int64_t* interfaceNumber = Dict_getInt(args, String_CONST("interfaceNumber")); uint32_t ifNum = (interfaceNumber) ? ((uint32_t) *interfaceNumber) : 0; String* error = NULL; uint8_t pkBytes[32]; if (ctx->ifCount == 0) { error = String_CONST("no interfaces are setup, call UDPInterface_new() first"); } else if (interfaceNumber && (*interfaceNumber >= ctx->ifCount || *interfaceNumber < 0)) { error = String_CONST("invalid interfaceNumber"); } else if (!publicKey || publicKey->len < 52 || (publicKey->len > 52 && publicKey->bytes[52] != '.')) { error = String_CONST("publicKey must be 52 characters long."); } else if (Base32_decode(pkBytes, 32, (uint8_t*)publicKey->bytes, 52) != 32) { error = String_CONST("failed to parse publicKey."); } else { struct UDPInterface* udpif = ctx->ifaces[ifNum]; switch (UDPInterface_beginConnection(address->bytes, pkBytes, password, udpif)) { case UDPInterface_beginConnection_OUT_OF_SPACE: error = String_CONST("no more space to register with the switch."); break; case UDPInterface_beginConnection_BAD_KEY: error = String_CONST("invalid cjdns public key."); break; case UDPInterface_beginConnection_BAD_ADDRESS: error = String_CONST("unable to parse ip address and port."); break; case UDPInterface_beginConnection_ADDRESS_MISMATCH: error = String_CONST("different address type than this socket is bound to."); break; case 0: error = String_CONST("none"); break; default: error = String_CONST("unknown error"); } } Dict out = Dict_CONST(String_CONST("error"), String_OBJ(error), NULL); Admin_sendMessage(&out, txid, ctx->admin); }
static void subscribe(Dict* args, void* vcontext, String* txid) { struct AdminLog* log = (struct AdminLog*) vcontext; String* levelName = Dict_getString(args, String_CONST("level")); enum Log_Level level = (levelName) ? Log_levelForName(levelName->bytes) : Log_Level_DEBUG; int64_t* lineNumPtr = Dict_getInt(args, String_CONST("line")); String* fileStr = Dict_getString(args, String_CONST("file")); const char* file = (fileStr && fileStr->len > 0) ? fileStr->bytes : NULL; char* error = "2+2=5"; if (level == Log_Level_INVALID) { level = Log_Level_KEYS; } if (lineNumPtr && *lineNumPtr < 0) { error = "Invalid line number, must be positive or 0 to signify any line is acceptable."; } else if (log->subscriptionCount >= MAX_SUBSCRIPTIONS) { error = "Max subscription count reached."; } else { struct Subscription* sub = &log->subscriptions[log->subscriptionCount]; sub->level = level; sub->alloc = Allocator_child(log->alloc); if (file) { int i; for (i = 0; i < FILE_NAME_COUNT; i++) { if (log->fileNames[i] && !strcmp(log->fileNames[i], file)) { file = log->fileNames[i]; sub->internalName = true; break; } } if (i == FILE_NAME_COUNT) { file = String_new(file, sub->alloc)->bytes; sub->internalName = false; } } sub->file = file; sub->lineNum = (lineNumPtr) ? *lineNumPtr : 0; sub->txid = String_clone(txid, sub->alloc); Random_bytes(log->rand, (uint8_t*) sub->streamId, 8); uint8_t streamIdHex[20]; Hex_encode(streamIdHex, 20, sub->streamId, 8); Dict response = Dict_CONST( String_CONST("error"), String_OBJ(String_CONST("none")), Dict_CONST( String_CONST("streamId"), String_OBJ(String_CONST((char*)streamIdHex)), NULL )); Admin_sendMessage(&response, txid, log->admin); log->subscriptionCount++; return; } Dict response = Dict_CONST( String_CONST("error"), String_OBJ(String_CONST(error)), NULL ); Admin_sendMessage(&response, txid, log->admin); }
static void sessionStats(Dict* args, void* vcontext, String* txid, struct Allocator* alloc) { struct Context* context = Identity_check((struct Context*) vcontext); int64_t* handleP = Dict_getInt(args, String_CONST("handle")); uint32_t handle = *handleP; struct SessionManager_Session* session = SessionManager_sessionForHandle(handle, context->sm); Dict* r = Dict_new(alloc); if (!session) { Dict_putString(r, String_CONST("error"), String_CONST("no such session"), alloc); Admin_sendMessage(r, txid, context->admin); return; } uint8_t printedAddr[40]; AddrTools_printIp(printedAddr, session->caSession->herIp6); Dict_putString(r, String_CONST("ip6"), String_new(printedAddr, alloc), alloc); String* state = String_new(CryptoAuth_stateString(CryptoAuth_getState(session->caSession)), alloc); Dict_putString(r, String_CONST("state"), state, alloc); struct ReplayProtector* rp = &session->caSession->replayProtector; Dict_putInt(r, String_CONST("duplicates"), rp->duplicates, alloc); Dict_putInt(r, String_CONST("lostPackets"), rp->lostPackets, alloc); Dict_putInt(r, String_CONST("receivedOutOfRange"), rp->receivedOutOfRange, alloc); struct Address addr; Bits_memcpyConst(addr.key, session->caSession->herPublicKey, 32); addr.path = session->sendSwitchLabel; addr.protocolVersion = session->version; Dict_putString(r, String_CONST("addr"), Address_toString(&addr, alloc), alloc); Dict_putString(r, String_CONST("publicKey"), Key_stringify(session->caSession->herPublicKey, alloc), alloc); Dict_putInt(r, String_CONST("version"), session->version, alloc); Dict_putInt(r, String_CONST("handle"), session->receiveHandle, alloc); Dict_putInt(r, String_CONST("sendHandle"), session->sendHandle, alloc); Dict_putInt(r, String_CONST("timeOfLastIn"), session->timeOfLastIn, alloc); Dict_putInt(r, String_CONST("timeOfLastOut"), session->timeOfLastOut, alloc); Dict_putString(r, String_CONST("deprecation"), String_CONST("publicKey,version will soon be removed"), alloc); Admin_sendMessage(r, txid, context->admin); return; }
static void showConnection(Dict* args, void* vcontext, String* txid) { struct Context* context = vcontext; int connNum = (int) *(Dict_getInt(args, String_CONST("connection"))); for (int i = 0; i < (int)context->ipTun->connectionList.count; i++) { if (connNum == context->ipTun->connectionList.connections[i].number) { showConn(&context->ipTun->connectionList.connections[i], txid, context->admin); return; } } sendError("connection not found", txid, context->admin); }
static void sessionStats(Dict* args, void* vcontext, String* txid, struct Allocator* alloc) { struct Context* context = vcontext; int64_t* handleP = Dict_getInt(args, String_CONST("handle")); uint32_t handle = *handleP; struct SessionManager_Session* session = SessionManager_sessionForHandle(handle, context->sm); uint8_t* ip6 = SessionManager_getIp6(handle, context->sm); Dict* r = Dict_new(alloc); if (!session) { Dict_putString(r, String_CONST("error"), String_CONST("no such session"), alloc); Admin_sendMessage(r, txid, context->admin); return; } // both or neither Assert_true(ip6); uint8_t printedAddr[40]; AddrTools_printIp(printedAddr, ip6); Dict_putString(r, String_CONST("ip6"), String_new(printedAddr, alloc), alloc); Dict_putString(r, String_CONST("state"), String_new(CryptoAuth_stateString(session->cryptoAuthState), alloc), alloc); struct ReplayProtector* rp = CryptoAuth_getReplayProtector(session->internal); Dict_putInt(r, String_CONST("duplicates"), rp->duplicates, alloc); Dict_putInt(r, String_CONST("lostPackets"), rp->lostPackets, alloc); Dict_putInt(r, String_CONST("receivedOutOfRange"), rp->receivedOutOfRange, alloc); uint8_t* key = CryptoAuth_getHerPublicKey(session->internal); Dict_putString(r, String_CONST("publicKey"), Key_stringify(key, alloc), alloc); Dict_putInt(r, String_CONST("version"), session->version, alloc); Dict_putInt(r, String_CONST("handle"), Endian_bigEndianToHost32(session->receiveHandle_be), alloc); Dict_putInt(r, String_CONST("sendHandle"), Endian_bigEndianToHost32(session->sendHandle_be), alloc); Dict_putInt(r, String_CONST("timeOfLastIn"), session->timeOfLastIn, alloc); Dict_putInt(r, String_CONST("timeOfLastOut"), session->timeOfLastOut, alloc); Admin_sendMessage(r, txid, context->admin); return; }
static void ethInterfaceSetBeacon(int ifNum, Dict* eth, struct Context* ctx) { int64_t* beaconP = Dict_getInt(eth, String_CONST("beacon")); if (beaconP) { int64_t beacon = *beaconP; if (beacon > 3 || beacon < 0) { Log_error(ctx->logger, "interfaces.ETHInterface.beacon may only be 0, 1,or 2"); } else { // We can cast beacon to an int here because we know it's small enough Log_info(ctx->logger, "Setting beacon mode on ETHInterface to [%d].", (int) beacon); Dict d = Dict_CONST(String_CONST("interfaceNumber"), Int_OBJ(ifNum), Dict_CONST(String_CONST("state"), Int_OBJ(beacon), NULL)); rpcCall(String_CONST("ETHInterface_beacon"), &d, ctx, ctx->alloc); } } }
static void pingResponse(struct RouterModule_Promise* promise, uint32_t lag, struct Node* node, Dict* responseDict) { struct Ping* ping = Identity_cast((struct Ping*)promise->userData); uint8_t versionStr[40] = "old"; String* version = String_CONST((char*)versionStr); String* versionBin = Dict_getString(responseDict, CJDHTConstants_VERSION); if (versionBin && versionBin->len == 20) { Hex_encode(versionStr, 40, (uint8_t*) versionBin->bytes, 20); version->len = 40; } int64_t* protocolVersion = Dict_getInt(responseDict, CJDHTConstants_PROTOCOL); int64_t pv = (protocolVersion) ? *protocolVersion : -1; Dict response = NULL; Dict verResponse = Dict_CONST(String_CONST("version"), String_OBJ(version), response); if (versionBin) { response = verResponse; } String* result = (responseDict) ? String_CONST("pong") : String_CONST("timeout"); response = Dict_CONST(String_CONST("result"), String_OBJ(result), response); Dict protoResponse = Dict_CONST(String_CONST("protocol"), Int_OBJ(pv), response); if (protocolVersion) { response = protoResponse; } response = Dict_CONST(String_CONST("ms"), Int_OBJ(lag), response); char from[60] = ""; if (node) { Address_print((uint8_t*)from, &node->address); } Dict fromResponse = Dict_CONST(String_CONST("from"), String_OBJ(String_CONST(from)), response); if (node) { response = fromResponse; } Admin_sendMessage(&response, ping->txid, ping->ctx->admin); }
static void minSinatures(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc) { struct Context* context = vcontext; struct Allocator* alloc = Allocator_child(context->alloc); int64_t* count = Dict_getInt(args, String_CONST("count")); char* err = "none"; if (*count < 0 || *count > INT32_MAX) { err = "count cannot be less than zero or more than INT32_MAX"; } else { context->rainfly->minSignatures = *count; } Dict* response = Dict_new(alloc); Dict_putString(response, String_CONST("error"), String_CONST(err), alloc); Admin_sendMessage(response, txid, context->admin); Allocator_free(alloc); }
static void add(Dict* args, void* vcontext, String* txid) { struct Context* context = (struct Context*) vcontext; String* passwd = Dict_getString(args, String_CONST("password")); int64_t* authType = Dict_getInt(args, String_CONST("authType")); if (!(passwd && authType)) { sendResponse(String_CONST("Must specify authType, and password."), context->admin, txid); } else if (*authType < 1 || *authType > 255) { sendResponse(String_CONST("Auth must be between 1 and 255 inclusive."), context->admin, txid); } else { struct User* u = context->allocator->malloc(sizeof(struct User), context->allocator); // At some point this will be implemented... u->trust = 0; int32_t ret = CryptoAuth_addUser(passwd, *authType, u, context->ca); switch (ret) { case 0: sendResponse(String_CONST("none"), context->admin, txid); break; case CryptoAuth_addUser_INVALID_AUTHTYPE: sendResponse(String_CONST("Specified auth type is not supported."), context->admin, txid); break; case CryptoAuth_addUser_OUT_OF_SPACE: sendResponse(String_CONST("Out of memory to store password."), context->admin, txid); break; case CryptoAuth_addUser_DUPLICATE: sendResponse(String_CONST("Password already added."), context->admin, txid); break; default: sendResponse(String_CONST("Unknown error."), context->admin, txid); }; } }
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); }
static void udpConnectTo(String* connectToAddress, Dict* config, struct UDPInterface* udpContext, struct Context* ctx) { String* password = Dict_getString(config, BSTR("password")); int64_t* authType = Dict_getInt(config, BSTR("authType")); String* publicKey = Dict_getString(config, BSTR("publicKey")); int64_t* trust = Dict_getInt(config, BSTR("trust")); #define FAIL_IF_NULL(cannotBeNull, fieldName) \ if (!cannotBeNull) { \ fprintf(stderr, \ "interfaces.UDPInterface['%s']." fieldName " is not set, " \ "this field is mandatory.\n", \ connectToAddress->bytes); \ exit(-1); \ } FAIL_IF_NULL(password, "password") FAIL_IF_NULL(authType, "authType") FAIL_IF_NULL(publicKey, "publicKey") FAIL_IF_NULL(trust, "trust") #undef FAIL_IF_NULL #define CHECK_RANGE(number, min, max) \ if (number < min || number > max) { \ fprintf(stderr, \ "interfaces.UDPInterface['%s'].number must be between min and max\n", \ connectToAddress->bytes); \ exit(-1); \ } CHECK_RANGE(*authType, 1, 255) CHECK_RANGE(*trust, 0, INT64_MAX) #undef CHECK_RANGE uint8_t pkBytes[32]; if (publicKey->len < 52 || Base32_decode(pkBytes, 32, (uint8_t*)publicKey->bytes, 52) != 32) { fprintf(stderr, "interfaces.UDPInterface['%s'].publicKey could not be parsed.\n", connectToAddress->bytes); exit(-1); } uint8_t addressBytes[16]; AddressCalc_addressForPublicKey(addressBytes, pkBytes); if (addressBytes[0] != 0xFC) { fprintf(stderr, "interfaces.UDPInterface['%s'].publicKey\n( %s )\nis not in FC00/8 range, " "it was probably mistranscribed.\n", connectToAddress->bytes, publicKey->bytes); exit(-1); } struct Interface* udp = UDPInterface_addEndpoint(udpContext, connectToAddress->bytes, ctx->eHandler); struct Interface* authedUdp = CryptoAuth_wrapInterface(udp, pkBytes, false, true, ctx->ca); CryptoAuth_setAuth(password, *authType, authedUdp); uint64_t switchAddr_be; SwitchCore_addInterface(authedUdp, *trust, &switchAddr_be, ctx->switchCore); struct Address addr; memset(&addr, 0, sizeof(struct Address)); memcpy(addr.key, pkBytes, 32); addr.networkAddress_be = switchAddr_be; RouterModule_addNode(&addr, ctx->routerModule); }
static struct Address* getNode(String* pathStr, struct Context* ctx, char** errOut, struct Allocator* alloc) { struct Address addr = {.path=0}; if (pathStr->len == 19 && !AddrTools_parsePath(&addr.path, pathStr->bytes)) { struct Node_Link* nl = Router_linkForPath(ctx->router, addr.path); if (!nl) { *errOut = "not_found"; return NULL; } else { Bits_memcpyConst(&addr, &nl->child->address, sizeof(struct Address)); } } else if (pathStr->len == 39 && !AddrTools_parseIp(addr.ip6.bytes, pathStr->bytes)) { struct Node_Two* n = Router_lookup(ctx->router, addr.ip6.bytes); if (!n || Bits_memcmp(addr.ip6.bytes, n->address.ip6.bytes, 16)) { *errOut = "not_found"; return NULL; } else { Bits_memcpyConst(&addr, &n->address, sizeof(struct Address)); } } else { struct Address* a = Address_fromString(pathStr, alloc); if (a) { return a; } *errOut = "parse_path"; return NULL; } return Allocator_clone(alloc, &addr); } static void pingNode(Dict* args, void* vctx, String* txid, struct Allocator* requestAlloc) { struct Context* ctx = Identity_check((struct Context*) vctx); String* pathStr = Dict_getString(args, String_CONST("path")); int64_t* timeoutPtr = Dict_getInt(args, String_CONST("timeout")); uint32_t timeout = (timeoutPtr && *timeoutPtr > 0) ? *timeoutPtr : 0; char* err = NULL; struct Address* addr = getNode(pathStr, ctx, &err, requestAlloc); if (err) { Dict errDict = Dict_CONST(String_CONST("error"), String_OBJ(String_CONST(err)), NULL); Admin_sendMessage(&errDict, txid, ctx->admin); return; } struct RouterModule_Promise* rp = RouterModule_pingNode(addr, timeout, ctx->module, ctx->allocator); struct Ping* ping = Allocator_calloc(rp->alloc, sizeof(struct Ping), 1); Identity_set(ping); ping->txid = String_clone(txid, rp->alloc); ping->rp = rp; ping->ctx = ctx; rp->userData = ping; rp->callback = pingResponse; } static void getPeers(Dict* args, void* vctx, String* txid, struct Allocator* requestAlloc) { struct Context* ctx = Identity_check((struct Context*) vctx); String* nearbyLabelStr = Dict_getString(args, String_CONST("nearbyPath")); String* pathStr = Dict_getString(args, String_CONST("path")); int64_t* timeoutPtr = Dict_getInt(args, String_CONST("timeout")); uint32_t timeout = (timeoutPtr && *timeoutPtr > 0) ? *timeoutPtr : 0; char* err = NULL; struct Address* addr = getNode(pathStr, ctx, &err, requestAlloc); uint64_t nearbyLabel = 0; if (!err && nearbyLabelStr) { if (nearbyLabelStr->len != 19 || AddrTools_parsePath(&nearbyLabel, nearbyLabelStr->bytes)) { err = "parse_nearbyLabel"; } } if (err) { Dict errDict = Dict_CONST(String_CONST("error"), String_OBJ(String_CONST(err)), NULL); Admin_sendMessage(&errDict, txid, ctx->admin); return; } struct RouterModule_Promise* rp = RouterModule_getPeers(addr, nearbyLabel, timeout, ctx->module, ctx->allocator); struct Ping* ping = Allocator_calloc(rp->alloc, sizeof(struct Ping), 1); Identity_set(ping); ping->txid = String_clone(txid, rp->alloc); ping->rp = rp; ping->ctx = ctx; rp->userData = ping; rp->callback = getPeersResponse; } static void findNode(Dict* args, void* vctx, String* txid, struct Allocator* requestAlloc) { struct Context* ctx = Identity_check((struct Context*) vctx); String* nodeToQueryStr = Dict_getString(args, String_CONST("nodeToQuery")); String* targetStr = Dict_getString(args, String_CONST("target")); int64_t* timeoutPtr = Dict_getInt(args, String_CONST("timeout")); uint32_t timeout = (timeoutPtr && *timeoutPtr > 0) ? *timeoutPtr : 0; char* err = NULL; struct Address* nodeToQuery = getNode(nodeToQueryStr, ctx, &err, requestAlloc); uint8_t target[16]; if (!err) { if (targetStr->len != 39 || AddrTools_parseIp(target, targetStr->bytes)) { err = "parse_target"; } } if (err) { Dict errDict = Dict_CONST(String_CONST("error"), String_OBJ(String_CONST(err)), NULL); Admin_sendMessage(&errDict, txid, ctx->admin); return; } struct RouterModule_Promise* rp = RouterModule_findNode(nodeToQuery, target, timeout, ctx->module, ctx->allocator); struct Ping* ping = Allocator_calloc(rp->alloc, sizeof(struct Ping), 1); Identity_set(ping); ping->txid = String_clone(txid, rp->alloc); ping->rp = rp; ping->ctx = ctx; rp->userData = ping; rp->callback = findNodeResponse; } void RouterModule_admin_register(struct RouterModule* module, struct Router* router, struct Admin* admin, struct Allocator* alloc) { // for improved reporting alloc = Allocator_child(alloc); struct Context* ctx = Allocator_clone(alloc, (&(struct Context) { .admin = admin, .allocator = alloc, .module = module, .router = router }));
static int getIntVal(Dict* d, String* name) { int64_t* valP = Dict_getInt(d, name); return (valP && (*valP > 0)) ? *valP : 0; }