ed25519/keypair.c \
ed25519/precomp_data.h \
ed25519/sc.c ed25519/sc.h \
- ed25519/seed.c \
ed25519/sha512.c ed25519/sha512.h \
ed25519/sign.c \
ed25519/verify.c
/*
device.c -- Interaction BSD tun/tap device
Copyright (C) 2001-2005 Ivo Timmermans,
- 2001-2013 Guus Sliepen <guus@tinc-vpn.org>
+ 2001-2014 Guus Sliepen <guus@tinc-vpn.org>
2009 Grzegorz Dymarek <gregd72002@googlemail.com>
This program is free software; you can redistribute it and/or modify
#ifdef ENABLE_TUNEMU
case DEVICE_TYPE_TUNEMU:
if(device_type == DEVICE_TYPE_TUNEMU)
- inlen = tunemu_read(device_fd, packet->data + 14, MTU - 14);
+ inlen = tunemu_read(device_fd, DATA(packet) + 14, MTU - 14);
else
#endif
- inlen = read(device_fd, packet->data + 14, MTU - 14);
+ inlen = read(device_fd, DATA(packet) + 14, MTU - 14);
if(inlen <= 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
return false;
}
- switch(packet->data[14] >> 4) {
+ switch(DATA(packet)[14] >> 4) {
case 4:
- packet->data[12] = 0x08;
- packet->data[13] = 0x00;
+ DATA(packet)[12] = 0x08;
+ DATA(packet)[13] = 0x00;
break;
case 6:
- packet->data[12] = 0x86;
- packet->data[13] = 0xDD;
+ DATA(packet)[12] = 0x86;
+ DATA(packet)[13] = 0xDD;
break;
default:
logger(DEBUG_TRAFFIC, LOG_ERR,
"Unknown IP version %d while reading packet from %s %s",
- packet->data[14] >> 4, device_info, device);
+ DATA(packet)[14] >> 4, device_info, device);
return false;
}
- memset(packet->data, 0, 12);
+ memset(DATA(packet), 0, 12);
packet->len = inlen + 14;
break;
case DEVICE_TYPE_TUNIFHEAD: {
u_int32_t type;
- struct iovec vector[2] = {{&type, sizeof type}, {packet->data + 14, MTU - 14}};
+ struct iovec vector[2] = {{&type, sizeof type}, {DATA(packet) + 14, MTU - 14}};
if((inlen = readv(device_fd, vector, 2)) <= 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
switch (ntohl(type)) {
case AF_INET:
- packet->data[12] = 0x08;
- packet->data[13] = 0x00;
+ DATA(packet)[12] = 0x08;
+ DATA(packet)[13] = 0x00;
break;
case AF_INET6:
- packet->data[12] = 0x86;
- packet->data[13] = 0xDD;
+ DATA(packet)[12] = 0x86;
+ DATA(packet)[13] = 0xDD;
break;
default:
return false;
}
- memset(packet->data, 0, 12);
+ memset(DATA(packet), 0, 12);
packet->len = inlen + 10;
break;
}
case DEVICE_TYPE_TAP:
- if((inlen = read(device_fd, packet->data, MTU)) <= 0) {
+ if((inlen = read(device_fd, DATA(packet), MTU)) <= 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
device, strerror(errno));
return false;
switch(device_type) {
case DEVICE_TYPE_TUN:
- if(write(device_fd, packet->data + 14, packet->len - 14) < 0) {
+ if(write(device_fd, DATA(packet) + 14, packet->len - 14) < 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info,
device, strerror(errno));
return false;
case DEVICE_TYPE_TUNIFHEAD: {
u_int32_t type;
- struct iovec vector[2] = {{&type, sizeof type}, {packet->data + 14, packet->len - 14}};
+ struct iovec vector[2] = {{&type, sizeof type}, {DATA(packet) + 14, packet->len - 14}};
int af;
- af = (packet->data[12] << 8) + packet->data[13];
+ af = (DATA(packet)[12] << 8) + DATA(packet)[13];
switch (af) {
case 0x0800:
}
case DEVICE_TYPE_TAP:
- if(write(device_fd, packet->data, packet->len) < 0) {
+ if(write(device_fd, DATA(packet), packet->len) < 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info,
device, strerror(errno));
return false;
#ifdef ENABLE_TUNEMU
case DEVICE_TYPE_TUNEMU:
- if(tunemu_write(device_fd, packet->data + 14, packet->len - 14) < 0) {
+ if(tunemu_write(device_fd, DATA(packet) + 14, packet->len - 14) < 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info,
device, strerror(errno));
return false;
/*
device.c -- Interaction with Windows tap driver in a Cygwin environment
Copyright (C) 2002-2005 Ivo Timmermans,
- 2002-2013 Guus Sliepen <guus@tinc-vpn.org>
+ 2002-2014 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
static bool read_packet(vpn_packet_t *packet) {
int inlen;
- if((inlen = read(sp[0], packet->data, MTU)) <= 0) {
+ if((inlen = read(sp[0], DATA(packet), MTU)) <= 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
device, strerror(errno));
return false;
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s",
packet->len, device_info);
- if(!WriteFile (device_handle, packet->data, packet->len, &outlen, NULL)) {
+ if(!WriteFile (device_handle, DATA(packet), packet->len, &outlen, NULL)) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError()));
return false;
}
+++ /dev/null
-#include "ed25519.h"
-
-#ifndef ED25519_NO_SEED
-
-#ifdef _WIN32
-#include <windows.h>
-#include <wincrypt.h>
-#else
-#include <stdio.h>
-#endif
-
-int ed25519_create_seed(unsigned char *seed) {
-#ifdef _WIN32
- HCRYPTPROV prov;
-
- if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
- return 1;
- }
-
- if (!CryptGenRandom(prov, 32, seed)) {
- CryptReleaseContext(prov, 0);
- return 1;
- }
-
- CryptReleaseContext(prov, 0);
-#else
- FILE *f = fopen("/dev/urandom", "rb");
-
- if (f == NULL) {
- return 1;
- }
-
- fread(seed, 1, 32, f);
- fclose(f);
-#endif
-
- return 0;
-}
-
-#endif
\ No newline at end of file
update_node_udp(n, NULL);
memset(&n->status, 0, sizeof n->status);
n->options = 0;
- } else if(n->connection) {
- if(n->status.sptps) {
- if(n->connection->outgoing)
- send_req_key(n);
- } else {
- send_ans_key(n);
- }
}
}
return NULL;
}
+/* Deleting */
+
+void hash_delete(hash_t *hash, const void *key) {
+ uint32_t i = modulo(hash_function(key, hash->size), hash->n);
+ hash->values[i] = NULL;
+}
+
/* Utility functions */
void hash_clear(hash_t *hash) {
extern void hash_free(hash_t *);
extern void hash_insert(hash_t *, const void *key, const void *value);
+extern void hash_delete(hash_t *, const void *key);
extern void *hash_search(const hash_t *, const void *key);
extern void *hash_search_or_insert(hash_t *, const void *key, const void *value);
char line[4096];
char node[4096];
+ char id[4096];
char from[4096];
char to[4096];
char subnet[4096];
long int last_state_change;
while(recvline(fd, line, sizeof line)) {
- int n = sscanf(line, "%d %d %s %s port %s %d %d %d %d %x %"PRIx32" %s %s %d %hd %hd %hd %ld", &code, &req, node, host, port, &cipher, &digest, &maclength, &compression, &options, &status_union.raw, nexthop, via, &distance, &pmtu, &minmtu, &maxmtu, &last_state_change);
+ int n = sscanf(line, "%d %d %s %s %s port %s %d %d %d %d %x %"PRIx32" %s %s %d %hd %hd %hd %ld", &code, &req, node, id, host, port, &cipher, &digest, &maclength, &compression, &options, &status_union.raw, nexthop, via, &distance, &pmtu, &minmtu, &maxmtu, &last_state_change);
if(n == 2)
break;
- if(n != 18) {
+ if(n != 19) {
fprintf(stderr, "Unable to parse node dump from tincd.\n");
return 1;
}
}
printf("Node: %s\n", item);
+ printf("Node ID: %s\n", id);
printf("Address: %s port %s\n", host, port);
char timestr[32] = "never";
}
-static bool invitation_send(void *handle, uint8_t type, const char *data, size_t len) {
+static bool invitation_send(void *handle, uint8_t type, const void *data, size_t len) {
while(len) {
int result = send(sock, data, len, 0);
if(result == -1 && errno == EINTR)
return true;
}
-static bool invitation_receive(void *handle, uint8_t type, const char *msg, uint16_t len) {
+static bool invitation_receive(void *handle, uint8_t type, const void *msg, uint16_t len) {
switch(type) {
case SPTPS_HANDSHAKE:
return sptps_send_record(&sptps, 0, cookie, sizeof cookie);
/*
device.c -- Interaction with Linux ethertap and tun/tap device
Copyright (C) 2001-2005 Ivo Timmermans,
- 2001-2013 Guus Sliepen <guus@tinc-vpn.org>
+ 2001-2014 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
logger(DEBUG_ALWAYS, LOG_INFO, "%s is a %s", device, device_info);
+ if(ifr.ifr_flags & IFF_TAP) {
+ struct ifreq ifr_mac = {};
+ if(!ioctl(device_fd, SIOCGIFHWADDR, &ifr_mac))
+ memcpy(mymac.x, ifr_mac.ifr_hwaddr.sa_data, ETH_ALEN);
+ else
+ logger(DEBUG_ALWAYS, LOG_WARNING, "Could not get MAC address of %s: %s", device, strerror(errno));
+ }
+
return true;
}
switch(device_type) {
case DEVICE_TYPE_TUN:
- inlen = read(device_fd, packet->data + 10, MTU - 10);
+ inlen = read(device_fd, DATA(packet) + 10, MTU - 10);
if(inlen <= 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s",
return false;
}
- memset(packet->data, 0, 12);
+ memset(DATA(packet), 0, 12);
packet->len = inlen + 10;
break;
case DEVICE_TYPE_TAP:
- inlen = read(device_fd, packet->data, MTU);
+ inlen = read(device_fd, DATA(packet), MTU);
if(inlen <= 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s",
switch(device_type) {
case DEVICE_TYPE_TUN:
- packet->data[10] = packet->data[11] = 0;
- if(write(device_fd, packet->data + 10, packet->len - 10) < 0) {
+ DATA(packet)[10] = DATA(packet)[11] = 0;
+ if(write(device_fd, DATA(packet) + 10, packet->len - 10) < 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device,
strerror(errno));
return false;
}
break;
case DEVICE_TYPE_TAP:
- if(write(device_fd, packet->data, packet->len) < 0) {
+ if(write(device_fd, DATA(packet), packet->len) < 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device,
strerror(errno));
return false;
/*
meta.c -- handle the meta communication
- Copyright (C) 2000-2013 Guus Sliepen <guus@tinc-vpn.org>,
+ Copyright (C) 2000-2014 Guus Sliepen <guus@tinc-vpn.org>,
2000-2005 Ivo Timmermans
2006 Scott Lamb <slamb@slamb.org>
#include "utils.h"
#include "xalloc.h"
-bool send_meta_sptps(void *handle, uint8_t type, const char *buffer, size_t length) {
+bool send_meta_sptps(void *handle, uint8_t type, const void *buffer, size_t length) {
connection_t *c = handle;
if(!c) {
send_meta(c, buffer, length);
}
-bool receive_meta_sptps(void *handle, uint8_t type, const char *data, uint16_t length) {
+bool receive_meta_sptps(void *handle, uint8_t type, const void *vdata, uint16_t length) {
+ const char *data = vdata;
connection_t *c = handle;
if(!c) {
/*
meta.h -- header for meta.c
- Copyright (C) 2000-2012 Guus Sliepen <guus@tinc-vpn.org>,
+ Copyright (C) 2000-2014 Guus Sliepen <guus@tinc-vpn.org>,
2000-2005 Ivo Timmermans
This program is free software; you can redistribute it and/or modify
#include "connection.h"
extern bool send_meta(struct connection_t *, const char *, int);
-extern bool send_meta_sptps(void *, uint8_t, const char *, size_t);
-extern bool receive_meta_sptps(void *, uint8_t, const char *, uint16_t);
+extern bool send_meta_sptps(void *, uint8_t, const void *, size_t);
+extern bool receive_meta_sptps(void *, uint8_t, const void *, uint16_t);
extern void broadcast_meta(struct connection_t *, const char *, int);
extern bool receive_meta(struct connection_t *);
/*
device.c -- Interaction with Windows tap driver in a MinGW environment
Copyright (C) 2002-2005 Ivo Timmermans,
- 2002-2013 Guus Sliepen <guus@tinc-vpn.org>
+ 2002-2014 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
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s",
packet->len, device_info);
- if(!WriteFile(device_handle, packet->data, packet->len, &outlen, &overlapped)) {
+ if(!WriteFile(device_handle, DATA(packet), packet->len, &outlen, &overlapped)) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError()));
return false;
}
static bool read_packet(vpn_packet_t *packet) {
int lenin;
- if((lenin = recv(device_fd, (void *)packet->data, MTU, 0)) <= 0) {
+ if((lenin = recv(device_fd, DATA(packet), MTU, 0)) <= 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
device, sockstrerror(sockerrno));
return false;
}
- if(!memcmp(&ignore_src, packet->data + 6, sizeof ignore_src)) {
+ if(!memcmp(&ignore_src, DATA(packet) + 6, sizeof ignore_src)) {
logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Ignoring loopback packet of %d bytes from %s", lenin, device_info);
return false;
}
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s",
packet->len, device_info);
- if(sendto(device_fd, (void *)packet->data, packet->len, 0, ai->ai_addr, ai->ai_addrlen) < 0) {
+ if(sendto(device_fd, DATA(packet), packet->len, 0, ai->ai_addr, ai->ai_addrlen) < 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device,
sockstrerror(sockerrno));
return false;
}
- memcpy(&ignore_src, packet->data + 6, sizeof ignore_src);
+ memcpy(&ignore_src, DATA(packet) + 6, sizeof ignore_src);
return true;
}
#define MTU 1518 /* 1500 bytes payload + 14 bytes ethernet header + 4 bytes VLAN tag */
#endif
-/* MAXSIZE is the maximum size of an encapsulated packet: MTU + seqno + padding + HMAC + compressor overhead */
-#define MAXSIZE (MTU + 4 + CIPHER_MAX_BLOCK_SIZE + DIGEST_MAX_SIZE + MTU/64 + 20)
+/* MAXSIZE is the maximum size of an encapsulated packet: MTU + seqno + srcid + dstid + padding + HMAC + compressor overhead */
+#define MAXSIZE (MTU + 4 + sizeof(node_id_t) + sizeof(node_id_t) + CIPHER_MAX_BLOCK_SIZE + DIGEST_MAX_SIZE + MTU/64 + 20)
/* MAXBUFSIZE is the maximum size of a request: enough for a MAXSIZEd packet or a 8192 bits RSA key */
#define MAXBUFSIZE ((MAXSIZE > 2048 ? MAXSIZE : 2048) + 128)
uint16_t x[8];
} ipv6_t;
+typedef struct node_id_t {
+ uint8_t x[6];
+} node_id_t;
+
typedef short length_t;
+typedef uint32_t seqno_t;
#define AF_UNKNOWN 255
#define SALEN(s) (s.sa_family==AF_INET?sizeof(struct sockaddr_in):sizeof(struct sockaddr_in6))
#endif
+#define SEQNO(x) ((x)->data + (x)->offset - 4)
+#define SRCID(x) ((node_id_t *)((x)->data + (x)->offset - 6))
+#define DSTID(x) ((node_id_t *)((x)->data + (x)->offset - 12))
+#define DATA(x) ((x)->data + (x)->offset)
+#define DEFAULT_PACKET_OFFSET 12
+
typedef struct vpn_packet_t {
- length_t len; /* the actual number of bytes in the `data' field */
+ length_t len; /* The actual number of valid bytes in the `data' field (including seqno or dstid/srcid) */
+ length_t offset; /* Offset in the buffer where the packet data starts (righter after seqno or dstid/srcid) */
int priority; /* priority or TOS */
- uint32_t seqno; /* 32 bits sequence number (network byte order of course) */
uint8_t data[MAXSIZE];
} vpn_packet_t;
extern void handle_new_unix_connection(void *, int);
extern int setup_listen_socket(const sockaddr_t *);
extern int setup_vpn_in_socket(const sockaddr_t *);
-extern bool send_sptps_data(void *handle, uint8_t type, const char *data, size_t len);
-extern bool receive_sptps_record(void *handle, uint8_t type, const char *data, uint16_t len);
+extern bool send_sptps_data(void *handle, uint8_t type, const void *data, size_t len);
+extern bool receive_sptps_record(void *handle, uint8_t type, const void *data, uint16_t len);
extern void send_packet(struct node_t *, vpn_packet_t *);
extern void receive_tcppacket(struct connection_t *, const char *, int);
extern void broadcast_packet(const struct node_t *, vpn_packet_t *);
/*
net_packet.c -- Handles in- and outgoing VPN packets
Copyright (C) 1998-2005 Ivo Timmermans,
- 2000-2013 Guus Sliepen <guus@tinc-vpn.org>
+ 2000-2014 Guus Sliepen <guus@tinc-vpn.org>
2010 Timothy Redaelli <timothy@redaelli.eu>
2010 Brandon Black <blblack@gmail.com>
len = 64;
vpn_packet_t packet;
- memset(packet.data, 0, 14);
- randomize(packet.data + 14, len - 14);
+ packet.offset = DEFAULT_PACKET_OFFSET;
+ memset(DATA(&packet), 0, 14);
+ randomize(DATA(&packet) + 14, len - 14);
packet.len = len;
packet.priority = 0;
n->status.send_locally = i >= 4 && n->mtuprobes <= 10 && n->prevedge;
}
static void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) {
- if(!packet->data[0]) {
+ if(!DATA(packet)[0]) {
logger(DEBUG_TRAFFIC, LOG_INFO, "Got MTU probe request %d from %s (%s)", packet->len, n->name, n->hostname);
/* It's a probe request, send back a reply */
/* Type 2 probe replies were introduced in protocol 17.3 */
if ((n->options >> 24) >= 3) {
- uint8_t* data = packet->data;
+ uint8_t *data = DATA(packet);
*data++ = 2;
uint16_t len16 = htons(len); memcpy(data, &len16, 2); data += 2;
struct timeval now;
gettimeofday(&now, NULL);
uint32_t sec = htonl(now.tv_sec); memcpy(data, &sec, 4); data += 4;
uint32_t usec = htonl(now.tv_usec); memcpy(data, &usec, 4); data += 4;
- packet->len = data - packet->data;
+ packet->len -= 10;
} else {
/* Legacy protocol: n won't understand type 2 probe replies. */
- packet->data[0] = 1;
+ DATA(packet)[0] = 1;
}
/* Temporarily set udp_confirmed, so that the reply is sent
n->status.udp_confirmed = udp_confirmed;
} else {
length_t probelen = len;
- if (packet->data[0] == 2) {
+ if (DATA(packet)[0] == 2) {
if (len < 3)
logger(DEBUG_TRAFFIC, LOG_WARNING, "Received invalid (too short) MTU probe reply from %s (%s)", n->name, n->hostname);
else {
- uint16_t probelen16; memcpy(&probelen16, packet->data + 1, 2); probelen = ntohs(probelen16);
+ uint16_t probelen16; memcpy(&probelen16, DATA(packet) + 1, 2); probelen = ntohs(probelen16);
}
}
- logger(DEBUG_TRAFFIC, LOG_INFO, "Got type %d MTU probe reply %d from %s (%s)", packet->data[0], probelen, n->name, n->hostname);
+ logger(DEBUG_TRAFFIC, LOG_INFO, "Got type %d MTU probe reply %d from %s (%s)", DATA(packet)[0], probelen, n->name, n->hostname);
/* It's a valid reply: now we know bidirectional communication
is possible using the address and socket that the reply
timersub(&now, &n->probe_time, &diff);
struct timeval probe_timestamp = now;
- if (packet->data[0] == 2 && packet->len >= 11) {
- uint32_t sec; memcpy(&sec, packet->data + 3, 4);
- uint32_t usec; memcpy(&usec, packet->data + 7, 4);
+ if (DATA(packet)[0] == 2 && packet->len >= 11) {
+ uint32_t sec; memcpy(&sec, DATA(packet) + 3, 4);
+ uint32_t usec; memcpy(&usec, DATA(packet) + 7, 4);
probe_timestamp.tv_sec = ntohl(sec);
probe_timestamp.tv_usec = ntohl(usec);
}
static bool try_mac(node_t *n, const vpn_packet_t *inpkt) {
if(n->status.sptps)
- return sptps_verify_datagram(&n->sptps, (char *)&inpkt->seqno, inpkt->len);
+ return sptps_verify_datagram(&n->sptps, DATA(inpkt), inpkt->len);
- if(!digest_active(n->indigest) || inpkt->len < sizeof inpkt->seqno + digest_length(n->indigest))
+ if(!digest_active(n->indigest) || inpkt->len < sizeof(seqno_t) + digest_length(n->indigest))
return false;
- return digest_verify(n->indigest, &inpkt->seqno, inpkt->len - digest_length(n->indigest), (const char *)&inpkt->seqno + inpkt->len - digest_length(n->indigest));
+ return digest_verify(n->indigest, SEQNO(inpkt), inpkt->len - digest_length(n->indigest), DATA(inpkt) + inpkt->len - digest_length(n->indigest));
}
-static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
+static bool receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
vpn_packet_t pkt1, pkt2;
vpn_packet_t *pkt[] = { &pkt1, &pkt2, &pkt1, &pkt2 };
int nextpkt = 0;
size_t outlen;
+ pkt1.offset = DEFAULT_PACKET_OFFSET;
+ pkt2.offset = DEFAULT_PACKET_OFFSET;
if(n->status.sptps) {
if(!n->sptps.state) {
} else {
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got packet from %s (%s) but he hasn't got our key yet", n->name, n->hostname);
}
- return;
+ return false;
}
- sptps_receive_data(&n->sptps, (char *)&inpkt->seqno, inpkt->len);
- return;
+ inpkt->offset += 2 * sizeof(node_id_t);
+ if(!sptps_receive_data(&n->sptps, DATA(inpkt), inpkt->len - 2 * sizeof(node_id_t))) {
+ logger(DEBUG_TRAFFIC, LOG_ERR, "Got bad packet from %s (%s)", n->name, n->hostname);
+ return false;
+ }
+ return true;
}
if(!n->status.validkey) {
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got packet from %s (%s) but he hasn't got our key yet", n->name, n->hostname);
- return;
+ return false;
}
/* Check packet length */
- if(inpkt->len < sizeof inpkt->seqno + digest_length(n->indigest)) {
+ if(inpkt->len < sizeof(seqno_t) + digest_length(n->indigest)) {
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got too short packet from %s (%s)",
n->name, n->hostname);
- return;
+ return false;
}
+ /* It's a legacy UDP packet, the data starts after the seqno */
+
+ inpkt->offset += sizeof(seqno_t);
+
/* Check the message authentication code */
if(digest_active(n->indigest)) {
inpkt->len -= digest_length(n->indigest);
- if(!digest_verify(n->indigest, &inpkt->seqno, inpkt->len, (const char *)&inpkt->seqno + inpkt->len)) {
+ if(!digest_verify(n->indigest, SEQNO(inpkt), inpkt->len, SEQNO(inpkt) + inpkt->len)) {
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got unauthenticated packet from %s (%s)", n->name, n->hostname);
- return;
+ return false;
}
}
/* Decrypt the packet */
vpn_packet_t *outpkt = pkt[nextpkt++];
outlen = MAXSIZE;
- if(!cipher_decrypt(n->incipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) {
+ if(!cipher_decrypt(n->incipher, SEQNO(inpkt), inpkt->len, SEQNO(outpkt), &outlen, true)) {
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Error decrypting packet from %s (%s)", n->name, n->hostname);
- return;
+ return false;
}
outpkt->len = outlen;
/* Check the sequence number */
- inpkt->len -= sizeof inpkt->seqno;
- inpkt->seqno = ntohl(inpkt->seqno);
+ seqno_t seqno;
+ memcpy(&seqno, SEQNO(inpkt), sizeof seqno);
+ seqno = ntohl(seqno);
+ inpkt->len -= sizeof seqno;
if(replaywin) {
- if(inpkt->seqno != n->received_seqno + 1) {
- if(inpkt->seqno >= n->received_seqno + replaywin * 8) {
+ if(seqno != n->received_seqno + 1) {
+ if(seqno >= n->received_seqno + replaywin * 8) {
if(n->farfuture++ < replaywin >> 2) {
logger(DEBUG_ALWAYS, LOG_WARNING, "Packet from %s (%s) is %d seqs in the future, dropped (%u)",
- n->name, n->hostname, inpkt->seqno - n->received_seqno - 1, n->farfuture);
- return;
+ n->name, n->hostname, seqno - n->received_seqno - 1, n->farfuture);
+ return false;
}
logger(DEBUG_ALWAYS, LOG_WARNING, "Lost %d packets from %s (%s)",
- inpkt->seqno - n->received_seqno - 1, n->name, n->hostname);
+ seqno - n->received_seqno - 1, n->name, n->hostname);
memset(n->late, 0, replaywin);
- } else if (inpkt->seqno <= n->received_seqno) {
- if((n->received_seqno >= replaywin * 8 && inpkt->seqno <= n->received_seqno - replaywin * 8) || !(n->late[(inpkt->seqno / 8) % replaywin] & (1 << inpkt->seqno % 8))) {
+ } else if (seqno <= n->received_seqno) {
+ if((n->received_seqno >= replaywin * 8 && seqno <= n->received_seqno - replaywin * 8) || !(n->late[(seqno / 8) % replaywin] & (1 << seqno % 8))) {
logger(DEBUG_ALWAYS, LOG_WARNING, "Got late or replayed packet from %s (%s), seqno %d, last received %d",
- n->name, n->hostname, inpkt->seqno, n->received_seqno);
- return;
+ n->name, n->hostname, seqno, n->received_seqno);
+ return false;
}
} else {
- for(int i = n->received_seqno + 1; i < inpkt->seqno; i++)
+ for(int i = n->received_seqno + 1; i < seqno; i++)
n->late[(i / 8) % replaywin] |= 1 << i % 8;
}
}
n->farfuture = 0;
- n->late[(inpkt->seqno / 8) % replaywin] &= ~(1 << inpkt->seqno % 8);
+ n->late[(seqno / 8) % replaywin] &= ~(1 << seqno % 8);
}
- if(inpkt->seqno > n->received_seqno)
- n->received_seqno = inpkt->seqno;
+ if(seqno > n->received_seqno)
+ n->received_seqno = seqno;
n->received++;
if(n->incompression) {
vpn_packet_t *outpkt = pkt[nextpkt++];
- if((outpkt->len = uncompress_packet(outpkt->data, inpkt->data, inpkt->len, n->incompression)) < 0) {
+ if((outpkt->len = uncompress_packet(DATA(outpkt), DATA(inpkt), inpkt->len, n->incompression)) < 0) {
logger(DEBUG_TRAFFIC, LOG_ERR, "Error while uncompressing packet from %s (%s)",
n->name, n->hostname);
- return;
+ return false;
}
inpkt = outpkt;
inpkt->priority = 0;
- if(!inpkt->data[12] && !inpkt->data[13])
+ if(!DATA(inpkt)[12] && !DATA(inpkt)[13])
mtu_probe_h(n, inpkt, origlen);
else
receive_packet(n, inpkt);
+ return true;
}
void receive_tcppacket(connection_t *c, const char *buffer, int len) {
vpn_packet_t outpkt;
+ outpkt.offset = DEFAULT_PACKET_OFFSET;
- if(len > sizeof outpkt.data)
+ if(len > sizeof outpkt.data - outpkt.offset)
return;
outpkt.len = len;
outpkt.priority = 0;
else
outpkt.priority = -1;
- memcpy(outpkt.data, buffer, len);
+ memcpy(DATA(&outpkt), buffer, len);
receive_packet(c->node, &outpkt);
}
+static bool try_sptps(node_t *n) {
+ if(n->status.validkey)
+ return true;
+
+ /* If n is a TCP-only neighbor, we'll only use "cleartext" PACKET
+ messages anyway, so there's no need for SPTPS at all. */
+ if(n->connection && ((myself->options | n->options) & OPTION_TCPONLY))
+ return false;
+
+ logger(DEBUG_TRAFFIC, LOG_INFO, "No valid key known yet for %s (%s)", n->name, n->hostname);
+
+ if(!n->status.waitingforkey)
+ send_req_key(n);
+ else if(n->last_req_key + 10 < now.tv_sec) {
+ logger(DEBUG_ALWAYS, LOG_DEBUG, "No key from %s after 10 seconds, restarting SPTPS", n->name);
+ sptps_stop(&n->sptps);
+ n->status.waitingforkey = false;
+ send_req_key(n);
+ }
+
+ return false;
+}
+
static void send_sptps_packet(node_t *n, vpn_packet_t *origpkt) {
- if(!n->status.validkey) {
- logger(DEBUG_TRAFFIC, LOG_INFO, "No valid key known yet for %s (%s)", n->name, n->hostname);
- if(!n->status.waitingforkey)
- send_req_key(n);
- else if(n->last_req_key + 10 < now.tv_sec) {
- logger(DEBUG_ALWAYS, LOG_DEBUG, "No key from %s after 10 seconds, restarting SPTPS", n->name);
- sptps_stop(&n->sptps);
- n->status.waitingforkey = false;
- send_req_key(n);
- }
+ /* Note: condition order is as intended - even if we have a direct
+ metaconnection, we want to try SPTPS anyway as it's the only way to
+ get UDP going */
+ if(!try_sptps(n) && !n->connection)
return;
- }
uint8_t type = 0;
int offset = 0;
- if(!(origpkt->data[12] | origpkt->data[13])) {
- sptps_send_record(&n->sptps, PKT_PROBE, (char *)origpkt->data, origpkt->len);
+ if(!(DATA(origpkt)[12] | DATA(origpkt)[13])) {
+ sptps_send_record(&n->sptps, PKT_PROBE, (char *)DATA(origpkt), origpkt->len);
return;
}
vpn_packet_t outpkt;
if(n->outcompression) {
- int len = compress_packet(outpkt.data + offset, origpkt->data + offset, origpkt->len - offset, n->outcompression);
+ outpkt.offset = 0;
+ int len = compress_packet(DATA(&outpkt) + offset, DATA(origpkt) + offset, origpkt->len - offset, n->outcompression);
if(len < 0) {
logger(DEBUG_TRAFFIC, LOG_ERR, "Error while compressing packet to %s (%s)", n->name, n->hostname);
} else if(len < origpkt->len - offset) {
}
}
- sptps_send_record(&n->sptps, type, (char *)origpkt->data + offset, origpkt->len - offset);
+ /* If we have a direct metaconnection to n, and we can't use UDP, then
+ don't bother with SPTPS and just use a "plaintext" PACKET message.
+ We don't really care about end-to-end security since we're not
+ sending the message through any intermediate nodes. */
+ if(n->connection && origpkt->len > n->minmtu)
+ send_tcppacket(n->connection, origpkt);
+ else
+ sptps_send_record(&n->sptps, type, DATA(origpkt) + offset, origpkt->len - offset);
return;
}
int origpriority = origpkt->priority;
#endif
+ pkt1.offset = DEFAULT_PACKET_OFFSET;
+ pkt2.offset = DEFAULT_PACKET_OFFSET;
+
if(!n->status.reachable) {
logger(DEBUG_TRAFFIC, LOG_INFO, "Trying to send UDP packet to unreachable node %s (%s)", n->name, n->hostname);
return;
return;
}
- if(n->options & OPTION_PMTU_DISCOVERY && inpkt->len > n->minmtu && (inpkt->data[12] | inpkt->data[13])) {
+ if(n->options & OPTION_PMTU_DISCOVERY && inpkt->len > n->minmtu && (DATA(inpkt)[12] | DATA(inpkt)[13])) {
logger(DEBUG_TRAFFIC, LOG_INFO,
"Packet for %s (%s) larger than minimum MTU, forwarding via %s",
n->name, n->hostname, n != n->nexthop ? n->nexthop->name : "TCP");
if(n->outcompression) {
outpkt = pkt[nextpkt++];
- if((outpkt->len = compress_packet(outpkt->data, inpkt->data, inpkt->len, n->outcompression)) < 0) {
+ if((outpkt->len = compress_packet(DATA(outpkt), DATA(inpkt), inpkt->len, n->outcompression)) < 0) {
logger(DEBUG_TRAFFIC, LOG_ERR, "Error while compressing packet to %s (%s)",
n->name, n->hostname);
return;
/* Add sequence number */
- inpkt->seqno = htonl(++(n->sent_seqno));
- inpkt->len += sizeof inpkt->seqno;
+ seqno_t seqno = htonl(++(n->sent_seqno));
+ memcpy(SEQNO(inpkt), &seqno, sizeof seqno);
+ inpkt->len += sizeof seqno;
/* Encrypt the packet */
outpkt = pkt[nextpkt++];
outlen = MAXSIZE;
- if(!cipher_encrypt(n->outcipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) {
+ if(!cipher_encrypt(n->outcipher, SEQNO(inpkt), inpkt->len, SEQNO(outpkt), &outlen, true)) {
logger(DEBUG_TRAFFIC, LOG_ERR, "Error while encrypting packet to %s (%s)", n->name, n->hostname);
goto end;
}
/* Add the message authentication code */
if(digest_active(n->outdigest)) {
- if(!digest_create(n->outdigest, &inpkt->seqno, inpkt->len, (char *)&inpkt->seqno + inpkt->len)) {
+ if(!digest_create(n->outdigest, SEQNO(inpkt), inpkt->len, SEQNO(inpkt) + inpkt->len)) {
logger(DEBUG_TRAFFIC, LOG_ERR, "Error while encrypting packet to %s (%s)", n->name, n->hostname);
goto end;
}
}
#endif
- if(sendto(listen_socket[sock].udp.fd, (char *) &inpkt->seqno, inpkt->len, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) {
+ if(sendto(listen_socket[sock].udp.fd, SEQNO(inpkt), inpkt->len, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) {
if(sockmsgsize(sockerrno)) {
if(n->maxmtu >= origlen)
n->maxmtu = origlen - 1;
origpkt->len = origlen;
}
-bool send_sptps_data(void *handle, uint8_t type, const char *data, size_t len) {
- node_t *to = handle;
+static bool send_sptps_data_priv(node_t *to, node_t *from, int type, const void *data, size_t len) {
+ node_t *relay = (to->via != myself && (type == PKT_PROBE || (len - SPTPS_DATAGRAM_OVERHEAD) <= to->via->minmtu)) ? to->via : to->nexthop;
+ bool direct = from == myself && to == relay;
+ bool relay_supported = (relay->options >> 24) >= 4;
+ bool tcponly = (myself->options | relay->options) & OPTION_TCPONLY;
- /* Send it via TCP if it is a handshake packet, TCPOnly is in use, or this packet is larger than the MTU. */
+ /* We don't really need the relay's key, but we need to establish a UDP tunnel with it and discover its MTU. */
+ if (!direct && relay_supported && !tcponly)
+ try_sptps(relay);
- if(type >= SPTPS_HANDSHAKE || ((myself->options | to->options) & OPTION_TCPONLY) || (type != PKT_PROBE && (len - SPTPS_DATAGRAM_OVERHEAD) > to->minmtu)) {
+ /* Send it via TCP if it is a handshake packet, TCPOnly is in use, this is a relay packet that the other node cannot understand, or this packet is larger than the MTU.
+ TODO: When relaying, the original sender does not know the end-to-end PMTU (it only knows the PMTU of the first hop).
+ This can lead to scenarios where large packets are sent over UDP to relay, but then relay has no choice but fall back to TCP. */
+
+ if(type == SPTPS_HANDSHAKE || tcponly || (!direct && !relay_supported) || (type != PKT_PROBE && (len - SPTPS_DATAGRAM_OVERHEAD) > relay->minmtu)) {
char buf[len * 4 / 3 + 5];
b64encode(data, buf, len);
/* If no valid key is known yet, send the packets using ANS_KEY requests,
to ensure we get to learn the reflexive UDP address. */
- if(!to->status.validkey) {
+ if(from == myself && !to->status.validkey) {
to->incompression = myself->incompression;
- return send_request(to->nexthop->connection, "%d %s %s %s -1 -1 -1 %d", ANS_KEY, myself->name, to->name, buf, to->incompression);
+ return send_request(to->nexthop->connection, "%d %s %s %s -1 -1 -1 %d", ANS_KEY, from->name, to->name, buf, to->incompression);
} else {
- return send_request(to->nexthop->connection, "%d %s %s %d %s", REQ_KEY, myself->name, to->name, REQ_SPTPS, buf);
+ return send_request(to->nexthop->connection, "%d %s %s %d %s", REQ_KEY, from->name, to->name, REQ_SPTPS, buf);
}
}
- /* Otherwise, send the packet via UDP */
+ size_t overhead = 0;
+ if(relay_supported) overhead += sizeof to->id + sizeof from->id;
+ char buf[len + overhead]; char* buf_ptr = buf;
+ if(relay_supported) {
+ if(direct) {
+ /* Inform the recipient that this packet was sent directly. */
+ node_id_t nullid = {};
+ memcpy(buf_ptr, &nullid, sizeof nullid); buf_ptr += sizeof nullid;
+ } else {
+ memcpy(buf_ptr, &to->id, sizeof to->id); buf_ptr += sizeof to->id;
+ }
+ memcpy(buf_ptr, &from->id, sizeof from->id); buf_ptr += sizeof from->id;
+
+ }
+ /* TODO: if this copy turns out to be a performance concern, change sptps_send_record() to add some "pre-padding" to the buffer and use that instead */
+ memcpy(buf_ptr, data, len); buf_ptr += len;
const sockaddr_t *sa = NULL;
int sock;
-
- if(to->status.send_locally)
- choose_local_address(to, &sa, &sock);
+ if(relay->status.send_locally)
+ choose_local_address(relay, &sa, &sock);
if(!sa)
- choose_udp_address(to, &sa, &sock);
-
- if(sendto(listen_socket[sock].udp.fd, data, len, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) {
+ choose_udp_address(relay, &sa, &sock);
+ logger(DEBUG_TRAFFIC, LOG_INFO, "Sending packet from %s (%s) to %s (%s) via %s (%s)", from->name, from->hostname, to->name, to->hostname, relay->name, relay->hostname);
+ if(sendto(listen_socket[sock].udp.fd, buf, buf_ptr - buf, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) {
if(sockmsgsize(sockerrno)) {
// Compensate for SPTPS overhead
len -= SPTPS_DATAGRAM_OVERHEAD;
- if(to->maxmtu >= len)
- to->maxmtu = len - 1;
- if(to->mtu >= len)
- to->mtu = len - 1;
+ if(relay->maxmtu >= len)
+ relay->maxmtu = len - 1;
+ if(relay->mtu >= len)
+ relay->mtu = len - 1;
} else {
- logger(DEBUG_TRAFFIC, LOG_WARNING, "Error sending UDP SPTPS packet to %s (%s): %s", to->name, to->hostname, sockstrerror(sockerrno));
+ logger(DEBUG_TRAFFIC, LOG_WARNING, "Error sending UDP SPTPS packet to %s (%s): %s", relay->name, relay->hostname, sockstrerror(sockerrno));
return false;
}
}
return true;
}
-bool receive_sptps_record(void *handle, uint8_t type, const char *data, uint16_t len) {
+bool send_sptps_data(void *handle, uint8_t type, const void *data, size_t len) {
+ return send_sptps_data_priv(handle, myself, type, data, len);
+}
+
+bool receive_sptps_record(void *handle, uint8_t type, const void *data, uint16_t len) {
node_t *from = handle;
if(type == SPTPS_HANDSHAKE) {
}
vpn_packet_t inpkt;
+ inpkt.offset = DEFAULT_PACKET_OFFSET;
if(type == PKT_PROBE) {
inpkt.len = len;
- memcpy(inpkt.data, data, len);
+ memcpy(DATA(&inpkt), data, len);
mtu_probe_h(from, &inpkt, len);
return true;
}
int offset = (type & PKT_MAC) ? 0 : 14;
if(type & PKT_COMPRESSED) {
- length_t ulen = uncompress_packet(inpkt.data + offset, (const uint8_t *)data, len, from->incompression);
+ length_t ulen = uncompress_packet(DATA(&inpkt) + offset, (const uint8_t *)data, len, from->incompression);
if(ulen < 0) {
return false;
} else {
if(inpkt.len > MAXSIZE)
abort();
} else {
- memcpy(inpkt.data + offset, data, len);
+ memcpy(DATA(&inpkt) + offset, data, len);
inpkt.len = len + offset;
}
/* Generate the Ethernet packet type if necessary */
if(offset) {
- switch(inpkt.data[14] >> 4) {
+ switch(DATA(&inpkt)[14] >> 4) {
case 4:
- inpkt.data[12] = 0x08;
- inpkt.data[13] = 0x00;
+ DATA(&inpkt)[12] = 0x08;
+ DATA(&inpkt)[13] = 0x00;
break;
case 6:
- inpkt.data[12] = 0x86;
- inpkt.data[13] = 0xDD;
+ DATA(&inpkt)[12] = 0x86;
+ DATA(&inpkt)[13] = 0xDD;
break;
default:
logger(DEBUG_TRAFFIC, LOG_ERR,
"Unknown IP version %d while reading packet from %s (%s)",
- inpkt.data[14] >> 4, from->name, from->hostname);
+ DATA(&inpkt)[14] >> 4, from->name, from->hostname);
return false;
}
}
if(n == myself) {
if(overwrite_mac)
- memcpy(packet->data, mymac.x, ETH_ALEN);
+ memcpy(DATA(packet), mymac.x, ETH_ALEN);
n->out_packets++;
n->out_bytes += packet->len;
devops.write(packet);
listen_socket_t *ls = data;
vpn_packet_t pkt;
char *hostname;
- sockaddr_t from = {{0}};
- socklen_t fromlen = sizeof from;
- node_t *n;
- int len;
+ node_id_t nullid = {};
+ sockaddr_t addr = {};
+ socklen_t addrlen = sizeof addr;
+ node_t *from, *to;
+ bool direct = false;
- len = recvfrom(ls->udp.fd, (char *) &pkt.seqno, MAXSIZE, 0, &from.sa, &fromlen);
+ pkt.offset = 0;
+ int len = recvfrom(ls->udp.fd, DATA(&pkt), MAXSIZE, 0, &addr.sa, &addrlen);
if(len <= 0 || len > MAXSIZE) {
if(!sockwouldblock(sockerrno))
pkt.len = len;
- sockaddrunmap(&from); /* Some braindead IPv6 implementations do stupid things. */
+ sockaddrunmap(&addr); /* Some braindead IPv6 implementations do stupid things. */
- n = lookup_node_udp(&from);
+ // Try to figure out who sent this packet.
+
+ node_t *n = lookup_node_udp(&addr);
+
+ if(!n) {
+ // It might be from a 1.1 node, which might have a source ID in the packet.
+ pkt.offset = 2 * sizeof(node_id_t);
+ from = lookup_node_id(SRCID(&pkt));
+ if(from && !memcmp(DSTID(&pkt), &nullid, sizeof nullid) && from->status.sptps) {
+ if(sptps_verify_datagram(&from->sptps, DATA(&pkt), pkt.len - 2 * sizeof(node_id_t)))
+ n = from;
+ else
+ goto skip_harder;
+ }
+ }
+
+ if(!n) {
+ pkt.offset = 0;
+ n = try_harder(&addr, &pkt);
+ }
+skip_harder:
if(!n) {
- n = try_harder(&from, &pkt);
- if(n)
- update_node_udp(n, &from);
- else if(debug_level >= DEBUG_PROTOCOL) {
- hostname = sockaddr2hostname(&from);
+ if(debug_level >= DEBUG_PROTOCOL) {
+ hostname = sockaddr2hostname(&addr);
logger(DEBUG_PROTOCOL, LOG_WARNING, "Received UDP packet from unknown source %s", hostname);
free(hostname);
+ }
+ return;
+ }
+
+ if(n->status.sptps) {
+ pkt.offset = 2 * sizeof(node_id_t);
+
+ if(!memcmp(DSTID(&pkt), &nullid, sizeof nullid)) {
+ direct = true;
+ from = n;
+ to = myself;
+ } else {
+ from = lookup_node_id(SRCID(&pkt));
+ to = lookup_node_id(DSTID(&pkt));
+ }
+ if(!from || !to) {
+ logger(DEBUG_PROTOCOL, LOG_WARNING, "Received UDP packet from %s (%s) with unknown source and/or destination ID", n->name, n->hostname);
return;
}
- else
+
+ if(to != myself) {
+ send_sptps_data_priv(to, n, 0, DATA(&pkt), pkt.len - 2 * sizeof(node_id_t));
return;
+ }
+ } else {
+ direct = true;
+ from = n;
}
- n->sock = ls - listen_socket;
+ pkt.offset = 0;
+ if(!receive_udppacket(from, &pkt))
+ return;
- receive_udppacket(n, &pkt);
+ n->sock = ls - listen_socket;
+ if(direct && sockaddrcmp(&addr, &n->address))
+ update_node_udp(n, &addr);
}
void handle_device_data(void *data, int flags) {
vpn_packet_t packet;
-
+ packet.offset = DEFAULT_PACKET_OFFSET;
packet.priority = 0;
if(devops.read(&packet)) {
#include "xalloc.h"
char *myport;
+static char *myname;
static io_t device_io;
devops_t devops;
bool device_standby = false;
xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
xasprintf(&envp[1], "DEVICE=%s", device ? : "");
xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
- xasprintf(&envp[3], "NAME=%s", myself->name);
+ xasprintf(&envp[3], "NAME=%s", myname);
execute_script("tinc-up", envp);
xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
xasprintf(&envp[1], "DEVICE=%s", device ? : "");
xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
- xasprintf(&envp[3], "NAME=%s", myself->name);
+ xasprintf(&envp[3], "NAME=%s", myname);
execute_script("tinc-down", envp);
return false;
}
+ myname = xstrdup(name);
myself = new_node();
myself->connection = new_connection();
myself->name = name;
if (!device_standby)
device_disable();
- if(myport) free(myport);
+ free(myport);
if (device_fd >= 0)
io_del(&device_io);
exit_control();
+ free(myname);
+ free(scriptextension);
+ free(scriptinterpreter);
+
return;
}
#include "utils.h"
#include "xalloc.h"
+static digest_t *sha256;
+
splay_tree_t *node_tree;
+static splay_tree_t *node_id_tree;
static hash_t *node_udp_cache;
+static hash_t *node_id_cache;
node_t *myself;
return strcmp(a->name, b->name);
}
+static int node_id_compare(const node_t *a, const node_t *b) {
+ return memcmp(&a->id, &b->id, sizeof(node_id_t));
+}
+
void init_nodes(void) {
+ sha256 = digest_open_by_name("sha256", sizeof(node_id_t));
+
node_tree = splay_alloc_tree((splay_compare_t) node_compare, (splay_action_t) free_node);
+ node_id_tree = splay_alloc_tree((splay_compare_t) node_id_compare, NULL);
node_udp_cache = hash_alloc(0x100, sizeof(sockaddr_t));
+ node_id_cache = hash_alloc(0x100, sizeof(node_id_t));
}
void exit_nodes(void) {
+ hash_free(node_id_cache);
hash_free(node_udp_cache);
+ splay_delete_tree(node_id_tree);
splay_delete_tree(node_tree);
+
+ digest_close(sha256);
}
node_t *new_node(void) {
}
void node_add(node_t *n) {
+ digest_create(sha256, n->name, strlen(n->name), &n->id);
+
splay_insert(node_tree, n);
+ splay_insert(node_id_tree, n);
}
void node_del(node_t *n) {
+ hash_delete(node_udp_cache, &n->address);
+ hash_delete(node_id_cache, &n->id);
+
for splay_each(subnet_t, s, n->subnet_tree)
subnet_del(n, s);
for splay_each(edge_t, e, n->edge_tree)
edge_del(e);
+ splay_delete(node_id_tree, n);
splay_delete(node_tree, n);
}
return splay_search(node_tree, &n);
}
+node_t *lookup_node_id(const node_id_t *id) {
+ node_t *n = hash_search(node_id_cache, id);
+ if(!n) {
+ node_t tmp = {.id = *id};
+ n = splay_search(node_id_tree, &tmp);
+ if(n)
+ hash_insert(node_id_cache, id, n);
+ }
+
+ return n;
+}
+
node_t *lookup_node_udp(const sockaddr_t *sa) {
return hash_search(node_udp_cache, sa);
}
return;
}
- hash_insert(node_udp_cache, &n->address, NULL);
+ hash_delete(node_udp_cache, &n->address);
if(sa) {
n->address = *sa;
n->hostname = sockaddr2hostname(&n->address);
logger(DEBUG_PROTOCOL, LOG_DEBUG, "UDP address of %s set to %s", n->name, n->hostname);
}
+
+ /* invalidate UDP information - note that this is a security feature as well to make sure
+ we can't be tricked into flooding any random address with UDP packets */
+ n->status.udp_confirmed = false;
+ n->mtuprobes = 0;
+ n->minmtu = 0;
+ n->maxmtu = MTU;
}
bool dump_nodes(connection_t *c) {
- for splay_each(node_t, n, node_tree)
- send_request(c, "%d %d %s %s %d %d %d %d %x %x %s %s %d %hd %hd %hd %ld", CONTROL, REQ_DUMP_NODES,
- n->name, n->hostname ?: "unknown port unknown", cipher_get_nid(n->outcipher),
+ for splay_each(node_t, n, node_tree) {
+ char id[2 * sizeof n->id + 1];
+ for (size_t c = 0; c < sizeof n->id; ++c)
+ sprintf(id + 2 * c, "%02hhx", n->id.x[c]);
+ id[sizeof id - 1] = 0;
+ send_request(c, "%d %d %s %s %s %d %d %d %d %x %x %s %s %d %hd %hd %hd %ld", CONTROL, REQ_DUMP_NODES,
+ n->name, id, n->hostname ?: "unknown port unknown", cipher_get_nid(n->outcipher),
digest_get_nid(n->outdigest), (int)digest_length(n->outdigest), n->outcompression,
n->options, bitfield_to_int(&n->status, sizeof n->status), n->nexthop ? n->nexthop->name : "-",
n->via ? n->via->name ?: "-" : "-", n->distance, n->mtu, n->minmtu, n->maxmtu, (long)n->last_state_change);
+ }
return send_request(c, "%d %d", CONTROL, REQ_DUMP_NODES);
}
typedef struct node_t {
char *name; /* name of this node */
+ node_id_t id; /* unique node ID (name hash) */
uint32_t options; /* options turned on for this node */
int sock; /* Socket to use for outgoing UDP packets */
extern void node_add(node_t *);
extern void node_del(node_t *);
extern node_t *lookup_node(char *);
+extern node_t *lookup_node_id(const node_id_t *);
extern node_t *lookup_node_udp(const sockaddr_t *);
extern bool dump_nodes(struct connection_t *);
extern bool dump_traffic(struct connection_t *);
/*
crypto.c -- Cryptographic miscellaneous functions and initialisation
- Copyright (C) 2007-2013 Guus Sliepen <guus@tinc-vpn.org>
+ Copyright (C) 2007-2014 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
#include "../crypto.h"
+#ifndef HAVE_MINGW
+
+static int random_fd = -1;
+
+static void random_init(void) {
+ random_fd = open("/dev/urandom", O_RDONLY);
+ if(random_fd < 0)
+ random_fd = open("/dev/random", O_RDONLY);
+ if(random_fd < 0) {
+ fprintf(stderr, "Could not open source of random numbers: %s\n", strerror(errno));
+ abort();
+ }
+}
+
+static void random_exit(void) {
+ close(random_fd);
+}
+
+void randomize(void *out, size_t outlen) {
+ while(outlen) {
+ size_t len = read(random_fd, out, outlen);
+ if(len <= 0) {
+ if(errno == EAGAIN || errno == EINTR)
+ continue;
+ fprintf(stderr, "Could not read random numbers: %s\n", strerror(errno));
+ abort();
+ }
+ out += len;
+ outlen -= len;
+ }
+}
+
+#else
+
+#include <wincrypt.h>
+HCRYPTPROV prov;
+
+void random_init(void) {
+ if(!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
+ fprintf(stderr, "CryptAcquireContext() failed!\n");
+ abort();
+ }
+}
+
+void random_exit(void) {
+ CryptReleaseContext(prov, 0);
+}
+
+void randomize(void *out, size_t outlen) {
+ if(!CryptGenRandom(prov, outlen, out)) {
+ fprintf(stderr, "CryptGenRandom() failed\n");
+ abort();
+ }
+}
+
+#endif
+
void crypto_init(void) {
- RAND_load_file("/dev/urandom", 1024);
+ random_init();
ENGINE_load_builtin_engines();
ENGINE_register_all_complete();
void crypto_exit(void) {
EVP_cleanup();
-}
-
-void randomize(void *out, size_t outlen) {
- RAND_pseudo_bytes(out, outlen);
+ ERR_free_strings();
+ ENGINE_cleanup();
+ random_exit();
}
/* Protocol version. Different major versions are incompatible. */
#define PROT_MAJOR 17
-#define PROT_MINOR 3 /* Should not exceed 255! */
+#define PROT_MINOR 4 /* Should not exceed 255! */
/* Silly Windows */
return true;
}
-static bool receive_invitation_sptps(void *handle, uint8_t type, const char *data, uint16_t len) {
+static bool receive_invitation_sptps(void *handle, uint8_t type, const void *data, uint16_t len) {
connection_t *c = handle;
if(type == 128)
}
if(experimental)
- if(!read_ecdsa_public_key(c))
- return false;
- } else {
- if(c->protocol_minor && !ecdsa_active(c->ecdsa))
- c->protocol_minor = 1;
+ read_ecdsa_public_key(c);
+ /* Ignore failures if no key known yet */
}
+ if(c->protocol_minor && !ecdsa_active(c->ecdsa))
+ c->protocol_minor = 1;
+
/* Forbid version rollback for nodes whose Ed25519 key we know */
if(ecdsa_active(c->ecdsa) && c->protocol_minor < 2) {
if(!(c->outdigest = digest_open_sha1(-1)))
return false;
- size_t len = rsa_size(c->rsa);
+ const size_t len = rsa_size(c->rsa);
char key[len];
char enckey[len];
char hexkey[2 * len + 1];
bool metakey_h(connection_t *c, const char *request) {
char hexkey[MAX_STRING_SIZE];
int cipher, digest, maclength, compression;
- size_t len = rsa_size(myself->connection->rsa);
+ const size_t len = rsa_size(myself->connection->rsa);
char enckey[len];
char key[len];
}
bool send_challenge(connection_t *c) {
- size_t len = rsa_size(c->rsa);
+ const size_t len = rsa_size(c->rsa);
char buffer[len * 2 + 1];
if(!c->hischallenge)
bool challenge_h(connection_t *c, const char *request) {
char buffer[MAX_STRING_SIZE];
- size_t len = rsa_size(myself->connection->rsa);
+ const size_t len = rsa_size(myself->connection->rsa);
size_t digestlen = digest_length(c->indigest);
char digest[digestlen];
}
if(ecdsa_active(c->ecdsa) || read_ecdsa_public_key(c)) {
- logger(DEBUG_ALWAYS, LOG_INFO, "Already have Ed25519 public key from %s (%s), not upgrading.", c->name, c->hostname);
+ char *knownkey = ecdsa_get_base64_public_key(c->ecdsa);
+ bool different = strcmp(knownkey, pubkey);
+ free(knownkey);
+ if(different) {
+ logger(DEBUG_ALWAYS, LOG_ERR, "Already have an Ed25519 public key from %s (%s) which is different from the one presented now!", c->name, c->hostname);
+ return false;
+ }
+ logger(DEBUG_ALWAYS, LOG_INFO, "Already have Ed25519 public key from %s (%s), ignoring.", c->name, c->hostname);
+ c->allow_request = TERMREQ;
+ return send_termreq(c);
+ }
+
+ c->ecdsa = ecdsa_set_base64_public_key(pubkey);
+ if(!c->ecdsa) {
+ logger(DEBUG_ALWAYS, LOG_INFO, "Got bad Ed25519 public key from %s (%s), not upgrading.", c->name, c->hostname);
return false;
}
/*
protocol_key.c -- handle the meta-protocol, key exchange
Copyright (C) 1999-2005 Ivo Timmermans,
- 2000-2013 Guus Sliepen <guus@tinc-vpn.org>
+ 2000-2014 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
return true;
}
-static bool send_initial_sptps_data(void *handle, uint8_t type, const char *data, size_t len) {
+static bool send_initial_sptps_data(void *handle, uint8_t type, const void *data, size_t len) {
node_t *to = handle;
to->sptps.send_data = send_sptps_data;
char buf[len * 4 / 3 + 5];
return true;
}
+ /* TODO: forwarding SPTPS packets in this way is inefficient because we send them over TCP without checking for UDP connectivity */
send_request(to->nexthop->connection, "%s", request);
}
update_node_udp(from, &sa);
}
- if(from->options & OPTION_PMTU_DISCOVERY && !(from->options & OPTION_TCPONLY))
+ /* Don't send probes if we can't send UDP packets directly to that node.
+ TODO: the indirect (via) condition can change at any time as edges are added and removed, so this should probably be moved to graph.c. */
+ if((from->via == myself || from->via == from) && from->options & OPTION_PMTU_DISCOVERY && !(from->options & OPTION_TCPONLY))
send_mtu_probe(from);
}
if(!send_request(c, "%d %hd", PACKET, packet->len))
return false;
- return send_meta(c, (char *)packet->data, packet->len);
+ return send_meta(c, (char *)DATA(packet), packet->len);
}
bool tcppacket_h(connection_t *c, const char *request) {
static bool read_packet(vpn_packet_t *packet) {
int inlen;
- if((inlen = read(device_fd, packet->data, MTU)) <= 0) {
+ if((inlen = read(device_fd, DATA(packet), MTU)) <= 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
device, strerror(errno));
return false;
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s",
packet->len, device_info);
- if(write(device_fd, packet->data, packet->len) < 0) {
+ if(write(device_fd, DATA(packet), packet->len) < 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device,
strerror(errno));
return false;
/* Find TCP header */
int start = ether_size;
- uint16_t type = packet->data[12] << 8 | packet->data[13];
+ uint16_t type = DATA(packet)[12] << 8 | DATA(packet)[13];
if(type == ETH_P_8021Q) {
start += 4;
- type = packet->data[16] << 8 | packet->data[17];
+ type = DATA(packet)[16] << 8 | DATA(packet)[17];
}
- if(type == ETH_P_IP && packet->data[start + 9] == 6)
- start += (packet->data[start] & 0xf) * 4;
- else if(type == ETH_P_IPV6 && packet->data[start + 6] == 6)
+ if(type == ETH_P_IP && DATA(packet)[start + 9] == 6)
+ start += (DATA(packet)[start] & 0xf) * 4;
+ else if(type == ETH_P_IPV6 && DATA(packet)[start + 6] == 6)
start += 40;
else
return;
return;
/* Use data offset field to calculate length of options field */
- int len = ((packet->data[start + 12] >> 4) - 5) * 4;
+ int len = ((DATA(packet)[start + 12] >> 4) - 5) * 4;
if(packet->len < start + 20 + len)
return;
/* Search for MSS option header */
for(int i = 0; i < len;) {
- if(packet->data[start + 20 + i] == 0)
+ if(DATA(packet)[start + 20 + i] == 0)
break;
- if(packet->data[start + 20 + i] == 1) {
+ if(DATA(packet)[start + 20 + i] == 1) {
i++;
continue;
}
- if(i > len - 2 || i > len - packet->data[start + 21 + i])
+ if(i > len - 2 || i > len - DATA(packet)[start + 21 + i])
break;
- if(packet->data[start + 20 + i] != 2) {
- if(packet->data[start + 21 + i] < 2)
+ if(DATA(packet)[start + 20 + i] != 2) {
+ if(DATA(packet)[start + 21 + i] < 2)
break;
- i += packet->data[start + 21 + i];
+ i += DATA(packet)[start + 21 + i];
continue;
}
- if(packet->data[start + 21] != 4)
+ if(DATA(packet)[start + 21] != 4)
break;
/* Found it */
- uint16_t oldmss = packet->data[start + 22 + i] << 8 | packet->data[start + 23 + i];
+ uint16_t oldmss = DATA(packet)[start + 22 + i] << 8 | DATA(packet)[start + 23 + i];
uint16_t newmss = mtu - start - 20;
- uint16_t csum = packet->data[start + 16] << 8 | packet->data[start + 17];
+ uint16_t csum = DATA(packet)[start + 16] << 8 | DATA(packet)[start + 17];
if(oldmss <= newmss)
break;
logger(DEBUG_TRAFFIC, LOG_INFO, "Clamping MSS of packet from %s to %s to %d", source->name, via->name, newmss);
/* Update the MSS value and the checksum */
- packet->data[start + 22 + i] = newmss >> 8;
- packet->data[start + 23 + i] = newmss & 0xff;
+ DATA(packet)[start + 22 + i] = newmss >> 8;
+ DATA(packet)[start + 23 + i] = newmss & 0xff;
csum ^= 0xffff;
csum -= oldmss;
csum += newmss;
csum ^= 0xffff;
- packet->data[start + 16] = csum >> 8;
- packet->data[start + 17] = csum & 0xff;
+ DATA(packet)[start + 16] = csum >> 8;
+ DATA(packet)[start + 17] = csum & 0xff;
break;
}
}
static void swap_mac_addresses(vpn_packet_t *packet) {
mac_t tmp;
- memcpy(&tmp, &packet->data[0], sizeof tmp);
- memcpy(&packet->data[0], &packet->data[6], sizeof tmp);
- memcpy(&packet->data[6], &tmp, sizeof tmp);
+ memcpy(&tmp, &DATA(packet)[0], sizeof tmp);
+ memcpy(&DATA(packet)[0], &DATA(packet)[6], sizeof tmp);
+ memcpy(&DATA(packet)[6], &tmp, sizeof tmp);
}
static void age_subnets(void *data) {
/* Copy headers from packet into properly aligned structs on the stack */
- memcpy(&ip, packet->data + ether_size, ip_size);
+ memcpy(&ip, DATA(packet) + ether_size, ip_size);
/* Remember original source and destination */
/* Copy first part of original contents to ICMP message */
- memmove(packet->data + ether_size + ip_size + icmp_size, packet->data + ether_size, oldlen);
+ memmove(DATA(packet) + ether_size + ip_size + icmp_size, DATA(packet) + ether_size, oldlen);
/* Fill in IPv4 header */
icmp.icmp_cksum = 0;
icmp.icmp_cksum = inet_checksum(&icmp, icmp_size, ~0);
- icmp.icmp_cksum = inet_checksum(packet->data + ether_size + ip_size + icmp_size, oldlen, icmp.icmp_cksum);
+ icmp.icmp_cksum = inet_checksum(DATA(packet) + ether_size + ip_size + icmp_size, oldlen, icmp.icmp_cksum);
/* Copy structs on stack back to packet */
- memcpy(packet->data + ether_size, &ip, ip_size);
- memcpy(packet->data + ether_size + ip_size, &icmp, icmp_size);
+ memcpy(DATA(packet) + ether_size, &ip, ip_size);
+ memcpy(DATA(packet) + ether_size + ip_size, &icmp, icmp_size);
packet->len = ether_size + ip_size + icmp_size + oldlen;
uint8_t *offset;
uint16_t ip_off, origf;
- memcpy(&ip, packet->data + ether_size, ip_size);
+ memcpy(&ip, DATA(packet) + ether_size, ip_size);
fragment.priority = packet->priority;
+ fragment.offset = DEFAULT_PACKET_OFFSET;
if(ip.ip_hl != ip_size / 4)
return;
logger(DEBUG_TRAFFIC, LOG_INFO, "Fragmenting packet of %d bytes to %s (%s)", packet->len, dest->name, dest->hostname);
- offset = packet->data + ether_size + ip_size;
+ offset = DATA(packet) + ether_size + ip_size;
maxlen = (dest->mtu - ether_size - ip_size) & ~0x7;
ip_off = ntohs(ip.ip_off);
origf = ip_off & ~IP_OFFMASK;
while(todo) {
len = todo > maxlen ? maxlen : todo;
- memcpy(fragment.data + ether_size + ip_size, offset, len);
+ memcpy(DATA(&fragment) + ether_size + ip_size, offset, len);
todo -= len;
offset += len;
ip.ip_off = htons(ip_off | origf | (todo ? IP_MF : 0));
ip.ip_sum = 0;
ip.ip_sum = inet_checksum(&ip, ip_size, ~0);
- memcpy(fragment.data, packet->data, ether_size);
- memcpy(fragment.data + ether_size, &ip, ip_size);
+ memcpy(DATA(&fragment), DATA(packet), ether_size);
+ memcpy(DATA(&fragment) + ether_size, &ip, ip_size);
fragment.len = ether_size + ip_size + len;
send_packet(dest, &fragment);
node_t *via;
ipv4_t dest;
- memcpy(&dest, &packet->data[30], sizeof dest);
+ memcpy(&dest, &DATA(packet)[30], sizeof dest);
subnet = lookup_subnet_ipv4(&dest);
if(!subnet) {
return route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_NET_ANO);
if(priorityinheritance)
- packet->priority = packet->data[15];
+ packet->priority = DATA(packet)[15];
via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via;
if(via && packet->len > MAX(via->mtu, 590) && via != myself) {
logger(DEBUG_TRAFFIC, LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu);
- if(packet->data[20] & 0x40) {
+ if(DATA(packet)[20] & 0x40) {
packet->len = MAX(via->mtu, 590);
route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED);
} else {
/* Copy headers from packet to structs on the stack */
- memcpy(&ip6, packet->data + ether_size, ip6_size);
+ memcpy(&ip6, DATA(packet) + ether_size, ip6_size);
/* Remember original source and destination */
/* Copy first part of original contents to ICMP message */
- memmove(packet->data + ether_size + ip6_size + icmp6_size, packet->data + ether_size, pseudo.length);
+ memmove(DATA(packet) + ether_size + ip6_size + icmp6_size, DATA(packet) + ether_size, pseudo.length);
/* Fill in IPv6 header */
checksum = inet_checksum(&pseudo, sizeof pseudo, ~0);
checksum = inet_checksum(&icmp6, icmp6_size, checksum);
- checksum = inet_checksum(packet->data + ether_size + ip6_size + icmp6_size, ntohl(pseudo.length) - icmp6_size, checksum);
+ checksum = inet_checksum(DATA(packet) + ether_size + ip6_size + icmp6_size, ntohl(pseudo.length) - icmp6_size, checksum);
icmp6.icmp6_cksum = checksum;
/* Copy structs on stack back to packet */
- memcpy(packet->data + ether_size, &ip6, ip6_size);
- memcpy(packet->data + ether_size + ip6_size, &icmp6, icmp6_size);
+ memcpy(DATA(packet) + ether_size, &ip6, ip6_size);
+ memcpy(DATA(packet) + ether_size + ip6_size, &icmp6, icmp6_size);
packet->len = ether_size + ip6_size + ntohl(pseudo.length);
if(!checklength(source, packet, ether_size + ip6_size))
return;
- if(packet->data[20] == IPPROTO_ICMPV6 && checklength(source, packet, ether_size + ip6_size + icmp6_size) && packet->data[54] == ND_NEIGHBOR_SOLICIT) {
+ if(DATA(packet)[20] == IPPROTO_ICMPV6 && checklength(source, packet, ether_size + ip6_size + icmp6_size) && DATA(packet)[54] == ND_NEIGHBOR_SOLICIT) {
route_neighborsol(source, packet);
return;
}
node_t *via;
ipv6_t dest;
- memcpy(&dest, &packet->data[38], sizeof dest);
+ memcpy(&dest, &DATA(packet)[38], sizeof dest);
subnet = lookup_subnet_ipv6(&dest);
if(!subnet) {
/* Copy headers from packet to structs on the stack */
- memcpy(&ip6, packet->data + ether_size, ip6_size);
- memcpy(&ns, packet->data + ether_size + ip6_size, ns_size);
+ memcpy(&ip6, DATA(packet) + ether_size, ip6_size);
+ memcpy(&ns, DATA(packet) + ether_size + ip6_size, ns_size);
if(has_opt)
- memcpy(&opt, packet->data + ether_size + ip6_size + ns_size, opt_size);
+ memcpy(&opt, DATA(packet) + ether_size + ip6_size + ns_size, opt_size);
/* First, snatch the source address from the neighbor solicitation packet */
if(overwrite_mac)
- memcpy(mymac.x, packet->data + ETH_ALEN, ETH_ALEN);
+ memcpy(mymac.x, DATA(packet) + ETH_ALEN, ETH_ALEN);
/* Check if this is a valid neighbor solicitation request */
checksum = inet_checksum(&ns, ns_size, checksum);
if(has_opt) {
checksum = inet_checksum(&opt, opt_size, checksum);
- checksum = inet_checksum(packet->data + ether_size + ip6_size + ns_size + opt_size, ETH_ALEN, checksum);
+ checksum = inet_checksum(DATA(packet) + ether_size + ip6_size + ns_size + opt_size, ETH_ALEN, checksum);
}
if(checksum) {
/* Create neighbor advertation reply */
- memcpy(packet->data, packet->data + ETH_ALEN, ETH_ALEN); /* copy destination address */
- packet->data[ETH_ALEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
+ memcpy(DATA(packet), DATA(packet) + ETH_ALEN, ETH_ALEN); /* copy destination address */
+ DATA(packet)[ETH_ALEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
ip6.ip6_dst = ip6.ip6_src; /* swap destination and source protocoll address */
ip6.ip6_src = ns.nd_ns_target;
if(has_opt)
- memcpy(packet->data + ether_size + ip6_size + ns_size + opt_size, packet->data + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */
+ memcpy(DATA(packet) + ether_size + ip6_size + ns_size + opt_size, DATA(packet) + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */
ns.nd_ns_cksum = 0;
ns.nd_ns_type = ND_NEIGHBOR_ADVERT;
checksum = inet_checksum(&ns, ns_size, checksum);
if(has_opt) {
checksum = inet_checksum(&opt, opt_size, checksum);
- checksum = inet_checksum(packet->data + ether_size + ip6_size + ns_size + opt_size, ETH_ALEN, checksum);
+ checksum = inet_checksum(DATA(packet) + ether_size + ip6_size + ns_size + opt_size, ETH_ALEN, checksum);
}
ns.nd_ns_hdr.icmp6_cksum = checksum;
/* Copy structs on stack back to packet */
- memcpy(packet->data + ether_size, &ip6, ip6_size);
- memcpy(packet->data + ether_size + ip6_size, &ns, ns_size);
+ memcpy(DATA(packet) + ether_size, &ip6, ip6_size);
+ memcpy(DATA(packet) + ether_size + ip6_size, &ns, ns_size);
if(has_opt)
- memcpy(packet->data + ether_size + ip6_size + ns_size, &opt, opt_size);
+ memcpy(DATA(packet) + ether_size + ip6_size + ns_size, &opt, opt_size);
send_packet(source, packet);
}
/* First, snatch the source address from the ARP packet */
if(overwrite_mac)
- memcpy(mymac.x, packet->data + ETH_ALEN, ETH_ALEN);
+ memcpy(mymac.x, DATA(packet) + ETH_ALEN, ETH_ALEN);
/* Copy headers from packet to structs on the stack */
- memcpy(&arp, packet->data + ether_size, arp_size);
+ memcpy(&arp, DATA(packet) + ether_size, arp_size);
/* Check if this is a valid ARP request */
if(subnet->owner == myself)
return; /* silently ignore */
- memcpy(packet->data, packet->data + ETH_ALEN, ETH_ALEN); /* copy destination address */
- packet->data[ETH_ALEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
+ memcpy(DATA(packet), DATA(packet) + ETH_ALEN, ETH_ALEN); /* copy destination address */
+ DATA(packet)[ETH_ALEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
memcpy(&addr, arp.arp_tpa, sizeof addr); /* save protocol addr */
memcpy(arp.arp_tpa, arp.arp_spa, sizeof addr); /* swap destination and source protocol address */
memcpy(arp.arp_spa, &addr, sizeof addr); /* ... */
memcpy(arp.arp_tha, arp.arp_sha, ETH_ALEN); /* set target hard/proto addr */
- memcpy(arp.arp_sha, packet->data + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */
+ memcpy(arp.arp_sha, DATA(packet) + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */
arp.arp_op = htons(ARPOP_REPLY);
/* Copy structs on stack back to packet */
- memcpy(packet->data + ether_size, &arp, arp_size);
+ memcpy(DATA(packet) + ether_size, &arp, arp_size);
send_packet(source, packet);
}
if(source == myself) {
mac_t src;
- memcpy(&src, &packet->data[6], sizeof src);
+ memcpy(&src, &DATA(packet)[6], sizeof src);
learn_mac(&src);
}
/* Lookup destination address */
- memcpy(&dest, &packet->data[0], sizeof dest);
+ memcpy(&dest, &DATA(packet)[0], sizeof dest);
subnet = lookup_subnet_mac(NULL, &dest);
if(!subnet || !subnet->owner) {
if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself)
return;
- uint16_t type = packet->data[12] << 8 | packet->data[13];
+ uint16_t type = DATA(packet)[12] << 8 | DATA(packet)[13];
if(priorityinheritance && type == ETH_P_IP && packet->len >= ether_size + ip_size)
- packet->priority = packet->data[15];
+ packet->priority = DATA(packet)[15];
// Handle packets larger than PMTU
length_t ethlen = 14;
if(type == ETH_P_8021Q) {
- type = packet->data[16] << 8 | packet->data[17];
+ type = DATA(packet)[16] << 8 | DATA(packet)[17];
ethlen += 4;
}
if(type == ETH_P_IP && packet->len > 576 + ethlen) {
- if(packet->data[6 + ethlen] & 0x40) {
+ if(DATA(packet)[6 + ethlen] & 0x40) {
packet->len = via->mtu;
route_ipv4_unreachable(source, packet, ethlen, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED);
} else {
len = c->outmaclength;
if(send_request(c, "%d %d %d", CONTROL, REQ_PCAP, len))
- send_meta(c, (char *)packet->data, len);
+ send_meta(c, (char *)DATA(packet), len);
}
}
static bool do_decrement_ttl(node_t *source, vpn_packet_t *packet) {
- uint16_t type = packet->data[12] << 8 | packet->data[13];
+ uint16_t type = DATA(packet)[12] << 8 | DATA(packet)[13];
length_t ethlen = ether_size;
if(type == ETH_P_8021Q) {
- type = packet->data[16] << 8 | packet->data[17];
+ type = DATA(packet)[16] << 8 | DATA(packet)[17];
ethlen += 4;
}
if(!checklength(source, packet, ethlen + ip_size))
return false;
- if(packet->data[ethlen + 8] < 1) {
- if(packet->data[ethlen + 11] != IPPROTO_ICMP || packet->data[ethlen + 32] != ICMP_TIME_EXCEEDED)
+ if(DATA(packet)[ethlen + 8] < 1) {
+ if(DATA(packet)[ethlen + 11] != IPPROTO_ICMP || DATA(packet)[ethlen + 32] != ICMP_TIME_EXCEEDED)
route_ipv4_unreachable(source, packet, ethlen, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL);
return false;
}
- uint16_t old = packet->data[ethlen + 8] << 8 | packet->data[ethlen + 9];
- packet->data[ethlen + 8]--;
- uint16_t new = packet->data[ethlen + 8] << 8 | packet->data[ethlen + 9];
+ uint16_t old = DATA(packet)[ethlen + 8] << 8 | DATA(packet)[ethlen + 9];
+ DATA(packet)[ethlen + 8]--;
+ uint16_t new = DATA(packet)[ethlen + 8] << 8 | DATA(packet)[ethlen + 9];
- uint32_t checksum = packet->data[ethlen + 10] << 8 | packet->data[ethlen + 11];
+ uint32_t checksum = DATA(packet)[ethlen + 10] << 8 | DATA(packet)[ethlen + 11];
checksum += old + (~new & 0xFFFF);
while(checksum >> 16)
checksum = (checksum & 0xFFFF) + (checksum >> 16);
- packet->data[ethlen + 10] = checksum >> 8;
- packet->data[ethlen + 11] = checksum & 0xff;
+ DATA(packet)[ethlen + 10] = checksum >> 8;
+ DATA(packet)[ethlen + 11] = checksum & 0xff;
return true;
if(!checklength(source, packet, ethlen + ip6_size))
return false;
- if(packet->data[ethlen + 7] < 1) {
- if(packet->data[ethlen + 6] != IPPROTO_ICMPV6 || packet->data[ethlen + 40] != ICMP6_TIME_EXCEEDED)
+ if(DATA(packet)[ethlen + 7] < 1) {
+ if(DATA(packet)[ethlen + 6] != IPPROTO_ICMPV6 || DATA(packet)[ethlen + 40] != ICMP6_TIME_EXCEEDED)
route_ipv6_unreachable(source, packet, ethlen, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT);
return false;
}
- packet->data[ethlen + 7]--;
+ DATA(packet)[ethlen + 7]--;
return true;
if(!do_decrement_ttl(source, packet))
return;
- uint16_t type = packet->data[12] << 8 | packet->data[13];
+ uint16_t type = DATA(packet)[12] << 8 | DATA(packet)[13];
switch (routing_mode) {
case RMODE_ROUTER:
device.c -- Interaction with Solaris tun device
Copyright (C) 2001-2005 Ivo Timmermans,
2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
- 2001-2013 Guus Sliepen <guus@tinc-vpn.org>
+ 2001-2014 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
switch(device_type) {
case DEVICE_TYPE_TUN:
- if((inlen = read(device_fd, packet->data + 14, MTU - 14)) <= 0) {
+ if((inlen = read(device_fd, DATA(packet) + 14, MTU - 14)) <= 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno));
return false;
}
- switch(packet->data[14] >> 4) {
+ switch(DATA(packet)[14] >> 4) {
case 4:
- packet->data[12] = 0x08;
- packet->data[13] = 0x00;
+ DATA(packet)[12] = 0x08;
+ DATA(packet)[13] = 0x00;
break;
case 6:
- packet->data[12] = 0x86;
- packet->data[13] = 0xDD;
+ DATA(packet)[12] = 0x86;
+ DATA(packet)[13] = 0xDD;
break;
default:
- logger(DEBUG_TRAFFIC, LOG_ERR, "Unknown IP version %d while reading packet from %s %s", packet->data[14] >> 4, device_info, device);
+ logger(DEBUG_TRAFFIC, LOG_ERR, "Unknown IP version %d while reading packet from %s %s", DATA(packet)[14] >> 4, device_info, device);
return false;
}
- memset(packet->data, 0, 12);
+ memset(DATA(packet), 0, 12);
packet->len = inlen + 14;
break;
case DEVICE_TYPE_TAP:
- if((inlen = read(device_fd, packet->data, MTU)) <= 0) {
+ if((inlen = read(device_fd, DATA(packet), MTU)) <= 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno));
return false;
}
switch(device_type) {
case DEVICE_TYPE_TUN:
- if(write(device_fd, packet->data + 14, packet->len - 14) < 0) {
+ if(write(device_fd, DATA(packet) + 14, packet->len - 14) < 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device, strerror(errno));
return false;
}
break;
case DEVICE_TYPE_TAP:
- if(write(device_fd, packet->data, packet->len) < 0) {
+ if(write(device_fd, DATA(packet), packet->len) < 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device, strerror(errno));
return false;
}
/*
sptps.c -- Simple Peer-to-Peer Security
- Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>,
+ Copyright (C) 2011-2014 Guus Sliepen <guus@tinc-vpn.org>,
2010 Brandon L. Black <blblack@gmail.com>
This program is free software; you can redistribute it and/or modify
}
// Send a record (datagram version, accepts all record types, handles encryption and authentication).
-static bool send_record_priv_datagram(sptps_t *s, uint8_t type, const char *data, uint16_t len) {
+static bool send_record_priv_datagram(sptps_t *s, uint8_t type, const void *data, uint16_t len) {
char buffer[len + 21UL];
// Create header with sequence number, length and record type
}
}
// 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 char *data, uint16_t len) {
+static bool send_record_priv(sptps_t *s, uint8_t type, const void *data, uint16_t len) {
if(s->datagram)
return send_record_priv_datagram(s, type, data, len);
}
// Send an application record.
-bool sptps_send_record(sptps_t *s, uint8_t type, const char *data, uint16_t len) {
+bool sptps_send_record(sptps_t *s, uint8_t type, const void *data, uint16_t len) {
// Sanity checks: application cannot send data before handshake is finished,
// and only record types 0..127 are allowed.
if(!s->outstate)
}
// Check datagram for valid HMAC
-bool sptps_verify_datagram(sptps_t *s, const char *data, size_t len) {
+bool sptps_verify_datagram(sptps_t *s, const void *data, size_t len) {
if(!s->instate || len < 21)
return error(s, EIO, "Received short packet");
}
// Receive incoming data. Check if it contains a complete record, if so, handle it.
-bool sptps_receive_data(sptps_t *s, const char *data, size_t len) {
+bool sptps_receive_data(sptps_t *s, const void *data, size_t len) {
if(!s->state)
return error(s, EIO, "Invalid session state zero");
}
// Start a SPTPS session.
-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) {
+bool sptps_start(sptps_t *s, void *handle, bool initiator, bool datagram, ecdsa_t *mykey, ecdsa_t *hiskey, const void *label, size_t labellen, send_data_t send_data, receive_record_t receive_record) {
// Initialise struct sptps
memset(s, 0, sizeof *s);
/*
sptps.h -- Simple Peer-to-Peer Security
- Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>,
+ Copyright (C) 2011-2014 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
// Overhead for datagrams
#define SPTPS_DATAGRAM_OVERHEAD 21
-typedef bool (*send_data_t)(void *handle, uint8_t type, const char *data, size_t len);
-typedef bool (*receive_record_t)(void *handle, uint8_t type, const char *data, uint16_t len);
+typedef bool (*send_data_t)(void *handle, uint8_t type, const void *data, size_t len);
+typedef bool (*receive_record_t)(void *handle, uint8_t type, const void *data, uint16_t len);
typedef struct sptps {
bool initiator;
extern void sptps_log_quiet(sptps_t *s, int s_errno, const char *format, va_list ap);
extern void sptps_log_stderr(sptps_t *s, int s_errno, const char *format, va_list ap);
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_start(sptps_t *s, void *handle, bool initiator, bool datagram, ecdsa_t *mykey, ecdsa_t *hiskey, const void *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 char *data, uint16_t len);
-extern bool sptps_receive_data(sptps_t *s, const char *data, size_t len);
+extern bool sptps_send_record(sptps_t *s, uint8_t type, const void *data, 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 char *data, size_t len);
+extern bool sptps_verify_datagram(sptps_t *s, const void *data, size_t len);
#endif
/*
sptps_speed.c -- SPTPS benchmark
- Copyright (C) 2013 Guus Sliepen <guus@tinc-vpn.org>,
+ Copyright (C) 2013-2014 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
char *logfilename = NULL;
struct timeval now;
-static bool send_data(void *handle, uint8_t type, const char *data, size_t len) {
+static bool send_data(void *handle, uint8_t type, const void *data, size_t len) {
int fd = *(int *)handle;
send(fd, data, len, 0);
return true;
}
-static bool receive_record(void *handle, uint8_t type, const char *data, uint16_t len) {
+static bool receive_record(void *handle, uint8_t type, const void *data, uint16_t len) {
return true;
}
/*
sptps_test.c -- Simple Peer-to-Peer Security test program
- Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>,
+ Copyright (C) 2011-2014 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
static int in = 0;
static int out = 1;
-static bool send_data(void *handle, uint8_t type, const char *data, size_t len) {
+static bool send_data(void *handle, uint8_t type, const void *data, size_t len) {
char hex[len * 2 + 1];
bin2hex(data, hex, len);
if(verbose)
return true;
}
-static bool receive_record(void *handle, uint8_t type, const char *data, uint16_t len) {
+static bool receive_record(void *handle, uint8_t type, const void *data, uint16_t len) {
if(verbose)
fprintf(stderr, "Received type %d record of %hu bytes:\n", type, len);
if(!writeonly)
// Prepare environment variables to be passed to the script
char *envp[10] = {NULL};
- xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
- xasprintf(&envp[1], "DEVICE=%s", device ? : "");
- xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
- xasprintf(&envp[3], "NODE=%s", owner->name);
+ int n = 0;
+ xasprintf(&envp[n++], "NETNAME=%s", netname ? : "");
+ xasprintf(&envp[n++], "DEVICE=%s", device ? : "");
+ xasprintf(&envp[n++], "INTERFACE=%s", iface ? : "");
+ xasprintf(&envp[n++], "NODE=%s", owner->name);
if(owner != myself) {
sockaddr2str(&owner->address, &address, &port);
- // 4 and 5 are reserved for SUBNET and WEIGHT
- xasprintf(&envp[6], "REMOTEADDRESS=%s", address);
- xasprintf(&envp[7], "REMOTEPORT=%s", port);
+ xasprintf(&envp[n++], "REMOTEADDRESS=%s", address);
+ xasprintf(&envp[n++], "REMOTEPORT=%s", port);
free(port);
free(address);
}
- xasprintf(&envp[8], "NAME=%s", myself->name);
+ xasprintf(&envp[n++], "NAME=%s", myself->name);
name = up ? "subnet-up" : "subnet-down";
weight = empty;
// Prepare the SUBNET and WEIGHT variables
- if(envp[4])
- free(envp[4]);
- if(envp[5])
- free(envp[5]);
- xasprintf(&envp[4], "SUBNET=%s", netstr);
- xasprintf(&envp[5], "WEIGHT=%s", weight);
+ free(envp[n]);
+ free(envp[n + 1]);
+ xasprintf(&envp[n], "SUBNET=%s", netstr);
+ xasprintf(&envp[n + 1], "WEIGHT=%s", weight);
execute_script(name, envp);
}
weight = empty;
// Prepare the SUBNET and WEIGHT variables
- xasprintf(&envp[4], "SUBNET=%s", netstr);
- xasprintf(&envp[5], "WEIGHT=%s", weight);
+ xasprintf(&envp[n], "SUBNET=%s", netstr);
+ xasprintf(&envp[n + 1], "WEIGHT=%s", weight);
execute_script(name, envp);
}
break;
char node[4096];
+ char id[4096];
char from[4096];
char to[4096];
char subnet[4096];
switch(req) {
case REQ_DUMP_NODES: {
- int n = sscanf(line, "%*d %*d %s %s port %s %d %d %d %d %x %x %s %s %d %hd %hd %hd %ld", node, host, port, &cipher, &digest, &maclength, &compression, &options, &status_int, nexthop, via, &distance, &pmtu, &minmtu, &maxmtu, &last_state_change);
- if(n != 16) {
+ int n = sscanf(line, "%*d %*d %s %s %s port %s %d %d %d %d %x %x %s %s %d %hd %hd %hd %ld", node, id, host, port, &cipher, &digest, &maclength, &compression, &options, &status_int, nexthop, via, &distance, &pmtu, &minmtu, &maxmtu, &last_state_change);
+ if(n != 17) {
fprintf(stderr, "Unable to parse node dump from tincd: %s\n", line);
return 1;
}
} else {
if(only_reachable && !status.reachable)
continue;
- printf("%s at %s port %s cipher %d digest %d maclength %d compression %d options %x status %04x nexthop %s via %s distance %d pmtu %hd (min %hd max %hd)\n",
- node, host, port, cipher, digest, maclength, compression, options, status_int, nexthop, via, distance, pmtu, minmtu, maxmtu);
+ printf("%s id %s at %s port %s cipher %d digest %d maclength %d compression %d options %x status %04x nexthop %s via %s distance %d pmtu %hd (min %hd max %hd)\n",
+ node, id, host, port, cipher, digest, maclength, compression, options, status_int, nexthop, via, distance, pmtu, minmtu, maxmtu);
}
} break;
}
case 2: {
- if((inlen = read(data_fd, packet->data, MTU)) <= 0) {
+ if((inlen = read(data_fd, DATA(packet), MTU)) <= 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
device, strerror(errno));
event_exit();
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s",
packet->len, device_info);
- if(write(write_fd, packet->data, packet->len) < 0) {
+ if(write(write_fd, DATA(packet), packet->len) < 0) {
if(errno != EINTR && errno != EAGAIN) {
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device, strerror(errno));
event_exit();
}
static bool read_packet(vpn_packet_t *packet) {
- int lenin = (ssize_t)plug.vde_recv(conn, packet->data, MTU, 0);
+ int lenin = (ssize_t)plug.vde_recv(conn, DATA(packet), MTU, 0);
if(lenin <= 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno));
event_exit();
}
static bool write_packet(vpn_packet_t *packet) {
- if((ssize_t)plug.vde_send(conn, packet->data, packet->len, 0) < 0) {
+ if((ssize_t)plug.vde_send(conn, DATA(packet), packet->len, 0) < 0) {
if(errno != EINTR && errno != EAGAIN) {
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device, strerror(errno));
event_exit();