static void search(Dict* args, void* vctx, String* txid, struct Allocator* reqAlloc) { struct Context* ctx = Identity_check((struct Context*) vctx); String* addrStr = Dict_getStringC(args, "ipv6"); int maxRequests = -1; uint64_t* maxRequestsPtr = Dict_getIntC(args, "maxRequests"); if (maxRequestsPtr) { maxRequests = *maxRequestsPtr; } uint8_t addr[16]; if (AddrTools_parseIp(addr, (uint8_t*) addrStr->bytes)) { Dict* resp = Dict_new(reqAlloc); Dict_putStringCC(resp, "error", "ipv6 invalid", reqAlloc); Admin_sendMessage(resp, txid, ctx->admin); } else { struct Allocator* alloc = Allocator_child(ctx->allocator); struct Search* s = Allocator_calloc(alloc, sizeof(struct Search), 1); s->promise = SearchRunner_search(addr, maxRequests, maxRequests, ctx->runner, alloc); s->ctx = ctx; s->txid = String_clone(txid, alloc); s->alloc = alloc; Identity_set(s); if (!s->promise) { Dict* resp = Dict_new(reqAlloc); Dict_putStringCC(resp, "error", "creating search", reqAlloc); Admin_sendMessage(resp, txid, ctx->admin); Allocator_free(alloc); return; } s->promise->userData = s; s->promise->callback = searchResponse; } }
List* CryptoAuth_getUsers(struct CryptoAuth* context, struct Allocator* alloc) { struct CryptoAuth_pvt* ca = Identity_check((struct CryptoAuth_pvt*) context); List* users = List_new(alloc); for (struct CryptoAuth_User* u = ca->users; u; u = u->next) { List_addString(users, String_clone(u->login, alloc), alloc); } return users; }
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); }
void CryptoAuth_setAuth(const String* password, const String* login, struct CryptoAuth_Session* caSession) { struct CryptoAuth_Session_pvt* session = Identity_check((struct CryptoAuth_Session_pvt*)caSession); if (!password && (session->password || session->authType)) { session->password = NULL; session->authType = 0; } else if (!session->password || !String_equals(session->password, password)) { session->password = String_clone(password, session->alloc); session->authType = 1; if (login) { session->authType = 2; session->login = String_clone(login, session->alloc); } } else { return; } reset(session); }
List* CryptoAuth_getUsers(struct CryptoAuth* context, struct Allocator* alloc) { struct CryptoAuth_pvt* ctx = Identity_check((struct CryptoAuth_pvt*) context); uint32_t count = ctx->passwordCount; List* users = NULL; for (uint32_t i = 0; i < count; i++ ) { users = List_addString(users, String_clone(ctx->passwords[i].user, alloc), alloc); } return users; }
int CryptoAuth_addUser_ipv6(String* password, String* login, uint8_t ipv6[16], struct CryptoAuth* cryptoAuth) { struct CryptoAuth_pvt* ca = Identity_check((struct CryptoAuth_pvt*) cryptoAuth); struct Allocator* alloc = Allocator_child(ca->allocator); struct CryptoAuth_User* user = Allocator_calloc(alloc, sizeof(struct CryptoAuth_User), 1); user->alloc = alloc; Identity_set(user); if (!login) { int i = 0; for (struct CryptoAuth_User* u = ca->users; u; u = u->next) { i++; } user->login = login = String_printf(alloc, "Anon #%d", i); } else { user->login = String_clone(login, alloc); } union CryptoHeader_Challenge ac; // Users specified with a login field might want to use authType 1 still. hashPassword(user->secret, &ac, login, password, 2); Bits_memcpyConst(user->userNameHash, ac.bytes, CryptoHeader_Challenge_KEYSIZE); hashPassword(user->secret, &ac, NULL, password, 1); Bits_memcpyConst(user->passwordHash, ac.bytes, CryptoHeader_Challenge_KEYSIZE); for (struct CryptoAuth_User* u = ca->users; u; u = u->next) { if (Bits_memcmp(user->secret, u->secret, 32)) { } else if (!login) { } else if (String_equals(login, u->login)) { Allocator_free(alloc); return CryptoAuth_addUser_DUPLICATE; } } if (ipv6) { Bits_memcpyConst(user->restrictedToip6, ipv6, 16); } // Add the user to the *end* of the list for (struct CryptoAuth_User** up = &ca->users; ; up = &(*up)->next) { if (!*up) { *up = user; break; } } return 0; }
static void adminExit(Dict* input, void* vcontext, String* txid, struct Allocator* requestAlloc) { struct Context* context = vcontext; Log_info(context->logger, "Got request to exit"); Log_info(context->logger, "Stopping angel"); context->exitTxid = String_clone(txid, context->allocator); Dict angelExit = Dict_CONST(String_CONST("q"), String_OBJ(String_CONST("Angel_exit")), NULL); Hermes_callAngel(&angelExit, onAngelExitResponse, context, context->allocator, NULL, context->hermes); }
int InterfaceController_getPeerStats(struct InterfaceController* ifController, struct Allocator* alloc, struct InterfaceController_PeerStats** statsOut) { struct InterfaceController_pvt* ic = Identity_check((struct InterfaceController_pvt*) ifController); int count = 0; for (int i = 0; i < ic->icis->length; i++) { struct InterfaceController_Iface_pvt* ici = ArrayList_OfIfaces_get(ic->icis, i); count += ici->peerMap.count; } struct InterfaceController_PeerStats* stats = Allocator_calloc(alloc, sizeof(struct InterfaceController_PeerStats), count); int xcount = 0; for (int j = 0; j < ic->icis->length; j++) { struct InterfaceController_Iface_pvt* ici = ArrayList_OfIfaces_get(ic->icis, j); for (int i = 0; i < (int)ici->peerMap.count; i++) { struct Peer* peer = Identity_check((struct Peer*) ici->peerMap.values[i]); struct InterfaceController_PeerStats* s = &stats[xcount]; xcount++; Bits_memcpy(&s->addr, &peer->addr, sizeof(struct Address)); s->bytesOut = peer->bytesOut; s->bytesIn = peer->bytesIn; s->timeOfLastMessage = peer->timeOfLastMessage; s->state = peer->state; s->isIncomingConnection = peer->isIncomingConnection; if (peer->caSession->displayName) { s->user = String_clone(peer->caSession->displayName, alloc); } struct ReplayProtector* rp = &peer->caSession->replayProtector; s->duplicates = rp->duplicates; s->lostPackets = rp->lostPackets; s->receivedOutOfRange = rp->receivedOutOfRange; struct PeerLink_Kbps kbps; PeerLink_kbps(peer->peerLink, &kbps); s->sendKbps = kbps.sendKbps; s->recvKbps = kbps.recvKbps; } } Assert_true(xcount == count); *statsOut = stats; return count; }
static String* getCorePath(struct Allocator* alloc) { struct Allocator* alloc2 = Allocator_child(alloc); char* cjdroute2Path = Process_getPath(alloc2); char* lastSlash = strrchr(cjdroute2Path, '/'); Assert_always(lastSlash != NULL); *lastSlash = '\0'; String* tempOutput = String_printf(alloc2, "%s/cjdns", cjdroute2Path); String* output = NULL; if (fileExists(tempOutput->bytes)) { output = String_clone(tempOutput, alloc); } Allocator_free(alloc2); return output; }
struct InterfaceController_Iface* InterfaceController_newIface(struct InterfaceController* ifc, String* name, struct Allocator* alloc) { struct InterfaceController_pvt* ic = Identity_check((struct InterfaceController_pvt*) ifc); struct InterfaceController_Iface_pvt* ici = Allocator_calloc(alloc, sizeof(struct InterfaceController_Iface_pvt), 1); ici->name = String_clone(name, alloc); ici->peerMap.allocator = alloc; ici->ic = ic; ici->alloc = alloc; ici->pub.addrIf.send = handleIncomingFromWire; ici->pub.ifNum = ArrayList_OfIfaces_add(ic->icis, ici); Identity_set(ici); return &ici->pub; }
int InterfaceController_bootstrapPeer(struct InterfaceController* ifc, int interfaceNumber, uint8_t* herPublicKey, const struct Sockaddr* lladdrParm, String* password, String* login, String* user, struct Allocator* alloc) { struct InterfaceController_pvt* ic = Identity_check((struct InterfaceController_pvt*) ifc); Assert_true(herPublicKey); Assert_true(password); struct InterfaceController_Iface_pvt* ici = ArrayList_OfIfaces_get(ic->icis, interfaceNumber); if (!ici) { return InterfaceController_bootstrapPeer_BAD_IFNUM; } Log_debug(ic->logger, "bootstrapPeer total [%u]", ici->peerMap.count); uint8_t ip6[16]; AddressCalc_addressForPublicKey(ip6, herPublicKey); if (!AddressCalc_validAddress(ip6) || !Bits_memcmp(ic->ca->publicKey, herPublicKey, 32)) { return InterfaceController_bootstrapPeer_BAD_KEY; } struct Allocator* epAlloc = Allocator_child(ici->alloc); struct Sockaddr* lladdr = Sockaddr_clone(lladdrParm, epAlloc); // TODO(cjd): eps are created in 3 places, there should be a factory function. struct Peer* ep = Allocator_calloc(epAlloc, sizeof(struct Peer), 1); int index = Map_EndpointsBySockaddr_put(&lladdr, &ep, &ici->peerMap); Assert_true(index >= 0); ep->alloc = epAlloc; ep->handle = ici->peerMap.handles[index]; ep->lladdr = lladdr; ep->ici = ici; ep->isIncomingConnection = false; Bits_memcpy(ep->addr.key, herPublicKey, 32); Address_getPrefix(&ep->addr); Identity_set(ep); Allocator_onFree(epAlloc, closeInterface, ep); Allocator_onFree(alloc, freeAlloc, epAlloc); ep->peerLink = PeerLink_new(ic->eventBase, epAlloc); ep->caSession = CryptoAuth_newSession(ic->ca, epAlloc, herPublicKey, false, "outer"); CryptoAuth_setAuth(password, login, ep->caSession); if (user) { ep->caSession->displayName = String_clone(user, epAlloc); } ep->switchIf.send = sendFromSwitch; if (SwitchCore_addInterface(ic->switchCore, &ep->switchIf, epAlloc, &ep->addr.path)) { Log_debug(ic->logger, "bootstrapPeer() SwitchCore out of space"); Allocator_free(epAlloc); return InterfaceController_bootstrapPeer_OUT_OF_SPACE; } // 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; if (Defined(Log_INFO)) { struct Allocator* tempAlloc = Allocator_child(alloc); String* addrStr = Address_toString(&ep->addr, tempAlloc); Log_info(ic->logger, "Adding peer [%s] from bootstrapPeer()", addrStr->bytes); Allocator_free(tempAlloc); } // We can't just add the node directly to the routing table because we do not know // the version. We'll send it a switch ping and when it responds, we will know it's // key (if we don't already) and version number. sendPing(ep); return 0; }
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 }));
/** @return a string representing the address and port to connect to. */ static String* initAngel(int fromAngel, int toAngel, int corePipes[2][2], struct PipeInterface** piOut, struct EventBase* eventBase, struct Log* logger, struct Allocator* alloc, struct Random* rand) { #define TO_CORE (corePipes[0][1]) #define FROM_CORE (corePipes[1][0]) #define TO_ANGEL_AS_CORE (corePipes[1][1]) #define FROM_ANGEL_AS_CORE (corePipes[0][0]) Dict core = Dict_CONST( String_CONST("fromCore"), Int_OBJ(FROM_CORE), Dict_CONST( String_CONST("toCore"), Int_OBJ(TO_CORE), NULL )); Dict admin = Dict_CONST( String_CONST("bind"), String_OBJ(String_CONST("127.0.0.1")), Dict_CONST( String_CONST("core"), Dict_OBJ(&core), Dict_CONST( String_CONST("pass"), String_OBJ(String_CONST("abcd")), NULL ))); Dict message = Dict_CONST( String_CONST("admin"), Dict_OBJ(&admin), NULL ); struct Allocator* tempAlloc; BufferAllocator_STACK(tempAlloc, 1024); #define BUFFER_SZ 1023 uint8_t buff[BUFFER_SZ + 1] = {0}; struct Writer* w = ArrayWriter_new(buff, BUFFER_SZ, tempAlloc); StandardBencSerializer_get()->serializeDictionary(w, &message); Log_info(logger, "Writing intial configuration to angel on [%d] config: [%s]", toAngel, buff); write(toAngel, buff, w->bytesWritten(w)); // This is angel->core data, we can throw this away. //Waiter_getData(buff, BUFFER_SZ, fromAngel, eventBase, NULL); //Log_info(logger, "Init message from angel to core: [%s]", buff); Bits_memset(buff, 0, BUFFER_SZ); struct PipeInterface* pi = PipeInterface_new(FROM_ANGEL_AS_CORE, TO_ANGEL_AS_CORE, eventBase, logger, alloc, rand); *piOut = pi; Log_info(logger, "PipeInterface [%p] is now ready.", (void*)pi); // Make sure the angel sends data to the core. InterfaceWaiter_waitForData(&pi->generic, eventBase, alloc, NULL); // Send response on behalf of core. char coreToAngelResponse[128] = " PADDING " "\xff\xff\xff\xff" "d" "5:error" "4:none" "e"; char* start = strchr(coreToAngelResponse, '\xff'); struct Message m = { .bytes = (uint8_t*) start, .length = strlen(start), .padding = start - coreToAngelResponse }; pi->generic.sendMessage(&m, &pi->generic); // This is angel->client data, it will tell us which port was bound. Waiter_getData(buff, BUFFER_SZ, fromAngel, eventBase, NULL); printf("Response from angel to client: [%s]\n", buff); struct Reader* reader = ArrayReader_new(buff, BUFFER_SZ, tempAlloc); Dict configStore; Dict* config = &configStore; Assert_true(!StandardBencSerializer_get()->parseDictionary(reader, tempAlloc, config)); Dict* responseAdmin = Dict_getDict(config, String_CONST("admin")); String* bind = Dict_getString(responseAdmin, String_CONST("bind")); Assert_true(bind); return String_clone(bind, alloc); } /** * This spawns itself as the Angel process which spawns itself again as the core process. * The "core process" pipes all of its inputs back to the originating process */ struct AdminTestFramework* AdminTestFramework_setUp(int argc, char** argv) { if (argc > 1 && !strcmp("angel", argv[1])) { exit(AngelInit_main(argc, argv)); } struct Allocator* alloc = CanaryAllocator_new(MallocAllocator_new(1<<20), NULL); struct Writer* logwriter = FileWriter_new(stdout, alloc); Assert_always(logwriter); struct Log* logger = WriterLog_new(logwriter, alloc); struct EventBase* eventBase = EventBase_new(alloc); struct Random* rand = Random_new(alloc, NULL); int fromAngel; int toAngel; int corePipes[2][2]; if (Pipe_createUniPipe(corePipes[0]) || Pipe_createUniPipe(corePipes[1])) { Except_raise(NULL, -1, "Failed to create pipes [%s]", Errno_getString()); } spawnAngel(&fromAngel, &toAngel); struct PipeInterface* pi; String* addrStr = initAngel(fromAngel, toAngel, corePipes, &pi, eventBase, logger, alloc, rand); Log_info(logger, "Angel initialized."); String* password = String_new("abcd", alloc); struct Admin* admin = Admin_new(&pi->generic, alloc, logger, eventBase, password); // Now setup the client. struct sockaddr_storage addr; int addrLen = sizeof(struct sockaddr_storage); Bits_memset(&addr, 0, sizeof(struct sockaddr_storage)); Assert_true(!evutil_parse_sockaddr_port(addrStr->bytes, (struct sockaddr*) &addr, &addrLen)); struct AdminClient* client = AdminClient_new((uint8_t*) &addr, addrLen, password, eventBase, logger, alloc); Assert_always(client); return alloc->clone(sizeof(struct AdminTestFramework), alloc, &(struct AdminTestFramework) { .admin = admin, .client = client, .alloc = alloc, .eventBase = eventBase, .logger = logger, .addr = alloc->clone(addrLen, alloc, &addr), .addrLen = addrLen, .angelInterface = &pi->generic }); }
static void udpInterface(Dict* config, struct Context* ctx) { List* ifaces = Dict_getList(config, String_CONST("UDPInterface")); if (!ifaces) { ifaces = List_new(ctx->alloc); List_addDict(ifaces, Dict_getDict(config, String_CONST("UDPInterface")), ctx->alloc); } uint32_t count = List_size(ifaces); for (uint32_t i = 0; i < count; i++) { Dict *udp = List_getDict(ifaces, i); if (!udp) { continue; } // Setup the interface. String* bindStr = Dict_getString(udp, String_CONST("bind")); Dict* d = Dict_new(ctx->alloc); if (bindStr) { Dict_putString(d, String_CONST("bindAddress"), bindStr, ctx->alloc); } Dict* resp = NULL; rpcCall0(String_CONST("UDPInterface_new"), d, ctx, ctx->alloc, &resp, true); int ifNum = *(Dict_getInt(resp, String_CONST("interfaceNumber"))); // Make the connections. Dict* connectTo = Dict_getDict(udp, String_CONST("connectTo")); if (connectTo) { struct Dict_Entry* entry = *connectTo; struct Allocator* perCallAlloc = Allocator_child(ctx->alloc); while (entry != NULL) { String* key = (String*) entry->key; if (entry->val->type != Object_DICT) { Log_critical(ctx->logger, "interfaces.UDPInterface.connectTo: entry [%s] " "is not a dictionary type.", key->bytes); exit(-1); } Dict* all = entry->val->as.dictionary; Dict* value = Dict_new(perCallAlloc); String* pub_d = Dict_getString(all, String_CONST("publicKey")); String* pss_d = Dict_getString(all, String_CONST("password")); String* peerName_d = Dict_getString(all, String_CONST("peerName")); String* login_d = Dict_getString(all, String_CONST("login")); if ( !pub_d || !pss_d ) { const char * error_name = "(unknown)"; if ( !pub_d ) { error_name = "publicKey"; } if ( !pss_d ) { error_name = "password"; } Log_warn(ctx->logger, "Skipping peer: missing %s for peer [%s]", error_name, key->bytes); if (abort_if_invalid_ref) { Assert_failure("Invalid peer reference"); } else { entry = entry->next; continue; } } Dict_putString(value, String_CONST("publicKey"), pub_d, perCallAlloc); Dict_putString(value, String_CONST("password"), pss_d, perCallAlloc); Dict_putString(value, String_CONST("peerName"), peerName_d, perCallAlloc); Dict_putString(value, String_CONST("login"), login_d, perCallAlloc); Log_keys(ctx->logger, "Attempting to connect to node [%s].", key->bytes); key = String_clone(key, perCallAlloc); char* lastColon = CString_strrchr(key->bytes, ':'); if (!Sockaddr_parse(key->bytes, NULL)) { // it's a sockaddr, fall through } else if (lastColon) { // try it as a hostname. int port = atoi(lastColon+1); if (!port) { Log_critical(ctx->logger, "Couldn't get port number from [%s]", key->bytes); exit(-1); } *lastColon = '\0'; struct Sockaddr* adr = Sockaddr_fromName(key->bytes, perCallAlloc); if (adr != NULL) { Sockaddr_setPort(adr, port); key = String_new(Sockaddr_print(adr, perCallAlloc), perCallAlloc); } else { Log_warn(ctx->logger, "Failed to lookup hostname [%s]", key->bytes); entry = entry->next; continue; } } struct Allocator* child = Allocator_child(ctx->alloc); struct Message* msg = Message_new(0, AdminClient_MAX_MESSAGE_SIZE + 256, child); int r = BencMessageWriter_writeDictTry(value, msg, NULL); const int max_reference_size = 298; if (r != 0 || msg->length > max_reference_size) { Log_warn(ctx->logger, "Peer skipped:"); Log_warn(ctx->logger, "Too long peer reference for [%s]", key->bytes); if (abort_if_invalid_ref) { Assert_failure("Invalid peer reference"); } else { entry = entry->next; continue; } } Dict_putInt(value, String_CONST("interfaceNumber"), ifNum, perCallAlloc); Dict_putString(value, String_CONST("address"), key, perCallAlloc); rpcCall(String_CONST("UDPInterface_beginConnection"), value, ctx, perCallAlloc); entry = entry->next; } Allocator_free(perCallAlloc); } } }
static void udpInterface(Dict* config, struct Context* ctx) { List* ifaces = Dict_getList(config, String_CONST("UDPInterface")); if (!ifaces) { ifaces = List_addDict(ifaces, Dict_getDict(config, String_CONST("UDPInterface")), ctx->alloc); } uint32_t count = List_size(ifaces); for (uint32_t i = 0; i < count; i++) { Dict *udp = List_getDict(ifaces, i); if (!udp) { continue; } // Setup the interface. String* bindStr = Dict_getString(udp, String_CONST("bind")); Dict* d = Dict_new(ctx->alloc); if (bindStr) { Dict_putString(d, String_CONST("bindAddress"), bindStr, ctx->alloc); } rpcCall(String_CONST("UDPInterface_new"), d, ctx, ctx->alloc); // Make the connections. Dict* connectTo = Dict_getDict(udp, String_CONST("connectTo")); if (connectTo) { struct Dict_Entry* entry = *connectTo; struct Allocator* perCallAlloc = Allocator_child(ctx->alloc); while (entry != NULL) { String* key = (String*) entry->key; if (entry->val->type != Object_DICT) { Log_critical(ctx->logger, "interfaces.UDPInterface.connectTo: entry [%s] " "is not a dictionary type.", key->bytes); exit(-1); } Dict* value = entry->val->as.dictionary; Log_keys(ctx->logger, "Attempting to connect to node [%s].", key->bytes); key = String_clone(key, perCallAlloc); char* lastColon = strrchr(key->bytes, ':'); if (!Sockaddr_parse(key->bytes, NULL)) { // it's a sockaddr, fall through } else if (lastColon) { // try it as a hostname. int port = atoi(lastColon+1); if (!port) { Log_critical(ctx->logger, "Couldn't get port number from [%s]", key->bytes); exit(-1); } *lastColon = '\0'; struct Sockaddr* adr = Sockaddr_fromName(key->bytes, perCallAlloc); if (adr != NULL) { Sockaddr_setPort(adr, port); key = String_new(Sockaddr_print(adr, perCallAlloc), perCallAlloc); } else { Log_warn(ctx->logger, "Failed to lookup hostname [%s]", key->bytes); entry = entry->next; continue; } } Dict_putString(value, String_CONST("address"), key, perCallAlloc); rpcCall(String_CONST("UDPInterface_beginConnection"), value, ctx, perCallAlloc); entry = entry->next; } Allocator_free(perCallAlloc); } } }
static void pingNode(Dict* args, void* vctx, String* txid, struct Allocator* requestAlloc) { struct Context* ctx = Identity_cast((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 = {.path=0}; struct Node* n = NULL; if (pathStr->len == 19 && !AddrTools_parsePath(&addr.path, (uint8_t*) pathStr->bytes)) { n = RouterModule_getNode(addr.path, ctx->router); } else if (!AddrTools_parseIp(addr.ip6.bytes, (uint8_t*) pathStr->bytes)) { n = RouterModule_lookup(addr.ip6.bytes, ctx->router); if (n && Bits_memcmp(addr.ip6.bytes, n->address.ip6.bytes, 16)) { n = NULL; } } else { err = "Unexpected address, must be either an ipv6 address " "eg: 'fc4f:d:e499:8f5b:c49f:6e6b:1ae:3120', 19 char path eg: '0123.4567.89ab.cdef'"; } if (!err) { if (!n) { err = "could not find node to ping"; } else { struct RouterModule_Promise* rp = RouterModule_pingNode(n, timeout, ctx->router, 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; } } if (err) { Dict errDict = Dict_CONST(String_CONST("error"), String_OBJ(String_CONST(err)), NULL); Admin_sendMessage(&errDict, txid, ctx->admin); } } void RouterModule_admin_register(struct RouterModule* module, struct Admin* admin, struct Allocator* alloc) { struct Context* ctx = Allocator_clone(alloc, (&(struct Context) { .admin = admin, .allocator = alloc, .router = module })); Identity_set(ctx); Admin_registerFunction("RouterModule_lookup", lookup, ctx, true, ((struct Admin_FunctionArg[]) { { .name = "address", .required = 1, .type = "String" } }), admin);
static void udpInterface(Dict* config, struct Context* ctx) { List* ifaces = Dict_getList(config, String_CONST("UDPInterface")); if (!ifaces) { ifaces = List_new(ctx->alloc); List_addDict(ifaces, Dict_getDict(config, String_CONST("UDPInterface")), ctx->alloc); } uint32_t count = List_size(ifaces); for (uint32_t i = 0; i < count; i++) { Dict *udp = List_getDict(ifaces, i); if (!udp) { continue; } // Setup the interface. String* bindStr = Dict_getString(udp, String_CONST("bind")); Dict* d = Dict_new(ctx->alloc); if (bindStr) { Dict_putString(d, String_CONST("bindAddress"), bindStr, ctx->alloc); } Dict* resp = NULL; rpcCall0(String_CONST("UDPInterface_new"), d, ctx, ctx->alloc, &resp, true); int ifNum = *(Dict_getInt(resp, String_CONST("interfaceNumber"))); // Make the connections. Dict* connectTo = Dict_getDict(udp, String_CONST("connectTo")); if (connectTo) { struct Dict_Entry* entry = *connectTo; struct Allocator* perCallAlloc = Allocator_child(ctx->alloc); while (entry != NULL) { String* key = (String*) entry->key; if (entry->val->type != Object_DICT) { Log_critical(ctx->logger, "interfaces.UDPInterface.connectTo: entry [%s] " "is not a dictionary type.", key->bytes); exit(-1); } Dict* value = entry->val->as.dictionary; Log_keys(ctx->logger, "Attempting to connect to node [%s].", key->bytes); key = String_clone(key, perCallAlloc); char* lastColon = CString_strrchr(key->bytes, ':'); if (!Sockaddr_parse(key->bytes, NULL)) { // it's a sockaddr, fall through } else if (lastColon) { // try it as a hostname. Log_critical(ctx->logger, "Couldn't add connection [%s], " "hostnames aren't supported.", key->bytes); exit(-1); } Dict_putInt(value, String_CONST("interfaceNumber"), ifNum, perCallAlloc); Dict_putString(value, String_CONST("address"), key, perCallAlloc); rpcCall(String_CONST("UDPInterface_beginConnection"), value, ctx, perCallAlloc); // Make a IPTunnel exception for this node Dict* aed = Dict_new(perCallAlloc); *lastColon = '\0'; Dict_putString(aed, String_CONST("route"), String_new(key->bytes, perCallAlloc), perCallAlloc); *lastColon = ':'; rpcCall(String_CONST("RouteGen_addException"), aed, ctx, perCallAlloc); entry = entry->next; } Allocator_free(perCallAlloc); } } }
void GlobalConfig_setTunName(struct GlobalConfig* conf, String* name) { struct GlobalConfig_pvt* ctx = Identity_check((struct GlobalConfig_pvt*) conf); // This is a memory leak but hopefully this function doesn't get called too much... ctx->tunName = String_clone(name, ctx->alloc); }