예제 #1
0
static void repeatHello()
{
    uint8_t* expectedOutput =
        "0000000101641c99f7719f5700000000a693a9fd3f0e27e81ab1100b57b37259"
        "4c2adca8671f1fdd050383c91e7d56ec2336c09739fa8e91d8dc5bec63e8fad0"
        "74bee22a90642a6ba8555be84c5e35970c5270e8f31f2a5978e0fbdee4542882"
        "97568f25a3fc2801aa707d954c78eccb970bcc8cb26867e9dbf0c9d6ef1b3f27"
        "24e7e550";

    struct Allocator* alloc = MallocAllocator_new(1<<20);
    struct Context* ctx = setUp(NULL, HERPUBKEY, "password", alloc);
    struct Message* msg = Message_new(0, CryptoHeader_SIZE + HELLOWORLDLEN, alloc);
    Message_push(msg, HELLOWORLD, HELLOWORLDLEN, NULL);

    Assert_true(!CryptoAuth_encrypt(ctx->sess, msg));

    Message_reset(msg);
    Message_push(msg, HELLOWORLD, HELLOWORLDLEN, NULL);

    Assert_true(!CryptoAuth_encrypt(ctx->sess, msg));

    char* actual = Hex_print(msg->bytes, msg->length, alloc);
    if (CString_strcmp(actual, expectedOutput)) {
        Assert_failure("Test failed.\n"
                       "Expected %s\n"
                       "     Got %s\n", expectedOutput, actual);
    }
    Allocator_free(alloc);
}
예제 #2
0
static bool PFChan_Core_sizeOk(enum PFChan_Core ev, int size)
{
    switch (ev) {
        case PFChan_Core_CONNECT:
            return (size == 8 + PFChan_Core_Connect_SIZE);

        case PFChan_Core_PATHFINDER:
        case PFChan_Core_PATHFINDER_GONE:
            return (size == 8 + PFChan_Core_Pathfinder_SIZE);

        case PFChan_Core_SWITCH_ERR:
            return (size >= 8 + PFChan_Core_SwitchErr_MIN_SIZE);

        case PFChan_Core_SEARCH_REQ:
            return (size == 8 + PFChan_Core_SearchReq_SIZE);

        case PFChan_Core_PEER:
        case PFChan_Core_PEER_GONE:
        case PFChan_Core_SESSION:
        case PFChan_Core_SESSION_ENDED:
        case PFChan_Core_DISCOVERED_PATH:
            return (size == 8 + PFChan_Node_SIZE);

        case PFChan_Core_MSG:
            return (size >= 8 + PFChan_Msg_MIN_SIZE);

        case PFChan_Core_PING:
        case PFChan_Core_PONG:
            return (size == 8 + PFChan_Ping_SIZE);
        default:;
    }
    Assert_failure("invalid event [%d]", ev);
}
예제 #3
0
static void notLinkedYet(struct TwoNodes* ctx)
{
    uint64_t now = Time_currentTimeMilliseconds(ctx->base);
    if ((now - ctx->startTime) > 5000) {
        Assert_failure("Failed to link in 5 seconds");
    }
}
예제 #4
0
Gcc_NORETURN
static void failure(struct Allocator_pvt* context,
                    const char* message,
                    const char* fileName,
                    int lineNum)
{
    Allocator_snapshot(&context->pub, 1);
    Assert_failure("%s:%d Fatal error: [%s]", fileName, lineNum, message);
}
예제 #5
0
static int pivotChildrenToAdoptedParents(struct Allocator_pvt* context, const char* file, int line)
{
    for (int i = 0; i < 10000; i++) {
        if (!pivotChildrenToAdoptedParents0(context, 0, i, file, line)) {
            // No out on i == 0 -> the allocator pivoted to another parent, cease freeing.
            return (i != 0);
        }
    }
    Assert_failure("Didn't free all allocators in 10000 deep iterations");
}
예제 #6
0
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);
}
예제 #7
0
static void waitUntilPong(struct Context* ctx)
{
    for (int i = 0; i < 10; i++) {
        struct Allocator* temp = Allocator_child(ctx->alloc);
        if (tryPing(temp, ctx)) {
            Allocator_free(temp);
            return;
        }
        sleep(200, ctx, temp);
        Allocator_free(temp);
    }
    Assert_failure("Failed connecting to core (perhaps you have a firewall on loopback device?)");
}
예제 #8
0
static inline void checkCanaries(struct Allocator_Allocation_pvt* alloc,
                                 struct Allocator_pvt* context)
{
    #ifdef Allocator_USE_CANARIES
        char* canary;
        if (alloc->beginCanary != context->canary) {
            canary = "begin";
        } else if (END_CANARY(alloc) != alloc->beginCanary) {
            canary = "end";
        } else {
            return;
        }
        Assert_failure("%s:%d Fatal error: invalid [%s] canary\n",
                       context->pub.fileName, context->pub.lineNum, canary);
    #endif
}
예제 #9
0
파일: CryptoAuth.c 프로젝트: cmotc/cjdns
static inline void hashPassword(uint8_t secretOut[32],
                                union CryptoHeader_Challenge* challengeOut,
                                const String* login,
                                const String* password,
                                const uint8_t authType)
{
    crypto_hash_sha256(secretOut, (uint8_t*) password->bytes, password->len);
    uint8_t tempBuff[32];
    if (authType == 1) {
        crypto_hash_sha256(tempBuff, secretOut, 32);
    } else if (authType == 2) {
        crypto_hash_sha256(tempBuff, (uint8_t*) login->bytes, login->len);
    } else {
        Assert_failure("Unsupported auth type [%u]", authType);
    }
    Bits_memcpyConst(challengeOut->bytes, tempBuff, CryptoHeader_Challenge_SIZE);
    CryptoHeader_setAuthChallengeDerivations(challengeOut, 0);
    challengeOut->challenge.type = authType;
    challengeOut->challenge.additional = 0;
}
예제 #10
0
static Iface_DEFUN messageToTun(struct Message* msg, struct Iface* iface)
{
    struct Context* ctx = Identity_check(((struct IfaceContext*)iface)->ctx);
    uint16_t type = TUNMessageType_pop(msg, NULL);
    if (type == Ethernet_TYPE_IP6) {
        struct Headers_IP6Header* ip = (struct Headers_IP6Header*) msg->bytes;
        Assert_true(Headers_getIpVersion(ip) == 6);
        Assert_true(!Bits_memcmp(ip->sourceAddr, ctx->sendingAddress, 16));
        Message_shift(msg, -Headers_IP6Header_SIZE, NULL);
        ctx->called |= 4;
    } else if (type == Ethernet_TYPE_IP4) {
        struct Headers_IP4Header* ip = (struct Headers_IP4Header*) msg->bytes;
        Assert_true(Headers_getIpVersion(ip) == 4);
        Assert_true(!Bits_memcmp(ip->sourceAddr, ctx->sendingAddress, 4));
        Message_shift(msg, -Headers_IP4Header_SIZE, NULL);
        ctx->called |= 1;
    } else {
        Assert_failure("unrecognized message type %u", (unsigned int)type);
    }
    Assert_true(msg->length == 12 && CString_strcmp(msg->bytes, "hello world") == 0);
    return 0;
}
예제 #11
0
static bool PFChan_Pathfinder_sizeOk(enum PFChan_Pathfinder ev, int size)
{
    switch (ev) {
        case PFChan_Pathfinder_CONNECT:
            return (size == 8 + PFChan_Pathfinder_Connect_SIZE);
        case PFChan_Pathfinder_SUPERIORITY:
            return (size == 8 + PFChan_Pathfinder_Superiority_SIZE);
        case PFChan_Pathfinder_NODE:
            return (size == 8 + PFChan_Node_SIZE);
        case PFChan_Pathfinder_SENDMSG:
            return (size >= 8 + PFChan_Msg_MIN_SIZE);
        case PFChan_Pathfinder_PING:
        case PFChan_Pathfinder_PONG:
            return (size >= 8 + PFChan_Ping_SIZE);
        case PFChan_Pathfinder_SESSIONS:
        case PFChan_Pathfinder_PEERS:
        case PFChan_Pathfinder_PATHFINDERS:
            return (size == 8);
        default:;
    }
    Assert_failure("invalid event [%d]", ev);
}
예제 #12
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);
}
예제 #13
0
// incoming message from network, pointing to the beginning of the switch header.
static uint8_t receiveMessage(struct Message* msg, struct Interface* iface)
{
    struct SwitchPinger* ctx = Identity_check((struct SwitchPinger*) iface->receiverContext);
    struct SwitchHeader* switchHeader = (struct SwitchHeader*) msg->bytes;
    ctx->incomingLabel = Endian_bigEndianToHost64(switchHeader->label_be);
    ctx->incomingVersion = 0;
    Message_shift(msg, -SwitchHeader_SIZE, NULL);

    uint32_t handle = Message_pop32(msg, NULL);
    #ifdef Version_7_COMPAT
    if (handle != 0xffffffff) {
        Message_push32(msg, handle, NULL);
        handle = 0xffffffff;
        Assert_true(SwitchHeader_isV7Ctrl(switchHeader));
    }
    #endif
    Assert_true(handle == 0xffffffff);

    struct Control* ctrl = (struct Control*) msg->bytes;
    if (ctrl->type_be == Control_PONG_be) {
        Message_shift(msg, -Control_HEADER_SIZE, NULL);
        ctx->error = Error_NONE;
        if (msg->length >= Control_Pong_MIN_SIZE) {
            struct Control_Ping* pongHeader = (struct Control_Ping*) msg->bytes;
            ctx->incomingVersion = Endian_bigEndianToHost32(pongHeader->version_be);
            if (pongHeader->magic != Control_Pong_MAGIC) {
                Log_debug(ctx->logger, "dropped invalid switch pong");
                return Error_INVALID;
            }
            Message_shift(msg, -Control_Pong_HEADER_SIZE, NULL);
        } else {
            Log_debug(ctx->logger, "got runt pong message, length: [%d]", msg->length);
            return Error_INVALID;
        }

    } else if (ctrl->type_be == Control_KEYPONG_be) {
        Message_shift(msg, -Control_HEADER_SIZE, NULL);
        ctx->error = Error_NONE;
        if (msg->length >= Control_KeyPong_HEADER_SIZE && msg->length <= Control_KeyPong_MAX_SIZE) {
            struct Control_KeyPing* pongHeader = (struct Control_KeyPing*) msg->bytes;
            ctx->incomingVersion = Endian_bigEndianToHost32(pongHeader->version_be);
            if (pongHeader->magic != Control_KeyPong_MAGIC) {
                Log_debug(ctx->logger, "dropped invalid switch key-pong");
                return Error_INVALID;
            }
            Bits_memcpyConst(ctx->incomingKey, pongHeader->key, 32);
            Message_shift(msg, -Control_KeyPong_HEADER_SIZE, NULL);
        } else if (msg->length > Control_KeyPong_MAX_SIZE) {
            Log_debug(ctx->logger, "got overlong key-pong message, length: [%d]", msg->length);
            return Error_INVALID;
        } else {
            Log_debug(ctx->logger, "got runt key-pong message, length: [%d]", msg->length);
            return Error_INVALID;
        }

    } else if (ctrl->type_be == Control_ERROR_be) {
        Message_shift(msg, -Control_HEADER_SIZE, NULL);
        Assert_true((uint8_t*)&ctrl->content.error.errorType_be == msg->bytes);
        if (msg->length < (Control_Error_HEADER_SIZE + SwitchHeader_SIZE + Control_HEADER_SIZE)) {
            Log_debug(ctx->logger, "runt error packet");
            return Error_NONE;
        }

        ctx->error = Message_pop32(msg, NULL);
        Message_push32(msg, 0, NULL);

        Message_shift(msg, -(Control_Error_HEADER_SIZE + SwitchHeader_SIZE), NULL);

        struct Control* origCtrl = (struct Control*) msg->bytes;

        Log_debug(ctx->logger, "error [%s] was caused by our [%s]",
                  Error_strerror(ctx->error),
                  Control_typeString(origCtrl->type_be));

        int shift;
        if (origCtrl->type_be == Control_PING_be) {
            shift = -(Control_HEADER_SIZE + Control_Ping_HEADER_SIZE);
        } else if (origCtrl->type_be == Control_KEYPING_be) {
            shift = -(Control_HEADER_SIZE + Control_KeyPing_HEADER_SIZE);
        } else {
            Assert_failure("problem in Ducttape.c");
        }
        if (msg->length < -shift) {
            Log_debug(ctx->logger, "runt error packet");
        }
        Message_shift(msg, shift, NULL);

    } else {
        // If it gets here then Ducttape.c is failing.
        Assert_true(false);
    }

    String* msgStr = &(String) { .bytes = (char*) msg->bytes, .len = msg->length };
    Pinger_pongReceived(msgStr, ctx->pinger);
    Bits_memset(ctx->incomingKey, 0, 32);
    return Error_NONE;
}

