Allow linking with multiple device drivers.
authorGuus Sliepen <guus@tinc-vpn.org>
Sun, 4 Dec 2011 00:20:59 +0000 (01:20 +0100)
committerGuus Sliepen <guus@tinc-vpn.org>
Sun, 4 Dec 2011 00:20:59 +0000 (01:20 +0100)
Apart from the platform specific tun/tap driver, link with the dummy and
raw_socket devices, and optionally with support for UML and VDE devices.
At runtime, the DeviceType option can be used to select which driver to
use.

23 files changed:
configure.in
doc/tinc.conf.5.in
doc/tinc.texi
src/Makefile.am
src/bsd/device.c
src/cygwin/device.c
src/device.h
src/dummy/device.c [deleted file]
src/dummy_device.c [new file with mode: 0644]
src/linux/device.c
src/mingw/device.c
src/net.c
src/net_packet.c
src/net_setup.c
src/process.c
src/raw_socket/device.c [deleted file]
src/raw_socket_device.c [new file with mode: 0644]
src/solaris/device.c
src/tincd.c
src/uml_device.c [new file with mode: 0644]
src/uml_socket/device.c [deleted file]
src/vde/device.c [deleted file]
src/vde_device.c [new file with mode: 0644]

index 65b5c4c189e63c1af2b726d4180baedab81ad322..c8cc203129b03e51c9dd8d48682211066f47b503 100644 (file)
@@ -72,6 +72,21 @@ case $host_os in
   ;;
 esac
 
