1
0
mirror of https://github.com/irssi/irssi.git synced 2024-12-04 14:46:39 -05:00

Revert "Network and IPv{4,6} related changes"

This commit is contained in:
ailin-nemui 2015-09-22 21:59:17 +02:00
parent 2d69deb0a3
commit f5f3d7cc98
19 changed files with 241 additions and 88 deletions

View File

@ -15,7 +15,7 @@
%9Examples:%9 %9Examples:%9
/TOGGLE resolve_reverse_lookup /TOGGLE resolve_prefer_ipv6
/TOGGLE channels_rejoin_unavailable ON /TOGGLE channels_rejoin_unavailable ON
%9See also:%9 SET %9See also:%9 SET

View File

@ -429,6 +429,9 @@
After connected to server, Irssi can automatically change your user After connected to server, Irssi can automatically change your user
mode. You can set it with /SET usermode <mode>, default is +i. mode. You can set it with /SET usermode <mode>, default is +i.
/SET resolve_prefer_ipv6 - If ON, prefer IPv6 for hosts that
have both v4 and v6 addresses.
5.5 Automatic reconnecting 5.5 Automatic reconnecting
If you get disconnected from server, Irssi will try to reconnect If you get disconnected from server, Irssi will try to reconnect

View File

@ -128,10 +128,10 @@ static SERVER_CONNECT_REC *get_server_connect(const char *data, int *plus_addr,
host = g_hash_table_lookup(optlist, "host"); host = g_hash_table_lookup(optlist, "host");
if (host != NULL && *host != '\0') { if (host != NULL && *host != '\0') {
IPADDR ip; IPADDR ip4, ip6;
if (net_gethostbyname(host, &ip) == 0) if (net_gethostbyname(host, &ip4, &ip6) == 0)
server_connect_own_ip_save(conn, &ip); server_connect_own_ip_save(conn, &ip4, &ip6);
} }
cmd_params_free(free_arg); cmd_params_free(free_arg);

View File

@ -9,4 +9,4 @@ char *realname;
char *own_host; /* address to use when connecting this server */ char *own_host; /* address to use when connecting this server */
char *autosendcmd; /* command to send after connecting to this ircnet */ 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 */

View File

@ -103,12 +103,15 @@ int net_gethostbyname_nonblock(const char *addr, GIOChannel *pipe,
srand(time(NULL)); srand(time(NULL));
memset(&rec, 0, sizeof(rec)); 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) { if (rec.error == 0) {
errorstr = NULL; errorstr = NULL;
if (reverse_lookup) { if (reverse_lookup) {
/* reverse lookup the IP, ignore any error */ /* 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 { } else {
errorstr = net_gethosterror(rec.error); errorstr = net_gethosterror(rec.error);
@ -119,11 +122,18 @@ int net_gethostbyname_nonblock(const char *addr, GIOChannel *pipe,
if (rec.errlen != 0) if (rec.errlen != 0)
g_io_channel_write_block(pipe, (void *) errorstr, rec.errlen); g_io_channel_write_block(pipe, (void *) errorstr, rec.errlen);
else { else {
if (rec.host) { if (rec.host4) {
len = strlen(rec.host) + 1; len = strlen(rec.host4) + 1;
g_io_channel_write_block(pipe, (void *) &len, g_io_channel_write_block(pipe, (void *) &len,
sizeof(int)); 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); len);
} }
} }
@ -144,7 +154,8 @@ int net_gethostbyname_return(GIOChannel *pipe, RESOLVED_IP_REC *rec)
rec->error = -1; rec->error = -1;
rec->errorstr = NULL; rec->errorstr = NULL;
rec->host = NULL; rec->host4 = NULL;
rec->host6 = NULL;
#ifndef WIN32 #ifndef WIN32
fcntl(g_io_channel_unix_get_fd(pipe), F_SETFL, O_NONBLOCK); 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); rec->errorstr = g_malloc0(rec->errlen+1);
g_io_channel_read_block(pipe, rec->errorstr, rec->errlen); g_io_channel_read_block(pipe, rec->errorstr, rec->errlen);
} else { } else {
if (rec->host) { if (rec->host4) {
g_io_channel_read_block(pipe, &len, sizeof(int)); g_io_channel_read_block(pipe, &len, sizeof(int));
rec->host = g_malloc0(len); rec->host4 = g_malloc0(len);
g_io_channel_read_block(pipe, rec->host, 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; RESOLVED_IP_REC iprec;
GIOChannel *handle; GIOChannel *handle;
IPADDR *ip;
g_return_if_fail(rec != NULL); 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_shutdown(rec->pipes[1], TRUE, NULL);
g_io_channel_unref(rec->pipes[1]); g_io_channel_unref(rec->pipes[1]);
ip = iprec.ip4.family != 0 ? &iprec.ip4 : &iprec.ip6;
handle = iprec.error == -1 ? NULL : 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); g_free_not_null(rec->my_ip);

View File

@ -4,12 +4,12 @@
#include "network.h" #include "network.h"
typedef struct { typedef struct {
IPADDR ip; /* resolved ip address */ IPADDR ip4, ip6; /* resolved ip addresses */
int error; /* error, 0 = no error, -1 = error: */ int error; /* error, 0 = no error, -1 = error: */
int errlen; /* error text length */ int errlen; /* error text length */
char *errorstr; /* error string - dynamically allocated, you'll char *errorstr; /* error string - dynamically allocated, you'll
need to free() it yourself unless it's NULL */ need to free() it yourself unless it's NULL */
char *host; /* dito */ char *host4, *host6; /* dito */
} RESOLVED_IP_REC; } RESOLVED_IP_REC;
typedef struct { typedef struct {

View File

@ -137,14 +137,35 @@ static int sin_get_port(union sockaddr_union *so)
/* Connect to socket */ /* Connect to socket */
GIOChannel *net_connect(const char *addr, int port, IPADDR *my_ip) 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); g_return_val_if_fail(addr != NULL, NULL);
if (net_gethostbyname(addr, &ip) == -1) if (net_gethostbyname(addr, &ip4, &ip6) == -1)
return NULL; 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 */ /* 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. /* Get IP addresses for host, both IPv4 and IPv6 if possible.
If ip->family is 0, the address wasn't found. If ip->family is 0, the address wasn't found.
Returns 0 = ok, others = error code for net_gethosterror() */ 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; union sockaddr_union *so;
struct addrinfo hints, *ailist; struct addrinfo hints, *ai, *ailist;
int ret; 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); 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)); memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_socktype = SOCK_STREAM; 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 */ /* save error to host_error for later use */
ret = getaddrinfo(addr, NULL, &hints, &ailist); ret = getaddrinfo(addr, NULL, &hints, &ailist);
if (ret != 0) if (ret != 0)
return ret; return ret;
so = (const union sockaddr_union *)ailist->ai_addr; /* count IPs */
sin_get_ip(so, ip); 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); 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; return 0;
#endif
} }
/* Get name for host, *name should be g_free()'d unless it's NULL. /* Get name for host, *name should be g_free()'d unless it's NULL.

View File

@ -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. /* Get IP addresses for host, both IPv4 and IPv6 if possible.
If ip->family is 0, the address wasn't found. If ip->family is 0, the address wasn't found.
Returns 0 = ok, others = error code for net_gethosterror() */ 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. /* Get name for host, *name should be g_free()'d unless it's NULL.
Return values are the same as with net_gethostbyname() */ Return values are the same as with net_gethostbyname() */
int net_gethostbyaddr(IPADDR *ip, char **name); int net_gethostbyaddr(IPADDR *ip, char **name);

