/*
 * Send a ping packet to one of the endpoints.
 */
static void sendPing(struct InterfaceController_Peer* ep)
{
    struct InterfaceController_pvt* ic = ifcontrollerForPeer(ep);

    ep->pingCount++;

    struct SwitchPinger_Ping* ping =
        SwitchPinger_newPing(ep->switchLabel,
                             String_CONST(""),
                             ic->timeoutMilliseconds,
                             onPingResponse,
                             ic->allocator,
                             ic->switchPinger);

    #ifdef Log_DEBUG
        uint8_t key[56];
        Base32_encode(key, 56, CryptoAuth_getHerPublicKey(ep->cryptoAuthIf), 32);
    #endif
    if (!ping) {
        Log_debug(ic->logger, "Failed to ping [%s.k], out of ping slots", key);
        return;
    } else {
        Log_debug(ic->logger, "SwitchPing [%s.k]", key);
    }

    ping->onResponseContext = ep;
}
Exemple #2
0
/*
 * Send a ping packet to one of the endpoints.
 */
static void sendPing(struct Peer* ep)
{
    struct InterfaceController_pvt* ic = Identity_check(ep->ici->ic);

    ep->pingCount++;

    struct SwitchPinger_Ping* ping =
        SwitchPinger_newPing(ep->addr.path,
                             String_CONST(""),
                             ic->timeoutMilliseconds,
                             onPingResponse,
                             ep->alloc,
                             ic->switchPinger);

    if (Defined(Log_DEBUG)) {
        uint8_t key[56];
        Base32_encode(key, 56, ep->caSession->herPublicKey, 32);
        if (!ping) {
            Log_debug(ic->logger, "Failed to ping [%s.k], out of ping slots", key);
        } else {
            Log_debug(ic->logger, "SwitchPing [%s.k]", key);
        }
    }

    if (ping) {
        ping->onResponseContext = ep;
    }
}
Exemple #3
0
String* Key_stringify(uint8_t key[32], struct Allocator* alloc)
{
    String* out = String_newBinary(NULL, 55, alloc);
    Base32_encode((uint8_t*)out->bytes, 53, key, 32);
    out->bytes[53] = '.';
    out->bytes[54] = 'k';
    return out;
}
static void onPingResponse(struct SwitchPinger_Response* resp, void* onResponseContext)
{
    if (SwitchPinger_Result_OK != resp->res) {
        return;
    }
    struct InterfaceController_Peer* ep =
        Identity_check((struct InterfaceController_Peer*) onResponseContext);
    struct InterfaceController_pvt* ic = ifcontrollerForPeer(ep);

    struct Address addr;
    Bits_memset(&addr, 0, sizeof(struct Address));
    Bits_memcpyConst(addr.key, CryptoAuth_getHerPublicKey(ep->cryptoAuthIf), 32);
    addr.path = ep->switchLabel;
    addr.protocolVersion = resp->version;

    #ifdef Log_DEBUG
        uint8_t addrStr[60];
        Address_print(addrStr, &addr);
        uint8_t key[56];
        Base32_encode(key, 56, CryptoAuth_getHerPublicKey(ep->cryptoAuthIf), 32);
    #endif

    if (!Version_isCompatible(Version_CURRENT_PROTOCOL, resp->version)) {
        Log_debug(ic->logger, "got switch pong from node [%s] with incompatible version [%d]",
                  key, resp->version);
    } else {
        Log_debug(ic->logger, "got switch pong from node [%s] with version [%d]",
                  key, resp->version);
    }

    if (!ep->timeOfLastPing) {
        // We've never heard from this machine before (or we've since forgotten about it)
        // This is here because we want the tests to function without the janitor present.
        // Other than that, it just makes a slightly more synchronous/guaranteed setup.
        Router_sendGetPeers(ic->router, &addr, 0, 0, ic->allocator);
    }

    struct Node_Link* link = Router_linkForPath(ic->router, resp->label);
    if (!link || !Node_getBestParent(link->child)) {
        RumorMill_addNode(ic->rumorMill, &addr);
    } else {
        Log_debug(ic->logger, "link exists");
    }

    ep->timeOfLastPing = Time_currentTimeMilliseconds(ic->eventBase);

    #ifdef Log_DEBUG
        // This will be false if it times out.
        //Assert_true(label == ep->switchLabel);
        uint8_t path[20];
        AddrTools_printPath(path, resp->label);
        uint8_t sl[20];
        AddrTools_printPath(sl, ep->switchLabel);
        Log_debug(ic->logger, "Received [%s] from lazy endpoint [%s]  [%s]",
                  SwitchPinger_resultString(resp->res)->bytes, path, sl);
    #endif
}
// Called from the pingInteral timeout.
static void pingCallback(void* vic)
{
    struct Context* ic = Identity_cast((struct Context*) vic);
    uint64_t now = Time_currentTimeMilliseconds(ic->eventBase);
    ic->pingCount++;

    // scan for endpoints have not sent anything recently.
    for (uint32_t i = 0; i < ic->peerMap.count; i++) {
        struct IFCPeer* ep = ic->peerMap.values[i];
        if (now > ep->timeOfLastMessage + ic->pingAfterMilliseconds) {
            #ifdef Log_DEBUG
                  uint8_t key[56];
                  Base32_encode(key, 56, CryptoAuth_getHerPublicKey(ep->cryptoAuthIf), 32);
            #endif
            if (ep->transient && now > ep->timeOfLastMessage + ic->forgetAfterMilliseconds) {
                Log_debug(ic->logger, "Unresponsive peer [%s.k] has not responded in [%u] "
                                      "seconds, dropping connection",
                                      key, ic->forgetAfterMilliseconds / 1024);
                Allocator_free(ep->external->allocator);
            } else if (now > ep->timeOfLastMessage + ic->unresponsiveAfterMilliseconds) {
                // Lets skip 87% of pings when they're really down.
                if (ic->pingCount % 8) {
                    continue;
                }
                ep->state = InterfaceController_PeerState_UNRESPONSIVE;
                uint32_t lag = ((now - ep->timeOfLastMessage) / 1024);
                Log_debug(ic->logger, "Pinging unresponsive peer [%s.k] lag [%u]", key, lag);
            } else {
                uint32_t lag = ((now - ep->timeOfLastMessage) / 1024);
                Log_debug(ic->logger, "Pinging lazy peer [%s] lag [%u]", key, lag);
            }

            struct SwitchPinger_Ping* ping =
                SwitchPinger_newPing(ep->switchLabel,
                                     String_CONST(""),
                                     ic->timeoutMilliseconds,
                                     onPingResponse,
                                     ic->switchPinger);

            ping->onResponseContext = ep;

            SwitchPinger_sendPing(ping);
        }
    }
}
Exemple #6
0
static int genAddress(uint8_t addressOut[40],
                      uint8_t privateKeyHexOut[65],
                      uint8_t publicKeyBase32Out[53])
{
    struct Address address;
    uint8_t privateKey[32];

    for (;;) {
        randombytes(privateKey, 32);
        crypto_scalarmult_curve25519_base(address.key, privateKey);
        AddressCalc_addressForPublicKey(address.ip6.bytes, address.key);
        // Brute force for keys until one matches FC00:/8
        if (address.ip6.bytes[0] == 0xFC) {
            Hex_encode(privateKeyHexOut, 65, privateKey, 32);
            Base32_encode(publicKeyBase32Out, 53, address.key, 32);
            Address_printIp(addressOut, &address);
            return 0;
        }
    }
}
Exemple #7
0
int main()
{
    struct Allocator* alloc;
    BufferAllocator_STACK(alloc, 512);
    struct Random* rand = Random_new(alloc, NULL);

    uint8_t bytes[32];
    Random_bytes(rand, bytes, 32);

    uint8_t base32[64];
    Bits_memset(base32, 0, 64);

    Assert_always(Base32_encode(base32, 64, bytes, 32) == 52);

    //printf("base32 encoded: %s\n", base32);

    uint8_t bytes2[32];
    Assert_always(Base32_decode(bytes2, 32, base32, 52) == 32);

    Assert_always(Bits_memcmp(bytes, bytes2, 32) == 0);
}
int main()
{
    /* verify public key */
    struct Address address;
    crypto_scalarmult_curve25519_base(address.key, privateKey);

    AddressCalc_addressForPublicKey(address.ip6.bytes, address.key);

    uint8_t privateKeyHexOut[65];
    uint8_t publicKeyHexOut[65];
    uint8_t publicKeyBase32Out[53];

    Hex_encode(privateKeyHexOut, 65, privateKey, 32);

    Hex_encode(publicKeyHexOut, 65, publicKey, 32);

    printf("Private key %s (hex)\n\nExpect:\nPublic Key: %s (hex)\n"
           "Public Key: %s (base32)\nAddress: %s\n",
           privateKeyHexOut,
           publicKeyHexOut,
           publicKeyBase32,
           ipv6);

    uint8_t addressOut[40];

    Hex_encode(publicKeyHexOut, 65, address.key, 32);
    Base32_encode(publicKeyBase32Out, 53, address.key, 32);
    Address_printIp(addressOut, &address);

    printf("\nGot:\nPublic Key: %s (hex)\n"
           "Public Key: %s (base32)\nAddress: %s\n",
           publicKeyHexOut,
           publicKeyBase32Out,
           addressOut);

    Assert_always(0 == memcmp(address.key, publicKey, 32));
    Assert_always(0 == strcmp(publicKeyBase32, (char*) publicKeyBase32Out));
    Assert_always(0 == strcmp(ipv6, (char*) addressOut));
}
static int genAddress(uint8_t addressOut[40],
                      uint8_t privateKeyHexOut[65],
                      uint8_t publicKeyBase32Out[53],
                      uint8_t privateKey[32])
{
    struct Address address;

    crypto_scalarmult_curve25519_base(address.key, privateKey);
    AddressCalc_addressForPublicKey(address.ip6.bytes, address.key);
    // Brute force for keys until one matches FC00:/8
    if(
        address.ip6.bytes[0] == 0xFC// &&
        //(address.ip6.bytes[15] & 0xF) == (address.ip6.bytes[15] & 0x0F << 4) &&
        //address.ip6.bytes[14] == address.ip6.bytes[15]
    )
    {
        Hex_encode(privateKeyHexOut, 65, privateKey, 32);
        Base32_encode(publicKeyBase32Out, 53, address.key, 32);
        Address_printIp(addressOut, &address);
        return 1;
    }
    return 0;
}
Exemple #10
0
int main()
{
    struct Allocator* alloc = MallocAllocator_new(20000);
    struct Random* rand = Random_new(alloc, NULL, NULL);

    uint8_t bytes[32];
    Random_bytes(rand, bytes, 32);

    uint8_t base32[64];
    Bits_memset(base32, 0, 64);

    Assert_always(Base32_encode(base32, 64, bytes, 32) == 52);

    //printf("base32 encoded: %s\n", base32);

    uint8_t bytes2[32];
    Assert_always(Base32_decode(bytes2, 32, base32, 52) == 32);

    Assert_always(Bits_memcmp(bytes, bytes2, 32) == 0);

    Allocator_free(alloc);
    return 0;
}
Exemple #11
0
int main(int argc, char** argv)
{
    #ifdef Log_KEYS
        fprintf(stderr, "Log_LEVEL = KEYS, EXPECT TO SEE PRIVATE KEYS IN YOUR LOGS!\n");
    #endif
    Crypto_init();
    assert(argc > 0);

    if (argc == 1) { // no arguments
        if (isatty(STDIN_FILENO)) {
            // We were started from a terminal
            // The chances an user wants to type in a configuration
            // bij hand are pretty slim so we show him the usage
            return usage(argv[0]);
        } else {
            // We assume stdin is a configuration file and that we should
            // start routing
        }
    }
    if (argc == 2) { // one argument
        if (strcmp(argv[1], "--help") == 0) {
            return usage(argv[0]);
        } else if (strcmp(argv[1], "--genconf") == 0) {
            return genconf();
        } else if (strcmp(argv[1], "--getcmds") == 0) {
            // Performed after reading the configuration
        } else if (strcmp(argv[1], "--pidfile") == 0) {
            // Performed after reading the configuration
        } else {
            fprintf(stderr, "%s: unrecognized option '%s'\n", argv[0], argv[1]);
        fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]);
            return -1;
        }
    }
    if (argc >  2) { // more than one argument?
        fprintf(stderr, "%s: too many arguments\n", argv[0]);
        fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]);
        return -1;
    }

    struct Context context;
    memset(&context, 0, sizeof(struct Context));
    context.base = event_base_new();

    // Allow it to allocate 4MB
    context.allocator = MallocAllocator_new(1<<22);
    struct Reader* reader = FileReader_new(stdin, context.allocator);
    Dict config;
    if (JsonBencSerializer_get()->parseDictionary(reader, context.allocator, &config)) {
        fprintf(stderr, "Failed to parse configuration.\n");
        return -1;
    }

    if (argc == 2 && strcmp(argv[1], "--getcmds") == 0) {
        return getcmds(&config);
    }
    if (argc == 2 && strcmp(argv[1], "--pidfile") == 0) {
        pidfile(&config);
        return 0;
    }

    char* user = setUser(Dict_getList(&config, BSTR("security")));

    // Admin
    Dict* adminConf = Dict_getDict(&config, BSTR("admin"));
    if (adminConf) {
        admin(adminConf, user, &context);
    }

    // Logging
    struct Writer* logwriter = FileWriter_new(stdout, context.allocator);
    struct Log logger = { .writer = logwriter };
    context.logger = &logger;

    struct Address myAddr;
    uint8_t privateKey[32];
    parsePrivateKey(&config, &myAddr, privateKey);

    context.eHandler = AbortHandler_INSTANCE;
    context.switchCore = SwitchCore_new(context.logger, context.allocator);
    context.ca =
        CryptoAuth_new(&config, context.allocator, privateKey, context.base, context.logger);
    context.registry = DHTModules_new(context.allocator);
    ReplyModule_register(context.registry, context.allocator);

    // Router
    Dict* routerConf = Dict_getDict(&config, BSTR("router"));
    registerRouter(routerConf, myAddr.key, &context);

    SerializationModule_register(context.registry, context.allocator);

    // Authed passwords.
    List* authedPasswords = Dict_getList(&config, BSTR("authorizedPasswords"));
    if (authedPasswords) {
        authorizedPasswords(authedPasswords, &context);
    }

    // Interfaces.
    Dict* interfaces = Dict_getDict(&config, BSTR("interfaces"));
    Dict* udpConf = Dict_getDict(interfaces, BSTR("UDPInterface"));

    if (udpConf) {
        configureUDP(udpConf, &context);
    }

    if (udpConf == NULL) {
        fprintf(stderr, "No interfaces configured to connect to.\n");
        return -1;
    }

    // pid file
    String* pidFile = Dict_getString(&config, BSTR("pidFile"));
    if (pidFile) {
        Log_info1(context.logger, "Writing pid of process to [%s].\n", pidFile->bytes);
        FILE* pf = fopen(pidFile->bytes, "w");
        if (!pf) {
            Log_critical2(context.logger,
                          "Failed to open pid file [%s] for writing, errno=%d\n",
                          pidFile->bytes,
                          errno);
            return -1;
        }
        fprintf(pf, "%d", getpid());
        fclose(pf);
    }

    Ducttape_register(&config,
                      privateKey,
                      context.registry,
                      context.routerModule,
                      context.routerIf,
                      context.switchCore,
                      context.base,
                      context.allocator,
                      context.logger);

    uint8_t address[53];
    Base32_encode(address, 53, myAddr.key, 32);
    Log_info1(context.logger, "Your address is: %s.k\n", address);
    uint8_t myIp[40];
    Address_printIp(myIp, &myAddr);
    Log_info1(context.logger, "Your IPv6 address is: %s\n", myIp);

    // Security.
    security(Dict_getList(&config, BSTR("security")), context.logger, context.eHandler);

    event_base_loop(context.base, 0);

    // Never reached.
    return 0;
}
Exemple #12
0
static void randomBase32(uint8_t output[32])
{
    uint8_t bin[16];
    randombytes(bin, 16);
    Base32_encode(output, 32, bin, 16);
}
/**
 * Check the table for nodes which might need to be pinged, ping a node if necessary.
 * If a node has not responded in unresponsiveAfterMilliseconds then mark them as unresponsive
 * and if the connection is incoming and the node has not responded in forgetAfterMilliseconds
 * then drop them entirely.
 * This is called every PING_INTERVAL_MILLISECONDS but pingCallback is a misleading name.
 */
