/** * 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; }
/** * 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; }
/** * 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; }
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); }
void NodeStore_addNode(struct NodeStore* store, struct Address* addr, const int64_t reachDifference) { Address_getPrefix(addr); if (memcmp(addr->ip6.bytes, store->thisNodeAddress, 16) == 0) { printf("got introduced to ourselves\n"); return; } if (addr->ip6.bytes[0] != 0xfc) { uint8_t address[60]; Address_print(address, addr); Log_critical1(store->logger, "tried to insert address %s which does not begin with 0xFC.\n", address); assert(false); } // TODO: maintain a sorted list. uint32_t pfx = Address_getPrefix(addr); if (store->size < store->capacity) { for (uint32_t i = 0; i < store->size; i++) { if (store->headers[i].addressPrefix == pfx && Address_isSameIp(&store->nodes[i].address, addr)) { int red = Address_checkRedundantRoute(&store->nodes[i].address, addr); if (red == 1) { #ifdef Log_DEBUG uint8_t nodeAddr[60]; Address_print(nodeAddr, &store->nodes[i].address); uint8_t newAddr[20]; Address_printNetworkAddress(newAddr, addr); Log_debug2(store->logger, "Found a better route to %s via %s\n", nodeAddr, newAddr); struct Node* n = NodeStore_getNodeByNetworkAddr(addr->networkAddress_be, store); if (n) { Log_warn(store->logger, "This route is probably invalid, giving up.\n"); continue; } #endif store->nodes[i].address.networkAddress_be = addr->networkAddress_be; } else if (red == 0 && store->nodes[i].address.networkAddress_be != addr->networkAddress_be) { // Completely different routes, store seperately. continue; } /*#ifdef Log_DEBUG uint32_t oldReach = store->headers[i].reach; #endif*/ adjustReach(&store->headers[i], reachDifference); /*#ifdef Log_DEBUG if (oldReach != store->headers[i].reach) { uint8_t nodeAddr[60]; Address_print(nodeAddr, addr); Log_debug3(store->logger, "Altering reach for node %s, old reach %u, new reach %u.\n", nodeAddr, oldReach, store->headers[i].reach); if (oldReach > store->headers[i].reach) { Log_debug(store->logger, "Reach was decreased!\n"); } } #endif*/ return; } #ifdef Log_DEBUG else if (store->headers[i].addressPrefix == pfx) { uint8_t realAddr[16]; AddressCalc_addressForPublicKey(realAddr, addr->key); assert(!memcmp(realAddr, addr->ip6.bytes, 16)); } #endif } #ifdef Log_DEBUG uint8_t nodeAddr[60]; Address_print(nodeAddr, addr); Log_debug2(store->logger, "Discovered node: %s reach %u\n", nodeAddr, reachDifference); #endif // Free space, regular insert. replaceNode(&store->nodes[store->size], &store->headers[store->size], addr); adjustReach(&store->headers[store->size], reachDifference); store->size++; return; } // The node whose reach OR distance is the least. // This means nodes who are close and have short reach will be removed uint32_t indexOfNodeToReplace = 0; uint32_t leastReachOrDistance = UINT32_MAX; for (uint32_t i = 0; i < store->size; i++) { uint32_t distance = store->headers[i].addressPrefix ^ pfx; if (distance == 0 && Address_isSame(&store->nodes[i].address, addr)) { // Node already exists adjustReach(&store->headers[store->size], reachDifference); return; } uint32_t reachOrDistance = store->headers[i].reach | distance; if (reachOrDistance < leastReachOrDistance) { leastReachOrDistance = reachOrDistance; indexOfNodeToReplace = i; } } replaceNode(&store->nodes[indexOfNodeToReplace], &store->headers[indexOfNodeToReplace], addr); adjustReach(&store->headers[indexOfNodeToReplace], reachDifference); }