static void onPingResponse(String* data, uint32_t milliseconds, void* vping)
{
    struct Ping* p = Identity_check((struct Ping*) vping);
    enum SwitchPinger_Result err = SwitchPinger_Result_OK;
    uint64_t label = p->context->incomingLabel;
    if (data) {
        if (label != p->label) {
            err = SwitchPinger_Result_LABEL_MISMATCH;
        } else if ((p->data || data->len > 0) && !String_equals(data, p->data)) {
            err = SwitchPinger_Result_WRONG_DATA;
        } else if (p->context->error == Error_LOOP_ROUTE) {
            err = SwitchPinger_Result_LOOP_ROUTE;
        } else if (p->context->error) {
            err = SwitchPinger_Result_ERROR_RESPONSE;
        }
    } else {
        err = SwitchPinger_Result_TIMEOUT;
    }

    uint32_t version = p->context->incomingVersion;
    struct SwitchPinger_Response* resp =
        Allocator_calloc(p->pub.pingAlloc, sizeof(struct SwitchPinger_Response), 1);
    resp->version = p->context->incomingVersion;
    resp->res = err;
    resp->label = label;
    resp->data = data;
    resp->milliseconds = milliseconds;
    resp->version = version;
    Bits_memcpyConst(resp->key, p->context->incomingKey, 32);
    resp->ping = &p->pub;
    p->onResponse(resp, p->pub.onResponseContext);
}

