Beispiel #1
0
static void tunInterface(Dict* ifaceConf, struct Allocator* tempAlloc, struct Context* ctx)
{
    String* ifaceType = Dict_getString(ifaceConf, String_CONST("type"));
    if (!String_equals(ifaceType, String_CONST("TUNInterface"))) {
        return;
    }

    // Setup the interface.
    String* tunfd = Dict_getString(ifaceConf, String_CONST("tunfd"));
    String* device = Dict_getString(ifaceConf, String_CONST("tunDevice"));

    Dict* args = Dict_new(tempAlloc);
    if (tunfd && device) {
        Dict_putString(args, String_CONST("path"), device, tempAlloc);
        Dict_putString(args, String_CONST("type"),
                       String_new(tunfd->bytes, tempAlloc), tempAlloc);
        Dict* res = NULL;
        rpcCall0(String_CONST("FileNo_import"), args, ctx, tempAlloc, &res, false);
        if (res) {
            Dict* args = Dict_new(tempAlloc);
            int64_t* tunfd = Dict_getInt(res, String_CONST("tunfd"));
            int64_t* type = Dict_getInt(res, String_CONST("type"));
            Dict_putInt(args, String_CONST("tunfd"), *tunfd, tempAlloc);
            Dict_putInt(args, String_CONST("type"), *type, tempAlloc);
            rpcCall0(String_CONST("Core_initTunfd"), args, ctx, tempAlloc, NULL, false);
        }
    } else {
        if (device) {
            Dict_putString(args, String_CONST("desiredTunName"), device, tempAlloc);
        }
        rpcCall0(String_CONST("Core_initTunnel"), args, ctx, tempAlloc, NULL, false);
    }
}
Beispiel #2
0
static void initTunfd(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc)
{
    struct Context* ctx = Identity_check((struct Context*) vcontext);
    struct Jmp jmp;
    Jmp_try(jmp) {
        int64_t* tunfd = Dict_getInt(args, String_CONST("tunfd"));
        int64_t* tuntype = Dict_getInt(args, String_CONST("type"));
        if (!tunfd || *tunfd < 0) {
            String* error = String_printf(requestAlloc, "Invalid tunfd");
            sendResponse(error, ctx->admin, txid, requestAlloc);
            return;
        }
        int fileno = *tunfd;
        int type = (*tuntype) ? *tuntype : FileNo_Type_NORMAL;
        struct Pipe* p = Pipe_forFiles(fileno, fileno, ctx->base, &jmp.handler, ctx->alloc);
        p->logger = ctx->logger;
        if (type == FileNo_Type_ANDROID) {
            struct AndroidWrapper* aw = AndroidWrapper_new(ctx->alloc, ctx->logger);
            Iface_plumb(&aw->externalIf, &p->iface);
            Iface_plumb(&aw->internalIf, &ctx->nc->tunAdapt->tunIf);
        } else {
            Iface_plumb(&p->iface, &ctx->nc->tunAdapt->tunIf);
        }
        sendResponse(String_CONST("none"), ctx->admin, txid, requestAlloc);
    } Jmp_catch {
        String* error = String_printf(requestAlloc, "Failed to configure tunnel [%s]", jmp.message);
        sendResponse(error, ctx->admin, txid, requestAlloc);
        return;
    }
}
Beispiel #3
0
static void adminPing(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc)
{
    struct Context* context = vcontext;
    String* pathStr = Dict_getString(args, String_CONST("path"));
    int64_t* timeoutPtr = Dict_getInt(args, String_CONST("timeout"));
    String* data = Dict_getString(args, String_CONST("data"));
    int64_t* keyPing = Dict_getInt(args, String_CONST("keyPing"));
    uint32_t timeout = (timeoutPtr) ? *timeoutPtr : DEFAULT_TIMEOUT;
    uint64_t path;
    String* err = NULL;
    if (pathStr->len != 19 || AddrTools_parsePath(&path, (uint8_t*) pathStr->bytes)) {
        err = String_CONST("path was not parsable.");
    } else {
        struct SwitchPinger_Ping* ping = SwitchPinger_newPing(path,
                                                              data,
                                                              timeout,
                                                              adminPingOnResponse,
                                                              context->alloc,
                                                              context->switchPinger);
        if (keyPing && *keyPing) { ping->keyPing = true; }
        if (!ping) {
            err = String_CONST("no open slots to store ping, try later.");
        } else {
            ping->onResponseContext = Allocator_clone(ping->pingAlloc, (&(struct Ping) {
                .context = context,
                .txid = String_clone(txid, ping->pingAlloc),
                .path = String_clone(pathStr, ping->pingAlloc)
            }));
        }
    }
Beispiel #4
0
struct EncodingScheme* EncodingScheme_fromList(List* scheme, struct Allocator* alloc)
{
    struct EncodingScheme* list = Allocator_malloc(alloc, sizeof(struct EncodingScheme));
    list->count = List_size(scheme);
    list->forms = Allocator_malloc(alloc, sizeof(struct EncodingScheme_Form) * list->count);
    for (int i = 0; i < (int)list->count; i++) {
        Dict* form = List_getDict(scheme, i);
        uint64_t* prefixLen = Dict_getInt(form, String_CONST("prefixLen"));
        uint64_t* bitCount = Dict_getInt(form, String_CONST("bitCount"));
        String* prefixStr = Dict_getString(form, String_CONST("prefix"));
        if (!prefixLen || !bitCount || !prefixStr || prefixStr->len != 8) {
            return NULL;
        }
        uint32_t prefix_be;
        if (Hex_decode((uint8_t*)&prefix_be, 4, prefixStr->bytes, 8) != 4) {
            return NULL;
        }
        list->forms[i].prefixLen = *prefixLen;
        list->forms[i].bitCount = *bitCount;
        list->forms[i].prefix = Endian_bigEndianToHost32(prefix_be);
    }
    if (!EncodingScheme_isSane(list)) {
        return NULL;
    }
    return list;
}
Beispiel #5
0
static bool checkArgs(Dict* args, struct Function* func, String* txid, struct Admin* admin)
{
    struct Dict_Entry* entry = *func->args;
    String* error = NULL;
    uint8_t buffer[1024];
    struct Allocator* alloc = BufferAllocator_new(buffer, 1024);
    while (entry != NULL) {
        String* key = (String*) entry->key;
        Assert_true(entry->val->type == Object_DICT);
        Dict* value = entry->val->as.dictionary;
        entry = entry->next;
        if (*Dict_getInt(value, String_CONST("required")) == 0) {
            continue;
        }
        String* type = Dict_getString(value, String_CONST("type"));
        if ((type == STRING && !Dict_getString(args, key))
            || (type == DICT && !Dict_getDict(args, key))
            || (type == INTEGER && !Dict_getInt(args, key))
            || (type == LIST && !Dict_getList(args, key)))
        {
            error = String_printf(alloc,
                                  "Entry [%s] is required and must be of type [%s]",
                                  key->bytes,
                                  type->bytes);
            break;
        }
    }
    if (error) {
        Dict d = Dict_CONST(String_CONST("error"), String_OBJ(error), NULL);
        Admin_sendMessage(&d, txid, admin);
    }
    return !error;
}
static void allowConnection(Dict* args,
                            void* vcontext,
                            String* txid,
                            struct Allocator* requestAlloc)
{
    struct Context* context = (struct Context*) vcontext;
    String* publicKeyOfAuthorizedNode =
        Dict_getString(args, String_CONST("publicKeyOfAuthorizedNode"));
    String* ip6Address = Dict_getString(args, String_CONST("ip6Address"));
    int64_t* ip6Prefix = Dict_getInt(args, String_CONST("ip6Prefix"));
    String* ip4Address = Dict_getString(args, String_CONST("ip4Address"));
    int64_t* ip4Prefix = Dict_getInt(args, String_CONST("ip4Prefix"));
    uint8_t pubKey[32];
    uint8_t ip6Addr[16];

    struct Sockaddr_storage ip6ToGive;
    struct Sockaddr_storage ip4ToGive;

    char* error;
    int ret;
    if (!ip6Address && !ip4Address) {
        error = "Must specify ip6Address or ip4Address";
    } else if ((ret = Key_parse(publicKeyOfAuthorizedNode, pubKey, ip6Addr)) != 0) {
        error = Key_parse_strerror(ret);
    } else if (ip6Prefix && !ip6Address) {
        error = "Must specify ip6Address with ip6Prefix";
    } else if (ip6Prefix && (*ip6Prefix > 128 || *ip6Prefix < 0)) {
        error = "ip6Prefix out of range: must be 0 to 128";
    } else if (ip4Prefix && (*ip4Prefix > 32 || *ip4Prefix < 0)) {
        error = "ip4Prefix out of range: must be 0 to 32";
    } else if (ip4Prefix && !ip4Address) {
        error = "Must specify ip4Address with ip4Prefix";
    } else if (ip6Address
        && (Sockaddr_parse(ip6Address->bytes, &ip6ToGive)
            || Sockaddr_getFamily(&ip6ToGive.addr) != Sockaddr_AF_INET6))
    {
        error = "malformed ip6Address";
    } else if (ip4Address
        && (Sockaddr_parse(ip4Address->bytes, &ip4ToGive)
            || Sockaddr_getFamily(&ip4ToGive.addr) != Sockaddr_AF_INET))
    {
        error = "malformed ip4Address";
    } else {
        int conn = IpTunnel_allowConnection(pubKey,
                                            (ip6Address) ? &ip6ToGive.addr : NULL,
                                            (ip6Prefix) ? (uint8_t) (*ip6Prefix) : 0,
                                            (ip4Address) ? &ip4ToGive.addr : NULL,
                                            (ip4Prefix) ? (uint8_t) (*ip4Prefix) : 0,
                                            context->ipTun);
        sendResponse(conn, txid, context->admin);
        return;
    }

    sendError(error, txid, context->admin);
}
Beispiel #7
0
static void authorizedPasswords(List* list, struct Context* ctx)
{
    uint32_t count = List_size(list);
    for (uint32_t i = 0; i < count; i++) {
        Dict* d = List_getDict(list, i);
        if (!d) {
            fprintf(stderr, "authorizedPasswords[%u] is not a dictionary type.\n", i);
            exit(-1);
        }
        String* passwd = Dict_getString(d, BSTR("password"));
        int64_t* authType = Dict_getInt(d, BSTR("authType"));
        int64_t* trust = Dict_getInt(d, BSTR("trust"));
        authorizedPassword(passwd, authType, trust, i, ctx);
    }
}
Beispiel #8
0
static void dns(Dict* dns, struct Context* ctx, struct Except* eh)
{
    List* servers = Dict_getList(dns, String_CONST("servers"));
    int count = List_size(servers);
    for (int i = 0; i < count; i++) {
        String* server = List_getString(servers, i);
        if (!server) {
            Except_throw(eh, "dns.servers[%d] is not a string", i);
        }
        Dict* d = Dict_new(ctx->alloc);
        Dict_putString(d, String_CONST("addr"), server, ctx->alloc);
        rpcCall(String_CONST("RainflyClient_addServer"), d, ctx, ctx->alloc);
    }

    List* keys = Dict_getList(dns, String_CONST("keys"));
    count = List_size(keys);
    for (int i = 0; i < count; i++) {
        String* key = List_getString(keys, i);
        if (!key) {
            Except_throw(eh, "dns.keys[%d] is not a string", i);
        }
        Dict* d = Dict_new(ctx->alloc);
        Dict_putString(d, String_CONST("ident"), key, ctx->alloc);
        rpcCall(String_CONST("RainflyClient_addKey"), d, ctx, ctx->alloc);
    }

    int64_t* minSigs = Dict_getInt(dns, String_CONST("minSignatures"));
    if (minSigs) {
        Dict* d = Dict_new(ctx->alloc);
        Dict_putInt(d, String_CONST("count"), *minSigs, ctx->alloc);
        rpcCall(String_CONST("RainflyClient_minSignatures"), d, ctx, ctx->alloc);
    }
}
Beispiel #9
0
static void add(Dict* args, void* vcontext, String* txid)
{
    struct Context* context = (struct Context*) vcontext;

    String* passwd = Dict_getString(args, String_CONST("password"));
    int64_t* authType = Dict_getInt(args, String_CONST("authType"));
    int64_t one = 1;
    if (!authType) {
        authType = &one;
    } else if (*authType < 1 || *authType > 255) {
        sendResponse(String_CONST("Specified auth type is not supported."), context->admin, txid);
        return;
    }

    int32_t ret = CryptoAuth_addUser(passwd, *authType, context, context->ca);

    switch (ret) {
        case 0:
            sendResponse(String_CONST("none"), context->admin, txid);
            break;
        case CryptoAuth_addUser_INVALID_AUTHTYPE:
            sendResponse(String_CONST("Specified auth type is not supported."),
                         context->admin, txid);
            break;
        case CryptoAuth_addUser_OUT_OF_SPACE:
            sendResponse(String_CONST("Out of memory to store password."), context->admin, txid);
            break;
        case CryptoAuth_addUser_DUPLICATE:
            sendResponse(String_CONST("Password already added."), context->admin, txid);
            break;
        default:
            sendResponse(String_CONST("Unknown error."), context->admin, txid);
    }
}
Beispiel #10
0
static void dumpRumorMill(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc)
{
    struct Context* ctx = Identity_check((struct Context*) vcontext);

    Dict* out = Dict_new(requestAlloc);
    struct RumorMill* rm = getRumorMill(ctx, Dict_getString(args, String_CONST("mill")));
    if (!rm) {
        Dict_putString(out,
                       String_CONST("error"),
                       String_CONST("mill must be one of "
                                    "[externalMill,linkMill,nodeMill,dhtMill,splitMill]"),
                       requestAlloc);
        Admin_sendMessage(out, txid, ctx->admin);
        return;
    }

    int64_t* page = Dict_getInt(args, String_CONST("page"));
    int ctr = (page) ? *page * ENTRIES_PER_PAGE : 0;

    List* table = List_new(requestAlloc);
    for (int i = 0; i < ENTRIES_PER_PAGE && ctr < rm->count; i++) {
        String* addr = Address_toString(&rm->addresses[ctr++], requestAlloc);
        List_addString(table, addr, requestAlloc);
    }
    Dict_putList(out, String_CONST("addresses"), table, requestAlloc);
    Dict_putInt(out, String_CONST("total"), rm->count, requestAlloc);
    Admin_sendMessage(out, txid, ctx->admin);
}
Beispiel #11
0
static void getHandles(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc)
{
    struct Context* context = Identity_check((struct Context*) vcontext);
    struct Allocator* alloc = Allocator_child(context->alloc);

    int64_t* page = Dict_getInt(args, String_CONST("page"));
    int i = (page) ? *page * ENTRIES_PER_PAGE : 0;
    struct SessionManager_HandleList* hList = SessionManager_getHandleList(context->sm, alloc);

    List* list = List_new(alloc);
    for (int counter = 0; i < hList->length && counter++ < ENTRIES_PER_PAGE; i++) {
        List_addInt(list, hList->handles[i], alloc);
    }

    Dict* r = Dict_new(alloc);
    Dict_putList(r, String_CONST("handles"), list, alloc);
    Dict_putInt(r, String_CONST("total"), hList->length, alloc);

    String* more = String_CONST("more");
    if (i < hList->length) {
        Dict_putInt(r, more, 1, alloc);
    }

    Admin_sendMessage(r, txid, context->admin);

    Allocator_free(alloc);
}
static void setUser(Dict* args, void* vctx, String* txid, struct Allocator* requestAlloc)
{
    struct Context* const ctx = Identity_check((struct Context*) vctx);
    struct Jmp jmp;
    Jmp_try(jmp) {
        int64_t* user = Dict_getInt(args, String_CONST("uid"));
        int64_t* group = Dict_getInt(args, String_CONST("gid"));
        int gid = group ? (int)*group : 0;
        int64_t* keepNetAdmin = Dict_getInt(args, String_CONST("keepNetAdmin"));
        Security_setUser(*user, gid, *keepNetAdmin, ctx->logger, &jmp.handler, requestAlloc);
    } Jmp_catch {
        sendError(jmp.message, txid, ctx->admin);
        return;
    }
    sendError("none", txid, ctx->admin);
}
Beispiel #13
0
static inline bool authValid(Dict* message, uint8_t* buffer, uint32_t length, struct Admin* admin)
{
    String* cookieStr = Dict_getString(message, String_CONST("cookie"));
    uint32_t cookie = (cookieStr != NULL) ? strtoll(cookieStr->bytes, NULL, 10) : 0;
    if (!cookie) {
        int64_t* cookieInt = Dict_getInt(message, String_CONST("cookie"));
        cookie = (cookieInt) ? *cookieInt : 0;
    }
    uint64_t nowSecs = Time_currentTimeSeconds(admin->eventBase);
    String* submittedHash = Dict_getString(message, String_CONST("hash"));
    if (cookie >  nowSecs || cookie < nowSecs - 20 || !submittedHash || submittedHash->len != 64) {
        return false;
    }

    uint8_t* hashPtr = (uint8_t*) strstr((char*) buffer, submittedHash->bytes);

    if (!hashPtr || !admin->password) {
        return false;
    }

    uint8_t passAndCookie[64];
    snprintf((char*) passAndCookie, 64, "%s%u", admin->password->bytes, cookie);
    uint8_t hash[32];
    crypto_hash_sha256(hash, passAndCookie, strlen((char*) passAndCookie));
    Hex_encode(hashPtr, 64, hash, 32);

    crypto_hash_sha256(hash, buffer, length);
    Hex_encode(hashPtr, 64, hash, 32);
    return memcmp(hashPtr, submittedHash->bytes, 64) == 0;
}
Beispiel #14
0
static void standardClientCallback(struct AdminClient_Promise* p, struct AdminClient_Result* res)
{
    struct Context* ctx = p->userData;
    //printf("%d\n", res->err);
    Assert_always(!res->err);
    Assert_always(Dict_getInt(res->responseDict, String_CONST("called!")));
    Assert_always(ctx->called);

    EventBase_endLoop(ctx->framework->eventBase);
}
Beispiel #15
0
static void adminPeerStats(Dict* args, void* vcontext, String* txid)
{
    struct Context* context = vcontext;
    struct Allocator* alloc = Allocator_child(context->alloc);
    struct InterfaceController_peerStats* stats = NULL;

    int64_t* page = Dict_getInt(args, String_CONST("page"));
    int i = (page) ? *page * ENTRIES_PER_PAGE : 0;

    int count = context->ic->getPeerStats(context->ic, alloc, &stats);

    String* bytesIn = String_CONST("bytesIn");
    String* bytesOut = String_CONST("bytesOut");
    String* pubKey = String_CONST("publicKey");
    String* state = String_CONST("state");
    String* last = String_CONST("last");
    String* switchLabel = String_CONST("switchLabel");
    String* isIncoming = String_CONST("isIncoming");

    List* list = NULL;
    for (int counter=0; i < count && counter++ < ENTRIES_PER_PAGE; i++) {
        Dict* d = Dict_new(alloc);
        Dict_putInt(d, bytesIn, stats[i].bytesIn, alloc);
        Dict_putInt(d, bytesOut, stats[i].bytesOut, alloc);
        Dict_putString(d, pubKey, Key_stringify(stats[i].pubKey, alloc), alloc);

        String* stateString = String_new(InterfaceController_stateString(stats[i].state), alloc);
        Dict_putString(d, state, stateString, alloc);

        Dict_putInt(d, last, stats[i].timeOfLastMessage, alloc);

        uint8_t labelStack[20];
        AddrTools_printPath(labelStack, stats[i].switchLabel);
        Dict_putString(d, switchLabel, String_new((char*)labelStack, alloc), alloc);

        Dict_putInt(d, isIncoming, stats[i].isIncomingConnection, alloc);

        list = List_addDict(list, d, alloc);
    }

    Dict response = Dict_CONST(
        String_CONST("peers"), List_OBJ(list), Dict_CONST(
        String_CONST("total"), Int_OBJ(count), NULL
    ));

    if (i < count) {
      response = Dict_CONST(
        String_CONST("more"), Int_OBJ(1), response
      );
    }

    Admin_sendMessage(&response, txid, context->admin);

    Allocator_free(alloc);
}
Beispiel #16
0
static void removeConnection(Dict* args, void* vcontext, String* txid)
{
    struct Context* context = vcontext;

    int conn = (int) *(Dict_getInt(args, String_CONST("connection")));
    char* error = "none";
    if (IpTunnel_removeConnection_NOT_FOUND == IpTunnel_removeConnection(conn, context->ipTun)) {
        error = "not found";
    }
    sendError(error, txid, context->admin);
}
Beispiel #17
0
static void dumpTable(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc)
{
    struct Context* ctx = Identity_check((struct Context*) vcontext);
    int64_t* page = Dict_getInt(args, String_CONST("page"));
    int ctr = (page) ? *page * ENTRIES_PER_PAGE : 0;

    Dict* out = Dict_new(requestAlloc);
    List* table = List_new(requestAlloc);
    struct Node_Two* nn = NULL;
    for (int i = 0; i < ctr+ENTRIES_PER_PAGE; i++) {
        nn = NodeStore_getNextNode(ctx->store, nn);
        if (!nn) { break; }
        if (i < ctr) { continue; }
        Dict* nodeDict = Dict_new(requestAlloc);

        String* ip = String_newBinary(NULL, 39, requestAlloc);
        Address_printIp(ip->bytes, &nn->address);
        Dict_putString(nodeDict, String_CONST("ip"), ip, requestAlloc);

        String* addr = Address_toString(&nn->address, requestAlloc);
        Dict_putString(nodeDict, String_CONST("addr"), addr, requestAlloc);

        String* path = String_newBinary(NULL, 19, requestAlloc);
        AddrTools_printPath(path->bytes, nn->address.path);
        Dict_putString(nodeDict, String_CONST("path"), path, requestAlloc);

        Dict_putInt(nodeDict, String_CONST("link"), Node_getCost(nn), requestAlloc);
        Dict_putInt(nodeDict, String_CONST("version"), nn->address.protocolVersion, requestAlloc);

        Dict_putInt(nodeDict,
                    String_CONST("time"),
                    NodeStore_timeSinceLastPing(ctx->store, nn),
                    requestAlloc);

        Dict_putInt(nodeDict,
                    String_CONST("bucket"),
                    NodeStore_bucketForAddr(ctx->store->selfAddress, &nn->address),
                    requestAlloc);

        List_addDict(table, nodeDict, requestAlloc);
    }
    Dict_putList(out, String_CONST("routingTable"), table, requestAlloc);

    if (nn) {
        Dict_putInt(out, String_CONST("more"), 1, requestAlloc);
    }
    Dict_putInt(out, String_CONST("count"), ctx->store->nodeCount, requestAlloc);
    Dict_putInt(out, String_CONST("peers"), ctx->store->peerCount, requestAlloc);

    Dict_putString(out, String_CONST("deprecation"),
        String_CONST("ip,path,version will soon be removed"), requestAlloc);

    Admin_sendMessage(out, txid, ctx->admin);
}
Beispiel #18
0
static void beginConnection(Dict* args, void* vcontext, String* txid)
{
    struct Context* ctx = vcontext;

    String* password = Dict_getString(args, String_CONST("password"));
    String* publicKey = Dict_getString(args, String_CONST("publicKey"));
    String* address = Dict_getString(args, String_CONST("address"));
    int64_t* interfaceNumber = Dict_getInt(args, String_CONST("interfaceNumber"));
    uint32_t ifNum = (interfaceNumber) ? ((uint32_t) *interfaceNumber) : 0;
    String* error = NULL;

    uint8_t pkBytes[32];

    if (ctx->ifCount == 0) {
        error = String_CONST("no interfaces are setup, call UDPInterface_new() first");

    } else if (interfaceNumber && (*interfaceNumber >= ctx->ifCount || *interfaceNumber < 0)) {
        error = String_CONST("invalid interfaceNumber");

    } else if (!publicKey
        || publicKey->len < 52
        || (publicKey->len > 52 && publicKey->bytes[52] != '.'))
    {
        error = String_CONST("publicKey must be 52 characters long.");

    } else if (Base32_decode(pkBytes, 32, (uint8_t*)publicKey->bytes, 52) != 32) {
        error = String_CONST("failed to parse publicKey.");

    } else {
        struct UDPInterface* udpif = ctx->ifaces[ifNum];
        switch (UDPInterface_beginConnection(address->bytes, pkBytes, password, udpif)) {
            case UDPInterface_beginConnection_OUT_OF_SPACE:
                error = String_CONST("no more space to register with the switch.");
                break;
            case UDPInterface_beginConnection_BAD_KEY:
                error = String_CONST("invalid cjdns public key.");
                break;
            case UDPInterface_beginConnection_BAD_ADDRESS:
                error = String_CONST("unable to parse ip address and port.");
                break;
            case UDPInterface_beginConnection_ADDRESS_MISMATCH:
                error = String_CONST("different address type than this socket is bound to.");
                break;
            case 0:
                error = String_CONST("none");
                break;
            default:
                error = String_CONST("unknown error");
        }
    }

    Dict out = Dict_CONST(String_CONST("error"), String_OBJ(error), NULL);
    Admin_sendMessage(&out, txid, ctx->admin);
}
Beispiel #19
0
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);
}
Beispiel #20
0
static void sessionStats(Dict* args,
                         void* vcontext,
                         String* txid,
                         struct Allocator* alloc)
{
    struct Context* context = Identity_check((struct Context*) vcontext);
    int64_t* handleP = Dict_getInt(args, String_CONST("handle"));
    uint32_t handle = *handleP;

