]> git.meshlink.io Git - meshlink/commitdiff
Merge branch 'master' of git://tinc-vpn.org/tinc into 1.1
authorGuus Sliepen <guus@tinc-vpn.org>
Wed, 22 Feb 2012 13:23:59 +0000 (14:23 +0100)
committerGuus Sliepen <guus@tinc-vpn.org>
Wed, 22 Feb 2012 13:23:59 +0000 (14:23 +0100)
Conflicts:
NEWS
README
configure.in
doc/tincd.8.in
src/Makefile.am
src/bsd/device.c
src/connection.c
src/connection.h
src/cygwin/device.c
src/device.h
src/dropin.h
src/linux/device.c
src/mingw/device.c
src/net.c
src/net_packet.c
src/net_setup.c
src/net_socket.c
src/process.c
src/protocol.c
src/protocol_key.c
src/raw_socket_device.c
src/route.c
src/solaris/device.c
src/tincd.c
src/uml_device.c

37 files changed:
NEWS
THANKS
configure.in
doc/tinc.conf.5.in
doc/tinc.texi
doc/tincd.8.in
src/Makefile.am
src/bsd/device.c
src/connection.c
src/connection.h
src/cygwin/device.c
src/device.h
src/dummy/device.c [deleted file]
src/dummy_device.c [new file with mode: 0644]
src/ipv4.h
src/linux/device.c
src/mingw/device.c
src/net.c
src/net_packet.c
src/net_setup.c
src/net_socket.c
src/node.h
src/openssl/prf.c
src/protocol.c
src/protocol_auth.c
src/protocol_edge.c
src/protocol_key.c
src/raw_socket/device.c [deleted file]
src/raw_socket_device.c [new file with mode: 0644]
src/route.c
src/route.h
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]

diff --git a/NEWS b/NEWS
index 679040b5c350bde9c29288054be957bd427aef9e..36f50606cd4bddad0c8cf063143dadd8b734560d 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -28,6 +28,13 @@ Version 1.1pre1              June 25 2011
  Thanks to Scott Lamb and Sven-Haegar Koch for their contributions to this
  version of tinc.
 
+Version 1.0.16               July 23 2011
+
+ * Fixed a performance issue with TCP communication under Windows.
+
+ * Fixed code that, during network outages, would cause tinc to exit when it
+   thought two nodes with identical Names were on the VPN.
+
 Version 1.0.15               June 24 2011
 
  * Improved logging to file.
diff --git a/THANKS b/THANKS
index e27fa9b2c308edeae3f5452622f96747caad69b3..521f1a20990c26d8bf5e496085a220258ac227cd 100644 (file)
--- a/THANKS
+++ b/THANKS
@@ -32,6 +32,7 @@ We would like to thank the following people for their contributions to tinc:
 * Menno Smits
 * Michael Tokarev
 * Miles Nordin
+* Nick Hibma
 * Nick Patavalis
 * Paul Littlefield
 * Robert van der Meulen
index 2e519b0393d77e82f664c3c173165d54e46379a8..4d2bcbd6e0130f93d40a72b0264608b12316091b 100644 (file)
@@ -73,6 +73,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])
@@ -85,6 +100,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
@@ -101,7 +118,7 @@ dnl We do this in multiple stages, because unlike Linux all the other operating
 
 AC_HEADER_STDC
 AC_CHECK_HEADERS([stdbool.h syslog.h sys/file.h sys/ioctl.h sys/mman.h sys/param.h sys/resource.h sys/socket.h sys/time.h sys/uio.h sys/un.h sys/wait.h netdb.h arpa/inet.h dirent.h])
-AC_CHECK_HEADERS([net/if.h net/if_types.h linux/if_tun.h net/if_tun.h net/tun/if_tun.h net/if_tap.h net/tap/if_tap.h net/ethernet.h net/if_arp.h netinet/in_systm.h netinet/in.h netinet/in6.h time.h],
+AC_CHECK_HEADERS([net/if.h net/if_types.h linux/if_tun.h net/if_tun.h net/tun/if_tun.h net/if_tap.h net/tap/if_tap.h net/ethernet.h net/if_arp.h netinet/in_systm.h netinet/in.h netinet/in6.h time.h netpacket/packet.h],
   [], [], [#include "have.h"]
 )
 AC_CHECK_HEADERS([netinet/if_ether.h netinet/ip.h netinet/ip6.h],
index a44f27cc056e0e8258a5970c0646ddd09fb4a71b..47cf82e5c7c0d06817f8fffe9ba09f671bd60ef8 100644 (file)
@@ -133,7 +133,10 @@ IPv6 listening sockets will be created.
 If your computer has more than one IPv4 or IPv6 address,
 .Nm tinc
 will by default listen on all of them for incoming connections.
-It is possible to bind only to a single address with this variable.
+Multiple
+.Va BindToAddress
+variables may be specified,
+in which case listening sockets for each specified address are made.
 
 .Pp
 This option may not work on all platforms.
@@ -147,6 +150,9 @@ It is possible to bind only to a single interface with this variable.
 .Pp
 This option may not work on all platforms.
 
+.It Va Broadcast Li = yes | no Po yes Pc Bq experimental
+When disabled, tinc will drop all broadcast and multicast packets, in both router and switch mode.
+
 .It Va ConnectTo Li = Ar name
 Specifies which other tinc daemon to connect to on startup.
 Multiple
@@ -165,6 +171,14 @@ If you don't specify a host with
 won't try to connect to other daemons at all,
 and will instead just listen for incoming connections.
 
+.It Va DecrementTTL Li = yes | no Po yes Pc
+When enabled,
+.Nm tinc
+will decrement the Time To Live field in IPv4 packets, or the Hop Limit field in IPv6 packets,
+before forwarding a received packet to the virtual network device or to another node,
+and will drop packets that have a TTL value of zero,
+in which case it will send an ICMP Time Exceeded packet back.
+
 .It Va Device Li = Ar device Po Pa /dev/tap0 , Pa /dev/net/tun No or other depending on platform Pc
 The virtual network device to use.
 .Nm tinc
@@ -177,30 +191,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 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
+.It tun Pq BSD and Linux
 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
 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
 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 and Linux
 Set type to tap.
 Tinc will expect packets read from the virtual network device
 to start with an Ethernet header.
index 69e5a2b289e4b2db2d15a74f0d04600c9af87cf3..4d9f233ac7a1c4e6ad6073ea3b9342dd2ce3f2a6 100644 (file)
@@ -782,7 +782,8 @@ both IPv4 and IPv6 or just IPv6 listening sockets will be created.
 @item BindToAddress = <@var{address}> [experimental]
 If your computer has more than one IPv4 or IPv6 address, tinc
 will by default listen on all of them for incoming connections.
-It is possible to bind only to a single address with this variable.
+Multiple BindToAddress variables may be specified,
+in which case listening sockets for each specified address are made.
 
 This option may not work on all platforms.
 
@@ -795,6 +796,10 @@ variable.
 
 This option may not work on all platforms.
 
+@cindex Broadcast
+@item Broadcast = <yes | no> (yes) [experimental]
+When disabled, tinc will drop all broadcast and multicast packets, in both router and switch mode.
+
 @cindex ConnectTo
 @item ConnectTo = <@var{name}>
 Specifies which other tinc daemon to connect to on startup.
@@ -807,6 +812,13 @@ If you don't specify a host with ConnectTo,
 tinc won't try to connect to other daemons at all,
 and will instead just listen for incoming connections.
 
+@cindex DecrementTTL
+@item DecrementTTL = <yes | no> (yes)
+When enabled, tinc will decrement the Time To Live field in IPv4 packets, or the Hop Limit field in IPv6 packets,
+before forwarding a received packet to the virtual network device or to another node,
+and will drop packets that have a TTL value of zero,
+in which case it will send an ICMP Time Exceeded packet back.
+
 @cindex Device
 @item Device = <@var{device}> (@file{/dev/tap0}, @file{/dev/net/tun} or other depending on platform)
 The virtual network device to use.
@@ -817,32 +829,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 and Linux)
 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)
 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)
 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 and Linux)
 Set type to tap.
 Tinc will expect packets read from the virtual network device
 to start with an Ethernet header.
