Browse Source

Beginnings of AFL fuzzing

Caleb James DeLisle 5 years ago
parent
commit
50e89d84b2

+ 0 - 1
admin/angel/Core.c

@@ -41,7 +41,6 @@
 #include "net/InterfaceController_admin.h"
 #include "interface/addressable/PacketHeaderToUDPAddrIface.h"
 #include "interface/ASynchronizer.h"
-#include "interface/FramingIface.h"
 #include "memory/Allocator.h"
 #include "memory/MallocAllocator.h"
 #include "memory/Allocator_admin.h"

+ 287 - 0
benc/serialization/json/test/JsonBencMessageReader_fuzzGen.js

@@ -0,0 +1,287 @@
+'use strict';
+// stringify it to reduce size
+const DEFAULT_CONF = JSON.stringify({
+    // Private key:
+    // Your confidentiality and data integrity depend on this key, keep it secret!
+    "privateKey": "ba13c8023eda49bd626ebfda4ecf9abd0eda6e07a8e77f19aa0b20c0d69eb915",
+
+    // This key corresponds to the public key and ipv6 address:
+    "publicKey": "hukfzjh5n30m10303bkhjg1wvuft90s0cqqg5jrjgg781dbly2z0.k",
+    "ipv6": "fccf:4352:ac9:7d1f:b32b:ba08:f086:8432",
+
+    // Anyone connecting and offering these passwords on connection will be allowed.
+    //
+    // WARNING: If a "login" parameter is passed, someone sniffing on the wire can
+    //          sniff the packet and crack to find it. If the "login" is not passed
+    //          then the hash of the 'password' is effectively the login, therefore
+    //          that can be cracked.
+    //
+    "authorizedPasswords":
+    [
+        // A unique string which is known to the client and server.
+        // Specify an optional user to identify the peer locally.
+        // It is not used for authentication.
+        {"password": "jq89d23lbvm26tk4t36yg5ugj717wkr", "user": "default-login"}
+
+        // More passwords should look like this.
+        // {"password": "l5t3tpn7z710p8cxly59zxbmy5n8buu", "user": "my-second-peer"},
+        // {"password": "97ylvcn49q4y19f7w7f248hts5l7pbp", "user": "my-third-peer"},
+        // {"password": "yxdzufqxwkbgp4ubusglxm5su4hwp41", "user": "my-fourth-peer"},
+
+        // Below is an example of your connection credentials
+        // that you can give to other people so they can connect
+        // to you using your default password (from above).
+        // The login field here yourself to your peer and the peerName field
+        // is the name the peer which will be displayed in peerStats
+        // Adding a unique password for each peer is advisable
+        // so that leaks can be isolated.
+        /*
+        "your.external.ip.goes.here:61151": {
+            "login": "default-login",
+            "password":"jq89d23lbvm26tk4t36yg5ugj717wkr",
+            "publicKey":"hukfzjh5n30m10303bkhjg1wvuft90s0cqqg5jrjgg781dbly2z0.k",
+            "peerName":"your-name-goes-here"
+        },
+        */
+    ],
+
+    // Settings for administering and extracting information from your router.
+    // This interface provides functions which can be called through a UDP socket.
+    // See admin/Readme.md for more information about the API and try:
+    // ./tools/cexec
+    // For a list of functions which can be called.
+    // For example: ./tools/cexec 'memory()'
+    // will call a function which gets the core's current memory consumption.
+    // ./tools/cjdnslog
+    // is a tool which uses this admin interface to get logs from cjdns.
+    "admin":
+    {
+        // Port to bind the admin RPC server to.
+        "bind": "127.0.0.1:11234",
+
+        // Password for admin RPC server.
+        // This is a static password by default, so that tools like
+        // ./tools/cexec can use the API without you creating a
+        // config file at ~/.cjdnsadmin first. If you decide to
+        // expose the admin API to the network, change the password!
+        "password": "NONE"
+    },
+
+    // Interfaces to connect to the switch core.
+    "interfaces":
+    {
+        // The interface which connects over UDP/IP based VPN tunnel.
+        "UDPInterface":
+        [
+            {
+                // Bind to this port.
+                "bind": "0.0.0.0:61151",
+
+                // Nodes to connect to (IPv4 only).
+                "connectTo":
+                {
+                    // Add connection credentials here to join the network
+                    // If you have several, don't forget the separating commas
+                    // They should look like:
+                    // "ipv4 address:port": {
+                    //     "login": "(optional) name your peer has for you"
+                    //     "password": "password to connect with",
+                    //     "publicKey": "remote node key.k",
+                    //     "peerName": "(optional) human-readable name for peer"
+                    // },
+                    // Ask somebody who is already connected.
+                }
+            },
+            {
+                // Bind to this port.
+                "bind": "[::]:61151",
+
+                // Nodes to connect to (IPv6 only).
+                "connectTo":
+                {
+                    // Add connection credentials here to join the network
+                    // Ask somebody who is already connected.
+                }
+            }
+        ]
+,
+        "ETHInterface":
+        [
+            // Alternatively bind to just one device and either beacon and/or
+            // connect to a specified MAC address
+            {
+                // Bind to this device (interface name, not MAC)
+                // "all" is a pseudo-name which will try to connect to all devices.
+                "bind": "all",
+
+                // Auto-connect to other cjdns nodes on the same network.
+                // Options:
+                //
+                // 0 -- Disabled.
+                //
+                // 1 -- Accept beacons, this will cause cjdns to accept incoming
+                //      beacon messages and try connecting to the sender.
+                //
+                // 2 -- Accept and send beacons, this will cause cjdns to broadcast
+                //      messages on the local network which contain a randomly
+                //      generated per-session password, other nodes which have this
+                //      set to 1 or 2 will hear the beacon messages and connect
+                //      automatically.
+                //
+                "beacon": 2,
+
+                // Node(s) to connect to manually
+                // Note: does not work with "all" pseudo-device-name
+                "connectTo":
+                {
+                    // Credentials for connecting look similar to UDP credentials
+                    // except they begin with the mac address, for example:
+                    // "01:02:03:04:05:06":{"password":"a","publicKey":"b"}
+                }
+            }
+        ]
+
+    },
+
+    // Configuration for the router.
+    "router":
+    {
+        // The interface which is used for connecting to the cjdns network.
+        "interface":
+        {
+            // The type of interface (only TUNInterface is supported for now)
+            "type": "TUNInterface"
+            // The type of tunfd (only "android" for now)
+            // If "android" here, the tunDevice should be used as the pipe path
+            // to transfer the tun file description.
+            // "tunfd" : "android"
+        },
+
+        // System for tunneling IPv4 and ICANN IPv6 through cjdns.
+        // This is using the cjdns switch layer as a VPN carrier.
+        "ipTunnel":
+        {
+            // Nodes allowed to connect to us.
+            // When a node with the given public key connects, give them the
+            // ip4 and/or ip6 addresses listed.
+            "allowedConnections":
+            [
+                // Give the client an address on 192.168.1.0/24, and an address
+                // it thinks has all of IPv6 behind it.
+                // ip4Prefix is the set of addresses which are routable from the tun
+                // for example, if you're advertizing a VPN into a company network
+                // which exists in 10.123.45.0/24 space, ip4Prefix should be 24
+                // default is 32 for ipv4 and 128 for ipv6
+                // so by default it will not install a route
+                // ip4Alloc is the block of addresses which are allocated to the
+                // for example if you want to issue 4 addresses to the client, those
+                // being 192.168.123.0 to 192.168.123.3, you would set this to 30
+                // default is 32 for ipv4 and 128 for ipv6 (1 address)
+                // {
+                //     "publicKey": "f64hfl7c4uxt6krmhPutTheRealAddressOfANodeHere7kfm5m0.k",
+                //     "ip4Address": "192.168.1.24",
+                //     "ip4Prefix": 0,
+                //     "ip4Alloc": 32,
+                //     "ip6Address": "2001:123:ab::10",
+                //     "ip6Prefix": 0
+                //     "ip6Alloc": 64,
+                // },
+
+                // It's ok to only specify one address and prefix/alloc are optional.
+                // {
+                //     "publicKey": "ydq8csdk8p8ThisIsJustAnExampleAddresstxuyqdf27hvn2z0.k",
+                //     "ip4Address": "192.168.1.25",
+                //     "ip4Prefix": 0,
+                // }
+            ],
+
+            "outgoingConnections":
+            [
+                // Connect to one or more machines and ask them for IP addresses.
+                // "6743gf5tw80ExampleExampleExampleExamplevlyb23zfnuzv0.k",
+                // "pw9tfmr8pcrExampleExampleExampleExample8rhg1pgwpwf80.k",
+                // "g91lxyxhq0kExampleExampleExampleExample6t0mknuhw75l0.k"
+            ]
+        }
+    },
+
+    // Dropping permissions.
+    // In the event of a serious security exploit in cjdns, leak of confidential
+    // network traffic and/or keys is highly likely but the following rules are
+    // designed to prevent the attack from spreading to the system on which cjdns
+    // is running.
+    // Counter-intuitively, cjdns is *more* secure if it is started as root because
+    // non-root users do not have permission to use chroot or change usernames,
+    // limiting the effectiveness of the mitigations herein.
+    "security":
+    [
+        // Change the user id to sandbox the cjdns process after it starts.
+        // If keepNetAdmin is set to 0, IPTunnel will be unable to set IP addresses
+        // and ETHInterface will be unable to hot-add new interfaces
+        // Use { "setuser": 0 } to disable.
+        // Default: enabled with keepNetAdmin
+        { "setuser": "nobody", "keepNetAdmin": 1 },
+
+        // Chroot changes the filesystem root directory which cjdns sees, blocking it
+        // from accessing files outside of the chroot sandbox, if the user does not
+        // have permission to use chroot(), this will fail quietly.
+        // Use { "chroot": 0 } to disable.
+        // Default: enabled (using "/var/run")
+        { "chroot": "/var/run/" },
+
+        // Nofiles is a deprecated security feature which prevents cjdns from opening
+        // any files at all, using this will block setting of IP addresses and
+        // hot-adding ETHInterface devices but for users who do not need this, it
+        // provides a formidable sandbox.
+        // Default: disabled
+        { "nofiles": 0 },
+
+        // Noforks will prevent cjdns from spawning any new processes or threads,
+        // this prevents many types of exploits from attacking the wider system.
+        // Default: enabled
+        { "noforks": 1 },
+
+        // Seccomp is the most advanced sandboxing feature in cjdns, it uses
+        // SECCOMP_BPF to filter the system calls which cjdns is able to make on a
+        // linux system, strictly limiting it's access to the outside world
+        // This will fail quietly on any non-linux system
+        // Default: enabled
+        { "seccomp": 1 },
+
+        // The client sets up the core using a sequence of RPC calls, the responses
+        // to these calls are verified but in the event that the client crashes
+        // setup of the core completes, it could leave the core in an insecure state
+        // This call constitutes the client telling the core that the security rules
+        // have been fully applied and the core may run. Without it, the core will
+        // exit within a few seconds with return code 232.
+        // Default: enabled
+        { "setupComplete": 1 }
+    ],
+
+    // Logging
+    "logging":
+    {
+        // Uncomment to have cjdns log to stdout rather than making logs available
+        // via the admin socket.
+        // "logTo":"stdout"
+    },
+
+    // If set to non-zero, cjdns will not fork to the background.
+    // Recommended for use in conjunction with "logTo":"stdout".
+    "noBackground":0,
+
+    // Pipe file will store in this path, recommended value: /tmp (for unix),
+    // \\\\.\\pipe (for windows)
+    // /data/local/tmp (for rooted android)
+    // /data/data/AppName (for non-root android)
+    "pipe":"/tmp",
+});
+
+module.exports.defaultConfLen = () => { return DEFAULT_CONF.length; };
+module.exports.defaultConf = (x) => {
+    const out = [];
+    for (let i = 0; i < DEFAULT_CONF.length; i++) {
+        out.push(x + '[' + i + ']=' + DEFAULT_CONF.charCodeAt(i) + ';');
+    }
+    return out.join('\n');
+}

