Browse Source

Merge branch 'socket' of https://github.com/sssemil/cjdns into crashey

Caleb James DeLisle 4 years ago
parent
commit
1b635b862e

+ 48 - 0
admin/angel/Core.c

@@ -33,6 +33,8 @@
 #include "interface/Iface.h"
 #include "util/events/UDPAddrIface.h"
 #include "interface/tuntap/TUNInterface.h"
+#include "interface/tuntap/SocketInterface.h"
+#include "interface/tuntap/SocketWrapper.h"
 #include "interface/tuntap/AndroidWrapper.h"
 #include "interface/UDPInterface_admin.h"
 #ifdef HAS_ETH_INTERFACE
@@ -147,6 +149,26 @@ static void sendResponse(String* error,
     Admin_sendMessage(output, txid, admin);
 }
 
+static void initSocket2(String* socketFullPath,
+                          bool attemptToCreate,
+                          struct Context* ctx,
+                          uint8_t addressPrefix,
+                          struct Except* eh)
+{
+    Log_debug(ctx->logger, "Initializing socket: %s;", socketFullPath->bytes);
+
+    struct Iface* rawSocketIf = SocketInterface_new(
+        socketFullPath->bytes, attemptToCreate, ctx->base, ctx->logger, NULL, ctx->alloc);
+
+    struct SocketWrapper* sw = SocketWrapper_new(ctx->alloc, ctx->logger);
+    Iface_plumb(&sw->externalIf, rawSocketIf);
+    Iface_plumb(&sw->internalIf, &ctx->nc->tunAdapt->tunIf);
+
+    SocketWrapper_addAddress(&sw->externalIf, ctx->nc->myAddress->ip6.bytes, ctx->logger,
+                                eh, ctx->alloc);
+    SocketWrapper_setMTU(&sw->externalIf, DEFAULT_MTU, ctx->logger, eh, ctx->alloc);
+}
+
 static void initTunnel2(String* desiredDeviceName,
                         struct Context* ctx,
                         uint8_t addressPrefix,
@@ -221,6 +243,26 @@ static void initTunnel(Dict* args, void* vcontext, String* txid, struct Allocato
     sendResponse(String_CONST("none"), ctx->admin, txid, requestAlloc);
 }
 
+static void initSocket(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc)
+{
+    struct Context* const ctx = Identity_check((struct Context*) vcontext);
+
+    struct Jmp jmp;
+    Jmp_try(jmp) {
+        String* socketFullPath = Dict_getStringC(args, "socketFullPath");
+        bool socketAttemptToCreate = *Dict_getIntC(args, "socketAttemptToCreate");
+        initSocket2(socketFullPath, socketAttemptToCreate, ctx, AddressCalc_ADDRESS_PREFIX_BITS,
+            &jmp.handler);
+    } Jmp_catch {
+        String* error = String_printf(requestAlloc, "Failed to configure socket [%s]",
+            jmp.message);
+        sendResponse(error, ctx->admin, txid, requestAlloc);
+        return;
+    }
+
+    sendResponse(String_CONST("none"), ctx->admin, txid, requestAlloc);
+}
+
 static void nodeInfo(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc)
 {
     struct Context* const ctx = Identity_check((struct Context*) vcontext);
@@ -330,6 +372,12 @@ void Core_init(struct Allocator* alloc,
         }), admin);
 
     Admin_registerFunction("Core_nodeInfo", nodeInfo, ctx, false, NULL, admin);
+
+    Admin_registerFunction("Core_initSocket", initSocket, ctx, true,
+        ((struct Admin_FunctionArg[]) {
+            { .name = "socketFullPath", .required = 1, .type = "String" },
+            { .name = "socketAttemptToCreate", .required = 1, .type = "Int" }
+        }), admin);
 }
 
 int Core_main(int argc, char** argv)

+ 31 - 0
client/Configurator.c

@@ -327,6 +327,36 @@ static void tunInterface(Dict* ifaceConf, struct Allocator* tempAlloc, struct Co
     }
 }
 
