diff options
author | Toni Uhlig <matzeton@googlemail.com> | 2020-07-21 15:44:41 +0200 |
---|---|---|
committer | Toni Uhlig <matzeton@googlemail.com> | 2020-07-21 15:44:41 +0200 |
commit | b8f28b2f7ba83f25413c0da02ba5248bc0433a63 (patch) | |
tree | a1ffe5693b0c29ff40e1c5e510a25bfd812a96fc | |
parent | 46305df5903270d9b63652a1ce5fae2ee861a0e4 (diff) |
use getaddrinfo() for client/server address resolving
Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
-rw-r--r-- | client.c | 54 | ||||
-rw-r--r-- | common-sodium.c | 17 | ||||
-rw-r--r-- | common-sodium.h | 5 | ||||
-rw-r--r-- | server.c | 63 | ||||
-rw-r--r-- | utils.h | 29 |
5 files changed, 116 insertions, 52 deletions
@@ -228,13 +228,15 @@ __attribute__((noreturn)) static void cleanup_and_exit(struct event_base ** cons int main(int argc, char ** argv) { + struct addrinfo * connect_addresses = NULL; + struct addrinfo * ai; + int gai_errno; + int bev_connected = 0; struct event_base * ev_base = NULL; struct event * ev_sig = NULL; struct bufferevent * bev; - struct sockaddr_in sin; struct longterm_keypair * my_keypair = NULL; struct connection * c = NULL; - char ip_str[INET6_ADDRSTRLEN + 1]; parse_cmdline(&opts, argc, argv); @@ -252,8 +254,14 @@ int main(int argc, char ** argv) return 1; } } - if (opts.port <= 0 || opts.port > 65535) { - LOG(ERROR, "Invalid port: %d", opts.port); + if (opts.host == NULL || opts.port == NULL) { + LOG(ERROR, "Invalid host/port"); + return 2; + } + LOG(NOTICE, "Resolving %s:%s..", opts.host, opts.port); + gai_errno = hostname_to_address(opts.host, opts.port, &connect_addresses); + if (gai_errno != 0) { + LOG(ERROR, "Address/Service translation error for %s:%s: %s", opts.host, opts.port, gai_strerror(gai_errno)); return 2; } @@ -264,11 +272,6 @@ int main(int argc, char ** argv) return 3; } - if (init_sockaddr_inet(&sin, opts.host, opts.port, ip_str) != 0) { - return 4; - } - LOG(NOTICE, "Connecting to %s:%u", ip_str, opts.port); - /* generate client keypair */ my_keypair = generate_keypair_sodium(); if (my_keypair == NULL) { @@ -322,7 +325,38 @@ int main(int argc, char ** argv) } ev_set_io_timeouts(bev); - if (bufferevent_socket_connect(bev, (struct sockaddr *)&sin, sizeof(sin)) != 0) { + for (ai = connect_addresses; ai != NULL; ai = ai->ai_next) { + struct sockaddr * sa = NULL; + socklen_t sl = 0; + + switch (ai->ai_family) { + case AF_INET: + sa = (struct sockaddr *)&((struct sockaddr_in *)ai->ai_addr)->sin_addr; + sl = sizeof(struct sockaddr_in); + break; + case AF_INET6: + sa = (struct sockaddr *)&((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr; + sl = sizeof(struct sockaddr_in6); + break; + default: + LOG(ERROR, "Unknown address family: %d", ai->ai_family); + cleanup_and_exit(&ev_base, &ev_sig, &my_keypair, &c, 14); + } + if (inet_ntop(ai->ai_family, sa, ip_str, sl) == NULL) { + LOG(WARNING, "Invalid IPv4 host"); + continue; + } + + LOG(NOTICE, "Connecting to %s:%s", ip_str, opts.port); + if (bufferevent_socket_connect(bev, ai->ai_addr, ai->ai_addrlen) == 0) { + bev_connected = 1; + break; + } + } + freeaddrinfo(connect_addresses); + connect_addresses = NULL; + + if (bev_connected == 0) { cleanup_and_exit(&ev_base, &ev_sig, &my_keypair, &c, 14); } diff --git a/common-sodium.c b/common-sodium.c index 1f3c88e..202eca6 100644 --- a/common-sodium.c +++ b/common-sodium.c @@ -94,23 +94,6 @@ int generate_session_keypair_sodium(struct connection * const state) return 0; } -int init_sockaddr_inet(struct sockaddr_in * const sin, - const char * const host, - int port, - char ip_str[INET6_ADDRSTRLEN + 1]) -{ - memset(sin, 0, sizeof(*sin)); - sin->sin_family = AF_INET; - sin->sin_port = htons(port); - if (inet_pton(sin->sin_family, host, &sin->sin_addr) <= 0 || - inet_ntop(sin->sin_family, &sin->sin_addr, ip_str, INET6_ADDRSTRLEN) == NULL) { - LOG(ERROR, "Invalid host: %s", host); - return 1; - } - - return 0; -} - int init_crypto_server(struct connection * const state, unsigned char const * const server_rx_header, size_t server_rx_header_size) diff --git a/common-sodium.h b/common-sodium.h index 8f218a0..b4a7d23 100644 --- a/common-sodium.h +++ b/common-sodium.h @@ -18,11 +18,6 @@ __attribute__((warn_unused_result)) struct longterm_keypair * generate_keypair_f __attribute__((warn_unused_result)) int generate_session_keypair_sodium(struct connection * const state); -__attribute__((warn_unused_result)) int init_sockaddr_inet(struct sockaddr_in * const sin, - const char * const host, - int port, - char ip_str[INET6_ADDRSTRLEN + 1]); - __attribute__((warn_unused_result)) int init_crypto_server(struct connection * const state, unsigned char const * const server_rx_header, size_t server_rx_header_size); @@ -285,12 +285,13 @@ __attribute__((noreturn)) static void cleanup_and_exit(struct event_base ** cons int main(int argc, char ** argv) { + struct addrinfo * connect_addresses = NULL; + struct addrinfo * ai; + int gai_errno; struct longterm_keypair * my_keypair = NULL; struct event_base * ev_base = NULL; struct event * ev_sig = NULL; struct evconnlistener * ev_listener = NULL; - struct sockaddr_in sin; - char ip_str[INET6_ADDRSTRLEN + 1]; parse_cmdline(&opts, argc, argv); @@ -305,8 +306,14 @@ int main(int argc, char ** argv) return 1; } } - if (opts.port <= 0 || opts.port > 65535) { - LOG(ERROR, "Invalid port: %d", opts.port); + if (opts.host == NULL || opts.port == NULL) { + LOG(ERROR, "Invalid host/port"); + return 2; + } + LOG(NOTICE, "Resolving %s:%s..", opts.host, opts.port); + gai_errno = hostname_to_address(opts.host, opts.port, &connect_addresses); + if (gai_errno != 0) { + LOG(ERROR, "Address/Service translation error for %s:%s: %s", opts.host, opts.port, gai_strerror(gai_errno)); return 2; } @@ -317,11 +324,6 @@ int main(int argc, char ** argv) return 2; } - if (init_sockaddr_inet(&sin, opts.host, opts.port, ip_str) != 0) { - return 3; - } - LOG(NOTICE, "Listen on %s:%u", ip_str, opts.port); - if (opts.key_string != NULL) { my_keypair = generate_keypair_from_secretkey_hexstr_sodium(opts.key_string, opts.key_length); } else { @@ -351,17 +353,46 @@ int main(int argc, char ** argv) cleanup_and_exit(&ev_base, &ev_listener, &ev_sig, &my_keypair, 7); } - ev_listener = evconnlistener_new_bind(ev_base, - accept_conn_cb, - my_keypair, - LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, - -1, - (struct sockaddr *)&sin, - sizeof(sin)); + for (ai = connect_addresses; ai != NULL; ai = ai->ai_next) { + struct sockaddr * sa = NULL; + socklen_t sl = 0; + + switch (ai->ai_family) { + case AF_INET: + sa = (struct sockaddr *)&((struct sockaddr_in *)ai->ai_addr)->sin_addr; + sl = sizeof(struct sockaddr_in); + break; + case AF_INET6: + sa = (struct sockaddr *)&((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr; + sl = sizeof(struct sockaddr_in6); + break; + default: + LOG(ERROR, "Unknown address family: %d", ai->ai_family); + cleanup_and_exit(&ev_base, &ev_listener, &ev_sig, &my_keypair, 8); + } + if (inet_ntop(ai->ai_family, sa, ip_str, sl) == NULL) { + LOG(WARNING, "Invalid IPv4 host"); + continue; + } + + LOG(NOTICE, "Listening on %s:%s", ip_str, opts.port); + ev_listener = evconnlistener_new_bind(ev_base, + accept_conn_cb, + my_keypair, + LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, + -1, ai->ai_addr, ai->ai_addrlen); + if (ev_listener != NULL) { + break; + } + } + freeaddrinfo(connect_addresses); + connect_addresses = NULL; + if (ev_listener == NULL) { LOG(ERROR, "Couldn't create listener: %s", strerror(errno)); cleanup_and_exit(&ev_base, &ev_listener, &ev_sig, &my_keypair, 8); } + evconnlistener_set_error_cb(ev_listener, accept_error_cb); event_base_dispatch(ev_base); @@ -1,9 +1,12 @@ #ifndef UTILS_H #define UTILS_H 1 +#include <netdb.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/types.h> +#include <sys/socket.h> #include <unistd.h> struct cmd_options { @@ -19,7 +22,7 @@ struct cmd_options { /* server: listen port * client: remote port */ - int port; + char * port; /* server: path to write to, received from client via PDU-type DATA * client: path to read from, send it via PDU-type DATA */ @@ -46,7 +49,7 @@ static inline void parse_cmdline(struct cmd_options * const opts, int argc, char opts->host = strdup(optarg); break; case 'p': - opts->port = atoi(optarg); /* meh, strtol is king */ + opts->port = strdup(optarg); break; case 'f': opts->filepath = strdup(optarg); @@ -59,8 +62,8 @@ static inline void parse_cmdline(struct cmd_options * const opts, int argc, char if (opts->host == NULL) { opts->host = strdup("127.0.0.1"); } - if (opts->port == 0) { - opts->port = 5555; + if (opts->port == NULL) { + opts->port = strdup("5555"); } if (opts->key_string != NULL) { opts->key_length = strlen(opts->key_string); @@ -86,4 +89,22 @@ static inline char * prettify_bytes_with_units(char * const out, size_t out_size return out; } +static inline int hostname_to_address(char const * const host, char const * const port, + struct addrinfo ** const result) +{ + int s; + struct addrinfo hints; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + + s = getaddrinfo(host, port, &hints, result); + if (s != 0) { + return s; + } + + return 0; +} #endif |