]> git.meshlink.io Git - meshlink/commitdiff
Move the routing header out of the SPTPS payload. outer-routing
authorGuus Sliepen <guus@meshlink.io>
Thu, 8 Nov 2018 19:27:54 +0000 (20:27 +0100)
committerGuus Sliepen <guus@meshlink.io>
Sun, 18 Nov 2018 23:25:50 +0000 (00:25 +0100)
Give every node in the mesh a unique ID (based on a hash of its name), and
add the ID of the source and destination packet at the start of a UDP
packet, before the SPTPS payload. This allows fast forwarding of packets,
and avoids having to look up nodes based on UDP address/port.

21 files changed:
src/Makefile.am
src/conf.c
src/devtools.c
src/have.h
src/meshlink.c
src/meshlink_internal.h
src/net.c
src/net.h
src/net_packet.c
src/net_setup.c
src/node.c
src/node.h
src/protocol.c
src/protocol.h
src/protocol_auth.c
src/protocol_key.c
src/protocol_misc.c
src/route.c [deleted file]
src/route.h [deleted file]
src/sptps.c
src/sptps.h

index ef0d8d9e800f9d663e2fa9c95fad41d546db7569..51c3daf2e849815788eadb6bd6a66d8f45c9201c 100644 (file)
@@ -70,7 +70,6 @@ libmeshlink_la_SOURCES = \
        protocol_edge.c \
        protocol_key.c \
        protocol_misc.c \
-       route.c route.h \
        sockaddr.h \
        splay_tree.c splay_tree.h \
        sptps.c sptps.h \
index e3574ea5442888b3fa3edee6886040264f2378c5..9e4ce4b984d833fa6fcd9f58dc43ec5eee3b0404 100644 (file)
@@ -18,7 +18,6 @@
 */
 
 #include "system.h"
-#include <assert.h>
 
 #include "splay_tree.h"
 #include "connection.h"
index 3f2c0a4942797ff24d931ffccdec65fcdac6d043..859a3bee134b7144fdc3ea5016bf29c466735a7f 100644 (file)
@@ -18,7 +18,6 @@
 */
 
 #include "system.h"
-#include <assert.h>
 
 #include "logger.h"
 #include "meshlink_internal.h"
index 536226d5826d54335c71678cb6ccfe6a0073b547..ff714a6997e887f19e1d74c1412bc326b6d78b6a 100644 (file)
@@ -42,6 +42,7 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <limits.h>
+#include <assert.h>
 
 #ifdef HAVE_MINGW
 #include <w32api.h>
index 8da56922aa5735828f0e598773c613fb3b13d645..048f72e502dae2e5873a3c75b67c2595db285099 100644 (file)
@@ -38,7 +38,6 @@ typedef struct {
 #include "netutl.h"
 #include "node.h"
 #include "protocol.h"
-#include "route.h"
 #include "sockaddr.h"
 #include "utils.h"
 #include "xalloc.h"
@@ -1457,7 +1456,7 @@ void meshlink_close(meshlink_handle_t *mesh) {
 
        if(mesh->conffile) {
                fclose(mesh->conffile);
-        }
+       }
 
        memset(mesh, 0, sizeof(*mesh));
 
@@ -1535,10 +1534,8 @@ void meshlink_set_log_cb(meshlink_handle_t *mesh, meshlink_log_level_t level, me
 }
 
 bool meshlink_send(meshlink_handle_t *mesh, meshlink_node_t *destination, const void *data, size_t len) {
-       meshlink_packethdr_t *hdr;
-
        // Validate arguments
-       if(!mesh || !destination || len >= MAXSIZE - sizeof(*hdr)) {
+       if(!mesh || !destination || len >= MAXSIZE) {
                meshlink_errno = MESHLINK_EINVAL;
                return false;
        }
@@ -1562,16 +1559,11 @@ bool meshlink_send(meshlink_handle_t *mesh, meshlink_node_t *destination, const
 
        packet->probe = false;
        packet->tcp = false;
-       packet->len = len + sizeof(*hdr);
-
-       hdr = (meshlink_packethdr_t *)packet->data;
-       memset(hdr, 0, sizeof(*hdr));
-       // leave the last byte as 0 to make sure strings are always
-       // null-terminated if they are longer than the buffer
-       strncpy((char *)hdr->destination, destination->name, (sizeof(hdr)->destination) - 1);
-       strncpy((char *)hdr->source, mesh->self->name, (sizeof(hdr)->source) - 1);
+       packet->len = len;
+       packet->src = mesh->self->id;
+       packet->dst = ((node_t *)destination)->id;
 
-       memcpy(packet->data + sizeof(*hdr), data, len);
+       memcpy(packet->data, data, len);
 
        // Queue it
        if(!meshlink_queue_push(&mesh->outpacketqueue, packet)) {
@@ -1596,7 +1588,13 @@ void meshlink_send_from_queue(event_loop_t *loop, meshlink_handle_t *mesh) {
 
        mesh->self->in_packets++;
        mesh->self->in_bytes += packet->len;
-       route(mesh, mesh->self, packet);
+       node_t *dest = lookup_node_id(mesh, packet->dst);
+
+       if(dest) {
+               send_packet(mesh, dest, packet);
+       }
+
+       free(packet);
 }
 
 ssize_t meshlink_get_pmtu(meshlink_handle_t *mesh, meshlink_node_t *destination) {
index 92774c49baf3c9481d4aac62273256156c77d629..ac35f2765302c619121b9b3bcc5e37550dc8f819 100644 (file)
@@ -89,6 +89,7 @@ struct meshlink_handle {
        struct splay_tree_t *config;
        struct splay_tree_t *edges;
        struct splay_tree_t *nodes;
+       struct splay_tree_t *node_ids;
 
        struct list_t *connections;
        struct list_t *outgoings;
@@ -119,7 +120,6 @@ struct meshlink_handle {
 
        bool default_blacklist;
 
-       hash_t *node_udp_cache;
        struct connection_t *everyone;
        struct ecdsa *invitation_key;
        int invitation_timeout;
@@ -163,12 +163,6 @@ struct meshlink_channel {
        meshlink_channel_poll_cb_t poll_cb;
 };
 
-/// Header for data packets routed between nodes
-typedef struct meshlink_packethdr {
-       uint8_t destination[16];
-       uint8_t source[16];
-} __attribute__((__packed__)) meshlink_packethdr_t;
-
 extern void meshlink_send_from_queue(event_loop_t *el, meshlink_handle_t *mesh);
 extern void update_node_status(meshlink_handle_t *mesh, struct node_t *n);
 extern meshlink_log_level_t global_log_level;
index 9d5e81719392d7027a970f9238fea35a1adfe229..806fe0d28baa189180622dd1fd31ea055e35b847 100644 (file)
--- a/src/net.c
+++ b/src/net.c
@@ -31,8 +31,6 @@
 #include "protocol.h"
 #include "xalloc.h"
 
-#include <assert.h>
-
 #if !defined(min)
 static inline int min(int a, int b) {
        return a < b ? a : b;
index 04bd55a50a0a5ff42fc50d2f314738f32d6b58a6..757d15e6ef90e8ed72a034d26953fb4798ff5266 100644 (file)
--- a/src/net.h
+++ b/src/net.h
@@ -41,6 +41,9 @@ typedef struct vpn_packet_t {
                unsigned int tcp: 1;
        };
        uint16_t len;           /* the actual number of bytes in the `data' field */
+
+       uint64_t src;
+       uint64_t dst;
        uint8_t data[MAXSIZE];
 } vpn_packet_t;
 
index 162dcef2075ea571d467a1ac3b7d18f9de24f18e..b8c513044ffdc24ae7230b0ea75daa3176fc87ca 100644 (file)
@@ -28,7 +28,6 @@
 #include "net.h"
 #include "netutl.h"
 #include "protocol.h"
-#include "route.h"
 #include "utils.h"
 #include "xalloc.h"
 
@@ -204,25 +203,7 @@ static void mtu_probe_h(meshlink_handle_t *mesh, node_t *n, vpn_packet_t *packet
 
 /* VPN packet I/O */
 
-static void receive_packet(meshlink_handle_t *mesh, node_t *n, vpn_packet_t *packet) {
-       logger(mesh, MESHLINK_DEBUG, "Received packet of %d bytes from %s", packet->len, n->name);
-
-       if(n->status.blacklisted) {
-               logger(mesh, MESHLINK_WARNING, "Dropping packet from blacklisted node %s", n->name);
-       } else {
-               n->in_packets++;
-               n->in_bytes += packet->len;
-
-               route(mesh, n, packet);
-       }
-}
-
-static bool try_mac(meshlink_handle_t *mesh, node_t *n, const vpn_packet_t *inpkt) {
-       (void)mesh;
-       return sptps_verify_datagram(&n->sptps, inpkt->data, inpkt->len);
-}
-
-static void receive_udppacket(meshlink_handle_t *mesh, node_t *n, vpn_packet_t *inpkt) {
+static void receive_udppacket(meshlink_handle_t *mesh, node_t *n, const void *data, uint16_t len) {
        if(!n->sptps.state) {
                if(!n->status.waitingforkey) {
                        logger(mesh, MESHLINK_DEBUG, "Got packet from %s but we haven't exchanged keys yet", n->name);
@@ -234,7 +215,7 @@ static void receive_udppacket(meshlink_handle_t *mesh, node_t *n, vpn_packet_t *
                return;
        }
 
-       sptps_receive_data(&n->sptps, inpkt->data, inpkt->len);
+       sptps_receive_data(&n->sptps, data, len);
 }
 
 static void send_sptps_packet(meshlink_handle_t *mesh, node_t *n, vpn_packet_t *origpkt) {
@@ -400,7 +381,14 @@ bool send_sptps_data(void *handle, uint8_t type, const void *data, size_t len) {
                choose_udp_address(mesh, to, &sa, &sock);
        }
 
-       if(sendto(mesh->listen_socket[sock].udp.fd, data, len, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) {
+       /* Add the source and destination IDs */
+
+       vpn_packet_t pkt;
+       pkt.src = mesh->self->id;
+       pkt.dst = to->id;
+       memcpy(pkt.data, data, len);
+
+       if(sendto(mesh->listen_socket[sock].udp.fd, &pkt.src, len + 16, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) {
                if(sockmsgsize(sockerrno)) {
                        if(to->maxmtu >= len) {
                                to->maxmtu = len - 1;
@@ -422,6 +410,8 @@ bool receive_sptps_record(void *handle, uint8_t type, const void *data, uint16_t
        node_t *from = handle;
        meshlink_handle_t *mesh = from->mesh;
 
+       assert(!from->status.blacklisted);
+
        if(type == SPTPS_HANDSHAKE) {
                if(!from->status.validkey) {
                        logger(mesh, MESHLINK_INFO, "SPTPS key exchange with %s succesful", from->name);
@@ -441,16 +431,52 @@ bool receive_sptps_record(void *handle, uint8_t type, const void *data, uint16_t
                return false;
        }
 
-       vpn_packet_t inpkt;
+       if(type == SPTPS_UNENCRYPTED) {
+               /* This is a packet that needs to be forwarded */
+               struct {
+                       uint64_t src;
+                       uint64_t dst;
+               } hdr;
+
+               if(len < sizeof(hdr)) {
+                       logger(mesh, MESHLINK_ERROR, "Too short packet from %s", from->name);
+                       return false;
+               }
+
+               memcpy(&hdr, data, sizeof(hdr));
+
+               if(hdr.src == mesh->self->id) {
+                       logger(mesh, MESHLINK_WARNING, "Dropping packet from ourself");
+                       return true;
+               }
+
+               node_t *orig = lookup_node_id(mesh, hdr.src);
+
+               if(!orig) {
+                       logger(mesh, MESHLINK_ERROR, "Received packet from %s with unknown source", from->name);
+                       return true;
+               }
+
+               if(orig->status.blacklisted) {
+                       logger(mesh, MESHLINK_WARNING, "Dropping packet from blacklisted node %s", orig->name);
+                       return true;
+               }
+
+               if(hdr.dst == mesh->self->id) {
+                       receive_udppacket(mesh, orig, data, len);
+               }
+
+               // TODO: forward
+               return true;
+       }
 
        if(type == PKT_PROBE) {
+               vpn_packet_t inpkt;
                inpkt.len = len;
                inpkt.probe = true;
                memcpy(inpkt.data, data, len);
                mtu_probe_h(mesh, from, &inpkt, len);
                return true;
-       } else {
-               inpkt.probe = false;
        }
 
        if(type & ~(PKT_COMPRESSED)) {
@@ -463,10 +489,10 @@ bool receive_sptps_record(void *handle, uint8_t type, const void *data, uint16_t
                return false;
        }
 
-       memcpy(inpkt.data, data, len); // TODO: get rid of memcpy
-       inpkt.len = len;
+       if(mesh->receive_cb) {
+               mesh->receive_cb(mesh, (meshlink_node_t *)from, data, len);
+       }
 
-       receive_packet(mesh, from, &inpkt);
        return true;
 }
 
@@ -511,38 +537,37 @@ void broadcast_packet(meshlink_handle_t *mesh, const node_t *from, vpn_packet_t
                }
 }
 
-static node_t *try_harder(meshlink_handle_t *mesh, const sockaddr_t *from, const vpn_packet_t *pkt) {
-       node_t *n = NULL;
-       bool hard = false;
-       static time_t last_hard_try = 0;
+void forward_udppacket(meshlink_handle_t *mesh, const node_t *from, vpn_packet_t *pkt) {
+       node_t *to = lookup_node_id(mesh, pkt->dst);
 
-       for splay_each(edge_t, e, mesh->edges) {
-               if(!e->to->status.reachable || e->to == mesh->self) {
-                       continue;
-               }
+       if(!to) {
+               logger(mesh, MESHLINK_WARNING, "Received UDP packet from %s with unknown destination", from->name);
+               return;
+       }
 
-               if(sockaddrcmp_noport(from, &e->address)) {
-                       if(last_hard_try == mesh->loop.now.tv_sec) {
-                               continue;
-                       }
+       if(pkt->len > to->minmtu) {
+               // send via TCP
+               abort();
+       }
 
-                       hard = true;
-               }
+       const sockaddr_t *sa;
+       int sock;
 
-               if(!try_mac(mesh, e->to, pkt)) {
-                       continue;
-               }
+       choose_udp_address(mesh, to, &sa, &sock);
 
-               n = e->to;
-               break;
-       }
+       if(sendto(mesh->listen_socket[sock].udp.fd, &pkt->src, pkt->len + 16, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) {
+               if(sockmsgsize(sockerrno)) {
+                       if(to->maxmtu >= pkt->len) {
+                               to->maxmtu = pkt->len - 1;
+                       }
 
-       if(hard) {
-               last_hard_try = mesh->loop.now.tv_sec;
+                       if(to->mtu >= pkt->len) {
+                               to->mtu = pkt->len - 1;
+                       }
+               } else {
+                       logger(mesh, MESHLINK_WARNING, "Error forwarding UDP SPTPS packet to %s: %s", to->name, sockstrerror(sockerrno));
+               }
        }
-
-       last_hard_try = mesh->loop.now.tv_sec;
-       return n;
 }
 
 void handle_incoming_vpn_data(event_loop_t *loop, void *data, int flags) {
@@ -556,9 +581,9 @@ void handle_incoming_vpn_data(event_loop_t *loop, void *data, int flags) {
        node_t *n;
        int len;
 
-       len = recvfrom(ls->udp.fd, pkt.data, MAXSIZE, 0, &from.sa, &fromlen);
+       len = recvfrom(ls->udp.fd, &pkt.src, 16 + MAXSIZE, 0, &from.sa, &fromlen);
 
-       if(len <= 0 || len > MAXSIZE) {
+       if(len <= 16 || len > MAXSIZE + 16) {
                if(!sockwouldblock(sockerrno)) {
                        logger(mesh, MESHLINK_ERROR, "Receiving packet failed: %s", sockstrerror(sockerrno));
                }
@@ -566,25 +591,20 @@ void handle_incoming_vpn_data(event_loop_t *loop, void *data, int flags) {
                return;
        }
 
-       pkt.len = len;
+       if(!pkt.src || !pkt.dst) {
+               logger(mesh, MESHLINK_WARNING, "Unhandled NULL ids in packet header");
+               return;
+       }
 
-       sockaddrunmap(&from); /* Some braindead IPv6 implementations do stupid things. */
+       pkt.len = len - 16;
 
-       n = lookup_node_udp(mesh, &from);
+       n = lookup_node_id(mesh, pkt.src);
 
        if(!n) {
-               n = try_harder(mesh, &from, &pkt);
-
-               if(n) {
-                       update_node_udp(mesh, n, &from);
-               } else if(mesh->log_level >= MESHLINK_WARNING) {
-                       hostname = sockaddr2hostname(&from);
-                       logger(mesh, MESHLINK_WARNING, "Received UDP packet from unknown source %s", hostname);
-                       free(hostname);
-                       return;
-               } else {
-                       return;
-               }
+               hostname = sockaddr2hostname(&from);
+               logger(mesh, MESHLINK_WARNING, "Received UDP packet from unknown source %s", hostname);
+               free(hostname);
+               return;
        }
 
        if(n->status.blacklisted) {
@@ -592,7 +612,20 @@ void handle_incoming_vpn_data(event_loop_t *loop, void *data, int flags) {
                return;
        }
 
+       if(n == mesh->self) {
+               logger(mesh, MESHLINK_WARNING, "Dropping packet from ourself");
+               return;
+       }
+
        n->sock = ls - mesh->listen_socket;
 
-       receive_udppacket(mesh, n, &pkt);
+       if(sockaddrcmp_noport(&n->address, &from)) {
+               update_node_udp(mesh, n, &from);
+       }
+
+       if(pkt.dst != mesh->self->id) {
+               forward_udppacket(mesh, n, &pkt);
+       } else {
+               receive_udppacket(mesh, n, pkt.data, pkt.len);
+       }
 }
index 10fb37b0005c5df5ae73b35bf33a66a9591796ac..811d9811a1430a85872396b1619d516aa2d07772 100644 (file)
@@ -28,7 +28,6 @@
 #include "net.h"
 #include "netutl.h"
 #include "protocol.h"
-#include "route.h"
 #include "utils.h"
 #include "xalloc.h"
 
@@ -469,7 +468,6 @@ bool setup_network(meshlink_handle_t *mesh) {
 
        mesh->pinginterval = 60;
        mesh->pingtimeout = 5;
-       maxoutbufsize = 10 * MTU;
 
        if(!setup_myself(mesh)) {
                return false;
index 4f4f599932caa1d6985afdc689b1a9d43b670310..164520aa302c0997b29a36e71f3424c1da48ab62 100644 (file)
@@ -33,22 +33,32 @@ static int node_compare(const node_t *a, const node_t *b) {
        return strcmp(a->name, b->name);
 }
 
+static int node_id_compare(const node_t *a, const node_t *b) {
+       if(a->id < b->id) {
+               return -1;
+       } else if(a->id == b->id) {
+               return 0;
+       } else {
+               return 1;
+       }
+}
+
 void init_nodes(meshlink_handle_t *mesh) {
        mesh->nodes = splay_alloc_tree((splay_compare_t) node_compare, (splay_action_t) free_node);
-       mesh->node_udp_cache = hash_alloc(0x100, sizeof(sockaddr_t));
+       mesh->node_ids = splay_alloc_tree((splay_compare_t) node_id_compare, NULL);
 }
 
 void exit_nodes(meshlink_handle_t *mesh) {
-       if(mesh->node_udp_cache) {
-               hash_free(mesh->node_udp_cache);
-       }
-
        if(mesh->nodes) {
                splay_delete_tree(mesh->nodes);
        }
 
-       mesh->node_udp_cache = NULL;
+       if(mesh->node_ids) {
+               splay_delete_tree(mesh->node_ids);
+       }
+
        mesh->nodes = NULL;
+       mesh->node_ids = NULL;
 }
 
 node_t *new_node(void) {
@@ -88,6 +98,7 @@ void free_node(node_t *n) {
 void node_add(meshlink_handle_t *mesh, node_t *n) {
        n->mesh = mesh;
        splay_insert(mesh->nodes, n);
+       update_node_id(mesh, n);
 }
 
 void node_del(meshlink_handle_t *mesh, node_t *n) {
@@ -102,15 +113,65 @@ void node_del(meshlink_handle_t *mesh, node_t *n) {
 
 node_t *lookup_node(meshlink_handle_t *mesh, const char *name) {
        const node_t n = {.name = (char *)name};
-       node_t *result;
-
-       result = splay_search(mesh->nodes, &n);
+       return splay_search(mesh->nodes, &n);
+}
 
-       return result;
+node_t *lookup_node_id(meshlink_handle_t *mesh, uint64_t id) {
+       const node_t n = {.id = id};
+       return splay_search(mesh->node_ids, &n);
 }
 
-node_t *lookup_node_udp(meshlink_handle_t *mesh, const sockaddr_t *sa) {
-       return hash_search(mesh->node_udp_cache, sa);
+void update_node_id(meshlink_handle_t *mesh, node_t *n) {
+       if(n->id) {
+               logger(mesh, LOG_WARNING, "Node %s already has id %"PRIu64"\n", n->name, n->id);
+               return;
+       }
+
+       struct {
+               uint8_t public[32];
+               uint32_t gen;
+       } input;
+
+       uint8_t hash[64];
+       uint64_t id;
+
+       memset(&input, 0, sizeof input);
+
+       strncpy(input.public, n->name, sizeof input.public);
+       input.gen = 0;
+
+       while(true) {
+               sha512(&input, sizeof input, hash);
+               memcpy(&id, hash, sizeof id);
+               input.gen++;
+
+               // ID 0 is reserved
+               if(!id) {
+                       continue;
+               }
+
+               // Check if there is a conflict with an existing node
+               node_t *other = lookup_node_id(mesh, id);
+               int cmp = other ? strcmp(n->name, other->name) : 0;
+
+               // If yes and we sort after the other, try again
+               if(cmp > 0) {
+                       continue;
+               }
+
+               if(other) {
+                       splay_delete(mesh->node_ids, other);
+               }
+
+               n->id = id;
+               splay_insert(mesh->node_ids, n);
+
+               if(other) {
+                       update_node_id(mesh, other);
+               }
+
+               break;
+       }
 }
 
 void update_node_udp(meshlink_handle_t *mesh, node_t *n, const sockaddr_t *sa) {
@@ -119,8 +180,6 @@ void update_node_udp(meshlink_handle_t *mesh, node_t *n, const sockaddr_t *sa) {
                return;
        }
 
-       hash_insert(mesh->node_udp_cache, &n->address, NULL);
-
        if(sa) {
                n->address = *sa;
                n->sock = 0;
@@ -132,8 +191,6 @@ void update_node_udp(meshlink_handle_t *mesh, node_t *n, const sockaddr_t *sa) {
                        }
                }
 
-               hash_insert(mesh->node_udp_cache, sa, n);
-
                meshlink_hint_address(mesh, (meshlink_node_t *)n, &sa->sa);
 
                if(mesh->log_level >= MESHLINK_DEBUG) {
index eaba79d0b01ae8bb959c773947d046688540cf81..3314feef55577123f6fc21bfcf5f2fd5c8a9d8a0 100644 (file)
@@ -53,6 +53,8 @@ typedef struct node_t {
        int sock;                               /* Socket to use for outgoing UDP packets */
        sockaddr_t address;                     /* his real (internet) ip to send UDP packets to */
 
+       uint64_t id;                            /* Unique ID for this node */
+
        node_status_t status;
        time_t last_state_change;
        time_t last_req_key;
@@ -95,7 +97,8 @@ extern void free_node(node_t *);
 extern void node_add(struct meshlink_handle *mesh, node_t *);
 extern void node_del(struct meshlink_handle *mesh, node_t *);
 extern node_t *lookup_node(struct meshlink_handle *mesh, const char *);
-extern node_t *lookup_node_udp(struct meshlink_handle *mesh, const sockaddr_t *);
+extern node_t *lookup_node_id(struct meshlink_handle *mesh, uint64_t id);
 extern void update_node_udp(struct meshlink_handle *mesh, node_t *, const sockaddr_t *);
+extern void update_node_id(struct meshlink_handle *mesh, node_t *);
 
 #endif
index 785e20b534b83213f9ed28b01941cce34b494e86..6736cae7750471a0354c94c9f9499e75bea38a4f 100644 (file)
 /* Jumptable for the request handlers */
 
 static bool (*request_handlers[])(meshlink_handle_t *, connection_t *, const char *) = {
-       id_h, NULL, NULL, NULL /* metakey_h, challenge_h, chal_reply_h */, ack_h,
-       status_h, error_h, termreq_h,
-       ping_h, pong_h,
-       NULL, NULL, //add_subnet_h, del_subnet_h,
-       add_edge_h, del_edge_h,
-       key_changed_h, req_key_h, ans_key_h, tcppacket_h, NULL, //control_h,
+       id_h,
+       ack_h,
+       ping_h,
+       pong_h,
+       add_edge_h,
+       del_edge_h,
+       req_key_h,
+       ans_key_h,
 };
 
 /* Request names */
 
 static char (*request_name[]) = {
-       "ID", "METAKEY", "CHALLENGE", "CHAL_REPLY", "ACK",
-       "STATUS", "ERROR", "TERMREQ",
-       "PING", "PONG",
-       "ADD_SUBNET", "DEL_SUBNET",
-       "ADD_EDGE", "DEL_EDGE", "KEY_CHANGED", "REQ_KEY", "ANS_KEY", "PACKET", "CONTROL",
+       "ID",
+       "ACK",
+       "PING",
+       "PONG",
+       "ADD_EDGE",
+       "DEL_EDGE",
+       "REQ_KEY",
+       "ANS_KEY",
 };
 
 bool check_id(const char *id) {
index 92ccef01482f7d8882b431c35420812cdac55a3a..4bf76ee9b278166f3580976f3a86311199f3888a 100644 (file)
@@ -24,8 +24,8 @@
 
 /* Protocol version. Different major versions are incompatible. */
 
-#define PROT_MAJOR 17
-#define PROT_MINOR 3 /* Should not exceed 255! */
+#define PROT_MAJOR 18
+#define PROT_MINOR 0 /* Should not exceed 255! */
 
 /* Silly Windows */
 
 
 typedef enum request_t {
        ALL = -1,                                       /* Guardian for allow_request */
-       ID = 0, METAKEY, CHALLENGE, CHAL_REPLY, ACK,
-       STATUS, ERROR, TERMREQ,
-       PING, PONG,
-       ADD_SUBNET, DEL_SUBNET,
-       ADD_EDGE, DEL_EDGE,
-       KEY_CHANGED, REQ_KEY, ANS_KEY,
-       PACKET,
+       ID = 0,
+       ACK,
+       PING,
+       PONG,
+       ADD_EDGE,
+       DEL_EDGE,
+       REQ_KEY,
+       ANS_KEY,
        /* Tinc 1.1 requests */
-       CONTROL,
        REQ_PUBKEY, ANS_PUBKEY,
        REQ_SPTPS,
        LAST                                            /* Guardian for the highest request number */
@@ -87,16 +87,12 @@ extern bool send_ping(struct meshlink_handle *mesh, struct connection_t *);
 extern bool send_pong(struct meshlink_handle *mesh, struct connection_t *);
 extern bool send_add_edge(struct meshlink_handle *mesh, struct connection_t *, const struct edge_t *, int contradictions);
 extern bool send_del_edge(struct meshlink_handle *mesh, struct connection_t *, const struct edge_t *, int contradictions);
-extern void send_key_changed(struct meshlink_handle *mesh);
 extern bool send_req_key(struct meshlink_handle *mesh, struct node_t *);
 
 /* Request handlers  */
 
 extern bool id_h(struct meshlink_handle *mesh, struct connection_t *, const char *);
 extern bool ack_h(struct meshlink_handle *mesh, struct connection_t *, const char *);
-extern bool status_h(struct meshlink_handle *mesh, struct connection_t *, const char *);
-extern bool error_h(struct meshlink_handle *mesh, struct connection_t *, const char *);
-extern bool termreq_h(struct meshlink_handle *mesh, struct connection_t *, const char *);
 extern bool ping_h(struct meshlink_handle *mesh, struct connection_t *, const char *);
 extern bool pong_h(struct meshlink_handle *mesh, struct connection_t *, const char *);
 extern bool add_edge_h(struct meshlink_handle *mesh, struct connection_t *, const char *);
@@ -104,6 +100,5 @@ extern bool del_edge_h(struct meshlink_handle *mesh, struct connection_t *, cons
 extern bool key_changed_h(struct meshlink_handle *mesh, struct connection_t *, const char *);
 extern bool req_key_h(struct meshlink_handle *mesh, struct connection_t *, const char *);
 extern bool ans_key_h(struct meshlink_handle *mesh, struct connection_t *, const char *);
-extern bool tcppacket_h(struct meshlink_handle *mesh, struct connection_t *, const char *);
 
 #endif
index e56aa88132d3977031fc08e4a4bf57de1add1aa8..6227e45596a72331f44194995e89a1fff2275e94 100644 (file)
@@ -37,8 +37,6 @@
 #include "xalloc.h"
 #include "ed25519/sha512.h"
 
-#include <assert.h>
-
 extern bool node_write_devclass(meshlink_handle_t *mesh, node_t *n);
 
 static bool send_proxyrequest(meshlink_handle_t *mesh, connection_t *c) {
@@ -342,8 +340,8 @@ bool id_h(meshlink_handle_t *mesh, connection_t *c, const char *request) {
 
                free(mykey);
 
-               c->protocol_minor = 2;
-               c->allow_request = 1;
+               c->protocol_minor = PROT_MINOR;
+               c->allow_request = LAST;
 
                return sptps_start(&c->sptps, c, false, false, mesh->invitation_key, c->ecdsa, meshlink_invitation_label, sizeof(meshlink_invitation_label), send_meta_sptps, receive_invitation_sptps);
        }
@@ -410,14 +408,6 @@ bool id_h(meshlink_handle_t *mesh, connection_t *c, const char *request) {
                return false;
        }
 
-       /* Forbid version rollback for nodes whose ECDSA key we know */
-
-       if(ecdsa_active(c->ecdsa) && c->protocol_minor < 2) {
-               logger(mesh, MESHLINK_ERROR, "Peer %s tries to roll back protocol version to %d.%d",
-                      c->name, c->protocol_major, c->protocol_minor);
-               return false;
-       }
-
        c->allow_request = ACK;
        char label[sizeof(meshlink_tcp_label) + strlen(mesh->self->name) + strlen(c->name) + 2];
 
index cae95047220341def5d777f2e01f58ed309d6c53..4218c055a6c6a997dfda6325983826c1d0206379 100644 (file)
 #include "utils.h"
 #include "xalloc.h"
 
-void send_key_changed(meshlink_handle_t *mesh) {
-       send_request(mesh, mesh->everyone, "%d %x %s", KEY_CHANGED, rand(), mesh->self->name);
-
-       /* Force key exchange for connections using SPTPS */
-
-       for splay_each(node_t, n, mesh->nodes)
-               if(n->status.reachable && n->status.validkey) {
-                       sptps_force_kex(&n->sptps);
-               }
-}
-
-bool key_changed_h(meshlink_handle_t *mesh, connection_t *c, const char *request) {
-       char name[MAX_STRING_SIZE];
-       node_t *n;
-
-       if(sscanf(request, "%*d %*x " MAX_STRING, name) != 1) {
-               logger(mesh, MESHLINK_ERROR, "Got bad %s from %s", "KEY_CHANGED", c->name);
-               return false;
-       }
-
-       if(seen_request(mesh, request)) {
-               return true;
-       }
-
-       n = lookup_node(mesh, name);
-
-       if(!n) {
-               logger(mesh, MESHLINK_ERROR, "Got %s from %s origin %s which does not exist", "KEY_CHANGED", c->name, name);
-               return true;
-       }
-
-       /* Tell the others */
-
-       forward_request(mesh, c, request);
-
-       return true;
-}
-
 static bool send_initial_sptps_data(void *handle, uint8_t type, const void *data, size_t len) {
        (void)type;
        node_t *to = handle;
index 727881bd1080476d2c5d9303b76d315f702cc2a0..b2e30680c576074f89507543208dbdea9f9f820a 100644 (file)
 #include "protocol.h"
 #include "utils.h"
 
-int maxoutbufsize = 0;
-
-/* Status and error notification routines */
-
-bool status_h(meshlink_handle_t *mesh, connection_t *c, const char *request) {
-       int statusno;
-       char statusstring[MAX_STRING_SIZE];
-
-       if(sscanf(request, "%*d %d " MAX_STRING, &statusno, statusstring) != 2) {
-               logger(mesh, MESHLINK_ERROR, "Got bad %s from %s", "STATUS", c->name);
-               return false;
-       }
-
-       logger(mesh, MESHLINK_INFO, "Status message from %s: %d: %s", c->name, statusno, statusstring);
-
-       return true;
-}
-
-bool error_h(meshlink_handle_t *mesh, connection_t *c, const char *request) {
-       int err;
-       char errorstring[MAX_STRING_SIZE];
-
-       if(sscanf(request, "%*d %d " MAX_STRING, &err, errorstring) != 2) {
-               logger(mesh, MESHLINK_ERROR, "Got bad %s from %s", "ERROR", c->name);
-               return false;
-       }
-
-       logger(mesh, MESHLINK_INFO, "Error message from %s: %d: %s", c->name, err, errorstring);
-
-       return false;
-}
-
-bool termreq_h(meshlink_handle_t *mesh, connection_t *c, const char *request) {
-       (void)mesh;
-       (void)c;
-       (void)request;
-       return false;
-}
-
 bool send_ping(meshlink_handle_t *mesh, connection_t *c) {
        c->status.pinged = true;
        c->last_ping_time = mesh->loop.now.tv_sec;
@@ -105,17 +66,3 @@ bool pong_h(meshlink_handle_t *mesh, connection_t *c, const char *request) {
 
        return true;
 }
-
-/* Sending and receiving packets via TCP */
-
-bool tcppacket_h(meshlink_handle_t *mesh, connection_t *c, const char *request) {
-       short int len;
-
-       if(sscanf(request, "%*d %hd", &len) != 1) {
-               logger(mesh, MESHLINK_ERROR, "Got bad %s from %s", "PACKET", c->name);
-               return false;
-       }
-
-       // This should never happen with MeshLink.
-       return false;
-}
diff --git a/src/route.c b/src/route.c
deleted file mode 100644 (file)
index f7a728d..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
-    route.c -- routing
-    Copyright (C) 2014 Guus Sliepen <guus@meshlink.io>
-
-    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 "logger.h"
-#include "meshlink_internal.h"
-#include "net.h"
-#include "route.h"
-#include "utils.h"
-
-bool decrement_ttl = false;
-
-static bool checklength(node_t *source, vpn_packet_t *packet, uint16_t length) {
-       if(packet->len < length) {
-               logger(source->mesh, MESHLINK_WARNING, "Got too short packet from %s", source->name);
-               return false;
-       } else {
-               return true;
-       }
-}
-
-void route(meshlink_handle_t *mesh, node_t *source, vpn_packet_t *packet) {
-       // TODO: route on name or key
-
-       node_t *owner = NULL;
-       node_t *via = NULL;
-       meshlink_packethdr_t *hdr = (meshlink_packethdr_t *) packet->data;
-       owner = lookup_node(mesh, (char *)hdr->destination);
-       logger(mesh, MESHLINK_DEBUG, "Routing packet from \"%s\" to \"%s\"\n", hdr->source, hdr->destination);
-
-       //Check Lenght
-       if(!checklength(source, packet, sizeof(*hdr))) {
-               return;
-       }
-
-       if(owner == NULL) {
-               //Lookup failed
-               logger(mesh, MESHLINK_WARNING, "Cant lookup the owner of a packet in the route() function. This should never happen!\n");
-               logger(mesh, MESHLINK_WARNING, "Destination was: %s\n", hdr->destination);
-               return;
-       }
-
-       if(owner == mesh->self) {
-               const void *payload = packet->data + sizeof(*hdr);
-               size_t len = packet->len - sizeof(*hdr);
-
-               char hex[len * 2 + 1];
-
-               if(mesh->log_level >= MESHLINK_DEBUG) {
-                       bin2hex(payload, hex, len);        // don't do this unless it's going to be logged
-               }
-
-               logger(mesh, MESHLINK_DEBUG, "I received a packet for me with payload: %s\n", hex);
-
-               if(mesh->receive_cb) {
-                       mesh->receive_cb(mesh, (meshlink_node_t *)source, payload, len);
-               }
-
-               return;
-       }
-
-       if(!owner->status.reachable) {
-               //TODO: check what to do here, not just print a warning
-               logger(mesh, MESHLINK_WARNING, "The owner of a packet in the route() function is unreachable. Dropping packet.\n");
-               return;
-       }
-
-       via = (owner->via == mesh->self) ? owner->nexthop : owner->via;
-
-       if(via == source) {
-               logger(mesh, MESHLINK_ERROR, "Routing loop for packet from %s!", source->name);
-               return;
-       }
-
-       send_packet(mesh, owner, packet);
-       return;
-}
diff --git a/src/route.h b/src/route.h
deleted file mode 100644 (file)
index 16e3a97..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef MESHLINK_ROUTE_H
-#define MESHLINK_ROUTE_H
-
-/*
-    route.h -- header file for route.c
-    Copyright (C) 2014, 2017 Guus Sliepen <guus@meshlink.io>
-
-    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 "net.h"
-#include "node.h"
-
-extern bool decrement_ttl;
-
-extern void route(struct meshlink_handle *mesh, struct node_t *, struct vpn_packet_t *);
-
-#endif
index f44374ee4bf472b7fea3127ff3b777ffa26aa517..a83382562abd5f4ec67171e6cf6bb2442df8a537 100644 (file)
@@ -106,6 +106,7 @@ static bool send_record_priv_datagram(sptps_t *s, uint8_t type, const void *data
                return s->send_data(s->handle, type, buffer, len + 5UL);
        }
 }
+
 // Send a record (private version, accepts all record types, handles encryption and authentication).
 static bool send_record_priv(sptps_t *s, uint8_t type, const void *data, uint16_t len) {
        if(s->datagram) {
@@ -147,6 +148,38 @@ bool sptps_send_record(sptps_t *s, uint8_t type, const void *data, uint16_t len)
        return send_record_priv(s, type, data, len);
 }
 
+// Pass through unencrypted data.
+bool sptps_send_unencrypted(sptps_t *s, const void *data, uint16_t len) {
+       // Sanity checks: application cannot send data before handshake is finished,
+       // and only non-datagram allowed.
+       if(!s->outstate) {
+               return error(s, EINVAL, "Handshake phase not finished yet");
+       }
+
+       if(s->datagram) {
+               return error(s, EINVAL, "Not allowed for datagrams");
+       }
+
+       return s->send_data(s->handle, SPTPS_UNENCRYPTED, data, len);
+}
+
+// Expect a given number of unencrypted bytes.
+bool sptps_expect_unencrypted(sptps_t *s, uint16_t len) {
+       // Sanity checks: application cannot send data before handshake is finished,
+       // and only non-datagram allowed.
+       if(!s->instate) {
+               return error(s, EINVAL, "Handshake phase not finished yet");
+       }
+
+       if(s->datagram) {
+               return error(s, EINVAL, "Not allowed for datagrams");
+       }
+
+       s->reclen = len;
+       s->passthrough = true;
+       return true;
+}
+
 // Send a Key EXchange record, containing a random nonce and an ECDHE public key.
 static bool send_kex(sptps_t *s) {
        size_t keylen = ECDH_SIZE;
@@ -564,6 +597,46 @@ bool sptps_receive_data(sptps_t *s, const void *data, size_t len) {
        const char *ptr = data;
 
        while(len) {
+               if(s->passthrough) {
+                       if(!s->buflen && s->reclen <= len) {
+                               len -= s->reclen;
+                               ptr += s->reclen;
+
+                               s->reclen = 0;
+                               s->passthrough = false;
+
+                               if(!s->receive_record(s->handle, SPTPS_UNENCRYPTED, data, s->reclen)) {
+                                       return false;
+                               }
+
+                               continue;
+                       }
+
+                       size_t toread = s->reclen - s->buflen;
+                       if (toread >= len) {
+                               toread = len;
+                       }
+
+                       memcpy(s->inbuf + s->buflen, ptr, toread);
+                       s->buflen += toread;
+                       len -= toread;
+                       ptr += toread;
+
+                       if(s->buflen < s->reclen) {
+                               return;
+                       }
+
+                       s->reclen = 0;
+                       s->passthrough = false;
+
+                       if(!s->receive_record(s->handle, SPTPS_UNENCRYPTED, data, s->reclen)) {
+                               return false;
+                       }
+
+                       s->buflen = 0;
+                       continue;
+               }
+
                // First read the 2 length bytes.
                if(s->buflen < 2) {
                        size_t toread = 2 - s->buflen;
index 11c0d2e66846390df29b12edf4b88a9c45c9ec79..ba37733eb9c2803721143eced63711c4e6ef7787 100644 (file)
@@ -32,6 +32,7 @@
 #define SPTPS_HANDSHAKE 128   // Key exchange and authentication
 #define SPTPS_ALERT 129       // Warning or error messages
 #define SPTPS_CLOSE 130       // Application closed the connection
+#define SPTPS_UNENCRYPTED 131 // Unencrypted data
 
 // Key exchange states
 #define SPTPS_KEX 1           // Waiting for the first Key EXchange record
@@ -45,13 +46,16 @@ typedef bool (*receive_record_t)(void *handle, uint8_t type, const void *data, u
 typedef struct sptps {
        bool initiator;
        bool datagram;
+
+       bool instate;
+       bool passthrough;
+
        int state;
 
        char *inbuf;
        size_t buflen;
        uint16_t reclen;
 
-       bool instate;
        chacha_poly1305_ctx_t *incipher;
        uint32_t inseqno;
        uint32_t received;
@@ -84,6 +88,8 @@ extern void (*sptps_log)(sptps_t *s, int s_errno, const char *format, va_list ap
 extern bool sptps_start(sptps_t *s, void *handle, bool initiator, bool datagram, ecdsa_t *mykey, ecdsa_t *hiskey, const char *label, size_t labellen, send_data_t send_data, receive_record_t receive_record);
 extern bool sptps_stop(sptps_t *s);
 extern bool sptps_send_record(sptps_t *s, uint8_t type, const void *data, uint16_t len);
+extern bool sptps_send_unencrypted(sptps_t *s, const void *data, uint16_t len);
+extern bool sptps_expect_unencrypted(sptps_t *s, uint16_t len);
 extern bool sptps_receive_data(sptps_t *s, const void *data, size_t len);
 extern bool sptps_force_kex(sptps_t *s);
 extern bool sptps_verify_datagram(sptps_t *s, const void *data, size_t len);