+static void socketInterface(Dict* ifaceConf, struct Allocator* tempAlloc, struct Context* ctx)
+{
+    String* ifaceType = Dict_getStringC(ifaceConf, "type");
+    if (!String_equals(ifaceType, String_CONST("SocketInterface"))) {
+        return;
+    }
+
+    // Setup the interface.
+    String* socketFullPath = Dict_getStringC(ifaceConf, "socketFullPath");
+
+    Dict* args = Dict_new(tempAlloc);
+    if (!socketFullPath) {
+        Log_critical(ctx->logger, "In router.interface"
+                                  " 'socketFullPath' is required if it's SocketInterface.");
+        exit(1);
+    }
+
+    // false by default
+    int64_t attemptToCreate = 0;
+
+    int64_t* socketAttemptToCreate = Dict_getIntC(ifaceConf, "socketAttemptToCreate");
+    if (socketAttemptToCreate && *socketAttemptToCreate) {
+        attemptToCreate = 1;
+    }
+
+    Dict_putStringC(args, "socketFullPath", socketFullPath, tempAlloc);
+    Dict_putIntC(args, "socketAttemptToCreate", attemptToCreate, tempAlloc);
+    rpcCall0(String_CONST("Core_initSocket"), args, ctx, tempAlloc, NULL, true);
+}
+
 static void ipTunnel(Dict* ifaceConf, struct Allocator* tempAlloc, struct Context* ctx)
 {
     List* incoming = Dict_getListC(ifaceConf, "allowedConnections");
@@ -411,6 +441,7 @@ static void supernodes(List* supernodes, struct Allocator* tempAlloc, struct Con
 static void routerConfig(Dict* routerConf, struct Allocator* tempAlloc, struct Context* ctx)
 {
     tunInterface(Dict_getDictC(routerConf, "interface"), tempAlloc, ctx);
+    socketInterface(Dict_getDictC(routerConf, "interface"), tempAlloc, ctx);
     ipTunnel(Dict_getDictC(routerConf, "ipTunnel"), tempAlloc, ctx);
     supernodes(Dict_getListC(routerConf, "supernodes"), tempAlloc, ctx);
 }

+ 33 - 0
interface/tuntap/SocketInterface.c

@@ -0,0 +1,33 @@
+/* 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/tuntap/SocketInterface.h"
+#include "exception/Except.h"
+#include "memory/Allocator.h"
+#include "util/events/EventBase.h"
+#include "util/events/Pipe.h"
+
+struct Iface* SocketInterface_new(const char* socketFullPath,
+                                    bool attemptToCreate,
+                                    struct EventBase* base,
+                                    struct Log* logger,
+                                    struct Except* eh,
+                                    struct Allocator* alloc)
+{
+    Log_info(logger, "Initializing socket: %s;", socketFullPath);
+
+    struct Pipe* p = Pipe_namedConnect(socketFullPath, attemptToCreate, base, eh, alloc);
+
+    return &p->iface;
+}

+ 43 - 0
interface/tuntap/SocketInterface.h

@@ -0,0 +1,43 @@
+/* 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 SocketInterface_H
+#define SocketInterface_H
+
+#include "util/events/EventBase.h"
+#include "util/log/Log.h"
+#include "exception/Except.h"
+#include "memory/Allocator.h"
+#include "util/Linker.h"
+Linker_require("interface/tuntap/SocketInterface.c");
+
+#include <stdbool.h>
+
+/**
+ * Create a new SocketInterface.
+ *
+ * @param socketFullPath full path to the socket file.
+ * @param base the libevent event base to use for listening for incoming packet events.
+ * @param logger for logging messages about the tun device.
+ * @param eh if this function fails, it will raise one an error.
+ * @param allocator a means of getting memory.
+ * @return a Interface.
+ */
+struct Iface* SocketInterface_new(const char* socketFullPath,
+                                    bool attemptToCreate,
+                                    struct EventBase* base,
+                                    struct Log* logger,
+                                    struct Except* eh,
+                                    struct Allocator* alloc);
+#endif

+ 113 - 0
interface/tuntap/SocketWrapper.c

@@ -0,0 +1,113 @@
+/* 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/tuntap/SocketWrapper.h"
+#include "util/platform/Sockaddr.h"
+#include "memory/Allocator.h"
+#include "util/Assert.h"
+#include "util/Identity.h"
+#include "wire/Ethernet.h"
+#include "wire/Headers.h"
+#include "wire/Message.h"
+#include "wire/Error.h"
+
+struct SocketWrapper_pvt
+{
+    struct SocketWrapper pub;
+    struct Log* logger;
+    Identity
+};
+
+static Iface_DEFUN incomingFromSocket(struct Message* msg, struct Iface* externalIf)
+{
+    struct SocketWrapper_pvt* ctx =
+        Identity_containerOf(externalIf, struct SocketWrapper_pvt, pub.externalIf);
+
+    if (!ctx->pub.internalIf.connectedIf) {
+        Log_debug(ctx->logger, "DROP message for socket not inited");
+        return NULL;
+    }
+
+    // get ess packet type
+    uint8_t type = Message_pop8(msg, NULL);
+    Log_debug(ctx->logger, "Packet type [%d]", type);
+
+    if (type == SocketWrapper_TYPE_TUN_PACKET) {
+        // skip tun packet length
+        Message_pop32(msg, NULL);
+        return Iface_next(&ctx->pub.internalIf, msg);
+    }
+
+    // skip all other types
+    return NULL;
+}
+
+static Iface_DEFUN incomingFromUs(struct Message* msg, struct Iface* internalIf)
+{
+    struct SocketWrapper_pvt* ctx =
+        Identity_containerOf(internalIf, struct SocketWrapper_pvt, pub.internalIf);
+
+    if (!ctx->pub.externalIf.connectedIf) {
+        Log_debug(ctx->logger, "DROP message for socket not inited");
+        return NULL;
+    }
+
+    // send payload length
+    Message_push32(msg, msg->length, NULL);
+    // mark this as a normal tun packet
+    Message_push8(msg, SocketWrapper_TYPE_TUN_PACKET, NULL);
+
+    return Iface_next(&ctx->pub.externalIf, msg);
+}
+
+struct SocketWrapper* SocketWrapper_new(struct Allocator* alloc, struct Log* log)
+{
+    struct SocketWrapper_pvt* context =
+        Allocator_calloc(alloc, sizeof(struct SocketWrapper_pvt), 1);
+    Identity_set(context);
+    context->pub.externalIf.send = incomingFromSocket;
+    context->pub.internalIf.send = incomingFromUs;
+    context->logger = log;
+
+    return &context->pub;
+}
+
+void SocketWrapper_addAddress(struct Iface* rawSocketIf,
+                                uint8_t* ipv6Addr,
+                                struct Log* logger,
+                                struct Except* eh,
+                                struct Allocator* alloc)
+{
+    size_t len = 16 /* IPv6 Address length */ + 1 /* Type prefix length */;
+    struct Message* out = Message_new(0, len, alloc);
+    Message_push(out, ipv6Addr, 16, eh);
+    Message_push8(out, SocketWrapper_TYPE_CONF_ADD_IPV6_ADDRESS, eh);
+
+    Iface_send(rawSocketIf, out);
+}
+
+void SocketWrapper_setMTU(struct Iface* rawSocketIf,
+                            uint32_t mtu,
+                            struct Log* logger,
+                            struct Except* eh,
+                            struct Allocator* alloc)
+{
+    size_t len = 4 /* MTU var size */ + 1 /* Type prefix length */;
+    struct Message* out = Message_new(0, len, alloc);
+    Message_push32(out, mtu, eh);
+    Message_push8(out, SocketWrapper_TYPE_CONF_SET_MTU, eh);
+
+    Iface_send(rawSocketIf, out);
+}

+ 47 - 0
interface/tuntap/SocketWrapper.h

@@ -0,0 +1,47 @@
+/* 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 SocketWrapper_H
+#define SocketWrapper_H
+
+#define SocketWrapper_TYPE_TUN_PACKET 0x0
+#define SocketWrapper_TYPE_CONF_ADD_IPV6_ADDRESS 0x1
+#define SocketWrapper_TYPE_CONF_SET_MTU 0x2
+
+#include "interface/Iface.h"
+#include "memory/Allocator.h"
+#include "util/log/Log.h"
+#include "util/Linker.h"
+Linker_require("interface/tuntap/SocketWrapper.c");
+
+struct SocketWrapper
+{
+    struct Iface internalIf;
+    struct Iface externalIf;
+};
+
+struct SocketWrapper* SocketWrapper_new(struct Allocator* alloc, struct Log* log);
+
+void SocketWrapper_addAddress(struct Iface* rawSocketIf,
+                                uint8_t* ipv6Addr,
+                                struct Log* logger,
+                                struct Except* eh,
+                                struct Allocator* alloc);
+
+void SocketWrapper_setMTU(struct Iface* rawSocketIf,
+                            uint32_t mtu,
+                            struct Log* logger,
+                            struct Except* eh,
+                            struct Allocator* alloc);
+#endif

+ 8 - 0
util/events/Pipe.h

@@ -22,6 +22,8 @@
 #include "util/Linker.h"
 Linker_require("util/events/libuv/Pipe.c");
 
+#include <stdbool.h>
+
 struct Pipe;
 typedef void (* Pipe_callback)(struct Pipe* p, int status);
 
@@ -67,6 +69,12 @@ struct Pipe* Pipe_named(const char* path,
                         struct Except* eh,
                         struct Allocator* userAlloc);
 
+struct Pipe* Pipe_namedConnect(const char* fullPath,
+                               bool attemptToCreate,
+                               struct EventBase* eb,
+                               struct Except* eh,
+                               struct Allocator* userAlloc);
+
 struct Pipe* Pipe_forFiles(int inFd,
                            int outFd,
                            struct EventBase* eb,

+ 90 - 0
util/events/libuv/Pipe.c

@@ -21,8 +21,10 @@
 #include "util/CString.h"
 #include "wire/Message.h"
 #include "wire/Error.h"
+#include "benc/String.h"
 
 #include <inttypes.h>
+#include <libgen.h>
 #include <stdio.h>
 
 struct Pipe_WriteRequest_pvt;
@@ -392,6 +394,60 @@ static struct Pipe_pvt* newPipe(struct EventBase* eb,
     return out;
 }
 
+static struct Pipe_pvt* newPipeAny(struct EventBase* eb,
+                                  const char* fullPath,
+                                  struct Except* eh,
+                                  struct Allocator* userAlloc)
+{
+    struct EventBase_pvt* ctx = EventBase_privatize(eb);
+    struct Allocator* alloc = Allocator_child(userAlloc);
+
+    char* name = NULL;
+    if (fullPath) {
+        name = basename(String_new(fullPath, alloc)->bytes);
+    }
+
+    struct Pipe_pvt* out = Allocator_clone(alloc, (&(struct Pipe_pvt) {
+        .pub = {
+            .iface = {
+                .send = sendMessage
+            },
+            .fullName = fullPath,
+            .name = name,
+            .base = eb
+        },
+        .alloc = alloc
+    }));
+
+    int ret;
+
+    ret = uv_pipe_init(ctx->loop, &out->peer, 0);
+    if (ret) {
+        Except_throw(eh, "uv_pipe_init() failed [%s]", uv_strerror(ret));
+    }
+
+    ret = uv_pipe_init(ctx->loop, &out->server, 0);
+    if (ret) {
+        Except_throw(eh, "uv_pipe_init() failed [%s]", uv_strerror(ret));
+    }
+
+    #ifdef win32
+        out->pub.fd = &out->peer.handle;
+    #else
+        out->pub.fd = &out->peer.io_watcher.fd;
+    #endif
+
+    Allocator_onFree(alloc, closeHandlesOnFree, out);
+    Allocator_onFree(alloc, blockFreeInsideCallback, out);
+
+    out->peer.data = out;
+    out->server.data = out;
+    out->out = &out->peer;
+    Identity_set(out);
+
+    return out;
+}
+
 struct Pipe* Pipe_forFiles(int inFd,
                            int outFd,
                            struct EventBase* eb,
@@ -457,3 +513,37 @@ struct Pipe* Pipe_named(const char* path,
 
     return &out->pub;
 }
+
+struct Pipe* Pipe_namedConnect(const char* fullPath,
+                               bool attemptToCreate,
+                               struct EventBase* eb,
+                               struct Except* eh,
+                               struct Allocator* userAlloc)
+{
+    struct Pipe_pvt* out = newPipeAny(eb, fullPath, eh, userAlloc);
+
+    if (attemptToCreate) {
+        // Attempt to create pipe.
+        int ret = uv_pipe_bind(&out->server, out->pub.fullName);
+        if (!ret) {
+            ret = uv_listen((uv_stream_t*) &out->server, 1, listenCallback);
+            if (ret) {
+                Except_throw(eh, "uv_listen() failed [%s] for pipe [%s]",
+                             uv_strerror(ret), out->pub.fullName);
+            }
+            return &out->pub;
+        }
+    }
+
+    uv_connect_t* req = Allocator_malloc(out->alloc, sizeof(uv_connect_t));
+    req->data = out;
+    uv_pipe_connect(req, &out->peer, out->pub.fullName, connected);
+
+    int err = (&out->peer)->delayed_error;
+    if (err != 0) {
+        Except_throw(eh, "uv_pipe_connect() failed [%s] for pipe [%s]",
+                     uv_strerror(err), out->pub.fullName);
+    }
+
+    return &out->pub;
+}