aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorToni Uhlig <matzeton@googlemail.com>2020-07-21 15:44:41 +0200
committerToni Uhlig <matzeton@googlemail.com>2020-07-21 15:44:41 +0200
commitb8f28b2f7ba83f25413c0da02ba5248bc0433a63 (patch)
treea1ffe5693b0c29ff40e1c5e510a25bfd812a96fc
parent46305df5903270d9b63652a1ce5fae2ee861a0e4 (diff)
use getaddrinfo() for client/server address resolving
Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
-rw-r--r--client.c54
-rw-r--r--common-sodium.c17
-rw-r--r--common-sodium.h5
-rw-r--r--server.c63
-rw-r--r--utils.h29
5 files changed, 116 insertions, 52 deletions
diff --git a/client.c b/client.c
index c8bb974..674afb9 100644
--- a/client.c
+++ b/client.c
@@ -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);
diff --git a/server.c b/server.c
index 7247371..5db4392 100644
--- a/server.c
+++ b/server.c
@@ -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);
diff --git a/utils.h b/utils.h
index b9fff6e..0774007 100644
--- a/utils.h
+++ b/utils.h
@@ -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