+ 55 - 0
benc/serialization/json/test/JsonBencMessageReader_fuzz_test.c

@@ -0,0 +1,55 @@
+/* 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 <https://www.gnu.org/licenses/>.
+ */
+#include "benc/serialization/json/JsonBencMessageReader.h"
+#include "crypto/random/Random.h"
+#include "memory/Allocator.h"
+#include "memory/MallocAllocator.h"
+#include "util/Bits.h"
+#include "util/Identity.h"
+#include "util/log/FileWriterLog.h"
+#include "util/CString.h"
+#include "util/events/EventBase.h"
+#include "crypto/random/test/DeterminentRandomSeed.h"
+#include "test/FuzzTest.h"
+#include "util/Js.h"
+
+Js({ file.lib = require('benc/serialization/json/test/JsonBencMessageReader_fuzzGen.js'); })
+
+struct FuzzTest* CJDNS_FUZZ_MK(struct Allocator* alloc)
+{
+    int len = 0;
+    Js({ return 'len=' + file.lib.defaultConfLen(); });
+    struct Message* msg = Message_new(len, 0, alloc);
+    uint8_t* x = msg->bytes;
+    Js({ return file.lib.defaultConf("x"); });
+    struct FuzzTest* out = Allocator_calloc(alloc, sizeof(struct FuzzTest), 1);
+    out->name = "JsonBencMessageReader_default";
+    out->fuzz = msg;
+    return out;
+}
+
+void CJDNS_FUZZ_MAIN(void* vctx, struct Message* fuzz)
+{
+    struct Allocator* alloc = (struct Allocator*) vctx;
+    Dict* out = NULL;
+    char* res = JsonBencMessageReader_readNoExcept(fuzz, alloc, &out, true);
+    if (res) { return; }
+    res = JsonBencMessageReader_readNoExcept(fuzz, alloc, &out, false);
+}
+
+void* CJDNS_FUZZ_INIT(struct Allocator* alloc, struct Random* rand)
+{
+    return alloc;
+}

+ 28 - 38
crypto/test/CryptoAuth_fuzz_test.c

@@ -25,6 +25,7 @@
 #include "crypto/random/test/DeterminentRandomSeed.h"
 #include "crypto/random/Random.h"
 #include "crypto/AddressCalc.h"
+#include "test/FuzzTest.h"
 
 struct DelayedMsg {
     struct Message* msg;
@@ -49,6 +50,7 @@ struct Context {
     struct Log* log;
     /** Number of messages which make back and forth *while* both CAs are in ESTABLISHED state. */
     int successMessageCount;
+    Identity
 };
 
 // Increase this number to make the fuzz test run longer.
@@ -265,23 +267,38 @@ static void mainLoop(struct Context* ctx)
     Assert_failure("Nodes could not sync");
 }
 
