浏览代码

Added two new tests and major refactoring with many bug fixes.

Caleb James DeLisle 11 年之前
父节点
当前提交
0cc47226c0

+ 10 - 1
crypto/CryptoAuth.c

@@ -162,6 +162,8 @@ static inline struct CryptoAuth_Auth* getAuth(union Headers_AuthChallenge auth,
             return &context->passwords[i];
         }
     }
+    Log_debug(context->logger, "Got unrecognized auth, password count = [%d]",
+              context->passwordCount);
     return NULL;
 }
 
@@ -686,6 +688,7 @@ static uint8_t decryptHandshake(struct CryptoAuth_Wrapper* wrapper,
         message->length = 0;
         wrapper->nextNonce = 0;
         wrapper->user = NULL;
+        Log_debug(wrapper->context->logger, "Got a connect-to-me message, sending a hello");
         // Send an empty response (to initiate the connection).
         encryptHandshake(message, wrapper);
         return Error_NONE;
@@ -862,9 +865,15 @@ static uint8_t receiveMessage(struct Message* received, struct Interface* interf
                             wrapper->tempKey,
                             NULL,
                             wrapper->context->logger);
+
+            // We'll optimistically advance the nextNonce value because decryptMessage()
+            // passes the message on to the upper level and if this message causes a
+            // response, we want the CA to be in ESTABLISHED state.
+            // if the decryptMessage() call fails, we CryptoAuth_reset() it back.
+            wrapper->nextNonce += 3;
+
             if (decryptMessage(wrapper, nonce, received, secret)) {
                 Log_debug(wrapper->context->logger, "Final handshake step succeeded.\n");
-                wrapper->nextNonce += 3;
                 Bits_memcpyConst(wrapper->secret, secret, 32);
                 return Error_NONE;
             }

+ 1 - 1
dht/dhtcore/RouterModule.c

@@ -1179,7 +1179,7 @@ int RouterModule_pingNode(struct Node* node,
 void RouterModule_addNode(struct RouterModule* module, struct Address* address, uint32_t version)
 {
     Address_getPrefix(address);
-    NodeStore_addNode(module->nodeStore, address, 0, version);
+    NodeStore_addNode(module->nodeStore, address, 1, version);
     struct Node* best = RouterModule_lookup(address->ip6.bytes, module);
     if (best && best->address.path != address->path) {
         RouterModule_pingNode(best, module, 0, NULL);

+ 4 - 1
interface/InterfaceConnector.c

@@ -19,7 +19,10 @@
 static uint8_t transferMessage(struct Message* msg, struct Interface* iface)
 {
     struct Interface* other = (struct Interface*) iface->receiverContext;
-    return other->sendMessage(msg, other);
+    if (other->sendMessage) {
+        return other->sendMessage(msg, other);
+    }
+    return 0;
 }
 
 /**

+ 21 - 0
memory/Allocator.h

@@ -129,4 +129,25 @@ struct Allocator
     struct Allocator* (* const child)(const struct Allocator* this);
 };
 
+#define Allocator_clone(alloc, content) \
+    alloc->clone(sizeof(*content), alloc, content)
+
+#define Allocator_malloc(alloc, size) \
+    alloc->malloc(size, alloc);
+
+#define Allocator_calloc(alloc, size, count) \
+    alloc->calloc(size, count, alloc)
+
+#define Allocator_onFree(alloc, callback, context) \
+    alloc->onFree(callback, context, alloc)
+
+#define Allocator_notOnFree(alloc, job) \
+    alloc->notOnFree(job, alloc)
+
+#define Allocator_realloc(alloc, orig, size) \
+    alloc->realloc(orig, size, alloc)
+
+#define Allocator_child(alloc) \
+    alloc->child(alloc)
+
 #endif /* MEMALLOCATOR_H */

+ 33 - 19
net/DefaultInterfaceController.c

@@ -93,7 +93,7 @@ struct Endpoint
      * The time of the last incoming message in milliseconds, used to clear out endpoints
      * if they are not responsive.
      */
-    uint32_t timeOfLastMessage;
+    uint64_t timeOfLastMessage;
 
     Identity
 };
@@ -190,7 +190,7 @@ static void onPingResponse(enum SwitchPinger_Result result,
 static void pingCallback(void* vic)
 {
     struct Context* ic = vic;
-    uint32_t now = Time_currentTimeMilliseconds(ic->eventBase);
+    uint64_t now = Time_currentTimeMilliseconds(ic->eventBase);
     ic->pingCount++;
 
     // scan for endpoints have not sent anything recently.
@@ -212,13 +212,15 @@ static void pingCallback(void* vic)
             }
 
             struct SwitchPinger_Ping* ping =
-                SwitchPinger_ping(ep->switchLabel,
-                                  String_CONST(""),
-                                  ic->timeoutMilliseconds,
-                                  onPingResponse,
-                                  ic->switchPinger);
+                SwitchPinger_newPing(ep->switchLabel,
+                                     String_CONST(""),
+                                     ic->timeoutMilliseconds,
+                                     onPingResponse,
+                                     ic->switchPinger);
 
             ping->onResponseContext = ep;
+
+            SwitchPinger_sendPing(ping);
         }
     }
 }
@@ -265,9 +267,17 @@ static uint8_t receivedAfterCryptoAuth(struct Message* msg, struct Interface* cr
             // prevent some kinds of nasty things which could be done with packet replay.
             // This is checking the message switch header and will drop it unless the label
             // directs it to *this* router.
-            if (msg->length < 8 || Bits_memcmp(msg->bytes, "\0\0\0\0\0\0\0\1", 8)) {
+            if (msg->length < 8 || msg->bytes[7] != 1) {
                 Log_info(ic->logger, "Dropping message because CA is not established.");
                 return Error_NONE;
+            } else {
+                // When a "server" gets a new connection from a "client" the router doesn't
+                // know about that client so if the client sends a packet to the server, the
+                // server will be unable to handle it until the client has sent inter-router
+                // communication to the server. Here we will ping the client so when the
+                // server gets the ping response, it will insert the client into it's table
+                // and know it's version.
+                pingCallback(ic);
             }
         }
     }
@@ -296,7 +306,7 @@ static uint8_t sendFromSwitch(struct Message* msg, struct Interface* switchIf)
 
     // If this node is unresponsive then return an error.
     struct Context* ic = interfaceControllerForEndpoint(ep);
-    uint32_t now = Time_currentTimeMilliseconds(ic->eventBase);
+    uint64_t now = Time_currentTimeMilliseconds(ic->eventBase);
     if (ret || now - ep->timeOfLastMessage > ic->unresponsiveAfterMilliseconds)
     {
         msg->bytes = messageBytes;
@@ -395,16 +405,18 @@ static struct Endpoint* insertEndpoint(uint8_t key[InterfaceController_KEY_SIZE]
                                        struct Interface* externalInterface,
                                        struct Context* ic)
 {
-    if (herPublicKey && !AddressCalc_validAddress(herPublicKey)) {
-        return NULL;
+    uint8_t ip6[16];
+    if (herPublicKey) {
+        AddressCalc_addressForPublicKey(ip6, herPublicKey);
+        if (ip6[0] != 0xfc) {
+            return NULL;
+        }
     }
 
     if (ic->endpointMap.count >= CJDNS_MAX_PEERS) {
         return NULL;
     }
 
-
-
     // This is the same no matter what endpoint.
     externalInterface->receiverContext = ic;
     externalInterface->receiveMessage = receiveMessage;
@@ -450,21 +462,23 @@ static struct Endpoint* insertEndpoint(uint8_t key[InterfaceController_KEY_SIZE]
         .allocator = epAllocator
     }), sizeof(struct Interface));
 
-    struct Address addr;
-    Bits_memset(&addr, 0, sizeof(struct Address));
-    if (SwitchCore_addInterface(&ep->switchIf, 0, &addr.path, ic->switchCore)) {
+    if (SwitchCore_addInterface(&ep->switchIf, 0, &ep->switchLabel, ic->switchCore)) {
         return NULL;
     }
 
-    ep->switchLabel = addr.path;
-
     authedIf->receiveMessage = receivedAfterCryptoAuth;
     authedIf->receiverContext = ep;
 
+    // We want the node to immedietly be pinged but we don't want it to appear unresponsive because
+    // the pinger will only ping every (PING_INTERVAL * 8) so we set timeOfLastMessage to
+    // (now - pingAfterMilliseconds - 1) so it will be considered a "lazy node".
+    ep->timeOfLastMessage =
+        Time_currentTimeMilliseconds(ic->eventBase) - ic->pingAfterMilliseconds - 1;
+
     if (herPublicKey) {
         #ifdef Log_INFO
             uint8_t printAddr[60];
-            Address_print(printAddr, &addr);
+            AddrTools_printIp(printAddr, ip6);
             Log_info(ic->logger, "Adding peer [%s]", printAddr);
         #endif
         #ifdef Log_KEYS

+ 105 - 90
net/Ducttape.c

@@ -64,7 +64,7 @@ static void outOfMemory(void* towel)
 
 static inline uint8_t incomingDHT(struct Message* message,
                                   struct Address* addr,
-                                  struct Ducttape_Private* context)
+                                  struct Ducttape_pvt* context)
 {
     struct DHTMessage dht;
     Bits_memset(&dht, 0, sizeof(struct DHTMessage));
@@ -93,7 +93,7 @@ static inline uint8_t incomingDHT(struct Message* message,
 /** Header must not be encrypted and must be aligned on the beginning of the ipv6 header. */
 static inline uint8_t sendToRouter(struct Node* node,
                                    struct Message* message,
-                                   struct Ducttape_Private* context)
+                                   struct Ducttape_pvt* context)
 {
     struct Address* addr = &node->address;
 
@@ -118,7 +118,11 @@ static inline uint8_t sendToRouter(struct Node* node,
     if (session->version) {
         node->version = session->version;
     } else if (node->version) {
+        // If the session is already running, we have to reset it otherwise we
+        // will have a version 1 session but not know the handle for the other
+        // node.
         session->version = node->version;
+        CryptoAuth_reset(&session->iface);
     }
 
     context->session = session;
@@ -129,7 +133,7 @@ static inline uint8_t sendToRouter(struct Node* node,
 static int handleOutgoing(struct DHTMessage* dmessage,
                           void* vcontext)
 {
-    struct Ducttape_Private* context = (struct Ducttape_Private*) vcontext;
+    struct Ducttape_pvt* context = Identity_cast((struct Ducttape_pvt*) vcontext);
 
     struct Message message =
         { .length = dmessage->length, .bytes = (uint8_t*) dmessage->bytes, .padding = 512 };
@@ -204,7 +208,7 @@ static inline bool isRouterTraffic(struct Message* message, struct Headers_IP6He
  * this is called from core() which calls through an interfaceMap.
  */
 static inline uint8_t incomingForMe(struct Message* message,
-                                    struct Ducttape_Private* context,
+                                    struct Ducttape_pvt* context,
                                     uint8_t herPubKey[32])
 {
     struct Address addr;
@@ -299,7 +303,7 @@ uint8_t Ducttape_injectIncomingForMe(struct Message* message,
                                      struct Ducttape* dt,
                                      uint8_t herPublicKey[32])
 {
-    struct Ducttape_Private* context = (struct Ducttape_Private*) dt;
+    struct Ducttape_pvt* context = Identity_cast((struct Ducttape_pvt*)dt);
     struct Headers_SwitchHeader sh;
     Bits_memcpyConst(&sh, message->bytes, Headers_SwitchHeader_SIZE);
     context->switchHeader = &sh;
@@ -338,7 +342,7 @@ static void debugHandles(struct Log* logger, struct SessionManager_Session* sess
  */
 static inline uint8_t sendToSwitch(struct Message* message,
                                    struct Headers_SwitchHeader* destinationSwitchHeader,
-                                   struct Ducttape_Private* context)
+                                   struct Ducttape_pvt* context)
 {
     Message_shift(message, Headers_SwitchHeader_SIZE);
     struct Headers_SwitchHeader* switchHeaderLocation =
@@ -362,7 +366,7 @@ static inline bool validEncryptedIP6(struct Message* message)
         && header->destinationAddr[0] == 0xFC;
 }
 
-static inline bool isForMe(struct Message* message, struct Ducttape_Private* context)
+static inline bool isForMe(struct Message* message, struct Ducttape_pvt* context)
 {
     struct Headers_IP6Header* header = (struct Headers_IP6Header*) message->bytes;
     return (Bits_memcmp(header->destinationAddr, context->myAddr.ip6.bytes, 16) == 0);
@@ -372,7 +376,7 @@ static inline bool isForMe(struct Message* message, struct Ducttape_Private* con
 static inline uint8_t incomingFromTun(struct Message* message,
                                       struct Interface* iface)
 {
-    struct Ducttape_Private* context = (struct Ducttape_Private*) iface->receiverContext;
+    struct Ducttape_pvt* context = Identity_cast((struct Ducttape_pvt*) iface->receiverContext);
     struct Headers_IP6Header* header = (struct Headers_IP6Header*) message->bytes;
 
     int version = Headers_getIpVersion(message->bytes);
@@ -417,23 +421,44 @@ static inline uint8_t incomingFromTun(struct Message* message,
         // 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 (forwardTo).
+    } 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;
     }
-    // else { we don't have *that* node in our store, proceed with forwardTo set to null and
-    // encrypt the message with a session corrisponding to the destination addr then send it to
-    // outgoingFromMe() where the best node to handle it will be looked up. }
-
-    // Grab out the header so it doesn't get clobbered.
-    struct Headers_IP6Header headerStore;
-    Bits_memcpyConst(&headerStore, header, Headers_IP6Header_SIZE);
-    context->ip6Header = &headerStore;
-
-    // Shift over the content.
-    Message_shift(message, -Headers_IP6Header_SIZE);
 
     struct SessionManager_Session* session =
-        SessionManager_getSession(headerStore.destinationAddr, NULL, context->sm);
+        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 it's 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);
+        Bits_memcpyConst(message->bytes, header, Headers_IP6Header_SIZE);
+        Message_shift(message, -(Headers_IP6Header_SIZE + Headers_CryptoAuth_SIZE));
+    } else {
+        Message_shift(message, 20);
+        Bits_memmoveConst(message->bytes, header, Headers_IP6Header_SIZE);
+        Message_shift(message, -(20 + Headers_IP6Header_SIZE));
+    }
+    // The message is now aligned on the content.
 
-    // This comes out at outgoingFromMe()
+    // This comes out at outgoingFromCryptoAuth() then outgoingFromMe()
     context->session = session;
     context->layer = Ducttape_SessionLayer_INNER;
     return session->iface.sendMessage(message, &session->iface);
@@ -447,7 +472,7 @@ static inline uint8_t incomingFromTun(struct Message* message,
  */
 static uint8_t sendToNode(struct Message* message, struct Interface* iface)
 {
-    struct Ducttape_Private* context = iface->receiverContext;
+    struct Ducttape_pvt* context = Identity_cast((struct Ducttape_pvt*)iface->receiverContext);
     struct IpTunnel_PacketInfoHeader* header = (struct IpTunnel_PacketInfoHeader*) message->bytes;
     Message_shift(message, -IpTunnel_PacketInfoHeader_SIZE);
     struct Node* n = RouterModule_lookup(header->nodeIp6Addr, context->routerModule);
@@ -486,7 +511,7 @@ static uint8_t sendToNode(struct Message* message, struct Interface* iface)
  */
 static uint8_t sendToTun(struct Message* message, struct Interface* iface)
 {
-    struct Ducttape_Private* context = iface->receiverContext;
+    struct Ducttape_pvt* context = Identity_cast((struct Ducttape_pvt*)iface->receiverContext);
     if (context->userIf) {
         return context->userIf->sendMessage(message, context->userIf);
     }
@@ -498,7 +523,7 @@ static uint8_t sendToTun(struct Message* message, struct Interface* iface)
  * 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_Private* context)
+static inline int core(struct Message* message, struct Ducttape_pvt* context)
 {
     context->ip6Header = (struct Headers_IP6Header*) message->bytes;
 
@@ -521,19 +546,6 @@ static inline int core(struct Message* message, struct Ducttape_Private* context
                 }
             }
 
-            #ifdef Version_0_COMPAT
-                if (session->version > 0) {
-            #endif
-            // Handle + nonce.
-            if (message->length < 8) {
-                Log_debug(context->logger, "runt");
-                return Error_INVALID;
-            }
-            Message_shift(message, -4);
-            #ifdef Version_0_COMPAT
-                }
-            #endif
-
             #ifdef Log_DEBUG
                 uint8_t addr[40];
                 AddrTools_printIp(addr, context->ip6Header->sourceAddr);
@@ -600,36 +612,43 @@ static inline int core(struct Message* message, struct Ducttape_Private* context
 /**
  * When we send a message it goes into the CryptoAuth.
  * for the content level crypto then it goes to outgoingFromCryptoAuth then comes here.
- * Message is aligned on the beginning of the crypto header, ip6 header must be reapplied.
+ * Message is aligned on the beginning of the CryptoAuth header.
  */
-static inline uint8_t outgoingFromMe(struct Message* message, struct Ducttape_Private* context)
+static inline uint8_t outgoingFromMe(struct Message* message, struct Ducttape_pvt* context)
 {
-    // Need to set the length field to take into account
-    // the crypto headers which are hidden under the ipv6 packet.
-    context->ip6Header->payloadLength_be = Endian_hostToBigEndian16(message->length);
+    // incomingFromTun checks the state of the CA session and puts the IP6 header in the
+    // right place so that it will be right behind the cryptoauth header.
 
     Message_shift(message, Headers_IP6Header_SIZE);
+    struct Headers_IP6Header* header = (struct Headers_IP6Header*) message->bytes;
+
+    if (!Bits_memcmp(header->destinationAddr, context->myAddr.ip6.bytes, 16)) {
+        // This happens when an empty connect-to-me packet is sent to us,
+        // CryptoAuth is called with a message and instead of returning a decrypted message
+        // to send to the TUN, it outputs a message to send back down the wire but the
+        // header is still the same.
+        // these messages are always empty so we just flip the source and destination around
+        // and send it back.
+        Bits_memcpyConst(header->destinationAddr, header->sourceAddr, 16);
+        Bits_memcpyConst(header->sourceAddr, context->myAddr.ip6.bytes, 16);
 
-    // If this message is addressed to us, it means the cryptoauth kicked back a response
-    // message when we asked it to decrypt a message for us and the ipv6 addresses need to
-    // be flipped to send it back to the other node.
-    if (isForMe(message, context)) {
-        struct Headers_IP6Header* ip6 = (struct Headers_IP6Header*) message->bytes;
-        Assert_true(context->ip6Header == ip6);
-        Bits_memcpyConst(ip6->destinationAddr, ip6->sourceAddr, 16);
-        Bits_memcpyConst(ip6->sourceAddr, &context->myAddr.ip6.bytes, 16);
-        // Say it came from us...
-        //context->routerAddress = context->myAddr.ip6.bytes; TODO should not be needed
     } else {
-        Bits_memcpyConst(message->bytes, context->ip6Header, Headers_IP6Header_SIZE);
+        // sanity check.
+        Assert_true(!Bits_memcmp(header->sourceAddr, context->myAddr.ip6.bytes, 16));
     }
 
+    // Need to set the length field to take into account
+    // the crypto headers which are hidden under the ipv6 packet.
+    header->payloadLength_be =
+        Endian_hostToBigEndian16(message->length - Headers_IP6Header_SIZE);
+
+
     // Forward this call to core() which will check it's validity
     // and since it's not to us, forward it to the correct node.
     return core(message, context);
 }
 
-static inline int incomingFromRouter(struct Message* message, struct Ducttape_Private* context)
+static inline int incomingFromRouter(struct Message* message, struct Ducttape_pvt* context)
 {
     if (!validEncryptedIP6(message)) {
         // Not valid cjdns IPv6, we'll try it as an IPv4 or ICANN-IPv6 packet
@@ -653,7 +672,7 @@ static inline int incomingFromRouter(struct Message* message, struct Ducttape_Pr
 
 static uint8_t incomingFromCryptoAuth(struct Message* message, struct Interface* iface)
 {
-    struct Ducttape_Private* context = (struct Ducttape_Private*) iface->receiverContext;
+    struct Ducttape_pvt* context = Identity_cast((struct Ducttape_pvt*) iface->receiverContext);
     enum Ducttape_SessionLayer layer = context->layer;
     context->layer = Ducttape_SessionLayer_INVALID;
     switch (layer) {
@@ -672,43 +691,39 @@ static uint8_t incomingFromCryptoAuth(struct Message* message, struct Interface*
 
 static uint8_t outgoingFromCryptoAuth(struct Message* message, struct Interface* iface)
 {
-    struct Ducttape_Private* context = (struct Ducttape_Private*) iface->senderContext;
+    struct Ducttape_pvt* context = Identity_cast((struct Ducttape_pvt*) iface->senderContext);
+
     enum Ducttape_SessionLayer layer = context->layer;
     context->layer = Ducttape_SessionLayer_INVALID;
 
     // Tag the message with the proper handle.
     struct SessionManager_Session* session = context->session;
-    if (session->version > 0) {
-        // If the session is established, we send their handle for the session,
-        // otherwise we send ours.
-        int state = CryptoAuth_getState(&session->iface);
-        if (state >= CryptoAuth_HANDSHAKE3 && layer == Ducttape_SessionLayer_OUTER) {
-            debugHandles(context->logger, session, "Sending run message");
-
-            Message_shift(message, 4);
-            ((uint32_t*)message->bytes)[0] = session->sendHandle_be;
-        } else if (state < CryptoAuth_HANDSHAKE3) {
-            debugHandles(context->logger, session, "Sending start message");
-
-            // the most significant bit in a handle is reserved to tell the recipient if it is
-            // an initiation handle or a running handle which they should look up in their map.
-            Message_shift(message, 4);
-            ((uint32_t*)message->bytes)[0] = session->receiveHandle_be;
+    if (layer == Ducttape_SessionLayer_OUTER) {
+        if (session->version > 0) {
+            // If the session is established, we send their handle for the session,
+            // otherwise we send ours.
+            int state = CryptoAuth_getState(&session->iface);
+            if (state >= CryptoAuth_HANDSHAKE3) {
+                debugHandles(context->logger, session, "Sending run message");
+
+                Message_shift(message, 4);
+                ((uint32_t*)message->bytes)[0] = session->sendHandle_be;
+            } else if (state < CryptoAuth_HANDSHAKE3) {
+                debugHandles(context->logger, session, "Sending start message");
+
+                // the most significant bit in a handle is reserved to tell the recipient if it is
+                // an initiation handle or a running handle which they should look up in their map.
+                Message_shift(message, 4);
+                ((uint32_t*)message->bytes)[0] = session->receiveHandle_be;
+            }
+        } else {
+            debugHandles(context->logger, session, "Sending protocol 0 message");
         }
+        return sendToSwitch(message, context->switchHeader, context);
     } else {
-        debugHandles(context->logger, session, "Sending protocol 0 message");
+        Log_debug(context->logger, "Sending layer3 message");
+        return outgoingFromMe(message, context);
     }
-
-    switch (layer) {
-        case Ducttape_SessionLayer_OUTER:
-            return sendToSwitch(message, context->switchHeader, context);
-        case Ducttape_SessionLayer_INNER:
-            return outgoingFromMe(message, context);
-        default:
-            Assert_always(false);
-    }
-    // never reached.
-    return 0;
 }
 
 /**
@@ -720,7 +735,7 @@ static uint8_t outgoingFromCryptoAuth(struct Message* message, struct Interface*
  * @param switchHeader the header.
  * @param switchIf the interface which leads to the switch.
  */
-static uint8_t handleControlMessage(struct Ducttape_Private* context,
+static uint8_t handleControlMessage(struct Ducttape_pvt* context,
                                     struct Message* message,
                                     struct Headers_SwitchHeader* switchHeader,
                                     struct Interface* switchIf)
@@ -880,7 +895,7 @@ static inline uint8_t* extractPublicKey(struct Message* message,
  */
 static uint8_t incomingFromSwitch(struct Message* message, struct Interface* switchIf)
 {
-    struct Ducttape_Private* context = switchIf->senderContext;
+    struct Ducttape_pvt* context = Identity_cast((struct Ducttape_pvt*)switchIf->senderContext);
     struct Headers_SwitchHeader* switchHeader = (struct Headers_SwitchHeader*) message->bytes;
     Message_shift(message, -Headers_SwitchHeader_SIZE);
 
@@ -985,7 +1000,7 @@ static uint8_t incomingFromSwitch(struct Message* message, struct Interface* swi
 
 static uint8_t incomingFromPinger(struct Message* message, struct Interface* iface)
 {
-    struct Ducttape_Private* context = iface->senderContext;
+    struct Ducttape_pvt* context = Identity_cast((struct Ducttape_pvt*)iface->senderContext);
     return context->switchInterface.receiveMessage(message, &context->switchInterface);
 }
 
@@ -1000,12 +1015,12 @@ struct Ducttape* Ducttape_register(uint8_t privateKey[32],
                                    struct IpTunnel* ipTun,
                                    struct Random* rand)
 {
-    struct Ducttape_Private* context =
-        allocator->calloc(sizeof(struct Ducttape_Private), 1, allocator);
+    struct Ducttape_pvt* context = allocator->calloc(sizeof(struct Ducttape_pvt), 1, allocator);
     context->registry = registry;
     context->routerModule = routerModule;
     context->logger = logger;
     context->forwardTo = NULL;
+    Identity_set(context);
 
     #ifdef Version_0_COMPAT
         AddressMapper_init(&context->addrMap);
@@ -1059,7 +1074,7 @@ struct Ducttape* Ducttape_register(uint8_t privateKey[32],
 
 void Ducttape_setUserInterface(struct Ducttape* dt, struct Interface* userIf)
 {
-    struct Ducttape_Private* context = (struct Ducttape_Private*) dt;
+    struct Ducttape_pvt* context = Identity_cast((struct Ducttape_pvt*) dt);
     context->userIf = userIf;
     userIf->receiveMessage = incomingFromTun;
     userIf->receiverContext = context;

+ 5 - 2
net/Ducttape_pvt.h

@@ -26,9 +26,10 @@
 #include "interface/Interface.h"
 #include "util/log/Log.h"
 #include "net/Ducttape.h"
+#include "util/events/EventBase.h"
+#include "util/Identity.h"
 
 #include <stdint.h>
-#include "util/events/EventBase.h"
 
 enum Ducttape_SessionLayer {
     Ducttape_SessionLayer_INVALID = 0,
@@ -44,7 +45,7 @@ enum Ducttape_SessionLayer {
  * and send the message toward the DHT core.
  */
 
-struct Ducttape_Private
+struct Ducttape_pvt
 {
     /** the public fields. */
     struct Ducttape public;
@@ -110,6 +111,8 @@ struct Ducttape_Private
 
     /** For tunneling IPv4 and ICANN IPv6 packets. */
     struct IpTunnel* ipTunnel;
+
+    Identity
 };
 
 #endif

+ 25 - 12
net/SwitchPinger.c

@@ -20,6 +20,7 @@
 #include "util/Endian.h"
 #include "util/Pinger.h"
 #include "util/version/Version.h"
+#include "util/Identity.h"
 #include "wire/Headers.h"
 #include "wire/Control.h"
 #include "wire/Error.h"
@@ -47,6 +48,8 @@ struct SwitchPinger
     uint32_t incomingVersion;
 
     bool isError;
+
+    Identity
 };
 
 struct Ping
@@ -57,12 +60,14 @@ struct Ping
     struct SwitchPinger* context;
     SwitchPinger_ResponseCallback onResponse;
     void* onResponseContext;
+    struct Pinger_Ping* pingerPing;
+    Identity
 };
 
 // incoming message from network, pointing to the beginning of the switch header.
 static uint8_t receiveMessage(struct Message* msg, struct Interface* iface)
 {
-    struct SwitchPinger* ctx = iface->receiverContext;
+    struct SwitchPinger* ctx = Identity_cast((struct SwitchPinger*) iface->receiverContext);
     struct Headers_SwitchHeader* switchHeader = (struct Headers_SwitchHeader*) msg->bytes;
     ctx->incomingLabel = Endian_bigEndianToHost64(switchHeader->label_be);
     ctx->incomingVersion = 0;
@@ -107,10 +112,10 @@ static uint8_t receiveMessage(struct Message* msg, struct Interface* iface)
         ctx->isError = true;
 
     } else {
-        Assert_true(false);
+        // If it gets here then Ducttape.c is failing.
+        Assert_always(false);
     }
 
-
     String* msgStr = &(String) { .bytes = (char*) msg->bytes, .len = msg->length };
     Pinger_pongReceived(msgStr, ctx->pinger);
     return Error_NONE;
@@ -118,7 +123,7 @@ static uint8_t receiveMessage(struct Message* msg, struct Interface* iface)
 
 static void onPingResponse(String* data, uint32_t milliseconds, void* vping)
 {
-    struct Ping* p = vping;
+    struct Ping* p = Identity_cast((struct Ping*) vping);
     enum SwitchPinger_Result err = SwitchPinger_Result_OK;
     uint64_t label = p->context->incomingLabel;
     if (data) {
@@ -139,7 +144,7 @@ static void onPingResponse(String* data, uint32_t milliseconds, void* vping)
 
 static void sendPing(String* data, void* sendPingContext)
 {
-    struct Ping* p = (struct Ping*) sendPingContext;
+    struct Ping* p = Identity_cast((struct Ping*) sendPingContext);
     #define BUFFER_SZ 4096
     uint8_t buffer[BUFFER_SZ];
     struct Message msg = {
@@ -201,18 +206,18 @@ String* SwitchPinger_resultString(enum SwitchPinger_Result result)
     };
 }
 
-struct SwitchPinger_Ping* SwitchPinger_ping(uint64_t label,
-                                            String* data,
-                                            uint32_t timeoutMilliseconds,
-                                            SwitchPinger_ResponseCallback onResponse,
-                                            struct SwitchPinger* ctx)
+struct SwitchPinger_Ping* SwitchPinger_newPing(uint64_t label,
+                                               String* data,
+                                               uint32_t timeoutMilliseconds,
+                                               SwitchPinger_ResponseCallback onResponse,
+                                               struct SwitchPinger* ctx)
 {
     if (data && data->len > Control_Ping_MAX_SIZE) {
         return NULL;
     }
 
     struct Pinger_Ping* pp =
-        Pinger_ping(data, onPingResponse, sendPing, timeoutMilliseconds, ctx->pinger);
+        Pinger_newPing(data, onPingResponse, sendPing, timeoutMilliseconds, ctx->pinger);
 
     if (!pp) {
         return NULL;
@@ -227,13 +232,20 @@ struct SwitchPinger_Ping* SwitchPinger_ping(uint64_t label,
             .data = String_clone(data, pp->pingAlloc),
             .context = ctx,
             .onResponse = onResponse,
+            .pingerPing = pp
         });
-
+    Identity_set(ping);
     pp->context = ping;
 
     return &ping->public;
 }
 
+void SwitchPinger_sendPing(struct SwitchPinger_Ping* ping)
+{
+    struct Ping* p = Identity_cast((struct Ping*) ping);
+    Pinger_sendPing(p->pingerPing);
+}
+
 struct SwitchPinger* SwitchPinger_new(struct Interface* iface,
                                       struct event_base* eventBase,
                                       struct Log* logger,
@@ -248,5 +260,6 @@ struct SwitchPinger* SwitchPinger_new(struct Interface* iface,
     }), sizeof(struct SwitchPinger));
     iface->receiveMessage = receiveMessage;
     iface->receiverContext = sp;
+    Identity_set(sp);
     return sp;
 }

+ 13 - 6
net/SwitchPinger.h

@@ -79,17 +79,24 @@ struct SwitchPinger;
 String* SwitchPinger_resultString(enum SwitchPinger_Result result);
 
 /**
- * Send a ping message.
+ * Allocate a ping message.
  *
  * @param label the HOST ORDER label of the node to send the ping message to.
  * @param data the content of the ping to send, if NULL, an empty string will be
  *             returned in the response.
  */
-struct SwitchPinger_Ping* SwitchPinger_ping(uint64_t label,
-                                            String* data,
-                                            uint32_t timeoutMilliseconds,
-                                            SwitchPinger_ResponseCallback onResponse,
-                                            struct SwitchPinger* sp);
+struct SwitchPinger_Ping* SwitchPinger_newPing(uint64_t label,
+                                               String* data,
+                                               uint32_t timeoutMilliseconds,
+                                               SwitchPinger_ResponseCallback onResponse,
+                                               struct SwitchPinger* sp);
+
+/**
+ * Send a ping message after allocating a callback structure for it.
+ *
+ * @param ping the ping to send.
+ */
+void SwitchPinger_sendPing(struct SwitchPinger_Ping* ping);
 
 struct SwitchPinger* SwitchPinger_new(struct Interface* iface,
                                       struct event_base* eventBase,

+ 2 - 1
net/SwitchPinger_admin.c

@@ -80,7 +80,7 @@ static void adminPing(Dict* args, void* vcontext, String* txid)
         err = String_CONST("path was not parsable.");
     } else {
         struct SwitchPinger_Ping* ping =
-            SwitchPinger_ping(path, data, timeout, adminPingOnResponse, context->switchPinger);
+            SwitchPinger_newPing(path, data, timeout, adminPingOnResponse, context->switchPinger);
         if (!ping) {
             err = String_CONST("no open slots to store ping, try later.");
         } else {
@@ -89,6 +89,7 @@ static void adminPing(Dict* args, void* vcontext, String* txid)
                     .context = context,
                     .txid = String_clone(txid, ping->pingAlloc),
                 });
+            SwitchPinger_sendPing(ping);
         }
     }
 

+ 12 - 22
net/test/DefaultInterfaceController_test.c

@@ -31,6 +31,7 @@
 #include "switch/NumberCompress.h"
 #include "switch/SwitchCore.h"
 #include "wire/Headers.h"
+#include "test/TestFramework.h"
 
 static uint8_t messageFromInterface(struct Message* message, struct Interface* thisIf)
 {
@@ -146,42 +147,31 @@ static int reconnectionNewEndpointTest(struct InterfaceController* ifController,
 int main()
 {
     struct Allocator* alloc = MallocAllocator_new(1<<20);
-    struct Random* rand = Random_new(alloc, NULL);
-    struct event_base* eventBase = EventBase_new(alloc);
 
-    struct Writer* logwriter = FileWriter_new(stdout, alloc);
-    struct Log* logger = WriterLog_new(logwriter, alloc);
+    struct TestFramework* tf =
+        TestFramework_setUp("\xad\x7e\xa3\x26\xaa\x01\x94\x0a\x25\xbc\x9e\x01\x26\x22\xdb\x69"
+                            "\x4f\xd9\xb4\x17\x7c\xf3\xf8\x91\x16\xf3\xcf\xe8\x5c\x80\xe1\x4a",
+                            alloc, NULL);
 
-    struct CryptoAuth* ca = CryptoAuth_new(alloc, NULL, eventBase, logger, rand);
-    uint8_t publicKey[32];
-    Bits_memcpyConst(publicKey, ca->publicKey, 32);
-    CryptoAuth_addUser(String_CONST("passwd"), 1, (void*)0x01, ca);
+    CryptoAuth_addUser(String_CONST("passwd"), 1, (void*)0x01, tf->cryptoAuth);
 
-    struct SwitchCore* switchCore = SwitchCore_new(logger, alloc);
     struct Message* message;
     struct Interface iface = {
         .sendMessage = messageFromInterface,
         .senderContext = &message,
         .allocator = alloc
     };
-    SwitchCore_setRouterInterface(&iface, switchCore);
+    SwitchCore_setRouterInterface(&iface, tf->switchCore);
 
-    // These are unused.
-    struct DHTModuleRegistry* registry = DHTModuleRegistry_new(alloc);
-    struct RouterModule* rm =
-        RouterModule_register(registry, alloc, publicKey, eventBase, logger, NULL, rand);
-
-    struct InterfaceController* ifController =
-        DefaultInterfaceController_new(ca, switchCore, rm, logger, eventBase, NULL, alloc);
 
     ////////////////////////
 
-    return reconnectionNewEndpointTest(ifController,
-                                       publicKey,
+    return reconnectionNewEndpointTest(tf->ifController,
+                                       tf->publicKey,
                                        &message,
                                        alloc,
-                                       eventBase,
-                                       logger,
+                                       tf->eventBase,
+                                       tf->logger,
                                        &iface,
-                                       rand);
+                                       tf->rand);
 }

+ 102 - 12
test/TestFramework.c

@@ -25,24 +25,38 @@
 #include "test/TestFramework.h"
 #include "util/log/WriterLog.h"
 #include "util/events/EventBase.h"
+#include "net/SwitchPinger.h"
+#include "net/DefaultInterfaceController.h"
 
-struct Ducttape* TestFramework_setUp()
+#include "crypto_scalarmult_curve25519.h"
+
+static uint8_t sendTo(struct Message* msg, struct Interface* iface)
 {
-    uint8_t* privateKey = (uint8_t*) "0123456789abcdefghijklmnopqrstuv";
-    uint8_t* publicKey = (uint8_t*)
-        "\x3f\x5b\x96\x62\x11\x11\xd8\x9c\x7d\x3f\x51\x71\x68\x78\xfa\xb4"
-        "\xc3\xcf\xd9\x7e\x32\x04\x12\xb4\xaf\x7e\x22\x92\xa5\xdf\x31\x71";
+    struct Interface* destIf = (struct Interface*) iface->senderContext;
+    printf("Transferring message to [%p]\n", (void*)destIf);
+    return destIf->receiveMessage(msg, destIf);
+}
 
-    // Allow it to allocate 4MB
-    struct Allocator* allocator = MallocAllocator_new(1<<22);
+struct TestFramework* TestFramework_setUp(char* privateKey,
+                                          struct Allocator* allocator,
+                                          struct Log* logger)
+{
     struct Random* rand = Random_new(allocator, NULL);
     struct EventBase* base = EventBase_new(allocator);
 
-    struct Writer* logwriter = FileWriter_new(stdout, allocator);
-    struct Log* logger = WriterLog_new(logwriter, allocator);
+    if (!logger) {
+        struct Writer* logwriter = FileWriter_new(stdout, allocator);
+        logger = WriterLog_new(logwriter, allocator);
+    }
+
+    uint8_t* publicKey = allocator->malloc(32, allocator);
+    crypto_scalarmult_curve25519_base(publicKey, (uint8_t*)privateKey);
+
+    uint8_t* ip = Allocator_malloc(allocator, 16);
+    AddressCalc_addressForPublicKey(ip, publicKey);
 
     struct SwitchCore* switchCore = SwitchCore_new(logger, allocator);
-    //struct CryptoAuth* ca = CryptoAuth_new(NULL, allocator, privateKey, base, logger);
+    struct CryptoAuth* ca = CryptoAuth_new(allocator, (uint8_t*)privateKey, base, logger, rand);
 
     struct DHTModuleRegistry* registry = DHTModuleRegistry_new(allocator);
     ReplyModule_register(registry, allocator);
@@ -54,6 +68,82 @@ struct Ducttape* TestFramework_setUp()
 
     struct IpTunnel* ipTun = IpTunnel_new(logger, base, allocator, rand);
 
-    return Ducttape_register(privateKey, registry, routerModule,
-                             switchCore, base, allocator, logger, NULL, ipTun, rand);
+    struct Ducttape* dt =
+        Ducttape_register((uint8_t*)privateKey, registry, routerModule,
+                          switchCore, base, allocator, logger, NULL, ipTun, rand);
+
+    struct SwitchPinger* sp = SwitchPinger_new(&dt->switchPingerIf, base, logger, allocator);
+
+    // Interfaces.
+    struct InterfaceController* ifController =
+        DefaultInterfaceController_new(ca,
+                                       switchCore,
+                                       routerModule,
+                                       logger,
+                                       base,
+                                       sp,
+                                       allocator);
+
+    struct TestFramework* tf = Allocator_clone(allocator, (&(struct TestFramework) {
+        .alloc = allocator,
+        .rand = rand,
+        .eventBase = base,
+        .logger = logger,
+        .switchCore = switchCore,
+        .ducttape = dt,
+        .cryptoAuth = ca,
+        .router = routerModule,
+        .switchPinger = sp,
+        .ifController = ifController,
+        .publicKey = publicKey,
+        .ip = ip
+    }));
+
+    return tf;
+}
+
+
+void TestFramework_linkNodes(struct TestFramework* client, struct TestFramework* server)
+{
+    struct Interface* ifaceB = Allocator_malloc(client->alloc, sizeof(struct Interface));
+    struct Interface* ifaceA = Allocator_clone(client->alloc, (&(struct Interface) {
+        .sendMessage = sendTo,
+        .senderContext = ifaceB,
+        .allocator = client->alloc
+    }));
+    Bits_memcpyConst(ifaceB, (&(struct Interface){
+        .sendMessage = sendTo,
+        .senderContext = ifaceA,
+        .allocator = client->alloc
+    }), sizeof(struct Interface));
+
+    client->ifController->registerInterface(ifaceA, client->ifController);
+    server->ifController->registerInterface(ifaceB, server->ifController);
+
+    // The server gets the authorized password and the client gets the connectTo
+    CryptoAuth_addUser(String_CONST("abcdefg1234"), 1, (void*)0x1, server->cryptoAuth);
+
+    uint8_t key[InterfaceController_KEY_SIZE];
+    Random_bytes(client->rand, key, InterfaceController_KEY_SIZE);
+
+    client->ifController->insertEndpoint(key,
+                                         server->publicKey,
+                                         String_CONST("abcdefg1234"),
+                                         ifaceA,
+                                         client->ifController);
+}
+
+void TestFramework_craftIPHeader(struct Message* msg, uint8_t srcAddr[16], uint8_t destAddr[16])
+{
+    Message_shift(msg, Headers_IP6Header_SIZE);
+    struct Headers_IP6Header* ip = (struct Headers_IP6Header*) msg->bytes;
+
+    ip->versionClassAndFlowLabel = 0;
+    ip->flowLabelLow_be = 0;
+    ip->payloadLength_be = Endian_hostToBigEndian16(msg->length - Headers_IP6Header_SIZE);
+    ip->nextHeader = 123; // made up number
+    ip->hopLimit = 255;
+    Bits_memcpyConst(ip->sourceAddr, srcAddr, 16);
+    Bits_memcpyConst(ip->destinationAddr, destAddr, 16);
+    Headers_setIpVersion(ip);
 }

+ 24 - 1
test/TestFramework.h

@@ -17,6 +17,29 @@
 
 #include "net/Ducttape.h"
 
-struct Ducttape* TestFramework_setUp();
+struct TestFramework
+{
+    struct Allocator* alloc;
+    struct Random* rand;
+    struct EventBase* eventBase;
+    struct Log* logger;
+    struct SwitchCore* switchCore;
+    struct Ducttape* ducttape;
+    struct CryptoAuth* cryptoAuth;
+    struct RouterModule* router;
+    struct SwitchPinger* switchPinger;
+    struct InterfaceController* ifController;
+    uint8_t* publicKey;
+    uint8_t* ip;
+};
+
+
+struct TestFramework* TestFramework_setUp(char* privateKey,
+                                          struct Allocator* allocator,
+                                          struct Log* logger);
+
+void TestFramework_linkNodes(struct TestFramework* client, struct TestFramework* server);
+
+void TestFramework_craftIPHeader(struct Message* msg, uint8_t srcAddr[16], uint8_t destAddr[16]);
 
 #endif

+ 7 - 1
test/cjdroute_injection_test.c

@@ -70,8 +70,11 @@ int main()
         "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
         "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
 
-    struct Ducttape* dt = TestFramework_setUp();
+    struct Allocator* alloc = MallocAllocator_new(1<<22);
+    struct Ducttape* dt =
+        TestFramework_setUp("0123456789abcdefghijklmnopqrstuv", alloc, NULL)->ducttape;
 
+    // This has to be limited because we are checking for an OOM issue.
     struct Allocator* allocator = MallocAllocator_new(85000);
     uint16_t buffLen = sizeof(struct Ducttape_IncomingForMe) + 8 + strlen(evilBenc);
     uint8_t* buff = allocator->calloc(buffLen, 1, allocator);
@@ -91,4 +94,7 @@ int main()
     struct Message m = { .bytes = buff, .length = buffLen, .padding = 0 };
 
     Ducttape_injectIncomingForMe(&m, dt, herPublicKey);
+
+    alloc->free(alloc);
+    allocator->free(allocator);
 }

+ 4 - 4
test/cjdroute_routerPing_test.c

@@ -16,12 +16,11 @@
 #define string_strlen
 #include "memory/MallocAllocator.h"
 #include "memory/Allocator.h"
-#include "net/Ducttape_pvt.h"
 #include "util/Base32.h"
 #include "util/Checksum.h"
 #include "util/platform/libc/string.h"
-
 #include "test/TestFramework.h"
+#include "net/Ducttape_pvt.h"
 
 #include <stdio.h>
 
@@ -34,8 +33,9 @@ uint8_t catchResponse(struct Message* msg, struct Interface* iface)
 int main()
 {
     char* pingBenc = "d1:q4:ping4:txid4:abcde";
-
-    struct Ducttape_Private* dt = (struct Ducttape_Private*) TestFramework_setUp();
+    struct Allocator* alloc = MallocAllocator_new(1<<22);
+    struct TestFramework* tf = TestFramework_setUp("0123456789abcdefghijklmnopqrstuv", alloc, NULL);
+    struct Ducttape_pvt* dt = Identity_cast((struct Ducttape_pvt*) tf->ducttape);
 
     struct Allocator* allocator = MallocAllocator_new(85000);
     uint16_t buffLen = sizeof(struct Ducttape_IncomingForMe) + 8 + strlen(pingBenc);

+ 199 - 0
test/threeNodes_test.c

@@ -0,0 +1,199 @@
+/* vim: set expandtab ts=4 sw=4: */
+/*
+ * You may redistribute this program and/or modify it under the terms of
+ * the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#define string_strncpy
+#define string_strlen
+#include "crypto/Key.h"
+#include "io/FileWriter.h"
+#include "memory/MallocAllocator.h"
+#include "memory/Allocator.h"
+#include "util/Base32.h"
+#include "util/Checksum.h"
+#include "util/platform/libc/string.h"
+#include "util/log/WriterLog.h"
+#include "test/TestFramework.h"
+#include "net/Ducttape_pvt.h"
+
+#include "wire/Headers.h"
+
+#include <stdio.h>
+
+#define TUNC 3
+#define TUNB 2
+#define TUNA 1
+uint8_t incomingTunC(struct Message* msg, struct Interface* iface)
+{
+    Message_shift(msg, -Headers_IP6Header_SIZE);
+    printf("Message from TUN in node C [%s] [%d]\n", msg->bytes, msg->length);
+    *((int*)iface->senderContext) = TUNC;
+    return 0;
+}
+uint8_t incomingTunB(struct Message* msg, struct Interface* iface)
+{
+    Message_shift(msg, -Headers_IP6Header_SIZE);
+    printf("Message from TUN in node B [%s]\n", msg->bytes);
+    *((int*)iface->senderContext) = TUNB;
+    return 0;
+}
+uint8_t incomingTunA(struct Message* msg, struct Interface* iface)
+{
+    Message_shift(msg, -Headers_IP6Header_SIZE);
+    uint8_t buff[1024];
+    Hex_encode(buff, 1024, msg->bytes, msg->length);
+    printf("Message from TUN in node A [%s] [%d] [%s]\n", msg->bytes, msg->length, buff);
+    *((int*)iface->senderContext) = TUNA;
+    return 0;
+}
+
+struct ThreeNodes
+{
+    struct Interface tunIfC;
+    struct TestFramework* nodeC;
+
+    struct Interface tunIfB;
+    struct TestFramework* nodeB;
+
+    struct Interface tunIfA;
+    struct TestFramework* nodeA;
+    int messageFrom;
+};
+
+static struct ThreeNodes* setUp(struct Allocator* alloc)
+{
+    struct Writer* logwriter = FileWriter_new(stdout, alloc);
+    struct Log* logger = WriterLog_new(logwriter, alloc);
+
+    struct TestFramework* a =
+        TestFramework_setUp("\xad\x7e\xa3\x26\xaa\x01\x94\x0a\x25\xbc\x9e\x01\x26\x22\xdb\x69"
+                            "\x4f\xd9\xb4\x17\x7c\xf3\xf8\x91\x16\xf3\xcf\xe8\x5c\x80\xe1\x4a",
+                            alloc, logger);
+    //"publicKey": "kmzm4w0kj9bswd5qmx74nu7kusv5pj40vcsmp781j6xxgpd59z00.k",
+    //"ipv6": "fc41:94b5:0925:7ba9:3959:11ab:a006:367a",
+
+    struct TestFramework* b =
+        TestFramework_setUp("\xea\x8d\x34\x04\xa9\x7c\xe4\xf9\xca\x7e\x24\xe6\xf1\x85\xb9\x3f"
+                            "\x01\x37\xb7\xa1\xf5\x2c\xce\xc0\x2c\xae\x03\xf1\x83\x38\x13\x24",
+                            alloc, logger);
+    // This address was found by brute force for one which falls between A and C without being
+    // closer in either direction (XOR is bidirectional address space distance)
+    // ipv6: fc2e:3273:644e:426f:283d:e3c7:c87c:41c1
+
+    struct TestFramework* c =
+        TestFramework_setUp("\xd8\x54\x3e\x70\xb9\xae\x7c\x41\xbc\x18\xa4\x9a\x9c\xee\xca\x9c"
+                            "\xdc\x45\x01\x96\x6b\xbd\x7e\x76\xcf\x3a\x9f\xbc\x12\xed\x8b\xb4",
+                            alloc, logger);
+    //"publicKey": "vz21tg07061s8v9mckrvgtfds7j2u5lst8cwl6nqhp81njrh5wg0.k",
+    //"ipv6": "fc1f:5b96:e1c5:625d:afde:2523:a7fa:383a",
+
+    Log_debug(a->logger, "Linking A and B");
+    TestFramework_linkNodes(b, a);
+    Log_debug(a->logger, "Linking A and B complete");
+    Log_debug(a->logger, "Linking B and C");
+    TestFramework_linkNodes(c, b);
+    Log_debug(a->logger, "Linking B and C complete");
+
+    struct ThreeNodes* out = Allocator_malloc(alloc, sizeof(struct ThreeNodes));
+
+    Bits_memcpyConst(out, (&(struct ThreeNodes) {
+        .tunIfC = {
+            .allocator = alloc,
+            .sendMessage = incomingTunC,
+            .senderContext = &out->messageFrom
+        },
+        .nodeC = c,
+        .tunIfB = {
+            .allocator = alloc,
+            .sendMessage = incomingTunB,
+            .senderContext = &out->messageFrom
+        },
+        .nodeB = b,
+        .tunIfA = {
+            .allocator = alloc,
+            .sendMessage = incomingTunA,
+            .senderContext = &out->messageFrom
+        },
+        .nodeA = a
+    }), sizeof(struct ThreeNodes));
+
+    Ducttape_setUserInterface(c->ducttape, &out->tunIfC);
+    Ducttape_setUserInterface(b->ducttape, &out->tunIfB);
+    Ducttape_setUserInterface(a->ducttape, &out->tunIfA);
+
+    Log_debug(a->logger, "Setup complete.");
+
+    return out;
+}
+
+void sendMessage(struct ThreeNodes* tn,
+                 char* message,
+                 struct TestFramework* from,
+                 struct TestFramework* to)
+{
+    struct Message* msg;
+    Message_STACK(msg, 64, 512);
+
+    Bits_memcpy(msg->bytes, message, strlen(message) + 1);
+    msg->length = strlen(message) + 1;
+
+    TestFramework_craftIPHeader(msg, from->ip, to->ip);
+    struct Interface* fromIf;
+
+    if (from == tn->nodeA) {
+        fromIf = &tn->tunIfA;
+    } else if (from == tn->nodeB) {
+        fromIf = &tn->tunIfB;
+    } else if (from == tn->nodeC) {
+        fromIf = &tn->tunIfC;
+    } else {
+        Assert_always(false);
+    }
+
+    fromIf->receiveMessage(msg, fromIf);
+
+    if (to == tn->nodeA) {
+        Assert_always(tn->messageFrom == TUNA);
+    } else if (to == tn->nodeB) {
+        Assert_always(tn->messageFrom == TUNB);
+    } else if (to == tn->nodeC) {
+        Assert_always(tn->messageFrom == TUNC);
+    } else {
+        Assert_always(false);
+    }
+
+    tn->messageFrom = 0;
+}
+
+/** Check if nodes A and C can communicate via B without A knowing that C exists. */
+int main()
+{
+    struct Allocator* alloc = MallocAllocator_new(1<<22);
+
+    struct ThreeNodes* tn = setUp(alloc);
+
+    sendMessage(tn, "Hello World!", tn->nodeA, tn->nodeC);
+    sendMessage(tn, "Hello cjdns!", tn->nodeC, tn->nodeA);
+    sendMessage(tn, "send", tn->nodeA, tn->nodeC);
+    sendMessage(tn, "a", tn->nodeC, tn->nodeA);
+    sendMessage(tn, "few", tn->nodeA, tn->nodeC);
+    sendMessage(tn, "packets", tn->nodeC, tn->nodeA);
+    sendMessage(tn, "to", tn->nodeA, tn->nodeC);
+    sendMessage(tn, "make", tn->nodeC, tn->nodeA);
+    sendMessage(tn, "sure", tn->nodeA, tn->nodeC);
+    sendMessage(tn, "the", tn->nodeC, tn->nodeA);
+    sendMessage(tn, "cryptoauth", tn->nodeA, tn->nodeC);
+    sendMessage(tn, "can", tn->nodeC, tn->nodeA);
+    sendMessage(tn, "establish", tn->nodeA, tn->nodeC);
+
+    alloc->free(alloc);
+}

+ 136 - 0
test/twoNodes_test.c

@@ -0,0 +1,136 @@
+/* vim: set expandtab ts=4 sw=4: */
+/*
+ * You may redistribute this program and/or modify it under the terms of
+ * the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#define string_strncpy
+#define string_strlen
+#include "crypto/Key.h"
+#include "memory/MallocAllocator.h"
+#include "memory/Allocator.h"
+#include "util/Base32.h"
+#include "util/Checksum.h"
+#include "util/platform/libc/string.h"
+#include "test/TestFramework.h"
+#include "net/Ducttape_pvt.h"
+#include "util/log/WriterLog.h"
+#include "io/FileWriter.h"
+#include "wire/Headers.h"
+
+#include <stdio.h>
+
+#define TUNB 2
+#define TUNA 1
+uint8_t incomingTunB(struct Message* msg, struct Interface* iface)
+{
+    Message_shift(msg, -Headers_IP6Header_SIZE);
+    printf("Message from TUN in node B [%s]\n", msg->bytes);
+    *((int*)iface->senderContext) = TUNB;
+    return 0;
+}
+uint8_t incomingTunA(struct Message* msg, struct Interface* iface)
+{
+    Message_shift(msg, -Headers_IP6Header_SIZE);
+    printf("Message from TUN in node A [%s]\n", msg->bytes);
+    *((int*)iface->senderContext) = TUNA;
+    return 0;
+}
+
+struct TwoNodes
+{
+    struct Interface tunIfB;
+    struct TestFramework* nodeB;
+
+    struct Interface tunIfA;
+    struct TestFramework* nodeA;
+    int messageFrom;
+};
+
+static struct TwoNodes* setUp(struct Allocator* alloc)
+{
+    struct Writer* logwriter = FileWriter_new(stdout, alloc);
+    struct Log* logger = WriterLog_new(logwriter, alloc);
+
+    struct TestFramework* a =
+        TestFramework_setUp("\xad\x7e\xa3\x26\xaa\x01\x94\x0a\x25\xbc\x9e\x01\x26\x22\xdb\x69"
+                            "\x4f\xd9\xb4\x17\x7c\xf3\xf8\x91\x16\xf3\xcf\xe8\x5c\x80\xe1\x4a",
+                            alloc, logger);
+    //"publicKey": "kmzm4w0kj9bswd5qmx74nu7kusv5pj40vcsmp781j6xxgpd59z00.k",
+    //"ipv6": "fc41:94b5:0925:7ba9:3959:11ab:a006:367a",
+
+
+    struct TestFramework* b =
+        TestFramework_setUp("\x50\xa0\x9c\xaf\xc3\xce\xee\xa9\x26\xce\x41\x7a\x14\xbc\x3d\x2f"
+                            "\xb9\xc0\xc9\xde\x59\x77\x6f\x78\x0a\x4f\xc9\x37\x56\xe7\x19\xa4",
+                            alloc, logger);
+    //"publicKey": "9u9crb3buyk4dbvfs8f6z68n9s9q4tj3qnpnvnrzxcl994h54js0.k",
+    //"ipv6": "fc20:1b0b:e296:df67:ee93:2fd9:e36d:12d9",
+
+    TestFramework_linkNodes(b, a);
+
+    struct TwoNodes* out = Allocator_malloc(alloc, sizeof(struct TwoNodes));
+
+    Bits_memcpyConst(out, (&(struct TwoNodes) {
+        .tunIfB = {
+            .allocator = alloc,
+            .sendMessage = incomingTunB,
+            .senderContext = &out->messageFrom
+        },
+        .nodeB = b,
+        .tunIfA = {
+            .allocator = alloc,
+            .sendMessage = incomingTunA,
+            .senderContext = &out->messageFrom
+        },
+        .nodeA = a
+    }), sizeof(struct TwoNodes));
+
+    Ducttape_setUserInterface(b->ducttape, &out->tunIfB);
+    Ducttape_setUserInterface(a->ducttape, &out->tunIfA);
+
+    return out;
+}
+
+void sendMessage(struct TwoNodes* tn, char* message, bool bToA)
+{
+    struct Message* msg;
+    Message_STACK(msg, 64, 512);
+
+    Bits_memcpy(msg->bytes, message, strlen(message) + 1);
+    msg->length = strlen(message) + 1;
+
+    if (bToA) {
+        TestFramework_craftIPHeader(msg, tn->nodeB->ip, tn->nodeA->ip);
+        tn->tunIfB.receiveMessage(msg, &tn->tunIfB);
+    } else {
+        TestFramework_craftIPHeader(msg, tn->nodeA->ip, tn->nodeB->ip);
+        tn->tunIfA.receiveMessage(msg, &tn->tunIfA);
+    }
+
+    Assert_always(tn->messageFrom == ((bToA) ? TUNA : TUNB));
+    tn->messageFrom = 0;
+}
+
+int main()
+{
+    struct Allocator* alloc = MallocAllocator_new(1<<22);
+    struct TwoNodes* tn = setUp(alloc);
+
+    sendMessage(tn, "Hello World!", true);
+    sendMessage(tn, "Hello cjdns!", false);
+    sendMessage(tn, "hi", true);
+    sendMessage(tn, "this is a test", false);
+    sendMessage(tn, "ok bye now", true);
+    sendMessage(tn, "byebye", false);
+
+    alloc->free(alloc);
+}

+ 0 - 1
util/Assert.h

@@ -15,7 +15,6 @@
 #ifndef Assert_H
 #define Assert_H
 
-#include "util/log/Log.h"
 #include "util/UniqueName.h"
 #include <stdio.h>
 #include <stdlib.h>

+ 7 - 6
util/Identity.h

@@ -17,20 +17,21 @@
 
 #include "util/Assert.h"
 
-#ifdef Identity_CHECK
+#ifndef Identity_MAGIC
+    #define Identity_MAGIC ((uint64_t) 0x0123456789abcdefull)
+#endif
 
-    /** This is unique to each file. */
-    static char Identity_ID;
+#ifdef Identity_CHECK
 
     /** This goes in each structure which will be checked. */
     #define Identity \
-        char* Identity_verifier;
+        uint64_t Identity_verifier;
 
     #define Identity_set(pointer) \
-        pointer->Identity_verifier = &Identity_ID
+        pointer->Identity_verifier = Identity_MAGIC
 
     #define Identity_check(pointer) \
-        Assert_always((pointer)->Identity_verifier == &Identity_ID)
+        Assert_always((pointer)->Identity_verifier == Identity_MAGIC)
 
     #define Identity_cast(pointer) \
         (pointer); Identity_check(pointer)

+ 12 - 11
util/Pinger.c

@@ -16,6 +16,7 @@
 #include "util/Pinger.h"
 #include "util/Time.h"
 #include "util/Timeout.h"
+#include "util/Identity.h"
 
 struct Ping
 {
@@ -27,12 +28,13 @@ struct Ping
     uint32_t timeSent;
     Pinger_SEND_PING(sendPing);
     Pinger_ON_RESPONSE(onResponse);
+    Identity
 };
 
 struct Pinger
 {
     struct Ping* pings[Pinger_MAX_CONCURRENT_PINGS];
-    struct event_base* eventBase;
+    struct EventBase* eventBase;
     struct Log* logger;
     struct Allocator* allocator;
 };
@@ -50,17 +52,17 @@ static void timeoutCallback(void* vping)
     callback(NULL, (struct Ping*) vping);
 }
 
-static void sendPingCallback(void* vping)
+void Pinger_sendPing(struct Pinger_Ping* ping)
 {
-    struct Ping* ping = vping;
-    ping->sendPing(ping->data, ping->public.context);
+    struct Ping* p = Identity_cast((struct Ping*) ping);
+    p->sendPing(p->data, ping->context);
 }
 
-struct Pinger_Ping* Pinger_ping(String* data,
-                                Pinger_ON_RESPONSE(onResponse),
-                                Pinger_SEND_PING(sendPing),
-                                uint32_t timeoutMilliseconds,
-                                struct Pinger* pinger)
+struct Pinger_Ping* Pinger_newPing(String* data,
+                                   Pinger_ON_RESPONSE(onResponse),
+                                   Pinger_SEND_PING(sendPing),
+                                   uint32_t timeoutMilliseconds,
+                                   struct Pinger* pinger)
 {
     struct Ping** location = NULL;
     uint32_t index;
@@ -95,12 +97,11 @@ struct Pinger_Ping* Pinger_ping(String* data,
         .timeSent = Time_currentTimeMilliseconds(pinger->eventBase),
         .onResponse = onResponse
     });
+    Identity_set(ping);
     ping->timeout =
         Timeout_setTimeout(timeoutCallback, ping, timeoutMilliseconds, pinger->eventBase, alloc);
     *location = ping;
 
-    Timeout_setTimeout(sendPingCallback, ping, 0, pinger->eventBase, alloc);
-
     return &ping->public;
 }
 

+ 14 - 5
util/Pinger.h

@@ -72,11 +72,20 @@ struct Pinger_Ping
  * @param pinger
  * @return a new Pinger_Ping if all goes well, NULL if there is no space.
  */
-struct Pinger_Ping* Pinger_ping(String* data,
-                                Pinger_ON_RESPONSE(onResponse),
-                                Pinger_SEND_PING(sendPing),
-                                uint32_t timeoutMilliseconds,
-                                struct Pinger* pinger);
+struct Pinger_Ping* Pinger_newPing(String* data,
+                                   Pinger_ON_RESPONSE(onResponse),
+                                   Pinger_SEND_PING(sendPing),
+                                   uint32_t timeoutMilliseconds,
+                                   struct Pinger* pinger);
+
+/**
+ * Once the ping has been allocated, send it.
+ * This is split into two functions so they caller can allocate a structure using thie ping's
+ * allocator and guarantee that the structure will be cleaned up after the ping is complete.
+ *
+ * @param ping the ping to send.
+ */
+void Pinger_sendPing(struct Pinger_Ping* ping);
 
 /**
  * Function to call when data comes in which appears to be a ping response.

+ 3 - 0
util/version/Version.h

@@ -124,6 +124,9 @@
  * protocol0 in some circumstances. If it knows nothing about the other node and it forwards a
  * message via an intermediary, the message will be unreadable at the other end.
  *
+ * Protocol1.2
+ * Changes in protocol1.1 are reverted as a solution was found in the implementation.
+ *
  * ----------------------------------
  *
  * Version 2: