More stuff

from http://whatthecommit.com/0cd527cd19f926a6e6b683a2efadb664
This commit is contained in:
angt
2016-04-04 16:46:10 +00:00
parent a1ba274fbf
commit 85367eff80

175
mud.c
View File

@@ -4,8 +4,15 @@
#define __APPLE_USE_RFC_3542 #define __APPLE_USE_RFC_3542
#endif #endif
#ifdef DEBUG
#include <stdio.h>
#define MUD_DEBUG(...) fprintf(stderr, __VA_ARGS__);
#else
#define MUD_DEBUG(...)
#endif
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <inttypes.h>
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
@@ -22,12 +29,40 @@
#define MUD_ASSERT(X) (void)sizeof(char[(X)?1:-1]) #define MUD_ASSERT(X) (void)sizeof(char[(X)?1:-1])
#define MUD_PACKET_MASK (0x3FF) #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_ABYTES (16) #define MUD_TIME_SIZE (6U)
#define MUD_KEYBYTES (32)
#define MUD_AD_SIZE (16U)
#define MUD_KEY_SIZE (32U)
#define MUD_NPUB_SIZE (MUD_TIME_SIZE)
#define MUD_PACKET_MIN_SIZE (MUD_NPUB_SIZE+MUD_AD_SIZE)
#define MUD_PONG_DATA_SIZE (3U*MUD_TIME_SIZE)
#define MUD_PONG_SIZE (MUD_PONG_DATA_SIZE+MUD_PACKET_MIN_SIZE)
#define MUD_ONE_MSEC (UINT64_C(1000))
#define MUD_ONE_SEC (1000*MUD_ONE_MSEC)
#define MUD_ONE_MIN (60*MUD_ONE_SEC)
#ifndef MUD_SEND_TIMEOUT
#define MUD_SEND_TIMEOUT (10*MUD_ONE_SEC)
#endif
#ifndef MUD_DOWN_TIMEOUT
#define MUD_DOWN_TIMEOUT (MUD_ONE_MIN)
#endif
#ifndef MUD_PONG_TIMEOUT
#define MUD_PONG_TIMEOUT (100*MUD_ONE_MSEC)
#endif
#ifndef MUD_TIME_TOLERANCE
#define MUD_TIME_TOLERANCE (10*MUD_ONE_MIN)
#endif
struct path_info { struct path_info {
uint64_t dt; uint64_t dt;
@@ -37,7 +72,7 @@ struct path_info {
}; };
struct path { struct path {
int up; unsigned up;
unsigned index; unsigned index;
struct sockaddr_storage addr; struct sockaddr_storage addr;
struct { struct {
@@ -50,6 +85,7 @@ struct path {
int64_t sdt; int64_t sdt;
uint64_t limit; uint64_t limit;
uint64_t pong_time; uint64_t pong_time;
uint64_t last_time;
struct path_info recv; struct path_info recv;
struct path_info send; struct path_info send;
struct path *next; struct path *next;
@@ -73,11 +109,15 @@ struct queue {
}; };
struct crypto { struct crypto {
uint8_t key[MUD_KEYBYTES]; uint8_t key[MUD_KEY_SIZE];
}; };
struct mud { struct mud {
int fd; int fd;
uint64_t send_timeout;
uint64_t down_timeout;
uint64_t pong_timeout;
uint64_t time_tolerance;
struct queue tx; struct queue tx;
struct queue rx; struct queue rx;
struct sock *sock; struct sock *sock;
@@ -112,7 +152,7 @@ uint64_t mud_now (struct mud *mud)
{ {
struct timeval now; struct timeval now;
gettimeofday(&now, NULL); gettimeofday(&now, NULL);
return (now.tv_sec*UINT64_C(1000000)+now.tv_usec)&((UINT64_C(1)<<48)-1); return (now.tv_sec*MUD_ONE_SEC+now.tv_usec)&((UINT64_C(1)<<48)-1);
} }
static static
@@ -166,12 +206,11 @@ ssize_t mud_send_path (struct mud *mud, struct path *path, uint64_t now, void *d
ssize_t ret = sendmsg(mud->fd, &msg, 0); ssize_t ret = sendmsg(mud->fd, &msg, 0);
if (ret > 0) { if (ret == (ssize_t)size) {
if (path->recv.time > path->send.time)
path->last_time = now;
path->send.time = now; path->send.time = now;
} else if ((ret == -1) &&
(errno != EAGAIN) &&
(errno != EINTR)) {
path->up = 0;
} }
return ret; return ret;
@@ -452,7 +491,7 @@ int mud_bind (struct mud *mud, const char *name)
int mud_set_key (struct mud *mud, unsigned char *key, size_t size) int mud_set_key (struct mud *mud, unsigned char *key, size_t size)
{ {
if (size != MUD_KEYBYTES) { if (size != MUD_KEY_SIZE) {
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
@@ -549,6 +588,12 @@ struct mud *mud_create (const char *port)
return NULL; return NULL;
} }
mud->send_timeout = MUD_SEND_TIMEOUT;
mud->down_timeout = MUD_DOWN_TIMEOUT;
mud->pong_timeout = MUD_PONG_TIMEOUT;
mud->time_tolerance = MUD_TIME_TOLERANCE;
return mud; return mud;
} }
@@ -595,7 +640,7 @@ int mud_encrypt (struct mud *mud, uint64_t nonce,
if (ad_size > src_size) if (ad_size > src_size)
ad_size = src_size; ad_size = src_size;
size_t size = src_size+6+MUD_ABYTES; size_t size = src_size+MUD_PACKET_MIN_SIZE;
if (size > dst_size) if (size > dst_size)
return 0; return 0;
@@ -603,15 +648,15 @@ int mud_encrypt (struct mud *mud, uint64_t nonce,
unsigned char npub[crypto_aead_chacha20poly1305_NPUBBYTES] = {0}; unsigned char npub[crypto_aead_chacha20poly1305_NPUBBYTES] = {0};
mud_write48(npub, nonce); mud_write48(npub, nonce);
memcpy(dst, npub, 6); memcpy(dst, npub, MUD_NPUB_SIZE);
if (src) if (src)
memcpy(dst+6, src, ad_size); memcpy(dst+MUD_NPUB_SIZE, src, ad_size);
crypto_aead_chacha20poly1305_encrypt( crypto_aead_chacha20poly1305_encrypt(
dst+ad_size+6, NULL, dst+ad_size+MUD_NPUB_SIZE, NULL,
src+ad_size, src_size-ad_size, src+ad_size, src_size-ad_size,
dst, ad_size+6, dst, ad_size+MUD_NPUB_SIZE,
NULL, NULL,
npub, npub,
mud->crypto.key); mud->crypto.key);
@@ -625,7 +670,7 @@ int mud_decrypt (struct mud *mud, uint64_t *nonce,
const unsigned char *src, size_t src_size, const unsigned char *src, size_t src_size,
size_t ad_size) size_t ad_size)
{ {
size_t size = src_size-6-MUD_ABYTES; size_t size = src_size-MUD_PACKET_MIN_SIZE;
if (ad_size > size) if (ad_size > size)
ad_size = size; ad_size = size;
@@ -635,14 +680,14 @@ int mud_decrypt (struct mud *mud, uint64_t *nonce,
unsigned char npub[crypto_aead_chacha20poly1305_NPUBBYTES] = {0}; unsigned char npub[crypto_aead_chacha20poly1305_NPUBBYTES] = {0};
memcpy(npub, src, 6); memcpy(npub, src, MUD_NPUB_SIZE);
memcpy(dst, src+6, ad_size); memcpy(dst, src+MUD_NPUB_SIZE, ad_size);
if (crypto_aead_chacha20poly1305_decrypt( if (crypto_aead_chacha20poly1305_decrypt(
dst+ad_size, NULL, dst+ad_size, NULL,
NULL, NULL,
src+ad_size+6, src_size-ad_size-6, src+ad_size+MUD_NPUB_SIZE, src_size-ad_size-MUD_NPUB_SIZE,
src, ad_size+6, src, ad_size+MUD_NPUB_SIZE,
npub, npub,
mud->crypto.key)) mud->crypto.key))
return -1; return -1;
@@ -724,13 +769,25 @@ int mud_pull (struct mud *mud)
ssize_t ret = recvmsg(mud->fd, &msg, 0); ssize_t ret = recvmsg(mud->fd, &msg, 0);
if (ret <= 0) if (ret <= (ssize_t)0)
break; return (int)ret;
if (ret < (ssize_t)MUD_PACKET_MIN_SIZE)
continue;
uint64_t now = mud_now(mud); uint64_t now = mud_now(mud);
uint64_t send_time = mud_read48(packet->data); uint64_t send_time = mud_read48(packet->data);
if (mud_dt(now, send_time) >= UINT64_C(1000000*60*10)) int pong_packet = !send_time;
if (pong_packet) {
if (ret != (ssize_t)MUD_PONG_SIZE)
continue;
send_time = mud_read48(&packet->data[MUD_TIME_SIZE]);
}
if (mud_dt(now, send_time) >= mud->time_tolerance)
continue; continue;
mud_unmapv4((struct sockaddr *)&addr); mud_unmapv4((struct sockaddr *)&addr);
@@ -772,6 +829,9 @@ int mud_pull (struct mud *mud)
sizeof(struct in6_addr)); sizeof(struct in6_addr));
} }
} else { } else {
if (pong_packet)
continue;
unsigned char tmp[sizeof(packet->data)]; unsigned char tmp[sizeof(packet->data)];
if (mud_decrypt(mud, NULL, tmp, sizeof(tmp), if (mud_decrypt(mud, NULL, tmp, sizeof(tmp),
@@ -794,25 +854,24 @@ int mud_pull (struct mud *mud)
path->recv.send_time = send_time; path->recv.send_time = send_time;
path->recv.time = now; path->recv.time = now;
if (!send_time) { if (pong_packet) {
uint64_t send_time = mud_read48(&packet->data[6*1]); uint64_t old_send_time = mud_read48(&packet->data[MUD_TIME_SIZE*2]);
uint64_t recv_time = mud_read48(&packet->data[6*2]); uint64_t dt = mud_read48(&packet->data[MUD_TIME_SIZE*3]);
uint64_t dt = mud_read48(&packet->data[6*3]);
path->dt = dt; path->dt = dt;
path->sdt = recv_time-send_time; path->sdt = send_time-old_send_time;
path->rtt = now-send_time; path->rtt = now-old_send_time;
continue; continue;
} }
if (!path->pong_time || if ((!path->pong_time) ||
(now-path->pong_time > UINT64_C(100000))) { (now-path->pong_time > mud->pong_timeout)) {
unsigned char tmp[256]; unsigned char tmp[MUD_PONG_SIZE];
unsigned char pong[6*3]; unsigned char pong[MUD_PONG_DATA_SIZE];
memcpy(pong, packet->data, 6); mud_write48(pong, now);
mud_write48(&pong[6*1], now); memcpy(&pong[MUD_TIME_SIZE], packet->data, MUD_TIME_SIZE);
mud_write48(&pong[6*2], path->rdt); mud_write48(&pong[MUD_TIME_SIZE*2], path->rdt);
int ret = mud_encrypt(mud, 0, tmp, sizeof(tmp), int ret = mud_encrypt(mud, 0, tmp, sizeof(tmp),
pong, sizeof(pong), sizeof(pong)); pong, sizeof(pong), sizeof(pong));
@@ -823,7 +882,7 @@ int mud_pull (struct mud *mud)
} }
} }
if (ret <= 6+MUD_ABYTES) if (ret == (ssize_t)MUD_PACKET_MIN_SIZE)
continue; continue;
packet->size = ret; packet->size = ret;
@@ -855,32 +914,42 @@ int mud_recv (struct mud *mud, void *data, size_t size)
return ret; return ret;
} }
static void mud_ping_path (struct mud *mud, struct path *path, uint64_t now)
{
unsigned char ping[32];
int ret = mud_encrypt(mud, now, ping, sizeof(ping), NULL, 0, 0);
if (ret <= 0)
return;
mud_send_path(mud, path, now, ping, (size_t)ret);
}
int mud_push (struct mud *mud) int mud_push (struct mud *mud)
{ {
uint64_t now = mud_now(mud);
struct path *path; struct path *path;
for (path = mud->path; path; path = path->next) { for (path = mud->path; path; path = path->next) {
uint64_t now = mud_now(mud);
if ((path->send.time > path->recv.time) && if ((path->send.time > path->last_time) &&
(path->send.time-path->recv.time > UINT64_C(200000)+path->rtt*4)) (path->send.time-path->last_time > mud->down_timeout+path->rtt))
path->up = 0; path->up = 0;
if (path->send.time && if (path->send.time) {
(now-path->send.time < UINT64_C(1000000))) if (now < path->send.time)
continue; continue;
unsigned char ping[32]; if ((now-path->send.time) < mud->send_timeout)
continue;
}
int ret = mud_encrypt(mud, now, ping, sizeof(ping), NULL, 0, 0); mud_ping_path(mud, path, now);
if (ret > 0)
mud_send_path(mud, path, now, ping, (size_t)ret);
} }
while (mud->tx.start != mud->tx.end) { while (mud->tx.start != mud->tx.end) {
uint64_t now = mud_now(mud);
struct packet *packet = &mud->tx.packet[mud->tx.start]; struct packet *packet = &mud->tx.packet[mud->tx.start];
struct path *path_min = NULL; struct path *path_min = NULL;