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); }
int main(int argc, char** argv) { printf("init test"); struct Allocator* alloc = MallocAllocator_new(1<<20); struct Log* logger = FileWriterLog_new(stdout, alloc); struct EventBase* base = EventBase_new(alloc); char* ifName; struct Iface* iface = TAPInterface_new(NULL, &ifName, NULL, logger, base, alloc); struct NDPServer* ndp = NDPServer_new(iface, alloc); ndp->generic.receiveMessage = receiveMessage; ndp->generic.receiverContext = alloc; ndp->advertisePrefix[0] = 0xfd; ndp->prefixLen = AddressCalc_ADDRESS_PREFIX_BITS; struct Sockaddr_storage ss; Assert_true(!Sockaddr_parse("fd00::1", &ss)); NetDev_addAddress(ifName, &ss.addr, AddressCalc_ADDRESS_PREFIX_BITS, logger, NULL); Timeout_setTimeout(fail, alloc, 10000, base, alloc); EventBase_beginLoop(base); printf("Test ended\n"); return 0; }
int UDPInterface_beginConnection(const char* address, uint8_t cryptoKey[32], String* password, struct UDPInterface* udp) { struct UDPInterface_pvt* udpif = (struct UDPInterface_pvt*) udp; struct Sockaddr_storage addr; if (Sockaddr_parse(address, &addr)) { return UDPInterface_beginConnection_BAD_ADDRESS; } if (addr.addr.addrLen != udp->addr->addrLen) { return UDPInterface_beginConnection_ADDRESS_MISMATCH; } struct Interface* iface = MultiInterface_ifaceForKey(udpif->multiIface, &addr); int ret = InterfaceController_registerPeer(udpif->ic, cryptoKey, password, false, false, iface); if (ret) { Allocator_free(iface->allocator); switch(ret) { case InterfaceController_registerPeer_BAD_KEY: return UDPInterface_beginConnection_BAD_KEY; case InterfaceController_registerPeer_OUT_OF_SPACE: return UDPInterface_beginConnection_OUT_OF_SPACE; default: return UDPInterface_beginConnection_UNKNOWN_ERROR; } } return 0; }
static void addServer(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc) { struct Context* context = vcontext; struct Allocator* alloc = Allocator_child(context->alloc); String* addrStr = Dict_getString(args, String_CONST("addr")); int ret; struct Sockaddr_storage ss; char* err = "none"; if (Sockaddr_parse(addrStr->bytes, &ss)) { err = "could not parse address"; } else if ((ret = RainflyClient_addServer(context->rainfly, &ss.addr))) { if (ret == RainflyClient_addServer_WRONG_ADDRESS_TYPE) { err = "RainflyClient_addServer_WRONG_ADDRESS_TYPE"; } else { err = "unknown error"; } } 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 checkRunningInstance(struct Allocator* allocator, struct EventBase* base, String* addr, String* password, struct Log* logger, struct Except* eh) { struct Allocator* alloc = Allocator_child(allocator); struct Sockaddr_storage pingAddrStorage; if (Sockaddr_parse(addr->bytes, &pingAddrStorage)) { Except_raise(eh, -1, "Unable to parse [%s] as an ip address port, eg: 127.0.0.1:11234", addr->bytes); } struct AdminClient* adminClient = AdminClient_new(&pingAddrStorage.addr, password, base, logger, alloc); // 100 milliseconds is plenty to wait for a process to respond on the same machine. adminClient->millisecondsToWait = 100; Dict* pingArgs = Dict_new(alloc); struct AdminClient_Result* pingResult = AdminClient_rpcCall(String_new("ping", alloc), pingArgs, adminClient, alloc); if (pingResult->err == AdminClient_Error_NONE) { Except_raise(eh, -1, "Startup failed: cjdroute is already running."); } Allocator_free(alloc); }
struct AdminTestFramework* AdminTestFramework_setUp(int argc, char** argv, char* testName) { if (argc > 2 && !strcmp(testName, argv[1]) && !strcmp("angel", argv[2])) { exit(AngelInit_main(argc-1, &argv[1])); } struct Allocator* alloc = MallocAllocator_new(1<<20); struct Writer* logwriter = FileWriter_new(stdout, alloc); Assert_true(logwriter); struct Log* logger = WriterLog_new(logwriter, alloc); struct EventBase* eventBase = EventBase_new(alloc); struct Random* rand = Random_new(alloc, logger, NULL); char asClientPipeName[32] = {0}; Random_base32(rand, (uint8_t*)asClientPipeName, 31); struct Pipe* asClientPipe = Pipe_named(asClientPipeName, eventBase, NULL, alloc); asClientPipe->logger = logger; char asCorePipeName[32] = {0}; Random_base32(rand, (uint8_t*)asCorePipeName, 31); struct Pipe* asCorePipe = Pipe_named(asCorePipeName, eventBase, NULL, alloc); asCorePipe->logger = logger; struct Interface* asCoreIface = FramingInterface_new(65535, &asCorePipe->iface, alloc); spawnAngel(testName, asClientPipeName, eventBase, alloc); Log_info(logger, "Initializing Angel"); initAngel(asClientPipe, asCoreIface, (char*)asCorePipe->name, eventBase, logger, alloc, rand); struct Sockaddr_storage addr; Assert_true(!Sockaddr_parse("127.0.0.1", &addr)); Log_info(logger, "Binding UDP admin socket"); struct AddrInterface* udpAdmin = UDPAddrInterface_new(eventBase, &addr.addr, alloc, NULL, logger); String* password = String_new("abcd", alloc); struct Admin* admin = Admin_new(udpAdmin, alloc, logger, eventBase, password); // Now setup the client. struct AdminClient* client = AdminClient_new(udpAdmin->addr, password, eventBase, logger, alloc); Assert_true(client); return Allocator_clone(alloc, (&(struct AdminTestFramework) { .admin = admin, .client = client, .alloc = alloc, .eventBase = eventBase, .logger = logger, .addr = Sockaddr_clone(udpAdmin->addr, alloc), .angelInterface = asCoreIface }));
static void addRemoveSomething(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc, enum addRemoveSomething_What what) { struct RouteGen_admin_Ctx* ctx = Identity_check((struct RouteGen_admin_Ctx*) vcontext); String* route = Dict_getString(args, String_CONST("route")); char* error = NULL; struct Sockaddr_storage ss; if (route->len > 63) { error = "parse_failed"; } if (!error) { if (Sockaddr_parse(route->bytes, &ss)) { error = "parse_failed"; } else { int family = Sockaddr_getFamily(&ss.addr); if (family != Sockaddr_AF_INET && family != Sockaddr_AF_INET6) { error = "unexpected_af"; } } } int retVal = -1; Dict* out = Dict_new(requestAlloc); if (!error) { switch (what) { case addRemoveSomething_What_ADD_EXCEPTION: RouteGen_addException(ctx->rg, &ss.addr); break; case addRemoveSomething_What_ADD_PREFIX: RouteGen_addPrefix(ctx->rg, &ss.addr); break; case addRemoveSomething_What_ADD_LOCALPREFIX: RouteGen_addLocalPrefix(ctx->rg, &ss.addr); break; case addRemoveSomething_What_RM_EXCEPTION: retVal = RouteGen_removeException(ctx->rg, &ss.addr); break; case addRemoveSomething_What_RM_PREFIX: retVal = RouteGen_removePrefix(ctx->rg, &ss.addr); break; case addRemoveSomething_What_RM_LOCALPREFIX: retVal = RouteGen_removeLocalPrefix(ctx->rg, &ss.addr); break; default: Assert_failure("invalid op"); } if (!retVal) { error = "no_such_route"; } else { error = "none"; } } Dict_putString(out, String_new("error", requestAlloc), String_new(error, requestAlloc), requestAlloc); Admin_sendMessage(out, txid, ctx->admin); }
static void expectConvert(char* address, char* expectedOutput) { struct Sockaddr_storage ss; Assert_always(!Sockaddr_parse(address, &ss)); struct Allocator* alloc = MallocAllocator_new(20000); char* outAddr = Sockaddr_print(&ss.addr, alloc); Assert_always(outAddr); Assert_always(strlen(outAddr) == strlen(expectedOutput)); Assert_always(!strcmp(outAddr, expectedOutput)); Allocator_free(alloc); }
int main(int argc, char** argv) { struct Allocator* alloc = MallocAllocator_new(1<<20); struct EventBase* base = EventBase_new(alloc); struct Writer* logWriter = FileWriter_new(stdout, alloc); struct Log* logger = WriterLog_new(logWriter, alloc); struct Sockaddr* addrA = Sockaddr_fromBytes(testAddrA, Sockaddr_AF_INET6, alloc); char assignedIfName[TUNInterface_IFNAMSIZ]; struct Interface* tun = TUNInterface_new(NULL, assignedIfName, base, logger, NULL, alloc); NetDev_addAddress(assignedIfName, addrA, 126, logger, NULL); struct Sockaddr_storage addr; Assert_always(!Sockaddr_parse("[fd00::1]", &addr)); #ifdef freebsd // tun is not setup synchronously in bsd but it lets you bind to the tun's // address anyway. sleep(1); #endif // Mac OSX and BSD do not set up their TUN devices synchronously. // We'll just keep on trying until this works. struct AddrInterface* udp = NULL; for (int i = 0; i < 20; i++) { if ((udp = setupUDP(base, &addr.addr, alloc, logger))) { break; } } Assert_always(udp); struct Sockaddr* dest = Sockaddr_clone(udp->addr, alloc); uint8_t* addrBytes; Assert_always(16 == Sockaddr_getAddress(dest, &addrBytes)); Bits_memcpy(addrBytes, testAddrB, 16); struct Message* msg; Message_STACK(msg, 0, 64); Message_push(msg, "Hello World", 12, NULL); Message_push(msg, dest, dest->addrLen, NULL); udp->generic.receiveMessage = receiveMessageUDP; udp->generic.receiverContext = alloc; tun->receiveMessage = receiveMessageTUN; udp->generic.sendMessage(msg, &udp->generic); Timeout_setTimeout(fail, NULL, 10000, base, alloc); EventBase_beginLoop(base); return 0; }
/** * Parse out an address. * * @param out a pointer to a byte array which will be set to the bytes of the ipv6 address. * @param hexAddr a string representation of the ipv6 address such as: * "fc4f:630d:e499:8f5b:c49f:6e6b:01ae:3120". * @return 0 if successful, -1 if the hexAddr is malformed. */ int AddrTools_parseIp(uint8_t out[16], const uint8_t hexAddr[40]) { struct Sockaddr_storage ss; if (Sockaddr_parse((const char*) hexAddr, &ss) || Sockaddr_getFamily(&ss.addr) != Sockaddr_AF_INET6) { return -1; } uint8_t* addr = NULL; Sockaddr_getAddress(&ss.addr, &addr); Bits_memcpy(out, addr, 16); return 0; }
static void newInterface(Dict* args, void* vcontext, String* txid) { struct Context* ctx = vcontext; String* bindAddress = Dict_getString(args, String_CONST("bindAddress")); struct Sockaddr_storage addr; if (Sockaddr_parse((bindAddress) ? bindAddress->bytes : "0.0.0.0", &addr)) { Dict out = Dict_CONST( String_CONST("error"), String_OBJ(String_CONST("Failed to parse address")), NULL ); Admin_sendMessage(&out, txid, ctx->admin); return; } newInterface2(ctx, &addr.addr, txid); }
static Iface_DEFUN messageToAngel(struct Message* msg, struct Iface* iface) { struct NodeContext* ctx = Identity_check((struct NodeContext*) iface); if (ctx->boundAddr) { return 0; } struct Allocator* alloc = Allocator_child(ctx->alloc); Dict* config = BencMessageReader_read(msg, alloc, NULL); Dict* admin = Dict_getDict(config, String_CONST("admin")); String* bind = Dict_getString(admin, String_CONST("bind")); struct Sockaddr_storage ss; Assert_true(!Sockaddr_parse(bind->bytes, &ss)); ctx->boundAddr = Sockaddr_clone(&ss.addr, ctx->alloc); Allocator_free(alloc); EventBase_endLoop(ctx->base); return 0; }
static void checkRunningInstance(struct Allocator* allocator, struct EventBase* base, String* addr, String* password, struct Log* logger, struct Except* eh) { struct Allocator* alloc = Allocator_child(allocator); struct Sockaddr_storage pingAddrStorage; if (Sockaddr_parse(addr->bytes, &pingAddrStorage)) { Except_throw(eh, "Unable to parse [%s] as an ip address port, eg: 127.0.0.1:11234", addr->bytes); } struct AdminClient* adminClient = AdminClient_new(&pingAddrStorage.addr, password, base, logger, alloc); // 100 milliseconds is plenty to wait for a process to respond on the same machine. adminClient->millisecondsToWait = 100; Dict* pingArgs = Dict_new(alloc); struct AdminClient_Promise* pingPromise = AdminClient_rpcCall(String_new("ping", alloc), pingArgs, adminClient, alloc); struct CheckRunningInstanceContext* ctx = Allocator_malloc(alloc, sizeof(struct CheckRunningInstanceContext)); ctx->base = base; ctx->alloc = alloc; ctx->res = NULL; pingPromise->callback = checkRunningInstanceCallback; pingPromise->userData = ctx; EventBase_beginLoop(base); Assert_true(ctx->res); if (ctx->res->err != AdminClient_Error_TIMEOUT) { Except_throw(eh, "Startup failed: cjdroute is already running. [%d]", ctx->res->err); } Allocator_free(alloc); }
int main(int argc, char** argv) { struct Allocator* alloc = MallocAllocator_new(1<<20); struct EventBase* base = EventBase_new(alloc); struct Writer* logWriter = FileWriter_new(stdout, alloc); struct Log* log = WriterLog_new(logWriter, alloc); struct Sockaddr* addrA = Sockaddr_fromBytes(testAddrA, Sockaddr_AF_INET6, alloc); char assignedIfName[TUNInterface_IFNAMSIZ]; struct Interface* tap = TUNInterface_new(NULL, assignedIfName, 1, base, log, NULL, alloc); struct TAPWrapper* tapWrapper = TAPWrapper_new(tap, log, alloc); // Now setup the NDP server so the tun will work correctly. struct NDPServer* ndp = NDPServer_new(&tapWrapper->generic, log, TAPWrapper_LOCAL_MAC, alloc); ndp->advertisePrefix[0] = 0xfd; ndp->prefixLen = 8; struct Interface* tun = &ndp->generic; NetDev_addAddress(assignedIfName, addrA, 126, log, NULL); struct Sockaddr_storage addr; Assert_true(!Sockaddr_parse("[::]", &addr)); struct AddrInterface* udp = TUNTools_setupUDP(base, &addr.addr, alloc, log); struct Sockaddr* dest = Sockaddr_clone(udp->addr, alloc); uint8_t* addrBytes; Assert_true(16 == Sockaddr_getAddress(dest, &addrBytes)); Bits_memcpy(addrBytes, testAddrB, 16); udp->generic.receiveMessage = receiveMessageUDP; udp->generic.receiverContext = alloc; tun->receiveMessage = receiveMessageTUN; TUNTools_sendHelloWorld(udp, dest, base, alloc); Timeout_setTimeout(fail, NULL, 10000000, base, alloc); EventBase_beginLoop(base); return 0; }
int main(int argc, char** argv) { // TODO: fix TUNConfigurator_addIp4Address() for Illumos, Darwin, BSD. #if defined(Illumos) || defined(Darwin) || defined(FreeBSD) || defined(OpenBSD) return 0; #endif struct Allocator* alloc = MallocAllocator_new(1<<20); struct EventBase* base = EventBase_new(alloc); struct Writer* logWriter = FileWriter_new(stdout, alloc); struct Log* logger = WriterLog_new(logWriter, alloc); struct Sockaddr* addrA = Sockaddr_fromBytes(testAddrA, Sockaddr_AF_INET, alloc); char assignedIfName[TUNInterface_IFNAMSIZ]; struct Interface* tun = TUNInterface_new(NULL, assignedIfName, base, logger, NULL, alloc); NetDev_addAddress(assignedIfName, addrA, 30, logger, NULL); struct Sockaddr_storage ss; Assert_true(!Sockaddr_parse("0.0.0.0", &ss)); struct AddrInterface* udp = UDPAddrInterface_new(base, &ss.addr, alloc, NULL, logger); struct Sockaddr* dest = Sockaddr_clone(udp->addr, alloc); uint8_t* addr; Assert_true(4 == Sockaddr_getAddress(dest, &addr)); Bits_memcpy(addr, testAddrB, 4); struct Message* msg; Message_STACK(msg, 0, 64); Message_push(msg, "Hello World", 12); Message_push(msg, dest, dest->addrLen); udp->generic.receiveMessage = receiveMessageUDP; udp->generic.receiverContext = alloc; tun->receiveMessage = receiveMessageTUN; udp->generic.sendMessage(msg, &udp->generic); Timeout_setTimeout(fail, NULL, 1000, base, alloc); EventBase_beginLoop(base); }
int main(int argc, char** argv) { struct Allocator* alloc = MallocAllocator_new(1<<20); struct EventBase* base = EventBase_new(alloc); struct Writer* logWriter = FileWriter_new(stdout, alloc); struct Log* logger = WriterLog_new(logWriter, alloc); // mock interface controller. struct InterfaceController ic = { .registerPeer = registerPeer }; struct Sockaddr_storage addr; Assert_always(!Sockaddr_parse("127.0.0.1", &addr)); struct UDPInterface* udpA = UDPInterface_new(base, &addr.addr, alloc, NULL, logger, &ic); struct UDPInterface* udpB = UDPInterface_new(base, &addr.addr, alloc, NULL, logger, &ic); struct Message* msg; Message_STACK(msg, 0, 128); Message_push(msg, "Hello World", 12, NULL); Message_push(msg, udpA->addr, udpA->addr->addrLen, NULL); struct Interface* ifA = &((struct UDPInterface_pvt*) udpA)->udpBase->generic; struct Interface* ifB = &((struct UDPInterface_pvt*) udpB)->udpBase->generic; ifA->receiveMessage = receiveMessageA; ifB->receiveMessage = receiveMessageB; ifB->receiverContext = alloc; struct Allocator* child = Allocator_child(alloc); msg = Message_clone(msg, child); ifB->sendMessage(msg, ifB); Allocator_free(child); Timeout_setTimeout(fail, NULL, 1000, base, alloc); EventBase_beginLoop(base); return 0; }
static void testAddr(struct Context* ctx, char* addr4, int prefix4, int alloc4, char* addr6, int prefix6, int alloc6) { struct Allocator* alloc = Allocator_child(ctx->alloc); struct IpTunnel* ipTun = IpTunnel_new(ctx->log, ctx->base, alloc, ctx->rand, NULL); struct Sockaddr* sa4 = NULL; struct Sockaddr_storage ip6ToGive; struct Sockaddr_storage ip4ToGive; if (addr4) { Assert_true(!Sockaddr_parse(addr4, &ip4ToGive)); sa4 = &ip4ToGive.addr; Assert_true(Sockaddr_getFamily(sa4) == Sockaddr_AF_INET); } struct Sockaddr* sa6 = NULL; if (addr6) { Assert_true(!Sockaddr_parse(addr6, &ip6ToGive)); sa6 = &ip6ToGive.addr; Assert_true(Sockaddr_getFamily(sa6) == Sockaddr_AF_INET6); } IpTunnel_allowConnection(ctx->pubKey, sa6, prefix6, alloc6, sa4, prefix4, alloc4, ipTun); struct Message* msg = Message_new(64, 512, alloc); const char* requestForAddresses = "d" "1:q" "21:IpTunnel_getAddresses" "4:txid" "4:abcd" "e"; CString_strcpy(msg->bytes, requestForAddresses); msg->length = CString_strlen(requestForAddresses); Message_push(msg, NULL, Headers_UDPHeader_SIZE, NULL); struct Headers_UDPHeader* uh = (struct Headers_UDPHeader*) msg->bytes; uh->length_be = Endian_hostToBigEndian16(msg->length - Headers_UDPHeader_SIZE); uint16_t* checksum = &((struct Headers_UDPHeader*) msg->bytes)->checksum_be; *checksum = 0; uint32_t length = msg->length; // Because of old reasons, we need to have at least an empty IPv6 header Message_push(msg, NULL, Headers_IP6Header_SIZE, NULL); struct Headers_IP6Header* ip = (struct Headers_IP6Header*) msg->bytes; Headers_setIpVersion(ip); ip->payloadLength_be = Endian_hostToBigEndian16(msg->length - Headers_IP6Header_SIZE); ip->nextHeader = 17; *checksum = Checksum_udpIp6(ip->sourceAddr, (uint8_t*) uh, length); pushRouteDataHeaders(ctx, msg); struct IfaceContext* nodeIf = Allocator_calloc(alloc, sizeof(struct IfaceContext), 1); nodeIf->ctx = ctx; nodeIf->iface.send = responseWithIpCallback; struct IfaceContext* tunIf = Allocator_calloc(alloc, sizeof(struct IfaceContext), 1); tunIf->ctx = ctx; tunIf->iface.send = messageToTun; Iface_plumb(&nodeIf->iface, &ipTun->nodeInterface); Iface_plumb(&tunIf->iface, &ipTun->tunInterface); ctx->expectedResponse = getExpectedResponse(sa4, prefix4, alloc4, sa6, prefix6, alloc6, alloc); Iface_send(&nodeIf->iface, msg); Assert_true(ctx->called == 2); ctx->called = 0; if (sa4) { uint8_t* addrBytes = NULL; Assert_true(Sockaddr_getAddress(sa4, &addrBytes) == 4); uint32_t addr; Bits_memcpy(&addr, addrBytes, 4); addr = Endian_bigEndianToHost32(addr); // Send from the address specified Assert_true(trySend4(alloc, addr, &nodeIf->iface, ctx)); if (alloc4 < 32) { // Send from another (random) address in the prefix uint32_t flip = Random_uint32(ctx->rand) >> alloc4; if (prefix4 != 32) { Assert_true(trySend4(alloc, addr ^ flip, &nodeIf->iface, ctx)); } else { // If netSize is not specified, we do not allow multi-address Assert_true(!trySend4(alloc, addr ^ flip, &nodeIf->iface, ctx)); } } else {
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); } } }
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; }
/* * This process is started with 2 parameters, they must all be numeric in base 10. * toAngel the pipe which is used to send data back to the angel process. * fromAngel the pipe which is used to read incoming data from the angel. * * Upon initialization, this process will wait for an initial configuration to be sent to * it and then it will send an initial response. */ int Core_main(int argc, char** argv) { struct Except* eh = NULL; if (argc != 3) { Except_raise(eh, -1, "This is internal to cjdns and shouldn't started manually."); } struct Allocator* alloc = MallocAllocator_new(ALLOCATOR_FAILSAFE); struct Log* preLogger = FileWriterLog_new(stderr, alloc); struct EventBase* eventBase = EventBase_new(alloc); // -------------------- Setup the Pre-Logger ---------------------- // struct Log* logger = IndirectLog_new(alloc); IndirectLog_set(logger, preLogger); // -------------------- Setup the PRNG ---------------------- // struct Random* rand = LibuvEntropyProvider_newDefaultRandom(eventBase, logger, eh, alloc); // -------------------- Change Canary Value ---------------------- // MallocAllocator_setCanary(alloc, (long)Random_int64(rand)); struct Allocator* tempAlloc = Allocator_child(alloc); // The first read inside of getInitialConfig() will begin it waiting. struct Pipe* angelPipe = Pipe_named(argv[2], eventBase, eh, alloc); angelPipe->logger = logger; angelPipe->onClose = angelDied; struct Interface* angelIface = FramingInterface_new(65535, &angelPipe->iface, alloc); Dict* config = getInitialConfig(angelIface, eventBase, tempAlloc, eh); struct Hermes* hermes = Hermes_new(angelIface, eventBase, logger, alloc); String* privateKeyHex = Dict_getString(config, String_CONST("privateKey")); Dict* adminConf = Dict_getDict(config, String_CONST("admin")); String* pass = Dict_getString(adminConf, String_CONST("pass")); String* bind = Dict_getString(adminConf, String_CONST("bind")); if (!(pass && privateKeyHex && bind)) { if (!pass) { Except_raise(eh, -1, "Expected 'pass'"); } if (!bind) { Except_raise(eh, -1, "Expected 'bind'"); } if (!privateKeyHex) { Except_raise(eh, -1, "Expected 'privateKey'"); } Except_raise(eh, -1, "Expected 'pass', 'privateKey' and 'bind' in configuration."); } Log_keys(logger, "Starting core with admin password [%s]", pass->bytes); uint8_t privateKey[32]; if (privateKeyHex->len != 64 || Hex_decode(privateKey, 32, (uint8_t*) privateKeyHex->bytes, 64) != 32) { Except_raise(eh, -1, "privateKey must be 64 bytes of hex."); } struct Sockaddr_storage bindAddr; if (Sockaddr_parse(bind->bytes, &bindAddr)) { Except_raise(eh, -1, "bind address [%s] unparsable", bind->bytes); } struct AddrInterface* udpAdmin = UDPAddrInterface_new(eventBase, &bindAddr.addr, alloc, eh, logger); struct Admin* admin = Admin_new(udpAdmin, alloc, logger, eventBase, pass); char* boundAddr = Sockaddr_print(udpAdmin->addr, tempAlloc); Dict adminResponse = Dict_CONST( String_CONST("bind"), String_OBJ(String_CONST(boundAddr)), NULL ); Dict response = Dict_CONST( String_CONST("error"), String_OBJ(String_CONST("none")), Dict_CONST( String_CONST("admin"), Dict_OBJ(&adminResponse), NULL )); // This always times out because the angel doesn't respond. Hermes_callAngel(&response, angelResponse, NULL, alloc, eh, hermes); // --------------------- Setup the Logger --------------------- // Dict* logging = Dict_getDict(config, String_CONST("logging")); String* logTo = Dict_getString(logging, String_CONST("logTo")); if (logTo && String_equals(logTo, String_CONST("stdout"))) { // do nothing, continue logging to stdout. } else { struct Log* adminLogger = AdminLog_registerNew(admin, alloc, rand); IndirectLog_set(logger, adminLogger); logger = adminLogger; } // CryptoAuth struct Address addr; parsePrivateKey(privateKey, &addr, eh); struct CryptoAuth* cryptoAuth = CryptoAuth_new(alloc, privateKey, eventBase, logger, rand); struct Sockaddr* myAddr = Sockaddr_fromBytes(addr.ip6.bytes, Sockaddr_AF_INET6, alloc); struct SwitchCore* switchCore = SwitchCore_new(logger, alloc); struct DHTModuleRegistry* registry = DHTModuleRegistry_new(alloc); ReplyModule_register(registry, alloc); // Router struct RouterModule* router = RouterModule_register(registry, alloc, addr.key, eventBase, logger, admin, rand); SerializationModule_register(registry, logger, alloc); struct IpTunnel* ipTun = IpTunnel_new(logger, eventBase, alloc, rand, hermes); struct Ducttape* dt = Ducttape_register(privateKey, registry, router, switchCore, eventBase, alloc, logger, admin, ipTun, rand); struct SwitchPinger* sp = SwitchPinger_new(&dt->switchPingerIf, eventBase, logger, alloc); // Interfaces. struct InterfaceController* ifController = DefaultInterfaceController_new(cryptoAuth, switchCore, router, logger, eventBase, sp, rand, alloc); // ------------------- Register RPC functions ----------------------- // SwitchPinger_admin_register(sp, admin, alloc); UDPInterface_admin_register(eventBase, alloc, logger, admin, ifController); #ifdef HAS_ETH_INTERFACE ETHInterface_admin_register(eventBase, alloc, logger, admin, ifController); #endif RouterModule_admin_register(router, admin, alloc); AuthorizedPasswords_init(admin, cryptoAuth, alloc); Admin_registerFunction("ping", adminPing, admin, false, NULL, admin); Core_admin_register(myAddr, dt, logger, ipTun, alloc, admin, eventBase); Security_admin_register(alloc, logger, admin); IpTunnel_admin_register(ipTun, admin, alloc); struct Context* ctx = Allocator_clone(alloc, (&(struct Context) { .allocator = alloc, .admin = admin, .logger = logger, .hermes = hermes }));
int main(int argc, char** argv) { if (argc > 1 && !strcmp("--genconf", argv[argc-1])) { genconf(); return 0; } struct Allocator* alloc = MallocAllocator_new(1<<22); struct EventBase* base = EventBase_new(alloc); struct Writer* logWriter = FileWriter_new(stdout, alloc); struct Log* logger = WriterLog_new(logWriter, alloc); struct Random* rand = Random_new(alloc, logger, NULL); struct Reader* stdinReader = FileReader_new(stdin, alloc); Dict config; if (JsonBencSerializer_get()->parseDictionary(stdinReader, alloc, &config)) { Log_critical(logger, "Failed to parse configuration"); return -1; } Dict* dns = Dict_getDict(&config, String_CONST("dns")); if (!dns) { Log_critical(logger, "No DNS in configuration"); return -1; } struct Sockaddr_storage addr; Assert_true(!Sockaddr_parse("::", &addr)); struct AddrInterface* ifaceB = UDPAddrInterface_new(base, &addr.addr, alloc, NULL, logger); struct RainflyClient* client = RainflyClient_new(ifaceB, base, rand, logger); String* bind = Dict_getString(dns, String_CONST("bind")); Assert_true(!Sockaddr_parse(bind ? bind->bytes : "[::]:5353", &addr)); struct AddrInterface* iface = UDPAddrInterface_new(base, &addr.addr, alloc, NULL, logger); struct DNSServer* dnsServer = DNSServer_new(iface, logger, client); List* auth = Dict_getList(dns, String_CONST("authorities")); for (int i = 0; i < (int)List_size(auth); i++) { String* str = List_getString(auth, i); if (!str) { Log_warn(logger, "Element [%d] in [dns.authorities] list of wrong type", i); continue; } uint8_t key[32] = {0}; if (str->len < 52 || Base32_decode(key, 32, str->bytes, 52) != 32) { Log_warn(logger, "Failed to parse key [%s]", str->bytes); continue; } if (RainflyClient_addKey(client, key)) { Log_warn(logger, "Failed to add key to RainflyClient [%s]", str->bytes); } } List* servers = Dict_getList(dns, String_CONST("servers")); for (int i = 0; i < (int)List_size(servers); i++) { String* str = List_getString(servers, i); if (!str) { Log_warn(logger, "Element [%d] in [dns.servers] list of wrong type", i); continue; } struct Sockaddr_storage node; if (Sockaddr_parse(str->bytes, &node)) { Log_warn(logger, "Failed to parse server name [%s]", str->bytes); continue; } if (RainflyClient_addServer(client, &node.addr)) { Log_warn(logger, "Failed to add server to RainflyClient [%s]", str->bytes); } } List* legacy = Dict_getList(dns, String_CONST("legacy")); for (int i = 0; i < (int)List_size(legacy); i++) { String* str = List_getString(legacy, i); if (!str) { Log_warn(logger, "Element [%d] in [dns.legacy] list of wrong type", i); continue; } struct Sockaddr_storage node; if (Sockaddr_parse(str->bytes, &node)) { Log_warn(logger, "Failed to parse legacy server name [%s]", str->bytes); continue; } if (DNSServer_addServer(dnsServer, &node.addr)) { Log_warn(logger, "Failed to add server to DNSServer [%s]", str->bytes); } } EventBase_beginLoop(base); }
int main() { AddressCalc_addressForPublicKey(nodeCjdnsIp6, fakePubKey); struct Allocator* alloc = MallocAllocator_new(1<<20); struct Writer* w = FileWriter_new(stdout, alloc); struct Log* logger = WriterLog_new(w, alloc); struct Random* rand = Random_new(alloc, logger, NULL); struct EventBase* eb = EventBase_new(alloc); struct IpTunnel* ipTun = IpTunnel_new(logger, eb, alloc, rand, NULL); struct Sockaddr_storage ip6ToGive; Sockaddr_parse("fd01:0101:0101:0101:0101:0101:0101:0101", &ip6ToGive); IpTunnel_allowConnection(fakePubKey, &ip6ToGive.addr, NULL, ipTun); struct Message* message; Message_STACK(message, 64, 512); message->alloc = alloc; const char* requestForAddresses = "d" "1:q" "21:IpTunnel_getAddresses" "4:txid" "4:abcd" "e"; CString_strcpy((char*)message->bytes, requestForAddresses); message->length = CString_strlen(requestForAddresses); Message_shift(message, Headers_UDPHeader_SIZE, NULL); struct Headers_UDPHeader* uh = (struct Headers_UDPHeader*) message->bytes; uh->srcPort_be = 0; uh->destPort_be = 0; uh->length_be = Endian_hostToBigEndian16(message->length - Headers_UDPHeader_SIZE); uint16_t* checksum = &uh->checksum_be; *checksum = 0; uint32_t length = message->length; Message_shift(message, Headers_IP6Header_SIZE, NULL); struct Headers_IP6Header* ip = (struct Headers_IP6Header*) message->bytes; ip->versionClassAndFlowLabel = 0; ip->flowLabelLow_be = 0; ip->payloadLength_be = Endian_hostToBigEndian16(length); ip->nextHeader = 17; ip->hopLimit = 255; Bits_memset(ip->sourceAddr, 0, 32); Headers_setIpVersion(ip); Message_shift(message, IpTunnel_PacketInfoHeader_SIZE, NULL); struct IpTunnel_PacketInfoHeader* pi = (struct IpTunnel_PacketInfoHeader*) message->bytes; Bits_memcpyConst(pi->nodeIp6Addr, nodeCjdnsIp6, 16); Bits_memcpyConst(pi->nodeKey, fakePubKey, 32); *checksum = Checksum_udpIp6(ip->sourceAddr, (uint8_t*) uh, length); ipTun->nodeInterface.receiveMessage = responseWithIpCallback; ipTun->nodeInterface.sendMessage(message, &ipTun->nodeInterface); Assert_true(called); called = 0; // Now create a message for someone else. Message_shift(message, Headers_UDPHeader_SIZE + Headers_IP6Header_SIZE + IpTunnel_PacketInfoHeader_SIZE, NULL); Bits_memcpyConst(ip->sourceAddr, fakeIp6ToGive, 16); // This can't be zero. Bits_memset(ip->destinationAddr, 1, 16); ipTun->tunInterface.receiveMessage = messageToTun; ipTun->nodeInterface.sendMessage(message, &ipTun->nodeInterface); Assert_true(called); Allocator_free(alloc); return 0; }
static void beginConnection(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc) { 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* peerName = Dict_getString(args, String_CONST("peerName")); String* error = NULL; Log_debug(ctx->logger, "Peering with [%s]", publicKey->bytes); struct Sockaddr_storage ss; uint8_t pkBytes[32]; int ret; if (interfaceNumber && *interfaceNumber < 0) { error = String_CONST("negative interfaceNumber"); } else if ((ret = Key_parse(publicKey, pkBytes, NULL))) { error = String_CONST(Key_parse_strerror(ret)); } else if (Sockaddr_parse(address->bytes, &ss)) { error = String_CONST("unable to parse ip address and port."); } else if (Sockaddr_getFamily(&ss.addr) != Sockaddr_getFamily(ctx->udpIf->addr)) { error = String_CONST("different address type than this socket is bound to."); } else { struct Sockaddr* addr = &ss.addr; char* addrPtr = NULL; int addrLen = Sockaddr_getAddress(&ss.addr, &addrPtr); Assert_true(addrLen > 0); struct Allocator* tempAlloc = Allocator_child(ctx->alloc); if (Bits_isZero(addrPtr, addrLen)) { // unspec'd address, convert to loopback if (Sockaddr_getFamily(addr) == Sockaddr_AF_INET) { addr = Sockaddr_clone(Sockaddr_LOOPBACK, tempAlloc); } else if (Sockaddr_getFamily(addr) == Sockaddr_AF_INET6) { addr = Sockaddr_clone(Sockaddr_LOOPBACK6, tempAlloc); } else { Assert_failure("Sockaddr which is not AF_INET nor AF_INET6"); } Sockaddr_setPort(addr, Sockaddr_getPort(&ss.addr)); } int ret = InterfaceController_bootstrapPeer( ctx->ic, ifNum, pkBytes, addr, password, peerName, ctx->alloc); Allocator_free(tempAlloc); if (ret) { switch(ret) { case InterfaceController_bootstrapPeer_BAD_IFNUM: error = String_CONST("no such interface for interfaceNumber"); break; case InterfaceController_bootstrapPeer_BAD_KEY: error = String_CONST("invalid cjdns public key."); break; case InterfaceController_bootstrapPeer_OUT_OF_SPACE: error = String_CONST("no more space to register with the switch."); break; default: error = String_CONST("unknown error"); break; } } else { error = String_CONST("none"); } } Dict out = Dict_CONST(String_CONST("error"), String_OBJ(error), NULL); Admin_sendMessage(&out, txid, ctx->admin); }
int main() { AddressCalc_addressForPublicKey(nodeCjdnsIp6, fakePubKey); struct Allocator* alloc = MallocAllocator_new(1<<20); struct Log* logger = FileWriterLog_new(stdout, alloc); struct Random* rand = Random_new(alloc, logger, NULL); struct EventBase* eb = EventBase_new(alloc); struct IpTunnel* ipTun = IpTunnel_new(logger, eb, alloc, rand); struct Sockaddr_storage ip6ToGive; Sockaddr_parse("fd01:0101:0101:0101:0101:0101:0101:0101", &ip6ToGive); IpTunnel_allowConnection(fakePubKey, &ip6ToGive.addr, 0, NULL, 0, ipTun); struct Message* message; Message_STACK(message, 64, 512); message->alloc = alloc; const char* requestForAddresses = "d" "1:q" "21:IpTunnel_getAddresses" "4:txid" "4:abcd" "e"; CString_strcpy((char*)message->bytes, requestForAddresses); message->length = CString_strlen(requestForAddresses); Message_shift(message, Headers_UDPHeader_SIZE, NULL); struct Headers_UDPHeader* uh = (struct Headers_UDPHeader*) message->bytes; uh->srcPort_be = 0; uh->destPort_be = 0; uh->length_be = Endian_hostToBigEndian16(message->length - Headers_UDPHeader_SIZE); uint16_t* checksum = &uh->checksum_be; *checksum = 0; uint32_t length = message->length; Message_shift(message, Headers_IP6Header_SIZE, NULL); struct Headers_IP6Header* ip = (struct Headers_IP6Header*) message->bytes; ip->versionClassAndFlowLabel = 0; ip->flowLabelLow_be = 0; ip->payloadLength_be = Endian_hostToBigEndian16(length); ip->nextHeader = 17; ip->hopLimit = 255; Bits_memset(ip->sourceAddr, 0, 32); Headers_setIpVersion(ip); Message_shift(message, RouteHeader_SIZE + DataHeader_SIZE, NULL); struct RouteHeader* rh = (struct RouteHeader*) message->bytes; struct DataHeader* dh = (struct DataHeader*) &rh[1]; Bits_memset(rh, 0, RouteHeader_SIZE + DataHeader_SIZE); Bits_memcpy(rh->ip6, nodeCjdnsIp6, 16); Bits_memcpy(rh->publicKey, fakePubKey, 32); DataHeader_setContentType(dh, ContentType_IPTUN); *checksum = Checksum_udpIp6(ip->sourceAddr, (uint8_t*) uh, length); int origCap = message->capacity; int origLen = message->length; struct Iface nodeIface = { .send = responseWithIpCallback }; Iface_plumb(&nodeIface, &ipTun->nodeInterface); struct Iface tunIface = { .send = messageToTun }; Iface_plumb(&tunIface, &ipTun->tunInterface); Iface_send(&nodeIface, message); Assert_true(called == 2); called = 0; // This is a hack, reusing the message will cause breakage if IpTunnel is refactored. Message_reset(message); Message_shift(message, origCap, NULL); message->length = origLen; Bits_memcpy(ip->sourceAddr, fakeIp6ToGive, 16); // This can't be zero. Bits_memset(ip->destinationAddr, 1, 16); Iface_send(&nodeIface, message); Assert_true(called == 1); Allocator_free(alloc); return 0; }
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); } } }
/** @return a string representing the address and port to connect to. */ static void 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 " "d" "5:error" "4:none" "e"; char* start = strchr(coreToAngelResponse, 'd'); 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); return; } /** * 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, logger, 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); Log_info(logger, "Initializing Angel"); struct PipeInterface* pi; initAngel(fromAngel, toAngel, corePipes, &pi, eventBase, logger, alloc, rand); struct Sockaddr_storage addr; Assert_true(!Sockaddr_parse("0.0.0.0", &addr)); Log_info(logger, "Binding UDP admin socket"); struct AddrInterface* udpAdmin = UDPAddrInterface_new(eventBase, &addr.addr, alloc, NULL, logger); String* password = String_new("abcd", alloc); struct Admin* admin = Admin_new(udpAdmin, alloc, logger, eventBase, password); // Now setup the client. struct AdminClient* client = AdminClient_new(udpAdmin->addr, password, eventBase, logger, alloc); Assert_always(client); return Allocator_clone(alloc, (&(struct AdminTestFramework) { .admin = admin, .client = client, .alloc = alloc, .eventBase = eventBase, .logger = logger, .addr = Sockaddr_clone(udpAdmin->addr, alloc), .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* 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); } } }
static struct Sockaddr* mkSockaddr(char* str, struct Allocator* alloc) { struct Sockaddr_storage ss; Assert_true(!Sockaddr_parse(str, &ss)); return Sockaddr_clone(&ss.addr, alloc); }
int main(int argc, char** argv) { Assert_ifParanoid(argc > 0); struct Allocator* allocator = MallocAllocator_new(1<<23); if (argc != 6 || (argc == 2 && (!(CString_strcmp(argv[1], "--help") == 0) || (CString_strcmp(argv[1], "-h") == 0)))) { return usage(allocator, argv[0]); } struct Except* eh = NULL; struct EventBase* eventBase = EventBase_new(allocator); struct Log* logger = FileWriterLog_new(stdout, allocator); String* privateKey = String_new(argv[3], allocator); String* adminBind = String_new(argv[4], allocator); String* adminPass = String_new(argv[5], allocator); String* logTo = String_new("stdout", allocator); // --------------------- Welcome to cjdns ---------------------- // char* sysInfo = SysInfo_describe(SysInfo_detect(), allocator); Log_info(logger, "Cjdns %s %s", ArchInfo_getArchStr(), sysInfo); // --------------------- Setup Pipes to Angel --------------------- // struct Allocator* corePipeAlloc = Allocator_child(allocator); String* corePipeDir = String_new(argv[1], allocator); String* corePipeName = String_new(argv[2], allocator); if (!Defined(win32) && access(corePipeDir->bytes, W_OK)) { Except_throw(eh, "Don't have write permission to [%s].", corePipeDir->bytes); } Assert_ifParanoid(EventBase_eventCount(eventBase) == 0); struct Pipe* corePipe = Pipe_named(corePipeDir->bytes, corePipeName->bytes, eventBase, eh, corePipeAlloc); Assert_ifParanoid(EventBase_eventCount(eventBase) == 2); corePipe->logger = logger; // --------------------- Pre-Configure Core ------------------------- // Dict* preConf = Dict_new(allocator); Dict* adminPreConf = Dict_new(allocator); Dict* logPreConf = Dict_new(allocator); Dict_putDict(preConf, String_CONST("admin"), adminPreConf, allocator); Dict_putDict(preConf, String_CONST("logging"), logPreConf, 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); Dict_putString(logPreConf, String_CONST("logTo"), logTo, allocator); struct Message* toCoreMsg = Message_new(0, 1024, allocator); BencMessageWriter_write(preConf, toCoreMsg, eh); Iface_CALL(corePipe->iface.send, toCoreMsg, &corePipe->iface); Log_debug(logger, "Sent [%d] bytes to core.", toCoreMsg->length); // --------------------- Get Response from Core --------------------- // struct Message* fromCoreMsg = InterfaceWaiter_waitForData(&corePipe->iface, eventBase, allocator, eh); Dict* responseFromCore = BencMessageReader_read(fromCoreMsg, allocator, eh); // --------------------- Close the Core Pipe --------------------- // Allocator_free(corePipeAlloc); corePipe = NULL; // --------------------- Get Admin Addr/Port/Passwd --------------------- // Dict* responseFromCoreAdmin = Dict_getDict(responseFromCore, String_CONST("admin")); adminBind = Dict_getString(responseFromCoreAdmin, String_CONST("bind")); if (!adminBind) { Except_throw(eh, "Didn't get ADMIN_BIND back from cjdroute."); } struct Sockaddr_storage adminAddr; if (Sockaddr_parse(adminBind->bytes, &adminAddr)) { Except_throw(eh, "Unable to parse [%s] as an IP address:port.", adminBind->bytes); } Assert_ifParanoid(EventBase_eventCount(eventBase) == 0); Log_info(logger, "Admin API ready at [%s].", adminBind->bytes); return 0; }