static uint8_t incomingFromCryptoAuth(struct Message* message, struct Interface* iface) { struct Context* context = iface->receiverContext; int layer = context->layer; context->layer = INVALID_LAYER; if (layer == INNER_LAYER) { return incomingForMe(message, context); } else if (layer == OUTER_LAYER) { return incomingFromRouter(message, context); } assert(false); }
static uint8_t incomingFromCryptoAuth(struct Message* message, struct Interface* iface) { struct Ducttape* context = iface->receiverContext; int layer = context->layer; context->layer = INVALID_LAYER; if (layer == INNER_LAYER) { return incomingForMe(message, context, CryptoAuth_getHerPublicKey(context->session)); } else if (layer == OUTER_LAYER) { return incomingFromRouter(message, context); } Assert_true(false); return 0; }
/** * Messages with content encrypted and header decrypted are sent here to be forwarded. * they may come from us, or from another node and may be to us or to any other node. * Message is aligned on the beginning of the ipv6 header. */ static inline int core(struct Message* message, struct Ducttape* context) { context->ip6Header = (struct Headers_IP6Header*) message->bytes; if (isForMe(message, context)) { Message_shift(message, -Headers_IP6Header_SIZE); if (memcmp(context->routerAddress, context->ip6Header->sourceAddr, 16)) { // triple encrypted // This call goes to incomingForMe() context->layer = INNER_LAYER; context->session = SessionManager_getSession(context->ip6Header->sourceAddr, NULL, context->sm); return context->session->receiveMessage(message, context->session); } else { // double encrypted, inner layer plaintext. // The session is still set from the router-to-router traffic and that is the one we use // to determine the node's id. return incomingForMe(message, context, CryptoAuth_getHerPublicKey(context->session)); } } if (context->ip6Header->hopLimit == 0) { Log_debug(context->logger, "dropped message because hop limit has been exceeded.\n"); // TODO: send back an error message in response. return Error_UNDELIVERABLE; } context->ip6Header->hopLimit--; struct Address* ft = context->forwardTo; context->forwardTo = NULL; if (!ft) { struct Node* bestNext = RouterModule_lookup(context->ip6Header->destinationAddr, context->routerModule); if (bestNext) { ft = &bestNext->address; } } if (ft) { #ifdef Log_DEBUG uint8_t nhAddr[60]; Address_print(nhAddr, ft); if (memcmp(context->ip6Header->destinationAddr, ft->ip6.bytes, 16)) { // Potentially forwarding for ourselves. struct Address destination; Bits_memcpyConst(destination.ip6.bytes, context->ip6Header->destinationAddr, 16); uint8_t ipAddr[40]; Address_printIp(ipAddr, &destination); Log_debug2(context->logger, "Forwarding data to %s via %s\n", ipAddr, nhAddr); } else { // Definitely forwarding on behalf of someone else. Log_debug1(context->logger, "Forwarding data to %s (last hop)\n", nhAddr); } #endif return sendToRouter(ft, message, context); } Log_debug(context->logger, "Dropped message because this node is the closest known " "node to the destination.\n"); return Error_UNDELIVERABLE; }
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); }
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; }
/** * Messages with content encrypted and header decrypted are sent here to be forwarded. * they may come from us, or from another node and may be to us or to any other node. * Message is aligned on the beginning of the ipv6 header. */ static inline int core(struct Message* message, struct Ducttape_MessageHeader* dtHeader, struct SessionManager_Session* session, struct Ducttape_pvt* context) { struct Headers_IP6Header* ip6Header = (struct Headers_IP6Header*) message->bytes; dtHeader->ip6Header = ip6Header; if (isForMe(message, context)) { Message_shift(message, -Headers_IP6Header_SIZE); if (Bits_memcmp(session->ip6, ip6Header->sourceAddr, 16)) { // triple encrypted // This call goes to incomingForMe() struct SessionManager_Session* session = SessionManager_getSession(ip6Header->sourceAddr, NULL, context->sm); #ifdef Log_DEBUG uint8_t addr[40]; AddrTools_printIp(addr, ip6Header->sourceAddr); Log_debug(context->logger, "Incoming layer3 message, ostensibly from [%s]", addr); #endif dtHeader->receiveHandle = Endian_bigEndianToHost32(session->receiveHandle_be); dtHeader->layer = Ducttape_SessionLayer_INNER; return session->iface.receiveMessage(message, &session->iface); } else { // double encrypted, inner layer plaintext. // The session is still set from the router-to-router traffic and that is the one we use // to determine the node's id. return incomingForMe(message, dtHeader, session, context, CryptoAuth_getHerPublicKey(&session->iface)); } } if (ip6Header->hopLimit == 0) { Log_debug(context->logger, "dropped message because hop limit has been exceeded.\n"); // TODO: send back an error message in response. return Error_UNDELIVERABLE; } ip6Header->hopLimit--; struct SessionManager_Session* nextHopSession = NULL; if (!dtHeader->nextHopReceiveHandle || !dtHeader->switchLabel) { struct Node* n = RouterModule_lookup(ip6Header->destinationAddr, context->routerModule); if (n) { nextHopSession = SessionManager_getSession(n->address.ip6.bytes, n->address.key, context->sm); dtHeader->switchLabel = n->address.path; } } else { nextHopSession = SessionManager_sessionForHandle(dtHeader->nextHopReceiveHandle, context->sm); } if (nextHopSession) { #ifdef Log_DEBUG struct Address addr; Bits_memcpyConst(addr.ip6.bytes, nextHopSession->ip6, 16); addr.path = dtHeader->switchLabel; uint8_t nhAddr[60]; Address_print(nhAddr, &addr); if (Bits_memcmp(ip6Header->destinationAddr, addr.ip6.bytes, 16)) { // Potentially forwarding for ourselves. struct Address destination; Bits_memcpyConst(destination.ip6.bytes, ip6Header->destinationAddr, 16); uint8_t ipAddr[40]; Address_printIp(ipAddr, &destination); Log_debug(context->logger, "Forwarding data to %s via %s\n", ipAddr, nhAddr); } else { // Definitely forwarding on behalf of someone else. Log_debug(context->logger, "Forwarding data to %s (last hop)\n", nhAddr); } #endif return sendToRouter(message, dtHeader, nextHopSession, context); } #ifdef Log_INFO struct Address destination; Bits_memcpyConst(destination.ip6.bytes, ip6Header->destinationAddr, 16); uint8_t ipAddr[40]; Address_printIp(ipAddr, &destination); Log_info(context->logger, "Dropped message because this node is the closest known " "node to the destination %s.", ipAddr); #endif return Error_UNDELIVERABLE; }
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); }
/** * Messages with content encrypted and header decrypted are sent here to be forwarded. * they may come from us, or from another node and may be to us or to any other node. * Message is aligned on the beginning of the ipv6 header. */ static inline int core(struct Message* message, struct Context* context) { context->ip6Header = (struct Headers_IP6Header*) message->bytes; if (!validIP6(message)) { Log_debug(context->logger, "Dropping message because of invalid ipv6 header.\n"); return Error_INVALID; } // Do this here and check for 1 hop, not 0 because we want to differentiate between single // hop traffic and routed traffic as single hop traffic doesn't need 2 layers of crypto. if (context->ip6Header->hopLimit == 1) { Log_debug(context->logger, "dropped message because hop limit has been exceeded.\n"); // TODO: send back an error message in response. return Error_UNDELIVERABLE; } if (isForMe(message, context)) { Message_shift(message, -Headers_IP6Header_SIZE); if (context->ip6Header->hopLimit != 0) { // triple encrypted // This call goes to incomingForMe() context->layer = INNER_LAYER; context->session = SessionManager_getSession(context->ip6Header->sourceAddr, NULL, context->sm); return context->session->receiveMessage(message, context->session); } else { // double encrypted, inner layer plaintext. // The session is still set from the router-to-router traffic and that is the one we use // to determine the node's id. return incomingForMe(message, context); } } if (context->ip6Header->hopLimit == 0) { Log_debug(context->logger, "0 hop message not addressed to us, broken route.\n"); return 0; } context->ip6Header->hopLimit--; struct Address* ft = context->forwardTo; context->forwardTo = NULL; if (!ft) { struct Node* bestNext = RouterModule_getBest(context->ip6Header->destinationAddr, context->routerModule); if (bestNext) { ft = &bestNext->address; } } if (ft) { #ifdef Log_DEBUG uint8_t nhAddr[60]; Address_print(nhAddr, ft); if (memcmp(context->ip6Header->destinationAddr, ft->ip6.bytes, 16)) { // Potentially forwarding for ourselves. struct Address destination; memcpy(destination.ip6.bytes, context->ip6Header->destinationAddr, 16); uint8_t ipAddr[40]; Address_printIp(ipAddr, &destination); Log_debug2(context->logger, "Forwarding data to %s via %s\n", ipAddr, nhAddr); } else { // Definitely forwarding on behalf of someone else. Log_debug1(context->logger, "Forwarding data to %s (last hop)\n", nhAddr); } #endif return sendToRouter(ft, message, context); } Log_debug(context->logger, "Dropped message because this node is the closest known " "node to the destination.\n"); return Error_UNDELIVERABLE; }