From ffaa890e99e2176ff3d2dec0ab5a8136e1e946ff Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Mon, 21 Sep 2015 13:54:13 +0200 Subject: Initial work to make irssi respect the resolved ip order Ip's aren't selected using random() anymore, also select the ip version by using getaddrinfo and some proper hints. --- src/core/chat-commands.c | 6 +-- src/core/chatnet-rec.h | 2 +- src/core/net-nonblock.c | 38 +++++------------ src/core/net-nonblock.h | 4 +- src/core/network.c | 98 +++++++------------------------------------ src/core/network.h | 2 +- src/core/server-connect-rec.h | 2 +- src/core/server-setup-rec.h | 2 +- src/core/servers-reconnect.c | 10 ++--- src/core/servers-setup.c | 67 +++++++++-------------------- src/core/servers-setup.h | 2 +- src/core/servers.c | 66 +++++++++-------------------- src/core/servers.h | 3 +- 13 files changed, 78 insertions(+), 224 deletions(-) (limited to 'src/core') diff --git a/src/core/chat-commands.c b/src/core/chat-commands.c index 8e881679..9c28a1fc 100644 --- a/src/core/chat-commands.c +++ b/src/core/chat-commands.c @@ -128,10 +128,10 @@ static SERVER_CONNECT_REC *get_server_connect(const char *data, int *plus_addr, host = g_hash_table_lookup(optlist, "host"); if (host != NULL && *host != '\0') { - IPADDR ip4, ip6; + IPADDR ip; - if (net_gethostbyname(host, &ip4, &ip6) == 0) - server_connect_own_ip_save(conn, &ip4, &ip6); + if (net_gethostbyname(host, &ip) == 0) + server_connect_own_ip_save(conn, &ip); } cmd_params_free(free_arg); diff --git a/src/core/chatnet-rec.h b/src/core/chatnet-rec.h index e3ed8aa0..3044643a 100644 --- a/src/core/chatnet-rec.h +++ b/src/core/chatnet-rec.h @@ -9,4 +9,4 @@ char *realname; char *own_host; /* address to use when connecting this server */ char *autosendcmd; /* command to send after connecting to this ircnet */ -IPADDR *own_ip4, *own_ip6; /* resolved own_address if not NULL */ +IPADDR *own_ip; /* resolved own_address if not NULL */ diff --git a/src/core/net-nonblock.c b/src/core/net-nonblock.c index e637e673..bc8c4b96 100644 --- a/src/core/net-nonblock.c +++ b/src/core/net-nonblock.c @@ -103,15 +103,12 @@ int net_gethostbyname_nonblock(const char *addr, GIOChannel *pipe, srand(time(NULL)); memset(&rec, 0, sizeof(rec)); - rec.error = net_gethostbyname(addr, &rec.ip4, &rec.ip6); + rec.error = net_gethostbyname(addr, &rec.ip); if (rec.error == 0) { errorstr = NULL; if (reverse_lookup) { /* reverse lookup the IP, ignore any error */ - if (rec.ip4.family != 0) - net_gethostbyaddr(&rec.ip4, &rec.host4); - if (rec.ip6.family != 0) - net_gethostbyaddr(&rec.ip6, &rec.host6); + net_gethostbyaddr(&rec.ip, &rec.host); } } else { errorstr = net_gethosterror(rec.error); @@ -122,18 +119,11 @@ int net_gethostbyname_nonblock(const char *addr, GIOChannel *pipe, if (rec.errlen != 0) g_io_channel_write_block(pipe, (void *) errorstr, rec.errlen); else { - if (rec.host4) { - len = strlen(rec.host4) + 1; + if (rec.host) { + len = strlen(rec.host) + 1; g_io_channel_write_block(pipe, (void *) &len, sizeof(int)); - g_io_channel_write_block(pipe, (void *) rec.host4, - len); - } - if (rec.host6) { - len = strlen(rec.host6) + 1; - g_io_channel_write_block(pipe, (void *) &len, - sizeof(int)); - g_io_channel_write_block(pipe, (void *) rec.host6, + g_io_channel_write_block(pipe, (void *) rec.host, len); } } @@ -154,8 +144,7 @@ int net_gethostbyname_return(GIOChannel *pipe, RESOLVED_IP_REC *rec) rec->error = -1; rec->errorstr = NULL; - rec->host4 = NULL; - rec->host6 = NULL; + rec->host = NULL; #ifndef WIN32 fcntl(g_io_channel_unix_get_fd(pipe), F_SETFL, O_NONBLOCK); @@ -174,15 +163,10 @@ int net_gethostbyname_return(GIOChannel *pipe, RESOLVED_IP_REC *rec) rec->errorstr = g_malloc0(rec->errlen+1); g_io_channel_read_block(pipe, rec->errorstr, rec->errlen); } else { - if (rec->host4) { - g_io_channel_read_block(pipe, &len, sizeof(int)); - rec->host4 = g_malloc0(len); - g_io_channel_read_block(pipe, rec->host4, len); - } - if (rec->host6) { + if (rec->host) { g_io_channel_read_block(pipe, &len, sizeof(int)); - rec->host6 = g_malloc0(len); - g_io_channel_read_block(pipe, rec->host6, len); + rec->host = g_malloc0(len); + g_io_channel_read_block(pipe, rec->host, len); } } @@ -227,7 +211,6 @@ static void simple_readpipe(SIMPLE_THREAD_REC *rec, GIOChannel *pipe) { RESOLVED_IP_REC iprec; GIOChannel *handle; - IPADDR *ip; g_return_if_fail(rec != NULL); @@ -241,9 +224,8 @@ static void simple_readpipe(SIMPLE_THREAD_REC *rec, GIOChannel *pipe) g_io_channel_shutdown(rec->pipes[1], TRUE, NULL); g_io_channel_unref(rec->pipes[1]); - ip = iprec.ip4.family != 0 ? &iprec.ip4 : &iprec.ip6; handle = iprec.error == -1 ? NULL : - net_connect_ip(ip, rec->port, rec->my_ip); + net_connect_ip(&iprec.ip, rec->port, rec->my_ip); g_free_not_null(rec->my_ip); diff --git a/src/core/net-nonblock.h b/src/core/net-nonblock.h index af5968c8..581536b3 100644 --- a/src/core/net-nonblock.h +++ b/src/core/net-nonblock.h @@ -4,12 +4,12 @@ #include "network.h" typedef struct { - IPADDR ip4, ip6; /* resolved ip addresses */ + IPADDR ip; /* resolved ip address */ int error; /* error, 0 = no error, -1 = error: */ int errlen; /* error text length */ char *errorstr; /* error string - dynamically allocated, you'll need to free() it yourself unless it's NULL */ - char *host4, *host6; /* dito */ + char *host; /* dito */ } RESOLVED_IP_REC; typedef struct { diff --git a/src/core/network.c b/src/core/network.c index bfaa47fb..303483c6 100644 --- a/src/core/network.c +++ b/src/core/network.c @@ -137,35 +137,14 @@ static int sin_get_port(union sockaddr_union *so) /* Connect to socket */ GIOChannel *net_connect(const char *addr, int port, IPADDR *my_ip) { - IPADDR ip4, ip6, *ip; + IPADDR ip; g_return_val_if_fail(addr != NULL, NULL); - if (net_gethostbyname(addr, &ip4, &ip6) == -1) + if (net_gethostbyname(addr, &ip) == -1) return NULL; - if (my_ip == NULL) { - /* prefer IPv4 addresses */ - ip = ip4.family != 0 ? &ip4 : &ip6; - } else if (IPADDR_IS_V6(my_ip)) { - /* my_ip is IPv6 address, use it if possible */ - if (ip6.family != 0) - ip = &ip6; - else { - my_ip = NULL; - ip = &ip4; - } - } else { - /* my_ip is IPv4 address, use it if possible */ - if (ip4.family != 0) - ip = &ip4; - else { - my_ip = NULL; - ip = &ip6; - } - } - - return net_connect_ip(ip, port, my_ip); + return net_connect_ip(&ip, port, my_ip); } /* Connect to socket with ip address */ @@ -413,82 +392,35 @@ int net_getsockname(GIOChannel *handle, IPADDR *addr, int *port) /* Get IP addresses for host, both IPv4 and IPv6 if possible. If ip->family is 0, the address wasn't found. Returns 0 = ok, others = error code for net_gethosterror() */ -int net_gethostbyname(const char *addr, IPADDR *ip4, IPADDR *ip6) +int net_gethostbyname(const char *addr, IPADDR *ip) { -#ifdef HAVE_IPV6 union sockaddr_union *so; - struct addrinfo hints, *ai, *ailist; - int ret, count_v4, count_v6, use_v4, use_v6; -#else - struct hostent *hp; - int count; -#endif + struct addrinfo hints, *ailist; + int ret; g_return_val_if_fail(addr != NULL, -1); - memset(ip4, 0, sizeof(IPADDR)); - memset(ip6, 0, sizeof(IPADDR)); + memset(ip, 0, sizeof(IPADDR)); -#ifdef HAVE_IPV6 memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_socktype = SOCK_STREAM; +#ifdef HAVE_IPV6 + hints.ai_family = AF_UNSPEC; +#else + hints.ai_family = AF_INET; +#endif + hints.ai_flags = (AI_V4MAPPED | AI_ADDRCONFIG); /* save error to host_error for later use */ ret = getaddrinfo(addr, NULL, &hints, &ailist); if (ret != 0) return ret; - /* count IPs */ - count_v4 = count_v6 = 0; - for (ai = ailist; ai != NULL; ai = ai->ai_next) { - if (ai->ai_family == AF_INET) - count_v4++; - else if (ai->ai_family == AF_INET6) - count_v6++; - } - - if (count_v4 == 0 && count_v6 == 0) - return HOST_NOT_FOUND; /* shouldn't happen? */ - - /* if there are multiple addresses, return random one */ - use_v4 = count_v4 <= 1 ? 0 : rand() % count_v4; - use_v6 = count_v6 <= 1 ? 0 : rand() % count_v6; - - count_v4 = count_v6 = 0; - for (ai = ailist; ai != NULL; ai = ai->ai_next) { - so = (union sockaddr_union *) ai->ai_addr; - - if (ai->ai_family == AF_INET) { - if (use_v4 == count_v4) - sin_get_ip(so, ip4); - count_v4++; - } else if (ai->ai_family == AF_INET6) { - if (use_v6 == count_v6) - sin_get_ip(so, ip6); - count_v6++; - } - } + so = (const union sockaddr_union *)ailist->ai_addr; + sin_get_ip(so, ip); freeaddrinfo(ailist); - return 0; -#else - hp = gethostbyname(addr); - if (hp == NULL) - return h_errno; - - /* count IPs */ - count = 0; - while (hp->h_addr_list[count] != NULL) - count++; - - if (count == 0) - return HOST_NOT_FOUND; /* shouldn't happen? */ - - /* if there are multiple addresses, return random one */ - ip4->family = AF_INET; - memcpy(&ip4->ip, hp->h_addr_list[rand() % count], 4); return 0; -#endif } /* Get name for host, *name should be g_free()'d unless it's NULL. diff --git a/src/core/network.h b/src/core/network.h index fa7e9675..ea8b3055 100644 --- a/src/core/network.h +++ b/src/core/network.h @@ -71,7 +71,7 @@ int net_transmit(GIOChannel *handle, const char *data, int len); /* Get IP addresses for host, both IPv4 and IPv6 if possible. If ip->family is 0, the address wasn't found. Returns 0 = ok, others = error code for net_gethosterror() */ -int net_gethostbyname(const char *addr, IPADDR *ip4, IPADDR *ip6); +int net_gethostbyname(const char *addr, IPADDR *ip); /* Get name for host, *name should be g_free()'d unless it's NULL. Return values are the same as with net_gethostbyname() */ int net_gethostbyaddr(IPADDR *ip, char **name); diff --git a/src/core/server-connect-rec.h b/src/core/server-connect-rec.h index 80c5761b..3f24e7d8 100644 --- a/src/core/server-connect-rec.h +++ b/src/core/server-connect-rec.h @@ -16,7 +16,7 @@ char *address; int port; char *chatnet; -IPADDR *own_ip4, *own_ip6; +IPADDR *own_ip; char *password; char *nick; diff --git a/src/core/server-setup-rec.h b/src/core/server-setup-rec.h index 2c9614c7..fbf49b2c 100644 --- a/src/core/server-setup-rec.h +++ b/src/core/server-setup-rec.h @@ -19,7 +19,7 @@ char *ssl_capath; char *ssl_ciphers; char *own_host; /* address to use when connecting this server */ -IPADDR *own_ip4, *own_ip6; /* resolved own_address if not NULL */ +IPADDR *own_ip; /* resolved own_address if not NULL */ time_t last_connect; /* to avoid reconnecting too fast.. */ diff --git a/src/core/servers-reconnect.c b/src/core/servers-reconnect.c index ae97ecd2..3ba18ad0 100644 --- a/src/core/servers-reconnect.c +++ b/src/core/servers-reconnect.c @@ -177,13 +177,9 @@ server_connect_copy_skeleton(SERVER_CONNECT_REC *src, int connect_info) dest->username = g_strdup(src->username); dest->realname = g_strdup(src->realname); - if (src->own_ip4 != NULL) { - dest->own_ip4 = g_new(IPADDR, 1); - memcpy(dest->own_ip4, src->own_ip4, sizeof(IPADDR)); - } - if (src->own_ip6 != NULL) { - dest->own_ip6 = g_new(IPADDR, 1); - memcpy(dest->own_ip6, src->own_ip6, sizeof(IPADDR)); + if (src->own_ip != NULL) { + dest->own_ip = g_new(IPADDR, 1); + memcpy(dest->own_ip, src->own_ip, sizeof(IPADDR)); } dest->channels = g_strdup(src->channels); diff --git a/src/core/servers-setup.c b/src/core/servers-setup.c index 90a447d4..e8506f0f 100644 --- a/src/core/servers-setup.c +++ b/src/core/servers-setup.c @@ -33,32 +33,22 @@ GSList *setupservers; static char *old_source_host; int source_host_ok; /* Use source_host_ip .. */ -IPADDR *source_host_ip4, *source_host_ip6; /* Resolved address */ +IPADDR source_host_ip; /* Resolved address */ -static void save_ips(IPADDR *ip4, IPADDR *ip6, - IPADDR **save_ip4, IPADDR **save_ip6) +static void save_ips(IPADDR *ip, IPADDR **save_ip) { - if (ip4->family == 0) - g_free_and_null(*save_ip4); + if (ip->family == 0) + g_free_and_null(*save_ip); else { - if (*save_ip4 == NULL) - *save_ip4 = g_new(IPADDR, 1); - memcpy(*save_ip4, ip4, sizeof(IPADDR)); - } - - if (ip6->family == 0) - g_free_and_null(*save_ip6); - else { - if (*save_ip6 == NULL) - *save_ip6 = g_new(IPADDR, 1); - memcpy(*save_ip6, ip6, sizeof(IPADDR)); + if (*save_ip == NULL) + *save_ip = g_new(IPADDR, 1); + memcpy(*save_ip, ip, sizeof(IPADDR)); } } static void get_source_host_ip(void) { const char *hostname; - IPADDR ip4, ip6; if (source_host_ok) return; @@ -66,28 +56,21 @@ static void get_source_host_ip(void) /* FIXME: This will block! */ hostname = settings_get_str("hostname"); source_host_ok = *hostname != '\0' && - net_gethostbyname(hostname, &ip4, &ip6) == 0; - - if (source_host_ok) - save_ips(&ip4, &ip6, &source_host_ip4, &source_host_ip6); - else { - g_free_and_null(source_host_ip4); - g_free_and_null(source_host_ip6); - } + net_gethostbyname(hostname, &source_host_ip) == 0; } static void conn_set_ip(SERVER_CONNECT_REC *conn, const char *own_host, - IPADDR **own_ip4, IPADDR **own_ip6) + IPADDR **own_ip) { - IPADDR ip4, ip6; + IPADDR ip; - if (*own_ip4 == NULL && *own_ip6 == NULL) { + if (*own_ip == NULL) { /* resolve the IP */ - if (net_gethostbyname(own_host, &ip4, &ip6) == 0) - save_ips(&ip4, &ip6, own_ip4, own_ip6); + if (net_gethostbyname(own_host, &ip) == 0) + save_ips(&ip, own_ip); } - server_connect_own_ip_save(conn, *own_ip4, *own_ip6); + server_connect_own_ip_save(conn, *own_ip); } /* Fill information to connection from server setup record */ @@ -98,8 +81,7 @@ void server_setup_fill_reconn(SERVER_CONNECT_REC *conn, g_return_if_fail(IS_SERVER_SETUP(sserver)); if (sserver->own_host != NULL) { - conn_set_ip(conn, sserver->own_host, - &sserver->own_ip4, &sserver->own_ip6); + conn_set_ip(conn, sserver->own_host, &sserver->own_ip); } if (sserver->chatnet != NULL && conn->chatnet == NULL) @@ -139,13 +121,9 @@ static void server_setup_fill(SERVER_CONNECT_REC *conn, } /* source IP */ - if (source_host_ip4 != NULL) { - conn->own_ip4 = g_new(IPADDR, 1); - memcpy(conn->own_ip4, source_host_ip4, sizeof(IPADDR)); - } - if (source_host_ip6 != NULL) { - conn->own_ip6 = g_new(IPADDR, 1); - memcpy(conn->own_ip6, source_host_ip6, sizeof(IPADDR)); + if (source_host_ok) { + conn->own_ip = g_new(IPADDR, 1); + memcpy(conn->own_ip, &source_host_ip, sizeof(IPADDR)); } signal_emit("server setup fill connect", 1, conn); @@ -206,8 +184,7 @@ static void server_setup_fill_chatnet(SERVER_CONNECT_REC *conn, conn->realname = g_strdup(chatnet->realname);; } if (chatnet->own_host != NULL) { - conn_set_ip(conn, chatnet->own_host, - &chatnet->own_ip4, &chatnet->own_ip6); + conn_set_ip(conn, chatnet->own_host, &chatnet->own_ip); } signal_emit("server setup fill chatnet", 2, conn, chatnet); @@ -481,8 +458,7 @@ static void server_setup_destroy(SERVER_SETUP_REC *rec) signal_emit("server setup destroyed", 1, rec); g_free_not_null(rec->own_host); - g_free_not_null(rec->own_ip4); - g_free_not_null(rec->own_ip6); + g_free_not_null(rec->own_ip); g_free_not_null(rec->chatnet); g_free_not_null(rec->password); g_free_not_null(rec->ssl_cert); @@ -556,7 +532,6 @@ void servers_setup_init(void) settings_add_str("proxy", "proxy_password", ""); setupservers = NULL; - source_host_ip4 = source_host_ip6 = NULL; old_source_host = NULL; read_settings(); @@ -567,8 +542,6 @@ void servers_setup_init(void) void servers_setup_deinit(void) { - g_free_not_null(source_host_ip4); - g_free_not_null(source_host_ip6); g_free_not_null(old_source_host); while (setupservers != NULL) diff --git a/src/core/servers-setup.h b/src/core/servers-setup.h index f7601a68..c4878094 100644 --- a/src/core/servers-setup.h +++ b/src/core/servers-setup.h @@ -16,7 +16,7 @@ struct _SERVER_SETUP_REC { extern GSList *setupservers; -extern IPADDR *source_host_ip4, *source_host_ip6; /* Resolved address */ +extern IPADDR source_host_ip; /* Resolved address */ extern int source_host_ok; /* Use source_host_ip .. */ /* Fill reconnection specific information to connection diff --git a/src/core/servers.c b/src/core/servers.c index 3342304e..e18f8d9c 100644 --- a/src/core/servers.c +++ b/src/core/servers.c @@ -218,7 +218,7 @@ static void server_real_connect(SERVER_REC *server, IPADDR *ip, return; if (ip != NULL) { - own_ip = IPADDR_IS_V6(ip) ? server->connrec->own_ip6 : server->connrec->own_ip4; + own_ip = server->connrec->own_ip; port = server->connrec->proxy != NULL ? server->connrec->proxy_port : server->connrec->port; handle = server->connrec->use_ssl ? @@ -280,30 +280,15 @@ static void server_connect_callback_readpipe(SERVER_REC *server) server->connect_pipe[0] = NULL; server->connect_pipe[1] = NULL; - /* figure out if we should use IPv4 or v6 address */ - if (iprec.error != 0) { - /* error */ - ip = NULL; - } else if (server->connrec->family == AF_INET) { - /* force IPv4 connection */ - ip = iprec.ip4.family == 0 ? NULL : &iprec.ip4; - servername = iprec.host4; - } else if (server->connrec->family == AF_INET6) { - /* force IPv6 connection */ - ip = iprec.ip6.family == 0 ? NULL : &iprec.ip6; - servername = iprec.host6; - } else { - /* pick the one that was found, or if both do it like - /SET resolve_prefer_ipv6 says. */ - if (iprec.ip4.family == 0 || - (iprec.ip6.family != 0 && - settings_get_bool("resolve_prefer_ipv6"))) { - ip = &iprec.ip6; - servername = iprec.host6; - } else { - ip = &iprec.ip4; - servername = iprec.host4; - } + ip = NULL; + + if (iprec.error == 0) { + // FIXME : REMOVE THIS BEFORE MERGE + if (server->connrec->family) + g_assert(server->connrec->family == iprec.ip.family); + + ip = &iprec.ip; + servername = iprec.host; } if (ip != NULL) { @@ -337,8 +322,7 @@ static void server_connect_callback_readpipe(SERVER_REC *server) } g_free(iprec.errorstr); - g_free(iprec.host4); - g_free(iprec.host6); + g_free(iprec.host); } SERVER_REC *server_connect(SERVER_CONNECT_REC *conn) @@ -623,8 +607,7 @@ void server_connect_unref(SERVER_CONNECT_REC *conn) g_free_not_null(conn->address); g_free_not_null(conn->chatnet); - g_free_not_null(conn->own_ip4); - g_free_not_null(conn->own_ip6); + g_free_not_null(conn->own_ip); g_free_not_null(conn->password); g_free_not_null(conn->nick); @@ -654,26 +637,15 @@ void server_change_nick(SERVER_REC *server, const char *nick) } /* Update own IPv4 and IPv6 records */ -void server_connect_own_ip_save(SERVER_CONNECT_REC *conn, - IPADDR *ip4, IPADDR *ip6) +void server_connect_own_ip_save(SERVER_CONNECT_REC *conn, IPADDR *ip) { - if (ip4 == NULL || ip4->family == 0) - g_free_and_null(conn->own_ip4); - if (ip6 == NULL || ip6->family == 0) - g_free_and_null(conn->own_ip6); - - if (ip4 != NULL && ip4->family != 0) { - /* IPv4 address was found */ - if (conn->own_ip4 == NULL) - conn->own_ip4 = g_new0(IPADDR, 1); - memcpy(conn->own_ip4, ip4, sizeof(IPADDR)); - } + if (ip == NULL || ip->family == 0) + g_free_and_null(conn->own_ip); - if (ip6 != NULL && ip6->family != 0) { - /* IPv6 address was found */ - if (conn->own_ip6 == NULL) - conn->own_ip6 = g_new0(IPADDR, 1); - memcpy(conn->own_ip6, ip6, sizeof(IPADDR)); + if (ip != NULL && ip->family != 0) { + if (conn->own_ip == NULL) + conn->own_ip = g_new0(IPADDR, 1); + memcpy(conn->own_ip, ip, sizeof(IPADDR)); } } diff --git a/src/core/servers.h b/src/core/servers.h index f39c650b..314faa32 100644 --- a/src/core/servers.h +++ b/src/core/servers.h @@ -67,8 +67,7 @@ void server_connect_failed(SERVER_REC *server, const char *msg); void server_change_nick(SERVER_REC *server, const char *nick); /* Update own IPv4 and IPv6 records */ -void server_connect_own_ip_save(SERVER_CONNECT_REC *conn, - IPADDR *ip4, IPADDR *ip6); +void server_connect_own_ip_save(SERVER_CONNECT_REC *conn, IPADDR *ip); /* `optlist' should contain only one unknown key - the server tag. returns NULL if there was unknown -option */ -- cgit v1.2.3