    struct SessionManager_Session* session = SessionManager_sessionForHandle(handle, context->sm);

    Dict* r = Dict_new(alloc);
    if (!session) {
        Dict_putString(r, String_CONST("error"), String_CONST("no such session"), alloc);
        Admin_sendMessage(r, txid, context->admin);
        return;
    }

    uint8_t printedAddr[40];
    AddrTools_printIp(printedAddr, session->caSession->herIp6);
    Dict_putString(r, String_CONST("ip6"), String_new(printedAddr, alloc), alloc);

    String* state =
        String_new(CryptoAuth_stateString(CryptoAuth_getState(session->caSession)), alloc);
    Dict_putString(r, String_CONST("state"), state, alloc);

    struct ReplayProtector* rp = &session->caSession->replayProtector;
    Dict_putInt(r, String_CONST("duplicates"), rp->duplicates, alloc);
    Dict_putInt(r, String_CONST("lostPackets"), rp->lostPackets, alloc);
    Dict_putInt(r, String_CONST("receivedOutOfRange"), rp->receivedOutOfRange, alloc);

    struct Address addr;
    Bits_memcpyConst(addr.key, session->caSession->herPublicKey, 32);
    addr.path = session->sendSwitchLabel;
    addr.protocolVersion = session->version;

    Dict_putString(r, String_CONST("addr"), Address_toString(&addr, alloc), alloc);