static void sendPing(String* data, void* sendPingContext)
{
    struct Ping* p = Identity_check((struct Ping*) sendPingContext);

    struct Message* msg = Message_new(0, data->len + 512, p->pub.pingAlloc);

    while (((uintptr_t)msg->bytes - data->len) % 4) {
        Message_push8(msg, 0, NULL);
    }
    msg->length = 0;

    Message_push(msg, data->bytes, data->len, NULL);
    Assert_true(!((uintptr_t)msg->bytes % 4) && "alignment fault");

    if (p->pub.keyPing) {
        Message_shift(msg, Control_KeyPing_HEADER_SIZE, NULL);
        struct Control_KeyPing* keyPingHeader = (struct Control_KeyPing*) msg->bytes;
        keyPingHeader->magic = Control_KeyPing_MAGIC;
        keyPingHeader->version_be = Endian_hostToBigEndian32(Version_CURRENT_PROTOCOL);
        Bits_memcpyConst(keyPingHeader->key, p->context->myAddr->key, 32);
    } else {
        Message_shift(msg, Control_Ping_HEADER_SIZE, NULL);
        struct Control_Ping* pingHeader = (struct Control_Ping*) msg->bytes;
        pingHeader->magic = Control_Ping_MAGIC;
        pingHeader->version_be = Endian_hostToBigEndian32(Version_CURRENT_PROTOCOL);
    }

    Message_shift(msg, Control_HEADER_SIZE, NULL);
    struct Control* ctrl = (struct Control*) msg->bytes;
    ctrl->checksum_be = 0;
    ctrl->type_be = (p->pub.keyPing) ? Control_KEYPING_be : Control_PING_be;
    ctrl->checksum_be = Checksum_engine(msg->bytes, msg->length);

    #ifdef Version_7_COMPAT
        if (0) {
    #endif
    Message_push32(msg, 0xffffffff, NULL);
    #ifdef Version_7_COMPAT
        }
    #endif

    Message_shift(msg, SwitchHeader_SIZE, NULL);
    struct SwitchHeader* switchHeader = (struct SwitchHeader*) msg->bytes;
    switchHeader->label_be = Endian_hostToBigEndian64(p->label);

    SwitchHeader_setVersion(switchHeader, SwitchHeader_CURRENT_VERSION);
    SwitchHeader_setPenalty(switchHeader, 0);
    SwitchHeader_setCongestion(switchHeader, 0);

    #ifdef Version_7_COMPAT
        // v7 detects ctrl packets by the bit which has been
        // re-appropriated for suppression of errors.
        switchHeader->congestAndSuppressErrors = 1;
        SwitchHeader_setVersion(switchHeader, 0);
    #endif

    p->context->iface->sendMessage(msg, p->context->iface);
}

