Example #1
0
/**
 * This is called as sendMessage() by the switch.
 * There is only one switch interface which sends all traffic.
 * message is aligned on the beginning of the switch header.
 */
static uint8_t incomingFromSwitch(struct Message* message, struct Interface* switchIf)
{
    struct Ducttape* context = switchIf->senderContext;
    struct Headers_SwitchHeader* switchHeader = (struct Headers_SwitchHeader*) message->bytes;
    Message_shift(message, -Headers_SwitchHeader_SIZE);

    // The label comes in reversed from the switch because the switch doesn't know that we aren't
    // another switch ready to parse more bits, bit reversing the label yields the source address.
    switchHeader->label_be = Bits_bitReverse64(switchHeader->label_be);

    if (Headers_getMessageType(switchHeader) == Headers_SwitchHeader_TYPE_CONTROL) {
        uint8_t labelStr[20];
        uint64_t label = Endian_bigEndianToHost64(switchHeader->label_be);
        AddrTools_printPath(labelStr, label);
        if (message->length < Control_HEADER_SIZE) {
            Log_info1(context->logger, "dropped runt ctrl packet from [%s]", labelStr);
            return Error_NONE;
        } else {
            Log_debug1(context->logger, "ctrl packet from [%s]", labelStr);
        }
        struct Control* ctrl = (struct Control*) message->bytes;
        bool pong = false;
        if (ctrl->type_be == Control_ERROR_be) {
            if (message->length < Control_Error_MIN_SIZE) {
                Log_info1(context->logger, "dropped runt error packet from [%s]", labelStr);
                return Error_NONE;
            }
            Log_info2(context->logger,
                      "error packet from [%s], error type [%d]",
                      labelStr,
                      Endian_bigEndianToHost32(ctrl->content.error.errorType_be));

            RouterModule_brokenPath(Endian_bigEndianToHost64(switchHeader->label_be),
                                    context->routerModule);

            uint8_t causeType = Headers_getMessageType(&ctrl->content.error.cause);
            if (causeType == Headers_SwitchHeader_TYPE_CONTROL) {
                if (message->length < Control_Error_MIN_SIZE + Control_HEADER_SIZE) {
                    Log_info1(context->logger,
                              "error packet from [%s] containing runt cause packet",
                              labelStr);
                    return Error_NONE;
                }
                struct Control* causeCtrl = (struct Control*) &(&ctrl->content.error.cause)[1];
                if (causeCtrl->type_be != Control_PING_be) {
                    Log_info3(context->logger,
                              "error packet from [%s] caused by [%s] packet ([%d])",
                              labelStr,
                              Control_typeString(causeCtrl->type_be),
                              Endian_bigEndianToHost16(causeCtrl->type_be));
                } else {
                    Log_debug2(context->logger,
                               "error packet from [%s] in response to ping, length: [%d].",
                               labelStr,
                               message->length);
                    // errors resulting from pings are forwarded back to the pinger.
                    pong = true;
                }
            } else if (causeType != Headers_SwitchHeader_TYPE_DATA) {
                Log_info1(context->logger,
                          "error packet from [%s] containing cause of unknown type [%d]",
                          labelStr);
            }
        } else if (ctrl->type_be == Control_PONG_be) {
            pong = true;
        } else if (ctrl->type_be == Control_PING_be) {
            ctrl->type_be = Control_PONG_be;
            Message_shift(message, Headers_SwitchHeader_SIZE);
            switchIf->receiveMessage(message, switchIf);
        } else {
            Log_info2(context->logger,
                      "control packet of unknown type from [%s], type [%d]",
                      labelStr, Endian_bigEndianToHost16(ctrl->type_be));
        }

        if (pong) {
            // Shift back over the header
            Message_shift(message, Headers_SwitchHeader_SIZE);
            context->switchPingerIf->receiveMessage(message, context->switchPingerIf);
        }
        return Error_NONE;
    }

    uint8_t* herKey = extractPublicKey(message, switchHeader->label_be, context->logger);
    int herAddrIndex;
    if (herKey) {
        uint8_t herAddrStore[16];
        AddressCalc_addressForPublicKey(herAddrStore, herKey);
        if (herAddrStore[0] != 0xFC) {
            Log_debug(context->logger,
                      "Got message from peer whose address is not in fc00::/8 range.\n");
            return 0;
        }
        herAddrIndex = AddressMapper_put(switchHeader->label_be, herAddrStore, &context->addrMap);
    } else {
        herAddrIndex = AddressMapper_indexOf(switchHeader->label_be, &context->addrMap);
        if (herAddrIndex == -1) {
            uint64_t label = Endian_bigEndianToHost64(switchHeader->label_be);
            struct Node* n = RouterModule_getNode(label, context->routerModule);
            if (n) {
                herAddrIndex = AddressMapper_put(switchHeader->label_be,
                                                 n->address.ip6.bytes,
                                                 &context->addrMap);
            } else {
                #ifdef Log_DEBUG
                    uint8_t switchAddr[20];
                    AddrTools_printPath(switchAddr, Endian_bigEndianToHost64(switchHeader->label_be));
                    Log_debug1(context->logger,
                               "Dropped traffic packet from unknown node. (%s)\n",
                               &switchAddr);
                #endif
                return 0;
            }
        }
    }

    // If the source address is the same as the router address, no third layer of crypto.
    context->routerAddress = context->addrMap.entries[herAddrIndex].address;

    // This is needed so that the priority and other information
    // from the switch header can be passed on properly.
    context->switchHeader = switchHeader;

    context->session = SessionManager_getSession(context->routerAddress, herKey, context->sm);

    // This goes to incomingFromCryptoAuth()
    // then incomingFromRouter() then core()
    context->layer = OUTER_LAYER;
    context->session->receiveMessage(message, context->session);

    return 0;
}
Example #2
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);
Example #3
0
static inline int incomingFromRouter(struct Message* message,
                                     struct Ducttape_MessageHeader* dtHeader,
                                     struct SessionManager_Session* session,
                                     struct Ducttape_pvt* context)
{
    uint8_t* pubKey = CryptoAuth_getHerPublicKey(&session->iface);
    if (!validEncryptedIP6(message)) {
        // Not valid cjdns IPv6, we'll try it as an IPv4 or ICANN-IPv6 packet
        // and check if we have an agreement with the node who sent it.
        Message_shift(message, IpTunnel_PacketInfoHeader_SIZE);
        struct IpTunnel_PacketInfoHeader* header =
            (struct IpTunnel_PacketInfoHeader*) message->bytes;

        uint8_t* addr = session->ip6;
        Bits_memcpyConst(header->nodeIp6Addr, addr, 16);
        Bits_memcpyConst(header->nodeKey, pubKey, 32);

        struct Interface* ipTun = &context->ipTunnel->nodeInterface;
        return ipTun->sendMessage(message, ipTun);
    }

    struct Address srcAddr = {
        .path = Endian_bigEndianToHost64(dtHeader->switchHeader->label_be)
    };
    Bits_memcpyConst(srcAddr.key, pubKey, 32);

    //Log_debug(context->logger, "Got message from router.\n");
    int ret = core(message, dtHeader, session, context);

    struct Node* n = RouterModule_getNode(srcAddr.path, context->routerModule);
    if (!n) {
        Address_getPrefix(&srcAddr);
        RouterModule_addNode(context->routerModule, &srcAddr, session->version);
    } else {
        n->reach += 1;
        RouterModule_updateReach(n, context->routerModule);
    }

    return ret;
}


static uint8_t incomingFromCryptoAuth(struct Message* message, struct Interface* iface)
{
    struct Ducttape_pvt* context = Identity_cast((struct Ducttape_pvt*) iface->receiverContext);
    struct Ducttape_MessageHeader* dtHeader = getDtHeader(message, false);
    enum Ducttape_SessionLayer layer = dtHeader->layer;
    dtHeader->layer = Ducttape_SessionLayer_INVALID;
    struct SessionManager_Session* session =
        SessionManager_sessionForHandle(dtHeader->receiveHandle, context->sm);

    if (!session) {
        // This should never happen but there's no strong preventitive.
        Log_info(context->logger, "SESSION DISAPPEARED!");
        return 0;
    }

    // If the packet came from a new session, put the send handle in the session.
    if (CryptoAuth_getState(iface) < CryptoAuth_ESTABLISHED) {
        // If this is true then the incoming message is definitely a handshake.
        if (message->length < 4) {
            debugHandles0(context->logger, session, "runt");
            return Error_INVALID;
        }
        if (layer == Ducttape_SessionLayer_OUTER) {
            #ifdef Version_2_COMPAT
            if (dtHeader->currentSessionVersion >= 3) {
                session->version = dtHeader->currentSessionVersion;
            #endif
                Message_pop(message, &session->sendHandle_be, 4);
            #ifdef Version_2_COMPAT
            } else {
                session->sendHandle_be = dtHeader->currentSessionSendHandle_be;
            }
            #endif
        } else {
            // inner layer, always grab the handle
            Message_pop(message, &session->sendHandle_be, 4);
            debugHandles0(context->logger, session, "New session, incoming layer3");
        }
    }

    switch (layer) {
        case Ducttape_SessionLayer_OUTER:
            return incomingFromRouter(message, dtHeader, session, context);
        case Ducttape_SessionLayer_INNER:
            return incomingForMe(message, dtHeader, session, context,
                                 CryptoAuth_getHerPublicKey(iface));
        default:
            Assert_always(false);
    }
    // never reached.
    return 0;
}

