Пример #1
0
static Iface_DEFUN incomingFromUpperDistributorIf(struct Message* msg,
                                                  struct Iface* upperDistributorIf)
{
    struct TUNAdapter_pvt* ud =
        Identity_containerOf(upperDistributorIf, struct TUNAdapter_pvt, pub.upperDistributorIf);
    Assert_true(msg->length >= RouteHeader_SIZE + DataHeader_SIZE);
    struct RouteHeader* hdr = (struct RouteHeader*) msg->bytes;
    struct DataHeader* dh = (struct DataHeader*) &hdr[1];
    enum ContentType type = DataHeader_getContentType(dh);
    Assert_true(type <= ContentType_IP6_RAW);

    // Shift ip address into destination slot.
    Bits_memmoveConst(&hdr->ip6[DataHeader_SIZE - 16], hdr->ip6, 16);
    // put my address as destination.
    Bits_memcpyConst(&hdr->ip6[DataHeader_SIZE], ud->myIp6, 16);

    Message_shift(msg, Headers_IP6Header_SIZE - DataHeader_SIZE - RouteHeader_SIZE, NULL);
    struct Headers_IP6Header* ip6 = (struct Headers_IP6Header*) msg->bytes;
    Bits_memset(ip6, 0, Headers_IP6Header_SIZE - 32);
    Headers_setIpVersion(ip6);
    ip6->payloadLength_be = Endian_bigEndianToHost16(msg->length - Headers_IP6Header_SIZE);
    ip6->nextHeader = type;
    ip6->hopLimit = 42;
    TUNMessageType_push(msg, Ethernet_TYPE_IP6, NULL);
    return sendToTunIf(msg, ud);
}
Пример #2
0
static inline uint8_t incomingDHT(struct Message* message,
                                  struct Address* addr,
                                  struct Ducttape_pvt* context)
{
    struct DHTMessage dht = {
        .address = addr,
        .binMessage = message,
        .allocator = message->alloc
    };

    DHTModuleRegistry_handleIncoming(&dht, context->registry);

    // TODO(cjd): return something meaningful.
    return Error_NONE;
}

/** Header must not be encrypted and must be aligned on the beginning of the ipv6 header. */
static inline uint8_t sendToRouter(struct Message* message,
                                   struct Ducttape_MessageHeader* dtHeader,
                                   struct SessionManager_Session* session,
                                   struct Ducttape_pvt* context)
{
    int safeDistance = SwitchHeader_SIZE;

    CryptoAuth_resetIfTimeout(session->internal);
    if (CryptoAuth_getState(session->internal) < CryptoAuth_HANDSHAKE3) {
        // Put the handle into the message so that it's authenticated.
        // see: sendToSwitch()
        //Log_debug(context->logger, "Sending receive handle under CryptoAuth");
        Message_push(message, &session->receiveHandle_be, 4, NULL);

        safeDistance += CryptoHeader_SIZE;
    } else {
        // 16 for the authenticator, 4 for the nonce and 4 for the handle
        safeDistance += 24;
    }

    Message_shift(message, safeDistance, NULL);
    if (dtHeader->switchHeader) {
        if (message->bytes != (uint8_t*)dtHeader->switchHeader) {
            Bits_memmoveConst(message->bytes, dtHeader->switchHeader, SwitchHeader_SIZE);
            dtHeader->switchHeader = (struct SwitchHeader*) message->bytes;
        }
    } else {
        dtHeader->switchHeader = (struct SwitchHeader*) message->bytes;
        Bits_memset(dtHeader->switchHeader, 0, SwitchHeader_SIZE);
    }
    Message_shift(message, -safeDistance, NULL);

    SwitchHeader_setVersion(dtHeader->switchHeader, SwitchHeader_CURRENT_VERSION);
    SwitchHeader_setLabelShift(dtHeader->switchHeader, 0);
    dtHeader->switchHeader->label_be = Endian_hostToBigEndian64(dtHeader->switchLabel);

    // This comes out in outgoingFromCryptoAuth() then sendToSwitch()
    dtHeader->receiveHandle = Endian_bigEndianToHost32(session->receiveHandle_be);
    dtHeader->layer = Ducttape_SessionLayer_OUTER;
    return Interface_sendMessage(session->internal, message);
}
Пример #3
0
/** Header must not be encrypted and must be aligned on the beginning of the ipv6 header. */
static inline uint8_t sendToRouter(struct Message* message,
                                   struct Ducttape_MessageHeader* dtHeader,
                                   struct SessionManager_Session* session,
                                   struct Ducttape_pvt* context)
{
    int safeDistance = Headers_SwitchHeader_SIZE;

    if (CryptoAuth_getState(&session->iface) < CryptoAuth_HANDSHAKE3) {
        // Bug 104, see Version.h
        #ifdef Version_2_COMPAT
        if (session->version >= 3) {
        #endif
            // Put the handle into the message so that it's authenticated.
            // see: sendToSwitch()
            Log_debug(context->logger, "Sending receive handle under CryptoAuth");
            Message_push(message, &session->receiveHandle_be, 4);
        #ifdef Version_2_COMPAT
        } else {
            // Otherwise it will be added on the other side.
            safeDistance += 4;
        }
        #endif

        safeDistance += Headers_CryptoAuth_SIZE;
    } else {
        // 16 for the authenticator, 4 for the nonce and 4 for the handle
        safeDistance += 24;
    }

    Message_shift(message, safeDistance);
    if (dtHeader->switchHeader) {
        if (message->bytes != (uint8_t*)dtHeader->switchHeader) {
            Bits_memmoveConst(message->bytes, dtHeader->switchHeader, Headers_SwitchHeader_SIZE);
            dtHeader->switchHeader = (struct Headers_SwitchHeader*) message->bytes;
        }
    } else {
        dtHeader->switchHeader = (struct Headers_SwitchHeader*) message->bytes;
        Bits_memset(dtHeader->switchHeader, 0, Headers_SwitchHeader_SIZE);
    }
    Message_shift(message, -safeDistance);

    dtHeader->switchHeader->label_be = Endian_hostToBigEndian64(dtHeader->switchLabel);


    // This comes out in outgoingFromCryptoAuth() then sendToSwitch()
    dtHeader->receiveHandle = Endian_bigEndianToHost32(session->receiveHandle_be);
    dtHeader->layer = Ducttape_SessionLayer_OUTER;
    return session->iface.sendMessage(message, &session->iface);
}
Пример #4
0
static Iface_DEFUN incomingFromTunIf(struct Message* msg, struct Iface* tunIf)
{
    struct TUNAdapter_pvt* ud = Identity_containerOf(tunIf, struct TUNAdapter_pvt, pub.tunIf);

    uint16_t ethertype = TUNMessageType_pop(msg, NULL);

    int version = Headers_getIpVersion(msg->bytes);
    if ((ethertype == Ethernet_TYPE_IP4 && version != 4)
        || (ethertype == Ethernet_TYPE_IP6 && version != 6))
    {
        Log_debug(ud->log, "DROP packet because ip version [%d] "
                  "doesn't match ethertype [%u].", version, Endian_bigEndianToHost16(ethertype));
        return NULL;
    }

    if (ethertype == Ethernet_TYPE_IP4) {
        return Iface_next(&ud->pub.ipTunnelIf, msg);
    }
    if (ethertype != Ethernet_TYPE_IP6) {
        Log_debug(ud->log, "DROP packet unknown ethertype [%u]",
                  Endian_bigEndianToHost16(ethertype));
        return NULL;
    }

    if (msg->length < Headers_IP6Header_SIZE) {
        Log_debug(ud->log, "DROP runt");
        return NULL;
    }

    struct Headers_IP6Header* header = (struct Headers_IP6Header*) msg->bytes;
    if (!AddressCalc_validAddress(header->destinationAddr)) {
        return Iface_next(&ud->pub.ipTunnelIf, msg);
    }
    if (Bits_memcmp(header->sourceAddr, ud->myIp6, 16)) {
        if (Defined(Log_DEBUG)) {
            uint8_t expectedSource[40];
            AddrTools_printIp(expectedSource, ud->myIp6);
            uint8_t packetSource[40];
            AddrTools_printIp(packetSource, header->sourceAddr);
            Log_debug(ud->log,
                      "DROP packet from [%s] because all messages must have source address [%s]",
                      packetSource, expectedSource);
        }
        return NULL;
    }
    if (!Bits_memcmp(header->destinationAddr, ud->myIp6, 16)) {
        // I'm Gonna Sit Right Down and Write Myself a Letter
        TUNMessageType_push(msg, ethertype, NULL);
        return Iface_next(tunIf, msg);
    }
    if (!Bits_memcmp(header->destinationAddr, "\xfc\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01", 16)) {
        return Iface_next(&ud->pub.magicIf, msg);
    }

    // first move the dest addr to the right place.
    Bits_memmoveConst(&header->destinationAddr[-DataHeader_SIZE], header->destinationAddr, 16);

    Message_shift(msg, DataHeader_SIZE + RouteHeader_SIZE - Headers_IP6Header_SIZE, NULL);
    struct RouteHeader* rh = (struct RouteHeader*) msg->bytes;

    struct DataHeader* dh = (struct DataHeader*) &rh[1];
    Bits_memset(dh, 0, DataHeader_SIZE);
    DataHeader_setContentType(dh, header->nextHeader);
    DataHeader_setVersion(dh, DataHeader_CURRENT_VERSION);

    // Other than the ipv6 addr at the end, everything is zeros right down the line.
    Bits_memset(rh, 0, RouteHeader_SIZE - 16);

    return Iface_next(&ud->pub.upperDistributorIf, msg);
}
Пример #5
0
// 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);
}
Пример #6
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);
}