From 794958aa7834c6703e369d15b99fe0b38a8edb05 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Mon, 16 Dec 2013 20:33:53 +0100 Subject: resolve: consider all addresses returned for a hostname --- src/fastd.c | 16 +++++++++++++--- src/fastd.h | 3 ++- src/peer.c | 26 +++++++++++++++++++------- src/peer.h | 12 +++++++++--- src/resolve.c | 41 +++++++++++++++++++++++++++-------------- 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); -- cgit v1.2.3