示例#1
0
static uint8_t responseWithIpCallback(struct Message* message, struct Interface* iface)
{
    struct IpTunnel_PacketInfoHeader* pi = (struct IpTunnel_PacketInfoHeader*) message->bytes;
    Assert_true(!Bits_memcmp(nodeCjdnsIp6, pi->nodeIp6Addr, 16));
    Assert_true(!Bits_memcmp(fakePubKey, pi->nodeKey, 32));

    Message_shift(message, -IpTunnel_PacketInfoHeader_SIZE, NULL);
    struct Headers_IP6Header* ip = (struct Headers_IP6Header*) message->bytes;
    Assert_true(Headers_getIpVersion(ip) == 6);
    uint16_t length = Endian_bigEndianToHost16(ip->payloadLength_be);
    Assert_true(length + Headers_IP6Header_SIZE == message->length);
    Assert_true(ip->nextHeader == 17);
    Assert_true(Bits_isZero(ip->sourceAddr, 32));

    Message_shift(message, -Headers_IP6Header_SIZE, NULL);
    struct Headers_UDPHeader* uh = (struct Headers_UDPHeader*) message->bytes;
    Assert_true(!Checksum_udpIp6(ip->sourceAddr, message->bytes, length));

    Assert_true(uh->srcPort_be == 0);
    Assert_true(uh->destPort_be == 0);
    Assert_true(Endian_bigEndianToHost16(uh->length_be) + Headers_UDPHeader_SIZE == length);

    Message_shift(message, -Headers_UDPHeader_SIZE, NULL);
    char* expectedResponse =
        "d"
          "9:addresses" "d"
            "3:ip6" "16:\xfd\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1"
          "e"
          "4:txid" "4:abcd"
        "e";
    Assert_true(message->length == (int32_t) CString_strlen(expectedResponse));
    Assert_true(!Bits_memcmp(message->bytes, expectedResponse, message->length));
    called = 1;
    return 0;
}
示例#2
0
int main()
{
    printInfo();

    volatile uint64_t b =  0x0123456789abcdef;
    volatile uint64_t sb = 0xefcdab8967452301;

    volatile uint32_t a =  0x01234567;
    volatile uint32_t sa = 0x67452301;

    volatile uint16_t c =  0xcabe;
    volatile uint16_t sc = 0xbeca;

    if (!Endian_isBigEndian()) {
        Assert_true(c == Endian_bigEndianToHost16(sc));
        Assert_true(c == Endian_hostToBigEndian16(sc));
        Assert_true(c == Endian_hostToLittleEndian16(c));
        Assert_true(c == Endian_littleEndianToHost16(c));

        Assert_true(a == Endian_bigEndianToHost32(sa));
        Assert_true(a == Endian_hostToBigEndian32(sa));
        Assert_true(a == Endian_hostToLittleEndian32(a));
        Assert_true(a == Endian_littleEndianToHost32(a));

        Assert_true(b == Endian_bigEndianToHost64(sb));
        Assert_true(b == Endian_hostToBigEndian64(sb));
        Assert_true(b == Endian_hostToLittleEndian64(b));
        Assert_true(b == Endian_littleEndianToHost64(b));
    } else {
        Assert_true(c == Endian_bigEndianToHost16(c));
        Assert_true(c == Endian_hostToBigEndian16(c));
        Assert_true(c == Endian_hostToLittleEndian16(sc));
        Assert_true(c == Endian_littleEndianToHost16(sc));

        Assert_true(a == Endian_bigEndianToHost32(a));
        Assert_true(a == Endian_hostToBigEndian32(a));
        Assert_true(a == Endian_hostToLittleEndian32(sa));
        Assert_true(a == Endian_littleEndianToHost32(sa));

        Assert_true(b == Endian_bigEndianToHost64(b));
        Assert_true(b == Endian_hostToBigEndian64(b));
        Assert_true(b == Endian_hostToLittleEndian64(sb));
        Assert_true(b == Endian_littleEndianToHost64(sb));
    }

    Assert_true(b == Endian_byteSwap64(sb));
    Assert_true(a == Endian_byteSwap32(sa));
    Assert_true(c == Endian_byteSwap16(sc));
    return 0;
}
示例#3
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);
}
示例#4
0
static uint8_t receiveMessageTUN(struct Message* msg, struct Interface* iface)
{
    receivedMessageTUNCount++;
    uint16_t ethertype = TUNMessageType_pop(msg, NULL);
    if (ethertype != Ethernet_TYPE_IP6) {
        printf("Spurious packet with ethertype [%04x]\n", Endian_bigEndianToHost16(ethertype));
        return 0;
    }

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

    if (msg->length != Headers_IP6Header_SIZE + Headers_UDPHeader_SIZE + 12) {
        int type = (msg->length >= Headers_IP6Header_SIZE) ? header->nextHeader : -1;
        printf("Message of unexpected length [%u] ip6->nextHeader: [%d]\n", msg->length, type);
        return 0;
    }

    if (Bits_memcmp(header->destinationAddr, testAddrB, 16)) { return 0; }
    if (Bits_memcmp(header->sourceAddr, testAddrA, 16)) { return 0; }

    Bits_memcpyConst(header->destinationAddr, testAddrA, 16);
    Bits_memcpyConst(header->sourceAddr, testAddrB, 16);

    TUNMessageType_push(msg, ethertype, NULL);

    return iface->sendMessage(msg, iface);
}
示例#5
0
Iface_DEFUN TUNTools_genericIP6Echo(struct Message* msg, struct TUNTools* tt)
{
    uint16_t ethertype = TUNMessageType_pop(msg, NULL);
    if (ethertype != Ethernet_TYPE_IP6) {
        Log_debug(tt->log, "Spurious packet with ethertype [%04x]\n",
                  Endian_bigEndianToHost16(ethertype));
        return 0;
    }

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

    if (msg->length != Headers_IP6Header_SIZE + Headers_UDPHeader_SIZE + 12) {
        int type = (msg->length >= Headers_IP6Header_SIZE) ? header->nextHeader : -1;
        Log_debug(tt->log, "Message of unexpected length [%u] ip6->nextHeader: [%d]\n",
                  msg->length, type);
        return 0;
    }
    uint8_t* address;
    Sockaddr_getAddress(tt->tunDestAddr, &address);
    Assert_true(!Bits_memcmp(header->destinationAddr, address, 16));
    Sockaddr_getAddress(tt->udpBindTo, &address);
    Assert_true(!Bits_memcmp(header->sourceAddr, address, 16));

    Sockaddr_getAddress(tt->udpBindTo, &address);
    Bits_memcpy(header->destinationAddr, address, 16);
    Sockaddr_getAddress(tt->tunDestAddr, &address);
    Bits_memcpy(header->sourceAddr, address, 16);

    TUNMessageType_push(msg, ethertype, NULL);

    return Iface_next(&tt->tunIface, msg);
}
示例#6
0
static inline bool validIP6(struct Message* message)
{
    struct Headers_IP6Header* header = (struct Headers_IP6Header*) message->bytes;
    uint16_t length = Endian_bigEndianToHost16(header->payloadLength_be);
    return header->sourceAddr[0] == 0xFC
        && header->destinationAddr[0] == 0xFC
        && length == message->length - Headers_IP6Header_SIZE;
}
示例#7
0
static Iface_DEFUN responseWithIpCallback(struct Message* message, struct Iface* iface)
{
    struct Context* ctx = Identity_check(((struct IfaceContext*)iface)->ctx);
    struct RouteHeader* rh = (struct RouteHeader*) message->bytes;
    Assert_true(!Bits_memcmp(ctx->ipv6, rh->ip6, 16));
    Assert_true(!Bits_memcmp(ctx->pubKey, rh->publicKey, 32));

    Message_shift(message, -(RouteHeader_SIZE + DataHeader_SIZE), NULL);
    struct Headers_IP6Header* ip = (struct Headers_IP6Header*) message->bytes;
    Assert_true(Headers_getIpVersion(ip) == 6);
    uint16_t length = Endian_bigEndianToHost16(ip->payloadLength_be);
    Assert_true(length + Headers_IP6Header_SIZE == message->length);
    Assert_true(ip->nextHeader == 17);
    Assert_true(Bits_isZero(ip->sourceAddr, 32));

    Message_shift(message, -Headers_IP6Header_SIZE, NULL);
    struct Headers_UDPHeader* uh = (struct Headers_UDPHeader*) message->bytes;
    Assert_true(!Checksum_udpIp6(ip->sourceAddr, message->bytes, length));

    Assert_true(uh->srcPort_be == 0);
    Assert_true(uh->destPort_be == 0);
    Assert_true(Endian_bigEndianToHost16(uh->length_be) + Headers_UDPHeader_SIZE == length);

    Message_shift(message, -Headers_UDPHeader_SIZE, NULL);

    struct Allocator* alloc = Allocator_child(ctx->alloc);
    char* messageContent = Escape_getEscaped(message->bytes, message->length, alloc);
    char* expectedContent =
        Escape_getEscaped(ctx->expectedResponse->bytes, ctx->expectedResponse->len, alloc);
    Log_debug(ctx->log, "Response: [%s]", messageContent);
    Log_debug(ctx->log, "Expected: [%s]", expectedContent);
    Allocator_free(alloc);

    // We can't check that the message is an exact match because the padding depends on the
    // alignment of the output but we can make sure the right content is there...
    // Message should start with "d0000" (with some number of zeros)
    Assert_true((int)ctx->expectedResponse->len == message->length);
    Assert_true(!Bits_memcmp(message->bytes, ctx->expectedResponse->bytes, message->length));
    ctx->called |= 2;

    return NULL;
}
示例#8
0
static uint8_t messageToTun(struct Message* message, struct Interface* iface)
{
    Assert_true(TUNMessageType_pop(message, NULL) == Ethernet_TYPE_IP6);
    struct Headers_IP6Header* ip = (struct Headers_IP6Header*) message->bytes;
    Assert_true(Headers_getIpVersion(ip) == 6);
    uint16_t length = Endian_bigEndianToHost16(ip->payloadLength_be);
    Assert_true(length + Headers_IP6Header_SIZE == message->length);
    Assert_true(ip->nextHeader == 17);
    Assert_true(!Bits_memcmp(ip->sourceAddr, fakeIp6ToGive, 16));
    called = 1;
    return 0;
}
示例#9
0
static Iface_DEFUN responseWithIpCallback(struct Message* message, struct Iface* iface)
{
    struct RouteHeader* rh = (struct RouteHeader*) message->bytes;
    Assert_true(!Bits_memcmp(nodeCjdnsIp6, rh->ip6, 16));
    Assert_true(!Bits_memcmp(fakePubKey, rh->publicKey, 32));

    Message_shift(message, -(RouteHeader_SIZE + DataHeader_SIZE), NULL);
    struct Headers_IP6Header* ip = (struct Headers_IP6Header*) message->bytes;
    Assert_true(Headers_getIpVersion(ip) == 6);
    uint16_t length = Endian_bigEndianToHost16(ip->payloadLength_be);
    Assert_true(length + Headers_IP6Header_SIZE == message->length);
    Assert_true(ip->nextHeader == 17);
    Assert_true(Bits_isZero(ip->sourceAddr, 32));

    Message_shift(message, -Headers_IP6Header_SIZE, NULL);
    struct Headers_UDPHeader* uh = (struct Headers_UDPHeader*) message->bytes;
    Assert_true(!Checksum_udpIp6(ip->sourceAddr, message->bytes, length));

    Assert_true(uh->srcPort_be == 0);
    Assert_true(uh->destPort_be == 0);
    Assert_true(Endian_bigEndianToHost16(uh->length_be) + Headers_UDPHeader_SIZE == length);

    Message_shift(message, -Headers_UDPHeader_SIZE, NULL);

    // We can't check that the message is an exact match because the padding depends on the
    // alignment of the output but we can make sure the right content is there...
    // Message should start with "d0000" (with some number of zeros)
    char* expectedResponse =
        "9:addresses" "d"
            "3:ip6" "16:\xfd\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1"
            "9:ip6Prefix" "i128e"
          "e"
          "4:txid" "4:abcd"
        "e";
    Assert_true(message->length >= (int32_t) CString_strlen(expectedResponse));
    Assert_true(CString_strstr(message->bytes, expectedResponse));
    called |= 2;
    return 0;
}
示例#10
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.
 * @param isFormV8 true if the control message is in the form specified by protocol version 8+
 */