    Dict_putString(r, String_CONST("publicKey"),
                      Key_stringify(session->caSession->herPublicKey, alloc), alloc);
    Dict_putInt(r, String_CONST("version"), session->version, alloc);
    Dict_putInt(r, String_CONST("handle"), session->receiveHandle, alloc);
    Dict_putInt(r, String_CONST("sendHandle"), session->sendHandle, alloc);

    Dict_putInt(r, String_CONST("timeOfLastIn"), session->timeOfLastIn, alloc);
    Dict_putInt(r, String_CONST("timeOfLastOut"), session->timeOfLastOut, alloc);

    Dict_putString(r, String_CONST("deprecation"),
        String_CONST("publicKey,version will soon be removed"), alloc);

    Admin_sendMessage(r, txid, context->admin);
    return;
}
Beispiel #21
0
static void showConnection(Dict* args, void* vcontext, String* txid)
{
    struct Context* context = vcontext;
    int connNum = (int) *(Dict_getInt(args, String_CONST("connection")));

    for (int i = 0; i < (int)context->ipTun->connectionList.count; i++) {
        if (connNum == context->ipTun->connectionList.connections[i].number) {
            showConn(&context->ipTun->connectionList.connections[i], txid, context->admin);
            return;
        }
    }
    sendError("connection not found", txid, context->admin);
}
Beispiel #22
0
static void sessionStats(Dict* args,
                         void* vcontext,
                         String* txid,
                         struct Allocator* alloc)
{
    struct Context* context = vcontext;
    int64_t* handleP = Dict_getInt(args, String_CONST("handle"));
    uint32_t handle = *handleP;