static uint8_t outgoingFromCryptoAuth(struct Message* message, struct Interface* iface)
{
    struct Ducttape_pvt* context = Identity_cast((struct Ducttape_pvt*) iface->senderContext);
    struct Ducttape_MessageHeader* dtHeader = getDtHeader(message, false);
    struct SessionManager_Session* session =
        SessionManager_sessionForHandle(dtHeader->receiveHandle, context->sm);

    enum Ducttape_SessionLayer layer = dtHeader->layer;
    dtHeader->layer = Ducttape_SessionLayer_INVALID;

    if (!session) {
        // This should never happen but there's no strong preventitive.
        Log_info(context->logger, "SESSION DISAPPEARED!");
        return 0;
    }

    if (layer == Ducttape_SessionLayer_OUTER) {
        return sendToSwitch(message, dtHeader, session, context);
    } else if (layer == Ducttape_SessionLayer_INNER) {
        Log_debug(context->logger, "Sending layer3 message");
        return outgoingFromMe(message, dtHeader, session, context);
    } else {
        Assert_true(0);
    }
}

/**
 * Handle an incoming control message from a switch.
 *
 * @param context the ducttape context.
 * @param message the control message, this should be alligned on the beginning of the content,
 *                that is to say, after the end of the switch header.
 * @param switchHeader the header.
 * @param switchIf the interface which leads to the switch.
 */
static uint8_t handleControlMessage(struct Ducttape_pvt* context,
                                    struct Message* message,
                                    struct Headers_SwitchHeader* switchHeader,
                                    struct Interface* switchIf)
{
    uint8_t labelStr[20];
    uint64_t label = Endian_bigEndianToHost64(switchHeader->label_be);
    AddrTools_printPath(labelStr, label);
    if (message->length < Control_HEADER_SIZE) {
        Log_info(context->logger, "dropped runt ctrl packet from [%s]", labelStr);
        return Error_NONE;
    }
    struct Control* ctrl = (struct Control*) message->bytes;

    if (Checksum_engine(message->bytes, message->length)) {
        Log_info(context->logger, "ctrl packet from [%s] with invalid checksum.", labelStr);
        return Error_NONE;
    }