@@ -1600,6 +1644,12 @@ Store a cookie in @var{filename} which allows tincctl to authenticate.
 If unspecified, the default is
 @file{@value{localstatedir}/run/tinc.@var{netname}.pid}.
 
+@item -o, --option=[@var{HOST}.]@var{KEY}=@var{VALUE}
+Without specifying a @var{HOST}, this will set server configuration variable @var{KEY} to @var{VALUE}.
+If specified as @var{HOST}.@var{KEY}=@var{VALUE},
+this will set the host configuration variable @var{KEY} of the host named @var{HOST} to @var{VALUE}.
+This option can be used more than once to specify multiple configuration variables.
+
 @item -L, --mlock
 Lock tinc into main memory.
 This will prevent sensitive data like shared private keys to be written to the system swap files/partitions.
index bb4aa48c2e61e09823ecbc3bea5cf521dfed8434..24b4da462cdd2b6a9b95e4ed765d082c46c0d97c 100644 (file)
@@ -8,11 +8,12 @@
 .Nd tinc VPN daemon
 .Sh SYNOPSIS
 .Nm
-.Op Fl cdDKnLRU
+.Op Fl cdDKnoLRU
 .Op Fl -config Ns = Ns Ar DIR
 .Op Fl -no-detach
 .Op Fl -debug Ns Op = Ns Ar LEVEL
 .Op Fl -net Ns = Ns Ar NETNAME
+.Op Fl -option Ns = Ns Ar [HOST.]KEY=VALUE
 .Op Fl -mlock
 .Op Fl -logfile Ns Op = Ns Ar FILE
 .Op Fl -bypass-security
@@ -61,6 +62,22 @@ for
 .Ar NETNAME
 is the same as not specifying any
 .Ar NETNAME .
+.It Fl o, -option Ns = Ns Ar [HOST.]KEY=VALUE
+Without specifying a
+.Ar HOST ,
+this will set server configuration variable
+.Ar KEY 
+to
+.Ar VALUE .
+If specified as
+.Ar HOST.KEY=VALUE ,
+this will set the host configuration variable 
+.Ar KEY
+of the host named
+.Ar HOST
+to
+.Ar VALUE .
+This option can be used more than once to specify multiple configuration variables.
 .It Fl L, -mlock
 Lock tinc into main memory.
 This will prevent sensitive data like shared private keys to be written to the system swap files/partitions.
index 61f9a9360a6af768e351e0c4ef0116b148a59183..ba8b34793cd68cf6827d02bb2afa54b66b103b52 100644 (file)
@@ -2,13 +2,22 @@
 
 sbin_PROGRAMS = tincd tincctl sptps_test
 
-EXTRA_DIST = linux bsd solaris cygwin mingw raw_socket uml_socket openssl gcrypt
+EXTRA_DIST = linux bsd solaris cygwin mingw openssl gcrypt
 
 tincd_SOURCES = \
        utils.c getopt.c getopt1.c list.c splay_tree.c dropin.c fake-getaddrinfo.c fake-getnameinfo.c \
        buffer.c conf.c connection.c control.c edge.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
 
 nodist_tincd_SOURCES = \
        device.c cipher.c crypto.c ecdh.c ecdsa.c digest.c prf.c rsa.c
index 9c3009d5bb7931720b33fc361f8f76741aca8718..9a1688a805624a0146f08e93ef09e8e62ee30754 100644 (file)
@@ -1,7 +1,7 @@
 /*
     device.c -- Interaction BSD tun/tap device
     Copyright (C) 2001-2005 Ivo Timmermans,
-                  2001-2011 Guus Sliepen <guus@tinc-vpn.org>
+                  2001-2012 Guus Sliepen <guus@tinc-vpn.org>
                   2009      Grzegorz Dymarek <gregd72002@googlemail.com>
 
     This program is free software; you can redistribute it and/or modify
@@ -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))
@@ -106,6 +106,10 @@ bool setup_device(void) {
                return false;
        }
 
+#ifdef FD_CLOEXEC
+       fcntl(device_fd, F_SETFD, FD_CLOEXEC);
+#endif
+
        switch(device_type) {
                default:
                        device_type = DEVICE_TYPE_TUN;
@@ -175,7 +179,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 +194,7 @@ void close_device(void) {
        free(iface);
 }
 
-bool read_packet(vpn_packet_t *packet) {
+static bool read_packet(vpn_packet_t *packet) {
        int inlen;
 
        switch(device_type) {
@@ -282,7 +286,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 +355,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 bae86b9072507b96d5359567e7bff843ddef9428..9587819d03e3d8bedf04890b8ad3bc526b9631ac 100644 (file)
@@ -32,7 +32,7 @@
 #include "xalloc.h"
 
 splay_tree_t *connection_tree; /* Meta connections */