-static void cycle(uint8_t randSeed[64],
-                  struct EventBase* base,
-                  struct Log* logger,
-                  struct Allocator* alloc)
+struct FuzzTest* CJDNS_FUZZ_MK(struct Allocator* alloc)
+{
+    struct Message* msg = Message_new(64, 0, alloc);
+    Bits_memset(msg->bytes, 0, 64);
+    struct FuzzTest* out = Allocator_calloc(alloc, sizeof(struct FuzzTest), 1);
+    out->name = "CryptoAuth_fuzz_test_default";
+    out->fuzz = msg;
+    return out;
+}
+
+void* CJDNS_FUZZ_INIT(struct Allocator* alloc, struct Random* rand)
 {
     struct Context* ctx = Allocator_calloc(alloc, sizeof(struct Context), 1);
+    Identity_set(ctx);
+    struct EventBase* base = EventBase_new(alloc);
     ctx->alloc = alloc;
-    ctx->log = logger;
-    struct RandomSeed* seed = DeterminentRandomSeed_new(alloc, randSeed);
-    struct Random* rand = ctx->rand = Random_newWithSeed(alloc, logger, seed, NULL);
-
-    ctx->nodeA.ca = CryptoAuth_new(alloc, NULL, base, logger, rand);
-    ctx->nodeB.ca = CryptoAuth_new(alloc, NULL, base, logger, rand);
+    ctx->nodeA.ca = CryptoAuth_new(alloc, NULL, base, NULL, rand);
+    ctx->nodeB.ca = CryptoAuth_new(alloc, NULL, base, NULL, rand);
     ctx->nodeA.session = CryptoAuth_newSession(
         ctx->nodeA.ca, alloc, ctx->nodeB.ca->publicKey, false, "nodeA");
     ctx->nodeB.session = CryptoAuth_newSession(
         ctx->nodeB.ca, alloc, ctx->nodeA.ca->publicKey, false, "nodeB");
+    return ctx;
+}
+
+void CJDNS_FUZZ_MAIN(void* vctx, struct Message* fuzz)
+{
+    struct Context* ctx = Identity_check((struct Context*) vctx);
+
+    // This is not ideal, but this test was already written before AFL.
+    struct RandomSeed* rs = DeterminentRandomSeed_new(ctx->alloc, fuzz->bytes);
+    ctx->rand = Random_newWithSeed(ctx->alloc, NULL, rs, NULL);
 
     if (maybe(ctx, 2)) {
         CryptoAuth_addUser_ipv6(String_CONST("pass"), String_CONST("user"), NULL, ctx->nodeB.ca);
@@ -305,31 +322,4 @@ static void cycle(uint8_t randSeed[64],
     }
 
     mainLoop(ctx);
-}
-
-int main(int argc, char** argv)
-{
-    struct Allocator* alloc = MallocAllocator_new(1048576);
-    struct Log* logger = FileWriterLog_new(stdout, alloc);
-    struct Random* rand = Random_new(alloc, logger, NULL);
-    struct EventBase* base = EventBase_new(alloc);
-
-    int cycles = QUICK_CYCLES;
-    for (int i = 0; i < argc; i++) {
-        if (!CString_strcmp("--fuzz", argv[i])) {
-            cycles = SLOW_CYCLES;
-            break;
-        }
-    }
-
-    uint8_t randSeed[64] = {0};
-    for (int i = 0; i < cycles; i++) {
-        Random_base32(rand, randSeed, 32);
-        struct Allocator* tempAlloc = Allocator_child(alloc);
-        Log_debug(logger, "===== %s =====", randSeed);
-        cycle(randSeed, base, logger, tempAlloc);
-        Allocator_free(tempAlloc);
-    }
-    Log_debug(logger, "===+++=== Completed Ok ===++++===");
-    return 0;
-}
+}

+ 0 - 174
interface/FramingIface.c

@@ -1,174 +0,0 @@
-/* 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 <https://www.gnu.org/licenses/>.
- */
-#include "interface/FramingIface.h"
-#include "interface/Iface.h"
-#include "memory/Allocator.h"
-#include "util/Identity.h"
-#include "wire/Error.h"
-
-struct MessageList;
-struct MessageList {
-    struct Message* msg;
-    struct MessageList* next;
-};
-
-struct FramingIface_pvt {
-    struct FramingIface pub;
-    const uint32_t maxMessageSize;
-    struct Allocator* alloc;
-    uint32_t padding;
-
-    // fields specific to this frame.
-    uint32_t bytesRemaining;
-    struct Allocator* frameAlloc;
-    struct MessageList* frameParts;
-
-    union {
-        uint32_t length_be;
-        uint8_t bytes[4];
-    } header;
-    uint32_t headerIndex;
-
-    Identity
-};
-
-static struct Message* mergeMessage(struct FramingIface_pvt* fi, struct Message* last)
-{
-    int length = last->length;
-
-    // The only accurate way to get the full length because this last might contain
-    // the beginning of the next frame.
-    struct MessageList* part = fi->frameParts;
-    for (part = fi->frameParts; part; part = part->next) {
-        length += part->msg->length;
-    }
-
-    struct Message* out = Message_new(0, length + fi->padding, fi->frameAlloc);
-    Message_push(out, last->bytes, last->length, NULL);
-    for (part = fi->frameParts; part; part = part->next) {
-        Message_push(out, part->msg->bytes, part->msg->length, NULL);
-    }
-
-    Assert_true(length <= out->length);
-    return out;
-}
-
-static Iface_DEFUN receiveMessage(struct Message* msg, struct Iface* streamIf)
-{
-    struct FramingIface_pvt* fi =
-        Identity_containerOf(streamIf, struct FramingIface_pvt, pub.streamIf);
-
-    if (fi->bytesRemaining > fi->maxMessageSize) {
-        // Oversize message
-        return NULL;
-    }
-
-    if (fi->frameParts) {
-        if (fi->bytesRemaining <= (uint32_t)msg->length) {
-            struct Message* wholeMessage = mergeMessage(fi, msg);
-            fi->bytesRemaining = 0;
-            fi->frameParts = NULL;
-            Assert_true(fi->headerIndex == 0);
-            struct Allocator* frameAlloc = fi->frameAlloc;
-            fi->frameAlloc = NULL;
-            // Run the message through again since it's almost certainly not perfect size.
-            Iface_CALL(receiveMessage, wholeMessage, streamIf);
-            Allocator_free(frameAlloc);
-            return NULL;
-        }
-        fi->bytesRemaining -= msg->length;
-        Allocator_adopt(fi->frameAlloc, msg->alloc);
-        struct MessageList* parts = Allocator_malloc(fi->frameAlloc, sizeof(struct MessageList));
-        parts->msg = msg;
-        parts->next = fi->frameParts;
-        fi->frameParts = parts;
-        return NULL;
-    }
-
-    for (;;) {
-        while (fi->headerIndex < 4) {
-            if (!msg->length) {
-                return NULL;
-            }
-            fi->header.bytes[fi->headerIndex] = msg->bytes[0];
-            Message_shift(msg, -1, NULL);
-            fi->headerIndex++;
-        }
-        fi->headerIndex = 0;
-
-        fi->bytesRemaining = Endian_bigEndianToHost32(fi->header.length_be);
-        if (fi->bytesRemaining > fi->maxMessageSize) {
-            // oversize
-            return NULL;
-        }
-
-        if (fi->bytesRemaining == (uint32_t)msg->length) {
-            fi->bytesRemaining = 0;
-            return Iface_next(&fi->pub.messageIf, msg);
-
-        } else if (fi->bytesRemaining < (uint32_t)msg->length) {
-            struct Allocator* alloc = Allocator_child(msg->alloc);
-            struct Message* m = Message_new(fi->bytesRemaining, fi->padding, alloc);
-            Bits_memcpy(m->bytes, msg->bytes, fi->bytesRemaining);
-            Message_shift(msg, -fi->bytesRemaining, NULL);
-            fi->bytesRemaining = 0;
-            Iface_send(&fi->pub.messageIf, m);
-            Allocator_free(alloc);
-            continue;
-
-        } else {
-            fi->frameAlloc = Allocator_child(fi->alloc);
-            struct Message* m = Allocator_calloc(fi->frameAlloc, sizeof(struct Message), 1);
-            m->capacity = m->length = msg->length + 4;
-            m->bytes = Allocator_malloc(fi->frameAlloc, m->length);
-            m->alloc = fi->frameAlloc;
-            Message_shift(m, -m->length, NULL);
-            Message_push(m, msg->bytes, msg->length, NULL);
-            Message_push(m, fi->header.bytes, 4, NULL);
-
-            fi->bytesRemaining -= msg->length;
-            fi->frameParts = Allocator_malloc(fi->frameAlloc, sizeof(struct MessageList));
-            fi->frameParts->msg = m;
-            fi->frameParts->next = NULL;
-        }
-        return NULL;
-    }
-}
-
-static Iface_DEFUN sendMessage(struct Message* msg, struct Iface* messageIf)
-{
-    struct FramingIface_pvt* fi =
-        Identity_containerOf(messageIf, struct FramingIface_pvt, pub.messageIf);
-    Message_push32(msg, msg->length, NULL);
-    return Iface_next(&fi->pub.streamIf, msg);
-}
-
-struct FramingIface* FramingIface_new(uint32_t maxMsgSize,
-                                      uint32_t padding,
-                                      struct Allocator* alloc)
-{
-    struct FramingIface_pvt* context =
-        Allocator_clone(alloc, (&(struct FramingIface_pvt) {
-            .maxMessageSize = maxMsgSize,
-            .alloc = alloc,
-            .padding = padding,
-            .pub = {
-                .streamIf = { .send = receiveMessage },
-                .messageIf = { .send = sendMessage }
-            }
-        }));
-    Identity_set(context);
-    return &context->pub;
-}