static Iface_DEFUN incomingFromCore(struct Message* msg, struct Iface* coreIf)
{
    struct ControlHandler_pvt* ch = Identity_check((struct ControlHandler_pvt*) coreIf);

    struct RouteHeader routeHdr;
    Message_pop(msg, &routeHdr, RouteHeader_SIZE, NULL);
    uint8_t labelStr[20];
    uint64_t label = Endian_bigEndianToHost64(routeHdr.sh.label_be);
    AddrTools_printPath(labelStr, label);
    // happens in benchmark
    // Log_debug(ch->log, "ctrl packet from [%s]", labelStr);

    if (msg->length < 4 + Control_Header_SIZE) {
        Log_info(ch->log, "DROP runt ctrl packet from [%s]", labelStr);
        return NULL;
    }

    Assert_true(routeHdr.flags & RouteHeader_flags_CTRLMSG);

    if (Checksum_engine(msg->bytes, msg->length)) {
        Log_info(ch->log, "DROP ctrl packet from [%s] with invalid checksum", labelStr);
        return NULL;
    }

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

    if (ctrl->header.type_be == Control_ERROR_be) {
        return handleError(msg, ch, label, labelStr);

    } else if (ctrl->header.type_be == Control_KEYPING_be
            || ctrl->header.type_be == Control_PING_be)
    {
        return handlePing(msg, ch, label, labelStr, ctrl->header.type_be);

    } else if (ctrl->header.type_be == Control_KEYPONG_be
            || ctrl->header.type_be == Control_PONG_be)
    {
        Log_debug(ch->log, "got switch pong from [%s]", labelStr);
        Message_push(msg, &routeHdr, RouteHeader_SIZE, NULL);
        return Iface_next(&ch->pub.switchPingerIf, msg);
    }

    Log_info(ch->log, "DROP control packet of unknown type from [%s], type [%d]",
             labelStr, Endian_bigEndianToHost16(ctrl->header.type_be));

    return NULL;
}
示例#11
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.
 * @param isFormV8 true if the control message is in the form specified by protocol version 8+
 */