static String* RESULT_STRING_OK =             String_CONST_SO("pong");
static String* RESULT_STRING_LABEL_MISMATCH = String_CONST_SO("diff_label");
static String* RESULT_STRING_WRONG_DATA =     String_CONST_SO("diff_data");
static String* RESULT_STRING_ERROR_RESPONSE = String_CONST_SO("err_switch");
static String* RESULT_STRING_TIMEOUT =        String_CONST_SO("timeout");
static String* RESULT_STRING_UNKNOWN =        String_CONST_SO("err_unknown");
static String* RESULT_STRING_LOOP =           String_CONST_SO("err_loop");

String* SwitchPinger_resultString(enum SwitchPinger_Result result)
{
    switch (result) {
        case SwitchPinger_Result_OK:
            return RESULT_STRING_OK;

        case SwitchPinger_Result_LABEL_MISMATCH:
            return RESULT_STRING_LABEL_MISMATCH;

        case SwitchPinger_Result_WRONG_DATA:
            return RESULT_STRING_WRONG_DATA;

        case SwitchPinger_Result_ERROR_RESPONSE:
            return RESULT_STRING_ERROR_RESPONSE;

        case SwitchPinger_Result_TIMEOUT:
            return RESULT_STRING_TIMEOUT;

        case SwitchPinger_Result_LOOP_ROUTE:
            return RESULT_STRING_LOOP;

        default:
            return RESULT_STRING_UNKNOWN;
    };
}