    struct SessionManager_Session* session = SessionManager_sessionForHandle(handle, context->sm);
    uint8_t* ip6 = SessionManager_getIp6(handle, context->sm);

    Dict* r = Dict_new(alloc);
    if (!session) {
        Dict_putString(r, String_CONST("error"), String_CONST("no such session"), alloc);
        Admin_sendMessage(r, txid, context->admin);
        return;
    }
    // both or neither
    Assert_true(ip6);

    uint8_t printedAddr[40];
    AddrTools_printIp(printedAddr, ip6);
    Dict_putString(r, String_CONST("ip6"), String_new(printedAddr, alloc), alloc);

    Dict_putString(r,
                   String_CONST("state"),
                   String_new(CryptoAuth_stateString(session->cryptoAuthState), alloc),
                   alloc);

    struct ReplayProtector* rp = CryptoAuth_getReplayProtector(session->internal);
    Dict_putInt(r, String_CONST("duplicates"), rp->duplicates, alloc);
    Dict_putInt(r, String_CONST("lostPackets"), rp->lostPackets, alloc);
    Dict_putInt(r, String_CONST("receivedOutOfRange"), rp->receivedOutOfRange, alloc);

    uint8_t* key = CryptoAuth_getHerPublicKey(session->internal);
    Dict_putString(r, String_CONST("publicKey"), Key_stringify(key, alloc), alloc);
    Dict_putInt(r, String_CONST("version"), session->version, alloc);
    Dict_putInt(r, String_CONST("handle"),
                Endian_bigEndianToHost32(session->receiveHandle_be), alloc);
    Dict_putInt(r, String_CONST("sendHandle"),
                Endian_bigEndianToHost32(session->sendHandle_be), alloc);