static void pingCallback(void* vic)
{
    struct InterfaceController_pvt* ic = Identity_check((struct InterfaceController_pvt*) vic);
    if (!ic->peerMap.count) { return; }

    uint64_t now = Time_currentTimeMilliseconds(ic->eventBase);

    // scan for endpoints have not sent anything recently.
    uint32_t startAt = Random_uint32(ic->rand) % ic->peerMap.count;
    for (uint32_t i = startAt, count = 0; (!count || i != startAt) && count <= ic->peerMap.count;) {
        i = (i + 1) % ic->peerMap.count;
        count++;

        struct InterfaceController_Peer* ep = ic->peerMap.values[i];

        if (now < ep->timeOfLastMessage + ic->pingAfterMilliseconds) {
            if (now < ep->timeOfLastPing + ic->pingAfterMilliseconds) {
                // Possibly an out-of-date node which is mangling packets, don't ping too often
                // because it causes the RumorMill to be filled with this node over and over.
                continue;
            }

            struct Node_Link* link = Router_linkForPath(ic->router, ep->switchLabel);
            // It exists, it's parent is the self-node, and it's label is equal to the switchLabel.
            if (link
                && Node_getBestParent(link->child)
                && Node_getBestParent(link->child)->parent->address.path == 1
                && Node_getBestParent(link->child)->cannonicalLabel == ep->switchLabel)
            {
                continue;
            }
        }

        #ifdef Log_DEBUG
              uint8_t key[56];
              Base32_encode(key, 56, CryptoAuth_getHerPublicKey(ep->cryptoAuthIf), 32);
        #endif

        if (ep->isIncomingConnection
            && now > ep->timeOfLastMessage + ic->forgetAfterMilliseconds)
        {
            Log_debug(ic->logger, "Unresponsive peer [%s.k] has not responded in [%u] "
                                  "seconds, dropping connection",
                                  key, ic->forgetAfterMilliseconds / 1024);
            Allocator_free(ep->external->allocator);
            continue;
        }

        bool unresponsive = (now > ep->timeOfLastMessage + ic->unresponsiveAfterMilliseconds);
        if (unresponsive) {
            // our link to the peer is broken...
            Router_disconnectedPeer(ic->router, ep->switchLabel);

            // Lets skip 87% of pings when they're really down.
            if (ep->pingCount % 8) {
                ep->pingCount++;
                continue;
            }

            ep->state = InterfaceController_PeerState_UNRESPONSIVE;
        }

        #ifdef Log_DEBUG
            uint32_t lag = (now - ep->timeOfLastMessage) / 1024;
            Log_debug(ic->logger,
                      "Pinging %s peer [%s.k] lag [%u]",
                      (unresponsive ? "unresponsive" : "lazy"), key, lag);
        #endif

        sendPing(ep);

        // we only ping one node
        return;
    }
}
Exemple #14
0
static void iciPing(struct InterfaceController_Iface_pvt* ici, struct InterfaceController_pvt* ic)
{
    if (!ici->peerMap.count) { return; }
    uint64_t now = Time_currentTimeMilliseconds(ic->eventBase);

    // scan for endpoints have not sent anything recently.
    uint32_t startAt = Random_uint32(ic->rand) % ici->peerMap.count;
    for (uint32_t i = startAt, count = 0; count < ici->peerMap.count;) {
        i = (i + 1) % ici->peerMap.count;
        count++;

        struct Peer* ep = ici->peerMap.values[i];

        if (now < ep->timeOfLastMessage + ic->pingAfterMilliseconds) {
            if (now < ep->timeOfLastPing + ic->pingAfterMilliseconds) {
                // Possibly an out-of-date node which is mangling packets, don't ping too often
                // because it causes the RumorMill to be filled with this node over and over.
                continue;
            }
        }

        uint8_t keyIfDebug[56];
        if (Defined(Log_DEBUG)) {
            Base32_encode(keyIfDebug, 56, ep->caSession->herPublicKey, 32);
        }

        if (ep->isIncomingConnection && now > ep->timeOfLastMessage + ic->forgetAfterMilliseconds) {
            Log_debug(ic->logger, "Unresponsive peer [%s.k] has not responded in [%u] "
                                  "seconds, dropping connection",
                                  keyIfDebug, ic->forgetAfterMilliseconds / 1024);
            sendPeer(0xffffffff, PFChan_Core_PEER_GONE, ep);
            Allocator_free(ep->alloc);
            continue;
        }

        bool unresponsive = (now > ep->timeOfLastMessage + ic->unresponsiveAfterMilliseconds);
        if (unresponsive) {
            // our link to the peer is broken...

            // Lets skip 87% of pings when they're really down.
            if (ep->pingCount % 8) {
                ep->pingCount++;
                continue;
            }

            sendPeer(0xffffffff, PFChan_Core_PEER_GONE, ep);
            ep->state = InterfaceController_PeerState_UNRESPONSIVE;
            SwitchCore_setInterfaceState(&ep->switchIf,
                                         SwitchCore_setInterfaceState_ifaceState_DOWN);
        }

        Log_debug(ic->logger,
                  "Pinging %s peer [%s.k] lag [%u]",
                  (unresponsive ? "unresponsive" : "lazy"),
                  keyIfDebug,
                  (uint32_t)((now - ep->timeOfLastMessage) / 1024));

        sendPing(ep);

        // we only ping one node
        return;
    }
}
Exemple #15
0
static int genconf()
{
    uint8_t passwdBin[16];
    randombytes(passwdBin, 16);
    uint8_t password[32];
    Base32_encode(password, 32, passwdBin, 16);

    uint16_t port;
    randombytes((uint8_t*) &port, 2);
    uint8_t publicKeyBase32[53];
    uint8_t address[40];
    uint8_t privateKeyHex[65];
    genAddress(address, privateKeyHex, publicKeyBase32);

    printf("{\n"
           "    // Private key:\n"
           "    // This key corrisponds to the public key: %s.k\n", publicKeyBase32);
    printf("    // And the ipv6 address: %s\n", address);
    printf("    // Your confidentiality and data integrity depend on this key, keep it secret!\n"
           "    //\n"
           "    \"privateKey\": \"%s\",\n", privateKeyHex);
    printf("\n"
           "    // Anyone connecting and offering these passwords on connection will be allowed.\n"
           "    //\n"
           "    // WARNING: Currently there is no key derivation done on the password field,\n"
           "    //          DO NOT USE A PASSWORD HERE use something which is truly random and\n"
           "    //          cannot be guessed.\n"
           "    // Including a username in the beginning of the password string is encouraged\n"
           "    // to aid in remembering which users are who.\n"
           "    //\n"
           "    \"authorizedPasswords\":\n"
           "    [\n"
           "        {\n"
           "            // A unique string which is known to the client and server.\n"
           "            \"password\": \"%s\",\n", password);
    printf("\n"
           "            // the authentication type, currently only 1 is supported.\n"
           "            \"authType\": 1,\n"
           "\n"
           "            // How much anti-flood trust to give a client\n"
           "            // who connects with this password.\n"
           "            \"trust\": 5000\n"
           "        },\n"
           "\n"
           "        /* These are your connection credentials\n"
           "           for people connecting to you with your default password.\n"
           "           adding more passwords for different users is advisable\n"
           "           so that leaks can be isolated.\n"
           "\n"
           "            \"your.external.ip.goes.here:%u\":\n", port);
    printf("            {\n"
           "                \"password\": \"%s\",\n", password);
    printf("                \"authType\": 1,\n"
           "                \"publicKey\": \"%s.k\",\n", publicKeyBase32);
    printf("                \"trust\": 10000\n"
           "            }\n"
           "        */\n"
           "    ],\n"
           "\n"
           "    // Settings for administering and extracting information from your router.\n"
           "    // This interface provides API functions which can be called through a TCP socket.\n"
           "    \"admin\":\n"
           "    {\n"
           "        // Port to bind the admin TCP server to.\n"
           "        \"bind\": \"127.0.0.1:11234\"\n"
           "    }\n"
           "\n"
           "    // Interfaces to connect to the switch core.\n"
           "    \"interfaces\":\n"
           "    {\n"
           "        // The interface which connects over UDP/IP based VPN tunnel.\n"
           "        \"UDPInterface\":\n"
           "        {\n"
           "            // Bind to this port.\n"
           "            \"bind\": \"0.0.0.0:%u\",\n", port);
    printf("\n"
           "            // Nodes to connect to.\n"
           "            \"connectTo\":\n"
           "            {\n"
           "                // Add connection credentials here to join the network\n"
           "                // Ask somebody who is already connected.\n"
           "            }\n"
           "        }\n"
           "    },\n"
           "\n"
           "    // Configuration for the router.\n"
           "    \"router\":\n"
           "    {\n"
           "        // The interface which is used for connecting to the cjdns network.\n"
           "        \"interface\":\n"
           "        {\n"
           "            // The type of interface (only TUNInterface is supported for now)\n"
           "            \"type\": \"TUNInterface\",\n"
           "\n"
           "            // The name of the TUN device to use.\n"
           "            // This allows you to create a persistent TUN device with the cjdns user\n"
           "            // authorized to use it so that cjdns does not need to run as root.\n"
           "            // If this is commented out, cjdns will try to allocate a TUN on startup.\n"
           "            // If it can't do that (because it's not root?) then it will run as a\n"
           "            // pure router, unable to send or receive traffic.\n"
           "            \"tunDevice\": \"tun0\"\n"
           "        }\n"
           "    },\n"
           "\n"
           "    // Tear down inactive CryptoAuth sessions after this number of seconds\n"
           "    // to make them more forgiving in the event that they become desynchronized.\n"
           "    \"resetAfterInactivitySeconds\": 30,\n"
           "\n"
           "    // Dropping permissions.\n"
           "    \"security\":\n"
           "    [\n"
           "        // Set number of open files to zero, in Linux, this will succeed even if\n"
           "        // files are already open and will not allow any files to be opened for the\n"
           "        // duration of the program's operation.\n"
           "        // Most security exploits require the use of files.\n"
           "        \"nofiles\",\n"
           "\n"
           "        // Change the user id to this user after starting up and getting resources.\n"
           "        {\"setuser\": \"nobody\"}\n"
           "     ],\n"
           "\n"
           "    // Version of the config file, used internally for migration.\n"
           "    \"version\": 1\n"
           "}\n");

    return 0;
}
// Called from the pingInteral timeout.
static void pingCallback(void* vic)
{
    struct Context* ic = Identity_cast((struct Context*) vic);
    uint64_t now = Time_currentTimeMilliseconds(ic->eventBase);
    ic->pingCount++;

    // scan for endpoints have not sent anything recently.
    for (uint32_t i = 0; i < ic->peerMap.count; i++) {
        struct IFCPeer* ep = ic->peerMap.values[i];

        // This is here because of a pathological state where the connection is in ESTABLISHED
        // state but the *direct peer* has somehow been dropped from the routing table.
        // TODO: understand the cause of this issue rather than checking for it once per second.
        struct Node* peerNode = RouterModule_getNode(ep->switchLabel, ic->routerModule);

        if (now > ep->timeOfLastMessage + ic->pingAfterMilliseconds || !peerNode) {
            #ifdef Log_DEBUG
                  uint8_t key[56];
                  Base32_encode(key, 56, CryptoAuth_getHerPublicKey(ep->cryptoAuthIf), 32);
            #endif

            if (ep->isIncomingConnection
                && now > ep->timeOfLastMessage + ic->forgetAfterMilliseconds)
            {
                Log_debug(ic->logger, "Unresponsive peer [%s.k] has not responded in [%u] "
                                      "seconds, dropping connection",
                                      key, ic->forgetAfterMilliseconds / 1024);
                Allocator_free(ep->external->allocator);
                return;
            }

            bool unresponsive = (now > ep->timeOfLastMessage + ic->unresponsiveAfterMilliseconds);
            uint32_t lag = ~0u;
            if (unresponsive) {
                // flush the peer from the table...
                RouterModule_brokenPath(ep->switchLabel, ic->routerModule);

                // Lets skip 87% of pings when they're really down.
                if (ic->pingCount % 8) {
                    continue;
                }

                ep->state = InterfaceController_PeerState_UNRESPONSIVE;
                lag = ((now - ep->timeOfLastMessage) / 1024);
            } else {
                lag = ((now - ep->timeOfLastMessage) / 1024);
            }

            struct SwitchPinger_Ping* ping =
                SwitchPinger_newPing(ep->switchLabel,
                                     String_CONST(""),
                                     ic->timeoutMilliseconds,
                                     onPingResponse,
                                     ic->allocator,
                                     ic->switchPinger);

            if (!ping) {
                Log_debug(ic->logger,
                          "Failed to ping %s peer [%s.k] lag [%u], out of ping slots.",
                          (unresponsive ? "unresponsive" : "lazy"), key, lag);
                return;
            }

            ping->onResponseContext = ep;

            SwitchPinger_sendPing(ping);

            Log_debug(ic->logger,
                      "Pinging %s peer [%s.k] lag [%u]",
                      (unresponsive ? "unresponsive" : "lazy"), key, lag);
        }
    }
}