static int onPingFree(struct Allocator_OnFreeJob* job)
{
    struct Ping* ping = Identity_check((struct Ping*)job->userData);
    struct SwitchPinger* ctx = Identity_check(ping->context);
    ctx->outstandingPings--;
    Assert_true(ctx->outstandingPings >= 0);
    return 0;
}

struct SwitchPinger_Ping* SwitchPinger_newPing(uint64_t label,
                                               String* data,
                                               uint32_t timeoutMilliseconds,
                                               SwitchPinger_ResponseCallback onResponse,
                                               struct Allocator* alloc,
                                               struct SwitchPinger* ctx)
{
    if (data && data->len > Control_Ping_MAX_SIZE) {
        return NULL;
    }

    if (ctx->outstandingPings > ctx->maxConcurrentPings) {
        Log_debug(ctx->logger, "Skipping switch ping because there are already [%d] outstanding",
                  ctx->outstandingPings);
        return NULL;
    }

    struct Pinger_Ping* pp =
        Pinger_newPing(data, onPingResponse, sendPing, timeoutMilliseconds, alloc, ctx->pinger);

    struct Ping* ping = Allocator_clone(pp->pingAlloc, (&(struct Ping) {
        .pub = {
            .pingAlloc = pp->pingAlloc
        },
        .label = label,
        .data = String_clone(data, pp->pingAlloc),
        .context = ctx,
        .onResponse = onResponse,
        .pingerPing = pp
    }));
예제 #14
0
static Iface_DEFUN incomingMsg(struct Message* msg, struct Pathfinder_pvt* pf)
{
    struct Address addr;
    struct RouteHeader* hdr = (struct RouteHeader*) msg->bytes;
    Message_shift(msg, -(RouteHeader_SIZE + DataHeader_SIZE), NULL);
    Bits_memcpy(addr.ip6.bytes, hdr->ip6, 16);
    Bits_memcpy(addr.key, hdr->publicKey, 32);
    addr.protocolVersion = Endian_bigEndianToHost32(hdr->version_be);
    addr.padding = 0;
    addr.path = Endian_bigEndianToHost64(hdr->sh.label_be);

    //Log_debug(pf->log, "Incoming DHT");

    struct DHTMessage dht = {
        .address = &addr,
        .binMessage = msg,
        .allocator = msg->alloc
    };

    DHTModuleRegistry_handleIncoming(&dht, pf->registry);

    struct Message* nodeMsg = Message_new(0, 256, msg->alloc);
    Iface_CALL(sendNode, nodeMsg, &addr, 0xfffffff0u, pf);

    if (dht.pleaseRespond) {
        // what a beautiful hack, see incomingFromDHT
        return Iface_next(&pf->pub.eventIf, msg);
    }

    return NULL;
}

static Iface_DEFUN incomingFromEventIf(struct Message* msg, struct Iface* eventIf)
{
    struct Pathfinder_pvt* pf = Identity_containerOf(eventIf, struct Pathfinder_pvt, pub.eventIf);
    enum PFChan_Core ev = Message_pop32(msg, NULL);
    if (Pathfinder_pvt_state_INITIALIZING == pf->state) {
        Assert_true(ev == PFChan_Core_CONNECT);
        return connected(pf, msg);
    }
    // Let the PF send another 128 path changes again because it's basically a new tick.
    pf->bestPathChanges = 0;
    switch (ev) {
        case PFChan_Core_SWITCH_ERR: return switchErr(msg, pf);
        case PFChan_Core_SEARCH_REQ: return searchReq(msg, pf);
        case PFChan_Core_PEER: return peer(msg, pf);
        case PFChan_Core_PEER_GONE: return peerGone(msg, pf);
        case PFChan_Core_SESSION: return session(msg, pf);
        case PFChan_Core_SESSION_ENDED: return sessionEnded(msg, pf);
        case PFChan_Core_DISCOVERED_PATH: return discoveredPath(msg, pf);
        case PFChan_Core_MSG: return incomingMsg(msg, pf);
        case PFChan_Core_PING: return handlePing(msg, pf);
        case PFChan_Core_PONG: return handlePong(msg, pf);
        case PFChan_Core_UNSETUP_SESSION:
        case PFChan_Core_LINK_STATE:
        case PFChan_Core_CTRL_MSG: return NULL;
        default:;
    }
    Assert_failure("unexpected event [%d]", ev);
}

static void sendEvent(struct Pathfinder_pvt* pf, enum PFChan_Pathfinder ev, void* data, int size)
{
    struct Allocator* alloc = Allocator_child(pf->alloc);
    struct Message* msg = Message_new(0, 512+size, alloc);
    Message_push(msg, data, size, NULL);
    Message_push32(msg, ev, NULL);
    Iface_send(&pf->pub.eventIf, msg);
    Allocator_free(alloc);
}

static void init(void* vpf)
{
    struct Pathfinder_pvt* pf = Identity_check((struct Pathfinder_pvt*) vpf);
    struct PFChan_Pathfinder_Connect conn = {
        .superiority_be = Endian_hostToBigEndian32(1),
        .version_be = Endian_hostToBigEndian32(Version_CURRENT_PROTOCOL)
    };
    CString_strncpy(conn.userAgent, "Cjdns internal pathfinder", 64);
    sendEvent(pf, PFChan_Pathfinder_CONNECT, &conn, PFChan_Pathfinder_Connect_SIZE);
}

struct Pathfinder* Pathfinder_register(struct Allocator* allocator,
                                       struct Log* log,
                                       struct EventBase* base,
                                       struct Random* rand,
                                       struct Admin* admin)
{
    struct Allocator* alloc = Allocator_child(allocator);
    struct Pathfinder_pvt* pf = Allocator_calloc(alloc, sizeof(struct Pathfinder_pvt), 1);
    Identity_set(pf);
    pf->alloc = alloc;
    pf->log = log;
    pf->base = base;
    pf->rand = rand;
    pf->admin = admin;

