mirror of
https://github.com/neocturne/fastd.git
synced 2025-05-14 20:25:08 +02:00
Dynamically create and destroy sockets without fixed binds
This commit is contained in:
parent
86df5dbefe
commit
cb98cbc593
8 changed files with 132 additions and 68 deletions
|
@ -434,7 +434,6 @@ bool fastd_read_config(fastd_context *ctx, fastd_config *conf, const char *filen
|
|||
}
|
||||
|
||||
static void count_peers(fastd_context *ctx, fastd_config *conf) {
|
||||
conf->n_peers = 0;
|
||||
conf->n_floating = 0;
|
||||
conf->n_v4 = 0;
|
||||
conf->n_v6 = 0;
|
||||
|
@ -444,8 +443,6 @@ static void count_peers(fastd_context *ctx, fastd_config *conf) {
|
|||
|
||||
fastd_peer_config *peer;
|
||||
for (peer = conf->peers; peer; peer = peer->next) {
|
||||
conf->n_peers++;
|
||||
|
||||
switch (peer->address.sa.sa_family) {
|
||||
case AF_UNSPEC:
|
||||
if (peer->hostname)
|
||||
|
|
97
src/fastd.c
97
src/fastd.c
|
@ -256,6 +256,21 @@ static void bind_sockets(fastd_context *ctx) {
|
|||
}
|
||||
}
|
||||
|
||||
fastd_socket* fastd_socket_open(fastd_context *ctx, int af) {
|
||||
const fastd_bind_address any_address = { .addr.sa.sa_family = af };
|
||||
|
||||
int fd = bind_socket(ctx, &any_address, true);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
|
||||
fastd_socket *sock = malloc(sizeof(fastd_socket));
|
||||
|
||||
sock->fd = fd;
|
||||
sock->addr = NULL;
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
static void init_tuntap(fastd_context *ctx) {
|
||||
struct ifreq ifr;
|
||||
|
||||
|
@ -309,19 +324,10 @@ static void close_tuntap(fastd_context *ctx) {
|
|||
free(ctx->ifname);
|
||||
}
|
||||
|
||||
static void close_socket(fastd_context *ctx, fastd_socket *sock) {
|
||||
if (sock->fd >= 0) {
|
||||
if(close(sock->fd))
|
||||
pr_error_errno(ctx, "closing socket: close");
|
||||
|
||||
sock->fd = -2;
|
||||
}
|
||||
}
|
||||
|
||||
static void close_sockets(fastd_context *ctx) {
|
||||
unsigned i;
|
||||
for (i = 0; i < ctx->n_socks; i++)
|
||||
close_socket(ctx, &ctx->socks[i]);
|
||||
fastd_socket_close(ctx, &ctx->socks[i]);
|
||||
|
||||
free(ctx->socks);
|
||||
}
|
||||
|
@ -555,8 +561,10 @@ static void init_peers(fastd_context *ctx) {
|
|||
for (peer_conf = ctx->conf->peers; peer_conf; peer_conf = peer_conf->next) {
|
||||
ctx->conf->protocol->peer_configure(ctx, peer_conf);
|
||||
|
||||
if (peer_conf->enabled)
|
||||
if (peer_conf->enabled) {
|
||||
fastd_peer_add(ctx, peer_conf);
|
||||
ctx->n_peers++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -574,7 +582,10 @@ static inline void update_time(fastd_context *ctx) {
|
|||
}
|
||||
|
||||
static inline void send_handshake(fastd_context *ctx, fastd_peer *peer) {
|
||||
if (peer->address.sa.sa_family && peer->sock) {
|
||||
if (!fastd_peer_is_established(peer))
|
||||
fastd_peer_reset_socket(ctx, peer);
|
||||
|
||||
if (peer->sock) {
|
||||
if (timespec_diff(&ctx->now, &peer->last_handshake) < ctx->conf->min_handshake_interval*1000
|
||||
&& fastd_peer_address_equal(&peer->address, &peer->last_handshake_address)) {
|
||||
pr_debug(ctx, "not sending a handshake to %P as we sent one a short time ago", peer);
|
||||
|
@ -663,7 +674,7 @@ static void handle_tun(fastd_context *ctx) {
|
|||
}
|
||||
}
|
||||
|
||||
static void handle_socket(fastd_context *ctx, const fastd_socket *sock) {
|
||||
static void handle_socket(fastd_context *ctx, fastd_socket *sock) {
|
||||
size_t max_len = PACKET_TYPE_LEN + methods_max_packet_size(ctx);
|
||||
fastd_buffer buffer = fastd_buffer_alloc(max_len, methods_min_decrypt_head_space(ctx), methods_min_decrypt_tail_space(ctx));
|
||||
uint8_t *packet_type;
|
||||
|
@ -752,17 +763,6 @@ static void handle_resolv_returns(fastd_context *ctx) {
|
|||
peer->last_resolve_return = ctx->now;
|
||||
|
||||
if (fastd_peer_claim_address(ctx, peer, NULL, &resolve_return.addr)) {
|
||||
if (!peer->sock) {
|
||||
switch(resolve_return.addr.sa.sa_family) {
|
||||
case AF_INET:
|
||||
peer->sock = ctx->sock_default_v4;
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
peer->sock = ctx->sock_default_v6;
|
||||
}
|
||||
}
|
||||
|
||||
send_handshake(ctx, peer);
|
||||
}
|
||||
else {
|
||||
|
@ -781,28 +781,44 @@ static inline void handle_socket_error(fastd_context *ctx, fastd_socket *sock) {
|
|||
else
|
||||
pr_warn(ctx, "socket bind %I lost", &sock->addr->addr);
|
||||
|
||||
close_socket(ctx, sock);
|
||||
fastd_socket_close(ctx, sock);
|
||||
}
|
||||
|
||||
static void handle_input(fastd_context *ctx) {
|
||||
struct pollfd fds[ctx->n_socks + 2];
|
||||
const size_t n_fds = 2 + ctx->n_socks + ctx->n_peers;
|
||||
struct pollfd fds[n_fds];
|
||||
fds[0].fd = ctx->tunfd;
|
||||
fds[0].events = POLLIN;
|
||||
fds[1].fd = ctx->resolverfd;
|
||||
fds[1].events = POLLIN;
|
||||
|
||||
unsigned i;
|
||||
for (i = 0; i < ctx->n_socks; i++) {
|
||||
fds[i+2].fd = ctx->socks[i].fd;
|
||||
fds[i+2].events = POLLIN;
|
||||
for (i = 2; i < ctx->n_socks+2; i++) {
|
||||
fds[i].fd = ctx->socks[i-2].fd;
|
||||
fds[i].events = POLLIN;
|
||||
}
|
||||
|
||||
fastd_peer *peer;
|
||||
for (peer = ctx->peers; peer; peer = peer->next) {
|
||||
if (peer->sock && fastd_peer_is_socket_dynamic(peer))
|
||||
fds[i].fd = peer->sock->fd;
|
||||
else
|
||||
fds[i].fd = -1;
|
||||
|
||||
fds[i].events = POLLIN;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i != n_fds)
|
||||
exit_bug(ctx, "fd count mismatch");
|
||||
|
||||
int timeout = fastd_task_timeout(ctx);
|
||||
|
||||
if (timeout < 0 || timeout > 60000)
|
||||
timeout = 60000; /* call maintenance at least once a minute */
|
||||
|
||||
int ret = poll(fds, ctx->n_socks + 2, timeout);
|
||||
int ret = poll(fds, n_fds, timeout);
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR)
|
||||
return;
|
||||
|
@ -817,15 +833,24 @@ static void handle_input(fastd_context *ctx) {
|
|||
if (fds[1].revents & POLLIN)
|
||||
handle_resolv_returns(ctx);
|
||||
|
||||
for (i = 0; i < ctx->n_socks; i++) {
|
||||
if (fds[i+2].revents & (POLLERR|POLLHUP|POLLNVAL)) {
|
||||
handle_socket_error(ctx, &ctx->socks[i]);
|
||||
continue;
|
||||
for (i = 2; i < ctx->n_socks+2; i++) {
|
||||
if (fds[i].revents & (POLLERR|POLLHUP|POLLNVAL))
|
||||
handle_socket_error(ctx, &ctx->socks[i-2]);
|
||||
else if (fds[i].revents & POLLIN)
|
||||
handle_socket(ctx, &ctx->socks[i-2]);
|
||||
}
|
||||
|
||||
if (fds[i+2].revents & POLLIN)
|
||||
handle_socket(ctx, &ctx->socks[i]);
|
||||
for (peer = ctx->peers; peer; peer = peer->next) {
|
||||
if (fds[i].revents & (POLLERR|POLLHUP|POLLNVAL))
|
||||
fastd_peer_reset_socket(ctx, peer);
|
||||
else if (fds[i].revents & POLLIN)
|
||||
handle_socket(ctx, peer->sock);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i != n_fds)
|
||||
exit_bug(ctx, "fd count mismatch");
|
||||
}
|
||||
|
||||
static void cleanup_peers(fastd_context *ctx) {
|
||||
|
|
15
src/fastd.h
15
src/fastd.h
|
@ -73,7 +73,7 @@ struct _fastd_protocol {
|
|||
void (*peer_configure)(fastd_context *ctx, fastd_peer_config *peer_conf);
|
||||
|
||||
void (*handshake_init)(fastd_context *ctx, const fastd_socket *sock, const fastd_peer_address *address, const fastd_peer_config *peer_conf);
|
||||
void (*handshake_handle)(fastd_context *ctx, const fastd_socket *sock, const fastd_peer_address *address, const fastd_peer_config *peer_conf, const fastd_handshake *handshake, const fastd_method *method);
|
||||
void (*handshake_handle)(fastd_context *ctx, fastd_socket *sock, const fastd_peer_address *address, const fastd_peer_config *peer_conf, const fastd_handshake *handshake, const fastd_method *method);
|
||||
|
||||
void (*handle_recv)(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer);
|
||||
void (*send)(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer);
|
||||
|
@ -189,7 +189,6 @@ struct _fastd_config {
|
|||
fastd_string_stack *peer_dirs;
|
||||
fastd_peer_config *peers;
|
||||
|
||||
unsigned n_peers;
|
||||
unsigned n_floating;
|
||||
unsigned n_v4;
|
||||
unsigned n_v6;
|
||||
|
@ -228,6 +227,7 @@ struct _fastd_context {
|
|||
|
||||
struct timespec now;
|
||||
|
||||
unsigned n_peers;
|
||||
fastd_peer *peers;
|
||||
fastd_queue task_queue;
|
||||
|
||||
|
@ -268,6 +268,8 @@ void fastd_send(fastd_context *ctx, const fastd_socket *sock, const fastd_peer_a
|
|||
void fastd_send_handshake(fastd_context *ctx, const fastd_socket *sock, const fastd_peer_address *address, fastd_buffer buffer);
|
||||
void fastd_handle_receive(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer);
|
||||
|
||||
fastd_socket* fastd_socket_open(fastd_context *ctx, int af);
|
||||
|
||||
void fastd_resolve_peer(fastd_context *ctx, fastd_peer *peer);
|
||||
|
||||
int fastd_vsnprintf(const fastd_context *ctx, char *buffer, size_t size, const char *format, va_list ap);
|
||||
|
@ -394,6 +396,15 @@ static inline void fastd_string_stack_free(fastd_string_stack *str) {
|
|||
}
|
||||
}
|
||||
|
||||
static inline void fastd_socket_close(fastd_context *ctx, fastd_socket *sock) {
|
||||
if (sock->fd >= 0) {
|
||||
if(close(sock->fd))
|
||||
pr_error_errno(ctx, "closing socket: close");
|
||||
|
||||
sock->fd = -2;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool timespec_after(const struct timespec *tp1, const struct timespec *tp2) {
|
||||
return (tp1->tv_sec > tp2->tv_sec ||
|
||||
(tp1->tv_sec == tp2->tv_sec && tp1->tv_nsec > tp2->tv_nsec));
|
||||
|
|
|
@ -180,7 +180,7 @@ static fastd_string_stack* parse_string_list(uint8_t *data, size_t len) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
void fastd_handshake_handle(fastd_context *ctx, const fastd_socket *sock, const fastd_peer_address *address, const fastd_peer_config *peer_conf, fastd_buffer buffer) {
|
||||
void fastd_handshake_handle(fastd_context *ctx, fastd_socket *sock, const fastd_peer_address *address, const fastd_peer_config *peer_conf, fastd_buffer buffer) {
|
||||
if (buffer.len < sizeof(fastd_packet)) {
|
||||
pr_warn(ctx, "received a short handshake from %I", address);
|
||||
goto end_free;
|
||||
|
|
|
@ -71,7 +71,7 @@ struct _fastd_handshake {
|
|||
fastd_buffer fastd_handshake_new_init(fastd_context *ctx, size_t tail_space);
|
||||
fastd_buffer fastd_handshake_new_reply(fastd_context *ctx, const fastd_handshake *handshake, const fastd_method *method, size_t tail_space);
|
||||
|
||||
void fastd_handshake_handle(fastd_context *ctx, const fastd_socket *sock, const fastd_peer_address *address, const fastd_peer_config *peer_conf, fastd_buffer buffer);
|
||||
void fastd_handshake_handle(fastd_context *ctx, fastd_socket *sock, const fastd_peer_address *address, const fastd_peer_config *peer_conf, fastd_buffer buffer);
|
||||
|
||||
|
||||
static inline void fastd_handshake_add(fastd_context *ctx, fastd_buffer *buffer, fastd_handshake_record_type type, size_t len, const void *data) {
|
||||
|
|
60
src/peer.c
60
src/peer.c
|
@ -146,10 +146,46 @@ static void on_disestablish(fastd_context *ctx, fastd_peer *peer) {
|
|||
free(cwd);
|
||||
}
|
||||
|
||||
static inline void reset_peer(fastd_context *ctx, fastd_peer *peer) {
|
||||
static inline void free_socket(fastd_context *ctx, fastd_peer *peer) {
|
||||
if (peer->sock) {
|
||||
if (fastd_peer_is_socket_dynamic(peer)) {
|
||||
fastd_socket_close(ctx, peer->sock);
|
||||
free(peer->sock);
|
||||
}
|
||||
peer->sock = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void fastd_peer_reset_socket(fastd_context *ctx, fastd_peer *peer) {
|
||||
if (!fastd_peer_is_socket_dynamic(peer))
|
||||
return;
|
||||
|
||||
pr_debug(ctx, "resetting socket for peer %P", peer);
|
||||
|
||||
free_socket(ctx, peer);
|
||||
|
||||
switch (peer->address.sa.sa_family) {
|
||||
case AF_INET:
|
||||
if (ctx->sock_default_v4)
|
||||
peer->sock = ctx->sock_default_v4;
|
||||
else
|
||||
peer->sock = fastd_socket_open(ctx, AF_INET);
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
if (ctx->sock_default_v6)
|
||||
peer->sock = ctx->sock_default_v6;
|
||||
else
|
||||
peer->sock = fastd_socket_open(ctx, AF_INET6);
|
||||
}
|
||||
}
|
||||
|
||||
static void reset_peer(fastd_context *ctx, fastd_peer *peer) {
|
||||
if (peer->established)
|
||||
on_disestablish(ctx, peer);
|
||||
|
||||
free_socket(ctx, peer);
|
||||
|
||||
ctx->conf->protocol->reset_peer_state(ctx, peer);
|
||||
|
||||
int i, deleted = 0;
|
||||
|
@ -167,7 +203,7 @@ static inline void reset_peer(fastd_context *ctx, fastd_peer *peer) {
|
|||
fastd_task_delete_peer(ctx, peer);
|
||||
}
|
||||
|
||||
static inline void setup_peer(fastd_context *ctx, fastd_peer *peer) {
|
||||
static void setup_peer(fastd_context *ctx, fastd_peer *peer) {
|
||||
if (peer->config->hostname)
|
||||
peer->address.sa.sa_family = AF_UNSPEC;
|
||||
else
|
||||
|
@ -175,19 +211,6 @@ static inline void setup_peer(fastd_context *ctx, fastd_peer *peer) {
|
|||
|
||||
peer->established = false;
|
||||
|
||||
switch (peer->address.sa.sa_family) {
|
||||
case AF_INET:
|
||||
peer->sock = ctx->sock_default_v4;
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
peer->sock = ctx->sock_default_v6;
|
||||
break;
|
||||
|
||||
default:
|
||||
peer->sock = NULL;
|
||||
}
|
||||
|
||||
peer->last_resolve = (struct timespec){0, 0};
|
||||
peer->last_resolve_return = (struct timespec){0, 0};
|
||||
peer->seen = (struct timespec){0, 0};
|
||||
|
@ -292,7 +315,7 @@ bool fastd_peer_address_equal(const fastd_peer_address *addr1, const fastd_peer_
|
|||
return true;
|
||||
}
|
||||
|
||||
bool fastd_peer_claim_address(fastd_context *ctx, fastd_peer *new_peer, const fastd_socket *sock, const fastd_peer_address *addr) {
|
||||
bool fastd_peer_claim_address(fastd_context *ctx, fastd_peer *new_peer, fastd_socket *sock, const fastd_peer_address *addr) {
|
||||
if (addr->sa.sa_family != AF_UNSPEC) {
|
||||
fastd_peer *peer;
|
||||
for (peer = ctx->peers; peer; peer = peer->next) {
|
||||
|
@ -316,8 +339,10 @@ bool fastd_peer_claim_address(fastd_context *ctx, fastd_peer *new_peer, const fa
|
|||
}
|
||||
|
||||
new_peer->address = *addr;
|
||||
if (sock)
|
||||
if (sock && sock->addr && sock != new_peer->sock) {
|
||||
free_socket(ctx, new_peer);
|
||||
new_peer->sock = sock;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -358,6 +383,7 @@ fastd_peer* fastd_peer_add(fastd_context *ctx, fastd_peer_config *peer_conf) {
|
|||
|
||||
peer->config = peer_conf;
|
||||
peer->protocol_state = NULL;
|
||||
peer->sock = NULL;
|
||||
setup_peer(ctx, peer);
|
||||
|
||||
pr_verbose(ctx, "adding peer %P", peer);
|
||||
|
|
|
@ -35,7 +35,7 @@ struct _fastd_peer {
|
|||
|
||||
const fastd_peer_config *config;
|
||||
|
||||
const fastd_socket *sock;
|
||||
fastd_socket *sock;
|
||||
fastd_peer_address address;
|
||||
|
||||
bool established;
|
||||
|
@ -88,7 +88,8 @@ void fastd_peer_reset(fastd_context *ctx, fastd_peer *peer);
|
|||
void fastd_peer_delete(fastd_context *ctx, fastd_peer *peer);
|
||||
fastd_peer* fastd_peer_add(fastd_context *ctx, fastd_peer_config *conf);
|
||||
void fastd_peer_set_established(fastd_context *ctx, fastd_peer *peer);
|
||||
bool fastd_peer_claim_address(fastd_context *ctx, fastd_peer *peer, const fastd_socket *sock, const fastd_peer_address *addr);
|
||||
bool fastd_peer_claim_address(fastd_context *ctx, fastd_peer *peer, fastd_socket *sock, const fastd_peer_address *addr);
|
||||
void fastd_peer_reset_socket(fastd_context *ctx, fastd_peer *peer);
|
||||
|
||||
const fastd_eth_addr* fastd_get_source_address(const fastd_context *ctx, fastd_buffer buffer);
|
||||
const fastd_eth_addr* fastd_get_dest_address(const fastd_context *ctx, fastd_buffer buffer);
|
||||
|
@ -119,6 +120,10 @@ static inline void fastd_peer_seen(fastd_context *ctx, fastd_peer *peer) {
|
|||
peer->seen = ctx->now;
|
||||
}
|
||||
|
||||
static inline bool fastd_peer_is_socket_dynamic(const fastd_peer *peer) {
|
||||
return (!peer->sock || !peer->sock->addr);
|
||||
}
|
||||
|
||||
static inline bool fastd_eth_addr_is_unicast(const fastd_eth_addr *addr) {
|
||||
return ((addr->data[0] & 1) == 0);
|
||||
}
|
||||
|
|
|
@ -305,7 +305,7 @@ static void respond_handshake(fastd_context *ctx, const fastd_socket *sock, cons
|
|||
fastd_send_handshake(ctx, sock, address, buffer);
|
||||
}
|
||||
|
||||
static bool establish(fastd_context *ctx, fastd_peer *peer, const fastd_method *method, const fastd_socket *sock, const fastd_peer_address *address, bool initiator,
|
||||
static bool establish(fastd_context *ctx, fastd_peer *peer, const fastd_method *method, fastd_socket *sock, const fastd_peer_address *address, bool initiator,
|
||||
const ecc_public_key_256 *A, const ecc_public_key_256 *B, const ecc_public_key_256 *X,
|
||||
const ecc_public_key_256 *Y, const ecc_public_key_256 *sigma, uint64_t serial) {
|
||||
uint8_t hashinput[5*PUBLICKEYBYTES];
|
||||
|
@ -362,7 +362,7 @@ static bool establish(fastd_context *ctx, fastd_peer *peer, const fastd_method *
|
|||
return true;
|
||||
}
|
||||
|
||||
static void finish_handshake(fastd_context *ctx, const fastd_socket *sock, const fastd_peer_address *address, fastd_peer *peer, const handshake_key *handshake_key, const ecc_public_key_256 *peer_handshake_key,
|
||||
static void finish_handshake(fastd_context *ctx, fastd_socket *sock, const fastd_peer_address *address, fastd_peer *peer, const handshake_key *handshake_key, const ecc_public_key_256 *peer_handshake_key,
|
||||
const fastd_handshake *handshake, const fastd_method *method) {
|
||||
pr_debug(ctx, "finishing handshake with %P[%I]...", peer, address);
|
||||
|
||||
|
@ -433,7 +433,7 @@ static void finish_handshake(fastd_context *ctx, const fastd_socket *sock, const
|
|||
fastd_send_handshake(ctx, sock, address, buffer);
|
||||
}
|
||||
|
||||
static void handle_finish_handshake(fastd_context *ctx, const fastd_socket *sock, const fastd_peer_address *address, fastd_peer *peer, const handshake_key *handshake_key, const ecc_public_key_256 *peer_handshake_key,
|
||||
static void handle_finish_handshake(fastd_context *ctx, fastd_socket *sock, const fastd_peer_address *address, fastd_peer *peer, const handshake_key *handshake_key, const ecc_public_key_256 *peer_handshake_key,
|
||||
const fastd_handshake *handshake, const fastd_method *method) {
|
||||
pr_debug(ctx, "handling handshake finish with %P[%I]...", peer, address);
|
||||
|
||||
|
@ -522,7 +522,7 @@ static inline bool has_field(const fastd_handshake *handshake, uint8_t type, siz
|
|||
return (handshake->records[type].length == length);
|
||||
}
|
||||
|
||||
static void protocol_handshake_handle(fastd_context *ctx, const fastd_socket *sock, const fastd_peer_address *address, const fastd_peer_config *peer_conf, const fastd_handshake *handshake, const fastd_method *method) {
|
||||
static void protocol_handshake_handle(fastd_context *ctx, fastd_socket *sock, const fastd_peer_address *address, const fastd_peer_config *peer_conf, const fastd_handshake *handshake, const fastd_method *method) {
|
||||
handshake_key *handshake_key;
|
||||
char *peer_version_name = NULL;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue