From 078b835209bd22b5cf3f497f2b06f3fad0a078ca Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Mon, 29 Oct 2012 22:21:47 +0100 Subject: Add support for multiple binds --- src/config.c | 37 +++++-- src/config.y | 37 ++++--- src/fastd.c | 242 ++++++++++++++++++++++++++++-------------- src/fastd.h | 33 ++++-- src/handshake.c | 8 +- src/handshake.h | 2 +- src/peer.c | 18 +++- src/peer.h | 3 +- src/protocol_ec25519_fhmqvc.c | 37 ++++--- src/types.h | 2 + 10 files changed, 284 insertions(+), 135 deletions(-) diff --git a/src/config.c b/src/config.c index 4eee712..be67e2b 100644 --- a/src/config.c +++ b/src/config.c @@ -629,26 +629,34 @@ static void option_bind(fastd_context *ctx, fastd_config *conf, const char *arg) l = 0; } - if (strcmp(addrstr, "any") == 0) { - conf->bind_addr_in.sin_addr.s_addr = htonl(INADDR_ANY); - conf->bind_addr_in.sin_port = htons(l); + fastd_bind_address *addr = calloc(1, sizeof(fastd_bind_address)); + addr->next = conf->bind_addrs; + conf->bind_addrs = addr; - conf->bind_addr_in6.sin6_addr = in6addr_any; - conf->bind_addr_in6.sin6_port = htons(l); + if (strcmp(addrstr, "any") == 0) { + /* nothing to do */ } else if (arg[0] == '[') { - conf->bind_addr_in6.sin6_family = AF_INET6; - if (inet_pton(AF_INET6, addrstr, &conf->bind_addr_in6.sin6_addr) != 1) + addr->addr.in6.sin6_family = AF_INET6; + addr->addr.in6.sin6_port = htons(l); + + if (inet_pton(AF_INET6, addrstr, &addr->addr.in6.sin6_addr) != 1) exit_error(ctx, "invalid bind address `%s'", addrstr); - conf->bind_addr_in6.sin6_port = htons(l); } else { - conf->bind_addr_in.sin_family = AF_INET; - if (inet_pton(AF_INET, addrstr, &conf->bind_addr_in.sin_addr) != 1) + addr->addr.in.sin_family = AF_INET; + addr->addr.in.sin_port = htons(l); + + if (inet_pton(AF_INET, addrstr, &addr->addr.in.sin_addr) != 1) exit_error(ctx, "invalid bind address `%s'", addrstr); - conf->bind_addr_in.sin_port = htons(l); } + if (!conf->bind_addr_default_v4 && addr->addr.sa.sa_family != AF_INET6) + conf->bind_addr_default_v4 = addr; + + if (!conf->bind_addr_default_v6 && addr->addr.sa.sa_family != AF_INET) + conf->bind_addr_default_v6 = addr; + free(addrstr); } @@ -886,6 +894,13 @@ void fastd_config_release(fastd_context *ctx, fastd_config *conf) { conf->log_files = next; } + while (conf->bind_addrs) { + fastd_bind_address *next = conf->bind_addrs->next; + free(conf->bind_addrs->bindtodev); + free(conf->bind_addrs); + conf->bind_addrs = next; + } + free(conf->ifname); free(conf->secret); free(conf->on_up); diff --git a/src/config.y b/src/config.y index 2b1af0f..d87c151 100644 --- a/src/config.y +++ b/src/config.y @@ -187,21 +187,32 @@ log_level: TOK_FATAL { $$ = LOG_CRIT; } interface: TOK_STRING { free(conf->ifname); conf->ifname = strdup($1->str); } ; -bind: TOK_ADDR maybe_port { - conf->bind_addr_in.sin_family = AF_INET; - conf->bind_addr_in.sin_addr = $1; - conf->bind_addr_in.sin_port = htons($2); +bind_new: { + fastd_bind_address *addr = calloc(1, sizeof(fastd_bind_address)); + addr->next = conf->bind_addrs; + conf->bind_addrs = addr; } - | TOK_ADDR6 maybe_port { - conf->bind_addr_in6.sin6_family = AF_INET6; - conf->bind_addr_in6.sin6_addr = $1; - conf->bind_addr_in6.sin6_port = htons($2); + +bind: bind_new TOK_ADDR maybe_port { + conf->bind_addrs->addr.in.sin_family = AF_INET; + conf->bind_addrs->addr.in.sin_addr = $2; + conf->bind_addrs->addr.in.sin_port = htons($3); + if (!conf->bind_addr_default_v4) + conf->bind_addr_default_v4 = conf->bind_addrs; + } + | bind_new TOK_ADDR6 maybe_port { + conf->bind_addrs->addr.in6.sin6_family = AF_INET6; + conf->bind_addrs->addr.in6.sin6_addr = $2; + conf->bind_addrs->addr.in6.sin6_port = htons($3); + if (!conf->bind_addr_default_v6) + conf->bind_addr_default_v6 = conf->bind_addrs; } - | TOK_ANY maybe_port { - conf->bind_addr_in.sin_addr.s_addr = htonl(INADDR_ANY); - conf->bind_addr_in.sin_port = htons($2); - conf->bind_addr_in6.sin6_addr = in6addr_any; - conf->bind_addr_in6.sin6_port = htons($2); + | bind_new TOK_ANY maybe_port { + conf->bind_addrs->addr.in.sin_port = htons($3); + if (!conf->bind_addr_default_v4) + conf->bind_addr_default_v4 = conf->bind_addrs; + if (!conf->bind_addr_default_v6) + conf->bind_addr_default_v6 = conf->bind_addrs; } ; diff --git a/src/fastd.c b/src/fastd.c index 5388384..fc6f016 100644 --- a/src/fastd.c +++ b/src/fastd.c @@ -146,62 +146,141 @@ static void crypto_free(fastd_context *ctx) { #endif } + +static unsigned max_sockets(const fastd_config *conf) { + unsigned n = 0; + fastd_bind_address *addr; + + for (addr = conf->bind_addrs; addr; addr = addr->next) + n++; + + return n; +} + static void init_sockets(fastd_context *ctx) { - struct sockaddr_in addr_in = ctx->conf->bind_addr_in; - struct sockaddr_in6 addr_in6 = ctx->conf->bind_addr_in6; + static const fastd_bind_address bind_any = {}; - if (addr_in.sin_family == AF_UNSPEC && addr_in6.sin6_family == AF_UNSPEC) { - if (ctx->conf->peer_dirs || ctx->conf->n_floating || ctx->conf->n_v4 || ctx->conf->n_dynamic || ctx->conf->n_dynamic_v4) - addr_in.sin_family = AF_INET; + const fastd_bind_address *addr = ctx->conf->bind_addrs; + const fastd_bind_address *default_v4 = ctx->conf->bind_addr_default_v4; + const fastd_bind_address *default_v6 = ctx->conf->bind_addr_default_v6; - if (ctx->conf->peer_dirs || ctx->conf->n_floating || ctx->conf->n_v6 || ctx->conf->n_dynamic || ctx->conf->n_dynamic_v6) - addr_in6.sin6_family = AF_INET6; - } + if (!addr) + addr = default_v4 = default_v6 = &bind_any; - if (addr_in.sin_family == AF_UNSPEC && ctx->conf->n_v4) - pr_warn(ctx, "there are IPv4 peers defined, but bind is explicitly set to IPv6"); + unsigned n_v4 = 0, n_v6 = 0; + bool info_ipv6 = true; - if (addr_in6.sin6_family == AF_UNSPEC && ctx->conf->n_v6) - pr_warn(ctx, "there are IPv6 peers defined, but bind is explicitly set to IPv4"); + ctx->socks = calloc(max_sockets(ctx->conf), sizeof(fastd_socket)); - if (addr_in.sin_family == AF_INET) { - pr_debug(ctx, "initializing IPv4 socket..."); + while (addr) { + int fd = -1; + int af = AF_UNSPEC; - if ((ctx->sockfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) - exit_errno(ctx, "socket"); + if (addr->addr.sa.sa_family != AF_INET) { + fd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (fd < 0) { + if (info_ipv6) { + pr_warn(ctx, "there seems to be no IPv6 support; explicitely bind to an IPv4 address (or 0.0.0.0) to disable this warning"); + info_ipv6 = false; + } + } + else { + af = AF_INET6; - if (bind(ctx->sockfd, (struct sockaddr*)&addr_in, sizeof(struct sockaddr_in))) - exit_errno(ctx, "bind"); + int val = (addr->addr.sa.sa_family == AF_INET6); + if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val))) { + pr_warn_errno(ctx, "setsockopt"); + goto error; + } + } + } + if (fd < 0 && addr->addr.sa.sa_family != AF_INET6) { + fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (fd < 0) + exit_errno(ctx, "unable to create socket"); + else + af = AF_INET; + } - pr_debug(ctx, "IPv4 socket initialized."); - } - else { - ctx->sockfd = -1; - } + if (fd < 0) + goto error; + + if (addr->bindtodev) { + if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, addr->bindtodev, strlen(addr->bindtodev))) { + pr_warn_errno(ctx, "setsockopt: unable to bind to device"); + goto error; + } + } + + fastd_peer_address bind_address = addr->addr; - if (addr_in6.sin6_family == AF_INET6) { - pr_debug(ctx, "initializing IPv6 socket..."); + if (bind_address.sa.sa_family == AF_UNSPEC) { + memset(&bind_address, 0, sizeof(bind_address)); + bind_address.sa.sa_family = af; - if ((ctx->sock6fd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0) { - if (ctx->sockfd >= 0) - pr_warn_errno(ctx, "socket"); + if (af == AF_INET6) + bind_address.in6.sin6_port = addr->addr.in.sin_port; else - exit_errno(ctx, "socket"); + bind_address.in.sin_port = addr->addr.in.sin_port; + } + + if (bind(fd, (struct sockaddr*)&bind_address, af == AF_INET6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))) { + pr_warn(ctx, "bind"); + goto error; + } + + ctx->socks[ctx->n_socks] = (fastd_socket){fd, addr}; + + if (af == AF_INET6) { + if (addr == default_v6) + ctx->sock_default_v6 = &ctx->socks[ctx->n_socks]; + + n_v6++; + + if (addr->addr.sa.sa_family == AF_UNSPEC) { + if (addr == default_v4) + ctx->sock_default_v4 = &ctx->socks[ctx->n_socks]; + + n_v4++; + } } else { - int val = 1; - if (setsockopt(ctx->sock6fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val))) - exit_errno(ctx, "setsockopt"); + if (addr == default_v4) + ctx->sock_default_v4 = &ctx->socks[ctx->n_socks]; - if (bind(ctx->sock6fd, (struct sockaddr*)&addr_in6, sizeof(struct sockaddr_in6))) - exit_errno(ctx, "bind"); + n_v4++; + } - pr_debug(ctx, "IPv6 socket initialized."); + ctx->n_socks++; + + addr = addr->next; + continue; + + error: + if (fd >= 0) { + if (close(fd)) + pr_error_errno(ctx, "close"); } + + if (addr->bindtodev) + pr_warn(ctx, "unable to bind to %I on `%s'", addr->addr, addr->bindtodev); + else + pr_warn(ctx, "unable to bind to %I", addr->addr); + + if (addr == default_v4 || addr == default_v6) + exit_error(ctx, "unable to bind to default address"); + + addr = addr->next; } - else { - ctx->sock6fd = -1; - } + + if (!ctx->n_socks) + exit_error(ctx, "all bind attempts failed"); + + if (!n_v4 && ctx->conf->n_v4) + pr_warn(ctx, "there are IPv4 peers defined, but there was no successful IPv4 bind"); + + if (!n_v6 && ctx->conf->n_v6) + pr_warn(ctx, "there are IPv6 peers defined, but there was no successful IPv4 bind"); } static void init_tuntap(fastd_context *ctx) { @@ -236,9 +315,7 @@ static void init_tuntap(fastd_context *ctx) { ctx->ifname = strndup(ifr.ifr_name, IFNAMSIZ); - int ctl_sock = ctx->sockfd; - if (ctl_sock < 0) - ctl_sock = ctx->sock6fd; + int ctl_sock = ctx->socks[0].fd; ifr.ifr_mtu = ctx->conf->mtu; if (ioctl(ctl_sock, SIOCSIFMTU, &ifr) < 0) @@ -255,15 +332,13 @@ static void close_tuntap(fastd_context *ctx) { } static void close_sockets(fastd_context *ctx) { - if (ctx->sockfd >= 0) { - if(close(ctx->sockfd)) + unsigned i; + for (i = 0; i < ctx->n_socks; i++) { + if(close(ctx->socks[i].fd)) pr_warn_errno(ctx, "closing IPv4 socket: close"); } - if (ctx->sock6fd >= 0) { - if(close(ctx->sock6fd)) - pr_warn_errno(ctx, "closing IPv6 socket: close"); - } + free(ctx->socks); } static size_t methods_max_packet_size(fastd_context *ctx) { @@ -347,8 +422,10 @@ static size_t methods_min_decrypt_tail_space(fastd_context *ctx) { return ret; } -static void fastd_send_type(fastd_context *ctx, const fastd_peer_address *address, uint8_t packet_type, fastd_buffer buffer) { - int sockfd; +static void fastd_send_type(fastd_context *ctx, const fastd_socket *sock, const fastd_peer_address *address, uint8_t packet_type, fastd_buffer buffer) { + if (!sock) + exit_bug(ctx, "send: sock == NULL"); + struct msghdr msg; memset(&msg, 0, sizeof(msg)); @@ -356,13 +433,11 @@ static void fastd_send_type(fastd_context *ctx, const fastd_peer_address *addres case AF_INET: msg.msg_name = (void*)&address->in; msg.msg_namelen = sizeof(struct sockaddr_in); - sockfd = ctx->sockfd; break; case AF_INET6: msg.msg_name = (void*)&address->in6; msg.msg_namelen = sizeof(struct sockaddr_in6); - sockfd = ctx->sock6fd; break; default: @@ -379,7 +454,7 @@ static void fastd_send_type(fastd_context *ctx, const fastd_peer_address *addres int ret; do { - ret = sendmsg(sockfd, &msg, 0); + ret = sendmsg(sock->fd, &msg, 0); } while (ret < 0 && errno == EINTR); if (ret < 0) @@ -388,12 +463,12 @@ static void fastd_send_type(fastd_context *ctx, const fastd_peer_address *addres fastd_buffer_free(buffer); } -void fastd_send(fastd_context *ctx, const fastd_peer_address *address, fastd_buffer buffer) { - fastd_send_type(ctx, address, PACKET_DATA, buffer); +void fastd_send(fastd_context *ctx, const fastd_socket *sock, const fastd_peer_address *address, fastd_buffer buffer) { + fastd_send_type(ctx, sock, address, PACKET_DATA, buffer); } -void fastd_send_handshake(fastd_context *ctx, const fastd_peer_address *address, fastd_buffer buffer) { - fastd_send_type(ctx, address, PACKET_HANDSHAKE, buffer); +void fastd_send_handshake(fastd_context *ctx, const fastd_socket *sock, const fastd_peer_address *address, fastd_buffer buffer) { + fastd_send_type(ctx, sock, address, PACKET_HANDSHAKE, buffer); } void fastd_handle_receive(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer) { @@ -514,7 +589,7 @@ 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 != AF_UNSPEC) { + if (peer->address.sa.sa_family && 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); @@ -523,7 +598,7 @@ static inline void send_handshake(fastd_context *ctx, fastd_peer *peer) { pr_debug(ctx, "sending handshake to %P...", peer); peer->last_handshake = ctx->now; peer->last_handshake_address = peer->address; - ctx->conf->protocol->handshake_init(ctx, &peer->address, peer->config); + ctx->conf->protocol->handshake_init(ctx, peer->sock, &peer->address, peer->config); } } @@ -603,7 +678,7 @@ static void handle_tun(fastd_context *ctx) { } } -static void handle_socket(fastd_context *ctx, int sockfd) { +static void handle_socket(fastd_context *ctx, const 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; @@ -611,7 +686,7 @@ static void handle_socket(fastd_context *ctx, int sockfd) { fastd_peer_address recvaddr; socklen_t recvaddrlen = sizeof(recvaddr); - ssize_t len = recvfrom(sockfd, buffer.data, buffer.len, 0, (struct sockaddr*)&recvaddr, &recvaddrlen); + ssize_t len = recvfrom(sock->fd, buffer.data, buffer.len, 0, (struct sockaddr*)&recvaddr, &recvaddrlen); if (len < 0) { if (errno != EINTR) pr_warn(ctx, "recvfrom: %s", strerror(errno)); @@ -638,7 +713,7 @@ static void handle_socket(fastd_context *ctx, int sockfd) { break; case PACKET_HANDSHAKE: - fastd_handshake_handle(ctx, &recvaddr, peer->config, buffer); + fastd_handshake_handle(ctx, sock, &recvaddr, peer->config, buffer); break; default: @@ -651,11 +726,11 @@ static void handle_socket(fastd_context *ctx, int sockfd) { switch (*packet_type) { case PACKET_DATA: fastd_buffer_free(buffer); - ctx->conf->protocol->handshake_init(ctx, &recvaddr, NULL); + ctx->conf->protocol->handshake_init(ctx, sock, &recvaddr, NULL); break; case PACKET_HANDSHAKE: - fastd_handshake_handle(ctx, &recvaddr, NULL, buffer); + fastd_handshake_handle(ctx, sock, &recvaddr, NULL, buffer); break; default: @@ -691,7 +766,18 @@ static void handle_resolv_returns(fastd_context *ctx) { peer->last_resolve_return = ctx->now; - if (fastd_peer_claim_address(ctx, peer, &resolve_return.addr)) { + 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 { @@ -705,22 +791,24 @@ static void handle_resolv_returns(fastd_context *ctx) { } static void handle_input(fastd_context *ctx) { - struct pollfd fds[4]; + struct pollfd fds[ctx->n_socks + 2]; fds[0].fd = ctx->tunfd; fds[0].events = POLLIN; - fds[1].fd = ctx->sockfd; + fds[1].fd = ctx->resolverfd; fds[1].events = POLLIN; - fds[2].fd = ctx->sock6fd; - fds[2].events = POLLIN; - fds[3].fd = ctx->resolverfd; - fds[3].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; + } int timeout = fastd_task_timeout(ctx); if (timeout < 0 || timeout > 60000) timeout = 60000; /* call maintenance at least once a minute */ - int ret = poll(fds, 4, timeout); + int ret = poll(fds, ctx->n_socks + 2, timeout); if (ret < 0) { if (errno == EINTR) return; @@ -731,13 +819,14 @@ static void handle_input(fastd_context *ctx) { update_time(ctx); if (fds[0].revents & POLLIN) - handle_tun(ctx); + handle_tun(ctx); if (fds[1].revents & POLLIN) - handle_socket(ctx, ctx->sockfd); - if (fds[2].revents & POLLIN) - handle_socket(ctx, ctx->sock6fd); - if (fds[3].revents & POLLIN) handle_resolv_returns(ctx); + + for (i = 0; i < ctx->n_socks; i++) { + if (fds[i+2].revents & POLLIN) + handle_socket(ctx, &ctx->socks[i]); + } } static void cleanup_peers(fastd_context *ctx) { @@ -875,7 +964,6 @@ int main(int argc, char *argv[]) { init_log(&ctx); fastd_reconfigure(&ctx, &conf); - } pthread_sigmask(SIG_SETMASK, &oldset, NULL); diff --git a/src/fastd.h b/src/fastd.h index 1694105..cf5aaf1 100644 --- a/src/fastd.h +++ b/src/fastd.h @@ -71,8 +71,8 @@ struct _fastd_protocol { fastd_protocol_config* (*init)(fastd_context *ctx); void (*peer_configure)(fastd_context *ctx, fastd_peer_config *peer_conf); - void (*handshake_init)(fastd_context *ctx, const fastd_peer_address *address, const fastd_peer_config *peer_conf); - void (*handshake_handle)(fastd_context *ctx, const fastd_peer_address *address, const fastd_peer_config *peer_conf, const fastd_handshake *handshake, const fastd_method *method); + 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 (*handle_recv)(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer); void (*send)(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer); @@ -131,6 +131,17 @@ struct _fastd_log_fd { int fd; }; +struct _fastd_bind_address { + fastd_bind_address *next; + fastd_peer_address addr; + char *bindtodev; +}; + +struct _fastd_socket { + int fd; + const fastd_bind_address *addr; +}; + struct _fastd_config { int log_stderr_level; int log_syslog_level; @@ -149,8 +160,10 @@ struct _fastd_config { char *ifname; - struct sockaddr_in bind_addr_in; - struct sockaddr_in6 bind_addr_in6; + fastd_bind_address *bind_addrs; + + fastd_bind_address *bind_addr_default_v4; + fastd_bind_address *bind_addr_default_v6; uint16_t mtu; fastd_mode mode; @@ -219,8 +232,12 @@ struct _fastd_context { int resolvewfd; int tunfd; - int sockfd; - int sock6fd; + + unsigned n_socks; + fastd_socket *socks; + + fastd_socket *sock_default_v4; + fastd_socket *sock_default_v6; #ifdef USE_CRYPTO_AES128CTR fastd_crypto_aes128ctr_context *crypto_aes128ctr; @@ -244,8 +261,8 @@ struct _fastd_string_stack { }; -void fastd_send(fastd_context *ctx, const fastd_peer_address *address, fastd_buffer buffer); -void fastd_send_handshake(fastd_context *ctx, const fastd_peer_address *address, fastd_buffer buffer); +void fastd_send(fastd_context *ctx, const fastd_socket *sock, const fastd_peer_address *address, fastd_buffer buffer); +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); void fastd_resolve_peer(fastd_context *ctx, fastd_peer *peer); diff --git a/src/handshake.c b/src/handshake.c index f2bdb4c..e823a0e 100644 --- a/src/handshake.c +++ b/src/handshake.c @@ -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_peer_address *address, const fastd_peer_config *peer_conf, fastd_buffer buffer) { +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) { if (buffer.len < sizeof(fastd_packet)) { pr_warn(ctx, "received a short handshake from %I", address); goto end_free; @@ -304,10 +304,10 @@ void fastd_handshake_handle(fastd_context *ctx, const fastd_peer_address *addres fastd_handshake_add_uint8(ctx, &reply_buffer, RECORD_REPLY_CODE, reply_code); fastd_handshake_add_uint8(ctx, &reply_buffer, RECORD_ERROR_DETAIL, error_detail); - fastd_send_handshake(ctx, address, reply_buffer); + fastd_send_handshake(ctx, sock, address, reply_buffer); } else { - ctx->conf->protocol->handshake_handle(ctx, address, peer_conf, &handshake, method); + ctx->conf->protocol->handshake_handle(ctx, sock, address, peer_conf, &handshake, method); } } else { @@ -334,7 +334,7 @@ void fastd_handshake_handle(fastd_context *ctx, const fastd_peer_address *addres goto end_free; } - ctx->conf->protocol->handshake_handle(ctx, address, peer_conf, &handshake, method); + ctx->conf->protocol->handshake_handle(ctx, sock, address, peer_conf, &handshake, method); } else { const char *error_field_str; diff --git a/src/handshake.h b/src/handshake.h index 0db4e2f..7744665 100644 --- a/src/handshake.h +++ b/src/handshake.h @@ -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_peer_address *address, const fastd_peer_config *peer_conf, fastd_buffer buffer); +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); static inline void fastd_handshake_add(fastd_context *ctx, fastd_buffer *buffer, fastd_handshake_record_type type, size_t len, const void *data) { diff --git a/src/peer.c b/src/peer.c index 54db531..e29e350 100644 --- a/src/peer.c +++ b/src/peer.c @@ -176,6 +176,19 @@ 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}; @@ -280,7 +293,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_peer_address *addr) { +bool fastd_peer_claim_address(fastd_context *ctx, fastd_peer *new_peer, const 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) { @@ -304,6 +317,9 @@ bool fastd_peer_claim_address(fastd_context *ctx, fastd_peer *new_peer, const fa } new_peer->address = *addr; + if (sock) + new_peer->sock = sock; + return true; } diff --git a/src/peer.h b/src/peer.h index b326ad1..37b5ba2 100644 --- a/src/peer.h +++ b/src/peer.h @@ -35,6 +35,7 @@ struct _fastd_peer { const fastd_peer_config *config; + const fastd_socket *sock; fastd_peer_address address; bool established; @@ -87,7 +88,7 @@ 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_peer_address *addr); +bool fastd_peer_claim_address(fastd_context *ctx, fastd_peer *peer, const fastd_socket *sock, const fastd_peer_address *addr); 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); diff --git a/src/protocol_ec25519_fhmqvc.c b/src/protocol_ec25519_fhmqvc.c index 02920f4..8c96c01 100644 --- a/src/protocol_ec25519_fhmqvc.c +++ b/src/protocol_ec25519_fhmqvc.c @@ -228,7 +228,7 @@ static void maintenance(fastd_context *ctx) { } } -static void protocol_handshake_init(fastd_context *ctx, const fastd_peer_address *address, const fastd_peer_config *peer_conf) { +static void protocol_handshake_init(fastd_context *ctx, const fastd_socket *sock, const fastd_peer_address *address, const fastd_peer_config *peer_conf) { maintenance(ctx); fastd_buffer buffer = fastd_handshake_new_init(ctx, 3*(4+PUBLICKEYBYTES) /* sender key, receipient key, handshake key */); @@ -242,10 +242,10 @@ static void protocol_handshake_init(fastd_context *ctx, const fastd_peer_address fastd_handshake_add(ctx, &buffer, RECORD_SENDER_HANDSHAKE_KEY, PUBLICKEYBYTES, ctx->protocol_state->handshake_key.public_key.p); - fastd_send_handshake(ctx, address, buffer); + fastd_send_handshake(ctx, sock, address, buffer); } -static void respond_handshake(fastd_context *ctx, const fastd_peer_address *address, const fastd_peer *peer, const handshake_key *handshake_key, const ecc_public_key_256 *peer_handshake_key, +static void respond_handshake(fastd_context *ctx, const fastd_socket *sock, const fastd_peer_address *address, const 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, "responding handshake with %P[%I]...", peer, address); @@ -302,10 +302,10 @@ static void respond_handshake(fastd_context *ctx, const fastd_peer_address *addr fastd_handshake_add(ctx, &buffer, RECORD_RECEIPIENT_HANDSHAKE_KEY, PUBLICKEYBYTES, peer_handshake_key->p); fastd_handshake_add(ctx, &buffer, RECORD_T, HMACBYTES, hmacbuf); - fastd_send_handshake(ctx, address, buffer); + fastd_send_handshake(ctx, sock, address, buffer); } -static bool establish(fastd_context *ctx, fastd_peer *peer, const fastd_method *method, const fastd_peer_address *address, bool initiator, +static bool establish(fastd_context *ctx, fastd_peer *peer, const fastd_method *method, const 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]; @@ -344,7 +344,7 @@ static bool establish(fastd_context *ctx, fastd_peer *peer, const fastd_method * fastd_peer_seen(ctx, peer); - if (!fastd_peer_claim_address(ctx, peer, address)) { + if (!fastd_peer_claim_address(ctx, peer, sock, address)) { pr_warn(ctx, "can't set address %I which is used by a fixed peer", address); fastd_peer_reset(ctx, peer); return false; @@ -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_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, 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, const fastd_handshake *handshake, const fastd_method *method) { pr_debug(ctx, "finishing handshake with %P[%I]...", peer, address); @@ -418,7 +418,7 @@ static void finish_handshake(fastd_context *ctx, const fastd_peer_address *addre memcpy(hashinput+PUBLICKEYBYTES, handshake_key->public_key.p, PUBLICKEYBYTES); crypto_auth_hmacsha256(hmacbuf, hashinput, 2*PUBLICKEYBYTES, shared_handshake_key); - if (!establish(ctx, peer, method, address, true, &handshake_key->public_key, peer_handshake_key, &ctx->conf->protocol_config->public_key, + if (!establish(ctx, peer, method, sock, address, true, &handshake_key->public_key, peer_handshake_key, &ctx->conf->protocol_config->public_key, &peer->config->protocol_config->public_key, &sigma, handshake_key->serial)) return; @@ -430,11 +430,10 @@ static void finish_handshake(fastd_context *ctx, const fastd_peer_address *addre fastd_handshake_add(ctx, &buffer, RECORD_RECEIPIENT_HANDSHAKE_KEY, PUBLICKEYBYTES, peer_handshake_key->p); fastd_handshake_add(ctx, &buffer, RECORD_T, HMACBYTES, hmacbuf); - fastd_send_handshake(ctx, address, buffer); - + fastd_send_handshake(ctx, sock, address, buffer); } -static void handle_finish_handshake(fastd_context *ctx, 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, 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, const fastd_handshake *handshake, const fastd_method *method) { pr_debug(ctx, "handling handshake finish with %P[%I]...", peer, address); @@ -485,11 +484,11 @@ static void handle_finish_handshake(fastd_context *ctx, const fastd_peer_address return; } - establish(ctx, peer, method, address, false, peer_handshake_key, &handshake_key->public_key, &peer->config->protocol_config->public_key, + establish(ctx, peer, method, sock, address, false, peer_handshake_key, &handshake_key->public_key, &peer->config->protocol_config->public_key, &ctx->conf->protocol_config->public_key, &sigma, handshake_key->serial); } -static const fastd_peer_config* match_sender_key(fastd_context *ctx, const fastd_peer_address *address, const fastd_peer_config *peer_conf, const unsigned char key[32]) { +static const fastd_peer_config* match_sender_key(fastd_context *ctx, const fastd_socket *sock, const fastd_peer_address *address, const fastd_peer_config *peer_conf, const unsigned char key[32]) { if (peer_conf) { if (memcmp(peer_conf->protocol_config->public_key.p, key, PUBLICKEYBYTES) == 0) return peer_conf; @@ -523,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_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, const 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; @@ -534,7 +533,7 @@ static void protocol_handshake_handle(fastd_context *ctx, const fastd_peer_addre return; } - peer_conf = match_sender_key(ctx, address, peer_conf, handshake->records[RECORD_SENDER_KEY].data); + peer_conf = match_sender_key(ctx, sock, address, peer_conf, handshake->records[RECORD_SENDER_KEY].data); if (!peer_conf) { pr_debug(ctx, "ignoring handshake from %I (unknown key or unresolved host)", address); return; @@ -589,7 +588,7 @@ static void protocol_handshake_handle(fastd_context *ctx, const fastd_peer_addre peer->last_handshake_response = ctx->now; peer->last_handshake_response_address = *address; - respond_handshake(ctx, address, peer, &ctx->protocol_state->handshake_key, handshake->records[RECORD_SENDER_HANDSHAKE_KEY].data, handshake, method); + respond_handshake(ctx, sock, address, peer, &ctx->protocol_state->handshake_key, handshake->records[RECORD_SENDER_HANDSHAKE_KEY].data, handshake, method); break; case 2: @@ -610,7 +609,7 @@ static void protocol_handshake_handle(fastd_context *ctx, const fastd_peer_addre pr_verbose(ctx, "received handshake response from %P[%I] using fastd %s", peer, address, peer_version_name); free(peer_version_name); - finish_handshake(ctx, address, peer, handshake_key, handshake->records[RECORD_SENDER_HANDSHAKE_KEY].data, handshake, method); + finish_handshake(ctx, sock, address, peer, handshake_key, handshake->records[RECORD_SENDER_HANDSHAKE_KEY].data, handshake, method); break; case 3: @@ -627,7 +626,7 @@ static void protocol_handshake_handle(fastd_context *ctx, const fastd_peer_addre pr_debug(ctx, "received handshake finish from %P[%I]", peer, address); - handle_finish_handshake(ctx, address, peer, handshake_key, handshake->records[RECORD_SENDER_HANDSHAKE_KEY].data, handshake, method); + handle_finish_handshake(ctx, sock, address, peer, handshake_key, handshake->records[RECORD_SENDER_HANDSHAKE_KEY].data, handshake, method); break; default: @@ -702,7 +701,7 @@ static void session_send(fastd_context *ctx, fastd_peer *peer, fastd_buffer buff return; } - fastd_send(ctx, &peer->address, send_buffer); + fastd_send(ctx, peer->sock, &peer->address, send_buffer); fastd_task_delete_peer_keepalives(ctx, peer); fastd_task_schedule_keepalive(ctx, peer, ctx->conf->keepalive_interval*1000); diff --git a/src/types.h b/src/types.h index f079d3c..13236b6 100644 --- a/src/types.h +++ b/src/types.h @@ -44,6 +44,8 @@ typedef enum _fastd_mode { typedef struct _fastd_buffer fastd_buffer; typedef union _fastd_peer_address fastd_peer_address; +typedef struct _fastd_bind_address fastd_bind_address; +typedef struct _fastd_socket fastd_socket; typedef struct _fastd_peer_config fastd_peer_config; typedef struct _fastd_eth_addr fastd_eth_addr; typedef struct _fastd_peer fastd_peer; -- cgit v1.2.3