static Iface_DEFUN incomingFromCore(struct Message* msg, struct Iface* coreIf)
{
    struct ControlHandler_pvt* ch = Identity_check((struct ControlHandler_pvt*) coreIf);

    struct SwitchHeader switchHeader;
    Message_pop(msg, &switchHeader, SwitchHeader_SIZE, NULL);
    uint8_t labelStr[20];
    uint64_t label = Endian_bigEndianToHost64(switchHeader.label_be);
    AddrTools_printPath(labelStr, label);
    Log_debug(ch->log, "ctrl packet from [%s]", labelStr);

    if (msg->length < 4 + Control_Header_SIZE) {
        Log_info(ch->log, "DROP runt ctrl packet from [%s]", labelStr);
        return NULL;
    }

    Assert_true(Message_pop32(msg, NULL) == 0xffffffff);

    if (Checksum_engine(msg->bytes, msg->length)) {
        Log_info(ch->log, "DROP ctrl packet from [%s] with invalid checksum", labelStr);
        return NULL;
    }

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

    if (ctrl->header.type_be == Control_ERROR_be) {
        return handleError(msg, ch, label, labelStr);

    } else if (ctrl->header.type_be == Control_KEYPING_be
            || ctrl->header.type_be == Control_PING_be)
    {
        return handlePing(msg, ch, label, labelStr, ctrl->header.type_be);

    } else if (ctrl->header.type_be == Control_KEYPONG_be
            || ctrl->header.type_be == Control_PONG_be)
    {
        Log_debug(ch->log, "got switch pong from [%s]", labelStr);
        // Shift back over the header
        Message_shift(msg, 4 + SwitchHeader_SIZE, NULL);
        return Iface_next(&ch->pub.switchPingerIf, msg);
    }

    Log_info(ch->log, "DROP control packet of unknown type from [%s], type [%d]",
             labelStr, Endian_bigEndianToHost16(ctrl->header.type_be));

    return NULL;
}
static uint8_t receiveMessageTUN(struct Message* msg, struct Interface* iface)
{
    receivedMessageTUNCount++;
    uint16_t ethertype = TUNMessageType_pop(msg);
    if (ethertype != Ethernet_TYPE_IP4) {
        printf("Spurious packet with ethertype [%u]\n", Endian_bigEndianToHost16(ethertype));
        return 0;
    }

    struct Headers_IP4Header* header = (struct Headers_IP4Header*) msg->bytes;

    Assert_always(msg->length == Headers_IP4Header_SIZE + Headers_UDPHeader_SIZE + 12);

    Assert_always(!Bits_memcmp(header->destAddr, testAddrB, 4));
    Assert_always(!Bits_memcmp(header->sourceAddr, testAddrA, 4));

    Bits_memcpyConst(header->destAddr, testAddrA, 4);
    Bits_memcpyConst(header->sourceAddr, testAddrB, 4);

    TUNMessageType_push(msg, ethertype);

    return iface->sendMessage(msg, iface);
}
示例#13
0
文件: Checksum.c 项目: coinmint/cjdns
static uint32_t checksumStep(const uint8_t* buffer,
                             uint32_t length,
                             uint32_t state)
{
    uint32_t i;

    // Checksum pairs.
    for (i = 0; i < length / 2; i++) {
        state += (uint16_t) Endian_bigEndianToHost16( ((uint16_t*) buffer)[i] );
        if (state > 0xFFFF) {
            state -= 0xFFFF;
        }
    }

    // Do the odd byte if there is one.
    if (length % 2) {
        state += buffer[length - 1] << 8;
        if (state > 0xFFFF) {
            state -= 0xFFFF;
        }
    }
    return state;
}
示例#14
0
文件: Ducttape.c 项目: wpapper/cjdns
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;
}
示例#15
0
static void handleBeacon(struct Message* msg, struct ETHInterface* context)
{
    if (!context->beaconState) {
        // accepting beacons disabled.
        Log_debug(context->logger, "Dropping beacon because beaconing is disabled");
        return;
    }

    struct sockaddr_ll addr;
    Bits_memcpyConst(&addr, &context->addrBase, sizeof(struct sockaddr_ll));
    Message_pop(msg, addr.sll_addr, 8);
    if (msg->length < Headers_Beacon_SIZE) {
        // Oversize messages are ok because beacons may contain more information in the future.
        Log_debug(context->logger, "Dropping wrong size beacon, expected [%d] got [%d]",
                  Headers_Beacon_SIZE, msg->length);
        return;
    }
    struct Headers_Beacon* beacon = (struct Headers_Beacon*) msg->bytes;

    uint32_t theirVersion = Endian_bigEndianToHost32(beacon->version_be);
    if (!Version_isCompatible(theirVersion, Version_CURRENT_PROTOCOL)) {
        #ifdef Log_DEBUG
            uint8_t mac[18];
            AddrTools_printMac(mac, addr.sll_addr);
            Log_debug(context->logger, "Dropped beacon from [%s] which was version [%d] "
                      "our version is [%d] making them incompatable",
                      mac, theirVersion, Version_CURRENT_PROTOCOL);
        #endif
        return;
    }

    #ifdef Log_DEBUG
        uint8_t mac[18];
        AddrTools_printMac(mac, addr.sll_addr);
        Log_debug(context->logger, "Got beacon from [%s]", mac);
    #endif

    String passStr = { .bytes = (char*) beacon->password, .len = Headers_Beacon_PASSWORD_LEN };
    struct Interface* iface = MultiInterface_ifaceForKey(context->multiIface, addr.sll_addr);
    int ret = InterfaceController_registerPeer(context->ic,
                                               beacon->publicKey,
                                               &passStr,
                                               false,
                                               true,
                                               iface);
    if (ret != 0) {
        uint8_t mac[18];
        AddrTools_printMac(mac, addr.sll_addr);
        Log_info(context->logger, "Got beacon from [%s] and registerPeer returned [%d]", mac, ret);
    }
}