View File

@ -16,7 +16,7 @@ char *address;
int port; int port;
char *chatnet; char *chatnet;
IPADDR *own_ip; IPADDR *own_ip4, *own_ip6;
char *password; char *password;
char *nick; char *nick;

View File

@ -19,7 +19,7 @@ char *ssl_capath;
char *ssl_ciphers; char *ssl_ciphers;
char *own_host; /* address to use when connecting this server */ 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.. */ time_t last_connect; /* to avoid reconnecting too fast.. */

View File

@ -177,9 +177,13 @@ server_connect_copy_skeleton(SERVER_CONNECT_REC *src, int connect_info)
dest->username = g_strdup(src->username); dest->username = g_strdup(src->username);
dest->realname = g_strdup(src->realname); dest->realname = g_strdup(src->realname);
if (src->own_ip != NULL) { if (src->own_ip4 != NULL) {
dest->own_ip = g_new(IPADDR, 1); dest->own_ip4 = g_new(IPADDR, 1);
memcpy(dest->own_ip, src->own_ip, sizeof(IPADDR)); 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); dest->channels = g_strdup(src->channels);

View File

@ -33,22 +33,32 @@ GSList *setupservers;
static char *old_source_host; static char *old_source_host;
int source_host_ok; /* Use source_host_ip .. */ 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) if (ip4->family == 0)
g_free_and_null(*save_ip); g_free_and_null(*save_ip4);
else { else {
if (*save_ip == NULL) if (*save_ip4 == NULL)
*save_ip = g_new(IPADDR, 1); *save_ip4 = g_new(IPADDR, 1);
memcpy(*save_ip, ip, sizeof(IPADDR)); 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) static void get_source_host_ip(void)
{ {
const char *hostname; const char *hostname;
IPADDR ip4, ip6;
if (source_host_ok) if (source_host_ok)
return; return;
@ -56,21 +66,28 @@ static void get_source_host_ip(void)
/* FIXME: This will block! */ /* FIXME: This will block! */
hostname = settings_get_str("hostname"); hostname = settings_get_str("hostname");
source_host_ok = *hostname != '\0' && 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, 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 */ /* resolve the IP */
if (net_gethostbyname(own_host, &ip) == 0) if (net_gethostbyname(own_host, &ip4, &ip6) == 0)
save_ips(&ip, own_ip); 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 */ /* 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)); g_return_if_fail(IS_SERVER_SETUP(sserver));
if (sserver->own_host != NULL) { 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) if (sserver->chatnet != NULL && conn->chatnet == NULL)
@ -121,9 +139,13 @@ static void server_setup_fill(SERVER_CONNECT_REC *conn,
} }
/* source IP */ /* source IP */
if (source_host_ok) { if (source_host_ip4 != NULL) {
conn->own_ip = g_new(IPADDR, 1); conn->own_ip4 = g_new(IPADDR, 1);
memcpy(conn->own_ip, &source_host_ip, sizeof(IPADDR)); 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); 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);; conn->realname = g_strdup(chatnet->realname);;
} }
if (chatnet->own_host != NULL) { 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); 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); signal_emit("server setup destroyed", 1, rec);
g_free_not_null(rec->own_host); 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->chatnet);
g_free_not_null(rec->password); g_free_not_null(rec->password);
g_free_not_null(rec->ssl_cert); g_free_not_null(rec->ssl_cert);
@ -532,6 +556,7 @@ void servers_setup_init(void)
settings_add_str("proxy", "proxy_password", ""); settings_add_str("proxy", "proxy_password", "");
setupservers = NULL; setupservers = NULL;
source_host_ip4 = source_host_ip6 = NULL;
old_source_host = NULL; old_source_host = NULL;
read_settings(); read_settings();
@ -542,6 +567,8 @@ void servers_setup_init(void)
void servers_setup_deinit(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); g_free_not_null(old_source_host);
while (setupservers != NULL) while (setupservers != NULL)