    bool pong = false;
    if (ctrl->type_be == Control_ERROR_be) {
        if (message->length < Control_Error_MIN_SIZE) {
            Log_info(context->logger, "dropped runt error packet from [%s]", labelStr);
            return Error_NONE;
        }

        uint64_t path = Endian_bigEndianToHost64(switchHeader->label_be);
        RouterModule_brokenPath(path, context->routerModule);

        uint8_t causeType = Headers_getMessageType(&ctrl->content.error.cause);
        if (causeType == Headers_SwitchHeader_TYPE_CONTROL) {
            if (message->length < Control_Error_MIN_SIZE + Control_HEADER_SIZE) {
                Log_info(context->logger,
                          "error packet from [%s] containing runt cause packet",
                          labelStr);
                return Error_NONE;
            }
            struct Control* causeCtrl = (struct Control*) &(&ctrl->content.error.cause)[1];
            if (causeCtrl->type_be != Control_PING_be) {
                Log_info(context->logger,
                          "error packet from [%s] caused by [%s] packet ([%u])",
                          labelStr,
                          Control_typeString(causeCtrl->type_be),
                          Endian_bigEndianToHost16(causeCtrl->type_be));
            } else {
                if (LabelSplicer_isOneHop(label)
                    && ctrl->content.error.errorType_be
                        == Endian_hostToBigEndian32(Error_UNDELIVERABLE))
                {
                    // this is our own InterfaceController complaining
                    // because the node isn't responding to pings.
                    return Error_NONE;
                }
                Log_debug(context->logger,
                           "error packet from [%s] in response to ping, err [%u], length: [%u].",
                           labelStr,
                           Endian_bigEndianToHost32(ctrl->content.error.errorType_be),
                           message->length);
                // errors resulting from pings are forwarded back to the pinger.
                pong = true;
            }
        } else if (causeType != Headers_SwitchHeader_TYPE_DATA) {
            Log_info(context->logger,
                      "error packet from [%s] containing cause of unknown type [%u]",
                      labelStr, causeType);
        } else {
            Log_info(context->logger,
                      "error packet from [%s], error type [%u]",
                      labelStr,
                      Endian_bigEndianToHost32(ctrl->content.error.errorType_be));
        }
    } else if (ctrl->type_be == Control_PONG_be) {
        pong = true;
    } else if (ctrl->type_be == Control_PING_be) {

        Message_shift(message, -Control_HEADER_SIZE);

        if (message->length < Control_Ping_MIN_SIZE) {
            Log_info(context->logger, "dropped runt ping");
            return Error_INVALID;
        }
        struct Control_Ping* ping = (struct Control_Ping*) message->bytes;
        ping->magic = Control_Pong_MAGIC;
        ping->version_be = Endian_hostToBigEndian32(Version_CURRENT_PROTOCOL);
        Message_shift(message, Control_HEADER_SIZE);

        ctrl->type_be = Control_PONG_be;
        ctrl->checksum_be = 0;
        ctrl->checksum_be = Checksum_engine(message->bytes, message->length);
        Message_shift(message, Headers_SwitchHeader_SIZE);
        Log_info(context->logger, "got switch ping from [%s]", labelStr);
        switchIf->receiveMessage(message, switchIf);
    } else {
        Log_info(context->logger,
                  "control packet of unknown type from [%s], type [%d]",
                  labelStr, Endian_bigEndianToHost16(ctrl->type_be));
    }