static void sendBeacon(void* vcontext)
{
    struct ETHInterface* context = Identity_cast((struct ETHInterface*) vcontext);
    if (context->beaconState != ETHInterface_beacon_ACCEPTING_AND_SENDING) {
        // beaconing disabled
        return;
    }

    struct {
        struct sockaddr_ll addr;
        struct Headers_Beacon beacon;
    } content;

    Bits_memcpyConst(&content.addr, &context->addrBase, sizeof(struct sockaddr_ll));
    Bits_memset(content.addr.sll_addr, 0xff, 6);
    InterfaceController_populateBeacon(context->ic, &content.beacon);

    struct Message m = {
        .bytes=(uint8_t*)content.addr.sll_addr,
        .padding=0,
        .length=sizeof(struct Headers_Beacon) + 8
    };

    int ret;
    if ((ret = sendMessage(&m, &context->generic)) != 0) {
        Log_info(context->logger, "Got error [%d] sending beacon [%s]", ret, strerror(errno));
    }
}

static void handleEvent(void* vcontext)
{
    struct ETHInterface* context = Identity_cast((struct ETHInterface*) vcontext);

    struct Message message =
        { .bytes = context->messageBuff + PADDING, .padding = PADDING, .length = MAX_PACKET_SIZE };

    struct sockaddr_ll addr;
    uint32_t addrLen = sizeof(struct sockaddr_ll);

    // Knock it out of alignment by 2 bytes so that it will be
    // aligned when the idAndPadding is shifted off.
    Message_shift(&message, 2);

    int rc = recvfrom(context->socket,
                      message.bytes,
                      message.length,
                      0,
                      (struct sockaddr*) &addr,
                      &addrLen);

    if (rc < 0) {
        Log_debug(context->logger, "Failed to receive eth frame");
        return;
    }

    //Assert_true(addrLen == SOCKADDR_LL_LEN);

    // Pop the first 2 bytes of the message containing the node id and amount of padding.
    uint16_t idAndPadding_be;
    Message_pop(&message, &idAndPadding_be, 2);

    const uint16_t idAndPadding = Endian_bigEndianToHost16(idAndPadding_be);
    message.length = rc - 2 - ((idAndPadding & 7) * 8);
    const uint16_t id = idAndPadding >> 3;
    Message_push(&message, &id, 2);
    Message_push(&message, addr.sll_addr, 6);

    if (addr.sll_pkttype == PACKET_BROADCAST) {
        handleBeacon(&message, context);
        return;
    }

    /* Cut down on the noise
    uint8_t buff[sizeof(addr) * 2 + 1] = {0};
    Hex_encode(buff, sizeof(buff), (uint8_t*)&addr, sizeof(addr));
    Log_debug(context->logger, "Got ethernet frame from [%s]", buff);
    */

    context->generic.receiveMessage(&message, &context->generic);
}