View File

@ -16,7 +16,7 @@ struct _SERVER_SETUP_REC {
extern GSList *setupservers; 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 .. */ extern int source_host_ok; /* Use source_host_ip .. */
/* Fill reconnection specific information to connection /* Fill reconnection specific information to connection

View File

@ -218,7 +218,7 @@ static void server_real_connect(SERVER_REC *server, IPADDR *ip,
return; return;
if (ip != NULL) { 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 ? port = server->connrec->proxy != NULL ?
server->connrec->proxy_port : server->connrec->port; server->connrec->proxy_port : server->connrec->port;
handle = server->connrec->use_ssl ? 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[0] = NULL;
server->connect_pipe[1] = NULL; server->connect_pipe[1] = NULL;
/* figure out if we should use IPv4 or v6 address */
if (iprec.error != 0) {
/* error */
ip = NULL; ip = NULL;
} else if (server->connrec->family == AF_INET) {
if (iprec.error == 0) { /* force IPv4 connection */
// FIXME : REMOVE THIS BEFORE MERGE ip = iprec.ip4.family == 0 ? NULL : &iprec.ip4;
if (server->connrec->family) servername = iprec.host4;
g_assert(server->connrec->family == iprec.ip.family); } else if (server->connrec->family == AF_INET6) {
/* force IPv6 connection */
ip = &iprec.ip; ip = iprec.ip6.family == 0 ? NULL : &iprec.ip6;
servername = iprec.host; 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) { if (ip != NULL) {
@ -322,7 +337,8 @@ static void server_connect_callback_readpipe(SERVER_REC *server)
} }
g_free(iprec.errorstr); g_free(iprec.errorstr);
g_free(iprec.host); g_free(iprec.host4);
g_free(iprec.host6);
} }
SERVER_REC *server_connect(SERVER_CONNECT_REC *conn) 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->address);
g_free_not_null(conn->chatnet); 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->password);
g_free_not_null(conn->nick); 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 */ /* 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) if (ip4 == NULL || ip4->family == 0)
g_free_and_null(conn->own_ip); 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 (ip4 != NULL && ip4->family != 0) {
if (conn->own_ip == NULL) /* IPv4 address was found */
conn->own_ip = g_new0(IPADDR, 1); if (conn->own_ip4 == NULL)
memcpy(conn->own_ip, ip, sizeof(IPADDR)); 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) void servers_init(void)
{ {
settings_add_bool("server", "resolve_prefer_ipv6", FALSE);
settings_add_bool("server", "resolve_reverse_lookup", FALSE); settings_add_bool("server", "resolve_reverse_lookup", FALSE);
lookup_servers = servers = NULL; lookup_servers = servers = NULL;

View File

@ -67,7 +67,8 @@ void server_connect_failed(SERVER_REC *server, const char *msg);
void server_change_nick(SERVER_REC *server, const char *nick); void server_change_nick(SERVER_REC *server, const char *nick);
/* Update own IPv4 and IPv6 records */ /* 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. /* `optlist' should contain only one unknown key - the server tag.
returns NULL if there was unknown -option */ returns NULL if there was unknown -option */

View File

@ -138,7 +138,7 @@ static void cmd_server_add(const char *data)
if (*password != '\0') g_free_and_null(rec->password); if (*password != '\0') g_free_and_null(rec->password);
if (g_hash_table_lookup(optlist, "host")) { if (g_hash_table_lookup(optlist, "host")) {
g_free_and_null(rec->own_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"); value = g_hash_table_lookup(optlist, "host");
if (value != NULL && *value != '\0') { if (value != NULL && *value != '\0') {
rec->own_host = g_strdup(value); 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); signal_emit("server add fill", 2, rec, optlist);

View File

@ -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, "realname")) g_free_and_null(rec->realname);
if (g_hash_table_lookup(optlist, "host")) { if (g_hash_table_lookup(optlist, "host")) {
g_free_and_null(rec->own_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, "usermode")) g_free_and_null(rec->usermode);
if (g_hash_table_lookup(optlist, "autosendcmd")) g_free_and_null(rec->autosendcmd); 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"); value = g_hash_table_lookup(optlist, "host");
if (value != NULL && *value != '\0') { if (value != NULL && *value != '\0') {
rec->own_host = g_strdup(value); rec->own_host = g_strdup(value);
rec->own_ip = NULL; rec->own_ip4 = rec->own_ip6 = NULL;
} }
value = g_hash_table_lookup(optlist, "usermode"); value = g_hash_table_lookup(optlist, "usermode");

View File

@ -264,12 +264,12 @@ GIOChannel *dcc_connect_ip(IPADDR *ip, int port)
} }
if (own_ip == NULL) 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); handle = net_connect_ip(ip, port, own_ip);
if (handle == NULL && errno == EADDRNOTAVAIL && own_ip != NULL) { if (handle == NULL && errno == EADDRNOTAVAIL && own_ip != NULL) {
/* dcc_own_ip is external address */ /* 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); handle = net_connect_ip(ip, port, own_ip);
} }
return handle; return handle;

View File

@ -585,7 +585,7 @@ static LISTEN_REC *find_listen(const char *ircnet, int port)
static void add_listen(const char *ircnet, int port) static void add_listen(const char *ircnet, int port)
{ {
LISTEN_REC *rec; LISTEN_REC *rec;
IPADDR ip, *my_ip; IPADDR ip4, ip6, *my_ip;
if (port <= 0 || *ircnet == '\0') if (port <= 0 || *ircnet == '\0')
return; return;
@ -593,13 +593,16 @@ static void add_listen(const char *ircnet, int port)
/* bind to specific host/ip? */ /* bind to specific host/ip? */
my_ip = NULL; my_ip = NULL;
if (*settings_get_str("irssiproxy_bind") != '\0') { 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, printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
"Proxy: can not resolve '%s' - aborting", "Proxy: can not resolve '%s' - aborting",
settings_get_str("irssiproxy_bind")); settings_get_str("irssiproxy_bind"));
return; 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); rec = g_new0(LISTEN_REC, 1);