    Dict_putInt(r, String_CONST("timeOfLastIn"), session->timeOfLastIn, alloc);
    Dict_putInt(r, String_CONST("timeOfLastOut"), session->timeOfLastOut, alloc);

    Admin_sendMessage(r, txid, context->admin);
    return;
}
Beispiel #23
0
static void ethInterfaceSetBeacon(int ifNum, Dict* eth, struct Context* ctx)
{
    int64_t* beaconP = Dict_getInt(eth, String_CONST("beacon"));
    if (beaconP) {
        int64_t beacon = *beaconP;
        if (beacon > 3 || beacon < 0) {
            Log_error(ctx->logger, "interfaces.ETHInterface.beacon may only be 0, 1,or 2");
        } else {
            // We can cast beacon to an int here because we know it's small enough
            Log_info(ctx->logger, "Setting beacon mode on ETHInterface to [%d].", (int) beacon);
            Dict d = Dict_CONST(String_CONST("interfaceNumber"), Int_OBJ(ifNum),
                     Dict_CONST(String_CONST("state"), Int_OBJ(beacon), NULL));
            rpcCall(String_CONST("ETHInterface_beacon"), &d, ctx, ctx->alloc);
        }
    }
}
Beispiel #24
0
static void pingResponse(struct RouterModule_Promise* promise,
                         uint32_t lag,
                         struct Node* node,
                         Dict* responseDict)
{
    struct Ping* ping = Identity_cast((struct Ping*)promise->userData);

    uint8_t versionStr[40] = "old";
    String* version = String_CONST((char*)versionStr);
    String* versionBin = Dict_getString(responseDict, CJDHTConstants_VERSION);
    if (versionBin && versionBin->len == 20) {
        Hex_encode(versionStr, 40, (uint8_t*) versionBin->bytes, 20);
        version->len = 40;
    }
    int64_t* protocolVersion = Dict_getInt(responseDict, CJDHTConstants_PROTOCOL);
    int64_t pv = (protocolVersion) ? *protocolVersion : -1;

    Dict response = NULL;
    Dict verResponse = Dict_CONST(String_CONST("version"), String_OBJ(version), response);
    if (versionBin) {
        response = verResponse;
    }

    String* result = (responseDict) ? String_CONST("pong") : String_CONST("timeout");
    response = Dict_CONST(String_CONST("result"), String_OBJ(result), response);

    Dict protoResponse = Dict_CONST(String_CONST("protocol"), Int_OBJ(pv), response);
    if (protocolVersion) {
        response = protoResponse;
    }

    response = Dict_CONST(String_CONST("ms"), Int_OBJ(lag), response);

    char from[60] = "";
    if (node) {
        Address_print((uint8_t*)from, &node->address);
    }
    Dict fromResponse = Dict_CONST(String_CONST("from"), String_OBJ(String_CONST(from)), response);
    if (node) {
        response = fromResponse;
    }

    Admin_sendMessage(&response, ping->txid, ping->ctx->admin);
}
Beispiel #25
0
static void minSinatures(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc)
{
    struct Context* context = vcontext;
    struct Allocator* alloc = Allocator_child(context->alloc);
    int64_t* count = Dict_getInt(args, String_CONST("count"));
    char* err = "none";
    if (*count < 0 || *count > INT32_MAX) {
        err = "count cannot be less than zero or more than INT32_MAX";
    } else {
        context->rainfly->minSignatures = *count;
    }

    Dict* response = Dict_new(alloc);
    Dict_putString(response, String_CONST("error"), String_CONST(err), alloc);

    Admin_sendMessage(response, txid, context->admin);

    Allocator_free(alloc);
}
Beispiel #26
0
static void add(Dict* args, void* vcontext, String* txid)
{
    struct Context* context = (struct Context*) vcontext;

    String* passwd = Dict_getString(args, String_CONST("password"));
    int64_t* authType = Dict_getInt(args, String_CONST("authType"));

    if (!(passwd && authType)) {
        sendResponse(String_CONST("Must specify authType, and password."), context->admin, txid);
    } else if (*authType < 1 || *authType > 255) {
        sendResponse(String_CONST("Auth must be between 1 and 255 inclusive."), context->admin, txid);
    } else {
        struct User* u = context->allocator->malloc(sizeof(struct User), context->allocator);
        // At some point this will be implemented...
        u->trust = 0;
        int32_t ret = CryptoAuth_addUser(passwd, *authType, u, context->ca);

        switch (ret) {
            case 0:
                sendResponse(String_CONST("none"), context->admin, txid);
                break;
            case CryptoAuth_addUser_INVALID_AUTHTYPE:
                sendResponse(String_CONST("Specified auth type is not supported."),
                             context->admin,
                             txid);
                break;
            case CryptoAuth_addUser_OUT_OF_SPACE:
                sendResponse(String_CONST("Out of memory to store password."), context->admin, txid);
                break;
            case CryptoAuth_addUser_DUPLICATE:
                sendResponse(String_CONST("Password already added."), context->admin, txid);
                break;
            default:
                sendResponse(String_CONST("Unknown error."), context->admin, txid);
        };
    }
}
Beispiel #27
0
static void pingResponse(struct RouterModule_Promise* promise,
                         uint32_t lag,
                         struct Address* from,
                         Dict* responseDict)
{
    struct Ping* ping = Identity_check((struct Ping*)promise->userData);
    struct Allocator* tempAlloc = promise->alloc;
    Dict* resp = Dict_new(tempAlloc);

    String* versionBin = Dict_getString(responseDict, CJDHTConstants_VERSION);
    if (versionBin && versionBin->len == 20) {
        String* versionStr = String_newBinary(NULL, 40, tempAlloc);
        Hex_encode(versionStr->bytes, 40, versionBin->bytes, 20);
        Dict_putString(resp, String_CONST("version"), versionStr, tempAlloc);
    } else {
        Dict_putString(resp, String_CONST("version"), String_CONST("unknown"), tempAlloc);
    }

    String* result = (responseDict) ? String_CONST("pong") : String_CONST("timeout");
    Dict_putString(resp, String_CONST("result"), result, tempAlloc);

    int64_t* protocolVersion = Dict_getInt(responseDict, CJDHTConstants_PROTOCOL);
    if (protocolVersion) {
        Dict_putInt(resp, String_CONST("protocol"), *protocolVersion, tempAlloc);
    }

    Dict_putInt(resp, String_CONST("ms"), lag, tempAlloc);

    if (from) {
        uint8_t fromStr[60] = "";
        Address_print(fromStr, from);
        Dict_putString(resp, String_CONST("from"), String_new(fromStr, tempAlloc), tempAlloc);
    }

    Admin_sendMessage(resp, ping->txid, ping->ctx->admin);
}
Beispiel #28
0
static void udpConnectTo(String* connectToAddress,
                         Dict* config,
                         struct UDPInterface* udpContext,
                         struct Context* ctx)
{
    String* password = Dict_getString(config, BSTR("password"));
    int64_t* authType = Dict_getInt(config, BSTR("authType"));
    String* publicKey = Dict_getString(config, BSTR("publicKey"));
    int64_t* trust = Dict_getInt(config, BSTR("trust"));

