ircd: server connection configuration
Fix the server connection configuration so that it can simultaneously handle a hostname/IPv4/IPv6 for connecting and a hostname/IPv4/IPv6 for binding. Maintains backwards compatibility for matching a hostname with a mask. Multiple host/vhost entries can be specified and the last value for each address family is stored. Hostnames that resolve automatically overwrite the IP address. Server connections can now be made to either IPv4 or IPv6 at random as well as preferring a specific address family.
This commit is contained in:
parent
65f43a4fc4
commit
d4214e9445
9 changed files with 248 additions and 121 deletions
|
@ -243,27 +243,31 @@ conf_set_serverinfo_network_name(void *data)
|
|||
static void
|
||||
conf_set_serverinfo_vhost(void *data)
|
||||
{
|
||||
if(rb_inet_pton(AF_INET, (char *) data, &ServerInfo.ip.sin_addr) <= 0)
|
||||
struct rb_sockaddr_storage addr;
|
||||
|
||||
if(rb_inet_pton_sock(data, (struct sockaddr *)&addr) <= 0 || GET_SS_FAMILY(&addr) != AF_INET)
|
||||
{
|
||||
conf_report_error("Invalid IPv4 address for server vhost (%s)", (char *) data);
|
||||
return;
|
||||
}
|
||||
ServerInfo.ip.sin_family = AF_INET;
|
||||
ServerInfo.specific_ipv4_vhost = 1;
|
||||
|
||||
ServerInfo.bind4 = addr;
|
||||
}
|
||||
|
||||
static void
|
||||
conf_set_serverinfo_vhost6(void *data)
|
||||
{
|
||||
|
||||
#ifdef RB_IPV6
|
||||
if(rb_inet_pton(AF_INET6, (char *) data, &ServerInfo.ip6.sin6_addr) <= 0)
|
||||
struct rb_sockaddr_storage addr;
|
||||
|
||||
if(rb_inet_pton_sock(data, (struct sockaddr *)&addr) <= 0 || GET_SS_FAMILY(&addr) != AF_INET6)
|
||||
{
|
||||
conf_report_error("Invalid IPv6 address for server vhost (%s)", (char *) data);
|
||||
return;
|
||||
}
|
||||
|
||||
ServerInfo.specific_ipv6_vhost = 1;
|
||||
ServerInfo.ip6.sin6_family = AF_INET6;
|
||||
ServerInfo.bind6 = addr;
|
||||
#else
|
||||
conf_report_error("Warning -- ignoring serverinfo::vhost6 -- IPv6 support not available.");
|
||||
#endif
|
||||
|
@ -1301,7 +1305,12 @@ conf_end_connect(struct TopConf *tc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if(EmptyString(yy_server->host))
|
||||
if(EmptyString(yy_server->connect_host)
|
||||
&& GET_SS_FAMILY(&yy_server->connect4) != AF_INET
|
||||
#ifdef RB_IPV6
|
||||
&& GET_SS_FAMILY(&yy_server->connect6) != AF_INET6
|
||||
#endif
|
||||
)
|
||||
{
|
||||
conf_report_error("Ignoring connect block for %s -- missing host.",
|
||||
yy_server->name);
|
||||
|
@ -1326,23 +1335,57 @@ conf_end_connect(struct TopConf *tc)
|
|||
static void
|
||||
conf_set_connect_host(void *data)
|
||||
{
|
||||
rb_free(yy_server->host);
|
||||
yy_server->host = rb_strdup(data);
|
||||
if (strchr(yy_server->host, ':'))
|
||||
yy_server->aftype = AF_INET6;
|
||||
struct rb_sockaddr_storage addr;
|
||||
|
||||
if(rb_inet_pton_sock(data, (struct sockaddr *)&addr) <= 0)
|
||||
{
|
||||
rb_free(yy_server->connect_host);
|
||||
yy_server->connect_host = rb_strdup(data);
|
||||
}
|
||||
else if(GET_SS_FAMILY(&addr) == AF_INET)
|
||||
{
|
||||
yy_server->connect4 = addr;
|
||||
}
|
||||
#ifdef RB_IPV6
|
||||
else if(GET_SS_FAMILY(&addr) == AF_INET6)
|
||||
{
|
||||
yy_server->connect6 = addr;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
conf_report_error("Unsupported IP address for server connect host (%s)",
|
||||
(char *)data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
conf_set_connect_vhost(void *data)
|
||||
{
|
||||
if(rb_inet_pton_sock(data, (struct sockaddr *)&yy_server->my_ipnum) <= 0)
|
||||
struct rb_sockaddr_storage addr;
|
||||
|
||||
if(rb_inet_pton_sock(data, (struct sockaddr *)&addr) <= 0)
|
||||
{
|
||||
conf_report_error("Invalid IP address for server connect vhost (%s)",
|
||||
(char *) data);
|
||||
rb_free(yy_server->bind_host);
|
||||
yy_server->bind_host = rb_strdup(data);
|
||||
}
|
||||
else if(GET_SS_FAMILY(&addr) == AF_INET)
|
||||
{
|
||||
yy_server->bind4 = addr;
|
||||
}
|
||||
#ifdef RB_IPV6
|
||||
else if(GET_SS_FAMILY(&addr) == AF_INET6)
|
||||
{
|
||||
yy_server->bind6 = addr;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
conf_report_error("Unsupported IP address for server connect vhost (%s)",
|
||||
(char *)data);
|
||||
return;
|
||||
}
|
||||
|
||||
yy_server->flags |= SERVER_VHOSTED;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -2071,7 +2114,7 @@ conf_end_opm(struct TopConf *tc)
|
|||
else
|
||||
{
|
||||
char ip[HOSTIPLEN];
|
||||
if(!rb_inet_ntop_sock((struct sockaddr *)&ServerInfo.ip, ip, sizeof(ip)))
|
||||
if(!rb_inet_ntop_sock((struct sockaddr *)&ServerInfo.bind4, ip, sizeof(ip)))
|
||||
conf_report_error("No opm::listen_ipv4 nor serverinfo::vhost directive; cannot listen on IPv4");
|
||||
else
|
||||
conf_create_opm_listener(ip, yy_opm_port_ipv4);
|
||||
|
@ -2085,7 +2128,7 @@ conf_end_opm(struct TopConf *tc)
|
|||
else
|
||||
{
|
||||
char ip[HOSTIPLEN];
|
||||
if(!rb_inet_ntop_sock((struct sockaddr *)&ServerInfo.ip6, ip, sizeof(ip)))
|
||||
if(!rb_inet_ntop_sock((struct sockaddr *)&ServerInfo.bind6, ip, sizeof(ip)))
|
||||
conf_report_error("No opm::listen_ipv6 nor serverinfo::vhost directive; cannot listen on IPv6");
|
||||
else
|
||||
conf_create_opm_listener(ip, yy_opm_port_ipv6);
|
||||
|
|
|
@ -680,11 +680,11 @@ set_default_conf(void)
|
|||
ServerInfo.description = NULL;
|
||||
ServerInfo.network_name = NULL;
|
||||
|
||||
memset(&ServerInfo.ip, 0, sizeof(ServerInfo.ip));
|
||||
ServerInfo.specific_ipv4_vhost = 0;
|
||||
memset(&ServerInfo.bind4, 0, sizeof(ServerInfo.bind4));
|
||||
SET_SS_FAMILY(&ServerInfo.bind4, AF_UNSPEC);
|
||||
#ifdef RB_IPV6
|
||||
memset(&ServerInfo.ip6, 0, sizeof(ServerInfo.ip6));
|
||||
ServerInfo.specific_ipv6_vhost = 0;
|
||||
memset(&ServerInfo.bind6, 0, sizeof(ServerInfo.bind6));
|
||||
SET_SS_FAMILY(&ServerInfo.bind6, AF_UNSPEC);
|
||||
#endif
|
||||
|
||||
AdminInfo.name = NULL;
|
||||
|
|
100
ircd/s_newconf.c
100
ircd/s_newconf.c
|
@ -324,8 +324,24 @@ struct server_conf *
|
|||
make_server_conf(void)
|
||||
{
|
||||
struct server_conf *server_p = rb_malloc(sizeof(struct server_conf));
|
||||
server_p->aftype = AF_INET;
|
||||
return server_p;
|
||||
|
||||
SET_SS_FAMILY(&server_p->connect4, AF_UNSPEC);
|
||||
SET_SS_LEN(&server_p->connect4, sizeof(struct sockaddr_in));
|
||||
|
||||
SET_SS_FAMILY(&server_p->bind4, AF_UNSPEC);
|
||||
SET_SS_LEN(&server_p->bind4, sizeof(struct sockaddr_in));
|
||||
|
||||
#ifdef RB_IPV6
|
||||
SET_SS_FAMILY(&server_p->connect6, AF_UNSPEC);
|
||||
SET_SS_LEN(&server_p->connect6, sizeof(struct sockaddr_in6));
|
||||
|
||||
SET_SS_FAMILY(&server_p->bind6, AF_UNSPEC);
|
||||
SET_SS_LEN(&server_p->bind6, sizeof(struct sockaddr_in6));
|
||||
#endif
|
||||
|
||||
server_p->aftype = AF_UNSPEC;
|
||||
|
||||
return rb_malloc(sizeof(struct server_conf));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -348,13 +364,14 @@ free_server_conf(struct server_conf *server_p)
|
|||
}
|
||||
|
||||
rb_free(server_p->name);
|
||||
rb_free(server_p->host);
|
||||
rb_free(server_p->connect_host);
|
||||
rb_free(server_p->bind_host);
|
||||
rb_free(server_p->class_name);
|
||||
rb_free(server_p);
|
||||
}
|
||||
|
||||
/*
|
||||
* conf_dns_callback
|
||||
* conf_connect_dns_callback
|
||||
* inputs - pointer to struct ConfItem
|
||||
* - pointer to adns reply
|
||||
* output - none
|
||||
|
@ -364,14 +381,59 @@ free_server_conf(struct server_conf *server_p)
|
|||
* if successful save hp in the conf item it was called with
|
||||
*/
|
||||
static void
|
||||
conf_dns_callback(const char *result, int status, int aftype, void *data)
|
||||
conf_connect_dns_callback(const char *result, int status, int aftype, void *data)
|
||||
{
|
||||
struct server_conf *server_p = data;
|
||||
|
||||
if(status == 1)
|
||||
rb_inet_pton_sock(result, (struct sockaddr *)&server_p->my_ipnum);
|
||||
if(aftype == AF_INET)
|
||||
{
|
||||
if(status == 1)
|
||||
rb_inet_pton_sock(result, (struct sockaddr *)&server_p->connect4);
|
||||
|
||||
server_p->dns_query = 0;
|
||||
server_p->dns_query_connect4 = 0;
|
||||
}
|
||||
#ifdef RB_IPV6
|
||||
else if(aftype == AF_INET6)
|
||||
{
|
||||
if(status == 1)
|
||||
rb_inet_pton_sock(result, (struct sockaddr *)&server_p->connect6);
|
||||
|
||||
server_p->dns_query_connect6 = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* conf_bind_dns_callback
|
||||
* inputs - pointer to struct ConfItem
|
||||
* - pointer to adns reply
|
||||
* output - none
|
||||
* side effects - called when resolver query finishes
|
||||
* if the query resulted in a successful search, hp will contain
|
||||
* a non-null pointer, otherwise hp will be null.
|
||||
* if successful save hp in the conf item it was called with
|
||||
*/
|
||||
static void
|
||||
conf_bind_dns_callback(const char *result, int status, int aftype, void *data)
|
||||
{
|
||||
struct server_conf *server_p = data;
|
||||
|
||||
if(aftype == AF_INET)
|
||||
{
|
||||
if(status == 1)
|
||||
rb_inet_pton_sock(result, (struct sockaddr *)&server_p->bind4);
|
||||
|
||||
server_p->dns_query_bind4 = 0;
|
||||
}
|
||||
#ifdef RB_IPV6
|
||||
else if(aftype == AF_INET6)
|
||||
{
|
||||
if(status == 1)
|
||||
rb_inet_pton_sock(result, (struct sockaddr *)&server_p->bind6);
|
||||
|
||||
server_p->dns_query_bind6 = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -395,11 +457,25 @@ add_server_conf(struct server_conf *server_p)
|
|||
server_p->class_name = rb_strdup("default");
|
||||
}
|
||||
|
||||
if(strpbrk(server_p->host, "*?"))
|
||||
return;
|
||||
if(server_p->connect_host && !strpbrk(server_p->connect_host, "*?"))
|
||||
{
|
||||
server_p->dns_query_connect4 =
|
||||
lookup_hostname(server_p->connect_host, AF_INET, conf_connect_dns_callback, server_p);
|
||||
#ifdef RB_IPV6
|
||||
server_p->dns_query_connect6 =
|
||||
lookup_hostname(server_p->connect_host, AF_INET6, conf_connect_dns_callback, server_p);
|
||||
#endif
|
||||
}
|
||||
|
||||
server_p->dns_query =
|
||||
lookup_hostname(server_p->host, GET_SS_FAMILY(&server_p->my_ipnum), conf_dns_callback, server_p);
|
||||
if(server_p->bind_host)
|
||||
{
|
||||
server_p->dns_query_bind4 =
|
||||
lookup_hostname(server_p->bind_host, AF_INET, conf_bind_dns_callback, server_p);
|
||||
#ifdef RB_IPV6
|
||||
server_p->dns_query_bind6 =
|
||||
lookup_hostname(server_p->bind_host, AF_INET6, conf_bind_dns_callback, server_p);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
struct server_conf *
|
||||
|
|
127
ircd/s_serv.c
127
ircd/s_serv.c
|
@ -363,6 +363,8 @@ check_server(const char *name, struct Client *client_p)
|
|||
|
||||
RB_DLINK_FOREACH(ptr, server_conf_list.head)
|
||||
{
|
||||
struct rb_sockaddr_storage client_addr;
|
||||
|
||||
tmp_p = ptr->data;
|
||||
|
||||
if(ServerConfIllegal(tmp_p))
|
||||
|
@ -373,10 +375,19 @@ check_server(const char *name, struct Client *client_p)
|
|||
|
||||
name_matched = true;
|
||||
|
||||
/* XXX: Fix me for IPv6 */
|
||||
/* XXX sockhost is the IPv4 ip as a string */
|
||||
if(match(tmp_p->host, client_p->host) ||
|
||||
match(tmp_p->host, client_p->sockhost))
|
||||
if(rb_inet_pton_sock(client_p->sockhost, (struct sockaddr *)&client_addr) <= 0)
|
||||
SET_SS_FAMILY(&client_addr, AF_UNSPEC);
|
||||
|
||||
if((tmp_p->connect_host && match(tmp_p->connect_host, client_p->host))
|
||||
|| (GET_SS_FAMILY(&client_addr) == GET_SS_FAMILY(&tmp_p->connect4)
|
||||
&& comp_with_mask_sock((struct sockaddr *)&client_addr,
|
||||
(struct sockaddr *)&tmp_p->connect4, 32))
|
||||
#ifdef RB_IPV6
|
||||
|| (GET_SS_FAMILY(&client_addr) == GET_SS_FAMILY(&tmp_p->connect6)
|
||||
&& comp_with_mask_sock((struct sockaddr *)&client_addr,
|
||||
(struct sockaddr *)&tmp_p->connect6, 128))
|
||||
#endif
|
||||
)
|
||||
{
|
||||
host_matched = true;
|
||||
|
||||
|
@ -1010,7 +1021,8 @@ int
|
|||
serv_connect(struct server_conf *server_p, struct Client *by)
|
||||
{
|
||||
struct Client *client_p;
|
||||
struct rb_sockaddr_storage myipnum;
|
||||
struct rb_sockaddr_storage sa_connect;
|
||||
struct rb_sockaddr_storage sa_bind;
|
||||
char note[HOSTLEN + 10];
|
||||
rb_fde_t *F;
|
||||
|
||||
|
@ -1018,8 +1030,39 @@ serv_connect(struct server_conf *server_p, struct Client *by)
|
|||
if(server_p == NULL)
|
||||
return 0;
|
||||
|
||||
#ifdef RB_IPV6
|
||||
if(server_p->aftype != AF_UNSPEC
|
||||
&& GET_SS_FAMILY(&server_p->connect4) == AF_INET
|
||||
&& GET_SS_FAMILY(&server_p->connect6) == AF_INET6)
|
||||
{
|
||||
if(rand() % 2 == 0)
|
||||
{
|
||||
sa_connect = server_p->connect4;
|
||||
sa_bind = server_p->bind4;
|
||||
}
|
||||
else
|
||||
{
|
||||
sa_connect = server_p->connect6;
|
||||
sa_bind = server_p->bind6;
|
||||
}
|
||||
}
|
||||
else if(server_p->aftype == AF_INET || GET_SS_FAMILY(&server_p->connect4) == AF_INET)
|
||||
#endif
|
||||
{
|
||||
sa_connect = server_p->connect4;
|
||||
sa_bind = server_p->bind4;
|
||||
}
|
||||
#ifdef RB_IPV6
|
||||
else if(server_p->aftype == AF_INET6 || GET_SS_FAMILY(&server_p->connect6) == AF_INET6)
|
||||
{
|
||||
sa_connect = server_p->connect6;
|
||||
sa_bind = server_p->bind6;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* log */
|
||||
rb_inet_ntop_sock((struct sockaddr *)&server_p->my_ipnum, buf, sizeof(buf));
|
||||
buf[0] = 0;
|
||||
rb_inet_ntop_sock((struct sockaddr *)&sa_connect, buf, sizeof(buf));
|
||||
ilog(L_SERVER, "Connect to *[%s] @%s", server_p->name, buf);
|
||||
|
||||
/*
|
||||
|
@ -1037,7 +1080,12 @@ serv_connect(struct server_conf *server_p, struct Client *by)
|
|||
}
|
||||
|
||||
/* create a socket for the server connection */
|
||||
if((F = rb_socket(GET_SS_FAMILY(&server_p->my_ipnum), SOCK_STREAM, 0, NULL)) == NULL)
|
||||
if(GET_SS_FAMILY(&sa_connect) == AF_UNSPEC)
|
||||
{
|
||||
ilog_error("unspecified socket address family");
|
||||
return 0;
|
||||
}
|
||||
else if((F = rb_socket(GET_SS_FAMILY(&sa_connect), SOCK_STREAM, 0, NULL)) == NULL)
|
||||
{
|
||||
ilog_error("opening a stream socket");
|
||||
return 0;
|
||||
|
@ -1052,11 +1100,14 @@ serv_connect(struct server_conf *server_p, struct Client *by)
|
|||
|
||||
/* Copy in the server, hostname, fd */
|
||||
rb_strlcpy(client_p->name, server_p->name, sizeof(client_p->name));
|
||||
rb_strlcpy(client_p->host, server_p->host, sizeof(client_p->host));
|
||||
if(server_p->connect_host)
|
||||
rb_strlcpy(client_p->host, server_p->connect_host, sizeof(client_p->host));
|
||||
else
|
||||
rb_strlcpy(client_p->host, buf, sizeof(client_p->host));
|
||||
rb_strlcpy(client_p->sockhost, buf, sizeof(client_p->sockhost));
|
||||
client_p->localClient->F = F;
|
||||
/* shove the port number into the sockaddr */
|
||||
SET_SS_PORT(&server_p->my_ipnum, htons(server_p->port));
|
||||
SET_SS_PORT(&sa_connect, htons(server_p->port));
|
||||
|
||||
/*
|
||||
* Set up the initial server evilness, ripped straight from
|
||||
|
@ -1091,58 +1142,22 @@ serv_connect(struct server_conf *server_p, struct Client *by)
|
|||
SetConnecting(client_p);
|
||||
rb_dlinkAddTail(client_p, &client_p->node, &global_client_list);
|
||||
|
||||
if(ServerConfVhosted(server_p))
|
||||
if(GET_SS_FAMILY(&sa_bind) == AF_UNSPEC)
|
||||
{
|
||||
memcpy(&myipnum, &server_p->my_ipnum, sizeof(myipnum));
|
||||
SET_SS_FAMILY(&myipnum, GET_SS_FAMILY(&server_p->my_ipnum));
|
||||
SET_SS_PORT(&myipnum, 0);
|
||||
|
||||
}
|
||||
else if(GET_SS_FAMILY(&server_p->my_ipnum) == AF_INET && ServerInfo.specific_ipv4_vhost)
|
||||
{
|
||||
memcpy(&myipnum, &ServerInfo.ip, sizeof(myipnum));
|
||||
SET_SS_FAMILY(&myipnum, AF_INET);
|
||||
SET_SS_PORT(&myipnum, 0);
|
||||
SET_SS_LEN(&myipnum, sizeof(struct sockaddr_in));
|
||||
}
|
||||
|
||||
if(GET_SS_FAMILY(&sa_connect) == GET_SS_FAMILY(&ServerInfo.bind4))
|
||||
sa_bind = ServerInfo.bind4;
|
||||
#ifdef RB_IPV6
|
||||
else if((GET_SS_FAMILY(&server_p->my_ipnum) == AF_INET6) && ServerInfo.specific_ipv6_vhost)
|
||||
{
|
||||
memcpy(&myipnum, &ServerInfo.ip6, sizeof(myipnum));
|
||||
SET_SS_FAMILY(&myipnum, AF_INET6);
|
||||
SET_SS_PORT(&myipnum, 0);
|
||||
SET_SS_LEN(&myipnum, sizeof(struct sockaddr_in6));
|
||||
}
|
||||
if(GET_SS_FAMILY(&sa_connect) == GET_SS_FAMILY(&ServerInfo.bind6))
|
||||
sa_bind = ServerInfo.bind6;
|
||||
#endif
|
||||
else
|
||||
{
|
||||
if(ServerConfSSL(server_p))
|
||||
{
|
||||
rb_connect_tcp(client_p->localClient->F,
|
||||
(struct sockaddr *)&server_p->my_ipnum, NULL, 0,
|
||||
serv_connect_ssl_callback, client_p,
|
||||
ConfigFileEntry.connect_timeout);
|
||||
}
|
||||
else
|
||||
rb_connect_tcp(client_p->localClient->F,
|
||||
(struct sockaddr *)&server_p->my_ipnum, NULL, 0,
|
||||
serv_connect_callback, client_p,
|
||||
ConfigFileEntry.connect_timeout);
|
||||
|
||||
return 1;
|
||||
}
|
||||
if(ServerConfSSL(server_p))
|
||||
rb_connect_tcp(client_p->localClient->F, (struct sockaddr *)&server_p->my_ipnum,
|
||||
(struct sockaddr *)&myipnum,
|
||||
GET_SS_LEN(&myipnum), serv_connect_ssl_callback, client_p,
|
||||
ConfigFileEntry.connect_timeout);
|
||||
else
|
||||
rb_connect_tcp(client_p->localClient->F, (struct sockaddr *)&server_p->my_ipnum,
|
||||
(struct sockaddr *)&myipnum,
|
||||
GET_SS_LEN(&myipnum), serv_connect_callback, client_p,
|
||||
ConfigFileEntry.connect_timeout);
|
||||
|
||||
rb_connect_tcp(client_p->localClient->F,
|
||||
(struct sockaddr *)&sa_connect,
|
||||
GET_SS_FAMILY(&sa_bind) == AF_UNSPEC ? NULL : (struct sockaddr *)&sa_bind,
|
||||
GET_SS_LEN(&sa_bind),
|
||||
ServerConfSSL(server_p) ? serv_connect_ssl_callback : serv_connect_callback,
|
||||
client_p, ConfigFileEntry.connect_timeout);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue