示例#1
0
static void lookup(Dict* args, void* vcontext, String* txid)
{
    struct Context* ctx = vcontext;
    String* addrStr = Dict_getString(args, String_CONST("address"));
    char* err = NULL;
    uint8_t addr[16];
    uint8_t resultBuff[60];
    char* result = (char*) resultBuff;
    if (addrStr->len != 39) {
        err = "address wrong length";
    } else if (AddrTools_parseIp(addr, (uint8_t*) addrStr->bytes)) {
        err = "failed to parse address";
    } else {
        struct Node* n = RouterModule_lookup(addr, ctx->routerModule);
        if (!n) {
            result = "not found";
        } else if (memcmp(addr, n->address.ip6.bytes, 16)) {
            Address_print(resultBuff, &n->address);
        } else {
            AddrTools_printPath(resultBuff, n->address.path);
        }
    }
    Dict response = Dict_CONST(
        String_CONST("error"), String_OBJ(String_CONST((err) ? err : "none")), Dict_CONST(
        String_CONST("result"), String_OBJ(String_CONST(result)), NULL
    ));
    Admin_sendMessage(&response, txid, ctx->admin);
}
示例#2
0
文件: Ducttape.c 项目: coinmint/cjdns
// Called by the TUN device.
static inline uint8_t ip6FromTun(struct Message* message,
                                 struct Interface* interface)
{
    struct Ducttape* context = (struct Ducttape*) interface->receiverContext;

    struct Headers_IP6Header* header = (struct Headers_IP6Header*) message->bytes;

    if (memcmp(header->sourceAddr, context->myAddr.ip6.bytes, 16)) {
        Log_warn(context->logger, "dropped message because only one address is allowed to be used "
                                  "and the source address was different.\n");
        return Error_INVALID;
    }
    if (!memcmp(header->destinationAddr, context->myAddr.ip6.bytes, 16)) {
        // I'm Gonna Sit Right Down and Write Myself a Letter
        interface->sendMessage(message, interface);
        return Error_NONE;
    }

    context->switchHeader = NULL;

    struct Node* bestNext = RouterModule_lookup(header->destinationAddr, context->routerModule);
    if (bestNext) {
        context->forwardTo = &bestNext->address;
        if (!memcmp(header->destinationAddr, bestNext->address.ip6.bytes, 16)) {
            // Direct send, skip the innermost layer of encryption.
            #ifdef Log_DEBUG
                uint8_t nhAddr[60];
                Address_print(nhAddr, &bestNext->address);
                Log_debug1(context->logger, "Forwarding data to %s (last hop)\n", nhAddr);
            #endif
            return sendToRouter(&bestNext->address, message, context);
        }
    }

    // Grab out the header so it doesn't get clobbered.
    struct Headers_IP6Header headerStore;
    Bits_memcpyConst(&headerStore, header, Headers_IP6Header_SIZE);
    context->ip6Header = &headerStore;

    // Shift over the content.
    Message_shift(message, -Headers_IP6Header_SIZE);

    struct Interface* session =
        SessionManager_getSession(headerStore.destinationAddr, NULL, context->sm);

    // This comes out at outgoingFromMe()
    context->layer = INNER_LAYER;
    return session->sendMessage(message, session);
}
示例#3
0
文件: Ducttape.c 项目: wpapper/cjdns
/**
 * Send an arbitrary message to a node.
 *
 * @param message to be sent, must be prefixed with IpTunnel_PacketInfoHeader.
 * @param iface an interface for which receiverContext is the ducttape.
 */
static uint8_t sendToNode(struct Message* message, struct Interface* iface)
{
    struct Ducttape_pvt* context = Identity_cast((struct Ducttape_pvt*)iface->receiverContext);
    struct Ducttape_MessageHeader* dtHeader = getDtHeader(message, true);
    struct IpTunnel_PacketInfoHeader* header = (struct IpTunnel_PacketInfoHeader*) message->bytes;
    Message_shift(message, -IpTunnel_PacketInfoHeader_SIZE);
    struct Node* n = RouterModule_lookup(header->nodeIp6Addr, context->routerModule);
    if (n) {
        if (!Bits_memcmp(header->nodeKey, n->address.key, 32)) {
            // Found the node.
            #ifdef Log_DEBUG
                uint8_t nhAddr[60];
                Address_print(nhAddr, &n->address);
                Log_debug(context->logger, "Sending arbitrary data to [%s]", nhAddr);
            #endif

            struct SessionManager_Session* session =
                SessionManager_getSession(n->address.ip6.bytes, n->address.key, context->sm);

            n->version = session->version = (n->version > session->version)
                ? n->version : session->version;

            dtHeader->switchLabel = n->address.path;
            return sendToRouter(message, dtHeader, session, context);
        }
    }

    #ifdef Log_DEBUG
        uint8_t printedIp6[40];
        AddrTools_printIp(printedIp6, header->nodeIp6Addr);
        Log_debug(context->logger, "Couldn't find node [%s] for sending to.", printedIp6);
    #endif

    // Now lets trigger a search for this node.
    uint64_t now = Time_currentTimeMilliseconds(context->eventBase);
    if (context->timeOfLastSearch + context->timeBetweenSearches < now) {
        context->timeOfLastSearch = now;
        RouterModule_search(header->nodeIp6Addr, context->routerModule, context->alloc);
    }
    return 0;
}
示例#4
0
文件: Ducttape.c 项目: coinmint/cjdns
/**
 * Messages with content encrypted and header decrypted are sent here to be forwarded.
 * they may come from us, or from another node and may be to us or to any other node.
 * Message is aligned on the beginning of the ipv6 header.
 */
static inline int core(struct Message* message, struct Ducttape* context)
{
    context->ip6Header = (struct Headers_IP6Header*) message->bytes;

    if (isForMe(message, context)) {
        Message_shift(message, -Headers_IP6Header_SIZE);

        if (memcmp(context->routerAddress, context->ip6Header->sourceAddr, 16)) {
            // triple encrypted
            // This call goes to incomingForMe()
            context->layer = INNER_LAYER;
            context->session =
                SessionManager_getSession(context->ip6Header->sourceAddr, NULL, context->sm);
            return context->session->receiveMessage(message, context->session);
        } else {
            // double encrypted, inner layer plaintext.
            // The session is still set from the router-to-router traffic and that is the one we use
            // to determine the node's id.
            return incomingForMe(message, context, CryptoAuth_getHerPublicKey(context->session));
        }
    }

    if (context->ip6Header->hopLimit == 0) {
        Log_debug(context->logger, "dropped message because hop limit has been exceeded.\n");
        // TODO: send back an error message in response.
        return Error_UNDELIVERABLE;
    }
    context->ip6Header->hopLimit--;

    struct Address* ft = context->forwardTo;
    context->forwardTo = NULL;
    if (!ft) {
        struct Node* bestNext =
            RouterModule_lookup(context->ip6Header->destinationAddr, context->routerModule);
        if (bestNext) {
            ft = &bestNext->address;
        }
    }

    if (ft) {
        #ifdef Log_DEBUG
            uint8_t nhAddr[60];
            Address_print(nhAddr, ft);
            if (memcmp(context->ip6Header->destinationAddr, ft->ip6.bytes, 16)) {
                // Potentially forwarding for ourselves.
                struct Address destination;
                Bits_memcpyConst(destination.ip6.bytes, context->ip6Header->destinationAddr, 16);
                uint8_t ipAddr[40];
                Address_printIp(ipAddr, &destination);
                Log_debug2(context->logger, "Forwarding data to %s via %s\n", ipAddr, nhAddr);
            } else {
                // Definitely forwarding on behalf of someone else.
                Log_debug1(context->logger, "Forwarding data to %s (last hop)\n", nhAddr);
            }
        #endif
        return sendToRouter(ft, message, context);
    }
    Log_debug(context->logger, "Dropped message because this node is the closest known "
                               "node to the destination.\n");
    return Error_UNDELIVERABLE;
}
示例#5
0
static void pingNode(Dict* args, void* vctx, String* txid, struct Allocator* requestAlloc)
{
    struct Context* ctx = Identity_cast((struct Context*) vctx);
    String* pathStr = Dict_getString(args, String_CONST("path"));
    int64_t* timeoutPtr = Dict_getInt(args, String_CONST("timeout"));
    uint32_t timeout = (timeoutPtr && *timeoutPtr > 0) ? *timeoutPtr : 0;

    char* err = NULL;

    struct Address addr = {.path=0};
    struct Node* n = NULL;

    if (pathStr->len == 19 && !AddrTools_parsePath(&addr.path, (uint8_t*) pathStr->bytes)) {
        n = RouterModule_getNode(addr.path, ctx->router);
    } else if (!AddrTools_parseIp(addr.ip6.bytes, (uint8_t*) pathStr->bytes)) {
        n = RouterModule_lookup(addr.ip6.bytes, ctx->router);
        if (n && Bits_memcmp(addr.ip6.bytes, n->address.ip6.bytes, 16)) {
            n = NULL;
        }
    } else {
        err = "Unexpected address, must be either an ipv6 address "
              "eg: 'fc4f:d:e499:8f5b:c49f:6e6b:1ae:3120', 19 char path eg: '0123.4567.89ab.cdef'";
    }

    if (!err) {
        if (!n) {
            err = "could not find node to ping";
        } else {
            struct RouterModule_Promise* rp =
                RouterModule_pingNode(n, timeout, ctx->router, ctx->allocator);
            struct Ping* ping = Allocator_calloc(rp->alloc, sizeof(struct Ping), 1);
            Identity_set(ping);
            ping->txid = String_clone(txid, rp->alloc);
            ping->rp = rp;
            ping->ctx = ctx;
            rp->userData = ping;
            rp->callback = pingResponse;
        }
    }

    if (err) {
        Dict errDict = Dict_CONST(String_CONST("error"), String_OBJ(String_CONST(err)), NULL);
        Admin_sendMessage(&errDict, txid, ctx->admin);
    }
}

void RouterModule_admin_register(struct RouterModule* module,
                                 struct Admin* admin,
                                 struct Allocator* alloc)
{
    struct Context* ctx = Allocator_clone(alloc, (&(struct Context) {
        .admin = admin,
        .allocator = alloc,
        .router = module
    }));
    Identity_set(ctx);

    Admin_registerFunction("RouterModule_lookup", lookup, ctx, true,
        ((struct Admin_FunctionArg[]) {
            { .name = "address", .required = 1, .type = "String" }
        }), admin);
示例#6
0
文件: Ducttape.c 项目: wpapper/cjdns
/**
 * Messages with content encrypted and header decrypted are sent here to be forwarded.
 * they may come from us, or from another node and may be to us or to any other node.
 * Message is aligned on the beginning of the ipv6 header.
 */
static inline int core(struct Message* message,
                       struct Ducttape_MessageHeader* dtHeader,
                       struct SessionManager_Session* session,
                       struct Ducttape_pvt* context)
{
    struct Headers_IP6Header* ip6Header = (struct Headers_IP6Header*) message->bytes;
    dtHeader->ip6Header = ip6Header;

    if (isForMe(message, context)) {
        Message_shift(message, -Headers_IP6Header_SIZE);

        if (Bits_memcmp(session->ip6, ip6Header->sourceAddr, 16)) {
            // triple encrypted
            // This call goes to incomingForMe()
            struct SessionManager_Session* session =
                SessionManager_getSession(ip6Header->sourceAddr, NULL, context->sm);

            #ifdef Log_DEBUG
                uint8_t addr[40];
                AddrTools_printIp(addr, ip6Header->sourceAddr);
                Log_debug(context->logger, "Incoming layer3 message, ostensibly from [%s]", addr);
            #endif

            dtHeader->receiveHandle = Endian_bigEndianToHost32(session->receiveHandle_be);
            dtHeader->layer = Ducttape_SessionLayer_INNER;
            return session->iface.receiveMessage(message, &session->iface);
        } else {
            // double encrypted, inner layer plaintext.
            // The session is still set from the router-to-router traffic and that is the one we use
            // to determine the node's id.
            return incomingForMe(message, dtHeader, session, context,
                                 CryptoAuth_getHerPublicKey(&session->iface));
        }
    }

    if (ip6Header->hopLimit == 0) {
        Log_debug(context->logger, "dropped message because hop limit has been exceeded.\n");
        // TODO: send back an error message in response.
        return Error_UNDELIVERABLE;
    }
    ip6Header->hopLimit--;

    struct SessionManager_Session* nextHopSession = NULL;
    if (!dtHeader->nextHopReceiveHandle || !dtHeader->switchLabel) {
        struct Node* n = RouterModule_lookup(ip6Header->destinationAddr, context->routerModule);
        if (n) {
            nextHopSession =
                SessionManager_getSession(n->address.ip6.bytes, n->address.key, context->sm);
            dtHeader->switchLabel = n->address.path;
        }
    } else {
        nextHopSession =
            SessionManager_sessionForHandle(dtHeader->nextHopReceiveHandle, context->sm);
    }

    if (nextHopSession) {
        #ifdef Log_DEBUG
            struct Address addr;
            Bits_memcpyConst(addr.ip6.bytes, nextHopSession->ip6, 16);
            addr.path = dtHeader->switchLabel;
            uint8_t nhAddr[60];
            Address_print(nhAddr, &addr);
            if (Bits_memcmp(ip6Header->destinationAddr, addr.ip6.bytes, 16)) {
                // Potentially forwarding for ourselves.
                struct Address destination;
                Bits_memcpyConst(destination.ip6.bytes, ip6Header->destinationAddr, 16);
                uint8_t ipAddr[40];
                Address_printIp(ipAddr, &destination);
                Log_debug(context->logger, "Forwarding data to %s via %s\n", ipAddr, nhAddr);
            } else {
                // Definitely forwarding on behalf of someone else.
                Log_debug(context->logger, "Forwarding data to %s (last hop)\n", nhAddr);
            }
        #endif
        return sendToRouter(message, dtHeader, nextHopSession, context);
    }

    #ifdef Log_INFO
        struct Address destination;
        Bits_memcpyConst(destination.ip6.bytes, ip6Header->destinationAddr, 16);
        uint8_t ipAddr[40];
        Address_printIp(ipAddr, &destination);
        Log_info(context->logger, "Dropped message because this node is the closest known "
                                   "node to the destination %s.", ipAddr);
    #endif
    return Error_UNDELIVERABLE;
}
示例#7
0
文件: Ducttape.c 项目: wpapper/cjdns
// Called by the TUN device.
static inline uint8_t incomingFromTun(struct Message* message,
                                      struct Interface* iface)
{
    struct Ducttape_pvt* context = Identity_cast((struct Ducttape_pvt*) iface->receiverContext);

    uint16_t ethertype = TUNMessageType_pop(message);

    struct Headers_IP6Header* header = (struct Headers_IP6Header*) message->bytes;

    int version = Headers_getIpVersion(message->bytes);
    if ((ethertype == Ethernet_TYPE_IP4 && version != 4)
        || (ethertype == Ethernet_TYPE_IP6 && version != 6))
    {
        Log_warn(context->logger, "dropped packet because ip version [%d] "
                 "doesn't match ethertype [%u].", version, Endian_bigEndianToHost16(ethertype));
        return Error_INVALID;
    }

    if (ethertype != Ethernet_TYPE_IP6 || !AddressCalc_validAddress(header->sourceAddr)) {
        return context->ipTunnel->tunInterface.sendMessage(message,
                                                           &context->ipTunnel->tunInterface);
    }

    if (Bits_memcmp(header->sourceAddr, context->myAddr.ip6.bytes, 16)) {
        uint8_t expectedSource[40];
        AddrTools_printIp(expectedSource, context->myAddr.ip6.bytes);
        uint8_t packetSource[40];
        AddrTools_printIp(packetSource, header->sourceAddr);
        Log_warn(context->logger,
                 "dropped packet from [%s] because all messages must have source address [%s]",
                 (char*) packetSource, (char*) expectedSource);
        return Error_INVALID;
    }
    if (!Bits_memcmp(header->destinationAddr, context->myAddr.ip6.bytes, 16)) {
        // I'm Gonna Sit Right Down and Write Myself a Letter
        TUNMessageType_push(message, ethertype);
        iface->sendMessage(message, iface);
        return Error_NONE;
    }