+ 0 - 45
interface/FramingIface.h

@@ -1,45 +0,0 @@
-/* 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 <https://www.gnu.org/licenses/>.
- */
-#ifndef FramingIface_H
-#define FramingIface_H
-
-#include "interface/Iface.h"
-#include "memory/Allocator.h"
-#include "util/Linker.h"
-Linker_require("interface/FramingIface.c");
-
-struct FramingIface
-{
-    struct Iface messageIf;
-    struct Iface streamIf;
-};
-
-/**
- * Framed message format:
- * [4 bytes length][ <length> bytes content ....... ]
- * The length is of only the content, not including the beginning 4 bytes
- * which represents the length itself.
- *
- * @param maxMessageSize how large of a framed message to allow
- * @param padding the amount of padding to apply to each full frame when it comes in, for outgoing
- *                messages the message has no added padding, it is just sent across the wire as it
- *                is.
- * @param alloc
- */
-struct FramingIface* FramingIface_new(uint32_t maxMessageSize,
-                                      uint32_t padding,
-                                      struct Allocator* alloc);
-
-#endif

+ 0 - 153
interface/test/FramingIface_fuzz_test.c

@@ -1,153 +0,0 @@
-/* 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 <https://www.gnu.org/licenses/>.
- */
-#include "interface/FramingIface.h"
-#include "crypto/random/Random.h"
-#include "memory/Allocator.h"
-#include "memory/MallocAllocator.h"
-#include "util/Bits.h"
-#include "util/Identity.h"
-#include "util/log/FileWriterLog.h"
-#include "util/CString.h"
-#include "crypto/random/test/DeterminentRandomSeed.h"
-
-struct Context
-{
-    struct Iface internalIf;
-
-    int currentMessage;
-
-    // the expected output
-    struct Message** messages;
-    int messageCount;
-
-    struct Allocator* alloc;
-    Identity
-};
-
-static Iface_DEFUN messageOut(struct Message* msg, struct Iface* iface)
-{
-    struct Context* ctx = Identity_check((struct Context*) iface);
-    Assert_true(ctx->currentMessage < ctx->messageCount);
-
-    // The list is populated backwards so we have to count down...
-    struct Message* ctrlMsg = ctx->messages[ctx->messageCount - (++ctx->currentMessage)];
-
-    Assert_true(ctrlMsg->length == msg->length);
-    Assert_true(!Bits_memcmp(ctrlMsg->bytes, msg->bytes, msg->length));
-    return 0;
-}
-
-/** The maximum size of a frame inside of one of the messages sent to the framing interface. */
-#define MAX_FRAME_SZ 2048
-
-/** The maximum size of a message which is sent to the frame interface. */
-#define MAX_MSG_SZ 2048
-
-/** Size of the buffer where we will be doing our work. */
-#define WORK_BUFF_SZ 4096
-
-#define QUICK_CYCLES 100
-#define SLOW_CYCLES 200000
-
-#define CYCLES 100
-
-#define MIN_MSG_SZ 1
-
-#define MAX_MSGS_PER_FRAME 1024
-
-int main(int argc, char** argv)
-{
-    struct Allocator* mainAlloc = MallocAllocator_new(1<<20);
-    struct Log* log = FileWriterLog_new(stdout, mainAlloc);
-    struct Random* rand = Random_new(mainAlloc, log, NULL);
-    struct Context* ctx = Allocator_calloc(mainAlloc, sizeof(struct Context), 1);
-    Identity_set(ctx);
-    ctx->internalIf.send = messageOut;
-    struct Iface externalIf = { .send = NULL };
-    struct FramingIface* framingIface = FramingIface_new(4096, 512, mainAlloc);
-    Iface_plumb(&framingIface->messageIf, &ctx->internalIf);
-    Iface_plumb(&framingIface->streamIf, &externalIf);
-
-    int cycles = QUICK_CYCLES;
-    for (int i = 0; i < argc; i++) {
-        if (!CString_strcmp("--fuzz", argv[i])) {
-            cycles = SLOW_CYCLES;
-            break;
-        }
-    }
-
-    for (int i = 0; i < cycles; i++) {
-        struct Allocator* alloc = Allocator_child(mainAlloc);
-
-        // max frame size must be at least 5 so that at least 1 byte of data is sent.
-        int maxFrameSize = ( Random_uint32(rand) % (MAX_FRAME_SZ - 1) ) + 1;
-        int minMessageSize = maxFrameSize / MAX_MSGS_PER_FRAME;
-        if (minMessageSize < MIN_MSG_SZ) { minMessageSize = MIN_MSG_SZ; }
-        int maxMessageSize = (Random_uint32(rand) % (MAX_MSG_SZ - minMessageSize)) + minMessageSize;
-        if (maxMessageSize == minMessageSize) { maxMessageSize++; }
-        // Log_debug(log, "maxFrameSize[%d] maxMessageSize[%d]", maxFrameSize, maxMessageSize);
-        ctx->alloc = alloc;
-        ctx->messages = NULL;
-        ctx->messageCount = 0;
-        ctx->currentMessage = 0;
-
-        // Create one huge message, then create lots of little frames inside of it
-        // then split it up in random places and send the sections to the framing
-        // interface.
-        struct Message* msg = Message_new(WORK_BUFF_SZ, 0, alloc);
-
-        Assert_true(WORK_BUFF_SZ == msg->length);
-        Random_bytes(rand, msg->bytes, msg->length);
-        Message_shift(msg, -WORK_BUFF_SZ, NULL);
-
-        for (;;) {
-            int len = Random_uint32(rand) % maxFrameSize;
-            if (!len) { len++; }
-            if (msg->padding < len + 4) { break; }
-            Message_shift(msg, len, NULL);
-
-            ctx->messageCount++;
-            ctx->messages =
-                Allocator_realloc(alloc, ctx->messages, ctx->messageCount * sizeof(char*));
-            struct Message* om = ctx->messages[ctx->messageCount-1] = Message_new(len, 0, alloc);
-            Bits_memcpy(om->bytes, msg->bytes, len);
-
-            Message_push32(msg, len, NULL);
-        }
-
-        int i = 0;
-        do {
-            int nextMessageSize =
-                (Random_uint32(rand) % (maxMessageSize - minMessageSize)) + minMessageSize;
-            // Prevent oom conditions.
-            if (i++ > 1000) { nextMessageSize = msg->length; }
-            if (!nextMessageSize) { nextMessageSize++; }
-            if (nextMessageSize > msg->length) { nextMessageSize = msg->length; }
-            struct Allocator* msgAlloc = Allocator_child(alloc);
-            struct Message* m = Message_new(nextMessageSize, 0, msgAlloc);
-            Message_pop(msg, m->bytes, nextMessageSize, NULL);
-            Iface_send(&externalIf, m);
-            Allocator_free(msgAlloc);
-        } while (msg->length);
-
-        Assert_true(ctx->messageCount == ctx->currentMessage);
-
-        Allocator_free(alloc);
-    }
-
-    Log_debug(log, "===+++=== Completed Ok ===++++===");
-    Allocator_free(mainAlloc);
-    return 0;
-}

+ 0 - 111
interface/test/FramingIface_test.c

