From c2a3ae0706e877ee452de78b36c8aa6f776b9767 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Mon, 21 Sep 2015 13:54:13 +0200 Subject: [PATCH 1/4] 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 +- src/fe-common/core/fe-server.c | 4 +- src/fe-common/irc/fe-ircnet.c | 4 +- src/irc/dcc/dcc.c | 4 +- src/irc/proxy/listen.c | 9 ++-- 17 files changed, 87 insertions(+), 236 deletions(-) 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) { + if (rec->host) { 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) { - 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 (ip == NULL || ip->family == 0) + g_free_and_null(conn->own_ip); - 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 (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 */ diff --git a/src/fe-common/core/fe-server.c b/src/fe-common/core/fe-server.c index 429e6dac..f8558ad1 100644 --- a/src/fe-common/core/fe-server.c +++ b/src/fe-common/core/fe-server.c @@ -138,7 +138,7 @@ static void cmd_server_add(const char *data) if (*password != '\0') g_free_and_null(rec->password); if (g_hash_table_lookup(optlist, "host")) { g_free_and_null(rec->own_host); - rec->own_ip4 = rec->own_ip6 = NULL; + rec->own_ip = NULL; } } @@ -193,7 +193,7 @@ static void cmd_server_add(const char *data) value = g_hash_table_lookup(optlist, "host"); if (value != NULL && *value != '\0') { rec->own_host = g_strdup(value); - rec->own_ip4 = rec->own_ip6 = NULL; + rec->own_ip = NULL; } signal_emit("server add fill", 2, rec, optlist); diff --git a/src/fe-common/irc/fe-ircnet.c b/src/fe-common/irc/fe-ircnet.c index 6618edd7..4071f367 100644 --- a/src/fe-common/irc/fe-ircnet.c +++ b/src/fe-common/irc/fe-ircnet.c @@ -108,7 +108,7 @@ static void cmd_network_add(const char *data) if (g_hash_table_lookup(optlist, "realname")) g_free_and_null(rec->realname); if (g_hash_table_lookup(optlist, "host")) { g_free_and_null(rec->own_host); - rec->own_ip4 = rec->own_ip6 = NULL; + rec->own_ip = NULL; } if (g_hash_table_lookup(optlist, "usermode")) g_free_and_null(rec->usermode); if (g_hash_table_lookup(optlist, "autosendcmd")) g_free_and_null(rec->autosendcmd); @@ -140,7 +140,7 @@ static void cmd_network_add(const char *data) value = g_hash_table_lookup(optlist, "host"); if (value != NULL && *value != '\0') { rec->own_host = g_strdup(value); - rec->own_ip4 = rec->own_ip6 = NULL; + rec->own_ip = NULL; } value = g_hash_table_lookup(optlist, "usermode"); diff --git a/src/irc/dcc/dcc.c b/src/irc/dcc/dcc.c index 17f6c477..7fef2ae5 100644 --- a/src/irc/dcc/dcc.c +++ b/src/irc/dcc/dcc.c @@ -264,12 +264,12 @@ GIOChannel *dcc_connect_ip(IPADDR *ip, int port) } if (own_ip == NULL) - own_ip = IPADDR_IS_V6(ip) ? source_host_ip6 : source_host_ip4; + own_ip = &source_host_ip; handle = net_connect_ip(ip, port, own_ip); if (handle == NULL && errno == EADDRNOTAVAIL && own_ip != NULL) { /* dcc_own_ip is external address */ - own_ip = IPADDR_IS_V6(ip) ? source_host_ip6 : source_host_ip4; + own_ip = &source_host_ip; handle = net_connect_ip(ip, port, own_ip); } return handle; diff --git a/src/irc/proxy/listen.c b/src/irc/proxy/listen.c index dcc94e6b..16950c79 100644 --- a/src/irc/proxy/listen.c +++ b/src/irc/proxy/listen.c @@ -585,7 +585,7 @@ static LISTEN_REC *find_listen(const char *ircnet, int port) static void add_listen(const char *ircnet, int port) { LISTEN_REC *rec; - IPADDR ip4, ip6, *my_ip; + IPADDR ip, *my_ip; if (port <= 0 || *ircnet == '\0') return; @@ -593,16 +593,13 @@ static void add_listen(const char *ircnet, int port) /* bind to specific host/ip? */ my_ip = NULL; if (*settings_get_str("irssiproxy_bind") != '\0') { - if (net_gethostbyname(settings_get_str("irssiproxy_bind"), - &ip4, &ip6) != 0) { + if (net_gethostbyname(settings_get_str("irssiproxy_bind"), &ip) != 0) { printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Proxy: can not resolve '%s' - aborting", settings_get_str("irssiproxy_bind")); return; } - - my_ip = ip6.family == 0 ? &ip4 : ip4.family == 0 || - settings_get_bool("resolve_prefer_ipv6") ? &ip6 : &ip4; + my_ip = &ip; } rec = g_new0(LISTEN_REC, 1); From 67452b0b4445343cb9ef79ef0b00b1e73c4092a9 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Mon, 21 Sep 2015 14:38:10 +0200 Subject: [PATCH 2/4] Ding dong the switch is dead --- docs/help/in/toggle.in | 2 +- docs/manual.txt | 3 --- src/core/servers.c | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/docs/help/in/toggle.in b/docs/help/in/toggle.in index f87a6462..71f5c8f4 100644 --- a/docs/help/in/toggle.in +++ b/docs/help/in/toggle.in @@ -15,7 +15,7 @@ %9Examples:%9 - /TOGGLE resolve_prefer_ipv6 + /TOGGLE resolve_reverse_lookup /TOGGLE channels_rejoin_unavailable ON %9See also:%9 SET diff --git a/docs/manual.txt b/docs/manual.txt index b2d0de14..12d8031e 100644 --- a/docs/manual.txt +++ b/docs/manual.txt @@ -429,9 +429,6 @@ After connected to server, Irssi can automatically change your user mode. You can set it with /SET usermode , default is +i. - /SET resolve_prefer_ipv6 - If ON, prefer IPv6 for hosts that - have both v4 and v6 addresses. - 5.5 Automatic reconnecting If you get disconnected from server, Irssi will try to reconnect diff --git a/src/core/servers.c b/src/core/servers.c index e18f8d9c..66060a7f 100644 --- a/src/core/servers.c +++ b/src/core/servers.c @@ -710,7 +710,6 @@ static void sig_chat_protocol_deinit(CHAT_PROTOCOL_REC *proto) void servers_init(void) { - settings_add_bool("server", "resolve_prefer_ipv6", FALSE); settings_add_bool("server", "resolve_reverse_lookup", FALSE); lookup_servers = servers = NULL; From 32c33357d3404071ad95681cb8038eab3d80dc2f Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Wed, 23 Sep 2015 15:37:23 +0200 Subject: [PATCH 3/4] Respect the user preference Try to resolve the address using the user-specified ip version and fail gracefully if the network doesn't support it. --- src/core/chat-commands.c | 2 +- src/core/net-nonblock.c | 6 +++--- src/core/net-nonblock.h | 2 +- src/core/network.c | 9 +++++---- src/core/network.h | 2 +- src/core/servers-setup.c | 4 ++-- src/core/servers.c | 15 +++++++++------ src/irc/proxy/listen.c | 2 +- 8 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/core/chat-commands.c b/src/core/chat-commands.c index 9c28a1fc..9f7a0671 100644 --- a/src/core/chat-commands.c +++ b/src/core/chat-commands.c @@ -130,7 +130,7 @@ static SERVER_CONNECT_REC *get_server_connect(const char *data, int *plus_addr, if (host != NULL && *host != '\0') { IPADDR ip; - if (net_gethostbyname(host, &ip) == 0) + if (net_gethostbyname(host, &ip, conn->family) == 0) server_connect_own_ip_save(conn, &ip); } diff --git a/src/core/net-nonblock.c b/src/core/net-nonblock.c index bc8c4b96..50f48e42 100644 --- a/src/core/net-nonblock.c +++ b/src/core/net-nonblock.c @@ -73,7 +73,7 @@ static int g_io_channel_read_block(GIOChannel *channel, void *data, int len) /* nonblocking gethostbyname(), ip (IPADDR) + error (int, 0 = not error) is written to pipe when found PID of the resolver child is returned */ int net_gethostbyname_nonblock(const char *addr, GIOChannel *pipe, - int reverse_lookup) + int family, int reverse_lookup) { RESOLVED_IP_REC rec; const char *errorstr; @@ -103,7 +103,7 @@ int net_gethostbyname_nonblock(const char *addr, GIOChannel *pipe, srand(time(NULL)); memset(&rec, 0, sizeof(rec)); - rec.error = net_gethostbyname(addr, &rec.ip); + rec.error = net_gethostbyname(addr, &rec.ip, family); if (rec.error == 0) { errorstr = NULL; if (reverse_lookup) { @@ -267,7 +267,7 @@ int net_connect_nonblock(const char *server, int port, const IPADDR *my_ip, rec->pipes[1] = g_io_channel_new(fd[1]); /* start nonblocking host name lookup */ - net_gethostbyname_nonblock(server, rec->pipes[1], 0); + net_gethostbyname_nonblock(server, rec->pipes[1], 0, 0); rec->tag = g_input_add(rec->pipes[0], G_INPUT_READ, (GInputFunction) simple_readpipe, rec); diff --git a/src/core/net-nonblock.h b/src/core/net-nonblock.h index 581536b3..96ad06c3 100644 --- a/src/core/net-nonblock.h +++ b/src/core/net-nonblock.h @@ -26,7 +26,7 @@ typedef void (*NET_HOST_CALLBACK) (RESOLVED_NAME_REC *, void *); /* nonblocking gethostbyname(), PID of the resolver child is returned. */ int net_gethostbyname_nonblock(const char *addr, GIOChannel *pipe, - int reverse_lookup); + int family, int reverse_lookup); /* Get host's name, call func when finished */ int net_gethostbyaddr_nonblock(IPADDR *ip, NET_HOST_CALLBACK func, void *data); /* get the resolved IP address. returns -1 if some error occurred with read() */ diff --git a/src/core/network.c b/src/core/network.c index 303483c6..ec7aed6e 100644 --- a/src/core/network.c +++ b/src/core/network.c @@ -141,7 +141,8 @@ GIOChannel *net_connect(const char *addr, int port, IPADDR *my_ip) g_return_val_if_fail(addr != NULL, NULL); - if (net_gethostbyname(addr, &ip) == -1) + // XXX : should we use the my_ip->family instead ? + if (net_gethostbyname(addr, &ip, 0) == -1) return NULL; return net_connect_ip(&ip, port, my_ip); @@ -392,9 +393,9 @@ 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 *ip) +int net_gethostbyname(const char *addr, IPADDR *ip, int family) { - union sockaddr_union *so; + const union sockaddr_union *so; struct addrinfo hints, *ailist; int ret; @@ -405,7 +406,7 @@ int net_gethostbyname(const char *addr, IPADDR *ip) memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_socktype = SOCK_STREAM; #ifdef HAVE_IPV6 - hints.ai_family = AF_UNSPEC; + hints.ai_family = (family == 0) ? AF_UNSPEC : family; #else hints.ai_family = AF_INET; #endif diff --git a/src/core/network.h b/src/core/network.h index ea8b3055..1e1313a3 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 *ip); +int net_gethostbyname(const char *addr, IPADDR *ip, int family); /* 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/servers-setup.c b/src/core/servers-setup.c index e8506f0f..37cd5b8b 100644 --- a/src/core/servers-setup.c +++ b/src/core/servers-setup.c @@ -56,7 +56,7 @@ static void get_source_host_ip(void) /* FIXME: This will block! */ hostname = settings_get_str("hostname"); source_host_ok = *hostname != '\0' && - net_gethostbyname(hostname, &source_host_ip) == 0; + net_gethostbyname(hostname, &source_host_ip, 0) == 0; } static void conn_set_ip(SERVER_CONNECT_REC *conn, const char *own_host, @@ -66,7 +66,7 @@ static void conn_set_ip(SERVER_CONNECT_REC *conn, const char *own_host, if (*own_ip == NULL) { /* resolve the IP */ - if (net_gethostbyname(own_host, &ip) == 0) + if (net_gethostbyname(own_host, &ip, 0) == 0) save_ips(&ip, own_ip); } diff --git a/src/core/servers.c b/src/core/servers.c index 66060a7f..f8efd62f 100644 --- a/src/core/servers.c +++ b/src/core/servers.c @@ -283,12 +283,14 @@ static void server_connect_callback_readpipe(SERVER_REC *server) 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; + /* we've resolved the server address, now check whether the version + * of the one returned by the system matches the one required by the + * user by using -{4,6} or by specifying the "family" parameter for + * the server */ + if (server->connrec->family == 0 || server->connrec->family == iprec.ip.family) { + ip = &iprec.ip; + servername = iprec.host; + } } if (ip != NULL) { @@ -407,6 +409,7 @@ int server_start_connect(SERVER_REC *server) server->connect_pid = net_gethostbyname_nonblock(connect_address, server->connect_pipe[1], + server->connrec->family, settings_get_bool("resolve_reverse_lookup")); server->connect_tag = g_input_add(server->connect_pipe[0], G_INPUT_READ, diff --git a/src/irc/proxy/listen.c b/src/irc/proxy/listen.c index 16950c79..27c7a0f2 100644 --- a/src/irc/proxy/listen.c +++ b/src/irc/proxy/listen.c @@ -593,7 +593,7 @@ static void add_listen(const char *ircnet, int port) /* bind to specific host/ip? */ my_ip = NULL; if (*settings_get_str("irssiproxy_bind") != '\0') { - if (net_gethostbyname(settings_get_str("irssiproxy_bind"), &ip) != 0) { + if (net_gethostbyname(settings_get_str("irssiproxy_bind"), &ip, 0) != 0) { printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Proxy: can not resolve '%s' - aborting", settings_get_str("irssiproxy_bind")); From aeb3cd9dbf565ad964f6b51870e96f5e2871d05d Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Thu, 24 Sep 2015 11:25:09 +0200 Subject: [PATCH 4/4] Pass AF_UNSPEC to net_gethostbyname instead of 0 0 might be a valid family. --- src/core/net-nonblock.c | 2 +- src/core/network.c | 4 ++-- src/core/servers-setup.c | 5 +++-- src/irc/proxy/listen.c | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/core/net-nonblock.c b/src/core/net-nonblock.c index 50f48e42..2f207bdf 100644 --- a/src/core/net-nonblock.c +++ b/src/core/net-nonblock.c @@ -267,7 +267,7 @@ int net_connect_nonblock(const char *server, int port, const IPADDR *my_ip, rec->pipes[1] = g_io_channel_new(fd[1]); /* start nonblocking host name lookup */ - net_gethostbyname_nonblock(server, rec->pipes[1], 0, 0); + net_gethostbyname_nonblock(server, rec->pipes[1], AF_UNSPEC, 0); rec->tag = g_input_add(rec->pipes[0], G_INPUT_READ, (GInputFunction) simple_readpipe, rec); diff --git a/src/core/network.c b/src/core/network.c index ec7aed6e..a94c1ca2 100644 --- a/src/core/network.c +++ b/src/core/network.c @@ -142,7 +142,7 @@ GIOChannel *net_connect(const char *addr, int port, IPADDR *my_ip) g_return_val_if_fail(addr != NULL, NULL); // XXX : should we use the my_ip->family instead ? - if (net_gethostbyname(addr, &ip, 0) == -1) + if (net_gethostbyname(addr, &ip, AF_UNSPEC) == -1) return NULL; return net_connect_ip(&ip, port, my_ip); @@ -406,7 +406,7 @@ int net_gethostbyname(const char *addr, IPADDR *ip, int family) memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_socktype = SOCK_STREAM; #ifdef HAVE_IPV6 - hints.ai_family = (family == 0) ? AF_UNSPEC : family; + hints.ai_family = family; #else hints.ai_family = AF_INET; #endif diff --git a/src/core/servers-setup.c b/src/core/servers-setup.c index 37cd5b8b..f4948030 100644 --- a/src/core/servers-setup.c +++ b/src/core/servers-setup.c @@ -56,7 +56,7 @@ static void get_source_host_ip(void) /* FIXME: This will block! */ hostname = settings_get_str("hostname"); source_host_ok = *hostname != '\0' && - net_gethostbyname(hostname, &source_host_ip, 0) == 0; + net_gethostbyname(hostname, &source_host_ip, AF_UNSPEC) == 0; } static void conn_set_ip(SERVER_CONNECT_REC *conn, const char *own_host, @@ -66,7 +66,7 @@ static void conn_set_ip(SERVER_CONNECT_REC *conn, const char *own_host, if (*own_ip == NULL) { /* resolve the IP */ - if (net_gethostbyname(own_host, &ip, 0) == 0) + if (net_gethostbyname(own_host, &ip, AF_UNSPEC) == 0) save_ips(&ip, own_ip); } @@ -103,6 +103,7 @@ static void server_setup_fill(SERVER_CONNECT_REC *conn, conn->address = g_strdup(address); if (port > 0) conn->port = port; + conn->family = AF_UNSPEC; if (strchr(address, '/') != NULL) conn->unix_socket = TRUE; diff --git a/src/irc/proxy/listen.c b/src/irc/proxy/listen.c index 27c7a0f2..13f2ab51 100644 --- a/src/irc/proxy/listen.c +++ b/src/irc/proxy/listen.c @@ -593,7 +593,7 @@ static void add_listen(const char *ircnet, int port) /* bind to specific host/ip? */ my_ip = NULL; if (*settings_get_str("irssiproxy_bind") != '\0') { - if (net_gethostbyname(settings_get_str("irssiproxy_bind"), &ip, 0) != 0) { + if (net_gethostbyname(settings_get_str("irssiproxy_bind"), &ip, AF_UNSPEC) != 0) { printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Proxy: can not resolve '%s' - aborting", settings_get_str("irssiproxy_bind"));