    #define FAIL_IF_NULL(cannotBeNull, fieldName) \
        if (!cannotBeNull) {                                                     \
            fprintf(stderr,                                                      \
                    "interfaces.UDPInterface['%s']." fieldName " is not set, "   \
                    "this field is mandatory.\n",                                \
                    connectToAddress->bytes);                                    \
            exit(-1);                                                            \
        }

    FAIL_IF_NULL(password, "password")
    FAIL_IF_NULL(authType, "authType")
    FAIL_IF_NULL(publicKey, "publicKey")
    FAIL_IF_NULL(trust, "trust")

    #undef FAIL_IF_NULL

    #define CHECK_RANGE(number, min, max) \
        if (number < min || number > max) {                                           \
        fprintf(stderr,                                                               \
                "interfaces.UDPInterface['%s'].number must be between min and max\n", \
                connectToAddress->bytes);                                             \
        exit(-1);                                                                     \
    }

    CHECK_RANGE(*authType, 1, 255)
    CHECK_RANGE(*trust, 0, INT64_MAX)

    #undef CHECK_RANGE

    uint8_t pkBytes[32];
    if (publicKey->len < 52 || Base32_decode(pkBytes, 32, (uint8_t*)publicKey->bytes, 52) != 32) {
        fprintf(stderr,
                "interfaces.UDPInterface['%s'].publicKey could not be parsed.\n",
                connectToAddress->bytes);
        exit(-1);
    }
    uint8_t addressBytes[16];
    AddressCalc_addressForPublicKey(addressBytes, pkBytes);
    if (addressBytes[0] != 0xFC) {
        fprintf(stderr,
                "interfaces.UDPInterface['%s'].publicKey\n( %s )\nis not in FC00/8 range, "
                "it was probably mistranscribed.\n",
                connectToAddress->bytes,
                publicKey->bytes);
        exit(-1);
    }

    struct Interface* udp =
        UDPInterface_addEndpoint(udpContext, connectToAddress->bytes, ctx->eHandler);
    struct Interface* authedUdp = CryptoAuth_wrapInterface(udp, pkBytes, false, true, ctx->ca);
    CryptoAuth_setAuth(password, *authType, authedUdp);

    uint64_t switchAddr_be;
    SwitchCore_addInterface(authedUdp, *trust, &switchAddr_be, ctx->switchCore);
    struct Address addr;
    memset(&addr, 0, sizeof(struct Address));
    memcpy(addr.key, pkBytes, 32);
    addr.networkAddress_be = switchAddr_be;
    RouterModule_addNode(&addr, ctx->routerModule);
}
Beispiel #29
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
    }));
Beispiel #30
0
static int getIntVal(Dict* d, String* name)
{
    int64_t* valP = Dict_getInt(d, name);
    return (valP && (*valP > 0)) ? *valP : 0;
}