    if (pong && context->pub.switchPingerIf.receiveMessage) {
        // Shift back over the header
        Message_shift(message, Headers_SwitchHeader_SIZE);
        context->pub.switchPingerIf.receiveMessage(
            message, &context->pub.switchPingerIf);
    }
    return Error_NONE;
}
Example #4
0
static int handleOutgoing(struct DHTMessage* dmessage,
                          void* vcontext)
{
    struct Ducttape_pvt* context = Identity_cast((struct Ducttape_pvt*) vcontext);

    struct Message message = {
        .length = dmessage->length,
        .bytes = (uint8_t*) dmessage->bytes,
        .padding = 512,
        .capacity = DHTMessage_MAX_SIZE
    };

    Message_shift(&message, Headers_UDPHeader_SIZE);
    struct Headers_UDPHeader* uh = (struct Headers_UDPHeader*) message.bytes;
    uh->sourceAndDestPorts = 0;
    uh->length_be = Endian_hostToBigEndian16(dmessage->length);
    uh->checksum_be = 0;

    uint16_t payloadLength = message.length;

    Message_shift(&message, Headers_IP6Header_SIZE);
    struct Headers_IP6Header* header = (struct Headers_IP6Header*) message.bytes;
    header->versionClassAndFlowLabel = 0;
    header->flowLabelLow_be = 0;
    header->nextHeader = 17;
    header->hopLimit = 0;
    header->payloadLength_be = Endian_hostToBigEndian16(payloadLength);

    Bits_memcpyConst(header->sourceAddr,
                     context->myAddr.ip6.bytes,
                     Address_SEARCH_TARGET_SIZE);

    Bits_memcpyConst(header->destinationAddr,
                     dmessage->address->ip6.bytes,
                     Address_SEARCH_TARGET_SIZE);

    #ifdef Log_DEBUG
        Assert_true(!((uintptr_t)dmessage->bytes % 4) || !"alignment fault");
    #endif

    uh->checksum_be =
        Checksum_udpIp6(header->sourceAddr, (uint8_t*) uh, message.length - Headers_IP6Header_SIZE);

    struct Ducttape_MessageHeader* dtHeader = getDtHeader(&message, true);
    dtHeader->ip6Header = header;
    dtHeader->switchLabel = dmessage->address->path;

    struct SessionManager_Session* session =
        SessionManager_getSession(dmessage->address->ip6.bytes,
                                  dmessage->address->key,
                                  context->sm);
    if (session->version == Version_DEFAULT_ASSUMPTION && dmessage->replyTo) {
        int64_t* verPtr = Dict_getInt(dmessage->replyTo->asDict, String_CONST("p"));
        session->version = (verPtr) ? *verPtr : Version_DEFAULT_ASSUMPTION;
    }
    if (session->version == Version_DEFAULT_ASSUMPTION) {
        struct Node* n = RouterModule_getNode(dmessage->address->path, context->routerModule);
        if (n) {
            n->version = session->version =
                (n->version > session->version) ? n->version : session->version;
        }
    }

    sendToRouter(&message, dtHeader, session, context);

    return 0;
}

// Aligned on the beginning of the content.
static inline bool isRouterTraffic(struct Message* message, struct Headers_IP6Header* ip6)
{
    if (ip6->nextHeader != 17 || ip6->hopLimit != 0) {
        return false;
    }

    struct Headers_UDPHeader* uh = (struct Headers_UDPHeader*) message->bytes;
    return message->length >= Headers_UDPHeader_SIZE
        && uh->sourceAndDestPorts == 0
        && (int) Endian_bigEndianToHost16(uh->length_be) ==
            (message->length - Headers_UDPHeader_SIZE);
}

#define debugHandles(logger, session, message, ...) \
    do {                                                                               \
        uint8_t ip[40];                                                                \
        AddrTools_printIp(ip, session->ip6);                                           \
        Log_debug(logger, "ver[%u] send[%d] recv[%u] ip[%s] " message,                 \
                  session->version,                                                    \
                  Endian_hostToBigEndian32(session->sendHandle_be),                    \
                  Endian_hostToBigEndian32(session->receiveHandle_be),                 \
                  ip,                                                                  \
                  __VA_ARGS__);                                                        \
    } while (0)
//CHECKFILES_IGNORE expecting a ;

#define debugHandles0(logger, session, message) \
    debugHandles(logger, session, message "%s", "")

#define debugHandlesAndLabel(logger, session, label, message, ...) \
    do {                                                                               \
        uint8_t path[20];                                                              \
        AddrTools_printPath(path, label);                                              \
        debugHandles(logger, session, "path[%s] " message, path, __VA_ARGS__);         \
    } while (0)
//CHECKFILES_IGNORE expecting a ;

#define debugHandlesAndLabel0(logger, session, label, message) \
    debugHandlesAndLabel(logger, session, label, "%s", message)


/**
 * Message which is for us, message is aligned on the beginning of the content.
 * this is called from core() which calls through an interfaceMap.
 */
static inline uint8_t incomingForMe(struct Message* message,
                                    struct Ducttape_MessageHeader* dtHeader,
                                    struct SessionManager_Session* session,
                                    struct Ducttape_pvt* context,
                                    uint8_t herPublicKey[32])
{
    struct Address addr;
    Bits_memcpyConst(addr.ip6.bytes, session->ip6, 16);
    //AddressCalc_addressForPublicKey(addr.ip6.bytes, herPubKey);

    if (Bits_memcmp(addr.ip6.bytes, dtHeader->ip6Header->sourceAddr, 16)) {
        #ifdef Log_DEBUG
            uint8_t keyAddr[40];
            Address_printIp(keyAddr, &addr);
            Bits_memcpyConst(addr.ip6.bytes, dtHeader->ip6Header->sourceAddr, 16);
            uint8_t srcAddr[40];
            Address_printIp(srcAddr, &addr);
            Log_debug(context->logger,
                       "Dropped packet because source address is not same as key.\n"
                       "    %s source addr\n"
                       "    %s hash of key\n",
                       srcAddr,
                       keyAddr);
        #endif
        return Error_INVALID;
    }

    if (isRouterTraffic(message, dtHeader->ip6Header)) {
        // Check the checksum.
        struct Headers_UDPHeader* uh = (struct Headers_UDPHeader*) message->bytes;

        if (Checksum_udpIp6(dtHeader->ip6Header->sourceAddr, (uint8_t*)uh, message->length)) {
            #ifdef Log_DEBUG
                uint8_t keyAddr[40];
                Address_printIp(keyAddr, &addr);
                Log_debug(context->logger,
                          "Router packet with incorrect checksum, from [%s]", keyAddr);
            #endif
            return Error_INVALID;
        }

        // Shift off the UDP header.
        Message_shift(message, -Headers_UDPHeader_SIZE);
        addr.path = Endian_bigEndianToHost64(dtHeader->switchHeader->label_be);
        Bits_memcpyConst(addr.key, herPublicKey, 32);
        return incomingDHT(message, &addr, context);
    }

    if (!context->userIf) {
        Log_warn(context->logger,
                 "Dropping message because there is no router interface configured.\n");
        return Error_UNDELIVERABLE;
    }

    // prevent router advertizement schenanigans
    if (dtHeader->ip6Header->hopLimit == 255) {
        dtHeader->ip6Header->hopLimit--;
    }

    // Now write a message to the TUN device.
    // Need to move the ipv6 header forward up to the content because there's a crypto header
    // between the ipv6 header and the content which just got eaten.
    Message_shift(message, Headers_IP6Header_SIZE);
    uint16_t sizeDiff = message->bytes - (uint8_t*)dtHeader->ip6Header;
    if (sizeDiff) {
        dtHeader->ip6Header->payloadLength_be =
            Endian_hostToBigEndian16(
                Endian_bigEndianToHost16(dtHeader->ip6Header->payloadLength_be) - sizeDiff);
        Bits_memmoveConst(message->bytes, dtHeader->ip6Header, Headers_IP6Header_SIZE);
    }

    TUNMessageType_push(message, Ethernet_TYPE_IP6);

    context->userIf->sendMessage(message, context->userIf);
    return Error_NONE;
}

uint8_t Ducttape_injectIncomingForMe(struct Message* message,
                                     struct Ducttape* dt,
                                     uint8_t herPublicKey[32])
{
    struct Ducttape_pvt* context = Identity_cast((struct Ducttape_pvt*)dt);
    struct Ducttape_MessageHeader* dtHeader = getDtHeader(message, true);
    struct Headers_SwitchHeader sh;
    Bits_memcpyConst(&sh, message->bytes, Headers_SwitchHeader_SIZE);
    dtHeader->switchHeader = &sh;
    Message_shift(message, -Headers_SwitchHeader_SIZE);

    struct Headers_IP6Header ip6;
    Bits_memcpyConst(&ip6, message->bytes, Headers_IP6Header_SIZE);
    dtHeader->ip6Header = &ip6;
    Message_shift(message, -Headers_IP6Header_SIZE);

    struct SessionManager_Session s;
    AddressCalc_addressForPublicKey(s.ip6, herPublicKey);
    s.version = Version_CURRENT_PROTOCOL;

    return incomingForMe(message, dtHeader, &s, context, herPublicKey);
}