    pf->pub.eventIf.send = incomingFromEventIf;

    pf->dhtModule.context = pf;
    pf->dhtModule.handleOutgoing = incomingFromDHT;

    // This needs to be done asynchronously so the pf can be plumbed to the core
    Timeout_setTimeout(init, pf, 0, base, alloc);

    return &pf->pub;
}
예제 #15
0
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);
        }
    }
}
예제 #16
0
static void runTest0(char** prefixes,
                     char** exceptions4,
                     char** exceptions6,
                     char** expectedOut4,
                     char** expectedOut6,
                     struct Allocator* alloc,
                     struct Log* log)
{
    struct RouteGen* rg = RouteGen_new(alloc, log);
    for (int i = 0; prefixes[i]; i++) {
        RouteGen_addPrefix(rg, mkSockaddr(prefixes[i], alloc));
    }
    for (int i = 0; exceptions4 && exceptions4[i]; i++) {
        RouteGen_addException(rg, mkSockaddr(exceptions4[i], alloc));
    }
    for (int i = 0; exceptions6 && exceptions6[i]; i++) {
        RouteGen_addException(rg, mkSockaddr(exceptions6[i], alloc));
    }
    Dict* routes = RouteGen_getGeneratedRoutes(rg, alloc);
    List* routes4 = Dict_getList(routes, String_CONST("ipv4"));
    List* routes6 = Dict_getList(routes, String_CONST("ipv6"));
    if (expectedOut4) {
        for (int i = 0; expectedOut4[i]; i++) {
            Log_debug(log, "%s\n", expectedOut4[i]);
        }
        for (int i = 0; i < List_size(routes4); i++) {
            Log_debug(log, "%s\n", List_getString(routes4, i)->bytes);
        }

        Assert_true(!expectedOut4[List_size(routes4)]);
        for (int i = 0; i < List_size(routes4); i++) {
            String* str = List_getString(routes4, i);
            Assert_true(str);
            Assert_true(expectedOut4[i]);
            if (CString_strncmp(expectedOut4[i], str->bytes, str->len)) {
                Log_error(log, "Fail\nexpected: %s\nGot:      %s\n", expectedOut4[i], str->bytes);
                Assert_failure("fail");
            }
        }
    } else {
        Assert_true(!List_size(routes4));
    }
    if (expectedOut6) {
        for (int i = 0; expectedOut6[i]; i++) {
            Log_debug(log, "%s\n", expectedOut6[i]);
        }
        for (int i = 0; i < List_size(routes6); i++) {
            Log_debug(log, "%s\n", List_getString(routes6, i)->bytes);
        }

        Assert_true(!expectedOut6[List_size(routes6)]);
        for (int i = 0; i < List_size(routes6); i++) {
            String* str = List_getString(routes6, i);
            Assert_true(str);
            Assert_true(expectedOut6[i]);
            if (CString_strncmp(expectedOut6[i], str->bytes, str->len)) {
                Log_error(log, "Fail\nexpected: %s\nGot:      %s\n", expectedOut6[i], str->bytes);
                Assert_failure("fail");
            }
        }
    } else {
        Assert_true(!List_size(routes6));
    }
}
예제 #17
0
static Iface_DEFUN handlePing(struct Message* msg,
                              struct ControlHandler_pvt* ch,
                              uint64_t label,
                              uint8_t* labelStr,
                              uint16_t messageType_be)
{
    if (msg->length < handlePing_MIN_SIZE) {
        Log_info(ch->log, "DROP runt ping");
        return NULL;
    }

    struct Control* ctrl = (struct Control*) msg->bytes;
    Message_shift(msg, -Control_Header_SIZE, NULL);

    // Ping and keyPing share version location
    struct Control_Ping* ping = (struct Control_Ping*) msg->bytes;
    uint32_t herVersion = Endian_bigEndianToHost32(ping->version_be);
    if (!Version_isCompatible(Version_CURRENT_PROTOCOL, herVersion)) {
        Log_debug(ch->log, "DROP ping from incompatible version [%d]", herVersion);
        return NULL;
    }

    if (messageType_be == Control_KEYPING_be) {
        Log_debug(ch->log, "got switch keyPing from [%s]", labelStr);
        if (msg->length < Control_KeyPing_HEADER_SIZE) {
            // min keyPing size is longer
            Log_debug(ch->log, "DROP runt keyPing");
            return NULL;
        }
        if (msg->length > Control_KeyPing_MAX_SIZE) {
            Log_debug(ch->log, "DROP long keyPing");
            return NULL;
        }
        if (ping->magic != Control_KeyPing_MAGIC) {
            Log_debug(ch->log, "DROP keyPing (bad magic)");
            return NULL;
        }

        struct Control_KeyPing* keyPing = (struct Control_KeyPing*) msg->bytes;
        keyPing->magic = Control_KeyPong_MAGIC;
        ctrl->header.type_be = Control_KEYPONG_be;
        Bits_memcpy(keyPing->key, ch->myPublicKey, 32);

    } else if (messageType_be == Control_PING_be) {
        // Happens in benchmark.
        //Log_debug(ch->log, "got switch ping from [%s]", labelStr);
        if (ping->magic != Control_Ping_MAGIC) {
            Log_debug(ch->log, "DROP ping (bad magic)");
            return NULL;
        }
        ping->magic = Control_Pong_MAGIC;
        ctrl->header.type_be = Control_PONG_be;

    } else {
        Assert_failure("2+2=5");
    }

    ping->version_be = Endian_hostToBigEndian32(Version_CURRENT_PROTOCOL);

    Message_shift(msg, Control_Header_SIZE, NULL);

    ctrl->header.checksum_be = 0;
    ctrl->header.checksum_be = Checksum_engine(msg->bytes, msg->length);

    Message_shift(msg, RouteHeader_SIZE, NULL);

    struct RouteHeader* routeHeader = (struct RouteHeader*) msg->bytes;
    Bits_memset(routeHeader, 0, RouteHeader_SIZE);
    SwitchHeader_setVersion(&routeHeader->sh, SwitchHeader_CURRENT_VERSION);
    routeHeader->sh.label_be = Endian_hostToBigEndian64(label);
    routeHeader->flags |= RouteHeader_flags_CTRLMSG;

    return Iface_next(&ch->pub.coreIf, msg);
}
예제 #18
0
파일: Seccomp.c 프로젝트: cmotc/cjdns
static void catchViolation(int sig, siginfo_t* si, void* threadContext)
{
    printf("Attempted banned syscall number [%d] see doc/Seccomp.md for more information\n",
           GET_SYSCALL_NUM(si));
    Assert_failure("Disallowed Syscall");
}
예제 #19
0
static void encryptRndNonceTest()
{
    uint8_t buff[44];
    Bits_memset(buff, 0, 44);

    uint8_t nonce[24];
    Bits_memset(nonce, 0, 24);

    uint8_t secret[32];
    Bits_memset(secret, 0, 32);

    struct Message m = { .bytes=&buff[32], .length=HELLOWORLDLEN, .padding=32};
    CString_strcpy((char*) m.bytes, HELLOWORLDLOWER);

    CryptoAuth_encryptRndNonce(nonce, &m, secret);

    uint8_t* expected = (uint8_t*) "1391ac5d03ba9f7099bffbb6e6c69d67ae5bd79391a5b94399b293dc";
    uint8_t output[57];
    Hex_encode(output, 57, m.bytes, m.length);

    printf("\n%s\n%s\n", (char*) expected, (char*) output);
    Assert_true(!Bits_memcmp(expected, output, 56));

    Assert_true(!CryptoAuth_decryptRndNonce(nonce, &m, secret));
    Assert_true(m.length == HELLOWORLDLEN && !Bits_memcmp(m.bytes, HELLOWORLDLOWER, m.length));
}

