Compare commits

...

11 Commits

Author SHA1 Message Date
e4988b9e9c switch to libsodium implementation of aegis256 2020-06-09 20:59:55 +02:00
0183b35acf remove aegis256 submodule 2020-06-09 20:44:38 +02:00
Adrien Gallouët
faeb599a19 Rework mud_set_conf()
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2020-04-17 21:25:08 +00:00
Adrien Gallouët
a4e72918df Inline and move some functions
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2020-04-03 08:32:20 +00:00
Adrien Gallouët
d7e8dbe0e7 Code cleanup
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2020-03-30 20:43:49 +00:00
Adrien Gallouët
71d16f25ff Don't use a static mtid
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2020-03-26 22:31:33 +00:00
Adrien Gallouët
c426cef08b Fix non little endian arch
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2020-03-25 20:43:54 +00:00
Adrien Gallouët
bda2c6eaa7 Wait a few packets before computing the loss
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2020-03-07 15:13:37 +00:00
Adrien Gallouët
d68aee8249 Allow a different loss_limit per path
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2020-03-07 14:27:47 +00:00
Adrien Gallouët
2f966bb365 Fix fixed rate
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2020-02-29 09:57:08 +00:00
Adrien Gallouët
4a7740f70f Fix beat conf
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2020-02-21 16:37:04 +00:00
5 changed files with 189 additions and 244 deletions

4
.gitmodules vendored
View File

@@ -1,4 +0,0 @@
[submodule "aegis256"]
path = aegis256
url = https://github.com/angt/aegis256
ignore = dirty

Submodule aegis256 deleted from 42b0b3da1d

414
mud.c
View File

