Add MTU negotiation

This commit is contained in:
Adrien Gallouët
2016-09-23 15:11:42 +00:00
parent d5297b8a70
commit d255074199
2 changed files with 70 additions and 33 deletions

100
mud.c
View File

@@ -39,20 +39,21 @@
#define MUD_ONE_SEC (1000*MUD_ONE_MSEC) #define MUD_ONE_SEC (1000*MUD_ONE_MSEC)
#define MUD_ONE_MIN (60*MUD_ONE_SEC) #define MUD_ONE_MIN (60*MUD_ONE_SEC)
#define MUD_TIME_SIZE (6U) #define MUD_U48_SIZE (6U)
#define MUD_KEY_SIZE (32U) #define MUD_KEY_SIZE (32U)
#define MUD_MAC_SIZE (16U) #define MUD_MAC_SIZE (16U)
#define MUD_PACKET_MIN_SIZE (MUD_TIME_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)
#define MUD_PACKET_MASK (0x3FFU) #define MUD_PACKET_MASK (0x3FFU)
#define MUD_PACKET_COUNT ((MUD_PACKET_MASK)+1) #define MUD_PACKET_COUNT ((MUD_PACKET_MASK)+1)
#define MUD_PACKET_NEXT(X) (((X)+1)&(MUD_PACKET_MASK)) #define MUD_PACKET_NEXT(X) (((X)+1)&(MUD_PACKET_MASK))
#define MUD_PACKET_SIZEOF(X) ((X)+MUD_PACKET_MIN_SIZE) #define MUD_PACKET_SIZEOF(X) ((X)+MUD_PACKET_MIN_SIZE)
#define MUD_PONG_SIZE MUD_PACKET_SIZEOF(MUD_TIME_SIZE*3) #define MUD_PONG_SIZE MUD_PACKET_SIZEOF(MUD_U48_SIZE*3)
#define MUD_PKEY_SIZE (crypto_scalarmult_BYTES+1) #define MUD_PKEY_SIZE (crypto_scalarmult_BYTES+1)
#define MUD_KEYX_SIZE MUD_PACKET_SIZEOF(MUD_TIME_SIZE+2*MUD_PKEY_SIZE) #define MUD_KEYX_SIZE MUD_PACKET_SIZEOF(MUD_U48_SIZE+2*MUD_PKEY_SIZE)
#define MUD_MTUX_SIZE MUD_PACKET_SIZEOF(MUD_U48_SIZE*2)
#define MUD_PONG_TIMEOUT (100*MUD_ONE_MSEC) #define MUD_PONG_TIMEOUT (100*MUD_ONE_MSEC)
#define MUD_KEYX_TIMEOUT (60*MUD_ONE_MIN) #define MUD_KEYX_TIMEOUT (60*MUD_ONE_MIN)
@@ -63,6 +64,7 @@ enum mud_msg {
mud_ping, mud_ping,
mud_pong, mud_pong,
mud_keyx, mud_keyx,
mud_mtux,
}; };
struct ipaddr { struct ipaddr {
@@ -146,6 +148,8 @@ struct mud {
int fd; int fd;
uint64_t send_timeout; uint64_t send_timeout;
uint64_t time_tolerance; uint64_t time_tolerance;
uint64_t mtu;
uint64_t recv_mtu;
struct queue tx; struct queue tx;
struct queue rx; struct queue rx;
struct path *path; struct path *path;
@@ -609,6 +613,15 @@ int mud_set_time_tolerance_sec (struct mud *mud, unsigned sec)
return 0; return 0;
} }
int mud_get_mtu (struct mud *mud)
{
if ((!mud->recv_mtu) ||
(mud->mtu <= mud->recv_mtu))
return mud->mtu;
return mud->recv_mtu;
}
static static
int mud_setup_socket (int fd, int v4, int v6) int mud_setup_socket (int fd, int v4, int v6)
{ {
@@ -669,7 +682,7 @@ void mud_keyx_init (struct mud *mud)
mud->crypto.public.send[MUD_PKEY_SIZE-1] = mud->crypto.aes; mud->crypto.public.send[MUD_PKEY_SIZE-1] = mud->crypto.aes;
} }
struct mud *mud_create (int port, int v4, int v6, int aes) struct mud *mud_create (int port, int v4, int v6, int aes, int mtu)
{ {
if (sodium_init() == -1) if (sodium_init() == -1)
return NULL; return NULL;
@@ -694,6 +707,7 @@ struct mud *mud_create (int port, int v4, int v6, int aes)
mud->send_timeout = MUD_SEND_TIMEOUT; mud->send_timeout = MUD_SEND_TIMEOUT;
mud->time_tolerance = MUD_TIME_TOLERANCE; mud->time_tolerance = MUD_TIME_TOLERANCE;
mud->mtu = mtu;
unsigned char key[MUD_KEY_SIZE]; unsigned char key[MUD_KEY_SIZE];
@@ -748,15 +762,15 @@ int mud_encrypt (struct mud *mud, uint64_t nonce,
return 0; return 0;
struct crypto_opt opt = { struct crypto_opt opt = {
.dst = dst+MUD_TIME_SIZE, .dst = dst+MUD_U48_SIZE,
.src = { .data = src, .src = { .data = src,
.size = src_size }, .size = src_size },
.ad = { .data = dst, .ad = { .data = dst,
.size = MUD_TIME_SIZE }, .size = MUD_U48_SIZE },
}; };
mud_write48(opt.npub, nonce); mud_write48(opt.npub, nonce);
memcpy(dst, opt.npub, MUD_TIME_SIZE); memcpy(dst, opt.npub, MUD_U48_SIZE);
if (mud->crypto.use_next) { if (mud->crypto.use_next) {
mud_encrypt_opt(&mud->crypto.next, &opt); mud_encrypt_opt(&mud->crypto.next, &opt);
@@ -779,13 +793,13 @@ int mud_decrypt (struct mud *mud,
struct crypto_opt opt = { struct crypto_opt opt = {
.dst = dst, .dst = dst,
.src = { .data = src+MUD_TIME_SIZE, .src = { .data = src+MUD_U48_SIZE,
.size = src_size-MUD_TIME_SIZE }, .size = src_size-MUD_U48_SIZE },
.ad = { .data = src, .ad = { .data = src,
.size = MUD_TIME_SIZE }, .size = MUD_U48_SIZE },
}; };
memcpy(opt.npub, src, MUD_TIME_SIZE); memcpy(opt.npub, src, MUD_U48_SIZE);
if (mud_decrypt_opt(&mud->crypto.current, &opt)) { if (mud_decrypt_opt(&mud->crypto.current, &opt)) {
if (!mud_decrypt_opt(&mud->crypto.next, &opt)) { if (!mud_decrypt_opt(&mud->crypto.next, &opt)) {
@@ -892,35 +906,42 @@ void mud_ctrl_path (struct mud *mud, enum mud_msg msg, struct path *path,
uint64_t now) uint64_t now)
{ {
struct { struct {
unsigned char zero[MUD_TIME_SIZE]; unsigned char zero[MUD_U48_SIZE];
unsigned char time[MUD_TIME_SIZE]; unsigned char time[MUD_U48_SIZE];
unsigned char data[128+MUD_MAC_SIZE]; unsigned char data[128+MUD_MAC_SIZE];
} ctrl; } ctrl;
size_t size = 0; size_t size = 0;
memset(ctrl.zero, 0, MUD_TIME_SIZE); memset(ctrl.zero, 0, MUD_U48_SIZE);
mud_write48(ctrl.time, now); mud_write48(ctrl.time, now);
if (msg == mud_pong) { switch (msg) {
mud_write48(&ctrl.data[0], path->recv_send_time); case mud_pong:
mud_write48(&ctrl.data[MUD_TIME_SIZE], path->rdt); mud_write48(ctrl.data, path->recv_send_time);
size = MUD_TIME_SIZE*2; mud_write48(&ctrl.data[MUD_U48_SIZE], path->rdt);
} size = MUD_U48_SIZE*2;
break;
if (msg == mud_keyx) { case mud_keyx:
memcpy(ctrl.data, &mud->crypto.public, sizeof(mud->crypto.public)); memcpy(ctrl.data, &mud->crypto.public, sizeof(mud->crypto.public));
size = sizeof(mud->crypto.public); size = sizeof(mud->crypto.public);
break;
case mud_mtux:
mud_write48(ctrl.data, mud->mtu);
size = MUD_U48_SIZE;
break;
default:
return;
} }
struct crypto_opt opt = { struct crypto_opt opt = {
.dst = ctrl.data+size, .dst = ctrl.data+size,
.ad = { .data = ctrl.zero, .ad = { .data = ctrl.zero,
.size = size+2*MUD_TIME_SIZE }, .size = size+2*MUD_U48_SIZE },
}; };
mud_encrypt_opt(&mud->crypto.private, &opt); mud_encrypt_opt(&mud->crypto.private, &opt);
mud_send_path(mud, path, now, &ctrl, size+2*MUD_TIME_SIZE+MUD_MAC_SIZE, 0); mud_send_path(mud, path, now, &ctrl, size+2*MUD_U48_SIZE+MUD_MAC_SIZE, 0);
} }
static static
@@ -1027,10 +1048,10 @@ int mud_pull (struct mud *mud)
int mud_packet = !send_time; int mud_packet = !send_time;
if (mud_packet) { if (mud_packet) {
if (ret < (ssize_t)MUD_PACKET_SIZEOF(MUD_TIME_SIZE)) if (ret < (ssize_t)MUD_PACKET_SIZEOF(MUD_U48_SIZE))
continue; continue;
send_time = mud_read48(&packet->data[MUD_TIME_SIZE]); send_time = mud_read48(&packet->data[MUD_U48_SIZE]);
} }
if (mud_dt(now, send_time) >= mud->time_tolerance) if (mud_dt(now, send_time) >= mud->time_tolerance)
@@ -1076,8 +1097,8 @@ int mud_pull (struct mud *mud)
path->recv_time = now; path->recv_time = now;
if (mud_packet && (ret == (ssize_t)MUD_PONG_SIZE)) { if (mud_packet && (ret == (ssize_t)MUD_PONG_SIZE)) {
uint64_t st = mud_read48(&packet->data[MUD_TIME_SIZE*2]); uint64_t st = mud_read48(&packet->data[MUD_U48_SIZE*2]);
uint64_t dt = mud_read48(&packet->data[MUD_TIME_SIZE*3]); uint64_t dt = mud_read48(&packet->data[MUD_U48_SIZE*3]);
path->dt = dt; path->dt = dt;
path->sdt = send_time-st; path->sdt = send_time-st;
@@ -1092,8 +1113,13 @@ int mud_pull (struct mud *mud)
} }
if (mud_packet) { if (mud_packet) {
if (ret == (ssize_t)MUD_KEYX_SIZE) if (ret == (ssize_t)MUD_KEYX_SIZE) {
mud_recv_keyx(mud, path, now, &packet->data[MUD_TIME_SIZE*2]); mud_recv_keyx(mud, path, now, &packet->data[MUD_U48_SIZE*2]);
} else if (ret == (ssize_t)MUD_MTUX_SIZE) {
mud->recv_mtu = mud_read48(&packet->data[MUD_U48_SIZE*2]);
if (!path->state.active)
mud_ctrl_path(mud, mud_mtux, path, now);
}
continue; continue;
} }
@@ -1153,6 +1179,11 @@ int mud_push (struct mud *mud)
continue; continue;
} }
if (!mud->recv_mtu) {
mud_ctrl_path(mud, mud_mtux, path, now);
continue;
}
if ((!mud->crypto.time) || if ((!mud->crypto.time) ||
(now-mud->crypto.time >= MUD_KEYX_TIMEOUT)) { (now-mud->crypto.time >= MUD_KEYX_TIMEOUT)) {
mud_ctrl_path(mud, mud_keyx, path, now); mud_ctrl_path(mud, mud_keyx, path, now);
@@ -1210,6 +1241,11 @@ int mud_send (struct mud *mud, const void *data, size_t size, int tc)
if (!size) if (!size)
return 0; return 0;
if (size > (size_t)mud_get_mtu(mud)) {
errno = EMSGSIZE;
return -1;
}
unsigned next = MUD_PACKET_NEXT(mud->tx.end); unsigned next = MUD_PACKET_NEXT(mud->tx.end);
if (mud->tx.start == next) { if (mud->tx.start == next) {

3
mud.h
View File

@@ -4,13 +4,14 @@
struct mud; struct mud;
struct mud *mud_create (int, int, int, int); struct mud *mud_create (int, int, int, int, int);
void mud_delete (struct mud *); void mud_delete (struct mud *);
int mud_set_key (struct mud *, unsigned char *, size_t); int mud_set_key (struct mud *, unsigned char *, size_t);
int mud_get_key (struct mud *, unsigned char *, size_t *); int mud_get_key (struct mud *, unsigned char *, size_t *);
int mud_get_fd (struct mud *); int mud_get_fd (struct mud *);
int mud_get_mtu (struct mud *);
int mud_set_send_timeout_msec (struct mud *, unsigned); int mud_set_send_timeout_msec (struct mud *, unsigned);
int mud_set_time_tolerance_sec (struct mud *, unsigned); int mud_set_time_tolerance_sec (struct mud *, unsigned);