int ETHInterface_beginConnection(const char* macAddress,
                                 uint8_t cryptoKey[32],
                                 String* password,
                                 struct ETHInterface* ethIf)
{
    Identity_check(ethIf);
    struct sockaddr_ll addr;
    Bits_memcpyConst(&addr, &ethIf->addrBase, sizeof(struct sockaddr_ll));
    if (AddrTools_parseMac(addr.sll_addr, (const uint8_t*)macAddress)) {
        return ETHInterface_beginConnection_BAD_MAC;
    }

    struct Interface* iface = MultiInterface_ifaceForKey(ethIf->multiIface, &addr);
    int ret = InterfaceController_registerPeer(ethIf->ic, cryptoKey, password, false, false, iface);
    if (ret) {
        Allocator_free(iface->allocator);
        switch(ret) {
            case InterfaceController_registerPeer_BAD_KEY:
                return ETHInterface_beginConnection_BAD_KEY;

            case InterfaceController_registerPeer_OUT_OF_SPACE:
                return ETHInterface_beginConnection_OUT_OF_SPACE;

            default:
                return ETHInterface_beginConnection_UNKNOWN_ERROR;
        }
    }
    return 0;
}

int ETHInterface_beacon(struct ETHInterface* ethIf, int* state)
{
    Identity_check(ethIf);
    if (state) {
        ethIf->beaconState = *state;
        // Send out a beacon right away so we don't have to wait.
        if (ethIf->beaconState == ETHInterface_beacon_ACCEPTING_AND_SENDING) {
            sendBeacon(ethIf);
        }
    }
    return ethIf->beaconState;
}

struct ETHInterface* ETHInterface_new(struct EventBase* base,
                                      const char* bindDevice,
                                      struct Allocator* allocator,
                                      struct Except* exHandler,
                                      struct Log* logger,
                                      struct InterfaceController* ic)
{
    struct ETHInterface* context = Allocator_clone(allocator, (&(struct ETHInterface) {
        .generic = {
            .sendMessage = sendMessage,
            .allocator = allocator
        },
        .logger = logger,
        .ic = ic,
        .id = getpid()
    }));
示例#16
0
static Iface_DEFUN sendMessage(struct Message* msg, struct Iface* iface)
{
    struct ETHInterface_pvt* ctx =
        Identity_containerOf(iface, struct ETHInterface_pvt, pub.generic.iface);

    struct Sockaddr* sa = (struct Sockaddr*) msg->bytes;
    Assert_true(msg->length >= Sockaddr_OVERHEAD);
    Assert_true(sa->addrLen <= ETHInterface_Sockaddr_SIZE);

    struct ETHInterface_Sockaddr sockaddr = { .generic = { .addrLen = 0 } };
    Message_pop(msg, &sockaddr, sa->addrLen, NULL);

    struct sockaddr_ll addr;
    Bits_memcpy(&addr, &ctx->addrBase, sizeof(struct sockaddr_ll));

    if (sockaddr.generic.flags & Sockaddr_flags_BCAST) {
        Bits_memset(addr.sll_addr, 0xff, 6);
    } else {
        Bits_memcpy(addr.sll_addr, sockaddr.mac, 6);
    }

    struct ETHInterface_Header hdr = {
        .version = ETHInterface_CURRENT_VERSION,
        .zero = 0,
        .length_be = Endian_hostToBigEndian16(msg->length + ETHInterface_Header_SIZE),
        .fc00_be = Endian_hostToBigEndian16(0xfc00)
    };
    Message_push(msg, &hdr, ETHInterface_Header_SIZE, NULL);
    struct Except* eh = NULL;
    sendMessageInternal(msg, &addr, ctx, eh);
    return NULL;
}

static void handleEvent2(struct ETHInterface_pvt* context, struct Allocator* messageAlloc)
{
    struct Message* msg = Message_new(MAX_PACKET_SIZE, PADDING, messageAlloc);

    struct sockaddr_ll addr;
    uint32_t addrLen = sizeof(struct sockaddr_ll);

    // Knock it out of alignment by 2 bytes so that it will be
    // aligned when the idAndPadding is shifted off.
    Message_shift(msg, 2, NULL);

    int rc = recvfrom(context->socket,
                      msg->bytes,
                      msg->length,
                      0,
                      (struct sockaddr*) &addr,
                      &addrLen);

    if (rc < ETHInterface_Header_SIZE) {
        Log_debug(context->logger, "Failed to receive eth frame");
        return;
    }

    Assert_true(msg->length >= rc);
    msg->length = rc;

    //Assert_true(addrLen == SOCKADDR_LL_LEN);

    struct ETHInterface_Header hdr;
    Message_pop(msg, &hdr, ETHInterface_Header_SIZE, NULL);

    // here we could put a switch statement to handle different versions differently.
    if (hdr.version != ETHInterface_CURRENT_VERSION) {
        Log_debug(context->logger, "DROP unknown version");
        return;
    }

    uint16_t reportedLength = Endian_bigEndianToHost16(hdr.length_be);
    reportedLength -= ETHInterface_Header_SIZE;
    if (msg->length != reportedLength) {
        if (msg->length < reportedLength) {
            Log_debug(context->logger, "DROP size field is larger than frame");
            return;
        }
        msg->length = reportedLength;
    }
    if (hdr.fc00_be != Endian_hostToBigEndian16(0xfc00)) {
        Log_debug(context->logger, "DROP bad magic");
        return;
    }

    struct ETHInterface_Sockaddr  sockaddr = { .zero = 0 };
    Bits_memcpy(sockaddr.mac, addr.sll_addr, 6);
    sockaddr.generic.addrLen = ETHInterface_Sockaddr_SIZE;
    if (addr.sll_pkttype == PACKET_BROADCAST) {
        sockaddr.generic.flags |= Sockaddr_flags_BCAST;
    }

    Message_push(msg, &sockaddr, ETHInterface_Sockaddr_SIZE, NULL);

    Assert_true(!((uintptr_t)msg->bytes % 4) && "Alignment fault");

    Iface_send(&context->pub.generic.iface, msg);
}

static void handleEvent(void* vcontext)
{
    struct ETHInterface_pvt* context = Identity_check((struct ETHInterface_pvt*) vcontext);
    struct Allocator* messageAlloc = Allocator_child(context->pub.generic.alloc);
    handleEvent2(context, messageAlloc);
    Allocator_free(messageAlloc);
}

List* ETHInterface_listDevices(struct Allocator* alloc, struct Except* eh)
{
    List* out = List_new(alloc);
#ifndef android
    struct ifaddrs* ifaddr = NULL;
    if (getifaddrs(&ifaddr) || ifaddr == NULL) {
        Except_throw(eh, "getifaddrs() -> errno:%d [%s]", errno, strerror(errno));
    }
    for (struct ifaddrs* ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
        if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_PACKET) {
            List_addString(out, String_new(ifa->ifa_name, alloc), alloc);
        }
    }
    freeifaddrs(ifaddr);
#endif
    return out;
}