@@ -1,111 +0,0 @@
-/* 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 <https://www.gnu.org/licenses/>.
- */
-#include "interface/Iface.h"
-#include "interface/FramingIface.h"
-#include "memory/Allocator.h"
-#include "memory/MallocAllocator.h"
-#include "util/Endian.h"
-#include "util/Bits.h"
-#include "util/CString.h"
-#include "wire/Error.h"
-
-union MessageLength
-{
-    uint32_t length_be;
-    uint8_t bytes[4];
-};
-
-struct Context
-{
-    struct Iface iface;
-    struct Message** receivedMsg;
-    struct Allocator* childAlloc;
-    struct Iface dummyIf;
-    Identity
-};
-
-static Iface_DEFUN messageOut(struct Message* msg, struct Iface* iface)
-{
-    struct Context* ctx = Identity_check((struct Context*) iface);
-    Allocator_adopt(ctx->childAlloc, msg->alloc);
-    ctx->receivedMsg[0] = msg;
-    return NULL;
-}
-
-static void send(struct Iface* sendTo, struct Message* toSend, struct Allocator* cloneWith)
-{
-    struct Allocator* child = Allocator_child(cloneWith);
-    toSend = Message_clone(toSend, child);
-    Iface_send(sendTo, toSend);
-    Allocator_free(child);
-}
-
-int main()
-{
-    struct Allocator* alloc = MallocAllocator_new(1<<20);
-    struct Context* ctx = Allocator_calloc(alloc, sizeof(struct Context), 1);
-    Identity_set(ctx);
-    ctx->iface.send = messageOut;
-    struct FramingIface* framingIf = FramingIface_new(1024, 512, alloc);
-    Iface_plumb(&ctx->dummyIf, &framingIf->streamIf);
-    Iface_plumb(&ctx->iface, &framingIf->messageIf);
-    struct Message* output = NULL;
-    ctx->receivedMsg = &output;
-
-    char* text = "Hello World!";
-    Assert_true(12 == CString_strlen(text));
-    union MessageLength ml = { .length_be = Endian_hostToBigEndian32(12) };
-
-    struct Message* msg;
-
-    // first 2 bytes of length
-    msg = Message_new(0, 2, alloc);
-    Message_push(msg, ml.bytes, 2, NULL);
-    send(&ctx->dummyIf, msg, alloc);
-
-    // last 2 bytes of length and first 5 bytes of message "Hello"
-    msg = Message_new(0, 7, alloc);
-    Message_push(msg, text, 5, NULL);
-    Message_push(msg, &ml.bytes[2], 2, NULL);
-    send(&ctx->dummyIf, msg, alloc);
-
-    Assert_true(output == NULL);
-    ctx->childAlloc = Allocator_child(alloc);
-
-    // last 7 bytes of message " World!" and first byte of length of second message.
-    msg = Message_new(0, 8, alloc);
-    Message_push(msg, ml.bytes, 1, NULL);
-    Message_push(msg, &text[5], 7, NULL);
-    send(&ctx->dummyIf, msg, alloc);
-
-    Assert_true(output && output->length == (int)CString_strlen(text));
-    Assert_true(!Bits_memcmp(output->bytes, text, CString_strlen(text)));
-
-    Allocator_free(ctx->childAlloc);
-    ctx->childAlloc = Allocator_child(alloc);
-
-    // Send last 3 bytes of length and entire message.
-    msg = Message_new(0, 15, alloc);
-    Message_push(msg, text, 12, NULL);
-    Message_push(msg, &ml.bytes[1], 3, NULL);
-    send(&ctx->dummyIf, msg, alloc);
-
-    Assert_true(output && output->length == (int)CString_strlen(text));
-    Assert_true(!Bits_memcmp(output->bytes, text, CString_strlen(text)));
-
-    Allocator_free(alloc);
-
-    return 0;
-}

+ 1 - 0
node_build/Codestyle.js

