summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/fastd.c16
-rw-r--r--src/fastd.h3
-rw-r--r--src/peer.c26
-rw-r--r--src/peer.h12
-rw-r--r--src/resolve.c41
5 files changed, 70 insertions, 28 deletions
diff --git a/src/fastd.c b/src/fastd.c
index a9cb0c4..d6bfa2f 100644
--- a/src/fastd.c
+++ b/src/fastd.c
@@ -412,7 +412,7 @@ static void send_handshake(fastd_context_t *ctx, fastd_peer_t *peer) {
if (!peer->next_remote)
exit_bug(ctx, "send_handshake: no remote");
- fastd_peer_claim_address(ctx, peer, NULL, NULL, &peer->next_remote->address);
+ fastd_peer_claim_address(ctx, peer, NULL, NULL, &peer->next_remote->addresses[peer->next_remote->current_address]);
fastd_peer_reset_socket(ctx, peer);
}
@@ -456,10 +456,15 @@ static void handle_handshake_queue(fastd_context_t *ctx) {
if (fastd_peer_is_established(peer))
return;
+ if (++peer->next_remote->current_address < peer->next_remote->n_addresses)
+ return;
+
peer->next_remote = peer->next_remote->next;
if (!peer->next_remote)
peer->next_remote = peer->remotes;
+ peer->next_remote->current_address = 0;
+
if (fastd_remote_is_dynamic(peer->next_remote))
fastd_resolve_peer(ctx, peer, peer->next_remote);
}
@@ -503,12 +508,17 @@ static void handle_tun(fastd_context_t *ctx) {
static void handle_resolve_returns(fastd_context_t *ctx) {
fastd_resolve_return_t resolve_return;
-
while (read(ctx->resolverfd, &resolve_return, sizeof(resolve_return)) < 0) {
if (errno != EINTR)
exit_errno(ctx, "handle_resolve_return: read");
}
+ fastd_peer_address_t addresses[resolve_return.n_addr];
+ while (read(ctx->resolverfd, &addresses, sizeof(addresses)) < 0) {
+ if (errno != EINTR)
+ exit_errno(ctx, "handle_resolve_return: read");
+ }
+
fastd_peer_t *peer;
for (peer = ctx->peers; peer; peer = peer->next) {
if (!peer->config)
@@ -523,7 +533,7 @@ static void handle_resolve_returns(fastd_context_t *ctx) {
if (!remote)
continue;
- fastd_peer_handle_resolve(ctx, peer, remote, &resolve_return.addr);
+ fastd_peer_handle_resolve(ctx, peer, remote, resolve_return.n_addr, addresses);
break;
}
diff --git a/src/fastd.h b/src/fastd.h
index b170bb5..d03465d 100644
--- a/src/fastd.h
+++ b/src/fastd.h
@@ -80,7 +80,8 @@ union fastd_peer_address {
struct fastd_resolve_return {
fastd_remote_t *remote;
- fastd_peer_address_t addr;
+ size_t n_addr;
+ fastd_peer_address_t addr[];
};
struct fastd_log_file {
diff --git a/src/peer.c b/src/peer.c
index 5934d82..def664d 100644
--- a/src/peer.c
+++ b/src/peer.c
@@ -185,9 +185,15 @@ static void init_handshake(fastd_context_t *ctx, fastd_peer_t *peer) {
fastd_peer_schedule_handshake(ctx, peer, delay);
}
-void fastd_peer_handle_resolve(fastd_context_t *ctx, fastd_peer_t *peer, fastd_remote_t *remote, const fastd_peer_address_t *address) {
+void fastd_peer_handle_resolve(fastd_context_t *ctx, fastd_peer_t *peer, fastd_remote_t *remote, size_t n_addresses, const fastd_peer_address_t *addresses) {
remote->last_resolve_return = ctx->now;
- remote->address = *address;
+
+ free(remote->addresses);
+ remote->addresses = malloc(n_addresses*sizeof(fastd_peer_address_t));
+ memcpy(remote->addresses, addresses, n_addresses*sizeof(fastd_peer_address_t));
+
+ remote->n_addresses = n_addresses;
+ remote->current_address = 0;
if (peer->state == STATE_RESOLVING)
init_handshake(ctx, peer);
@@ -216,7 +222,7 @@ static void setup_peer(fastd_context_t *ctx, fastd_peer_t *peer) {
if (!peer->protocol_state)
ctx->conf->protocol->init_peer_state(ctx, peer);
- if(peer->next_remote) {
+ if (peer->next_remote) {
if (fastd_remote_is_dynamic(peer->next_remote)) {
peer->state = STATE_RESOLVING;
fastd_resolve_peer(ctx, peer, peer->next_remote);
@@ -390,8 +396,11 @@ bool fastd_peer_matches_address(fastd_context_t *ctx UNUSED, const fastd_peer_t
fastd_remote_t *remote;
for (remote = peer->remotes; remote; remote = remote->next) {
- if (fastd_peer_address_equal(&remote->address, addr))
- return true;
+ size_t i;
+ for (i = 0; i < remote->n_addresses; i++) {
+ if (fastd_peer_address_equal(&remote->addresses[i], addr))
+ return true;
+ }
}
return false;
@@ -525,8 +534,11 @@ fastd_peer_t* fastd_peer_add(fastd_context_t *ctx, fastd_peer_config_t *peer_con
(*remote)->ref = 1;
(*remote)->config = remote_config;
- if (!remote_config->hostname)
- (*remote)->address = remote_config->address;
+ if (!remote_config->hostname) {
+ (*remote)->n_addresses = 1;
+ (*remote)->addresses = malloc(sizeof(fastd_peer_address_t));
+ (*remote)->addresses[0] = remote_config->address;
+ }
remote = &(*remote)->next;
remote_config = remote_config->next;
diff --git a/src/peer.h b/src/peer.h
index fd32166..1a34ef5 100644
--- a/src/peer.h
+++ b/src/peer.h
@@ -89,7 +89,11 @@ struct fastd_remote {
unsigned ref;
fastd_remote_config_t *config;
- fastd_peer_address_t address;
+
+ size_t n_addresses;
+ size_t current_address;
+ fastd_peer_address_t *addresses;
+
struct timespec last_resolve;
struct timespec last_resolve_return;
};
@@ -133,7 +137,7 @@ bool fastd_peer_verify_temporary(fastd_context_t *ctx, fastd_peer_t *peer, const
void fastd_peer_enable_temporary(fastd_context_t *ctx, fastd_peer_t *peer);
void fastd_peer_set_established(fastd_context_t *ctx, fastd_peer_t *peer);
bool fastd_peer_may_connect(fastd_context_t *ctx, fastd_peer_t *peer);
-void fastd_peer_handle_resolve(fastd_context_t *ctx, fastd_peer_t *peer, fastd_remote_t *remote, const fastd_peer_address_t *address);
+void fastd_peer_handle_resolve(fastd_context_t *ctx, fastd_peer_t *peer, fastd_remote_t *remote, size_t n_addresses, const fastd_peer_address_t *addresses);
bool fastd_peer_owns_address(fastd_context_t *ctx, const fastd_peer_t *peer, const fastd_peer_address_t *addr);
bool fastd_peer_matches_address(fastd_context_t *ctx, const fastd_peer_t *peer, const fastd_peer_address_t *addr);
bool fastd_peer_claim_address(fastd_context_t *ctx, fastd_peer_t *peer, fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr);
@@ -188,8 +192,10 @@ static inline void fastd_remote_ref(fastd_remote_t *remote) {
}
static inline void fastd_remote_unref(fastd_remote_t *remote) {
- if(!--remote->ref)
+ if(!--remote->ref) {
+ free(remote->addresses);
free(remote);
+ }
}
static inline bool fastd_remote_is_dynamic(const fastd_remote_t *remote) {
diff --git a/src/resolve.c b/src/resolve.c
index 9631c48..1bda382 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -42,9 +42,9 @@ typedef struct resolv_arg {
static void* resolve_peer(void *varg) {
resolv_arg_t *arg = varg;
- struct addrinfo *res = NULL;
+ struct addrinfo *res = NULL, *res2;
+ size_t n_addr = 0;
int gai_ret;
- bool error = false;
char portstr[6];
snprintf(portstr, 6, "%u", ntohs(arg->constraints.in.sin_port));
@@ -63,24 +63,37 @@ static void* resolve_peer(void *varg) {
if (gai_ret || !res) {
pr_verbose(arg->ctx, "resolving host `%s' failed: %s", arg->hostname, gai_strerror(gai_ret));
- error = true;
}
- else if (res->ai_addrlen > sizeof(fastd_peer_address_t) || (res->ai_addr->sa_family != AF_INET && res->ai_addr->sa_family != AF_INET6)) {
- pr_warn(arg->ctx, "resolving host `%s': unsupported address returned", arg->hostname);
- error = true;
+ else {
+ for (res2 = res; res2; res2 = res2->ai_next)
+ n_addr++;
}
- fastd_resolve_return_t ret = {
- .remote = arg->remote
- };
+ fastd_resolve_return_t *ret = alloca(sizeof(fastd_resolve_return_t) + n_addr*sizeof(fastd_peer_address_t));
+ ret->remote = arg->remote;
+
+ if (n_addr) {
+ n_addr = 0;
+ for (res2 = res; res2; res2 = res2->ai_next) {
+ if (res2->ai_addrlen > sizeof(fastd_peer_address_t) || (res2->ai_addr->sa_family != AF_INET && res2->ai_addr->sa_family != AF_INET6)) {
+ pr_warn(arg->ctx, "resolving host `%s': unsupported address returned", arg->hostname);
+ continue;
+ }
+
+ memset(&ret->addr[n_addr], 0, sizeof(fastd_peer_address_t));
+ memcpy(&ret->addr[n_addr], res2->ai_addr, res2->ai_addrlen);
+ fastd_peer_address_simplify(&ret->addr[n_addr]);
- if (!error) {
- pr_verbose(arg->ctx, "resolved host `%s' successfully", arg->hostname);
- memcpy(&ret.addr, res->ai_addr, res->ai_addrlen);
- fastd_peer_address_simplify(&ret.addr);
+ n_addr++;
+ }
+
+ if (n_addr)
+ pr_verbose(arg->ctx, "resolved host `%s' successfully", arg->hostname);
}
- if (write(arg->ctx->resolvewfd, &ret, sizeof(ret)) < 0)
+ ret->n_addr = n_addr;
+
+ if (write(arg->ctx->resolvewfd, ret, sizeof(fastd_resolve_return_t) + n_addr*sizeof(fastd_peer_address_t)) < 0)
pr_error_errno(arg->ctx, "can't write resolve return");
freeaddrinfo(res);