diff --git a/docs/help/in/toggle.in b/docs/help/in/toggle.in index 71f5c8f4..f87a6462 100644 --- a/docs/help/in/toggle.in +++ b/docs/help/in/toggle.in @@ -15,7 +15,7 @@ %9Examples:%9 - /TOGGLE resolve_reverse_lookup + /TOGGLE resolve_prefer_ipv6 /TOGGLE channels_rejoin_unavailable ON %9See also:%9 SET diff --git a/docs/manual.txt b/docs/manual.txt index 12d8031e..b2d0de14 100644 --- a/docs/manual.txt +++ b/docs/manual.txt @@ -429,6 +429,9 @@ 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/chat-commands.c b/src/core/chat-commands.c index 9c28a1fc..8e881679 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 ip; + IPADDR ip4, ip6; - if (net_gethostbyname(host, &ip) == 0) - server_connect_own_ip_save(conn, &ip); + if (net_gethostbyname(host, &ip4, &ip6) == 0) + server_connect_own_ip_save(conn, &ip4, &ip6); } cmd_params_free(free_arg); diff --git a/src/core/chatnet-rec.h b/src/core/chatnet-rec.h index 3044643a..e3ed8aa0 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_ip; /* resolved own_address if not NULL */ +IPADDR *own_ip4, *own_ip6; /* resolved own_address if not NULL */ diff --git a/src/core/net-nonblock.c b/src/core/net-nonblock.c index bc8c4b96..e637e673 100644 --- a/src/core/net-nonblock.c +++ b/src/core/net-nonblock.c @@ -103,12 +103,15 @@ 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.ip4, &rec.ip6); if (rec.error == 0) { errorstr = NULL; if (reverse_lookup) { /* reverse lookup the IP, ignore any error */ - net_gethostbyaddr(&rec.ip, &rec.host); + if (rec.ip4.family != 0) + net_gethostbyaddr(&rec.ip4, &rec.host4); + if (rec.ip6.family != 0) + net_gethostbyaddr(&rec.ip6, &rec.host6); } } else { errorstr = net_gethosterror(rec.error); @@ -119,11 +122,18 @@ 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.host) { - len = strlen(rec.host) + 1; + if (rec.host4) { + len = strlen(rec.host4) + 1; g_io_channel_write_block(pipe, (void *) &len, sizeof(int)); - g_io_channel_write_block(pipe, (void *) rec.host, + 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, len); } } @@ -144,7 +154,8 @@ int net_gethostbyname_return(GIOChannel *pipe, RESOLVED_IP_REC *rec) rec->error = -1; rec->errorstr = NULL; - rec->host = NULL; + rec->host4 = NULL; + rec->host6 = NULL; #ifndef WIN32 fcntl(g_io_channel_unix_get_fd(pipe), F_SETFL, O_NONBLOCK); @@ -163,10 +174,15 @@ 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->host) { + if (rec->host4) { g_io_channel_read_block(pipe, &len, sizeof(int)); - rec->host = g_malloc0(len); - g_io_channel_read_block(pipe, rec->host, len); + 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); } } @@ -211,6 +227,7 @@ static void simple_readpipe(SIMPLE_THREAD_REC *rec, GIOChannel *pipe) { RESOLVED_IP_REC iprec; GIOChannel *handle; + IPADDR *ip; g_return_if_fail(rec != NULL); @@ -224,8 +241,9 @@ 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(&iprec.ip, rec->port, rec->my_ip); + net_connect_ip(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 581536b3..af5968c8 100644 --- a/src/core/net-nonblock.h +++ b/src/core/net-nonblock.h @@ -4,12 +4,12 @@ #include "network.h" typedef struct { - IPADDR ip; /* resolved ip address */ + IPADDR ip4, ip6; /* resolved ip addresses */ 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 *host; /* dito */ + char *host4, *host6; /* dito */ } RESOLVED_IP_REC; typedef struct { diff --git a/src/core/network.c b/src/core/network.c index 303483c6..bfaa47fb 100644 --- a/src/core/network.c +++ b/src/core/network.c @@ -137,14 +137,35 @@ static int sin_get_port(union sockaddr_union *so) /* Connect to socket */ GIOChannel *net_connect(const char *addr, int port, IPADDR *my_ip) { - IPADDR ip; + IPADDR ip4, ip6, *ip; g_return_val_if_fail(addr != NULL, NULL); - if (net_gethostbyname(addr, &ip) == -1) + if (net_gethostbyname(addr, &ip4, &ip6) == -1) return NULL; - return net_connect_ip(&ip, port, my_ip); + 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); } /* Connect to socket with ip address */ @@ -392,35 +413,82 @@ 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 *ip4, IPADDR *ip6) { +#ifdef HAVE_IPV6 union sockaddr_union *so; - struct addrinfo hints, *ailist; - int ret; + struct addrinfo hints, *ai, *ailist; + int ret, count_v4, count_v6, use_v4, use_v6; +#else + struct hostent *hp; + int count; +#endif g_return_val_if_fail(addr != NULL, -1); - memset(ip, 0, sizeof(IPADDR)); + memset(ip4, 0, sizeof(IPADDR)); + memset(ip6, 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; - so = (const union sockaddr_union *)ailist->ai_addr; - sin_get_ip(so, ip); + /* 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++; + } + } 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 ea8b3055..fa7e9675 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 *ip4, IPADDR *ip6); /* 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 3f24e7d8..80c5761b 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_ip; +IPADDR *own_ip4, *own_ip6; char *password; char *nick; diff --git a/src/core/server-setup-rec.h b/src/core/server-setup-rec.h index fbf49b2c..2c9614c7 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_ip; /* resolved own_address if not NULL */ +IPADDR *own_ip4, *own_ip6; /* 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 3ba18ad0..ae97ecd2 100644 --- a/src/core/servers-reconnect.c +++ b/src/core/servers-reconnect.c @@ -177,9 +177,13 @@ 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_ip != NULL) { - dest->own_ip = g_new(IPADDR, 1); - memcpy(dest->own_ip, src->own_ip, sizeof(IPADDR)); + 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)); } dest->channels = g_strdup(src->channels); diff --git a/src/core/servers-setup.c b/src/core/servers-setup.c index e8506f0f..90a447d4 100644 --- a/src/core/servers-setup.c +++ b/src/core/servers-setup.c @@ -33,22 +33,32 @@ GSList *setupservers; static char *old_source_host; int source_host_ok; /* Use source_host_ip .. */ -IPADDR source_host_ip; /* Resolved address */ +IPADDR *source_host_ip4, *source_host_ip6; /* Resolved address */ -static void save_ips(IPADDR *ip, IPADDR **save_ip) +static void save_ips(IPADDR *ip4, IPADDR *ip6, + IPADDR **save_ip4, IPADDR **save_ip6) { - if (ip->family == 0) - g_free_and_null(*save_ip); + if (ip4->family == 0) + g_free_and_null(*save_ip4); else { - if (*save_ip == NULL) - *save_ip = g_new(IPADDR, 1); - memcpy(*save_ip, ip, sizeof(IPADDR)); + 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)); } } static void get_source_host_ip(void) { const char *hostname; + IPADDR ip4, ip6; if (source_host_ok) return; @@ -56,21 +66,28 @@ 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, &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); + } } static void conn_set_ip(SERVER_CONNECT_REC *conn, const char *own_host, - IPADDR **own_ip) + IPADDR **own_ip4, IPADDR **own_ip6) { - IPADDR ip; + IPADDR ip4, ip6; - if (*own_ip == NULL) { + if (*own_ip4 == NULL && *own_ip6 == NULL) { /* resolve the IP */ - if (net_gethostbyname(own_host, &ip) == 0) - save_ips(&ip, own_ip); + if (net_gethostbyname(own_host, &ip4, &ip6) == 0) + save_ips(&ip4, &ip6, own_ip4, own_ip6); } - server_connect_own_ip_save(conn, *own_ip); + server_connect_own_ip_save(conn, *own_ip4, *own_ip6); } /* Fill information to connection from server setup record */ @@ -81,7 +98,8 @@ 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_ip); + conn_set_ip(conn, sserver->own_host, + &sserver->own_ip4, &sserver->own_ip6); } if (sserver->chatnet != NULL && conn->chatnet == NULL) @@ -121,9 +139,13 @@ static void server_setup_fill(SERVER_CONNECT_REC *conn, } /* source IP */ - if (source_host_ok) { - conn->own_ip = g_new(IPADDR, 1); - memcpy(conn->own_ip, &source_host_ip, sizeof(IPADDR)); + 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)); } signal_emit("server setup fill connect", 1, conn); @@ -184,7 +206,8 @@ 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_ip); + conn_set_ip(conn, chatnet->own_host, + &chatnet->own_ip4, &chatnet->own_ip6); } signal_emit("server setup fill chatnet", 2, conn, chatnet); @@ -458,7 +481,8 @@ 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_ip); + g_free_not_null(rec->own_ip4); + g_free_not_null(rec->own_ip6); g_free_not_null(rec->chatnet); g_free_not_null(rec->password); g_free_not_null(rec->ssl_cert); @@ -532,6 +556,7 @@ 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(); @@ -542,6 +567,8 @@ 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 c4878094..f7601a68 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_ip; /* Resolved address */ +extern IPADDR *source_host_ip4, *source_host_ip6; /* 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 66060a7f..3342304e 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 = server->connrec->own_ip; + own_ip = IPADDR_IS_V6(ip) ? server->connrec->own_ip6 : server->connrec->own_ip4; port = server->connrec->proxy != NULL ? server->connrec->proxy_port : server->connrec->port; handle = server->connrec->use_ssl ? @@ -280,15 +280,30 @@ static void server_connect_callback_readpipe(SERVER_REC *server) server->connect_pipe[0] = NULL; server->connect_pipe[1] = NULL; - 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; + /* 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; + } } if (ip != NULL) { @@ -322,7 +337,8 @@ static void server_connect_callback_readpipe(SERVER_REC *server) } g_free(iprec.errorstr); - g_free(iprec.host); + g_free(iprec.host4); + g_free(iprec.host6); } SERVER_REC *server_connect(SERVER_CONNECT_REC *conn) @@ -607,7 +623,8 @@ 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_ip); + g_free_not_null(conn->own_ip4); + g_free_not_null(conn->own_ip6); g_free_not_null(conn->password); g_free_not_null(conn->nick); @@ -637,15 +654,26 @@ 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 *ip) +void server_connect_own_ip_save(SERVER_CONNECT_REC *conn, + IPADDR *ip4, IPADDR *ip6) { - if (ip == NULL || ip->family == 0) - g_free_and_null(conn->own_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) { - if (conn->own_ip == NULL) - conn->own_ip = g_new0(IPADDR, 1); - memcpy(conn->own_ip, ip, sizeof(IPADDR)); + 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)); } } @@ -710,6 +738,7 @@ 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; diff --git a/src/core/servers.h b/src/core/servers.h index 314faa32..f39c650b 100644 --- a/src/core/servers.h +++ b/src/core/servers.h @@ -67,7 +67,8 @@ 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 *ip); +void server_connect_own_ip_save(SERVER_CONNECT_REC *conn, + IPADDR *ip4, IPADDR *ip6); /* `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 f8558ad1..429e6dac 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_ip = NULL; + rec->own_ip4 = rec->own_ip6 = 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_ip = NULL; + rec->own_ip4 = rec->own_ip6 = 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 4071f367..6618edd7 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_ip = NULL; + rec->own_ip4 = rec->own_ip6 = 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_ip = NULL; + rec->own_ip4 = rec->own_ip6 = NULL; } value = g_hash_table_lookup(optlist, "usermode"); diff --git a/src/irc/dcc/dcc.c b/src/irc/dcc/dcc.c index 7fef2ae5..17f6c477 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 = &source_host_ip; + own_ip = IPADDR_IS_V6(ip) ? source_host_ip6 : source_host_ip4; handle = net_connect_ip(ip, port, own_ip); if (handle == NULL && errno == EADDRNOTAVAIL && own_ip != NULL) { /* dcc_own_ip is external address */ - own_ip = &source_host_ip; + own_ip = IPADDR_IS_V6(ip) ? source_host_ip6 : source_host_ip4; 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 16950c79..dcc94e6b 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 ip, *my_ip; + IPADDR ip4, ip6, *my_ip; if (port <= 0 || *ircnet == '\0') return; @@ -593,13 +593,16 @@ 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"), + &ip4, &ip6) != 0) { printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Proxy: can not resolve '%s' - aborting", settings_get_str("irssiproxy_bind")); return; } - my_ip = &ip; + + my_ip = ip6.family == 0 ? &ip4 : ip4.family == 0 || + settings_get_bool("resolve_prefer_ipv6") ? &ip6 : &ip4; } rec = g_new0(LISTEN_REC, 1);