]> www.tinc-vpn.org Git - tinc/commitdiff
Merge remote-tracking branch 'dechamps/sleep' into 1.1
authorGuus Sliepen <guus@tinc-vpn.org>
Mon, 20 Mar 2017 21:33:18 +0000 (22:33 +0100)
committerGuus Sliepen <guus@tinc-vpn.org>
Mon, 20 Mar 2017 21:33:18 +0000 (22:33 +0100)
13 files changed:
doc/tinc.conf.5.in
doc/tinc.texi
src/Makefile.am
src/device.h
src/dropin.c
src/ethernet.h
src/fd_device.c [new file with mode: 0644]
src/net.h
src/net_setup.c
src/net_socket.c
src/protocol_auth.c
src/protocol_edge.c
src/tincctl.c

index 783c299fb1955606bfebad65ea8db0e7aa7de801..9365184b76eaf67198202946f835b0a3541cdeac 100644 (file)
@@ -234,6 +234,10 @@ Do NOT connect multiple
 .Nm tinc 
 daemons to the same multicast address, this will very likely cause routing loops.
 Also note that this can cause decrypted VPN packets to be sent out on a real network if misconfigured.
+.It fd
+Use a file descriptor.
+All packets are read from this interface.
+Packets received for the local node are written to it.
 .It uml Pq not compiled in by default
 Create a UNIX socket with the filename specified by
 .Va Device ,
index cb50e74af3f65f621a666c8fb399ad25e56fe010..29e2bdc9553950b02342b9f588c1c41add89c303 100644 (file)
@@ -958,6 +958,12 @@ This can be used to connect to UML, QEMU or KVM instances listening on the same
 Do NOT connect multiple tinc daemons to the same multicast address, this will very likely cause routing loops.
 Also note that this can cause decrypted VPN packets to be sent out on a real network if misconfigured.
 
+@cindex fd
+@item fd
+Use a file descriptor.
+All packets are read from this interface.
+Packets received for the local node are written to it.
+
 @cindex UML
 @item uml (not compiled in by default)
 Create a UNIX socket with the filename specified by
@@ -1086,10 +1092,6 @@ which normally would prevent the peers from learning each other's LAN address.
 Currently, local discovery is implemented by sending some packets to the local address of the node during UDP discovery.
 This will not work with old nodes that don't transmit their local address.
 
-@cindex LocalDiscoveryAddress
-@item LocalDiscoveryAddress <@var{address}>
-If this variable is specified, local discovery packets are sent to the given @var{address}.
-
 @cindex Mode
 @item Mode = <router|switch|hub> (router)
 This option selects the way packets are routed to other daemons.
index 200c71f5ae6c7cea7d1ca30350c07601648f5813..794e420209c44a7d3ef2ef67313bde6e9b442188 100644 (file)
@@ -1,6 +1,7 @@
 ## Produce this file with automake to get Makefile.in
 
-sbin_PROGRAMS = tincd tinc sptps_test sptps_keypair
+sbin_PROGRAMS = tincd tinc
+EXTRA_PROGRAMS = sptps_test sptps_keypair
 
 CLEANFILES = version_git.h
 
@@ -18,7 +19,7 @@ version.c: ${srcdir}/version.c
 endif
 
 if LINUX
-sbin_PROGRAMS += sptps_speed
+EXTRA_PROGRAMS += sptps_speed
 endif
 
 ed25519_SOURCES = \
@@ -58,6 +59,7 @@ tincd_SOURCES = \
        edge.c edge.h \
        ethernet.h \
        event.c event.h \
+       fd_device.c \
        graph.c graph.h \
        hash.c hash.h \
        have.h \
index 8046a255bff0ebb9a4bce9638005e119e0eefcd4..fa27df3d61955a2c470e5238954497f34e6debf9 100644 (file)
@@ -40,6 +40,7 @@ extern const devops_t os_devops;
 extern const devops_t dummy_devops;
 extern const devops_t raw_socket_devops;
 extern const devops_t multicast_devops;
+extern const devops_t fd_devops;
 extern const devops_t uml_devops;
 extern const devops_t vde_devops;
 extern devops_t devops;