    struct Ducttape_MessageHeader* dtHeader = getDtHeader(message, true);

    struct Node* bestNext = RouterModule_lookup(header->destinationAddr, context->routerModule);
    struct SessionManager_Session* nextHopSession;
    if (bestNext) {
        nextHopSession = SessionManager_getSession(bestNext->address.ip6.bytes,
                                                   bestNext->address.key,
                                                   context->sm);

        bestNext->version = nextHopSession->version = (bestNext->version > nextHopSession->version)
            ? bestNext->version : nextHopSession->version;

        dtHeader->switchLabel = bestNext->address.path;
        dtHeader->nextHopReceiveHandle = Endian_bigEndianToHost32(nextHopSession->receiveHandle_be);

        if (!Bits_memcmp(header->destinationAddr, bestNext->address.ip6.bytes, 16)) {
            // Direct send, skip the innermost layer of encryption.
            #ifdef Log_DEBUG
                uint8_t nhAddr[60];
                Address_print(nhAddr, &bestNext->address);
                Log_debug(context->logger, "Forwarding data to %s (last hop)\n", nhAddr);
            #endif
            return sendToRouter(message, dtHeader, nextHopSession, context);
        }
        // else { the message will need to be 3 layer encrypted but since we already did a lookup
        // of the best node to forward to, we can skip doing another lookup by storing a pointer
        // to that node in the context (bestNext).
    } else {
        #ifdef Log_WARN
            uint8_t thisAddr[40];
            uint8_t destAddr[40];
            AddrTools_printIp(thisAddr, context->myAddr.ip6.bytes);
            AddrTools_printIp(destAddr, header->destinationAddr);
            Log_warn(context->logger,
                     "Dropped message from TUN because this node [%s] is closest to dest [%s]",
                     thisAddr, destAddr);
        #endif
        return Error_UNDELIVERABLE;
    }

    #ifdef Log_DEBUG
        uint8_t destAddr[40];
        AddrTools_printIp(destAddr, header->destinationAddr);
        uint8_t nhAddr[60];
        Address_print(nhAddr, &bestNext->address);
        Log_debug(context->logger, "Sending to [%s] via [%s]", destAddr, nhAddr);
    #endif

    struct SessionManager_Session* session =
        SessionManager_getSession(header->destinationAddr, NULL, context->sm);

    // Copy the IP6 header back from where the CA header will be placed.
    // this is a mess.
    // We can't just copy the header to a safe place because the CryptoAuth
    // might buffer the message and send a connect-to-me packet and when the
    // hello packet comes in return, the CA will send the message and the header
    // needs to be in the message buffer.
    //
    // The CryptoAuth may send a 120 byte CA header and it might only send a 4 byte
    // nonce and 16 byte authenticator depending on its state.

    if (CryptoAuth_getState(&session->iface) < CryptoAuth_HANDSHAKE3) {
        // shift, copy, shift because shifting asserts that there is enough buffer space.
        Message_shift(message, Headers_CryptoAuth_SIZE + 4);
        Bits_memcpyConst(message->bytes, header, Headers_IP6Header_SIZE);
        Message_shift(message, -(Headers_IP6Header_SIZE + Headers_CryptoAuth_SIZE + 4));
        // now push the receive handle *under* the CA header.
        Message_push(message, &session->receiveHandle_be, 4);
        debugHandles0(context->logger, session, "layer3 sending start message");
    } else {
        // shift, copy, shift because shifting asserts that there is enough buffer space.
        Message_shift(message, 20);
        Bits_memmoveConst(message->bytes, header, Headers_IP6Header_SIZE);
        Message_shift(message, -(20 + Headers_IP6Header_SIZE));
        debugHandles0(context->logger, session, "layer3 sending run message");
    }

    // This comes out at outgoingFromCryptoAuth() then outgoingFromMe()
    dtHeader->receiveHandle = Endian_bigEndianToHost32(session->receiveHandle_be);
    dtHeader->layer = Ducttape_SessionLayer_INNER;
    return session->iface.sendMessage(message, &session->iface);
}