static int closeSocket(struct Allocator_OnFreeJob* j)
{
    struct ETHInterface_pvt* ctx = Identity_check((struct ETHInterface_pvt*) j->userData);
    close(ctx->socket);
    return 0;
}

struct ETHInterface* ETHInterface_new(struct EventBase* eventBase,
                                      const char* bindDevice,
                                      struct Allocator* alloc,
                                      struct Except* exHandler,
                                      struct Log* logger)
{
    struct ETHInterface_pvt* ctx = Allocator_calloc(alloc, sizeof(struct ETHInterface_pvt), 1);
    Identity_set(ctx);
    ctx->pub.generic.iface.send = sendMessage;
    ctx->pub.generic.alloc = alloc;
    ctx->logger = logger;

    struct ifreq ifr = { .ifr_ifindex = 0 };

    ctx->socket = socket(AF_PACKET, SOCK_DGRAM, Ethernet_TYPE_CJDNS);
    if (ctx->socket == -1) {
        Except_throw(exHandler, "call to socket() failed. [%s]", strerror(errno));
    }
    Allocator_onFree(alloc, closeSocket, ctx);

    CString_strncpy(ifr.ifr_name, bindDevice, IFNAMSIZ - 1);
    ctx->ifName = String_new(bindDevice, alloc);

    if (ioctl(ctx->socket, SIOCGIFINDEX, &ifr) == -1) {
        Except_throw(exHandler, "failed to find interface index [%s]", strerror(errno));
    }
    ctx->ifindex = ifr.ifr_ifindex;

    if (ioctl(ctx->socket, SIOCGIFFLAGS, &ifr) < 0) {
        Except_throw(exHandler, "ioctl(SIOCGIFFLAGS) [%s]", strerror(errno));
    }
    if (!((ifr.ifr_flags & IFF_UP) && (ifr.ifr_flags & IFF_RUNNING))) {
        Log_info(logger, "Bringing up interface [%s]", ifr.ifr_name);
        ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
        if (ioctl(ctx->socket, SIOCSIFFLAGS, &ifr) < 0) {
            Except_throw(exHandler, "ioctl(SIOCSIFFLAGS) [%s]", strerror(errno));
        }
    }

    ctx->addrBase = (struct sockaddr_ll) {
        .sll_family = AF_PACKET,
        .sll_protocol = Ethernet_TYPE_CJDNS,
        .sll_ifindex = ctx->ifindex,
        .sll_hatype = ARPHRD_ETHER,
        .sll_pkttype = PACKET_OTHERHOST,
        .sll_halen = ETH_ALEN
    };

    if (bind(ctx->socket, (struct sockaddr*) &ctx->addrBase, sizeof(struct sockaddr_ll))) {
        Except_throw(exHandler, "call to bind() failed [%s]", strerror(errno));
    }

    Socket_makeNonBlocking(ctx->socket);

    Event_socketRead(handleEvent, ctx, ctx->socket, eventBase, alloc, exHandler);

    return &ctx->pub;
}
示例#17
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);
}
示例#18
0
文件: Ducttape.c 项目: wpapper/cjdns
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);
}
示例#19
0
文件: Ducttape.c 项目: coinmint/cjdns
/**
 * 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;
}
示例#20
0
文件: Ducttape.c 项目: coinmint/cjdns
static int handleOutgoing(struct DHTMessage* dmessage,
                          void* vcontext)
{
    struct Ducttape* context = (struct Ducttape*) vcontext;

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

    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);

    context->ip6Header = header;
    context->switchHeader = NULL;

    sendToRouter(dmessage->address, &message, 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;
}

/**
 * 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* context,
                                    uint8_t herPubKey[32])
{
    struct Address addr;
    AddressCalc_addressForPublicKey(addr.ip6.bytes, herPubKey);

    if (memcmp(addr.ip6.bytes, context->ip6Header->sourceAddr, 16)) {
        #ifdef Log_DEBUG
            uint8_t keyAddr[40];
            Address_printIp(keyAddr, &addr);
            Bits_memcpyConst(addr.ip6.bytes, context->ip6Header->sourceAddr, 16);
            uint8_t srcAddr[40];
            Address_printIp(srcAddr, &addr);
            Log_debug2(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 (message->length == 0) {
        #ifdef Log_WARN
            uint8_t keyAddr[40];
            uint8_t ipv6Hex[80];
            Address_printIp(keyAddr, &addr);
            Hex_encode(ipv6Hex, 80, (uint8_t*) context->ip6Header, 40);
            Log_warn2(context->logger,
                      "Got ipv6 packet from %s which has no content!\nIPv6 Header: [%s]",
                      keyAddr, ipv6Hex);
        #endif
        return Error_INVALID;
    }

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

    // RouterModule_addNode(&addr, context->routerModule);

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

    // 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*)context->ip6Header;
    if (sizeDiff) {
        context->ip6Header->payloadLength_be =
            Endian_hostToBigEndian16(
                Endian_bigEndianToHost16(context->ip6Header->payloadLength_be) - sizeDiff);
        memmove(message->bytes, context->ip6Header, Headers_IP6Header_SIZE);
    }
    context->routerIf->sendMessage(message, context->routerIf);
    return Error_NONE;
}

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

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

    return incomingForMe(message, context, herPublicKey);
}

/**
 * Send a message to another switch.
 * Switchheader will precede the message.
 */