@@ -22,7 +22,6 @@
#include <netinet/in.h> #include <netinet/in.h>
#include <sodium.h> #include <sodium.h>
#include "aegis256/aegis256.h"
#if !defined MSG_CONFIRM #if !defined MSG_CONFIRM
#define MSG_CONFIRM 0 #define MSG_CONFIRM 0
@@ -125,12 +124,12 @@ struct mud_msg {
unsigned char mtu[2]; unsigned char mtu[2];
unsigned char loss; unsigned char loss;
unsigned char fixed_rate; unsigned char fixed_rate;
unsigned char loss_limit;
struct mud_addr addr; struct mud_addr addr;
}; };
struct mud_keyx { struct mud_keyx {
uint64_t time; uint64_t time;
uint64_t timeout;
unsigned char secret[crypto_scalarmult_SCALARBYTES]; unsigned char secret[crypto_scalarmult_SCALARBYTES];
unsigned char remote[MUD_PUBKEY_SIZE]; unsigned char remote[MUD_PUBKEY_SIZE];
unsigned char local[MUD_PUBKEY_SIZE]; unsigned char local[MUD_PUBKEY_SIZE];
@@ -142,16 +141,13 @@ struct mud_keyx {
struct mud { struct mud {
int fd; int fd;
int backup; int backup;
uint64_t keepalive; struct mud_conf conf;
uint64_t time_tolerance;
uint64_t loss_limit;
struct sockaddr_storage addr; struct sockaddr_storage addr;
struct mud_path *paths; struct mud_path *paths;
unsigned count; unsigned count;
struct mud_keyx keyx; struct mud_keyx keyx;
uint64_t last_recv_time; uint64_t last_recv_time;
size_t mtu; size_t mtu;
int tc;
struct { struct {
int set; int set;
struct sockaddr_storage addr; struct sockaddr_storage addr;
@@ -161,36 +157,29 @@ struct mud {
uint64_t window; uint64_t window;
uint64_t window_time; uint64_t window_time;
uint64_t base_time; uint64_t base_time;
#if defined __APPLE__
mach_timebase_info_data_t mtid;
#endif
}; };
static int static inline int
mud_addr_is_v6(struct mud_addr *addr)
{
static const unsigned char v4mapped[] = {
[10] = 255,
[11] = 255,
};
return memcmp(addr->v6, v4mapped, sizeof(v4mapped));
}
static int
mud_encrypt_opt(const struct mud_crypto_key *k, mud_encrypt_opt(const struct mud_crypto_key *k,
const struct mud_crypto_opt *c) const struct mud_crypto_opt *c)
{ {
if (k->aes) { if (k->aes) {
unsigned char npub[AEGIS256_NPUBBYTES]; unsigned char npub[crypto_aead_aegis256_NPUBBYTES];
memcpy(npub, c->dst, MUD_TIME_SIZE); memcpy(npub, c->dst, MUD_TIME_SIZE);
memset(npub + MUD_TIME_SIZE, 0, sizeof(npub) - MUD_TIME_SIZE); memset(npub + MUD_TIME_SIZE, 0, sizeof(npub) - MUD_TIME_SIZE);
return aegis256_encrypt( return crypto_aead_aegis256_encrypt(
c->dst + MUD_TIME_SIZE, c->dst + MUD_TIME_SIZE,
NULL, NULL,
c->src, c->src,
c->size, c->size,
c->dst, c->dst,
MUD_TIME_SIZE, MUD_TIME_SIZE,
NULL, // nsec
npub, npub,
k->encrypt.key k->encrypt.key
); );
@@ -214,19 +203,20 @@ mud_encrypt_opt(const struct mud_crypto_key *k,
} }
} }
static int static inline int
mud_decrypt_opt(const struct mud_crypto_key *k, mud_decrypt_opt(const struct mud_crypto_key *k,
const struct mud_crypto_opt *c) const struct mud_crypto_opt *c)
{ {
if (k->aes) { if (k->aes) {
unsigned char npub[AEGIS256_NPUBBYTES]; unsigned char npub[crypto_aead_aegis256_NPUBBYTES];
memcpy(npub, c->src, MUD_TIME_SIZE); memcpy(npub, c->src, MUD_TIME_SIZE);
memset(npub + MUD_TIME_SIZE, 0, sizeof(npub) - MUD_TIME_SIZE); memset(npub + MUD_TIME_SIZE, 0, sizeof(npub) - MUD_TIME_SIZE);
return aegis256_decrypt( return crypto_aead_aegis256_decrypt(
c->dst, c->dst,
NULL, NULL,
NULL, // nsec
c->src + MUD_TIME_SIZE, c->src + MUD_TIME_SIZE,
c->size - MUD_TIME_SIZE, c->size - MUD_TIME_SIZE,
c->src, MUD_TIME_SIZE, c->src, MUD_TIME_SIZE,
@@ -252,47 +242,39 @@ mud_decrypt_opt(const struct mud_crypto_key *k,
} }
} }
static void static inline void
mud_store(unsigned char *dst, uint64_t src, size_t size) mud_store(unsigned char *dst, uint64_t src, size_t size)
{ {
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
memcpy(dst, &src, size);
#else
dst[0] = (unsigned char)(src); dst[0] = (unsigned char)(src);
dst[1] = (unsigned char)(src >> 8); dst[1] = (unsigned char)(src >> 8);
if (size < 48) return; if (size <= 2) return;
dst[2] = (unsigned char)(src >> 16); dst[2] = (unsigned char)(src >> 16);
dst[3] = (unsigned char)(src >> 24); dst[3] = (unsigned char)(src >> 24);
dst[4] = (unsigned char)(src >> 32); dst[4] = (unsigned char)(src >> 32);
dst[5] = (unsigned char)(src >> 40); dst[5] = (unsigned char)(src >> 40);
if (size < 64) return; if (size <= 6) return;
dst[6] = (unsigned char)(src >> 48); dst[6] = (unsigned char)(src >> 48);
dst[7] = (unsigned char)(src >> 56); dst[7] = (unsigned char)(src >> 56);
#endif
} }
static uint64_t static inline uint64_t
mud_load(const unsigned char *src, size_t size) mud_load(const unsigned char *src, size_t size)
{ {
uint64_t ret = 0; uint64_t ret = 0;
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
memcpy(&ret, src, size);
#else
ret = src[0]; ret = src[0];
ret |= ((uint64_t)src[1]) << 8; ret |= ((uint64_t)src[1]) << 8;
if (size < 48) return ret; if (size <= 2) return ret;
ret |= ((uint64_t)src[2]) << 16; ret |= ((uint64_t)src[2]) << 16;
ret |= ((uint64_t)src[3]) << 24; ret |= ((uint64_t)src[3]) << 24;
ret |= ((uint64_t)src[4]) << 32; ret |= ((uint64_t)src[4]) << 32;
ret |= ((uint64_t)src[5]) << 40; ret |= ((uint64_t)src[5]) << 40;
if (size < 64) return ret; if (size <= 6) return ret;
ret |= ((uint64_t)src[6]) << 48; ret |= ((uint64_t)src[6]) << 48;
ret |= ((uint64_t)src[7]) << 56; ret |= ((uint64_t)src[7]) << 56;
#endif
return ret; return ret;
} }
static uint64_t static inline uint64_t
mud_time(void) mud_time(void)
{ {
#if defined CLOCK_REALTIME #if defined CLOCK_REALTIME
@@ -310,15 +292,12 @@ mud_time(void)
#endif #endif
} }
static uint64_t static inline uint64_t
mud_now(struct mud *mud) mud_now(struct mud *mud)
{ {
#if defined __APPLE__ #if defined __APPLE__
static mach_timebase_info_data_t mtid;
if (!mtid.denom)
mach_timebase_info(&mtid);
return MUD_TIME_MASK(mud->base_time return MUD_TIME_MASK(mud->base_time
+ (mach_absolute_time() * mtid.numer / mtid.denom) + (mach_absolute_time() * mud->mtid.numer / mud->mtid.denom)
/ 1000ULL); / 1000ULL);
#elif defined CLOCK_MONOTONIC #elif defined CLOCK_MONOTONIC
struct timespec tv; struct timespec tv;
@@ -331,19 +310,19 @@ mud_now(struct mud *mud)
#endif #endif
} }
static uint64_t static inline uint64_t
mud_abs_diff(uint64_t a, uint64_t b) mud_abs_diff(uint64_t a, uint64_t b)
{ {
return (a >= b) ? a - b : b - a; return (a >= b) ? a - b : b - a;
} }
static int static inline int
mud_timeout(uint64_t now, uint64_t last, uint64_t timeout) mud_timeout(uint64_t now, uint64_t last, uint64_t timeout)
{ {
return (!last) || (MUD_TIME_MASK(now - last) >= timeout); return (!last) || (MUD_TIME_MASK(now - last) >= timeout);
} }
static void static inline void
mud_unmapv4(struct sockaddr_storage *addr) mud_unmapv4(struct sockaddr_storage *addr)
{ {
if (addr->ss_family != AF_INET6) if (addr->ss_family != AF_INET6)
@@ -427,7 +406,7 @@ mud_send_path(struct mud *mud, struct mud_path *path, uint64_t now,
cmsg->cmsg_level = IPPROTO_IP; cmsg->cmsg_level = IPPROTO_IP;
cmsg->cmsg_type = IP_TOS; cmsg->cmsg_type = IP_TOS;
cmsg->cmsg_len = CMSG_LEN(sizeof(int)); cmsg->cmsg_len = CMSG_LEN(sizeof(int));
memcpy(CMSG_DATA(cmsg), &mud->tc, sizeof(int)); memcpy(CMSG_DATA(cmsg), &mud->conf.tc, sizeof(int));
} else if (path->addr.ss_family == AF_INET6) { } else if (path->addr.ss_family == AF_INET6) {
msg.msg_namelen = sizeof(struct sockaddr_in6); msg.msg_namelen = sizeof(struct sockaddr_in6);
@@ -449,7 +428,7 @@ mud_send_path(struct mud *mud, struct mud_path *path, uint64_t now,
cmsg->cmsg_level = IPPROTO_IPV6; cmsg->cmsg_level = IPPROTO_IPV6;
cmsg->cmsg_type = IPV6_TCLASS; cmsg->cmsg_type = IPV6_TCLASS;
cmsg->cmsg_len = CMSG_LEN(sizeof(int)); cmsg->cmsg_len = CMSG_LEN(sizeof(int));
memcpy(CMSG_DATA(cmsg), &mud->tc, sizeof(int)); memcpy(CMSG_DATA(cmsg), &mud->conf.tc, sizeof(int));
} else { } else {
errno = EAFNOSUPPORT; errno = EAFNOSUPPORT;
return -1; return -1;
@@ -476,35 +455,6 @@ mud_sso_int(int fd, int level, int optname, int opt)
return setsockopt(fd, level, optname, &opt, sizeof(opt)); return setsockopt(fd, level, optname, &opt, sizeof(opt));
} }
static int
mud_cmp_addr(struct sockaddr_storage *a, struct sockaddr_storage *b)
{
if (a->ss_family != b->ss_family)
return 1;
if (a->ss_family == AF_INET) {
struct sockaddr_in *_a = (struct sockaddr_in *)a;
struct sockaddr_in *_b = (struct sockaddr_in *)b;
return ((memcmp(&_a->sin_port, &_b->sin_port,
sizeof(_a->sin_port))) ||
(memcmp(&_a->sin_addr, &_b->sin_addr,
sizeof(_a->sin_addr))));
}
if (a->ss_family == AF_INET6) {
struct sockaddr_in6 *_a = (struct sockaddr_in6 *)a;
struct sockaddr_in6 *_b = (struct sockaddr_in6 *)b;
return ((memcmp(&_a->sin6_port, &_b->sin6_port,
sizeof(_a->sin6_port))) ||
(memcmp(&_a->sin6_addr, &_b->sin6_addr,
sizeof(_a->sin6_addr))));
}
return 1;
}
struct mud_path * struct mud_path *
mud_get_paths(struct mud *mud, unsigned *ret_count) mud_get_paths(struct mud *mud, unsigned *ret_count)
{ {
@@ -548,34 +498,6 @@ mud_get_paths(struct mud *mud, unsigned *ret_count)
return paths; return paths;
} }
static void
mud_copy_port(struct sockaddr_storage *d, struct sockaddr_storage *s)
{
void *port;
switch (s->ss_family) {
case AF_INET:
port = &((struct sockaddr_in *)s)->sin_port;
break;
case AF_INET6:
port = &((struct sockaddr_in6 *)s)->sin6_port;
break;
default:
return;
}
switch (d->ss_family) {
case AF_INET:
memcpy(&((struct sockaddr_in *)d)->sin_port,
port, sizeof(in_port_t));
break;
case AF_INET6:
memcpy(&((struct sockaddr_in6 *)d)->sin6_port,
port, sizeof(in_port_t));
break;
}
}
static void static void
mud_reset_path(struct mud_path *path) mud_reset_path(struct mud_path *path)
{ {
@@ -584,6 +506,48 @@ mud_reset_path(struct mud_path *path)
path->mtu.last = 0; path->mtu.last = 0;
} }
static inline int
mud_cmp_addr(struct sockaddr_storage *a, struct sockaddr_storage *b)
{
if (a->ss_family != b->ss_family)
return 1;
if (a->ss_family == AF_INET) {
struct sockaddr_in *_a = (struct sockaddr_in *)a;
struct sockaddr_in *_b = (struct sockaddr_in *)b;
return memcmp(&_a->sin_addr, &_b->sin_addr, sizeof(_a->sin_addr));
}
if (a->ss_family == AF_INET6) {
struct sockaddr_in6 *_a = (struct sockaddr_in6 *)a;
struct sockaddr_in6 *_b = (struct sockaddr_in6 *)b;
return memcmp(&_a->sin6_addr, &_b->sin6_addr, sizeof(_a->sin6_addr));
}
return 1;
}
static inline int
mud_cmp_port(struct sockaddr_storage *a, struct sockaddr_storage *b)
{
if (a->ss_family != b->ss_family)
return 1;
if (a->ss_family == AF_INET) {
struct sockaddr_in *_a = (struct sockaddr_in *)a;
struct sockaddr_in *_b = (struct sockaddr_in *)b;
return memcmp(&_a->sin_port, &_b->sin_port, sizeof(_a->sin_port));
}
if (a->ss_family == AF_INET6) {
struct sockaddr_in6 *_a = (struct sockaddr_in6 *)a;
struct sockaddr_in6 *_b = (struct sockaddr_in6 *)b;
return memcmp(&_a->sin6_port, &_b->sin6_port, sizeof(_a->sin6_port));
}
return 1;
}
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)
@@ -593,15 +557,18 @@ mud_get_path(struct mud *mud, struct sockaddr_storage *local_addr,
return NULL; return NULL;
} }
mud_copy_port(local_addr, &mud->addr);
for (unsigned i = 0; i < mud->count; i++) { for (unsigned i = 0; i < mud->count; i++) {
struct mud_path *path = &mud->paths[i]; struct mud_path *path = &mud->paths[i];
if ((path->state != MUD_EMPTY) && if (path->state == MUD_EMPTY)
(!mud_cmp_addr(local_addr, &path->local_addr)) && continue;
(!mud_cmp_addr(addr, &path->addr)))
return path; if (mud_cmp_addr(local_addr, &path->local_addr) ||
mud_cmp_addr(addr, &path->addr) ||
mud_cmp_port(addr, &path->addr))
continue;
return path;
} }
if (!create) { if (!create) {
@@ -644,6 +611,7 @@ mud_get_path(struct mud *mud, struct sockaddr_storage *local_addr,
path->state = MUD_UP; path->state = MUD_UP;
path->conf.beat = 100 * MUD_ONE_MSEC; path->conf.beat = 100 * MUD_ONE_MSEC;
path->conf.fixed_rate = 1; path->conf.fixed_rate = 1;
path->conf.loss_limit = 255;
path->idle = mud_now(mud); path->idle = mud_now(mud);
return path; return path;
@@ -738,69 +706,36 @@ mud_set_key(struct mud *mud, unsigned char *key, size_t size)
return 0; return 0;
} }
static int
mud_set_msec(uint64_t *dst, unsigned long msec)
{
if (!msec)
return 0;
const uint64_t x = msec * MUD_ONE_MSEC;
if ((x >> MUD_TIME_BITS) ||
((uint64_t)msec != x / MUD_ONE_MSEC)) {
errno = ERANGE;
return -1;
}
*dst = x;
return 0;
}
int int
mud_set_conf(struct mud *mud, struct mud_conf *conf) mud_set_conf(struct mud *mud, struct mud_conf *conf)
{ {
uint64_t keepalive = mud->keepalive; struct mud_conf c = mud->conf;
uint64_t timetolerance = mud->time_tolerance; int ret = 0;
uint64_t kxtimeout = mud->keyx.timeout;
uint64_t losslimit = mud->loss_limit;
int tc = mud->tc;
if (mud_set_msec(&keepalive, conf->keepalive)) if (conf->keepalive)
return -1; c.keepalive = conf->keepalive;
if (mud_set_msec(&timetolerance, conf->timetolerance)) if (conf->timetolerance)
return -2; c.timetolerance = conf->timetolerance;
if (mud_set_msec(&kxtimeout, conf->kxtimeout)) if (conf->kxtimeout)
return -3; c.kxtimeout = conf->kxtimeout;
if (conf->losslimit) {
if (conf->losslimit > 100) {
errno = ERANGE;
return -4;
}
losslimit = conf->losslimit * 255U / 100U;
}
if (conf->tc & 1) { if (conf->tc & 1) {
tc = conf->tc >> 1; int tc = conf->tc >> 1;
if (tc < 0 || tc > 255) { if (tc < 0 || tc > 255) {
errno = ERANGE; errno = ERANGE;
return -5; ret = -1;
} }
c.tc = tc;
} else if (conf->tc) { } else if (conf->tc) {
errno = EINVAL; errno = EINVAL;
return -5; ret = -1;
} }
mud->keepalive = keepalive; *conf = mud->conf = c;
mud->time_tolerance = timetolerance;
mud->keyx.timeout = kxtimeout;
mud->loss_limit = losslimit;
mud->tc = tc;
return 0; return ret;
} }
size_t size_t
@@ -869,9 +804,11 @@ mud_keyx(struct mud_keyx *kx, unsigned char *remote, int aes)
} }
static int static int
mud_keyx_init(struct mud_keyx *kx, uint64_t now) mud_keyx_init(struct mud *mud, uint64_t now)
{ {
if (!mud_timeout(now, kx->time, kx->timeout)) struct mud_keyx *kx = &mud->keyx;
if (!mud_timeout(now, kx->time, mud->conf.kxtimeout))
return 1; return 1;
static const unsigned char test[crypto_scalarmult_BYTES] = { static const unsigned char test[crypto_scalarmult_BYTES] = {
@@ -896,7 +833,7 @@ mud_keyx_init(struct mud_keyx *kx, uint64_t now)
int int
mud_set_aes(struct mud *mud) mud_set_aes(struct mud *mud)
{ {
if (!aegis256_is_available()) { if (!crypto_aead_aegis256_is_available()) {
errno = ENOTSUP; errno = ENOTSUP;
return -1; return -1;
} }
@@ -948,14 +885,17 @@ mud_create(struct sockaddr *addr)
return NULL; return NULL;
} }
mud->keepalive = 25 * MUD_ONE_SEC; mud->conf.keepalive = 25 * MUD_ONE_SEC;
mud->time_tolerance = 10 * MUD_ONE_MIN; mud->conf.timetolerance = 10 * MUD_ONE_MIN;
mud->keyx.timeout = 60 * MUD_ONE_MIN; mud->conf.kxtimeout = 60 * MUD_ONE_MIN;
mud->tc = 192; // CS6 mud->conf.tc = 192; // CS6
mud->loss_limit = 25;
memcpy(&mud->addr, addr, addrlen); memcpy(&mud->addr, addr, addrlen);
#if defined __APPLE__
mach_timebase_info(&mud->mtid);
#endif
uint64_t now = mud_now(mud); uint64_t now = mud_now(mud);
uint64_t base_time = mud_time(); uint64_t base_time = mud_time();
@@ -1054,32 +994,25 @@ mud_localaddr(struct sockaddr_storage *addr, struct msghdr *msg)
for (; cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { for (; cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
if ((cmsg->cmsg_level == IPPROTO_IP) && if ((cmsg->cmsg_level == IPPROTO_IP) &&
(cmsg->cmsg_type == MUD_PKTINFO)) (cmsg->cmsg_type == MUD_PKTINFO)) {
break; addr->ss_family = AF_INET;
memcpy(&((struct sockaddr_in *)addr)->sin_addr,
MUD_PKTINFO_SRC(CMSG_DATA(cmsg)),
sizeof(struct in_addr));
return 0;
}
if ((cmsg->cmsg_level == IPPROTO_IPV6) && if ((cmsg->cmsg_level == IPPROTO_IPV6) &&
(cmsg->cmsg_type == IPV6_PKTINFO)) (cmsg->cmsg_type == IPV6_PKTINFO)) {
break; addr->ss_family = AF_INET6;
memcpy(&((struct sockaddr_in6 *)addr)->sin6_addr,
&((struct in6_pktinfo *)CMSG_DATA(cmsg))->ipi6_addr,
sizeof(struct in6_addr));
mud_unmapv4(addr);
return 0;
}
} }
if (!cmsg) return 1;
return 1;
memset(addr, 0, sizeof(struct sockaddr_storage));
if (cmsg->cmsg_level == IPPROTO_IP) {
addr->ss_family = AF_INET;
memcpy(&((struct sockaddr_in *)addr)->sin_addr,
MUD_PKTINFO_SRC(CMSG_DATA(cmsg)),
sizeof(struct in_addr));
} else {
addr->ss_family = AF_INET6;
memcpy(&((struct sockaddr_in6 *)addr)->sin6_addr,
&((struct in6_pktinfo *)CMSG_DATA(cmsg))->ipi6_addr,
sizeof(struct in6_addr));
mud_unmapv4(addr);
}
return 0;
} }
static int static int
@@ -1135,6 +1068,7 @@ mud_send_msg(struct mud *mud, struct mud_path *path, uint64_t now,
msg->loss = (unsigned char)path->tx.loss; msg->loss = (unsigned char)path->tx.loss;
msg->fixed_rate = path->conf.fixed_rate; msg->fixed_rate = path->conf.fixed_rate;
msg->loss_limit = path->conf.loss_limit;
const struct mud_crypto_opt opt = { const struct mud_crypto_opt opt = {
.dst = dst, .dst = dst,
@@ -1170,51 +1104,23 @@ mud_decrypt_msg(struct mud *mud,
return size; return size;
} }
static void
mud_update_stat(struct mud_stat *stat, const uint64_t val)
{
if (stat->setup) {
const uint64_t var = mud_abs_diff(stat->val, val);
stat->var = ((stat->var << 1) + stat->var + var) >> 2;
stat->val = ((stat->val << 3) - stat->val + val) >> 3;
} else {
stat->setup = 1;
stat->var = val >> 1;
stat->val = val;
}
}
static void
mud_ss_from_packet(struct sockaddr_storage *ss, struct mud_msg *pkt)
{
if (mud_addr_is_v6(&pkt->addr)) {
ss->ss_family = AF_INET6;
memcpy(&((struct sockaddr_in6 *)ss)->sin6_addr, pkt->addr.v6, 16);
memcpy(&((struct sockaddr_in6 *)ss)->sin6_port, pkt->addr.port, 2);
} else {
ss->ss_family = AF_INET;
memcpy(&((struct sockaddr_in *)ss)->sin_addr, pkt->addr.v4, 4);
memcpy(&((struct sockaddr_in *)ss)->sin_port, pkt->addr.port, 2);
}
}
static void static void
mud_update_window(struct mud *mud, struct mud_path *path, uint64_t now, mud_update_window(struct mud *mud, struct mud_path *path, uint64_t now,
uint64_t tx_dt, uint64_t tx_bytes, uint64_t tx_pkt, uint64_t tx_dt, uint64_t tx_bytes, uint64_t tx_pkt,
uint64_t rx_dt, uint64_t rx_bytes, uint64_t rx_pkt) uint64_t rx_dt, uint64_t rx_bytes, uint64_t rx_pkt)
{ {
if (rx_dt && rx_dt > tx_dt + (tx_dt >> 3)) { if (rx_dt && rx_dt > tx_dt + (tx_dt >> 3)) {
path->tx.rate = (7 * rx_bytes * MUD_ONE_SEC) / (8 * rx_dt); if (!path->conf.fixed_rate)
path->tx.rate = (7 * rx_bytes * MUD_ONE_SEC) / (8 * rx_dt);
} else { } else {
uint64_t tx_acc = path->msg.tx.acc + tx_pkt; uint64_t tx_acc = path->msg.tx.acc + tx_pkt;
uint64_t rx_acc = path->msg.rx.acc + rx_pkt; uint64_t rx_acc = path->msg.rx.acc + rx_pkt;
if (tx_acc >= rx_acc) if (tx_acc > 1000) {
path->tx.loss = (tx_acc - rx_acc) * 255U / tx_acc; if (tx_acc >= rx_acc)
path->tx.loss = (tx_acc - rx_acc) * 255U / tx_acc;
if (tx_acc > 10000) { path->msg.tx.acc = tx_acc - (tx_acc >> 4);
path->msg.tx.acc = tx_acc - (tx_acc >> 3); path->msg.rx.acc = rx_acc - (rx_acc >> 4);
path->msg.rx.acc = rx_acc - (rx_acc >> 3);
} else { } else {
path->msg.tx.acc = tx_acc; path->msg.tx.acc = tx_acc;
path->msg.rx.acc = rx_acc; path->msg.rx.acc = rx_acc;
@@ -1258,6 +1164,45 @@ mud_update_mtu(struct mud_path *path, size_t size)
} }
} }
static void
mud_update_stat(struct mud_stat *stat, const uint64_t val)
{
if (stat->setup) {
const uint64_t var = mud_abs_diff(stat->val, val);
stat->var = ((stat->var << 1) + stat->var + var) >> 2;
stat->val = ((stat->val << 3) - stat->val + val) >> 3;
} else {
stat->setup = 1;
stat->var = val >> 1;
stat->val = val;
}
}
static int
mud_addr_is_v6(struct mud_addr *addr)
{
static const unsigned char v4mapped[] = {
[10] = 255,
[11] = 255,
};
return memcmp(addr->v6, v4mapped, sizeof(v4mapped));
}
static void
mud_ss_from_packet(struct sockaddr_storage *ss, struct mud_msg *pkt)
{
if (mud_addr_is_v6(&pkt->addr)) {
ss->ss_family = AF_INET6;
memcpy(&((struct sockaddr_in6 *)ss)->sin6_addr, pkt->addr.v6, 16);
memcpy(&((struct sockaddr_in6 *)ss)->sin6_port, pkt->addr.port, 2);
} else {
ss->ss_family = AF_INET;
memcpy(&((struct sockaddr_in *)ss)->sin_addr, pkt->addr.v4, 4);
memcpy(&((struct sockaddr_in *)ss)->sin_port, pkt->addr.port, 2);
}
}
static void static void
mud_recv_msg(struct mud *mud, struct mud_path *path, mud_recv_msg(struct mud *mud, struct mud_path *path,
uint64_t now, uint64_t sent_time, uint64_t now, uint64_t sent_time,
@@ -1321,6 +1266,7 @@ mud_recv_msg(struct mud *mud, struct mud_path *path,
path->conf.tx_max_rate = max_rate; path->conf.tx_max_rate = max_rate;
path->conf.fixed_rate = msg->fixed_rate; path->conf.fixed_rate = msg->fixed_rate;
path->conf.loss_limit = msg->loss_limit;
path->msg.sent++; path->msg.sent++;
path->msg.time = now; path->msg.time = now;
@@ -1328,7 +1274,7 @@ mud_recv_msg(struct mud *mud, struct mud_path *path,
if (memcmp(msg->pkey, mud->keyx.remote, MUD_PUBKEY_SIZE)) { if (memcmp(msg->pkey, mud->keyx.remote, MUD_PUBKEY_SIZE)) {
if (!mud->peer.set) if (!mud->peer.set)
mud_keyx_init(&mud->keyx, now); mud_keyx_init(mud, now);
if (mud_keyx(&mud->keyx, msg->pkey, msg->aes)) { if (mud_keyx(&mud->keyx, msg->pkey, msg->aes)) {
mud->bad.keyx.addr = path->addr; mud->bad.keyx.addr = path->addr;
mud->bad.keyx.time = now; mud->bad.keyx.time = now;
@@ -1378,8 +1324,8 @@ mud_recv(struct mud *mud, void *data, size_t size)
mud_unmapv4(&addr); mud_unmapv4(&addr);
if ((MUD_TIME_MASK(now - sent_time) > mud->time_tolerance) && if ((MUD_TIME_MASK(now - sent_time) > mud->conf.timetolerance) &&
(MUD_TIME_MASK(sent_time - now) > mud->time_tolerance)) { (MUD_TIME_MASK(sent_time - now) > mud->conf.timetolerance)) {
mud->bad.difftime.addr = addr; mud->bad.difftime.addr = addr;
mud->bad.difftime.time = now; mud->bad.difftime.time = now;
mud->bad.difftime.count++; mud->bad.difftime.count++;
@@ -1445,7 +1391,7 @@ mud_path_is_ok(struct mud *mud, struct mud_path *path)
if (!path->mtu.ok) if (!path->mtu.ok)
return 0; return 0;
if (path->tx.loss > mud->loss_limit) if (path->tx.loss > path->conf.loss_limit)
return 0; return 0;
if (mud->peer.set) if (mud->peer.set)
@@ -1464,7 +1410,7 @@ mud_update(struct mud *mud)
uint64_t now = mud_now(mud); uint64_t now = mud_now(mud);
if (mud->peer.set && !mud_keyx_init(&mud->keyx, now)) if (mud->peer.set && !mud_keyx_init(mud, now))
now = mud_now(mud); now = mud_now(mud);
for (unsigned i = 0; i < mud->count; i++) { for (unsigned i = 0; i < mud->count; i++) {
@@ -1506,7 +1452,7 @@ mud_update(struct mud *mud)
if (path->msg.sent >= MUD_MSG_SENT_MAX) { if (path->msg.sent >= MUD_MSG_SENT_MAX) {
timeout = 2 * MUD_MSG_SENT_MAX * timeout; timeout = 2 * MUD_MSG_SENT_MAX * timeout;
} else if (path->ok && mud_timeout(now, path->idle, MUD_ONE_SEC)) { } else if (path->ok && mud_timeout(now, path->idle, MUD_ONE_SEC)) {
timeout = mud->keepalive; timeout = mud->conf.keepalive;
} }
if (mud_timeout(now, path->msg.time, timeout)) { if (mud_timeout(now, path->msg.time, timeout)) {
@@ -1545,7 +1491,8 @@ mud_set_state(struct mud *mud, struct sockaddr *addr,
unsigned long tx_max_rate, unsigned long tx_max_rate,
unsigned long rx_max_rate, unsigned long rx_max_rate,
unsigned long beat, unsigned long beat,
unsigned char fixed_rate) unsigned char fixed_rate,
unsigned char loss_limit)
{ {
if (!mud->peer.set || state > MUD_UP) { if (!mud->peer.set || state > MUD_UP) {
errno = EINVAL; errno = EINVAL;
@@ -1570,11 +1517,14 @@ mud_set_state(struct mud *mud, struct sockaddr *addr,
path->conf.rx_max_rate = path->rx.rate = rx_max_rate; path->conf.rx_max_rate = path->rx.rate = rx_max_rate;
if (beat) if (beat)
path->conf.beat = beat; path->conf.beat = beat * MUD_ONE_MSEC;
if (fixed_rate) if (fixed_rate)
path->conf.fixed_rate = fixed_rate >> 1; path->conf.fixed_rate = fixed_rate >> 1;
if (loss_limit)
path->conf.loss_limit = loss_limit;
if (state && path->state != state) { if (state && path->state != state) {
path->state = state; path->state = state;
mud_reset_path(path); mud_reset_path(path);

11
mud.h
View File

@@ -23,10 +23,9 @@ struct mud_stat {
}; };
struct mud_conf { struct mud_conf {
unsigned long keepalive; uint64_t keepalive;
unsigned long timetolerance; uint64_t timetolerance;
unsigned long kxtimeout; uint64_t kxtimeout;
unsigned losslimit;
int tc; int tc;
}; };
@@ -65,6 +64,7 @@ struct mud_path {
uint64_t rx_max_rate; uint64_t rx_max_rate;
uint64_t beat; uint64_t beat;
unsigned char fixed_rate; unsigned char fixed_rate;
unsigned char loss_limit;
} conf; } conf;
uint64_t idle; uint64_t idle;
unsigned char ok; unsigned char ok;
@@ -95,7 +95,8 @@ int mud_set_aes (struct mud *);
int mud_set_conf (struct mud *, struct mud_conf *); int mud_set_conf (struct mud *, struct mud_conf *);
int mud_set_state (struct mud *, struct sockaddr *, enum mud_state, int mud_set_state (struct mud *, struct sockaddr *, enum mud_state,
unsigned long, unsigned long, unsigned long, unsigned char); unsigned long, unsigned long, unsigned long,
unsigned char, unsigned char);
int mud_peer (struct mud *, struct sockaddr *); int mud_peer (struct mud *, struct sockaddr *);

3
test.c
View File

@@ -1,5 +1,4 @@
#include "mud.c" #include "mud.c"
#include "aegis256/aegis256.c"
#include <stdio.h> #include <stdio.h>
#include <poll.h> #include <poll.h>
@@ -52,7 +51,7 @@ main(int argc, char **argv)
// ...from loopback at 1MBps (not 1Mbps) // ...from loopback at 1MBps (not 1Mbps)
if (mud_set_state(mud, (struct sockaddr *)&local, if (mud_set_state(mud, (struct sockaddr *)&local,
MUD_UP, 1000 * 1000, 1000 * 1000, 0, 0)) { MUD_UP, 1000 * 1000, 1000 * 1000, 0, 0, 0)) {
perror("mud_set_state"); perror("mud_set_state");
return -1; return -1;
} }