From d4214e9445d9f9d0f0ede3e09a9f81deee95d69c Mon Sep 17 00:00:00 2001 From: Simon Arlott Date: Sun, 24 Apr 2016 17:05:05 +0100 Subject: [PATCH] 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. --- doc/ircd.conf.example | 6 +- doc/reference.conf | 11 +-- doc/sgml/oper-guide/config.sgml | 10 +-- include/s_conf.h | 8 +- include/s_newconf.h | 20 +++-- ircd/newconf.c | 79 +++++++++++++++----- ircd/s_conf.c | 8 +- ircd/s_newconf.c | 100 ++++++++++++++++++++++--- ircd/s_serv.c | 127 ++++++++++++++++++-------------- 9 files changed, 248 insertions(+), 121 deletions(-) diff --git a/doc/ircd.conf.example b/doc/ircd.conf.example index 2305c3024..5d7f984e2 100644 --- a/doc/ircd.conf.example +++ b/doc/ircd.conf.example @@ -310,10 +310,6 @@ connect "irc.uplink.com" { flags = compressed, topicburst; #fingerprint = "c77106576abf7f9f90cca0f63874a60f2e40a64b"; - - /* If the connection is IPv6, uncomment below. - * Use 0::1, not ::1, for IPv6 localhost. */ - #aftype = ipv6; }; connect "ssl.uplink.com" { @@ -454,7 +450,7 @@ opm { * to be effective. * If omitted, it defaults to serverinfo::vhost6. */ - #listen_ipv6 = "0::1"; + #listen_ipv6 = "::1"; /* IPv6 port to listen on. * This should not be the same as any existing listeners. diff --git a/doc/reference.conf b/doc/reference.conf index aff7787c0..731eadf8c 100644 --- a/doc/reference.conf +++ b/doc/reference.conf @@ -571,17 +571,14 @@ connect "irc.uplink.com" { }; connect "ipv6.lame.server" { - /* Hosts that are IPv6 addresses must be in :: shortened form - * if applicable. Addresses starting with a colon get an extra - * zero prepended, for example: 0::1 - */ + host = "192.0.2.1"; host = "2001:db8:3::8"; send_password = "password"; accept_password = "password"; port = 6666; - /* aftype: controls whether the connection uses "ipv4" or "ipv6". - * Default is ipv4. + /* aftype: controls whether the outgoing connection uses "ipv4" or "ipv6". + * Default is to try either at random. */ aftype = ipv6; class = "server"; @@ -930,7 +927,7 @@ opm { * to be effective. * If omitted, it defaults to serverinfo::vhost6. */ - #listen_ipv6 = "0::1"; + #listen_ipv6 = "::1"; /* IPv6 port to listen on. * This should not be the same as any existing listeners. diff --git a/doc/sgml/oper-guide/config.sgml b/doc/sgml/oper-guide/config.sgml index 0d5851246..798d6fcfa 100644 --- a/doc/sgml/oper-guide/config.sgml +++ b/doc/sgml/oper-guide/config.sgml @@ -105,7 +105,7 @@ serverinfo { vhost - An optional text field which defines an IP from which to connect outward to other IRC servers. + An optional text field which defines an IPv4 address from which to connect outward to other IRC servers. @@ -113,7 +113,7 @@ serverinfo { vhost6 - An optional text field which defines an IPv6 IP from which to connect outward to other IRC servers. + An optional text field which defines an IPv6 address from which to connect outward to other IRC servers. @@ -599,10 +599,6 @@ connect "name" { Furthermore, if a hostname is used, it must have an A or AAAA record (no CNAME) and it must be the primary hostname for inbound connections to work. - - IPv6 addresses must be in :: shortened form; addresses which - then start with a colon must be prepended with a zero, - for example 0::1. @@ -662,7 +658,7 @@ connect "name" { aftype - The protocol that should be used to connect with, either ipv4 or ipv6. This defaults to ipv4 unless host is a numeric IPv6 address. + The protocol that must be used to connect with, either ipv4 or ipv6. This defaults to neither, allowing connection using either address family. diff --git a/include/s_conf.h b/include/s_conf.h index dbbdce194..4c3bd5eed 100644 --- a/include/s_conf.h +++ b/include/s_conf.h @@ -282,14 +282,10 @@ struct server_info char *description; char *network_name; int hub; - struct sockaddr_in ip; + struct rb_sockaddr_storage bind4; int default_max_clients; #ifdef RB_IPV6 - struct sockaddr_in6 ip6; -#endif - int specific_ipv4_vhost; -#ifdef RB_IPV6 - int specific_ipv6_vhost; + struct rb_sockaddr_storage bind6; #endif char *ssl_private_key; char *ssl_ca_cert; diff --git a/include/s_newconf.h b/include/s_newconf.h index 22c24784e..4218a8282 100644 --- a/include/s_newconf.h +++ b/include/s_newconf.h @@ -178,7 +178,13 @@ extern const char *get_oper_privs(int flags); struct server_conf { char *name; - char *host; + char *connect_host; + struct rb_sockaddr_storage connect4; + uint16_t dns_query_connect4; +#ifdef RB_IPV6 + struct rb_sockaddr_storage connect6; + uint16_t dns_query_connect6; +#endif char *passwd; char *spasswd; char *certfp; @@ -188,17 +194,20 @@ struct server_conf time_t hold; int aftype; - struct rb_sockaddr_storage my_ipnum; + char *bind_host; + struct rb_sockaddr_storage bind4; + uint16_t dns_query_bind4; +#ifdef RB_IPV6 + struct rb_sockaddr_storage bind6; + uint16_t dns_query_bind6; +#endif char *class_name; struct Class *class; rb_dlink_node node; - - uint16_t dns_query; }; #define SERVER_ILLEGAL 0x0001 -#define SERVER_VHOSTED 0x0002 #define SERVER_ENCRYPTED 0x0004 #define SERVER_COMPRESSED 0x0008 #define SERVER_TB 0x0010 @@ -206,7 +215,6 @@ struct server_conf #define SERVER_SSL 0x0040 #define ServerConfIllegal(x) ((x)->flags & SERVER_ILLEGAL) -#define ServerConfVhosted(x) ((x)->flags & SERVER_VHOSTED) #define ServerConfEncrypted(x) ((x)->flags & SERVER_ENCRYPTED) #define ServerConfCompressed(x) ((x)->flags & SERVER_COMPRESSED) #define ServerConfTb(x) ((x)->flags & SERVER_TB) diff --git a/ircd/newconf.c b/ircd/newconf.c index 253d02b6e..47a5924c0 100644 --- a/ircd/newconf.c +++ b/ircd/newconf.c @@ -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); diff --git a/ircd/s_conf.c b/ircd/s_conf.c index dcb4911f0..976c0ce7e 100644 --- a/ircd/s_conf.c +++ b/ircd/s_conf.c @@ -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; diff --git a/ircd/s_newconf.c b/ircd/s_newconf.c index 3815f839f..a9c661799 100644 --- a/ircd/s_newconf.c +++ b/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 * diff --git a/ircd/s_serv.c b/ircd/s_serv.c index 734efb9e4..28ed4286b 100644 --- a/ircd/s_serv.c +++ b/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; }