/**
 * Send a message to another switch.
 * Switchheader will precede the message.
 */
static inline uint8_t sendToSwitch(struct Message* message,
                                   struct Ducttape_MessageHeader* dtHeader,
                                   struct SessionManager_Session* session,
                                   struct Ducttape_pvt* context)
{
    uint64_t label = dtHeader->switchLabel;

    if (CryptoAuth_getState(&session->iface) >= CryptoAuth_HANDSHAKE3) {
        debugHandlesAndLabel0(context->logger, session, label, "layer2 sending run message");
        uint32_t sendHandle_be = session->sendHandle_be;
        #ifdef Version_2_COMPAT
        if (session->version < 3) {
            sendHandle_be |= HANDLE_FLAG_BIT_be;
        }
        #endif
        Message_push(message, &sendHandle_be, 4);
    } else {
        debugHandlesAndLabel0(context->logger, session, label, "layer2 sending start message");
        #ifdef Version_2_COMPAT
        if (session->version < 3) {
            Message_push(message, &session->receiveHandle_be, 4);
        }
        #endif
    }

    Message_shift(message, Headers_SwitchHeader_SIZE);

    Assert_true(message->bytes == (uint8_t*)dtHeader->switchHeader);

    return context->switchInterface.receiveMessage(message, &context->switchInterface);
}
Example #5
0
/**
 * This is called as sendMessage() by the switch.
 * There is only one switch interface which sends all traffic.
 * message is aligned on the beginning of the switch header.
 */