static struct Random* evilRandom(struct Allocator* alloc, struct Log* logger)
{
    struct RandomSeed* evilSeed = DeterminentRandomSeed_new(alloc, NULL);
    return Random_newWithSeed(alloc, logger, evilSeed, NULL);
}

struct Context
{
    struct Allocator* alloc;
    struct CryptoAuth* ca;
    struct CryptoAuth_Session* sess;
    struct Log* log;
    struct EventBase* base;
};

static struct Context* setUp(uint8_t* myPrivateKey,
                             uint8_t* herPublicKey,
                             uint8_t* authPassword,
                             struct Allocator* alloc)
{
    struct Context* ctx = Allocator_calloc(alloc, sizeof(struct Context), 1);
    struct Log* log = ctx->log = FileWriterLog_new(stdout, alloc);
    struct EventBase* base = ctx->base = EventBase_new(alloc);
    struct CryptoAuth* ca = ctx->ca =
        CryptoAuth_new(alloc, myPrivateKey, base, log, evilRandom(alloc, log));

    struct CryptoAuth_Session* sess = ctx->sess =
        CryptoAuth_newSession(ca, alloc, herPublicKey, NULL, false, Gcc_FILE);

    if (authPassword) {
        CryptoAuth_setAuth(String_CONST(authPassword), NULL, sess);
    }