@@ -89,6 +89,7 @@ var parseFile = function (fileName, fileContent) {
         var n = name.replace(/_.*/, '');
         if ((/^\w+\s.*\(/).test(line)) {
             if (!(/^int main\(/.test(line)
+                || / CJDNS_/.test(line)
                 || line.indexOf(' '+n) > -1
                 || /^[ ]?static /.test(line)
                 || /^typedef /.test(line)))

+ 212 - 0
test/Afl_fuzz_test_disabled.c

@@ -0,0 +1,212 @@
+/* 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 <https://www.gnu.org/licenses/>.
+ */
+#include "crypto/Key.h"
+//#include "io/FileWriter.h"
+//#include "memory/MallocAllocator.h"
+#include "memory/Allocator.h"
+#include "crypto/random/Random.h"
+#include "interface/Iface.h"
+//#include "util/Base32.h"
+#include "util/Checksum.h"
+//#include "util/log/WriterLog.h"
+#include "test/TestFramework.h"
+#include "wire/Headers.h"
+//#include "wire/Ethernet.h"
+//#include "interface/tuntap/TUNMessageType.h"
+//#include "util/Hex.h"
+#include "util/events/Time.h"
+#include "util/events/Timeout.h"
+//#include "dht/dhtcore/NodeStore.h"
+#include "dht/Pathfinder_pvt.h"
+#include "test/FuzzTest.h"
+
+#include <stdio.h>
+
+struct Context
+{
+    struct TestFramework* nodeB;
+    struct Iface tunB;
+    struct TestFramework* nodeA;
+    struct Iface tunA;
+    int messageFrom;
+    bool beaconsSent;
+
+    struct Timeout* checkLinkageTimeout;
+    struct Log* logger;
+    struct EventBase* base;
+
+    uint64_t startTime;
+
+    Identity
+};
+
+#define TUNB 2
+#define TUNA 1
+
+static Iface_DEFUN incomingTun(struct Message* msg, struct Iface* tunB)
+{
+    return 0;
+}
+
+static void notLinkedYet(struct Context* ctx)
+{
+    uint64_t now = Time_currentTimeMilliseconds(ctx->base);
+    if ((now - ctx->startTime) > 5000) {
+        Assert_failure("Failed to link in 5 seconds");
+    }
+}
+
+static void checkLinkage(void* vContext)
+{
+    struct Context* ctx = Identity_check((struct Context*) vContext);
+
+    if (!ctx->beaconsSent) {
+        if (Pathfinder_getNodeStore(ctx->nodeA->pathfinder) &&
+            Pathfinder_getNodeStore(ctx->nodeB->pathfinder))
+        {
+            Log_debug(ctx->logger, "Linking A and B");
+            TestFramework_linkNodes(ctx->nodeB, ctx->nodeA, true);
+            ctx->beaconsSent = true;
+        }
+        return;
+    }
+
+
+    if (Pathfinder_getNodeStore(ctx->nodeA->pathfinder)->nodeCount < 2) {
+        notLinkedYet(ctx);
+        return;
+    }
+    Log_debug(ctx->logger, "A seems to be linked with B");
+    if (Pathfinder_getNodeStore(ctx->nodeB->pathfinder)->nodeCount < 2) {
+        notLinkedYet(ctx);
+        return;
+    }
+    Log_debug(ctx->logger, "B seems to be linked with A");
+    Log_debug(ctx->logger, "\n\nSetup Complete\n\n");
+
+    Timeout_clearTimeout(ctx->checkLinkageTimeout);
+}
+
+/*
+static void runTest(struct Context* tn)
+{
+    sendMessage(tn, "Hello World!", tn->nodeA, tn->nodeB);
+    sendMessage(tn, "Hello cjdns!", tn->nodeB, tn->nodeA);
+    sendMessage(tn, "send", tn->nodeA, tn->nodeB);
+    sendMessage(tn, "a", tn->nodeB, tn->nodeA);
+    sendMessage(tn, "few", tn->nodeA, tn->nodeB);
+    sendMessage(tn, "packets", tn->nodeB, tn->nodeA);
+    sendMessage(tn, "to", tn->nodeA, tn->nodeB);
+    sendMessage(tn, "make", tn->nodeB, tn->nodeA);
+    sendMessage(tn, "sure", tn->nodeA, tn->nodeB);
+    sendMessage(tn, "the", tn->nodeB, tn->nodeA);
+    sendMessage(tn, "cryptoauth", tn->nodeA, tn->nodeB);
+    sendMessage(tn, "can", tn->nodeB, tn->nodeA);
+    sendMessage(tn, "establish", tn->nodeA, tn->nodeB);
+
+    Log_debug(tn->logger, "\n\nTest passed, shutting down\n\n");
+    EventBase_endLoop(tn->base);
+}
+*/
+
+struct FuzzTest* CJDNS_FUZZ_MK(struct Allocator* alloc)
+{
+    struct Message* msg = Message_new(0, 2, alloc);
+    Message_push16(msg, 500, NULL);
+    struct FuzzTest* out = Allocator_calloc(alloc, sizeof(struct FuzzTest), 1);
+    out->name = "Map_fuzz_test_default";
+    out->fuzz = msg;
+    return out;
+}
+
+void* CJDNS_FUZZ_INIT(struct Allocator* alloc, struct Random* rand)
+{
+    struct Log* logger = NULL;
+    //struct Writer* logwriter = FileWriter_new(stdout, alloc);
+    //struct Log* logger = WriterLog_new(logwriter, alloc);
+    struct EventBase* base = EventBase_new(alloc);
+    struct Context* ctx = Allocator_calloc(alloc, sizeof(struct Context), 1);
+    Identity_set(ctx);
+    ctx->base = base;
+
+    uint8_t address[16];
+    uint8_t publicKey[32];
+    uint8_t privateKeyA[32];
+    Key_gen(address, publicKey, privateKeyA, rand);
+    struct TestFramework* a =
+        TestFramework_setUp((char*) privateKeyA, alloc, base, rand, logger);
+
+    uint8_t privateKeyB[32];
+    Key_gen(address, publicKey, privateKeyB, rand);
+    struct TestFramework* b =
+        TestFramework_setUp((char*) privateKeyB, alloc, base, rand, logger);
+
+    ctx->tunB.send = incomingTun;
+    ctx->tunA.send = incomingTun;
+    Iface_plumb(&ctx->tunB, b->tunIf);
+    Iface_plumb(&ctx->tunA, a->tunIf);
+    ctx->nodeB = b;
+    ctx->nodeA = a;
+    ctx->logger = logger;
+    ctx->checkLinkageTimeout = Timeout_setInterval(checkLinkage, ctx, 1, base, alloc);
+    ctx->base = base;
+    ctx->startTime = Time_currentTimeMilliseconds(base);
+
+    Log_debug(a->logger, "Waiting for nodes to link asynchronously...");
+    EventBase_beginLoop(base);
+
+    return ctx;
+}
+
+void CJDNS_FUZZ_MAIN(void* vctx, struct Message* msg)
+{
+    struct Context* ctx = Identity_check((struct Context*) vctx);
+    struct TestFramework* from = ctx->nodeA;
+    struct TestFramework* to = ctx->nodeB;
+
+    // forget it, it's gonna get killed in the Upper
+    if (msg->length < RouteHeader_SIZE) { return; }
+
+    // Lets fill in the ipv6, pubkey & label so that any
+    // old packet dump will work fine for testing
+    {
+        struct RouteHeader* rh = (struct RouteHeader*) msg->bytes;
+        if (!Bits_isZero(rh->ip6, 16)) { Bits_memcpy(rh->ip6, to->ip, 16); }
+        if (!Bits_isZero(rh->publicKey, 32)) { Bits_memcpy(rh->publicKey, to->publicKey, 32); }
+        rh->sh.label_be = EncodingScheme_serializeDirector(from->scheme, 1, -1);
+    }
+
+    // We're not limited to sending data types which we have registered for
+    Assert_true(!UpperDistributor_registerHandler(ctx->nodeA->nc->upper, 0, 0xfcfc));
+
+    struct Headers_UDPHeader udp = {
+        .srcPort_be = 0xfcfc,
+        .destPort_be = Endian_hostToBigEndian16(1), // UpperDistributor MAGIC_PORT
+        .length_be = Endian_hostToBigEndian16(msg->length + Headers_UDPHeader_SIZE),
+        .checksum_be = 0,
+    };
+    Message_push(msg, &udp, Headers_UDPHeader_SIZE, NULL);
+    uint8_t srcAndDest[32] = { [31] = 1 };
+    // fc00::1
+    AddressCalc_makeValidAddress(&srcAndDest[16]);
+    Bits_memcpy(&srcAndDest, from->ip, 16);
+    uint16_t checksum = Checksum_udpIp6(srcAndDest, msg->bytes, msg->length);
+    ((struct Headers_UDPHeader*)msg->bytes)->checksum_be = checksum;
+    TestFramework_craftIPHeader(msg, srcAndDest, &srcAndDest[16]);
+
+    Iface_send(&ctx->tunA, Message_clone(msg, from->alloc));
+
+    TestFramework_assertLastMessageUnaltered(ctx->nodeA);
+}

+ 32 - 0
test/FuzzTest.h

@@ -0,0 +1,32 @@
+/* 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 <https://www.gnu.org/licenses/>.
+ */
+#ifndef FuzzTest_H
+#define FuzzTest_H
+
+#include "wire/Message.h"
+#include "util/Linker.h"
+
+struct FuzzTest
+{
+    char* name;
+    struct Message* fuzz;
+    struct FuzzTest* next;
+};
+
+void CJDNS_FUZZ_MAIN(void* vctx, struct Message* fuzz);
+struct FuzzTest* CJDNS_FUZZ_MK(struct Allocator* alloc);
+void* CJDNS_FUZZ_INIT(struct Allocator* alloc, struct Random* rand);
+
+#endif

+ 13 - 1
test/TestFramework.c

@@ -22,6 +22,7 @@
 #include "memory/MallocAllocator.h"
 #include "memory/Allocator.h"
 #include "switch/SwitchCore.h"
+#include "subnode/SubnodePathfinder.h"
 #include "test/TestFramework.h"
 #include "util/log/WriterLog.h"
 #include "util/events/EventBase.h"
@@ -36,6 +37,7 @@
 #include "net/UpperDistributor.h"
 #include "net/TUNAdapter.h"
 #include "wire/Headers.h"
+#include "switch/NumberCompress.h"
 
 struct TestFramework_Link
 {
@@ -115,7 +117,16 @@ struct TestFramework* TestFramework_setUp(char* privateKey,
         privateKey = (char*)pks;
     }
 
-    struct NetCore* nc = NetCore_new(privateKey, allocator, base, rand, logger);
+    struct EncodingScheme* scheme = NumberCompress_defineScheme(allocator);
+
+    struct NetCore* nc =
+        NetCore_new(privateKey, allocator, base, rand, logger);
+
+    struct SubnodePathfinder* spf = SubnodePathfinder_new(
+        allocator, logger, base, rand, nc->myAddress, privateKey, scheme);
+    struct ASynchronizer* spfAsync = ASynchronizer_new(allocator, base, logger);
+    Iface_plumb(&spfAsync->ifA, &spf->eventIf);
+    EventEmitter_regPathfinderIface(nc->ee, &spfAsync->ifB);
 
     struct Pathfinder* pf = Pathfinder_register(allocator, logger, base, rand, NULL);
     pf->fullVerify = true;
@@ -134,6 +145,7 @@ struct TestFramework* TestFramework_setUp(char* privateKey,
     tf->publicKey = nc->myAddress->key;
     tf->ip = nc->myAddress->ip6.bytes;
     tf->pathfinder = pf;
+    tf->scheme = scheme;
 
     return tf;
 }

+ 2 - 0
test/TestFramework.h

@@ -15,6 +15,7 @@
 #ifndef TestFramework_H
 #define TestFramework_H
 
+#include "switch/EncodingScheme.h"
 #include "net/NetCore.h"
 #include "util/Linker.h"
 Linker_require("test/TestFramework.c");
@@ -28,6 +29,7 @@ struct TestFramework
     struct Pathfinder* pathfinder;
     struct Iface* tunIf;
     struct NetCore* nc;
+    struct EncodingScheme* scheme;
 
     /** The last message which this node sent. */
     struct Message* lastMsg;

+ 116 - 9
test/testcjdroute.c

@@ -12,13 +12,20 @@
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
+#include "crypto/random/Random.h"
+#include "crypto/random/test/DeterminentRandomSeed.h"
 #include "util/Assert.h"
 #include "util/events/Time.h"
 #include "util/events/EventBase.h"
 #include "util/CString.h"
 #include "memory/MallocAllocator.h"
+#include "wire/Message.h"
+#include "test/FuzzTest.h"
+#include "util/Js.h"
 
 #include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
 
 #ifdef SUBNODE
     #define testcjdroute_SUBNODE 1
@@ -26,19 +33,29 @@
     #define testcjdroute_SUBNODE 0
 #endif
 
-<?js require("./test/testcjdroute.js").generate(
-    file, builder, testcjdroute_SUBNODE, this.async()); ?>
-
-<?js return file.testcjdroute_prototypes; ?>
+Js({
+    require("./test/testcjdroute.js").generate(
+        file, builder, testcjdroute_SUBNODE, this.async());
+})
+Js({ return file.testcjdroute_prototypes; })
 
 typedef int (* Test)(int argc, char** argv);
+typedef void* (* FuzzTestInit)(struct Allocator* alloc, struct Random* rand);
+typedef void (* FuzzTest)(void* ctx, struct Message* fuzz);
+typedef struct FuzzTest* (* MkFuzz)(struct Allocator* alloc);
 
-static struct {
+static const struct {
     Test func;
     char* name;
-} TESTS[] = {
-    <?js return file.testcjdroute_tests ?>
-};
+} TESTS[] = { Js({ return file.testcjdroute_tests }) };
+
+static const struct {
+    FuzzTestInit init;
+    FuzzTest fuzz;
+    MkFuzz mkFuzz;
+    char* name;
+} FUZZ_TESTS[] = { Js({ return file.testcjdroute_fuzzTests }) };
+static const int FUZZ_TEST_COUNT = (int) (sizeof(FUZZ_TESTS) / sizeof(*FUZZ_TESTS));
 
 static uint64_t runTest(Test test,
                         char* name,
@@ -70,8 +87,98 @@ static void usage(char* appName)
     }
 }
 
+static struct Message* readStdin(struct Allocator* alloc)
+{
+    uint8_t buff[4096] = { 0 };
+    ssize_t length = read(STDIN_FILENO, buff, 4096);
+    if (length >= 4096) {
+        printf("No test files over 4096 bytes\n");
+        length = 0;
+    }
+    struct Message* msg = Message_new(length, 0, alloc);
+    Bits_memcpy(msg->bytes, buff, length);
+    return msg;
+}
+
+static void** initFuzzTests(struct Allocator* alloc, struct Random* rand, struct EventBase* base)
+{
+    void** contexts = Allocator_calloc(alloc, sizeof(char*), FUZZ_TEST_COUNT);
+    for (int i = 0; i < FUZZ_TEST_COUNT; i++) {
+        contexts[i] = FUZZ_TESTS[i].init(alloc, rand);
+    }
+    return contexts;
+}
+
+// We don't really want to let AFL write the random seed because the amount of mixing
+// that occurs between the input and output makes any attempt at optimizing the seed
+// useless.
+//
+// We do, however, want to make sure that crashes discovered by AFL are reproducable.
+//
+// We might imagine letting part of the AFL message content be the random data which
+// is returned, but we don't know how much will be requested in advance. Possibly
+// something for the future.
+#define RANDOM_SEED "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
+
+static int fuzzMain()
+{
+    struct Allocator* alloc = MallocAllocator_new(1<<24);
+    struct EventBase* base = EventBase_new(alloc);
+    struct RandomSeed* rs = DeterminentRandomSeed_new(alloc, RANDOM_SEED);
+    struct Random* rand = Random_newWithSeed(alloc, NULL, rs, NULL);
+
+#ifdef __AFL_INIT
+    // Enable AFL deferred forkserver mode. Requires compilation using afl-clang-fast
+    void** ctxs = initFuzzTests(alloc, rand, base);
+    __AFL_INIT();
+    #define CTX(selector) ctxs[selector]
+#else
+    // avoid warning
+    if (0) { initFuzzTests(alloc, rand, base); }
+    #define CTX(selector) FUZZ_TESTS[selector].init(alloc, rand)
+#endif
+
+    struct Message* fuzz = readStdin(alloc);
+    if (fuzz->length < 4) { return 100; }
+    uint32_t selector = Message_pop32(fuzz, NULL);
+    printf("x\n");
+    if (selector >= FUZZ_TEST_COUNT) {
+        printf("selector [%x] out of bounds [%u]\n", selector, FUZZ_TEST_COUNT);
+        return 100;
+    }
+    printf("Running [%s] ([%u])\n", FUZZ_TESTS[selector].name, selector);
+    void* ctx = CTX(selector);
+    FUZZ_TESTS[selector].fuzz(ctx, fuzz);
+    Allocator_free(alloc);
+    return 0;
+}
+
+static int mkFuzz()
+{
+    struct Allocator* alloc = MallocAllocator_new(1<<24);
+    for (int i = 0; i < FUZZ_TEST_COUNT; i++) {
+        printf("Making test data [%s]\n", FUZZ_TESTS[i].name);
+        struct Allocator* child = Allocator_child(alloc);
+        struct FuzzTest* ft = FUZZ_TESTS[i].mkFuzz(child);
+        uint32_t i_be = Endian_hostToBigEndian32(i);
+        while (ft) {
+            int f = open(ft->name, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+            if (f == -1) { perror(""); }
+            Assert_true(f > -1);
+            Assert_true(write(f, &i_be, 4) == 4);
+            Assert_true(write(f, ft->fuzz->bytes, ft->fuzz->length) == ft->fuzz->length);
+            close(f);
+            ft = ft->next;
+        }
+        Allocator_free(child);
+    }
+    return 0;
+}
+
 int main(int argc, char** argv)
 {
+    if (argc > 1 && !CString_strcmp("mkfuzz", argv[1])) { return mkFuzz(); }
+    if (argc > 1 && !CString_strcmp("fuzz", argv[1])) { return fuzzMain(); }
     struct Allocator* alloc = MallocAllocator_new(4096);
     struct EventBase* base = EventBase_new(alloc);
     uint64_t now = Time_hrtime();
@@ -81,7 +188,7 @@ int main(int argc, char** argv)
         usage(argv[0]);
         return 100;
     }
-    if (CString_strcmp("all", argv[1])) {
+    if (argc > 1 && CString_strcmp("all", argv[1])) {
         for (int i = 0; i < (int)(sizeof(TESTS)/sizeof(*TESTS)); i++) {
             if (!CString_strcmp(TESTS[i].name, argv[1])) {
                 TESTS[i].func(argc, argv);

+ 24 - 4
test/testcjdroute.js

@@ -58,17 +58,37 @@ var generate = module.exports.generate = function (file, builder, isSubnode, cal
     getTests('.', tests, isSubnode, function () {
         var prototypes = [];
         var listContent = [];
+        var fuzzTests = [];
         tests.forEach(function (test) {
-            var main = /^.*\/([^\/]+)\.c$/.exec(test)[1] + '_main';
+            var testProto = /^.*\/([^\/]+)\.c$/.exec(test)[1];
+            var main = testProto + '_main';
             (builder.config['cflags'+test] =
                 builder.config['cflags'+test] || [])
                 .push('-D', 'main='+main,
-                      '-D', main+'(...)='+main+'(int argc, char** argv);int '+main+'(int argc, char** argv)');
+                      '-D', main+'(...)='+main+'(int argc, char** argv);int '+main+'(int argc, char** argv)',
+                      '-D', 'CJDNS_FUZZ_INIT='+testProto+'_FUZZ_INIT',
+                      '-D', 'CJDNS_FUZZ_MAIN='+testProto+'_FUZZ_MAIN',
+                      '-D', 'CJDNS_FUZZ_MK='+testProto+'_FUZZ_MK'
+                );
             file.links.push(test);
-            listContent.push('{ .func = '+main+', .name = "'+test.replace(/^.*\/|.c$/g, '')+'" },');
-            prototypes.push('int '+main+'(int argc, char** argv);');
+            if (test.indexOf('_fuzz_test') > -1) {
+                prototypes.push('void* '+testProto+'_FUZZ_INIT(struct Allocator* alloc, ' +
+                    'struct Random* rand);');
+                prototypes.push('void '+testProto+'_FUZZ_MAIN(void* ctx, struct Message* fuzz);');
+                prototypes.push('struct FuzzTest* '+testProto+'_FUZZ_MK(struct Allocator* alloc);');
+                fuzzTests.push('{' +
+                    '.init = '+testProto+'_FUZZ_INIT, ' +
+                    '.name = "'+test.replace(/^.*\/|.c$/g, '')+'", ' +
+                    '.fuzz = '+testProto+'_FUZZ_MAIN, ' +
+                    '.mkFuzz = '+testProto+'_FUZZ_MK, ' +
+                '},');
+            } else {
+                prototypes.push('int '+main+'(int argc, char** argv);');
+                listContent.push('{ .func = '+main+', .name = "'+test.replace(/^.*\/|.c$/g, '')+'" },');
+            }
         });
         file.testcjdroute_tests = listContent.join('\n');
+        file.testcjdroute_fuzzTests = fuzzTests.join('\n');
         file.testcjdroute_prototypes = prototypes.join('\n');
         callback();
     });

+ 25 - 0
util/Js.h

@@ -0,0 +1,25 @@
+/* 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 <https://www.gnu.org/licenses/>.
+ */
+#ifndef Js_H
+#define Js_H
+
+#define Js(x)
+
+#if !defined(__INTELLISENSE__)
+    #undef Js
+    #define Js(x) <?js do x while (0); ?>
+#endif
+
+#endif

+ 39 - 58
util/test/Map_fuzz_test.c

@@ -13,11 +13,10 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 #include "crypto/random/Random.h"
-#include "memory/MallocAllocator.h"
-#include "benc/String.h"
 #include "util/Assert.h"
-#include "util/events/Time.h"
-#include "util/log/FileWriterLog.h"
+#include "wire/Message.h"
+#include "test/FuzzTest.h"
+#include "util/events/EventBase.h"
 
 #define Map_NAME OfLongsByInteger
 #define Map_KEY_TYPE uint32_t
@@ -25,65 +24,47 @@
 #define Map_ENABLE_HANDLES
 #include "util/Map.h"
 
-#include <stdio.h>
-#include <stdbool.h>
-
-// Increase this number to make the fuzz test run longer.
-#define QUICK_CYCLES 5
-#define SLOW_CYCLES 1000
-
-int main(int argc, char* argv[])
+struct FuzzTest* CJDNS_FUZZ_MK(struct Allocator* alloc)
 {
-    int cycles = QUICK_CYCLES;
-    for (int i = 0; i < argc; i++) {
-        if (!CString_strcmp("--fuzz", argv[i])) {
-            cycles = SLOW_CYCLES;
-            break;
-        }
-    }
+    struct Message* msg = Message_new(0, 2, alloc);
+    Message_push16(msg, 500, NULL);
+    struct FuzzTest* out = Allocator_calloc(alloc, sizeof(struct FuzzTest), 1);
+    out->name = "Map_fuzz_test_default";
+    out->fuzz = msg;
+    return out;
+}
 
-    // This test is too slow to run with the normal battery of tests
-    if (cycles == QUICK_CYCLES) {
-        return 0;
-    }
+void* CJDNS_FUZZ_INIT(struct Allocator* alloc, struct Random* rand)
+{
+    return alloc;
+}
 
-    struct Allocator* mainAlloc = MallocAllocator_new(1<<18);
-    struct Random* rand = Random_new(mainAlloc, NULL, NULL);
-    struct Log* logger = FileWriterLog_new(stdout, mainAlloc);
+void CJDNS_FUZZ_MAIN(void* vctx, struct Message* fuzz)
+{
+    struct Allocator* alloc = (struct Allocator*) vctx;
+    if (fuzz->length < 4) { return; }
+    uint32_t size = Message_pop16(fuzz, NULL) % 4096;
 
-    for (int cycle = 0; cycle < cycles; cycle++) {
-        struct Allocator* alloc = MallocAllocator_new(1<<24);
-        struct Map_OfLongsByInteger* map = Map_OfLongsByInteger_new(alloc);
-        uint32_t size;
-        Random_bytes(rand, (uint8_t*) &size, 4);
-        size = size % 4096;
-        uint32_t* keys = Allocator_malloc(alloc, sizeof(uint32_t) * size);
-        uint64_t* vals = Allocator_malloc(alloc, sizeof(uint64_t) * size);
+    struct Map_OfLongsByInteger* map = Map_OfLongsByInteger_new(alloc);
+    size = size % 4096;
+    uint32_t* keys = Allocator_malloc(alloc, sizeof(uint32_t) * size);
+    uint64_t* vals = Allocator_malloc(alloc, sizeof(uint64_t) * size);
 
-        uint32_t key = 3;
-        uint64_t val = 4;
-        int64_t begin = Time_hrtime();
-        for (uint32_t i = 0; i < size; i++) {
-            keys[i] = key;
-            vals[i] = val;
-            Map_OfLongsByInteger_put(&key, &val, map);
-            key += ((val >> 13 ^ size << 19) & 0x000fffff) + 1;
-            //Log_debug(logger, "%u", (val >> 13 ^ size << 19) & 0x000fffff);
-            Assert_true(key > keys[i]);
-            val += key >> 19 ^ i << 13;
-        }
-        int64_t timeUsed = Time_hrtime() - begin;
-        Log_debug(logger, "cycle %d Map put %u values used %lu ms.\n",
-                cycle, size, (unsigned long)(timeUsed / 1000000));
+    uint32_t key = 3;
+    uint64_t val = 4;
+    for (uint32_t i = 0; i < size; i++) {
+        keys[i] = key;
+        vals[i] = val;
+        Map_OfLongsByInteger_put(&key, &val, map);
+        key += ((val >> 13 ^ size << 19) & 0x000fffff) + 1;
+        //Log_debug(logger, "%u", (val >> 13 ^ size << 19) & 0x000fffff);
+        Assert_true(key > keys[i]);
+        val += key >> 19 ^ i << 13;
+    }
 
-        // check all keys there
-        for (uint32_t i = 0; i < size; ++i) {
-            int index = Map_OfLongsByInteger_indexForKey(&keys[i], map);
-            Assert_true(map->values[index] == vals[i]);
-        }
-        Allocator_free(alloc);
+    // check all keys there
+    for (uint32_t i = 0; i < size; ++i) {
+        int index = Map_OfLongsByInteger_indexForKey(&keys[i], map);
+        Assert_true(map->values[index] == vals[i]);
     }
-    Log_debug(logger, "===+++=== Completed Ok ===++++===");
-    Allocator_free(mainAlloc);
-    return 0;
 }

+ 0 - 63
util/test/Timeout_test.c.disabled

@@ -1,63 +0,0 @@
-/*
- * 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 <https://www.gnu.org/licenses/>.
- */
-#include <stdio.h>
-#include <event2/event.h>
-
-#include "memory/MemAllocator.h"
-#include "memory/BufferAllocator.h"
-#include "util/Timeout.h"
-
-/**
- * This is slow so it should only be run manually.
- */
-
-struct Context
-{
-    struct Timeout* timeout;
-
-    uint32_t count;
-};
-
-void callback(void* context)
-{
-    printf("Timeout was called!\n");
-    *((uint32_t*) context) = 1;
-}
-
-void intervalCallback(void* vcontext)
-{
-    struct Context* context = (struct Context*) vcontext;
-    context->count++;
-    if (context->count > 2) {
-        Timeout_resetTimeout(context->timeout, 5000);
-    }
-    if (context->count > 3) {
-        Timeout_clearTimeout(context->timeout);
-    }
-    printf("Interval was called!\n");
-}
-
-int main()
-{
-    uint8_t buffer[1024];
-    struct MemAllocator* allocator = BufferAllocator_new(buffer, 1024);
-    struct Context timeoutContext = {NULL, 0};
-    struct Context intervalContext = {NULL, 0};
-    struct event_base* base = event_base_new();
-    timeoutContext.timeout =
-        Timeout_setTimeout(callback, &timeoutContext, 2000, base, allocator);
-    intervalContext.timeout =
-        Timeout_setInterval(intervalCallback, &intervalContext, 500, base, allocator);
-    event_base_loop(base, 0);
-}