static void showConn(struct IpTunnel_Connection* conn, String* txid, struct Admin* admin, struct Allocator* alloc) { Dict* d = Dict_new(alloc); if (!Bits_isZero(conn->connectionIp6, 16)) { struct Sockaddr* addr = Sockaddr_clone(Sockaddr_LOOPBACK6, alloc); uint8_t* address; Assert_true(16 == Sockaddr_getAddress(addr, &address)); Bits_memcpy(address, conn->connectionIp6, 16); char* printedAddr = Sockaddr_print(addr, alloc); Dict_putString(d, String_CONST("ip6Address"), String_CONST(printedAddr), alloc); Dict_putInt(d, String_CONST("ip6Prefix"), conn->connectionIp6Prefix, alloc); } if (!Bits_isZero(conn->connectionIp4, 4)) { struct Sockaddr* addr = Sockaddr_clone(Sockaddr_LOOPBACK, alloc); uint8_t* address; Assert_true(4 == Sockaddr_getAddress(addr, &address)); Bits_memcpy(address, conn->connectionIp4, 4); char* printedAddr = Sockaddr_print(addr, alloc); Dict_putString(d, String_CONST("ip4Address"), String_CONST(printedAddr), alloc); Dict_putInt(d, String_CONST("ip4Prefix"), conn->connectionIp4Prefix, alloc); } Dict_putString(d, String_CONST("key"), Key_stringify(conn->routeHeader.publicKey, alloc), alloc); Dict_putInt(d, String_CONST("outgoing"), (conn->isOutgoing) ? 1 : 0, alloc); Dict_putString(d, String_CONST("error"), String_CONST("none"), alloc); Admin_sendMessage(d, txid, admin); }
static void adminPingOnResponse(struct SwitchPinger_Response* resp, void* vping) { struct Allocator* pingAlloc = resp->ping->pingAlloc; struct Ping* ping = vping; Dict* rd = Dict_new(pingAlloc); if (resp->res == SwitchPinger_Result_LABEL_MISMATCH) { uint8_t path[20] = {0}; AddrTools_printPath(path, resp->label); String* pathStr = String_new(path, pingAlloc); Dict_putString(rd, String_CONST("rpath"), pathStr, pingAlloc); } Dict_putInt(rd, String_CONST("version"), resp->version, pingAlloc); Dict_putInt(rd, String_CONST("ms"), resp->milliseconds, pingAlloc); Dict_putString(rd, String_CONST("result"), SwitchPinger_resultString(resp->res), pingAlloc); Dict_putString(rd, String_CONST("path"), ping->path, pingAlloc); if (resp->data) { Dict_putString(rd, String_CONST("data"), resp->data, pingAlloc); } if (!Bits_isZero(resp->key, 32)) { Dict_putString(rd, String_CONST("key"), Key_stringify(resp->key, pingAlloc), pingAlloc); } Admin_sendMessage(rd, ping->txid, ping->context->admin); }
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 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 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 showConn(struct IpTunnel_Connection* conn, String* txid, struct Admin* admin) { struct Allocator* alloc; BufferAllocator_STACK(alloc, 1024); Dict* d = Dict_new(alloc); char ip6[40]; if (!Bits_isZero(conn->connectionIp6, 16)) { Assert_always(evutil_inet_ntop(AF_INET6, conn->connectionIp6, ip6, 40)); Dict_putString(d, String_CONST("ip6Address"), String_CONST(ip6), alloc); } char ip4[16]; if (!Bits_isZero(conn->connectionIp4, 4)) { Assert_always(evutil_inet_ntop(AF_INET, conn->connectionIp4, ip4, 16)); Dict_putString(d, String_CONST("ip4Address"), String_CONST(ip4), alloc); } Dict_putString(d, String_CONST("key"), Key_stringify(conn->header.nodeKey, alloc), alloc); Dict_putInt(d, String_CONST("outgoing"), conn->isOutgoing, alloc); Admin_sendMessage(d, txid, admin); }
static void adminPeerStats(Dict* args, void* vcontext, String* txid, struct Allocator* alloc) { struct Context* context = Identity_check((struct Context*)vcontext); struct InterfaceController_PeerStats* stats = NULL; int64_t* page = Dict_getInt(args, String_CONST("page")); int i = (page) ? *page * ENTRIES_PER_PAGE : 0; int count = InterfaceController_getPeerStats(context->ic, alloc, &stats); String* bytesIn = String_CONST("bytesIn"); String* bytesOut = String_CONST("bytesOut"); String* pubKey = String_CONST("publicKey"); String* addr = String_CONST("addr"); String* state = String_CONST("state"); String* last = String_CONST("last"); String* switchLabel = String_CONST("switchLabel"); String* isIncoming = String_CONST("isIncoming"); String* user = String_CONST("user"); String* version = String_CONST("version"); String* duplicates = String_CONST("duplicates"); String* lostPackets = String_CONST("lostPackets"); String* receivedOutOfRange = String_CONST("receivedOutOfRange"); List* list = List_new(alloc); 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, addr, Address_toString(&stats[i].addr, alloc), alloc); Dict_putString(d, pubKey, Key_stringify(stats[i].addr.key, 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].addr.path); Dict_putString(d, switchLabel, String_new((char*)labelStack, alloc), alloc); Dict_putInt(d, isIncoming, stats[i].isIncomingConnection, alloc); Dict_putInt(d, duplicates, stats[i].duplicates, alloc); Dict_putInt(d, lostPackets, stats[i].lostPackets, alloc); Dict_putInt(d, receivedOutOfRange, stats[i].receivedOutOfRange, alloc); if (stats[i].user) { Dict_putString(d, user, stats[i].user, alloc); } uint8_t address[16]; AddressCalc_addressForPublicKey(address, stats[i].addr.key); Dict_putInt(d, version, stats[i].addr.protocolVersion, alloc); List_addDict(list, d, alloc); } Dict* resp = Dict_new(alloc); Dict_putList(resp, String_CONST("peers"), list, alloc); Dict_putInt(resp, String_CONST("total"), count, alloc); if (i < count) { Dict_putInt(resp, String_CONST("more"), 1, alloc); } Dict_putString(resp, String_CONST("deprecation"), String_CONST("publicKey,switchLabel,version will soon be removed"), alloc); Admin_sendMessage(resp, txid, context->admin); }
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); }