Add mud_get_paths() to export all paths

Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
This commit is contained in:
Adrien Gallouët
2018-02-26 23:57:39 +00:00
parent 81b279b060
commit 5a62bd7faa
2 changed files with 140 additions and 96 deletions

197
mud.c
View File

@@ -1,5 +1,3 @@
#include "mud.h"
#if defined __APPLE__ #if defined __APPLE__
#define __APPLE_USE_RFC_3542 #define __APPLE_USE_RFC_3542
#endif #endif
@@ -8,15 +6,15 @@
#define _GNU_SOURCE #define _GNU_SOURCE
#endif #endif
#include "mud.h"
#include <errno.h> #include <errno.h>
#include <inttypes.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h> #include <sys/time.h>
#include <arpa/inet.h> #include <arpa/inet.h>
@@ -65,7 +63,6 @@
#define MUD_KEY_SIZE (32U) #define MUD_KEY_SIZE (32U)
#define MUD_MAC_SIZE (16U) #define MUD_MAC_SIZE (16U)
#define MUD_PUB_SIZE (crypto_scalarmult_BYTES) #define MUD_PUB_SIZE (crypto_scalarmult_BYTES)
#define MUD_SID_SIZE (8U)
#define MUD_PACKET_MIN_SIZE (MUD_U48_SIZE + MUD_MAC_SIZE) #define MUD_PACKET_MIN_SIZE (MUD_U48_SIZE + MUD_MAC_SIZE)
#define MUD_PACKET_MAX_SIZE (1500U) #define MUD_PACKET_MAX_SIZE (1500U)
@@ -80,33 +77,6 @@
#define MUD_SEND_TIMEOUT (MUD_ONE_SEC) #define MUD_SEND_TIMEOUT (MUD_ONE_SEC)
#define MUD_TIME_TOLERANCE (10 * MUD_ONE_MIN) #define MUD_TIME_TOLERANCE (10 * MUD_ONE_MIN)
struct mud_path {
enum mud_state state;
struct sockaddr_storage local_addr, addr;
struct {
uint64_t send_time;
int remote;
struct {
size_t remote;
size_t local;
} mtu;
unsigned char kiss[MUD_SID_SIZE];
} conf;
uint64_t rdt;
uint64_t rtt;
uint64_t sdt;
uint64_t rst;
uint64_t r_sdt;
uint64_t r_rdt;
uint64_t r_rst;
int64_t r_dt;
uint64_t limit;
uint64_t recv_time;
uint64_t send_time;
uint64_t stat_time;
struct mud_path *next;
};
struct mud_crypto_opt { struct mud_crypto_opt {
unsigned char *dst; unsigned char *dst;
struct { struct {
@@ -142,7 +112,7 @@ struct mud_packet {
} hdr; } hdr;
union { union {
struct { struct {
unsigned char kiss[MUD_SID_SIZE]; unsigned char kiss[MUD_KISS_SIZE];
unsigned char mtu[MUD_U48_SIZE]; unsigned char mtu[MUD_U48_SIZE];
unsigned char state; unsigned char state;
struct mud_public public; struct mud_public public;
@@ -161,7 +131,8 @@ struct mud {
int fd; int fd;
uint64_t send_timeout; uint64_t send_timeout;
uint64_t time_tolerance; uint64_t time_tolerance;
struct mud_path *path; struct mud_path *paths;
unsigned count;
struct { struct {
uint64_t time; uint64_t time;
unsigned char secret[crypto_scalarmult_SCALARBYTES]; unsigned char secret[crypto_scalarmult_SCALARBYTES];
@@ -177,7 +148,7 @@ struct mud {
int set; int set;
struct sockaddr_storage addr; struct sockaddr_storage addr;
} peer; } peer;
unsigned char kiss[MUD_SID_SIZE]; unsigned char kiss[MUD_KISS_SIZE];
}; };
static int static int
@@ -392,41 +363,92 @@ mud_cmp_addr(struct sockaddr_storage *a, struct sockaddr_storage *b)
return 1; return 1;
} }
struct mud_path *
mud_get_paths(struct mud *mud, unsigned *ret_count)
{
unsigned count = 0;
if (!ret_count)
return NULL;
for (unsigned i = 0; i < mud->count; i++) {
struct mud_path *path = &mud->paths[i];
if (path->state != MUD_EMPTY)
count++;
}
size_t size = count * sizeof(struct mud_path);
if (!size)
return NULL;
struct mud_path *paths = malloc(size);
if (!paths)
return NULL;
count = 0;
for (unsigned i = 0; i < mud->count; i++) {
struct mud_path *path = &mud->paths[i];
if (path->state != MUD_EMPTY)
memcpy(&paths[count++], path, sizeof(struct mud_path));
}
*ret_count = count;
return paths;
}
static struct mud_path * static struct mud_path *
mud_get_path(struct mud *mud, struct sockaddr_storage *local_addr, mud_get_path(struct mud *mud, struct sockaddr_storage *local_addr,
struct sockaddr_storage *addr, int create) struct sockaddr_storage *addr, int create)
{ {
struct mud_path *path;
if (local_addr->ss_family != addr->ss_family) { if (local_addr->ss_family != addr->ss_family) {
errno = EINVAL; errno = EINVAL;
return NULL; return NULL;
} }
for (path = mud->path; path; path = path->next) { for (unsigned i = 0; i < mud->count; i++) {
if (mud_cmp_addr(local_addr, &path->local_addr)) struct mud_path *path = &mud->paths[i];
continue;
if (mud_cmp_addr(addr, &path->addr)) if (path->state &&
continue; !mud_cmp_addr(local_addr, &path->local_addr) &&
!mud_cmp_addr(addr, &path->addr))
break; return path;
} }
if (path || !create) if (!create)
return path;
path = calloc(1, sizeof(struct mud_path));
if (!path)
return NULL; return NULL;
memmove(&path->local_addr, local_addr, sizeof(*local_addr)); struct mud_path *path = NULL;
memmove(&path->addr, addr, sizeof(*addr));
for (unsigned i = 0; i < mud->count; i++) {
if (mud->paths[i].state == MUD_EMPTY) {
path = &mud->paths[i];
break;
}
}
if (!path) {
struct mud_path *paths = realloc(mud->paths,
(mud->count + 1) * sizeof(struct mud_path));
if (!paths)
return NULL;
mud->count++;
mud->paths = paths;
path = &paths[mud->count - 1];
}
memcpy(&path->local_addr, local_addr, sizeof(*local_addr));
memcpy(&path->addr, addr, sizeof(*addr));
path->conf.mtu.local = mud->mtu; // XXX path->conf.mtu.local = mud->mtu; // XXX
path->next = mud->path;
mud->path = path;
return path; return path;
} }
@@ -564,7 +586,8 @@ mud_set_time_tolerance(struct mud *mud, unsigned long msec)
int int
mud_set_state(struct mud *mud, struct sockaddr *peer, enum mud_state state) mud_set_state(struct mud *mud, struct sockaddr *peer, enum mud_state state)
{ {
if (!mud->peer.set || (state >= MUD_LAST)) { if (!mud->peer.set ||
(state < MUD_DOWN) || (state > MUD_UP)) {
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
@@ -574,7 +597,7 @@ mud_set_state(struct mud *mud, struct sockaddr *peer, enum mud_state state)
if (mud_ss_from_sa(&addr, peer)) if (mud_ss_from_sa(&addr, peer))
return -1; return -1;
struct mud_path *path = mud_get_path(mud, &addr, &mud->peer.addr, state != MUD_DOWN); struct mud_path *path = mud_get_path(mud, &addr, &mud->peer.addr, state > MUD_DOWN);
if (!path) if (!path)
return -1; return -1;
@@ -591,11 +614,13 @@ size_t
mud_get_mtu(struct mud *mud) mud_get_mtu(struct mud *mud)
{ {
size_t mtu = mud->mtu; size_t mtu = mud->mtu;
struct mud_path *path;
for (path = mud->path; path; path = path->next) { for (unsigned i = 0; i < mud->count; i++) {
struct mud_path *path = &mud->paths[i];
if (path->conf.mtu.local && path->conf.mtu.local < mtu) if (path->conf.mtu.local && path->conf.mtu.local < mtu)
mtu = path->conf.mtu.local; mtu = path->conf.mtu.local;
if (path->conf.mtu.remote && path->conf.mtu.remote < mtu) if (path->conf.mtu.remote && path->conf.mtu.remote < mtu)
mtu = path->conf.mtu.remote; mtu = path->conf.mtu.remote;
} }
@@ -614,11 +639,12 @@ mud_set_mtu(struct mud *mud, size_t mtu)
mtu -= MUD_PACKET_MIN_SIZE; mtu -= MUD_PACKET_MIN_SIZE;
struct mud_path *path; for (unsigned i = 0; i < mud->count; i++) {
struct mud_path *path = &mud->paths[i];
for (path = mud->path; path; path = path->next) {
if (path->conf.mtu.local == mtu) if (path->conf.mtu.local == mtu)
continue; continue;
path->conf.mtu.local = mtu; path->conf.mtu.local = mtu;
path->conf.remote = 0; path->conf.remote = 0;
} }
@@ -789,17 +815,11 @@ mud_delete(struct mud *mud)
if (!mud) if (!mud)
return; return;
while (mud->path) { if (mud->paths)
struct mud_path *path = mud->path; free(mud->paths);
mud->path = path->next;
free(path);
}
if (mud->fd != -1) { if (mud->fd >= 0)
int err = errno;
close(mud->fd); close(mud->fd);
errno = err;
}
sodium_free(mud); sodium_free(mud);
} }
@@ -962,21 +982,13 @@ mud_packet_send(struct mud *mud, enum mud_packet_code code,
} }
static void static void
mud_kiss_path(struct mud *mud, struct mud_path *path) mud_kiss_path(struct mud *mud, unsigned char *kiss)
{ {
struct mud_path **p = &mud->path; for (unsigned i = 0; i < mud->count; i++) {
struct mud_path *path = &mud->paths[i];
while (*p) { if (memcmp(path->conf.kiss, kiss, sizeof(path->conf.kiss)))
struct mud_path *t = *p; memset(path, 0, sizeof(struct mud_path));
if ((t == path) ||
!memcmp(t->conf.kiss, path->conf.kiss, sizeof(path->conf.kiss))) {
p = &t->next;
continue;
}
*p = t->next;
free(t);
} }
} }
@@ -1037,7 +1049,7 @@ mud_packet_recv(struct mud *mud, struct mud_path *path,
mud->crypto.use_next = 1; mud->crypto.use_next = 1;
} }
} else { } else {
mud_kiss_path(mud, path); mud_kiss_path(mud, path->conf.kiss);
mud_keyx(mud, packet->data.conf.public.local, mud_keyx(mud, packet->data.conf.public.local,
packet->data.conf.aes); packet->data.conf.aes);
path->state = (enum mud_state)packet->data.conf.state; path->state = (enum mud_state)packet->data.conf.state;
@@ -1156,10 +1168,10 @@ mud_update(struct mud *mud)
uint64_t now = mud_now(); uint64_t now = mud_now();
int update_keyx = !mud_keyx_init(mud, now); int update_keyx = !mud_keyx_init(mud, now);
struct mud_path *path = mud->path; for (unsigned i = 0; i < mud->count; i++) {
struct mud_path *path = &mud->paths[i];
for (; path; path = path->next) { if (path->state < MUD_DOWN)
if (path->state == MUD_DOWN)
continue; continue;
if (update_keyx || mud_timeout(now, path->recv_time, mud->send_timeout + MUD_ONE_SEC)) if (update_keyx || mud_timeout(now, path->recv_time, mud->send_timeout + MUD_ONE_SEC))
@@ -1196,17 +1208,18 @@ mud_send(struct mud *mud, const void *data, size_t size, int tc)
return -1; return -1;
} }
struct mud_path *path;
struct mud_path *path_min = NULL; struct mud_path *path_min = NULL;
struct mud_path *path_backup = NULL; struct mud_path *path_backup = NULL;
int64_t limit_min = INT64_MAX; int64_t limit_min = INT64_MAX;
for (path = mud->path; path; path = path->next) { for (unsigned i = 0; i < mud->count; i++) {
switch (path->state) { struct mud_path *path = &mud->paths[i];
case MUD_BACKUP: path_backup = path; /* FALLTHRU */
case MUD_DOWN: continue; if (path->state <= MUD_DOWN) {
default: break; if (path->state == MUD_BACKUP)
path_backup = path;
continue;
} }
int64_t limit = path->limit; int64_t limit = path->limit;

39
mud.h
View File

@@ -1,15 +1,44 @@
#pragma once #pragma once
#include <stddef.h> #include <stddef.h>
#include <inttypes.h>
#include <sys/socket.h>
#define MUD_KISS_SIZE (8U)
struct mud; struct mud;
struct sockaddr;
enum mud_state { enum mud_state {
MUD_UP = 0, MUD_EMPTY = 0,
MUD_BACKUP,
MUD_DOWN, MUD_DOWN,
MUD_LAST, MUD_BACKUP,
MUD_UP,
};
struct mud_path {
enum mud_state state;
struct sockaddr_storage local_addr, addr;
struct {
uint64_t send_time;
int remote;
struct {
size_t remote;
size_t local;
} mtu;
unsigned char kiss[MUD_KISS_SIZE];
} conf;
uint64_t rdt;
uint64_t rtt;
uint64_t sdt;
uint64_t rst;
uint64_t r_sdt;
uint64_t r_rdt;
uint64_t r_rst;
int64_t r_dt;
uint64_t limit;
uint64_t recv_time;
uint64_t send_time;
uint64_t stat_time;
}; };
struct mud *mud_create (struct sockaddr *); struct mud *mud_create (struct sockaddr *);
@@ -34,3 +63,5 @@ int mud_peer (struct mud *, struct sockaddr *);
int mud_recv (struct mud *, void *, size_t); int mud_recv (struct mud *, void *, size_t);
int mud_send (struct mud *, const void *, size_t, int); int mud_send (struct mud *, const void *, size_t, int);
struct mud_path *mud_get_paths(struct mud *, unsigned *);