-connection_t *broadcast;
+connection_t *everyone;
 
 static int connection_compare(const connection_t *a, const connection_t *b) {
        return a < b ? -1 : a == b ? 0 : 1;
@@ -40,14 +40,14 @@ static int connection_compare(const connection_t *a, const connection_t *b) {
 
 void init_connections(void) {
        connection_tree = splay_alloc_tree((splay_compare_t) connection_compare, (splay_action_t) free_connection);
-       broadcast = new_connection();
-       broadcast->name = xstrdup("everyone");
-       broadcast->hostname = xstrdup("BROADCAST");
+       everyone = new_connection();
+       everyone->name = xstrdup("everyone");
+       everyone->hostname = xstrdup("BROADCAST");
 }
 
 void exit_connections(void) {
        splay_delete_tree(connection_tree);
-       free_connection(broadcast);
+       free_connection(everyone);
 }
 
 connection_t *new_connection(void) {
index 26aa3f0c25c0f9159c08d2b05d9896abddecdb0d..20e00763c0a1d9881b15509b34061b0327b0bce0 100644 (file)
@@ -99,7 +99,7 @@ typedef struct connection_t {
 } connection_t;
 
 extern splay_tree_t *connection_tree;
-extern connection_t *broadcast;
+extern connection_t *everyone;
 
 extern void init_connections(void);
 extern void exit_connections(void);
index a4ab938c8ab4c899b612a1712031e21027bc9266..cf9f1b579c497338eda1dfcfd60837110d017e20 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 inlen;
 
        if((inlen = 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 outlen;
 
        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 16a24868dc0dd79cf0c1eb388347e09f2788a602..993d4ce82698a49bba569b3c03bd024ab9790422 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
@@ -32,10 +32,19 @@ extern uint64_t device_in_bytes;
 extern uint64_t device_out_packets;
 extern uint64_t device_out_bytes;
 
-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 940c239c985737669802aca300d80c34f78369af..57d236d33115f901ce2087834917b4214bf42826 100644 (file)
 #define ICMP_NET_UNKNOWN 6
 #endif
 
+#ifndef ICMP_TIME_EXCEEDED
+#define ICMP_TIME_EXCEEDED 11
+#endif
+
+#ifndef ICMP_EXC_TTL
+#define ICMP_EXC_TTL 0
+#endif
+
 #ifndef ICMP_NET_UNREACH
 #define ICMP_NET_UNREACH 0
 #endif
index d36f3f67faa21c41ee14c21446faa2cb129455d1..ccb9a3f008d99f54b42ca1cc7dcd6aa51c0f417b 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-2012 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
@@ -41,6 +41,7 @@ int device_fd = -1;
 static device_type_t device_type;
 char *device = NULL;
 char *iface = NULL;
+static char *type = NULL;
 static char ifrname[IFNAMSIZ];
 static char *device_info;
 
@@ -49,7 +50,7 @@ uint64_t device_in_bytes = 0;
 uint64_t device_out_packets = 0;
 uint64_t device_out_bytes = 0;
 
-bool setup_device(void) {
+static bool setup_device(void) {
        if(!get_config_string(lookup_config(config_tree, "Device"), &device))
                device = xstrdup(DEFAULT_DEVICE);
 
@@ -67,9 +68,20 @@ bool setup_device(void) {
                return false;
        }
 
+#ifdef FD_CLOEXEC
+       fcntl(device_fd, F_SETFD, FD_CLOEXEC);
+#endif
+
        struct ifreq ifr = {{{0}}};
 
-       if(routing_mode == RMODE_ROUTER) {
+       get_config_string(lookup_config(config_tree, "DeviceType"), &type);
+
+       if(type && strcasecmp(type, "tun") && strcasecmp(type, "tap")) {
+               logger(LOG_ERR, "Unknown device type %s!", type);
+               return false;
+       }
+
+       if((type && !strcasecmp(type, "tun")) || (!type && routing_mode == RMODE_ROUTER)) {
                ifr.ifr_flags = IFF_TUN;
                device_type = DEVICE_TYPE_TUN;
                device_info = "Linux tun/tap device (tun mode)";
@@ -106,14 +118,15 @@ bool setup_device(void) {
        return true;
 }
 
-void close_device(void) {
+static void close_device(void) {
        close(device_fd);
 
+       free(type);
        free(device);
        free(iface);
 }
 
-bool read_packet(vpn_packet_t *packet) {
+static bool read_packet(vpn_packet_t *packet) {
        int inlen;
        
        switch(device_type) {
@@ -152,7 +165,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);
 
@@ -182,8 +195,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_in_bytes);
        logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_out_bytes);
 }
+
+const devops_t os_devops = {
+       .setup = setup_device,
+       .close = close_device,
+       .read = read_packet,
+       .write = write_packet,
+       .dump_stats = dump_device_stats,
+};
index bdca8424fe178cc33612eb31650cf50c3df6fa1b..e468338668b2bdd83bc21fbfadd4b8d7804aadd3 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 outlen;
        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 f9020b3b9aa8d4ab771167fa3cb5760ebe6f4211..336bf9eec312bcc381751fd5d2fba8c8306d078a 100644 (file)
--- a/src/net.c
+++ b/src/net.c
@@ -64,7 +64,7 @@ void purge(void) {
                        for(snode = n->subnet_tree->head; snode; snode = snext) {
                                snext = snode->next;
                                s = snode->data;
-                               send_del_subnet(broadcast, s);
+                               send_del_subnet(everyone, s);
                                if(!strictsubnets)
                                        subnet_del(n, s);
                        }
@@ -73,7 +73,7 @@ void purge(void) {
                                enext = enode->next;
                                e = enode->data;
                                if(!tunnelserver)
-                                       send_del_edge(broadcast, e);
+                                       send_del_edge(everyone, e);
                                edge_del(e);
                        }
                }
@@ -119,7 +119,7 @@ void terminate_connection(connection_t *c, bool report) {
 
        if(c->edge) {
                if(report && !tunnelserver)
-                       send_del_edge(broadcast, c->edge);
+                       send_del_edge(everyone, c->edge);
 
                edge_del(c->edge);
 
@@ -134,7 +134,7 @@ void terminate_connection(connection_t *c, bool report) {
                        e = lookup_edge(c->node, myself);
                        if(e) {
                                if(!tunnelserver)
-                                       send_del_edge(broadcast, e);
+                                       send_del_edge(everyone, e);
                                edge_del(e);
                        }
                }
@@ -310,14 +310,14 @@ int reload_configuration(void) {
                        next = node->next;
                        subnet = node->data;
                        if(subnet->expires == 1) {
-                               send_del_subnet(broadcast, subnet);
+                               send_del_subnet(everyone, subnet);
                                if(subnet->owner->status.reachable)
                                        subnet_update(subnet->owner, subnet, false);
                                subnet_del(subnet->owner, subnet);
                        } else if(subnet->expires == -1) {
                                subnet->expires = 0;
                        } else {
-                               send_add_subnet(broadcast, subnet);
+                               send_add_subnet(everyone, subnet);
                                if(subnet->owner->status.reachable)
                                        subnet_update(subnet->owner, subnet, true);
                        }
index 875a0832bf88cf0fc37a0dd4ce01775faf5b8439..f7d8640300a6bc5065b572e0828446e9b3cb7c0a 100644 (file)
@@ -381,7 +381,6 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
        static int priority = 0;
        int origpriority = origpkt->priority;
 #endif
-       int sock;
 
        if(!n->status.reachable) {
                ifdebug(TRAFFIC) logger(LOG_INFO, "Trying to send UDP packet to unreachable node %s (%s)", n->name, n->hostname);
@@ -463,26 +462,28 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
 
        /* Determine which socket we have to use */
 
-       for(sock = 0; sock < listen_sockets; sock++)
-               if(n->address.sa.sa_family == listen_socket[sock].sa.sa.sa_family)
-                       break;
-
-       if(sock >= listen_sockets)
-               sock = 0;                               /* If none is available, just use the first and hope for the best. */
+       if(n->address.sa.sa_family != listen_socket[n->sock].sa.sa.sa_family) {
+               for(int sock = 0; sock < listen_sockets; sock++) {
+                       if(n->address.sa.sa_family == listen_socket[sock].sa.sa.sa_family) {
+                               n->sock = sock;
+                               break;
+                       }
+               }
+       }
 
        /* Send the packet */
 
 #if defined(SOL_IP) && defined(IP_TOS)
        if(priorityinheritance && origpriority != priority
-          && listen_socket[sock].sa.sa.sa_family == AF_INET) {
+          && listen_socket[n->sock].sa.sa.sa_family == AF_INET) {
                priority = origpriority;
                ifdebug(TRAFFIC) logger(LOG_DEBUG, "Setting outgoing packet priority to %d", priority);
-               if(setsockopt(listen_socket[sock].udp, SOL_IP, IP_TOS, &priority, sizeof priority))     /* SO_PRIORITY doesn't seem to work */
+               if(setsockopt(listen_socket[n->sock].udp, SOL_IP, IP_TOS, &priority, sizeof(priority))) /* SO_PRIORITY doesn't seem to work */
                        logger(LOG_ERR, "System call `%s' failed: %s", "setsockopt", strerror(errno));
        }
 #endif
 
-       if(sendto(listen_socket[sock].udp, (char *) &inpkt->seqno, inpkt->len, 0, &(n->address.sa), SALEN(n->address.sa)) < 0 && !sockwouldblock(sockerrno)) {
+       if(sendto(listen_socket[n->sock].udp, (char *) &inpkt->seqno, inpkt->len, 0, &(n->address.sa), SALEN(n->address.sa)) < 0 && !sockwouldblock(sockerrno)) {
                if(sockmsgsize(sockerrno)) {
                        if(n->maxmtu >= origlen)
                                n->maxmtu = origlen - 1;
@@ -507,7 +508,7 @@ void send_packet(node_t *n, vpn_packet_t *packet) {
                         memcpy(packet->data, mymac.x, ETH_ALEN);
                n->out_packets++;
                n->out_bytes += packet->len;
-               write_packet(packet);
+               devops.write(packet);
                return;
        }
 
@@ -631,6 +632,8 @@ void handle_incoming_vpn_data(int sock, short events, void *data) {
                        return;
        }
 
+       n->sock = (intptr_t)data;
+
        receive_udppacket(n, &pkt);
 }
 
@@ -639,7 +642,7 @@ void handle_device_data(int sock, short events, void *data) {
 
        packet.priority = 0;
 
-       if(read_packet(&packet)) {
+       if(devops.read(&packet)) {
                myself->in_packets++;
                myself->in_bytes += packet.len;
                route(myself, &packet);
index bacbeac9d4f10f1e7b9dd3b2b343a1acc6316155..207ce42543b4c9da1c542aa4f7484b580953a425 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-2012 Guus Sliepen <guus@tinc-vpn.org>
                   2006      Scott Lamb <slamb@slamb.org>
                   2010      Brandon Black <blblack@gmail.com>
 
@@ -44,6 +44,7 @@
 
 char *myport;
 static struct event device_ev;
+devops_t devops;
 
 bool node_read_ecdsa_public_key(node_t *n) {
        if(ecdsa_active(&n->ecdsa))
@@ -151,8 +152,7 @@ bool read_rsa_public_key(connection_t *c) {
        fp = fopen(fname, "r");
 
        if(!fp) {
-               logger(LOG_ERR, "Error reading RSA public key file `%s': %s",
-                          fname, strerror(errno));
+               logger(LOG_ERR, "Error reading RSA public key file `%s': %s", fname, strerror(errno));
                free(fname);
                return false;
        }
@@ -179,8 +179,7 @@ static bool read_ecdsa_private_key(void) {
        fp = fopen(fname, "r");
 
        if(!fp) {
-               logger(LOG_ERR, "Error reading ECDSA private key file `%s': %s",
-                          fname, strerror(errno));
+               logger(LOG_ERR, "Error reading ECDSA private key file `%s': %s", fname, strerror(errno));
                free(fname);
                return false;
        }
@@ -349,7 +348,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];
@@ -475,6 +474,8 @@ static bool setup_myself(void) {
                myself->options |= OPTION_CLAMP_MSS;
 
        get_config_bool(lookup_config(config_tree, "PriorityInheritance"), &priorityinheritance);
+       get_config_bool(lookup_config(config_tree, "DecrementTTL"), &decrement_ttl);
+       get_config_bool(lookup_config(config_tree, "Broadcast"), &broadcast);
 
 #if !defined(SOL_IP) || !defined(IP_TOS)
        if(priorityinheritance)
@@ -589,7 +590,24 @@ static bool setup_myself(void) {
 
        /* Open device */
 
-       if(!setup_device())
+       devops = os_devops;
+
+       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
+       }
+
+       if(!devops.setup())
                return false;
 
        if(device_fd >= 0) {
@@ -597,7 +615,7 @@ static bool setup_myself(void) {
 
                if (event_add(&device_ev, NULL) < 0) {
                        logger(LOG_ERR, "event_add failed: %s", strerror(errno));
-                       close_device();
+                       devops.close();
                        return false;
                }
        }
@@ -620,72 +638,78 @@ static bool setup_myself(void) {
 
        /* Open sockets */
 
-       get_config_string(lookup_config(config_tree, "BindToAddress"), &address);
+       listen_sockets = 0;
+       cfg = lookup_config(config_tree, "BindToAddress");
 
-       hint.ai_family = addressfamily;
-       hint.ai_socktype = SOCK_STREAM;
-       hint.ai_protocol = IPPROTO_TCP;
-       hint.ai_flags = AI_PASSIVE;
+       do {
+               get_config_string(cfg, &address);
+               if(cfg)
+                       cfg = lookup_config_next(config_tree, cfg);
 
-       err = getaddrinfo(address, myport, &hint, &ai);
+               hint.ai_family = addressfamily;
+               hint.ai_socktype = SOCK_STREAM;
+               hint.ai_protocol = IPPROTO_TCP;
+               hint.ai_flags = AI_PASSIVE;
 
-       if(err || !ai) {
-               logger(LOG_ERR, "System call `%s' failed: %s", "getaddrinfo",
-                          gai_strerror(err));
-               return false;
-       }
+               err = getaddrinfo(address, myport, &hint, &ai);
+               free(address);
 
-       listen_sockets = 0;
+               if(err || !ai) {
+                       logger(LOG_ERR, "System call `%s' failed: %s", "getaddrinfo",
+                                  gai_strerror(err));
+                       return false;
+               }
 
-       for(aip = ai; aip; aip = aip->ai_next) {
-               listen_socket[listen_sockets].tcp =
-                       setup_listen_socket((sockaddr_t *) aip->ai_addr);
+               for(aip = ai; aip; aip = aip->ai_next) {
+                       if(listen_sockets >= MAXSOCKETS) {
+                               logger(LOG_ERR, "Too many listening sockets");
+                               return false;
+                       }
 
-               if(listen_socket[listen_sockets].tcp < 0)
-                       continue;
+                       listen_socket[listen_sockets].tcp =
+                               setup_listen_socket((sockaddr_t *) aip->ai_addr);
 
-               listen_socket[listen_sockets].udp =
-                       setup_vpn_in_socket((sockaddr_t *) aip->ai_addr);
+                       if(listen_socket[listen_sockets].tcp < 0)
+                               continue;
 
-               if(listen_socket[listen_sockets].udp < 0) {
-                       close(listen_socket[listen_sockets].tcp);
-                       continue;
-               }
+                       listen_socket[listen_sockets].udp =
+                               setup_vpn_in_socket((sockaddr_t *) aip->ai_addr);
 
-               event_set(&listen_socket[listen_sockets].ev_tcp,
-                                 listen_socket[listen_sockets].tcp,
-                                 EV_READ|EV_PERSIST,
-                                 handle_new_meta_connection, NULL);
-               if(event_add(&listen_socket[listen_sockets].ev_tcp, NULL) < 0) {
-                       logger(LOG_ERR, "event_add failed: %s", strerror(errno));
-                       abort();
-               }
+                       if(listen_socket[listen_sockets].udp < 0) {
+                               close(listen_socket[listen_sockets].tcp);
+                               continue;
+                       }
 
-               event_set(&listen_socket[listen_sockets].ev_udp,
-                                 listen_socket[listen_sockets].udp,
-                                 EV_READ|EV_PERSIST,
-                                 handle_incoming_vpn_data, NULL);
-               if(event_add(&listen_socket[listen_sockets].ev_udp, NULL) < 0) {
-                       logger(LOG_ERR, "event_add failed: %s", strerror(errno));
-                       abort();
-               }
+                       event_set(&listen_socket[listen_sockets].ev_tcp,
+                                         listen_socket[listen_sockets].tcp,
+                                         EV_READ|EV_PERSIST,
+                                         handle_new_meta_connection, NULL);
+                       if(event_add(&listen_socket[listen_sockets].ev_tcp, NULL) < 0) {
+                               logger(LOG_ERR, "event_add failed: %s", strerror(errno));
+                               abort();
+                       }
 
-               ifdebug(CONNECTIONS) {
-                       hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr);
-                       logger(LOG_NOTICE, "Listening on %s", hostname);
-                       free(hostname);
-               }
+                       event_set(&listen_socket[listen_sockets].ev_udp,
+                                         listen_socket[listen_sockets].udp,
+                                         EV_READ|EV_PERSIST,
+                                         handle_incoming_vpn_data, (void *)(intptr_t)listen_sockets);
+                       if(event_add(&listen_socket[listen_sockets].ev_udp, NULL) < 0) {
+                               logger(LOG_ERR, "event_add failed: %s", strerror(errno));
+                               abort();
+                       }
 
-               memcpy(&listen_socket[listen_sockets].sa, aip->ai_addr, aip->ai_addrlen);
-               listen_sockets++;
+                       ifdebug(CONNECTIONS) {
+                               hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr);
+                               logger(LOG_NOTICE, "Listening on %s", hostname);
+                               free(hostname);
+                       }
 
-               if(listen_sockets >= MAXSOCKETS) {
-                       logger(LOG_WARNING, "Maximum of %d listening sockets reached", MAXSOCKETS);
-                       break;
+                       memcpy(&listen_socket[listen_sockets].sa, aip->ai_addr, aip->ai_addrlen);
+                       listen_sockets++;
                }
-       }
 
-       freeaddrinfo(ai);
+               freeaddrinfo(ai);
+       } while(cfg);
 
        if(listen_sockets)
                logger(LOG_NOTICE, "Ready");
@@ -778,7 +802,7 @@ void close_network_connections(void) {
        for(i = 0; i < 4; i++)
                free(envp[i]);
 
-       close_device();
+       devops.close();
 
        return;
 }
index a1dfcd3552cec4b2545313f03a9b32d70035cb08..730cf6b8e56f5f00ffce0fa12ec34e6a7334aedd 100644 (file)
@@ -1,7 +1,7 @@
 /*
     net_socket.c -- Handle various kinds of sockets.
     Copyright (C) 1998-2005 Ivo Timmermans,
-                  2000-2010 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2012 Guus Sliepen <guus@tinc-vpn.org>
                   2006      Scott Lamb <slamb@slamb.org>
                   2009      Florian Forster <octo@verplant.org>
 
@@ -33,8 +33,6 @@
 #include "utils.h"
 #include "xalloc.h"
 
-#include <assert.h>
-
 /* Needed on Mac OS/X */
 #ifndef SOL_TCP
 #define SOL_TCP IPPROTO_TCP
@@ -109,63 +107,6 @@ static bool bind_to_interface(int sd) {
        return true;
 }
 
-static bool bind_to_address(connection_t *c) {
-       char *node;
-       struct addrinfo *ai_list;
-       struct addrinfo *ai_ptr;
-       struct addrinfo ai_hints;
-       int status;
-
-       assert(c != NULL);
-       assert(c->socket >= 0);
-
-       node = NULL;
-       if(!get_config_string(lookup_config(config_tree, "BindToAddress"),
-                               &node))
-               return true;
-
-       assert(node != NULL);
-
-       memset(&ai_hints, 0, sizeof(ai_hints));
-       ai_hints.ai_family = c->address.sa.sa_family;
-       /* We're called from `do_outgoing_connection' only. */
-       ai_hints.ai_socktype = SOCK_STREAM;
-       ai_hints.ai_protocol = IPPROTO_TCP;
-
-       ai_list = NULL;
-
-       status = getaddrinfo(node, /* service = */ NULL,
-                       &ai_hints, &ai_list);
-       if(status) {
-               logger(LOG_WARNING, "Error looking up %s port %s: %s",
-                               node, "any", gai_strerror(status));
-               free(node);
-               return false;
-       }
-       assert(ai_list != NULL);
-
-       status = -1;
-       for(ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next) {
-               status = bind(c->socket,
-                               ai_list->ai_addr, ai_list->ai_addrlen);
-               if(!status)
-                       break;
-       }
-
-
-       if(status) {
-               logger(LOG_ERR, "Can't bind to %s/tcp: %s", node, sockstrerror(sockerrno));
-       } else ifdebug(CONNECTIONS) {
-               logger(LOG_DEBUG, "Successfully bound outgoing "
-                               "TCP socket to %s", node);
-       }
-
-       free(node);
-       freeaddrinfo(ai_list);
-
-       return status ? false : true;
-}
-
 int setup_listen_socket(const sockaddr_t *sa) {
        int nfd;
        char *addrstr;
@@ -179,6 +120,10 @@ int setup_listen_socket(const sockaddr_t *sa) {
                return -1;
        }
 
+#ifdef FD_CLOEXEC
+       fcntl(nfd, F_SETFD, FD_CLOEXEC);
+#endif
+
        /* Optimize TCP settings */
 
        option = 1;
@@ -237,6 +182,10 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
                return -1;
        }
 
+#ifdef FD_CLOEXEC
+       fcntl(nfd, F_SETFD, FD_CLOEXEC);
+#endif
+
 #ifdef O_NONBLOCK
        {
                int flags = fcntl(nfd, F_GETFL);
@@ -409,6 +358,10 @@ begin:
 
        c->socket = socket(c->address.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
 
+#ifdef FD_CLOEXEC
+       fcntl(c->socket, F_SETFD, FD_CLOEXEC);
+#endif
+
        if(c->socket == -1) {
                ifdebug(CONNECTIONS) logger(LOG_ERR, "Creating socket for %s failed: %s", c->hostname, sockstrerror(sockerrno));
                goto begin;
@@ -421,7 +374,6 @@ begin:
 #endif
 
        bind_to_interface(c->socket);
-       bind_to_address(c);
 
        /* Optimize TCP settings */
 
index 0ce7542324846e81a7faa0de0960a36974d68f58..4464011fc1f60e3ad94a355510432cb6039b1b69 100644 (file)
@@ -43,6 +43,7 @@ typedef struct node_t {
        char *name;                             /* name of this node */
        uint32_t options;                       /* options turned on for this node */
 
+       int sock;                               /* Socket to use for outgoing UDP packets */
        sockaddr_t address;                     /* his real (internet) ip to send UDP packets to */
        char *hostname;                         /* the hostname of its real ip */
 
index 13841c4d158ab4a9dce69328d9a55337d63de0cd..1c432c7dd5a399ffe4cb4a5aaa2369597ad5821f 100644 (file)
@@ -19,6 +19,8 @@
 
 #include "system.h"
 
+#include <openssl/obj_mac.h>
+
 #include "digest.h"
 #include "prf.h"
 
index 63163a0f596e82b9f77931a0cfb0e0bb89efae9d..116e139eebc98c686652bb62e8b4d0095b3a525e 100644 (file)
@@ -96,7 +96,7 @@ bool send_request(connection_t *c, const char *format, ...) {
 
        request[len++] = '\n';
 
-       if(c == broadcast) {
+       if(c == everyone) {
                broadcast_meta(NULL, request, len);
                return true;
        } else
index 4e2bd8712dbe592e89ce6c26d206c902965bd4ca..a542ca9ea922813b75cc741f24dbe8d1f2550c9c 100644 (file)
@@ -651,7 +651,7 @@ bool ack_h(connection_t *c, char *request) {
        if(tunnelserver)
                send_add_edge(c, c->edge);
        else
-               send_add_edge(broadcast, c->edge);
+               send_add_edge(everyone, c->edge);
 
        /* Run MST and SSSP algorithms */
 
index 1dd68d5e86c71db1c2df12afdbde59e031d629ad..e6736945323f733ad9ed1bb9c7494550838240ae 100644 (file)
@@ -254,7 +254,7 @@ bool del_edge_h(connection_t *c, char *request) {
                e = lookup_edge(to, myself);
                if(e) {
                        if(!tunnelserver)
-                               send_del_edge(broadcast, e);
+                               send_del_edge(everyone, e);
                        edge_del(e);
                }
        }
index 5246e7d2d8cc573c808600fdff934604154ef5ee..c392a469846e3878a53a65b84a110f43698df02e 100644 (file)
@@ -40,7 +40,7 @@ void send_key_changed(void) {
        splay_node_t *node;
        connection_t *c;
 
-       send_request(broadcast, "%d %x %s", KEY_CHANGED, rand(), myself->name);
+       send_request(everyone, "%d %x %s", KEY_CHANGED, rand(), myself->name);
 
        /* Immediately send new keys to directly connected nodes to keep UDP mappings alive */
 
diff --git a/src/raw_socket/device.c b/src/raw_socket/device.c
deleted file mode 100644 (file)
index 410e46e..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 inlen;
-
-       if((inlen = 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 = inlen;
-
-       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..3785dcf
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+    device.c -- raw socket
+    Copyright (C) 2002-2005 Ivo Timmermans,
+                  2002-2012 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"
+
+#ifdef HAVE_NETPACKET_PACKET_H
+#include <netpacket/packet.h>
+#endif
+
+#include "conf.h"
+#include "device.h"
+#include "net.h"
+#include "logger.h"
+#include "utils.h"
+#include "route.h"
+#include "xalloc.h"
+
+#if defined(PF_PACKET) && defined(ETH_P_ALL) && defined(AF_PACKET)
+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);
+
+#ifdef FD_CLOEXEC
+       fcntl(device_fd, F_SETFD, FD_CLOEXEC);
+#endif
+
+       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 inlen;
+
+       if((inlen = 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 = inlen;
+
+       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,
+};
+
+#else
+
+static bool not_supported(void) {
+       logger(LOG_ERR, "Raw socket device not supported on this platform");
+       return false;
+}
+
+const devops_t raw_socket_devops = {
+       .setup = not_supported,
+       .close = NULL,
+       .read = NULL,
+       .write = NULL,
+       .dump_stats = NULL,
+};
+#endif
index 0b2d22eb55ca0c3f189391252d6baedd786ac07b..32be4dec404f06c2fffe6e53ef7c699343d064d0 100644 (file)
 
 rmode_t routing_mode = RMODE_ROUTER;
 fmode_t forwarding_mode = FMODE_INTERNAL;
+bool decrement_ttl = true;
 bool directonly = false;
 bool priorityinheritance = false;
 int macexpire = 600;
 bool overwrite_mac = false;
+bool broadcast = true;
 mac_t mymac = {{0xFE, 0xFD, 0, 0, 0, 0}};
 bool pcap = false;
 
@@ -439,11 +441,11 @@ static void route_ipv4(node_t *source, vpn_packet_t *packet) {
        if(!checklength(source, packet, ether_size + ip_size))
                return;
 
-       if(((packet->data[30] & 0xf0) == 0xe0) || (
+       if(broadcast && (((packet->data[30] & 0xf0) == 0xe0) || (
                        packet->data[30] == 255 &&
                        packet->data[31] == 255 &&
                        packet->data[32] == 255 &&
-                       packet->data[33] == 255))
+                       packet->data[33] == 255)))
                broadcast_packet(source, packet);
        else
                route_ipv4_unicast(source, packet);
@@ -731,7 +733,7 @@ static void route_ipv6(node_t *source, vpn_packet_t *packet) {
                return;
        }
 
-       if(packet->data[38] == 255)
+       if(broadcast && packet->data[38] == 255)
                broadcast_packet(source, packet);
        else
                route_ipv6_unicast(source, packet);
@@ -821,7 +823,8 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
        subnet = lookup_subnet_mac(NULL, &dest);
 
        if(!subnet) {
-               broadcast_packet(source, packet);
+               if(broadcast)
+                       broadcast_packet(source, packet);
                return;
        }
 
@@ -876,6 +879,50 @@ static void send_pcap(vpn_packet_t *packet) {
        }
 }
 
+static bool do_decrement_ttl(node_t *source, vpn_packet_t *packet) {
+       uint16_t type = packet->data[12] << 8 | packet->data[13];
+
+       switch (type) {
+               case ETH_P_IP:
+                       if(!checklength(source, packet, 14 + 32))
+                               return false;
+
+                       if(packet->data[22] < 1) {
+                               route_ipv4_unreachable(source, packet, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL);
+                               return false;
+                       }
+
+                       uint16_t old = packet->data[22] << 8 | packet->data[23];
+                       packet->data[22]--;
+                       uint16_t new = packet->data[22] << 8 | packet->data[23];
+
+                       uint32_t checksum = packet->data[24] << 8 | packet->data[25];
+                       checksum += old + (~new & 0xFFFF);
+                       while(checksum >> 16)
+                               checksum = (checksum & 0xFFFF) + (checksum >> 16);
+                       packet->data[24] = checksum >> 8;
+                       packet->data[25] = checksum & 0xff;
+
+                       return true;
+
+               case ETH_P_IPV6:
+                       if(!checklength(source, packet, 14 + 40))
+                               return false;
+
+                       if(packet->data[21] < 1) {
+                               route_ipv6_unreachable(source, packet, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT);
+                               return false;
+                       }
+
+                       packet->data[21]--;
+
+                       return true;
+
+               default:
+                       return true;
+       }
+}
+
 void route(node_t *source, vpn_packet_t *packet) {
        if(pcap)
                send_pcap(packet);
@@ -888,6 +935,10 @@ void route(node_t *source, vpn_packet_t *packet) {
        if(!checklength(source, packet, ether_size))
                return;
 
+       if(decrement_ttl && source != myself)
+               if(!do_decrement_ttl(source, packet))
+                       return;
+
        switch (routing_mode) {
                case RMODE_ROUTER:
                        {
index 5af2a0941ad52603ec560db60f7f6af53874f7fd..44023fdb3efff73dfd9dd474fa41a9c3c8527cd4 100644 (file)
@@ -38,8 +38,10 @@ typedef enum fmode_t {
 
 extern rmode_t routing_mode;
 extern fmode_t forwarding_mode;
+extern bool decrement_ttl;
 extern bool directonly;
 extern bool overwrite_mac;
+extern bool broadcast;
 extern bool priorityinheritance;
 extern int macexpire;
 extern bool pcap;
index eac267ad8b1603c53d5038be713764de15b434cc..365561fdacb2f063074aed9e358b23d96968e4be 100644 (file)
@@ -1,7 +1,7 @@
 /*
     device.c -- Interaction with Solaris tun device
     Copyright (C) 2001-2005 Ivo Timmermans,
-                  2001-2011 Guus Sliepen <guus@tinc-vpn.org>
+                  2001-2012 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
@@ -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;
 
@@ -55,6 +55,10 @@ bool setup_device(void) {
                return false;
        }
 
+#ifdef FD_CLOEXEC
+       fcntl(device_fd, F_SETFD, FD_CLOEXEC);
+#endif
+
        ppa = 0;
 
        ptr = device;
@@ -67,6 +71,10 @@ bool setup_device(void) {
                return false;
        }
 
+#ifdef FD_CLOEXEC
+       fcntl(ip_fd, F_SETFD, FD_CLOEXEC);
+#endif
+
        /* Assign a new PPA and get its unit number. */
        if((ppa = ioctl(device_fd, TUNNEWPPA, ppa)) < 0) {
                logger(LOG_ERR, "Can't assign new interface: %s", strerror(errno));
@@ -79,6 +87,10 @@ bool setup_device(void) {
                return false;
        }
 
+#ifdef FD_CLOEXEC
+       fcntl(if_fd, F_SETFD, FD_CLOEXEC);
+#endif
+
        if(ioctl(if_fd, I_PUSH, "ip") < 0) {
                logger(LOG_ERR, "Can't push IP module: %s", strerror(errno));
                return false;
@@ -105,7 +117,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 +126,7 @@ void close_device(void) {
        free(iface);
 }
 
-bool read_packet(vpn_packet_t *packet) {
+static bool read_packet(vpn_packet_t *packet) {
        int inlen;
 
        if((inlen = read(device_fd, packet->data + 14, MTU - 14)) <= 0) {
@@ -149,7 +161,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 +176,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 190884650e2cfdd9f0ecf69b83996b502bf53c7a..7970bcc9f2b67d1854df8fd0dece1ec2277ae774 100644 (file)
@@ -107,6 +107,7 @@ static struct option const long_options[] = {
        {"user", required_argument, NULL, 'U'},
        {"logfile", optional_argument, NULL, 4},
        {"pidfile", required_argument, NULL, 5},
+       {"option", required_argument, NULL, 'o'},
        {NULL, 0, NULL, 0}
 };
 
@@ -122,18 +123,18 @@ static void usage(bool status) {
                                program_name);
        else {
                printf("Usage: %s [option]...\n\n", program_name);
-               printf( "  -c, --config=DIR          Read configuration options from DIR.\n"
-                               "  -D, --no-detach           Don't fork and detach.\n"
-                               "  -d, --debug[=LEVEL]       Increase debug level or set it to LEVEL.\n"
-                               "  -n, --net=NETNAME         Connect to net NETNAME.\n"
-                               "  -L, --mlock               Lock tinc into main memory.\n"
-                               "      --logfile[=FILENAME]  Write log entries to a logfile.\n"
-                               "      --pidfile=FILENAME    Write PID and control socket cookie to FILENAME.\n"
-                               "      --bypass-security     Disables meta protocol security, for debugging.\n"
-                               "  -o [HOST.]KEY=VALUE       Set global/host configuration value.\n"
-                               "  -R, --chroot              chroot to NET dir at startup.\n"
-                               "  -U, --user=USER           setuid to given USER at startup.\n"                                "      --help                    Display this help and exit.\n"
-                               "      --version             Output version information and exit.\n\n");
+               printf( "  -c, --config=DIR              Read configuration options from DIR.\n"
+                               "  -D, --no-detach               Don't fork and detach.\n"
+                               "  -d, --debug[=LEVEL]           Increase debug level or set it to LEVEL.\n"
+                               "  -n, --net=NETNAME             Connect to net NETNAME.\n"
+                               "  -L, --mlock                   Lock tinc into main memory.\n"
+                               "      --logfile[=FILENAME]      Write log entries to a logfile.\n"
+                               "      --pidfile=FILENAME        Write PID and control socket cookie to FILENAME.\n"
+                               "      --bypass-security         Disables meta protocol security, for debugging.\n"
+                               "  -o, --option[HOST.]KEY=VALUE  Set global/host configuration value.\n"
+                               "  -R, --chroot                  chroot to NET dir at startup.\n"
+                               "  -U, --user=USER               setuid to given USER at startup.\n"                            "      --help                    Display this help and exit.\n"
+                               "      --version                 Output version information and exit.\n\n");
                printf("Report bugs to tinc@tinc-vpn.org.\n");
        }
 }
@@ -416,6 +417,7 @@ int main2(int argc, char **argv) {
        InitializeCriticalSection(&mutex);
        EnterCriticalSection(&mutex);
 #endif
+        char *priority = NULL;
 
        if(!detach())
                return 1;
@@ -445,8 +447,6 @@ int main2(int argc, char **argv) {
 
        /* Change process priority */
 
-        char *priority = NULL;
-
         if(get_config_string(lookup_config(config_tree, "ProcessPriority"), &priority)) {
                 if(!strcasecmp(priority, "Normal")) {
                         if (setpriority(NORMAL_PRIORITY_CLASS) != 0) {
@@ -483,7 +483,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..f0a9869
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+    device.c -- UML network socket
+    Copyright (C) 2002-2005 Ivo Timmermans,
+                  2002-2012 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;
+       }
+
+#ifdef FD_CLOEXEC
+       fcntl(write_fd, F_SETFD, FD_CLOEXEC);
+#endif
+
+       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;
+       }
+
+#ifdef FD_CLOEXEC
+       fcntl(data_fd, F_SETFD, FD_CLOEXEC);
+#endif
+
+       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;
+       }
+
+#ifdef FD_CLOEXEC
+       fcntl(device_fd, F_SETFD, FD_CLOEXEC);
+#endif
+
+       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 inlen;
+
+       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;
+                       }
+
+#ifdef FD_CLOEXEC
+                       fcntl(request_fd, F_SETFD, FD_CLOEXEC);
+#endif
+
+                       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((inlen = 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((inlen = 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 = inlen;
+
+                       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 d8f13a5..0000000
+++ /dev/null
@@ -1,278 +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"
-
-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 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 inlen;
-
-       switch(state) {
-               case 0: {
-                       struct sockaddr sa;
-                       int 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((inlen = 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((inlen = 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 = inlen;
-
-                       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(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 63171f9..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 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..258945e
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+    device.c -- VDE plug
+    Copyright (C) 2012 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);
+
+#ifdef FD_CLOEXEC
+       fcntl(device_fd, F_SETFD, FD_CLOEXEC);
+#endif
+
+       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,
+};