static uint8_t incomingFromSwitch(struct Message* message, struct Interface* switchIf)
{
    struct Context* context = switchIf->senderContext;
    struct Headers_SwitchHeader* switchHeader = (struct Headers_SwitchHeader*) message->bytes;
    Message_shift(message, -Headers_SwitchHeader_SIZE);

    // The label comes in reversed from the switch because the switch doesn't know that we aren't
    // another switch ready to parse more bits, bit reversing the label yields the source address.
    switchHeader->label_be = Bits_bitReverse64(switchHeader->label_be);

    if (Headers_getMessageType(switchHeader) == MessageType_CONTROL) {
        struct Control* ctrl = (struct Control*) (switchHeader + 1);
        if (ctrl->type_be == Control_ERROR_be) {
            if (memcmp(&ctrl->content.error.cause.label_be, &switchHeader->label_be, 8)) {
                Log_warn(context->logger,
                         "Different label for cause than return packet, this shouldn't happen. "
                         "Perhaps a packet was corrupted.\n");
                return 0;
            }
            uint32_t errType_be = ctrl->content.error.errorType_be;
            if (errType_be == Endian_bigEndianToHost32(Error_MALFORMED_ADDRESS)) {
                Log_info(context->logger, "Got malformed-address error, removing route.\n");
                RouterModule_brokenPath(switchHeader->label_be, context->routerModule);
                return 0;
            }
            Log_info1(context->logger,
                      "Got error packet, error type: %d",
                      Endian_bigEndianToHost32(errType_be));
        }
        return 0;
    }

    uint8_t* herKey = extractPublicKey(message, switchHeader->label_be, context->logger);
    int herAddrIndex;
    if (herKey) {
        uint8_t herAddrStore[16];
        AddressCalc_addressForPublicKey(herAddrStore, herKey);
        if (herAddrStore[0] != 0xFC) {
            Log_debug(context->logger,
                      "Got message from peer whose address is not in fc00::/8 range.\n");
            return 0;
        }
        herAddrIndex = AddressMapper_put(switchHeader->label_be, herAddrStore, &context->addrMap);
    } else {
        herAddrIndex = AddressMapper_indexOf(switchHeader->label_be, &context->addrMap);
        if (herAddrIndex == -1) {
            struct Node* n = RouterModule_getNode(switchHeader->label_be, context->routerModule);
            if (n) {
                herAddrIndex = AddressMapper_put(switchHeader->label_be,
                                                 n->address.ip6.bytes,
                                                 &context->addrMap);
            } else {
                #ifdef Log_DEBUG
                    uint8_t switchAddr[20];
                    struct Address addr;
                    addr.networkAddress_be = switchHeader->label_be;
                    Address_printNetworkAddress(switchAddr, &addr);
                    Log_debug1(context->logger,
                               "Dropped traffic packet from unknown node. (%s)\n",
                               &switchAddr);
                #endif
                return 0;
            }
        }
    }
    uint8_t* herAddr = context->addrMap.addresses[herAddrIndex];

    // This is needed so that the priority and other information
    // from the switch header can be passed on properly.
    context->switchHeader = switchHeader;

    context->session = SessionManager_getSession(herAddr, herKey, context->sm);

    // This goes to incomingFromCryptoAuth()
    // then incomingFromRouter() then core()
    context->layer = OUTER_LAYER;
    context->session->receiveMessage(message, context->session);

    return 0;
}
// Called from the pingInteral timeout.
static void pingCallback(void* vic)
{
    struct Context* ic = Identity_cast((struct Context*) vic);
    uint64_t now = Time_currentTimeMilliseconds(ic->eventBase);
    ic->pingCount++;

    // scan for endpoints have not sent anything recently.
    for (uint32_t i = 0; i < ic->peerMap.count; i++) {
        struct IFCPeer* ep = ic->peerMap.values[i];

        // This is here because of a pathological state where the connection is in ESTABLISHED
        // state but the *direct peer* has somehow been dropped from the routing table.
        // TODO: understand the cause of this issue rather than checking for it once per second.
        struct Node* peerNode = RouterModule_getNode(ep->switchLabel, ic->routerModule);

        if (now > ep->timeOfLastMessage + ic->pingAfterMilliseconds || !peerNode) {
            #ifdef Log_DEBUG
                  uint8_t key[56];
                  Base32_encode(key, 56, CryptoAuth_getHerPublicKey(ep->cryptoAuthIf), 32);
            #endif

            if (ep->isIncomingConnection
                && now > ep->timeOfLastMessage + ic->forgetAfterMilliseconds)
            {
                Log_debug(ic->logger, "Unresponsive peer [%s.k] has not responded in [%u] "
                                      "seconds, dropping connection",
                                      key, ic->forgetAfterMilliseconds / 1024);
                Allocator_free(ep->external->allocator);
                return;
            }

            bool unresponsive = (now > ep->timeOfLastMessage + ic->unresponsiveAfterMilliseconds);
            uint32_t lag = ~0u;
            if (unresponsive) {
                // flush the peer from the table...
                RouterModule_brokenPath(ep->switchLabel, ic->routerModule);

                // Lets skip 87% of pings when they're really down.
                if (ic->pingCount % 8) {
                    continue;
                }

                ep->state = InterfaceController_PeerState_UNRESPONSIVE;
                lag = ((now - ep->timeOfLastMessage) / 1024);
            } else {
                lag = ((now - ep->timeOfLastMessage) / 1024);
            }

            struct SwitchPinger_Ping* ping =
                SwitchPinger_newPing(ep->switchLabel,
                                     String_CONST(""),
                                     ic->timeoutMilliseconds,
                                     onPingResponse,
                                     ic->allocator,
                                     ic->switchPinger);

            if (!ping) {
                Log_debug(ic->logger,
                          "Failed to ping %s peer [%s.k] lag [%u], out of ping slots.",
                          (unresponsive ? "unresponsive" : "lazy"), key, lag);
                return;
            }

            ping->onResponseContext = ep;

            SwitchPinger_sendPing(ping);

            Log_debug(ic->logger,
                      "Pinging %s peer [%s.k] lag [%u]",
                      (unresponsive ? "unresponsive" : "lazy"), key, lag);
        }
    }
}