+AC_ARG_ENABLE(uml,
+  AS_HELP_STRING([--enable-uml], [enable support for User Mode Linux]),
+  [ AC_DEFINE(ENABLE_UML, 1, [Support for UML])
+    uml=true
+  ]
+)
+
+AC_ARG_ENABLE(vde,
+  AS_HELP_STRING([--enable-vde], [enable support for Virtual Distributed Ethernet]),
+  [ AC_CHECK_HEADERS(libvdeplug_dyn.h, [], [AC_MSG_ERROR([VDE plug header files not found.]); break])
+    AC_DEFINE(ENABLE_VDE, 1, [Support for VDE])
+    vde=true
+  ]
+)
+
 AC_ARG_ENABLE(tunemu,
   AS_HELP_STRING([--enable-tunemu], [enable support for the tunemu driver]),
   [ AC_DEFINE(ENABLE_TUNEMU, 1, [Support for tunemu])
@@ -84,6 +99,8 @@ AC_ARG_WITH(windows2000,
   [AC_DEFINE(WITH_WINDOWS2000, 1, [Compile with support for Windows 2000])]
 )
 
+AM_CONDITIONAL(UML, test "$uml" = true)
+AM_CONDITIONAL(VDE, test "$vde" = true)
 AM_CONDITIONAL(TUNEMU, test "$tunemu" = true)
 
 AC_CACHE_SAVE
index ce690308c05bec244d655b30e624ae47312a2a6a..dd74acfaf04efb59f7050c5f679a5aab4bef65cb 100644 (file)
@@ -177,30 +177,65 @@ instead of
 The info pages of the tinc package contain more information
 about configuring the virtual network device.
 
-.It Va DeviceType Li = tun | tunnohead | tunifhead | tap Po only supported on BSD platforms Pc
+.It Va DeviceType Li = Ar type Pq platform dependent
 The type of the virtual network device.
-Tinc will normally automatically select the right type, and this option should not be used.
-However, in case tinc does not seem to correctly interpret packets received from the virtual network device,
-using this option might help.
+Tinc will normally automatically select the right type of tun/tap interface, and this option should not be used.
+However, this option can be used to select one of the special interface types, if support for them is compiled in.
 .Bl -tag -width indent
 
-.It tun
+.It dummy
+Use a dummy interface.
+No packets are ever read or written to a virtual network device.
+Useful for testing, or when setting up a node that only forwards packets for other nodes.
+
+.It raw_socket
+Open a raw socket, and bind it to a pre-existing
+.Va Interface
+(eth0 by default).
+All packets are read from this interface.
+Packets received for the local node are written to the raw socket.
+However, at least on Linux, the operating system does not process IP packets destined for the local host.
+
+.It uml Pq not compiled in by default
+Create a UNIX socket with the filename specified by
+.Va Device ,
+or
+.Pa @localstatedir@/run/ Ns Ar NETNAME Ns Pa .umlsocket
+if not specified.
+.Nm tinc
+will wait for a User Mode Linux instance to connect to this socket.
+
+.It vde Pq not compiled in by default
+Uses the libvdeplug library to connect to a Virtual Distributed Ethernet switch,
+using the UNIX socket specified by
+.Va Device ,
+or
+.Pa @localstatedir@/run/vde.ctl
+if not specified.
+.El
+
+Also, in case tinc does not seem to correctly interpret packets received from the virtual network device,
+it can be used to change the way packets are interpreted:
+
+.Bl -tag -width indent
+
+.It tun Pq BSD only
 Set type to tun.
 Depending on the platform, this can either be with or without an address family header (see below).
 
-.It tunnohead
+.It tunnohead Pq BSD only
 Set type to tun without an address family header.
 Tinc will expect packets read from the virtual network device to start with an IP header.
 On some platforms IPv6 packets cannot be read from or written to the device in this mode.
 
-.It tunifhead
+.It tunifhead Pq BSD only
 Set type to tun with an address family header.
 Tinc will expect packets read from the virtual network device
 to start with a four byte header containing the address family,
 followed by an IP header.
 This mode should support both IPv4 and IPv6 packets.
 
-.It tap
+.It tap Pq BSD only
 Set type to tap.
 Tinc will expect packets read from the virtual network device
 to start with an Ethernet header.
index 52a0eccfccbd4002cde4dd2d7ad6ef37af7837dd..b7d646d58e01941acf716ce04b74ee3bb215c926 100644 (file)
@@ -794,32 +794,64 @@ Note that you can only use one device per daemon.
 See also @ref{Device files}.
 
 @cindex DeviceType
-@item DeviceType = <tun|tunnohead|tunifhead|tap> (only supported on BSD platforms)
+@item DeviceType = <@var{type}> (platform dependent)
 The type of the virtual network device.
-Tinc will normally automatically select the right type, and this option should not be used.
-However, in case tinc does not seem to correctly interpret packets received from the virtual network device,
-using this option might help.
+Tinc will normally automatically select the right type of tun/tap interface, and this option should not be used.
+However, this option can be used to select one of the special interface types, if support for them is compiled in.
 
 @table @asis
-@item tun
+@cindex dummy
+@item dummy
+Use a dummy interface.
+No packets are ever read or written to a virtual network device.
+Useful for testing, or when setting up a node that only forwards packets for other nodes.
+
+@cindex raw_socket
+@item raw_socket
+Open a raw socket, and bind it to a pre-existing
+@var{Interface} (eth0 by default).
+All packets are read from this interface.
+Packets received for the local node are written to the raw socket.
+However, at least on Linux, the operating system does not process IP packets destined for the local host.
+
+@cindex UML
+@item uml (not compiled in by default)
+Create a UNIX socket with the filename specified by
+@var{Device}, or @file{@value{localstatedir}/run/@var{netname}.umlsocket}
+if not specified.
+Tinc will wait for a User Mode Linux instance to connect to this socket.
+
+@cindex VDE
+@item vde (not compiled in by default)
+Uses the libvdeplug library to connect to a Virtual Distributed Ethernet switch,
+using the UNIX socket specified by
+@var{Device}, or @file{@value{localstatedir}/run/vde.ctl}
+if not specified.
+@end table
+
+Also, in case tinc does not seem to correctly interpret packets received from the virtual network device,
+it can be used to change the way packets are interpreted:
+
+@table @asis
+@item tun (BSD only)
 Set type to tun.
 Depending on the platform, this can either be with or without an address family header (see below).
 
 @cindex tunnohead
-@item tunnohead
+@item tunnohead (BSD only)
 Set type to tun without an address family header.
 Tinc will expect packets read from the virtual network device to start with an IP header.
 On some platforms IPv6 packets cannot be read from or written to the device in this mode.
 
 @cindex tunifhead
-@item tunifhead
+@item tunifhead (BSD only)
 Set type to tun with an address family header.
 Tinc will expect packets read from the virtual network device
 to start with a four byte header containing the address family,
 followed by an IP header.
 This mode should support both IPv4 and IPv6 packets.
 
-@item tap
+@item tap (BSD only)
 Set type to tap.
 Tinc will expect packets read from the virtual network device
 to start with an Ethernet header.
index a9e116d30d8ef9bca32dfaea1dbc1343d8f227b0..aca0e2dca3d39539fcfe8343a61764888d696a63 100644 (file)
@@ -2,11 +2,20 @@
 
 sbin_PROGRAMS = tincd
 
-EXTRA_DIST = linux/device.c bsd/device.c solaris/device.c cygwin/device.c mingw/device.c mingw/common.h raw_socket/device.c uml_socket/device.c vde/device.c
+EXTRA_DIST = linux/device.c bsd/device.c solaris/device.c cygwin/device.c mingw/device.c mingw/common.h
 
 tincd_SOURCES = conf.c connection.c edge.c event.c graph.c logger.c meta.c net.c net_packet.c net_setup.c      \
        net_socket.c netutl.c node.c process.c protocol.c protocol_auth.c protocol_edge.c protocol_misc.c       \
-       protocol_key.c protocol_subnet.c route.c subnet.c tincd.c
+       protocol_key.c protocol_subnet.c route.c subnet.c tincd.c \
+       dummy_device.c raw_socket_device.c
+       
+if UML
+tincd_SOURCES += uml_device.c
+endif
+
+if VDE
+tincd_SOURCES += vde_device.c
+endif
 
 if TUNEMU
 tincd_SOURCES += bsd/tunemu.c
index a41827ff25bb265857cff5f58811d31e83db4130..f1d3f9f470311137cb3de6059511ca4b6037cca5 100644 (file)
@@ -58,7 +58,7 @@ static device_type_t device_type = DEVICE_TYPE_TUNIFHEAD;
 static device_type_t device_type = DEVICE_TYPE_TUN;
 #endif
 
-bool setup_device(void) {
+static bool setup_device(void) {
        char *type;
 
        if(!get_config_string(lookup_config(config_tree, "Device"), &device))
@@ -175,7 +175,7 @@ bool setup_device(void) {
        return true;
 }
 
-void close_device(void) {
+static void close_device(void) {
        switch(device_type) {
 #ifdef HAVE_TUNEMU
                case DEVICE_TYPE_TUNEMU:
@@ -190,7 +190,7 @@ void close_device(void) {
        free(iface);
 }
 
-bool read_packet(vpn_packet_t *packet) {
+static bool read_packet(vpn_packet_t *packet) {
        int lenin;
 
        switch(device_type) {
@@ -282,7 +282,7 @@ bool read_packet(vpn_packet_t *packet) {
        return true;
 }
 
-bool write_packet(vpn_packet_t *packet) {
+static bool write_packet(vpn_packet_t *packet) {
        ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
                           packet->len, device_info);
 
@@ -351,8 +351,16 @@ bool write_packet(vpn_packet_t *packet) {
        return true;
 }
 
-void dump_device_stats(void) {
+static void dump_device_stats(void) {
        logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
        logger(LOG_DEBUG, " total bytes in:  %10"PRIu64, device_total_in);
        logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
 }
+
+const devops_t os_devops = {
+       .setup = setup_device,
+       .close = close_device,
+       .read = read_packet,
+       .write = write_packet,
+       .dump_stats = dump_device_stats,
+};
index 42016cb5a6e5e85fdd37bb26e6574fcaa2203a0b..4365399df44dcc3a0e7f85e9ec24ce93687dfed0 100644 (file)
@@ -1,7 +1,7 @@
 /*
     device.c -- Interaction with Windows tap driver in a Cygwin environment
     Copyright (C) 2002-2005 Ivo Timmermans,
-                  2002-2009 Guus Sliepen <guus@tinc-vpn.org>
+                  2002-2011 Guus Sliepen <guus@tinc-vpn.org>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -45,7 +45,7 @@ static uint64_t device_total_out = 0;
 static pid_t reader_pid;
 static int sp[2];
 
-bool setup_device(void) {
+static bool setup_device(void) {
        HKEY key, key2;
        int i, err;
 
@@ -214,7 +214,7 @@ bool setup_device(void) {
        return true;
 }
 
-void close_device(void) {
+static void close_device(void) {
        close(sp[0]);
        close(sp[1]);
        CloseHandle(device_handle);
@@ -225,7 +225,7 @@ void close_device(void) {
        free(iface);
 }
 
-bool read_packet(vpn_packet_t *packet) {
+static bool read_packet(vpn_packet_t *packet) {
        int lenin;
 
        if((lenin = read(sp[0], packet->data, MTU)) <= 0) {
@@ -244,7 +244,7 @@ bool read_packet(vpn_packet_t *packet) {
        return true;
 }
 
-bool write_packet(vpn_packet_t *packet) {
+static bool write_packet(vpn_packet_t *packet) {
        long lenout;
 
        ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
@@ -260,8 +260,16 @@ bool write_packet(vpn_packet_t *packet) {
        return true;
 }
 
-void dump_device_stats(void) {
+static void dump_device_stats(void) {
        logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
        logger(LOG_DEBUG, " total bytes in:  %10"PRIu64, device_total_in);
        logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
 }
+
+const devops_t os_devops = {
+       .setup = setup_device,
+       .close = close_device,
+       .read = read_packet,
+       .write = write_packet,
+       .dump_stats = dump_device_stats,
+};
index 5841253a088fe85f4de65c024396f37467f269bb..eaeca1883fcfb90b4cc289cec854627b9ec530e4 100644 (file)
@@ -1,7 +1,7 @@
 /*
-    net.h -- generic header for device.c
+    device.h -- generic header for device.c
     Copyright (C) 2001-2005 Ivo Timmermans
-                  2001-2006 Guus Sliepen <guus@tinc-vpn.org>
+                  2001-2011 Guus Sliepen <guus@tinc-vpn.org>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -28,10 +28,19 @@ extern char *device;
 
 extern char *iface;
 
-extern bool setup_device(void);
-extern void close_device(void);
-extern bool read_packet(struct vpn_packet_t *);
-extern bool write_packet(struct vpn_packet_t *);
-extern void dump_device_stats(void);
+typedef struct devops_t {
+       bool (*setup)(void);
+       void (*close)(void);
+       bool (*read)(struct vpn_packet_t *);
+       bool (*write)(struct vpn_packet_t *);
+       void (*dump_stats)(void);
+} devops_t;
+
+extern const devops_t os_devops;
+extern const devops_t dummy_devops;
+extern const devops_t raw_socket_devops;
+extern const devops_t uml_devops;
+extern const devops_t vde_devops;
+extern devops_t devops;
 
 #endif                                                 /* __TINC_DEVICE_H__ */
diff --git a/src/dummy/device.c b/src/dummy/device.c
deleted file mode 100644 (file)
index 25a38f2..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
-    device.c -- Dummy device
-    Copyright (C) 2009 Guus Sliepen <guus@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 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, write to the Free Software Foundation, Inc.,
-    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-*/
-
-#include "system.h"
-
-#include "device.h"
-#include "logger.h"
-#include "net.h"
-
-int device_fd = -1;
-char *device = "dummy";
-char *iface = "dummy";
-static char *device_info = "dummy device";
-
-static uint64_t device_total_in = 0;
-static uint64_t device_total_out = 0;
-
-bool setup_device(void) {
-       logger(LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
-       return true;
-}
-
-void close_device(void) {
-}
-
-bool read_packet(vpn_packet_t *packet) {
-       return false;
-}
-
-bool write_packet(vpn_packet_t *packet) {
-       device_total_out += packet->len;
-       return true;
-}
-
-void dump_device_stats(void) {
-       logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
-       logger(LOG_DEBUG, " total bytes in:  %10"PRIu64, device_total_in);
-       logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
-}
diff --git a/src/dummy_device.c b/src/dummy_device.c
new file mode 100644 (file)
index 0000000..9dd3fae
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+    device.c -- Dummy device
+    Copyright (C) 2011 Guus Sliepen <guus@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 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, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "system.h"
+
+#include "device.h"
+#include "logger.h"
+#include "net.h"
+
+static char *device_info = "dummy device";
+
+static uint64_t device_total_in = 0;
+static uint64_t device_total_out = 0;
+
+static bool setup_device(void) {
+       device = "dummy";
+       iface = "dummy";
+       logger(LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
+       return true;
+}
+
+static void close_device(void) {
+}
+
+static bool read_packet(vpn_packet_t *packet) {
+       return false;
+}
+
+static bool write_packet(vpn_packet_t *packet) {
+       device_total_out += packet->len;
+       return true;
+}
+
+static void dump_device_stats(void) {
+       logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
+       logger(LOG_DEBUG, " total bytes in:  %10"PRIu64, device_total_in);
+       logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
+}
+
+const devops_t dummy_devops = {
+       .setup = setup_device,
+       .close = close_device,
+       .read = read_packet,
+       .write = write_packet,
+       .dump_stats = dump_device_stats,
+};
index c7c1b65c67e86b38a5259cd2b18b1173ddba2d23..c06e7b93940b29812a7feb3a101e3e77e995dcf0 100644 (file)
@@ -1,7 +1,7 @@
 /*
     device.c -- Interaction with Linux ethertap and tun/tap device
     Copyright (C) 2001-2005 Ivo Timmermans,
-                  2001-2009 Guus Sliepen <guus@tinc-vpn.org>
+                  2001-2011 Guus Sliepen <guus@tinc-vpn.org>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -51,7 +51,7 @@ static char *device_info;
 static uint64_t device_total_in = 0;
 static uint64_t device_total_out = 0;
 
-bool setup_device(void) {
+static bool setup_device(void) {
        struct ifreq ifr;
        bool t1q = false;
 
@@ -121,14 +121,14 @@ bool setup_device(void) {
        return true;
 }
 
-void close_device(void) {
+static void close_device(void) {
        close(device_fd);
 
        free(device);
        free(iface);
 }
 
-bool read_packet(vpn_packet_t *packet) {
+static bool read_packet(vpn_packet_t *packet) {
        int lenin;
        
        switch(device_type) {
@@ -175,7 +175,7 @@ bool read_packet(vpn_packet_t *packet) {
        return true;
 }
 
-bool write_packet(vpn_packet_t *packet) {
+static bool write_packet(vpn_packet_t *packet) {
        ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
                           packet->len, device_info);
 
@@ -211,8 +211,16 @@ bool write_packet(vpn_packet_t *packet) {
        return true;
 }
 
-void dump_device_stats(void) {
+static void dump_device_stats(void) {
        logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
        logger(LOG_DEBUG, " total bytes in:  %10"PRIu64, device_total_in);
        logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
 }
+
+const devops_t os_devops = {
+       .setup = setup_device,
+       .close = close_device,
+       .read = read_packet,
+       .write = write_packet,
+       .dump_stats = dump_device_stats,
+};
index 1dac3bfa99450acf09913b51b0162b96c33c3781..b9588318f15ad894d3cb2d2da193c75c16dbd7f4 100644 (file)
@@ -83,7 +83,7 @@ static DWORD WINAPI tapreader(void *bla) {
        }
 }
 
-bool setup_device(void) {
+static bool setup_device(void) {
        HKEY key, key2;
        int i;
 
@@ -210,18 +210,18 @@ bool setup_device(void) {
        return true;
 }
 
-void close_device(void) {
+static void close_device(void) {
        CloseHandle(device_handle);
 
        free(device);
        free(iface);
 }
 
-bool read_packet(vpn_packet_t *packet) {
+static bool read_packet(vpn_packet_t *packet) {
        return false;
 }
 
-bool write_packet(vpn_packet_t *packet) {
+static bool write_packet(vpn_packet_t *packet) {
        long lenout;
        OVERLAPPED overlapped = {0};
 
@@ -238,8 +238,16 @@ bool write_packet(vpn_packet_t *packet) {
        return true;
 }
 
-void dump_device_stats(void) {
+static void dump_device_stats(void) {
        logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
        logger(LOG_DEBUG, " total bytes in:  %10"PRIu64, device_total_in);
        logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
 }
+
+const devops_t os_devops = {
+       .setup = setup_device,
+       .close = close_device,
+       .read = read_packet,
+       .write = write_packet,
+       .dump_stats = dump_device_stats,
+};
index 8762db3841912c5395dfdbe68a8c1d9710cf1512..ea4bbcfce218c5e9d1b2fd3908eb4d0ccb2a6e67 100644 (file)
--- a/src/net.c
+++ b/src/net.c
@@ -289,7 +289,7 @@ static void check_network_activity(fd_set * readset, fd_set * writeset) {
 
        /* check input from kernel */
        if(device_fd >= 0 && FD_ISSET(device_fd, readset)) {
-               if(read_packet(&packet)) {
+               if(devops.read(&packet)) {
                        errors = 0;
                        packet.priority = 0;
                        route(myself, &packet);
index fe20a2581283f3d460cd5e0caa626806b63fbe9e..54deb26c70ab66c1a2e755225ba4f053a93ce733 100644 (file)
@@ -518,7 +518,7 @@ void send_packet(const node_t *n, vpn_packet_t *packet) {
        if(n == myself) {
                if(overwrite_mac)
                         memcpy(packet->data, mymac.x, ETH_ALEN);
-               write_packet(packet);
+               devops.write(packet);
                return;
        }
 
index a11f0060705158dbe7f048e8b185989abf51fada..9cf24bf8cb42f165499168b1d95c04fc7616ca26 100644 (file)
@@ -1,7 +1,7 @@
 /*
     net_setup.c -- Setup.
     Copyright (C) 1998-2005 Ivo Timmermans,
-                  2000-2010 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2011 Guus Sliepen <guus@tinc-vpn.org>
                   2006      Scott Lamb <slamb@slamb.org>
                   2010      Brandon Black <blblack@gmail.com>
 
@@ -45,6 +45,7 @@
 #include "xalloc.h"
 
 char *myport;
+devops_t devops;
 
 bool read_rsa_public_key(connection_t *c) {
        FILE *fp;
@@ -276,7 +277,7 @@ void load_all_subnets(void) {
 static bool setup_myself(void) {
        config_t *cfg;
        subnet_t *subnet;
-       char *name, *hostname, *mode, *afname, *cipher, *digest;
+       char *name, *hostname, *mode, *afname, *cipher, *digest, *type;
        char *fname = NULL;
        char *address = NULL;
        char *envp[5];
@@ -539,7 +540,28 @@ static bool setup_myself(void) {
 
        /* Open device */
 
-       if(!setup_device())
+       if(get_config_string(lookup_config(config_tree, "DeviceType"), &type)) {
+               if(!strcasecmp(type, "dummy"))
+                       devops = dummy_devops;
+               else if(!strcasecmp(type, "raw_socket"))
+                       devops = raw_socket_devops;
+#ifdef ENABLE_UML
+               else if(!strcasecmp(type, "uml"))
+                       devops = uml_devops;
+#endif
+#ifdef ENABLE_VDE
+               else if(!strcasecmp(type, "vde"))
+                       devops = vde_devops;
+#endif
+               else {
+                       logger(LOG_ERR, "Unknown device type %s!", type);
+                       return false;
+               }
+       } else {
+               devops = os_devops;
+       }
+
+       if(!devops.setup())
                return false;
 
        /* Run tinc-up script to further initialize the tap interface */
@@ -702,7 +724,7 @@ void close_network_connections(void) {
        for(i = 0; i < 4; i++)
                free(envp[i]);
 
-       close_device();
+       devops.close();
 
        return;
 }
index c65923711244fe15d3dc04da236daa498c49dd4d..f33355ce1e739ff2837f8df919b3234f98fd37ca 100644 (file)
@@ -511,7 +511,7 @@ static RETSIGTYPE sigusr1_handler(int a) {
 }
 
 static RETSIGTYPE sigusr2_handler(int a) {
-       dump_device_stats();
+       devops.dump_stats();
        dump_nodes();
        dump_edges();
        dump_subnets();
diff --git a/src/raw_socket/device.c b/src/raw_socket/device.c
deleted file mode 100644 (file)
index abe368a..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
-    device.c -- raw socket
-    Copyright (C) 2002-2005 Ivo Timmermans,
-                  2002-2009 Guus Sliepen <guus@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 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, write to the Free Software Foundation, Inc.,
-    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-*/
-
-#include "system.h"
-
-#include <netpacket/packet.h>
-
-#include "conf.h"
-#include "device.h"
-#include "net.h"
-#include "logger.h"
-#include "utils.h"
-#include "route.h"
-#include "xalloc.h"
-
-int device_fd = -1;
-char *device = NULL;
-char *iface = NULL;
-static char ifrname[IFNAMSIZ];
-static char *device_info;
-
-static uint64_t device_total_in = 0;
-static uint64_t device_total_out = 0;
-
-bool setup_device(void) {
-       struct ifreq ifr;
-       struct sockaddr_ll sa;
-
-       if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
-               iface = xstrdup("eth0");
-
-       if(!get_config_string(lookup_config(config_tree, "Device"), &device))
-               device = xstrdup(iface);
-
-       device_info = "raw socket";
-
-       if((device_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0) {
-               logger(LOG_ERR, "Could not open %s: %s", device_info,
-                          strerror(errno));
-               return false;
-       }
-
-       memset(&ifr, 0, sizeof(ifr));
-       strncpy(ifr.ifr_ifrn.ifrn_name, iface, IFNAMSIZ);
-       if(ioctl(device_fd, SIOCGIFINDEX, &ifr)) {
-               close(device_fd);
-               logger(LOG_ERR, "Can't find interface %s: %s", iface,
-                          strerror(errno));
-               return false;
-       }
-
-       memset(&sa, '0', sizeof(sa));
-       sa.sll_family = AF_PACKET;
-       sa.sll_protocol = htons(ETH_P_ALL);
-       sa.sll_ifindex = ifr.ifr_ifindex;
-
-       if(bind(device_fd, (struct sockaddr *) &sa, (socklen_t) sizeof(sa))) {
-               logger(LOG_ERR, "Could not bind %s to %s: %s", device, iface, strerror(errno));
-               return false;
-       }
-
-       logger(LOG_INFO, "%s is a %s", device, device_info);
-
-       return true;
-}
-
-void close_device(void) {
-       close(device_fd);
-
-       free(device);
-       free(iface);
-}
-
-bool read_packet(vpn_packet_t *packet) {
-       int lenin;
-
-       if((lenin = read(device_fd, packet->data, MTU)) <= 0) {
-               logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
-                          device, strerror(errno));
-               return false;
-       }
-
-       packet->len = lenin;
-
-       device_total_in += packet->len;
-
-       ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
-                          device_info);
-
-       return true;
-}
-
-bool write_packet(vpn_packet_t *packet) {
-       ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
-                          packet->len, device_info);
-
-       if(write(device_fd, packet->data, packet->len) < 0) {
-               logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
-                          strerror(errno));
-               return false;
-       }
-
-       device_total_out += packet->len;
-
-       return true;
-}
-
-void dump_device_stats(void) {
-       logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
-       logger(LOG_DEBUG, " total bytes in:  %10"PRIu64, device_total_in);
-       logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
-}
diff --git a/src/raw_socket_device.c b/src/raw_socket_device.c
new file mode 100644 (file)
index 0000000..90ccedf
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+    device.c -- raw socket
+    Copyright (C) 2002-2005 Ivo Timmermans,
+                  2002-2011 Guus Sliepen <guus@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 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, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "system.h"
+
+#include <netpacket/packet.h>
+
+#include "conf.h"
+#include "device.h"
+#include "net.h"
+#include "logger.h"
+#include "utils.h"
+#include "route.h"
+#include "xalloc.h"
+
+static char *device_info;
+
+static uint64_t device_total_in = 0;
+static uint64_t device_total_out = 0;
+
+static bool setup_device(void) {
+       struct ifreq ifr;
+       struct sockaddr_ll sa;
+
+       if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
+               iface = xstrdup("eth0");
+
+       if(!get_config_string(lookup_config(config_tree, "Device"), &device))
+               device = xstrdup(iface);
+
+       device_info = "raw socket";
+
+       if((device_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0) {
+               logger(LOG_ERR, "Could not open %s: %s", device_info,
+                          strerror(errno));
+               return false;
+       }
+
+       memset(&ifr, 0, sizeof(ifr));
+       strncpy(ifr.ifr_ifrn.ifrn_name, iface, IFNAMSIZ);
+       if(ioctl(device_fd, SIOCGIFINDEX, &ifr)) {
+               close(device_fd);
+               logger(LOG_ERR, "Can't find interface %s: %s", iface,
+                          strerror(errno));
+               return false;
+       }
+
+       memset(&sa, '0', sizeof(sa));
+       sa.sll_family = AF_PACKET;
+       sa.sll_protocol = htons(ETH_P_ALL);
+       sa.sll_ifindex = ifr.ifr_ifindex;
+
+       if(bind(device_fd, (struct sockaddr *) &sa, (socklen_t) sizeof(sa))) {
+               logger(LOG_ERR, "Could not bind %s to %s: %s", device, iface, strerror(errno));
+               return false;
+       }
+
+       logger(LOG_INFO, "%s is a %s", device, device_info);
+
+       return true;
+}
+
+static void close_device(void) {
+       close(device_fd);
+
+       free(device);
+       free(iface);
+}
+
+static bool read_packet(vpn_packet_t *packet) {
+       int lenin;
+
+       if((lenin = read(device_fd, packet->data, MTU)) <= 0) {
+               logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
+                          device, strerror(errno));
+               return false;
+       }
+
+       packet->len = lenin;
+
+       device_total_in += packet->len;
+
+       ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
+                          device_info);
+
+       return true;
+}
+
+static bool write_packet(vpn_packet_t *packet) {
+       ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
+                          packet->len, device_info);
+
+       if(write(device_fd, packet->data, packet->len) < 0) {
+               logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
+                          strerror(errno));
+               return false;
+       }
+
+       device_total_out += packet->len;
+
+       return true;
+}
+
+static void dump_device_stats(void) {
+       logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
+       logger(LOG_DEBUG, " total bytes in:  %10"PRIu64, device_total_in);
+       logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
+}
+
+const devops_t raw_socket_devops = {
+       .setup = setup_device,
+       .close = close_device,
+       .read = read_packet,
+       .write = write_packet,
+       .dump_stats = dump_device_stats,
+};
index 0dfffb1b73fd0ae4a6e44f2a1e13f8f4dca6ba8c..579cece0d601100e6d79fcfc080a1e2bfed5c23e 100644 (file)
@@ -35,7 +35,7 @@
 #define DEFAULT_DEVICE "/dev/tun"
 
 int device_fd = -1;
-int ip_fd = -1, if_fd = -1;
+static int ip_fd = -1, if_fd = -1;
 char *device = NULL;
 char *iface = NULL;
 static char *device_info = NULL;
@@ -43,7 +43,7 @@ static char *device_info = NULL;
 static uint64_t device_total_in = 0;
 static uint64_t device_total_out = 0;
 
-bool setup_device(void) {
+static bool setup_device(void) {
        int ppa;
        char *ptr;
 
@@ -105,7 +105,7 @@ bool setup_device(void) {
        return true;
 }
 
-void close_device(void) {
+static void close_device(void) {
        close(if_fd);
        close(ip_fd);
        close(device_fd);
@@ -114,7 +114,7 @@ void close_device(void) {
        free(iface);
 }
 
-bool read_packet(vpn_packet_t *packet) {
+static bool read_packet(vpn_packet_t *packet) {
        int lenin;
 
        if((lenin = read(device_fd, packet->data + 14, MTU - 14)) <= 0) {
@@ -149,7 +149,7 @@ bool read_packet(vpn_packet_t *packet) {
        return true;
 }
 
-bool write_packet(vpn_packet_t *packet) {
+static bool write_packet(vpn_packet_t *packet) {
        ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
                           packet->len, device_info);
 
@@ -164,8 +164,16 @@ bool write_packet(vpn_packet_t *packet) {
        return true;
 }
 
-void dump_device_stats(void) {
+static void dump_device_stats(void) {
        logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
        logger(LOG_DEBUG, " total bytes in:  %10"PRIu64, device_total_in);
        logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
 }
+
+const devops_t os_devops = {
+       .setup = setup_device,
+       .close = close_device,
+       .read = read_packet,
+       .write = write_packet,
+       .dump_stats = dump_device_stats,
+};
index f075168d2df5de2890b6218bffa4e9e650dfcdc8..f7b956fea124301851d63ab2b1b2565ec7e3557b 100644 (file)
@@ -650,7 +650,7 @@ int main2(int argc, char **argv) {
        /* Shutdown properly. */
 
        ifdebug(CONNECTIONS)
-               dump_device_stats();
+               devops.dump_stats();
 
        close_network_connections();
 
diff --git a/src/uml_device.c b/src/uml_device.c
new file mode 100644 (file)
index 0000000..26bcb01
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+    device.c -- UML network socket
+    Copyright (C) 2002-2005 Ivo Timmermans,
+                  2002-2011 Guus Sliepen <guus@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 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, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "system.h"
+
+#include <sys/un.h>
+
+#include "conf.h"
+#include "device.h"
+#include "net.h"
+#include "logger.h"
+#include "utils.h"
+#include "route.h"
+#include "xalloc.h"
+
+static int listen_fd = -1;
+static int request_fd = -1;
+static int data_fd = -1;
+static int write_fd = -1;
+static int state = 0;
+static char *device_info;
+
+extern char *identname;
+extern volatile bool running;
+
+static uint64_t device_total_in = 0;
+static uint64_t device_total_out = 0;
+
+enum request_type { REQ_NEW_CONTROL };
+
+static struct request {
+  uint32_t magic;
+  uint32_t version;
+  enum request_type type;
+  struct sockaddr_un sock;
+} request;
+
+static struct sockaddr_un data_sun;
+
+static bool setup_device(void) {
+       struct sockaddr_un listen_sun;
+       static const int one = 1;
+       struct {
+               char zero;
+               int pid;
+               int usecs;
+       } name;
+       struct timeval tv;
+
+       if(!get_config_string(lookup_config(config_tree, "Device"), &device))
+               xasprintf(&device, LOCALSTATEDIR "/run/%s.umlsocket", identname);
+
+       get_config_string(lookup_config(config_tree, "Interface"), &iface);
+
+       device_info = "UML network socket";
+
+       if((write_fd = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
+               logger(LOG_ERR, "Could not open write %s: %s", device_info, strerror(errno));
+               running = false;
+               return false;
+       }
+
+       setsockopt(write_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one);
+
+       if(fcntl(write_fd, F_SETFL, O_NONBLOCK) < 0) {
+               logger(LOG_ERR, "System call `%s' failed: %s", "fcntl", strerror(errno));
+               running = false;
+               return false;
+       }
+
+       if((data_fd = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
+               logger(LOG_ERR, "Could not open data %s: %s", device_info, strerror(errno));
+               running = false;
+               return false;
+       }
+
+       setsockopt(data_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one);
+
+       if(fcntl(data_fd, F_SETFL, O_NONBLOCK) < 0) {
+               logger(LOG_ERR, "System call `%s' failed: %s", "fcntl", strerror(errno));
+               running = false;
+               return false;
+       }
+
+       name.zero = 0;
+       name.pid = getpid();
+       gettimeofday(&tv, NULL);
+       name.usecs = tv.tv_usec;
+       data_sun.sun_family = AF_UNIX;
+       memcpy(&data_sun.sun_path, &name, sizeof name);
+       
+       if(bind(data_fd, (struct sockaddr *)&data_sun, sizeof data_sun) < 0) {
+               logger(LOG_ERR, "Could not bind data %s: %s", device_info, strerror(errno));
+               running = false;
+               return false;
+       }
+
+       if((listen_fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
+               logger(LOG_ERR, "Could not open %s: %s", device_info,
+                          strerror(errno));
+               return false;
+       }
+
+       setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one);
+
+       if(fcntl(listen_fd, F_SETFL, O_NONBLOCK) < 0) {
+               logger(LOG_ERR, "System call `%s' failed: %s", "fcntl", strerror(errno));
+               return false;
+       }
+
+       listen_sun.sun_family = AF_UNIX;
+       strncpy(listen_sun.sun_path, device, sizeof listen_sun.sun_path);
+       if(bind(listen_fd, (struct sockaddr *)&listen_sun, sizeof listen_sun) < 0) {
+               logger(LOG_ERR, "Could not bind %s to %s: %s", device_info, device, strerror(errno));
+               return false;
+       }
+
+       if(listen(listen_fd, 1) < 0) {
+               logger(LOG_ERR, "Could not listen on %s %s: %s", device_info, device, strerror(errno));
+               return false;
+       }
+
+       device_fd = listen_fd;
+       state = 0;
+
+       logger(LOG_INFO, "%s is a %s", device, device_info);
+
+       if(routing_mode == RMODE_ROUTER)
+               overwrite_mac = true;
+
+       return true;
+}
+
+void close_device(void) {
+       if(listen_fd >= 0)
+               close(listen_fd);
+
+       if(request_fd >= 0)
+               close(request_fd);
+
+       if(data_fd >= 0)
+               close(data_fd);
+
+       if(write_fd >= 0)
+               close(write_fd);
+
+       unlink(device);
+
+       free(device);
+       if(iface) free(iface);
+}
+
+static bool read_packet(vpn_packet_t *packet) {
+       int lenin;
+
+       switch(state) {
+               case 0: {
+                       struct sockaddr sa;
+                       socklen_t salen = sizeof sa;
+
+                       request_fd = accept(listen_fd, &sa, &salen);
+                       if(request_fd < 0) {
+                               logger(LOG_ERR, "Could not accept connection to %s %s: %s", device_info, device, strerror(errno));
+                               return false;
+                       }
+
+                       if(fcntl(listen_fd, F_SETFL, O_NONBLOCK) < 0) {
+                               logger(LOG_ERR, "System call `%s' failed: %s", "fcntl", strerror(errno));
+                               running = false;
+                               return false;
+                       }
+
+                       close(listen_fd);
+                       listen_fd = -1;
+                       device_fd = request_fd;
+                       state = 1;
+
+                       return false;
+               }
+
+               case 1: {
+                       if((lenin = read(request_fd, &request, sizeof request)) != sizeof request) {
+                               logger(LOG_ERR, "Error while reading request from %s %s: %s", device_info,
+                                          device, strerror(errno));
+                               running = false;
+                               return false;
+                       }
+
+                       if(request.magic != 0xfeedface || request.version != 3 || request.type != REQ_NEW_CONTROL) {
+                               logger(LOG_ERR, "Unknown magic %x, version %d, request type %d from %s %s",
+                                               request.magic, request.version, request.type, device_info, device);
+                               running = false;
+                               return false;
+                       }
+
+                       if(connect(write_fd, &request.sock, sizeof request.sock) < 0) {
+                               logger(LOG_ERR, "Could not bind write %s: %s", device_info, strerror(errno));
+                               running = false;
+                               return false;
+                       }
+
+                       write(request_fd, &data_sun, sizeof data_sun);
+                       device_fd = data_fd;
+
+                       logger(LOG_INFO, "Connection with UML established");
+
+                       state = 2;
+                       return false;
+               }
+
+               case 2: {
+                       if((lenin = read(data_fd, packet->data, MTU)) <= 0) {
+                               logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
+                                          device, strerror(errno));
+                               running = false;
+                               return false;
+                       }
+
+                       packet->len = lenin;
+
+                       device_total_in += packet->len;
+
+                       ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
+                                          device_info);
+
+                       return true;
+               }
+
+               default:
+                       logger(LOG_ERR, "Invalid value for state variable in " __FILE__);
+                       abort();
+       }
+}
+
+static bool write_packet(vpn_packet_t *packet) {
+       if(state != 2) {
+               ifdebug(TRAFFIC) logger(LOG_DEBUG, "Dropping packet of %d bytes to %s: not connected to UML yet",
+                               packet->len, device_info);
+               return false;
+       }
+
+       ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
+                          packet->len, device_info);
+
+       if(write(write_fd, packet->data, packet->len) < 0) {
+               if(errno != EINTR && errno != EAGAIN) {
+                       logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, strerror(errno));
+                       running = false;
+               }
+
+               return false;
+       }
+
+       device_total_out += packet->len;
+
+       return true;
+}
+
+static void dump_device_stats(void) {
+       logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
+       logger(LOG_DEBUG, " total bytes in:  %10"PRIu64, device_total_in);
+       logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
+}
+
+const devops_t uml_devops = {
+       .setup = setup_device,
+       .close = close_device,
+       .read = read_packet,
+       .write = write_packet,
+       .dump_stats = dump_device_stats,
+};
diff --git a/src/uml_socket/device.c b/src/uml_socket/device.c
deleted file mode 100644 (file)
index a371e7b..0000000
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
-    device.c -- UML network socket
-    Copyright (C) 2002-2005 Ivo Timmermans,
-                  2002-2009 Guus Sliepen <guus@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 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, write to the Free Software Foundation, Inc.,
-    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-*/
-
-#include "system.h"
-
-#include <sys/un.h>
-
-#include "conf.h"
-#include "device.h"
-#include "net.h"
-#include "logger.h"
-#include "utils.h"
-#include "route.h"
-#include "xalloc.h"
-
-int device_fd = -1;
-static int listen_fd = -1;
-static int request_fd = -1;
-static int data_fd = -1;
-static int write_fd = -1;
-static int state = 0;
-char *device = NULL;
-char *iface = NULL;
-static char *device_info;
-
-extern char *identname;
-extern volatile bool running;
-
-static uint64_t device_total_in = 0;
-static uint64_t device_total_out = 0;
-
-enum request_type { REQ_NEW_CONTROL };
-
-static struct request {
-  uint32_t magic;
-  uint32_t version;
-  enum request_type type;
-  struct sockaddr_un sock;
-} request;
-
-static struct sockaddr_un data_sun;
-
-bool setup_device(void) {
-       struct sockaddr_un listen_sun;
-       static const int one = 1;
-       struct {
-               char zero;
-               int pid;
-               int usecs;
-       } name;
-       struct timeval tv;
-
-       if(!get_config_string(lookup_config(config_tree, "Device"), &device))
-               xasprintf(&device, LOCALSTATEDIR "/run/%s.umlsocket", identname);
-
-       get_config_string(lookup_config(config_tree, "Interface"), &iface);
-
-       device_info = "UML network socket";
-
-       if((write_fd = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
-               logger(LOG_ERR, "Could not open write %s: %s", device_info, strerror(errno));
-               running = false;
-               return false;
-       }
-
-       setsockopt(write_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one);
-
-       if(fcntl(write_fd, F_SETFL, O_NONBLOCK) < 0) {
-               logger(LOG_ERR, "System call `%s' failed: %s", "fcntl", strerror(errno));
-               running = false;
-               return false;
-       }
-
-       if((data_fd = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
-               logger(LOG_ERR, "Could not open data %s: %s", device_info, strerror(errno));
-               running = false;
-               return false;
-       }
-
-       setsockopt(data_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one);
-
-       if(fcntl(data_fd, F_SETFL, O_NONBLOCK) < 0) {
-               logger(LOG_ERR, "System call `%s' failed: %s", "fcntl", strerror(errno));
-               running = false;
-               return false;
-       }
-
-       name.zero = 0;
-       name.pid = getpid();
-       gettimeofday(&tv, NULL);
-       name.usecs = tv.tv_usec;
-       data_sun.sun_family = AF_UNIX;
-       memcpy(&data_sun.sun_path, &name, sizeof name);
-       
-       if(bind(data_fd, (struct sockaddr *)&data_sun, sizeof data_sun) < 0) {
-               logger(LOG_ERR, "Could not bind data %s: %s", device_info, strerror(errno));
-               running = false;
-               return false;
-       }
-
-       if((listen_fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
-               logger(LOG_ERR, "Could not open %s: %s", device_info,
-                          strerror(errno));
-               return false;
-       }
-
-       setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one);
-
-       if(fcntl(listen_fd, F_SETFL, O_NONBLOCK) < 0) {
-               logger(LOG_ERR, "System call `%s' failed: %s", "fcntl", strerror(errno));
-               return false;
-       }
-
-       listen_sun.sun_family = AF_UNIX;
-       strncpy(listen_sun.sun_path, device, sizeof listen_sun.sun_path);
-       if(bind(listen_fd, (struct sockaddr *)&listen_sun, sizeof listen_sun) < 0) {
-               logger(LOG_ERR, "Could not bind %s to %s: %s", device_info, device, strerror(errno));
-               return false;
-       }
-
-       if(listen(listen_fd, 1) < 0) {
-               logger(LOG_ERR, "Could not listen on %s %s: %s", device_info, device, strerror(errno));
-               return false;
-       }
-
-       device_fd = listen_fd;
-       state = 0;
-
-       logger(LOG_INFO, "%s is a %s", device, device_info);
-
-       if(routing_mode == RMODE_ROUTER)
-               overwrite_mac = true;
-
-       return true;
-}
-
-void close_device(void) {
-       if(listen_fd >= 0)
-               close(listen_fd);
-
-       if(request_fd >= 0)
-               close(request_fd);
-
-       if(data_fd >= 0)
-               close(data_fd);
-
-       if(write_fd >= 0)
-               close(write_fd);
-
-       unlink(device);
-
-       free(device);
-       if(iface) free(iface);
-}
-
-bool read_packet(vpn_packet_t *packet) {
-       int lenin;
-
-       switch(state) {
-               case 0: {
-                       struct sockaddr sa;
-                       socklen_t salen = sizeof sa;
-
-                       request_fd = accept(listen_fd, &sa, &salen);
-                       if(request_fd < 0) {
-                               logger(LOG_ERR, "Could not accept connection to %s %s: %s", device_info, device, strerror(errno));
-                               return false;
-                       }
-
-                       if(fcntl(listen_fd, F_SETFL, O_NONBLOCK) < 0) {
-                               logger(LOG_ERR, "System call `%s' failed: %s", "fcntl", strerror(errno));
-                               running = false;
-                               return false;
-                       }
-
-                       close(listen_fd);
-                       listen_fd = -1;
-                       device_fd = request_fd;
-                       state = 1;
-
-                       return false;
-               }
-
-               case 1: {
-                       if((lenin = read(request_fd, &request, sizeof request)) != sizeof request) {
-                               logger(LOG_ERR, "Error while reading request from %s %s: %s", device_info,
-                                          device, strerror(errno));
-                               running = false;
-                               return false;
-                       }
-
-                       if(request.magic != 0xfeedface || request.version != 3 || request.type != REQ_NEW_CONTROL) {
-                               logger(LOG_ERR, "Unknown magic %x, version %d, request type %d from %s %s",
-                                               request.magic, request.version, request.type, device_info, device);
-                               running = false;
-                               return false;
-                       }
-
-                       if(connect(write_fd, &request.sock, sizeof request.sock) < 0) {
-                               logger(LOG_ERR, "Could not bind write %s: %s", device_info, strerror(errno));
-                               running = false;
-                               return false;
-                       }
-
-                       write(request_fd, &data_sun, sizeof data_sun);
-                       device_fd = data_fd;
-
-                       logger(LOG_INFO, "Connection with UML established");
-
-                       state = 2;
-                       return false;
-               }
-
-               case 2: {
-                       if((lenin = read(data_fd, packet->data, MTU)) <= 0) {
-                               logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
-                                          device, strerror(errno));
-                               running = false;
-                               return false;
-                       }
-
-                       packet->len = lenin;
-
-                       device_total_in += packet->len;
-
-                       ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
-                                          device_info);
-
-                       return true;
-               }
-
-               default:
-                       logger(LOG_ERR, "Invalid value for state variable in " __FILE__);
-                       abort();
-       }
-}
-
-bool write_packet(vpn_packet_t *packet) {
-       if(state != 2) {
-               ifdebug(TRAFFIC) logger(LOG_DEBUG, "Dropping packet of %d bytes to %s: not connected to UML yet",
-                               packet->len, device_info);
-               return false;
-       }
-
-       ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
-                          packet->len, device_info);
-
-       if(write(write_fd, packet->data, packet->len) < 0) {
-               if(errno != EINTR && errno != EAGAIN) {
-                       logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, strerror(errno));
-                       running = false;
-               }
-
-               return false;
-       }
-
-       device_total_out += packet->len;
-
-       return true;
-}
-
-void dump_device_stats(void) {
-       logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
-       logger(LOG_DEBUG, " total bytes in:  %10"PRIu64, device_total_in);
-       logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
-}
diff --git a/src/vde/device.c b/src/vde/device.c
deleted file mode 100644 (file)
index 74cf3b6..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
-    device.c -- VDE plug
-    Copyright (C) 2011 Guus Sliepen <guus@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 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, write to the Free Software Foundation, Inc.,
-    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-*/
-
-#include "system.h"
-
-#include <libvdeplug_dyn.h>
-
-#include "conf.h"
-#include "device.h"
-#include "net.h"
-#include "logger.h"
-#include "utils.h"
-#include "route.h"
-#include "xalloc.h"
-
-int device_fd = -1;
-static struct vdepluglib plug;
-static struct vdeconn *conn = NULL;
-static int port = 0;
-static char *group = NULL;
-char *device = NULL;
-char *iface = NULL;
-static char *device_info;
-
-extern char *identname;
-extern volatile bool running;
-
-static uint64_t device_total_in = 0;
-static uint64_t device_total_out = 0;
-
-bool setup_device(void) {
-       libvdeplug_dynopen(plug);
-
-       if(!plug.dl_handle) {
-               logger(LOG_ERR, "Could not open libvdeplug library!");
-               return false;
-       }
-
-       if(!get_config_string(lookup_config(config_tree, "Device"), &device))
-               xasprintf(&device, LOCALSTATEDIR "/run/vde.ctl");
-
-       get_config_string(lookup_config(config_tree, "Interface"), &iface);
-
-       get_config_int(lookup_config(config_tree, "VDEPort"), &port);
-
-       get_config_string(lookup_config(config_tree, "VDEGroup"), &group);
-
-       device_info = "VDE socket";
-
-       struct vde_open_args args = {
-               .port = port,
-               .group = group,
-               .mode = 0700,
-       };
-
-       conn = plug.vde_open(device, identname, &args);
-       if(!conn) {
-               logger(LOG_ERR, "Could not open VDE socket %s", device);
-               return false;
-       }
-
-       device_fd = plug.vde_datafd(conn);
-
-       logger(LOG_INFO, "%s is a %s", device, device_info);
-
-       if(routing_mode == RMODE_ROUTER)
-               overwrite_mac = true;
-
-       return true;
-}
-
-void close_device(void) {
-       if(conn)
-               plug.vde_close(conn);
-
-       if(plug.dl_handle)
-               libvdeplug_dynclose(plug);
-
-       free(device);
-
-       free(iface);
-}
-
-bool read_packet(vpn_packet_t *packet) {
-       int lenin = plug.vde_recv(conn, packet->data, MTU, 0);
-       if(lenin <= 0) {
-               logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno));
-               running = false;
-               return false;
-       }
-
-       packet->len = lenin;
-       device_total_in += packet->len;
-       ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len, device_info);
-
-       return true;
-}
-
-bool write_packet(vpn_packet_t *packet) {
-       if(plug.vde_send(conn, packet->data, packet->len, 0) < 0) {
-               if(errno != EINTR && errno != EAGAIN) {
-                       logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, strerror(errno));
-                       running = false;
-               }
-
-               return false;
-       }
-
-       device_total_out += packet->len;
-
-       return true;
-}
-
-void dump_device_stats(void) {
-       logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
-       logger(LOG_DEBUG, " total bytes in:  %10"PRIu64, device_total_in);
-       logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
-}
diff --git a/src/vde_device.c b/src/vde_device.c
new file mode 100644 (file)
index 0000000..8f601e7
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+    device.c -- VDE plug
+    Copyright (C) 2011 Guus Sliepen <guus@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 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, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "system.h"
+
+#include <libvdeplug_dyn.h>
+
+#include "conf.h"
+#include "device.h"
+#include "net.h"
+#include "logger.h"
+#include "utils.h"
+#include "route.h"
+#include "xalloc.h"
+
+static struct vdepluglib plug;
+static struct vdeconn *conn = NULL;
+static int port = 0;
+static char *group = NULL;
+static char *device_info;
+
+extern char *identname;
+extern volatile bool running;
+
+static uint64_t device_total_in = 0;
+static uint64_t device_total_out = 0;
+
+static bool setup_device(void) {
+       libvdeplug_dynopen(plug);
+
+       if(!plug.dl_handle) {
+               logger(LOG_ERR, "Could not open libvdeplug library!");
+               return false;
+       }
+
+       if(!get_config_string(lookup_config(config_tree, "Device"), &device))
+               xasprintf(&device, LOCALSTATEDIR "/run/vde.ctl");
+
+       get_config_string(lookup_config(config_tree, "Interface"), &iface);
+
+       get_config_int(lookup_config(config_tree, "VDEPort"), &port);
+
+       get_config_string(lookup_config(config_tree, "VDEGroup"), &group);
+
+       device_info = "VDE socket";
+
+       struct vde_open_args args = {
+               .port = port,
+               .group = group,
+               .mode = 0700,
+       };
+
+       conn = plug.vde_open(device, identname, &args);
+       if(!conn) {
+               logger(LOG_ERR, "Could not open VDE socket %s", device);
+               return false;
+       }
+
+       device_fd = plug.vde_datafd(conn);
+
+       logger(LOG_INFO, "%s is a %s", device, device_info);
+
+       if(routing_mode == RMODE_ROUTER)
+               overwrite_mac = true;
+
+       return true;
+}
+
+static void close_device(void) {
+       if(conn)
+               plug.vde_close(conn);
+
+       if(plug.dl_handle)
+               libvdeplug_dynclose(plug);
+
+       free(device);
+
+       free(iface);
+}
+
+static bool read_packet(vpn_packet_t *packet) {
+       int lenin = plug.vde_recv(conn, packet->data, MTU, 0);
+       if(lenin <= 0) {
+               logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno));
+               running = false;
+               return false;
+       }
+
+       packet->len = lenin;
+       device_total_in += packet->len;
+       ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len, device_info);
+
+       return true;
+}
+
+static bool write_packet(vpn_packet_t *packet) {
+       if(plug.vde_send(conn, packet->data, packet->len, 0) < 0) {
+               if(errno != EINTR && errno != EAGAIN) {
+                       logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, strerror(errno));
+                       running = false;
+               }
+
+               return false;
+       }
+
+       device_total_out += packet->len;
+
+       return true;
+}
+
+static void dump_device_stats(void) {
+       logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
+       logger(LOG_DEBUG, " total bytes in:  %10"PRIu64, device_total_in);
+       logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
+}
+
+const devops_t vde_devops = {
+       .setup = setup_device,
+       .close = close_device,
+       .read = read_packet,
+       .write = write_packet,
+       .dump_stats = dump_device_stats,
+};