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 \
*/
#include "system.h"
-#include <assert.h>
#include "splay_tree.h"
#include "connection.h"
*/
#include "system.h"
-#include <assert.h>
#include "logger.h"
#include "meshlink_internal.h"
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
+#include <assert.h>
#ifdef HAVE_MINGW
#include <w32api.h>
#include "netutl.h"
#include "node.h"
#include "protocol.h"
-#include "route.h"
#include "sockaddr.h"
#include "utils.h"
#include "xalloc.h"
if(mesh->conffile) {
fclose(mesh->conffile);
- }
+ }
memset(mesh, 0, sizeof(*mesh));
}
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;
}
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)) {
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) {
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;
bool default_blacklist;
- hash_t *node_udp_cache;
struct connection_t *everyone;
struct ecdsa *invitation_key;
int invitation_timeout;
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;
#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;
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;
#include "net.h"
#include "netutl.h"
#include "protocol.h"
-#include "route.h"
#include "utils.h"
#include "xalloc.h"
/* 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);
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) {
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;
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);
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)) {
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;
}
}
}
-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) {
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));
}
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) {
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);
+ }
}
#include "net.h"
#include "netutl.h"
#include "protocol.h"
-#include "route.h"
#include "utils.h"
#include "xalloc.h"
mesh->pinginterval = 60;
mesh->pingtimeout = 5;
- maxoutbufsize = 10 * MTU;
if(!setup_myself(mesh)) {
return false;
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) {
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) {
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) {
return;
}
- hash_insert(mesh->node_udp_cache, &n->address, NULL);
-
if(sa) {
n->address = *sa;
n->sock = 0;
}
}
- hash_insert(mesh->node_udp_cache, sa, n);
-
meshlink_hint_address(mesh, (meshlink_node_t *)n, &sa->sa);
if(mesh->log_level >= MESHLINK_DEBUG) {
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;
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
/* 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) {
/* 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 */
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 *);
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
#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) {
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);
}
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];
#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;
#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;
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;
-}
+++ /dev/null
-/*
- 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;
-}
+++ /dev/null
-#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
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) {
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;
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;
#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
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;
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);