    return ctx;
}

static void testHello(uint8_t* password, uint8_t* expectedOutput)
{
    Assert_true(CString_strlen((char*)expectedOutput) == 264);
    struct Allocator* alloc = MallocAllocator_new(1<<20);
    struct Context* ctx = setUp(NULL, HERPUBKEY, password, alloc);
    struct Message* msg = Message_new(0, CryptoHeader_SIZE + 12, alloc);
    Message_push(msg, HELLOWORLD, HELLOWORLDLEN, NULL);

    Assert_true(!CryptoAuth_encrypt(ctx->sess, msg));

    char* actual = Hex_print(msg->bytes, msg->length, alloc);
    if (CString_strcmp(actual, expectedOutput)) {
        Assert_failure("Test failed.\n"
                       "Expected %s\n"
                       "     Got %s\n", expectedOutput, actual);
    }
    Allocator_free(alloc);
}
예제 #20
0
파일: Allocator.c 프로젝트: 0x20c24/cjdns
static void unroll(struct Allocator_pvt* context,
                   int includeAllocations,
                   struct Unroller* unroller)
{
    writeUnroller(unroller);
    const char* ident = (context->pub.fileName) ? context->pub.fileName : "UNKNOWN";

    fprintf(stderr, "%s:%d [%lu] bytes%s\n",
            ident,
            context->pub.lineNum,
            context->allocatedHere,
            (context->pub.isFreeing) ? " (freeing)" : "");

    struct Unroller childUnroller = {
        .content = ((context->nextSibling) ? "| " : "  "),
        .last = unroller
    };
    if (context->firstChild) {
        unroll(context->firstChild, includeAllocations, &childUnroller);
    }
    struct Allocator_Allocation_pvt* allocation = context->allocations;
    while (allocation && includeAllocations) {
        writeUnroller(&childUnroller);
        fprintf(stderr, "%s:%d [%lu] bytes at [0x%lx]\n",
                allocation->pub.fileName,
                allocation->pub.lineNum,
                allocation->pub.size,
                (long)(uintptr_t)allocation);
        allocation = allocation->next;
    }
    if (context->nextSibling) {
        unroll(context->nextSibling, includeAllocations, unroller);
    }
}

void Allocator_snapshot(struct Allocator* alloc, int includeAllocations)
{
    // get the root allocator.
    struct Allocator_pvt* rootAlloc = Identity_check((struct Allocator_pvt*)alloc);
    while (rootAlloc->parent && rootAlloc->parent != rootAlloc) {
        rootAlloc = rootAlloc->parent;
    }
    fprintf(stderr, "----- %scjdns memory snapshot -----\n", "");

    unroll(rootAlloc, includeAllocations, NULL);

    fprintf(stderr, "totalBytes [%ld] remaining [%ld]\n",
                    (long)rootAlloc->rootAlloc->maxSpace,
                    (long)rootAlloc->rootAlloc->spaceAvailable);

    fprintf(stderr, "----- %scjdns memory snapshot -----\n", "end ");
}

Gcc_NORETURN
static void failure(struct Allocator_pvt* context,
                    const char* message,
                    const char* fileName,
                    int lineNum)
{
    Allocator_snapshot(&context->pub, 1);
    Assert_failure("%s:%d Fatal error: [%s]", fileName, lineNum, message);
}