static inline uint8_t sendToSwitch(struct Message* message,
                                   struct Headers_SwitchHeader* destinationSwitchHeader,
                                   struct Ducttape* context)
{
    Message_shift(message, Headers_SwitchHeader_SIZE);
    struct Headers_SwitchHeader* switchHeaderLocation =
        (struct Headers_SwitchHeader*) message->bytes;

    if (destinationSwitchHeader != switchHeaderLocation) {
        memmove(message->bytes, destinationSwitchHeader, Headers_SwitchHeader_SIZE);
    }

    return context->switchInterface.receiveMessage(message, &context->switchInterface);
}
示例#21
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);
}
static uint8_t sendMessage(struct Message* message, struct Interface* iface)
{
    struct PacketHeaderToUDPAddrInterface_pvt* context =
        Identity_check((struct PacketHeaderToUDPAddrInterface_pvt*) iface);

    struct Sockaddr_storage ss;
    Message_pop(message, &ss, context->pub.addr->addrLen, NULL);
    struct Sockaddr* addr = &ss.addr;

    struct Headers_UDPHeader udp;
    udp.srcPort_be = Endian_hostToBigEndian16(Sockaddr_getPort(context->pub.addr));
    udp.destPort_be = Endian_hostToBigEndian16(Sockaddr_getPort(addr));
    udp.length_be = Endian_hostToBigEndian16(message->length + Headers_UDPHeader_SIZE);
    udp.checksum_be = 0;
    Message_push(message, &udp, sizeof(struct Headers_UDPHeader), NULL);

    struct Headers_IP6Header ip = {
        .nextHeader = 17,
        .hopLimit = 255,
    };
    ip.payloadLength_be = Endian_hostToBigEndian16(message->length);
    Headers_setIpVersion(&ip);
    uint8_t* addrPtr = NULL;
    Assert_true(Sockaddr_getAddress(addr, &addrPtr) == 16);
    Bits_memcpyConst(ip.destinationAddr, addrPtr, 16);
    Assert_true(Sockaddr_getAddress(context->pub.addr, &addrPtr) == 16);
    Bits_memcpyConst(ip.sourceAddr, addrPtr, 16);

    uint16_t checksum = Checksum_udpIp6(ip.sourceAddr, message->bytes, message->length);
    ((struct Headers_UDPHeader*)message->bytes)->checksum_be = checksum;

    Message_push(message, &ip, sizeof(struct Headers_IP6Header), NULL);

    return Interface_sendMessage(context->wrapped, message);
}

static uint8_t receiveMessage(struct Message* message, struct Interface* iface)
{
    struct PacketHeaderToUDPAddrInterface_pvt* context =
        Identity_check((struct PacketHeaderToUDPAddrInterface_pvt*) iface->receiverContext);

    if (message->length < Headers_IP6Header_SIZE + Headers_UDPHeader_SIZE) {
        // runt
        return Error_NONE;
    }

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

    // udp
    if (ip->nextHeader != 17) {
        return Error_NONE;
    }

    struct Allocator* alloc = Allocator_child(message->alloc);
    struct Sockaddr* addr = Sockaddr_clone(context->pub.addr, alloc);
    uint8_t* addrPtr = NULL;
    Assert_true(Sockaddr_getAddress(addr, &addrPtr) == 16);
    Bits_memcpyConst(addrPtr, ip->sourceAddr, 16);

    struct Headers_UDPHeader* udp = (struct Headers_UDPHeader*) (&ip[1]);
    Sockaddr_setPort(addr, Endian_bigEndianToHost16(udp->srcPort_be));

    if (Sockaddr_getPort(context->pub.addr) != Endian_bigEndianToHost16(udp->destPort_be)) {
        // not the right port
        return Error_NONE;
    }

    Message_shift(message, -(Headers_IP6Header_SIZE + Headers_UDPHeader_SIZE), NULL);
    Message_push(message, addr, addr->addrLen, NULL);

    return Interface_receiveMessage(&context->pub.generic, message);
}

struct AddrInterface* PacketHeaderToUDPAddrInterface_new(struct Interface* toWrap,
                                                         struct Allocator* alloc,
                                                         struct Sockaddr* addr)
{
    struct PacketHeaderToUDPAddrInterface_pvt* context =
        Allocator_malloc(alloc, sizeof(struct PacketHeaderToUDPAddrInterface_pvt));

    Bits_memcpyConst(context, (&(struct PacketHeaderToUDPAddrInterface_pvt) {
        .pub = {
            .generic = {
                .sendMessage = sendMessage,
                .senderContext = context,
                .allocator = alloc
            }
        },
        .wrapped = toWrap
    }), sizeof(struct PacketHeaderToUDPAddrInterface_pvt));