index c7b558a4288bad7a06041ab575ad47b3a86b8300..a4f7a65d5893ba3f9303b74d9c521d1c8cb6daa4 100644 (file)
@@ -106,14 +106,13 @@ int vasprintf(char **buf, const char *fmt, va_list ap) {
 
        va_copy(aq, ap);
        status = vsnprintf(*buf, len, fmt, aq);
-       buf[len - 1] = 0;
        va_end(aq);
 
        if(status >= 0)
                *buf = xrealloc(*buf, status + 1);
 
        if(status > len - 1) {
-               len = status;
+               len = status + 1;
                va_copy(aq, ap);
                status = vsnprintf(*buf, len, fmt, aq);
                va_end(aq);
index 085e96ad2bc11ed2eb6be65169eb44bb3d8a093a..0b4a1db06b216eb645ee3fc21efcedec108e2874 100644 (file)
 #define ETH_ALEN 6
 #endif
 
+#ifndef ETH_HLEN
+#define ETH_HLEN 14
+#endif
+
+#ifndef ETHER_TYPE_LEN
+#define ETHER_TYPE_LEN 2
+#endif
+
+
 #ifndef ARPHRD_ETHER
 #define ARPHRD_ETHER 1
 #endif
 #define ETH_P_8021Q 0x8100
 #endif
 
+#ifndef ETH_P_MAX
+#define ETH_P_MAX 0xFFFF
+#endif
+
 #ifndef HAVE_STRUCT_ETHER_HEADER
 struct ether_header {
        uint8_t ether_dhost[ETH_ALEN];
diff --git a/src/fd_device.c b/src/fd_device.c
new file mode 100644 (file)
index 0000000..67e0cb7
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+    fd_device.c -- Interaction with Android tun fd
+    Copyright (C)   2001-2005   Ivo Timmermans,
+                    2001-2016   Guus Sliepen <guus@tinc-vpn.org>
+                    2009        Grzegorz Dymarek <gregd72002@googlemail.com>
+                    2016        Pacien TRAN-GIRARD <pacien@pacien.net>
+
+    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 "conf.h"
+#include "device.h"
+#include "ethernet.h"
+#include "logger.h"
+#include "net.h"
+#include "route.h"
+#include "utils.h"
+
+static inline bool check_config(void) {
+       if(routing_mode == RMODE_SWITCH) {
+               logger(DEBUG_ALWAYS, LOG_ERR, "Switch mode not supported (requires unsupported TAP device)!");
+               return false;
+       }
+
+       if(!get_config_int(lookup_config(config_tree, "Device"), &device_fd)) {
+               logger(DEBUG_ALWAYS, LOG_ERR, "Could not read fd from configuration!");
+               return false;
+       }
+
+       return true;
+}
+
+static bool setup_device(void) {
+       if(!check_config()) {
+               return false;
+       }
+
+       if(device_fd < 0) {
+               logger(DEBUG_ALWAYS, LOG_ERR, "Could not open %s: %s!", device, strerror(errno));
+               return false;
+       }
+
+       logger(DEBUG_ALWAYS, LOG_INFO, "fd/%d adapter set up.", device_fd);
+
+       return true;
+}
+
+static void close_device(void) {
+       close(device_fd);
+       device_fd = -1;
+}
+
+static inline uint16_t get_ip_ethertype(vpn_packet_t *packet) {
+       switch (DATA(packet)[ETH_HLEN] >> 4) {
+       case 4:
+               return ETH_P_IP;
+
+       case 6:
+               return ETH_P_IPV6;
+
+       default:
+               return ETH_P_MAX;
+       }
+}
+
+static inline void set_etherheader(vpn_packet_t *packet, uint16_t ethertype) {
+       memset(DATA(packet), 0, ETH_HLEN - ETHER_TYPE_LEN);
+
+       DATA(packet)[ETH_HLEN - ETHER_TYPE_LEN] = (ethertype >> 8) & 0xFF;
+       DATA(packet)[ETH_HLEN - ETHER_TYPE_LEN + 1] = ethertype & 0xFF;
+}
+
+static bool read_packet(vpn_packet_t *packet) {
+       int lenin = read(device_fd, DATA(packet) + ETH_HLEN, MTU - ETH_HLEN);
+       if(lenin <= 0) {
+               logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from fd/%d: %s!", device_fd, strerror(errno));
+               return false;
+       }
+
+       uint16_t ethertype = get_ip_ethertype(packet);
+       if(ethertype == ETH_P_MAX) {
+               logger(DEBUG_TRAFFIC, LOG_ERR, "Unknown IP version while reading packet from fd/%d!", device_fd);
+               return false;
+       }
+
+       set_etherheader(packet, ethertype);
+       packet->len = lenin + ETH_HLEN;
+
+       logger(DEBUG_TRAFFIC, LOG_DEBUG, "Read packet of %d bytes from fd/%d.", packet->len, device_fd);
+
+       return true;
+}
+
+static bool write_packet(vpn_packet_t *packet) {
+       logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to fd/%d.", packet->len, device_fd);
+
+       if(write(device_fd, DATA(packet) + ETH_HLEN, packet->len - ETH_HLEN) < 0) {
+               logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to fd/%d: %s!", device_fd, strerror(errno));
+               return false;
+       }
+
+       return true;
+}
+
+const devops_t fd_devops = {
+       .setup = setup_device,
+       .close = close_device,
+       .read = read_packet,
+       .write = write_packet,
+};
index 7080869520d3e6b4b1bf1bac3fbef6b6a9613c47..69ca48877b9ff590ab433464c66db44c97ef3ef3 100644 (file)
--- a/src/net.h
+++ b/src/net.h
@@ -126,8 +126,9 @@ typedef struct outgoing_t {
        int timeout;
        splay_tree_t *config_tree;
        struct config_t *cfg;
-       struct addrinfo *ai;
+       struct addrinfo *ai;  // addresses from config files
        struct addrinfo *aip;
+       struct addrinfo *kai; // addresses known via other online nodes (use free_known_addresses())
        timeout_t ev;
 } outgoing_t;
 
index 9293c1189bd014d576d62c2e79113fb2edca4895..f5fddd4eb3b3bc8e5b8df28063cd23bc3831d0ea 100644 (file)
@@ -929,6 +929,8 @@ static bool setup_myself(void) {
                        devops = raw_socket_devops;
                else if(!strcasecmp(type, "multicast"))
                        devops = multicast_devops;
+               else if(!strcasecmp(type, "fd"))
+                       devops = fd_devops;
 #ifdef ENABLE_UML
                else if(!strcasecmp(type, "uml"))
                        devops = uml_devops;
index 8259d9a534172e79cefa11afc72de5d150e16e00..a1934e9f7320fd05cc0c7b95fd0362e6dc6900ec 100644 (file)
@@ -441,13 +441,20 @@ static void handle_meta_io(void *data, int flags) {
                handle_meta_connection_data(c);
 }
 
+static void free_known_addresses(struct addrinfo *ai) {
+       for(struct addrinfo *aip = ai, *next; aip; aip = next) {
+               next = aip->ai_next;
+               free(aip);
+       }
+}
+
 bool do_outgoing_connection(outgoing_t *outgoing) {
        char *address, *port, *space;
        struct addrinfo *proxyai = NULL;
        int result;
 
 begin:
-       if(!outgoing->ai) {
+       if(!outgoing->ai && !outgoing->kai) {
                if(!outgoing->cfg) {
                        logger(DEBUG_CONNECTIONS, LOG_ERR, "Could not set up a meta connection to %s", outgoing->name);
                        retry_outgoing(outgoing);
@@ -477,6 +484,11 @@ begin:
                if(outgoing->ai)
                        freeaddrinfo(outgoing->ai);
                outgoing->ai = NULL;
+
+               if(outgoing->kai)
+                       free_known_addresses(outgoing->kai);
+               outgoing->kai = NULL;
+
                goto begin;
        }
 
@@ -570,6 +582,7 @@ begin:
 // Find edges pointing to this node, and use them to build a list of unique, known addresses.
 static struct addrinfo *get_known_addresses(node_t *n) {
        struct addrinfo *ai = NULL;
+       struct addrinfo *oai = NULL;
 
        for splay_each(edge_t, e, n->edge_tree) {
                if(!e->reverse)
@@ -585,16 +598,15 @@ static struct addrinfo *get_known_addresses(node_t *n) {
                if(found)
                        continue;
 
-               struct addrinfo *nai = xzalloc(sizeof *nai);
-               if(ai)
-                       ai->ai_next = nai;
-               ai = nai;
+               oai = ai;
+               ai = xzalloc(sizeof *ai);
                ai->ai_family = e->reverse->address.sa.sa_family;
                ai->ai_socktype = SOCK_STREAM;
                ai->ai_protocol = IPPROTO_TCP;
                ai->ai_addrlen = SALEN(e->reverse->address.sa);
                ai->ai_addr = xmalloc(ai->ai_addrlen);
                memcpy(ai->ai_addr, &e->reverse->address, ai->ai_addrlen);
+               ai->ai_next = oai;
        }
 
        return ai;
@@ -621,8 +633,8 @@ void setup_outgoing_connection(outgoing_t *outgoing) {
 
        if(!outgoing->cfg) {
                if(n)
-                       outgoing->aip = outgoing->ai = get_known_addresses(n);
-               if(!outgoing->ai) {
+                       outgoing->aip = outgoing->kai = get_known_addresses(n);
+               if(!outgoing->kai) {
                        logger(DEBUG_ALWAYS, LOG_DEBUG, "No address known for %s", outgoing->name);
                        goto remove;
                }
@@ -777,6 +789,9 @@ static void free_outgoing(outgoing_t *outgoing) {
        if(outgoing->ai)
                freeaddrinfo(outgoing->ai);
 
+       if(outgoing->kai)
+               free_known_addresses(outgoing->kai);
+
        if(outgoing->config_tree)
                exit_configuration(&outgoing->config_tree);
 
index 224b6d8450955725758302990b327d11efc0a2cd..d4705bde819e1887c189951593d1a1e299e62fcd 100644 (file)
@@ -888,8 +888,10 @@ bool ack_h(connection_t *c, const char *request) {
        socklen_t local_salen = sizeof local_sa;
        if (getsockname(c->socket, &local_sa.sa, &local_salen) < 0)
                logger(DEBUG_ALWAYS, LOG_WARNING, "Could not get local socket address for connection with %s", c->name);
-       else
+       else {
                sockaddr_setport(&local_sa, myport);
+               c->edge->local_address = local_sa;
+       }
        c->edge->weight = (weight + c->estimated_weight) / 2;
        c->edge->connection = c;
        c->edge->options = c->options;
index dc0cf0512f6afcffc32510522192ea6e33150da7..92089b1c6a13d93c3ccfcf09fb6bb4a07f6ae69e 100644 (file)
@@ -132,63 +132,52 @@ bool add_edge_h(connection_t *c, const char *request) {
        e = lookup_edge(from, to);
 
        if(e) {
-               if(e->weight != weight || e->options != options || sockaddrcmp(&e->address, &address)) {
-                       if(from == myself) {
-                               logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) for ourself which does not match existing entry",
-                                                  "ADD_EDGE", c->name, c->hostname);
-                               send_add_edge(c, e);
-                               sockaddrfree(&local_address);
-                               return true;
-                       } else {
-                               logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) which does not match existing entry",
-                                                  "ADD_EDGE", c->name, c->hostname);
-                               e->options = options;
-                               if(sockaddrcmp(&e->address, &address)) {
-                                       sockaddrfree(&e->address);
-                                       e->address = address;
-                               }
-                               if(e->weight != weight) {
-                                       splay_node_t *node = splay_unlink(edge_weight_tree, e);
-                                       e->weight = weight;
-                                       splay_insert_node(edge_weight_tree, node);
-                               }
-
-                               goto done;
-                       }
-               } else if(sockaddrcmp(&e->local_address, &local_address)) {
-                       if(from == myself) {
-                               if(e->local_address.sa.sa_family && local_address.sa.sa_family) {
-                                       // Someone has the wrong local address for ourself. Correct then.
-                                       logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) for ourself which does not match existing entry",
-                                                          "ADD_EDGE", c->name, c->hostname);
-                                       send_add_edge(c, e);
-                                       sockaddrfree(&local_address);
-                                       return true;
-                               }
-                               // Otherwise, just ignore it.
-                               sockaddrfree(&local_address);
-                               return true;
-                       } else if(local_address.sa.sa_family && local_address.sa.sa_family != AF_UNKNOWN) {
-                               // We learned a new local address for this edge.
-                               // local_address.sa.sa_family will be 0 if we got it from older tinc versions
-                               // local_address.sa.sa_family will be 255 (AF_UNKNOWN) if we got it from newer versions
-                               // but for edge which does not have local_address
-                               sockaddrfree(&e->local_address);
-                               e->local_address = local_address;
-
-                               // Tell others about it.
-                               if(!tunnelserver)
-                                       forward_request(c, request);
-
-                               return true;
-                       } else {
-                               sockaddrfree(&local_address);
-                               return true;
-                       }
-               } else {
+               bool new_address = sockaddrcmp(&e->address, &address);
+               // local_address.sa.sa_family will be 0 if we got it from older tinc versions
+               // local_address.sa.sa_family will be 255 (AF_UNKNOWN) if we got it from newer versions
+               // but for edge which does not have local_address
+               bool new_local_address = local_address.sa.sa_family && local_address.sa.sa_family != AF_UNKNOWN &&
+                       sockaddrcmp(&e->local_address, &local_address);
+
+               if(e->weight == weight && e->options == options && !new_address && !new_local_address) {
+                       sockaddrfree(&address);
+                       sockaddrfree(&local_address);
+                       return true;
+               }
+
+               if(from == myself) {
+                       logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) for ourself which does not match existing entry",
+                                          "ADD_EDGE", c->name, c->hostname);
+                       send_add_edge(c, e);
+                       sockaddrfree(&address);
                        sockaddrfree(&local_address);
                        return true;
                }
+
+               logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) which does not match existing entry",
+                                  "ADD_EDGE", c->name, c->hostname);
+
+               e->options = options;
+
+               if(new_address) {
+                       sockaddrfree(&e->address);
+                       e->address = address;
+               } else {
+                       sockaddrfree(&address);
+               }
+
+               if(new_local_address) {
+                       sockaddrfree(&e->local_address);
+                       e->local_address = local_address;
+               } else {
+                       sockaddrfree(&local_address);
+               }
+
+               if(e->weight != weight) {
+                       splay_node_t *node = splay_unlink(edge_weight_tree, e);
+                       e->weight = weight;
+                       splay_insert_node(edge_weight_tree, node);
+               }
        } else if(from == myself) {
                logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) for ourself which does not exist",
                                   "ADD_EDGE", c->name, c->hostname);
@@ -198,20 +187,20 @@ bool add_edge_h(connection_t *c, const char *request) {
                e->to = to;
                send_del_edge(c, e);
                free_edge(e);
+               sockaddrfree(&address);
                sockaddrfree(&local_address);
                return true;
+       } else {
+               e = new_edge();
+               e->from = from;
+               e->to = to;
+               e->address = address;
+               e->local_address = local_address;
+               e->options = options;
+               e->weight = weight;
+               edge_add(e);
        }
 
-       e = new_edge();
-       e->from = from;
-       e->to = to;
-       e->address = address;
-       e->local_address = local_address;
-       e->options = options;
-       e->weight = weight;
-       edge_add(e);
-
-done:
        /* Tell the rest about the new edge */
 
        if(!tunnelserver)
index 1f0246c0aa8234cf7a454e2842d12e799143644c..5067ded5d95fa6385fc65a5f2e02879dcd3d881a 100644 (file)
@@ -1,6 +1,6 @@
 /*
     tincctl.c -- Controlling a running tincd
-    Copyright (C) 2007-2016 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2007-2017 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
@@ -721,6 +721,8 @@ bool connect_tincd(bool verbose) {
        }
 
        fclose(f);
+
+#ifndef HAVE_MINGW
        if ((pid == 0) || (kill(pid, 0) && (errno == ESRCH))) {
                fprintf(stderr, "Could not find tincd running at pid %d\n", pid);
                /* clean up the stale socket and pid file */
@@ -729,7 +731,6 @@ bool connect_tincd(bool verbose) {
                return false;
        }
 
-#ifndef HAVE_MINGW
        struct sockaddr_un sa;
        sa.sun_family = AF_UNIX;
        strncpy(sa.sun_path, unixsocketname, sizeof sa.sun_path);