* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
- *
- * $Id: s_serv.c 3550 2007-08-09 06:47:26Z nenolod $
*/
#include "stdinc.h"
#include "s_serv.h"
#include "class.h"
#include "client.h"
-#include "common.h"
#include "hash.h"
#include "match.h"
#include "ircd.h"
#include "capability.h"
#include "s_assert.h"
-#ifndef INADDR_NONE
-#define INADDR_NONE ((unsigned int) 0xffffffff)
-#endif
-
int MaxConnectionCount = 1;
int MaxClientCount = 1;
int refresh_user_links = 0;
* extra argument to "PASS" takes care of checking that. -orabidoo
*/
struct CapabilityIndex *serv_capindex = NULL;
+struct CapabilityIndex *cli_capindex = NULL;
unsigned int CAP_CAP;
unsigned int CAP_QS;
unsigned int CAP_CHW;
unsigned int CAP_IE;
unsigned int CAP_KLN;
-unsigned int CAP_ZIP;
unsigned int CAP_KNOCK;
unsigned int CAP_TB;
unsigned int CAP_UNKLN;
unsigned int CAP_BAN;
unsigned int CAP_MLOCK;
+unsigned int CLICAP_MULTI_PREFIX;
+unsigned int CLICAP_ACCOUNT_NOTIFY;
+unsigned int CLICAP_EXTENDED_JOIN;
+unsigned int CLICAP_AWAY_NOTIFY;
+unsigned int CLICAP_USERHOST_IN_NAMES;
+unsigned int CLICAP_CAP_NOTIFY;
+unsigned int CLICAP_CHGHOST;
+unsigned int CLICAP_ECHO_MESSAGE;
+
/*
* initialize our builtin capability table. --nenolod
*/
void
init_builtin_capabs(void)
{
+ static struct ClientCapability high_priority = {.flags = CLICAP_FLAGS_PRIORITY};
serv_capindex = capability_index_create("server capabilities");
/* These two are not set via CAPAB/GCAP keywords. */
CAP_CAP = capability_put_anonymous(serv_capindex);
CAP_TS6 = capability_put_anonymous(serv_capindex);
- CAP_QS = capability_put(serv_capindex, "QS");
- CAP_EX = capability_put(serv_capindex, "EX");
- CAP_CHW = capability_put(serv_capindex, "CHW");
- CAP_IE = capability_put(serv_capindex, "IE");
- CAP_KLN = capability_put(serv_capindex, "KLN");
- CAP_KNOCK = capability_put(serv_capindex, "KNOCK");
- CAP_ZIP = capability_put(serv_capindex, "ZIP");
- CAP_TB = capability_put(serv_capindex, "TB");
- CAP_UNKLN = capability_put(serv_capindex, "UNKLN");
- CAP_CLUSTER = capability_put(serv_capindex, "CLUSTER");
- CAP_ENCAP = capability_put(serv_capindex, "ENCAP");
- CAP_SERVICE = capability_put(serv_capindex, "SERVICES");
- CAP_RSFNC = capability_put(serv_capindex, "RSFNC");
- CAP_SAVE = capability_put(serv_capindex, "SAVE");
- CAP_EUID = capability_put(serv_capindex, "EUID");
- CAP_EOPMOD = capability_put(serv_capindex, "EOPMOD");
- CAP_BAN = capability_put(serv_capindex, "BAN");
- CAP_MLOCK = capability_put(serv_capindex, "MLOCK");
+ CAP_QS = capability_put(serv_capindex, "QS", NULL);
+ CAP_EX = capability_put(serv_capindex, "EX", NULL);
+ CAP_CHW = capability_put(serv_capindex, "CHW", NULL);
+ CAP_IE = capability_put(serv_capindex, "IE", NULL);
+ CAP_KLN = capability_put(serv_capindex, "KLN", NULL);
+ CAP_KNOCK = capability_put(serv_capindex, "KNOCK", NULL);
+ CAP_TB = capability_put(serv_capindex, "TB", NULL);
+ CAP_UNKLN = capability_put(serv_capindex, "UNKLN", NULL);
+ CAP_CLUSTER = capability_put(serv_capindex, "CLUSTER", NULL);
+ CAP_ENCAP = capability_put(serv_capindex, "ENCAP", NULL);
+ CAP_SERVICE = capability_put(serv_capindex, "SERVICES", NULL);
+ CAP_RSFNC = capability_put(serv_capindex, "RSFNC", NULL);
+ CAP_SAVE = capability_put(serv_capindex, "SAVE", NULL);
+ CAP_EUID = capability_put(serv_capindex, "EUID", NULL);
+ CAP_EOPMOD = capability_put(serv_capindex, "EOPMOD", NULL);
+ CAP_BAN = capability_put(serv_capindex, "BAN", NULL);
+ CAP_MLOCK = capability_put(serv_capindex, "MLOCK", NULL);
capability_require(serv_capindex, "QS");
capability_require(serv_capindex, "EX");
capability_require(serv_capindex, "IE");
capability_require(serv_capindex, "ENCAP");
+
+ cli_capindex = capability_index_create("client capabilities");
+
+ CLICAP_MULTI_PREFIX = capability_put(cli_capindex, "multi-prefix", &high_priority);
+ CLICAP_ACCOUNT_NOTIFY = capability_put(cli_capindex, "account-notify", &high_priority);
+ CLICAP_EXTENDED_JOIN = capability_put(cli_capindex, "extended-join", &high_priority);
+ CLICAP_AWAY_NOTIFY = capability_put(cli_capindex, "away-notify", &high_priority);
+ CLICAP_USERHOST_IN_NAMES = capability_put(cli_capindex, "userhost-in-names", &high_priority);
+ CLICAP_CAP_NOTIFY = capability_put(cli_capindex, "cap-notify", NULL);
+ CLICAP_CHGHOST = capability_put(cli_capindex, "chghost", &high_priority);
+ CLICAP_ECHO_MESSAGE = capability_put(cli_capindex, "echo-message", NULL);
}
static CNCB serv_connect_callback;
static CNCB serv_connect_ssl_callback;
+static SSL_OPEN_CB serv_connect_ssl_open_callback;
/*
* hunt_server - Do the basic thing in delivering the message (command)
struct server_conf *tmp_p;
struct Class *cltmp;
rb_dlink_node *ptr;
- int connecting = FALSE;
+ bool connecting = false;
int confrq = 0;
time_t next = 0;
continue;
/* don't allow ssl connections if ssl isn't setup */
- if(ServerConfSSL(tmp_p) && (!ssl_ok || !get_ssld_count()))
+ if(ServerConfSSL(tmp_p) && (!ircd_ssl_ok || !get_ssld_count()))
continue;
cltmp = tmp_p->class;
*/
client_p = find_server(NULL, tmp_p->name);
- if(!client_p && (CurrUsers(cltmp) < MaxUsers(cltmp)) && !connecting)
+ if(!client_p && (CurrUsers(cltmp) < MaxAutoconn(cltmp)) && !connecting)
{
server_p = tmp_p;
/* We connect only one at time... */
- connecting = TRUE;
+ connecting = true;
}
if((next > tmp_p->hold) || (next == 0))
* error afterwards if it fails.
* -- adrian
*/
- sendto_realops_snomask(SNO_GENERAL, L_ALL,
+ sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
"Connection to %s activated",
server_p->name);
rb_dlink_node *ptr;
int error = -1;
const char *encr;
+ bool name_matched = false;
+ bool host_matched = false;
+ bool certfp_failed = false;
s_assert(NULL != client_p);
if(client_p == NULL)
RB_DLINK_FOREACH(ptr, server_conf_list.head)
{
+ struct rb_sockaddr_storage client_addr;
+
tmp_p = ptr->data;
if(ServerConfIllegal(tmp_p))
if(!match(tmp_p->name, name))
continue;
- error = -3;
+ name_matched = true;
+
+ if(rb_inet_pton_sock(client_p->sockhost, &client_addr) <= 0)
+ SET_SS_FAMILY(&client_addr, AF_UNSPEC);
- /* 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((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))
+ || (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))
+ )
{
- error = -2;
+ host_matched = true;
if(tmp_p->passwd)
{
if(tmp_p->certfp)
{
- if(!client_p->certfp || strcasecmp(tmp_p->certfp, client_p->certfp) != 0)
+ if(!client_p->certfp || rb_strcasecmp(tmp_p->certfp, client_p->certfp) != 0) {
+ certfp_failed = true;
continue;
+ }
}
server_p = tmp_p;
}
if(server_p == NULL)
+ {
+ /* return the most specific error */
+ if(certfp_failed)
+ error = -6;
+ else if(host_matched)
+ error = -2;
+ else if(name_matched)
+ error = -3;
+
return error;
+ }
if(ServerConfSSL(server_p) && client_p->localClient->ssl_ctl == NULL)
{
return -5;
}
+ if (client_p->localClient->att_sconf && client_p->localClient->att_sconf->class == server_p->class) {
+ /* this is an outgoing connection that is already attached to the correct class */
+ } else if (CurrUsers(server_p->class) >= MaxUsers(server_p->class)) {
+ return -7;
+ }
attach_server_conf(client_p, server_p);
- /* clear ZIP/TB if they support but we dont want them */
-#ifdef HAVE_LIBZ
- if(!ServerConfCompressed(server_p))
-#endif
- ClearCap(client_p, CAP_ZIP);
-
+ /* clear TB if they support but we dont want it */
if(!ServerConfTb(server_p))
ClearCap(client_p, CAP_TB);
* - int flag of capabilities that this server has
* output - NONE
* side effects - send the CAPAB line to a server -orabidoo
- *
*/
void
send_capabilities(struct Client *client_p, unsigned int cap_can_send)
static void
burst_ban(struct Client *client_p)
{
- rb_dlink_node *ptr;
struct ConfItem *aconf;
- const char *type, *oper;
- /* +5 for !,@,{,} and null */
- char operbuf[NICKLEN + USERLEN + HOSTLEN + HOSTLEN + 5];
- char *p;
- size_t melen;
-
- melen = strlen(me.name);
- RB_DLINK_FOREACH(ptr, prop_bans.head)
- {
- aconf = ptr->data;
+ const char *type;
+ rb_dictionary_iter state;
+ RB_DICTIONARY_FOREACH(aconf, &state, prop_bans_dict)
+ {
/* Skip expired stuff. */
if(aconf->lifetime < rb_current_time())
continue;
default:
continue;
}
- oper = aconf->info.oper;
- if(aconf->flags & CONF_FLAGS_MYOPER)
- {
- /* Our operator{} names may not be meaningful
- * to other servers, so rewrite to our server
- * name.
- */
- rb_strlcpy(operbuf, aconf->info.oper, sizeof buf);
- p = strrchr(operbuf, '{');
- if (p != NULL &&
- operbuf + sizeof operbuf - p > (ptrdiff_t)(melen + 2))
- {
- memcpy(p + 1, me.name, melen);
- p[melen + 1] = '}';
- p[melen + 2] = '\0';
- oper = operbuf;
- }
- }
sendto_one(client_p, ":%s BAN %s %s %s %lu %d %d %s :%s%s%s",
me.id,
type,
(unsigned long)aconf->created,
(int)(aconf->hold - aconf->created),
(int)(aconf->lifetime - aconf->created),
- oper,
+ aconf->info.oper,
aconf->passwd,
aconf->spasswd ? "|" : "",
aconf->spasswd ? aconf->spasswd : "");
{
rb_dlink_node *ptr;
struct Ban *banptr;
- char *t;
- int tlen;
- int mlen;
- int cur_len;
- cur_len = mlen = sprintf(buf, ":%s BMASK %ld %s %c :",
- me.id, (long) chptr->channelts, chptr->chname, flag);
- t = buf + mlen;
+ send_multiline_init(client_p, " ", ":%s BMASK %ld %s %c :",
+ me.id,
+ (long)chptr->channelts,
+ chptr->chname,
+ flag);
- RB_DLINK_FOREACH(ptr, list->head)
+ RB_DLINK_FOREACH_PREV(ptr, list->tail)
{
banptr = ptr->data;
- tlen = strlen(banptr->banstr) + (banptr->forward ? strlen(banptr->forward) + 1 : 0) + 1;
-
- /* uh oh */
- if(cur_len + tlen > BUFSIZE - 3)
- {
- /* the one we're trying to send doesnt fit at all! */
- if(cur_len == mlen)
- {
- s_assert(0);
- continue;
- }
-
- /* chop off trailing space and send.. */
- *(t-1) = '\0';
- sendto_one(client_p, "%s", buf);
- cur_len = mlen;
- t = buf + mlen;
- }
-
if (banptr->forward)
- sprintf(t, "%s$%s ", banptr->banstr, banptr->forward);
+ send_multiline_item(client_p, "%s$%s",
+ banptr->banstr,
+ banptr->forward);
else
- sprintf(t, "%s ", banptr->banstr);
- t += tlen;
- cur_len += tlen;
+ send_multiline_item(client_p, "%s", banptr->banstr);
}
- /* cant ever exit the loop above without having modified buf,
- * chop off trailing space and send.
- */
- *(t-1) = '\0';
- sendto_one(client_p, "%s", buf);
+ send_multiline_fini(client_p, NULL);
}
/*
if(!IsPerson(target_p))
continue;
+ if(MyClient(target_p->from) && target_p->localClient->att_sconf != NULL && ServerConfNoExport(target_p->localClient->att_sconf))
+ continue;
+
send_umode(NULL, target_p, 0, ubuf);
if(!*ubuf)
{
use_id(target_p),
target_p->user->away);
+ if (IsOper(target_p) && target_p->user && target_p->user->opername)
+ {
+ if (target_p->user->privset)
+ sendto_one(client_p, ":%s OPER %s %s",
+ use_id(target_p),
+ target_p->user->opername,
+ target_p->user->privset->name);
+ else
+ sendto_one(client_p, ":%s OPER %s",
+ use_id(target_p),
+ target_p->user->opername);
+ }
+
hclientinfo.target = target_p;
call_hook(h_burst_client, &hclientinfo);
}
if((server_p = client_p->localClient->att_sconf) == NULL)
{
/* This shouldn't happen, better tell the ops... -A1kmm */
- sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) ? L_NETWIDE : L_ALL,
+ sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
"Warning: Lost connect{} block for server %s!", host);
return exit_client(client_p, client_p, client_p, "Lost connect{} block!");
}
/* Its got identd , since its a server */
SetGotId(client_p);
- /* If there is something in the serv_list, it might be this
- * connecting server..
- */
- if(!ServerInfo.hub && serv_list.head)
- {
- if(client_p != serv_list.head->data || serv_list.head->next)
- {
- ServerStats.is_ref++;
- sendto_one(client_p, "ERROR :I'm a leaf not a hub");
- return exit_client(client_p, client_p, client_p, "I'm a leaf");
- }
- }
-
if(IsUnknown(client_p))
{
/* the server may be linking based on certificate fingerprint now. --nenolod */
EmptyString(server_p->spasswd) ? "*" : server_p->spasswd, TS_CURRENT, me.id);
/* pass info to new server */
- send_capabilities(client_p, default_server_capabs
- | (ServerConfCompressed(server_p) ? CAP_ZIP_SUPPORTED : 0)
+ send_capabilities(client_p, default_server_capabs | CAP_MASK
| (ServerConfTb(server_p) ? CAP_TB : 0));
sendto_one(client_p, "SERVER %s 1 :%s%s",
if(!rb_set_buffers(client_p->localClient->F, READBUF_SIZE))
ilog_error("rb_set_buffers failed for server");
- /* Enable compression now */
- if(IsCapable(client_p, CAP_ZIP))
- {
- start_zlib_session(client_p);
- }
- sendto_one(client_p, "SVINFO %d %d 0 :%ld", TS_CURRENT, TS_MIN, (long int)rb_current_time());
-
client_p->servptr = &me;
if(IsAnyDead(client_p))
return CLIENT_EXITED;
- SetServer(client_p);
+ sendto_one(client_p, "SVINFO %d %d 0 :%ld", TS_CURRENT, TS_MIN, (long int)rb_current_time());
rb_dlinkAdd(client_p, &client_p->lnode, &me.serv->servers);
rb_dlinkMoveNode(&client_p->localClient->tnode, &unknown_list, &serv_list);
add_to_client_hash(client_p->name, client_p);
/* doesnt duplicate client_p->serv if allocated this struct already */
make_server(client_p);
+ SetServer(client_p);
client_p->serv->caps = client_p->localClient->caps;
if(target_p == client_p)
continue;
+ if(target_p->localClient->att_sconf != NULL && ServerConfNoExport(target_p->localClient->att_sconf))
+ continue;
+
if(has_id(target_p) && has_id(client_p))
{
sendto_one(target_p, ":%s SID %s 2 %s :%s%s",
if(IsMe(target_p) || target_p->from == client_p)
continue;
+ /* don't distribute downstream leaves of servers that are no-export */
+ if(MyClient(target_p->from) && target_p->from->localClient->att_sconf != NULL && ServerConfNoExport(target_p->from->localClient->att_sconf))
+ continue;
+
/* presumption, if target has an id, so does its uplink */
if(has_id(client_p) && has_id(target_p))
sendto_one(client_p, ":%s SID %s %d %s :%s%s",
serv_connect(struct server_conf *server_p, struct Client *by)
{
struct Client *client_p;
- struct rb_sockaddr_storage myipnum;
+ struct sockaddr_storage sa_connect[2];
+ struct sockaddr_storage sa_bind[ARRAY_SIZE(sa_connect)];
char note[HOSTLEN + 10];
rb_fde_t *F;
if(server_p == NULL)
return 0;
+ for (int i = 0; i < ARRAY_SIZE(sa_connect); i++) {
+ SET_SS_FAMILY(&sa_connect[i], AF_UNSPEC);
+ SET_SS_FAMILY(&sa_bind[i], AF_UNSPEC);
+ }
+
+ 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[0] = server_p->connect4;
+ sa_connect[1] = server_p->connect6;
+ sa_bind[0] = server_p->bind4;
+ sa_bind[1] = server_p->bind6;
+ }
+ else
+ {
+ sa_connect[0] = server_p->connect6;
+ sa_connect[1] = server_p->connect4;
+ sa_bind[0] = server_p->bind6;
+ sa_bind[1] = server_p->bind4;
+ }
+ }
+ else if(server_p->aftype == AF_INET || GET_SS_FAMILY(&server_p->connect4) == AF_INET)
+ {
+ sa_connect[0] = server_p->connect4;
+ sa_bind[0] = server_p->bind4;
+ }
+ else if(server_p->aftype == AF_INET6 || GET_SS_FAMILY(&server_p->connect6) == AF_INET6)
+ {
+ sa_connect[0] = server_p->connect6;
+ sa_bind[0] = server_p->bind6;
+ }
+
/* log */
- rb_inet_ntop_sock((struct sockaddr *)&server_p->my_ipnum, buf, sizeof(buf));
- ilog(L_SERVER, "Connect to *[%s] @%s", server_p->name, buf);
+#ifdef HAVE_LIBSCTP
+ if (ServerConfSCTP(server_p) && GET_SS_FAMILY(&sa_connect[1]) != AF_UNSPEC) {
+ char buf2[HOSTLEN + 1];
+
+ buf[0] = 0;
+ buf2[0] = 0;
+ rb_inet_ntop_sock((struct sockaddr *)&sa_connect[0], buf, sizeof(buf));
+ rb_inet_ntop_sock((struct sockaddr *)&sa_connect[1], buf2, sizeof(buf2));
+ ilog(L_SERVER, "Connect to *[%s] @%s&%s", server_p->name, buf, buf2);
+ } else {
+#else
+ {
+#endif
+ buf[0] = 0;
+ rb_inet_ntop_sock((struct sockaddr *)&sa_connect[0], buf, sizeof(buf));
+ ilog(L_SERVER, "Connect to *[%s] @%s", server_p->name, buf);
+ }
/*
* Make sure this server isn't already connected
*/
if((client_p = find_server(NULL, server_p->name)))
{
- sendto_realops_snomask(SNO_GENERAL, L_ALL,
+ sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
"Server %s already present from %s",
server_p->name, client_p->name);
if(by && IsPerson(by) && !MyClient(by))
return 0;
}
+ if (CurrUsers(server_p->class) >= MaxUsers(server_p->class)) {
+ sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
+ "No more connections allowed in class \"%s\" for server %s",
+ server_p->class->class_name, server_p->name);
+ if(by && IsPerson(by) && !MyClient(by))
+ sendto_one_notice(by, ":No more connections allowed in class \"%s\" for server %s",
+ server_p->class->class_name, server_p->name);
+ return 0;
+ }
+
/* 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[0]) == AF_UNSPEC) {
+ ilog_error("unspecified socket address family");
+ return 0;
+#ifdef HAVE_LIBSCTP
+ } else if (ServerConfSCTP(server_p)) {
+ if ((F = rb_socket(AF_INET6, SOCK_STREAM, IPPROTO_SCTP, NULL)) == NULL) {
+ ilog_error("opening a stream socket");
+ return 0;
+ }
+#endif
+ } else if ((F = rb_socket(GET_SS_FAMILY(&sa_connect[0]), SOCK_STREAM, IPPROTO_TCP, NULL)) == NULL) {
ilog_error("opening a stream socket");
return 0;
}
/* 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;
- add_to_cli_connid_hash(client_p);
/* shove the port number into the sockaddr */
-#ifdef RB_IPV6
- if(GET_SS_FAMILY(&server_p->my_ipnum) == AF_INET6)
- ((struct sockaddr_in6 *)&server_p->my_ipnum)->sin6_port = htons(server_p->port);
- else
-#endif
- ((struct sockaddr_in *)&server_p->my_ipnum)->sin_port = htons(server_p->port);
+ SET_SS_PORT(&sa_connect[0], htons(server_p->port));
+ SET_SS_PORT(&sa_connect[1], htons(server_p->port));
/*
* Set up the initial server evilness, ripped straight from
*/
make_server(client_p);
if(by && IsClient(by))
- strcpy(client_p->serv->by, by->name);
+ rb_strlcpy(client_p->serv->by, by->name, sizeof(client_p->serv->by));
else
strcpy(client_p->serv->by, "AutoConn.");
SetConnecting(client_p);
rb_dlinkAddTail(client_p, &client_p->node, &global_client_list);
- if(ServerConfVhosted(server_p))
- {
- memcpy(&myipnum, &server_p->my_ipnum, sizeof(myipnum));
- ((struct sockaddr_in *)&myipnum)->sin_port = 0;
- SET_SS_FAMILY(&myipnum, GET_SS_FAMILY(&server_p->my_ipnum));
-
- }
- else if(GET_SS_FAMILY(&server_p->my_ipnum) == AF_INET && ServerInfo.specific_ipv4_vhost)
- {
- memcpy(&myipnum, &ServerInfo.ip, sizeof(myipnum));
- ((struct sockaddr_in *)&myipnum)->sin_port = 0;
- SET_SS_FAMILY(&myipnum, AF_INET);
- SET_SS_LEN(&myipnum, sizeof(struct sockaddr_in));
+ for (int i = 0; i < ARRAY_SIZE(sa_connect); i++) {
+ if (GET_SS_FAMILY(&sa_bind[i]) == AF_UNSPEC) {
+ if (GET_SS_FAMILY(&sa_connect[i]) == GET_SS_FAMILY(&ServerInfo.bind4))
+ sa_bind[i] = ServerInfo.bind4;
+ if (GET_SS_FAMILY(&sa_connect[i]) == GET_SS_FAMILY(&ServerInfo.bind6))
+ sa_bind[i] = ServerInfo.bind6;
+ }
}
-#ifdef RB_IPV6
- else if((GET_SS_FAMILY(&server_p->my_ipnum) == AF_INET6) && ServerInfo.specific_ipv6_vhost)
+#ifdef HAVE_LIBSCTP
+ if (ServerConfSCTP(server_p)) {
+ rb_connect_sctp(client_p->localClient->F,
+ sa_connect, ARRAY_SIZE(sa_connect), sa_bind, ARRAY_SIZE(sa_bind),
+ ServerConfSSL(server_p) ? serv_connect_ssl_callback : serv_connect_callback,
+ client_p, ConfigFileEntry.connect_timeout);
+ } else {
+#else
{
- memcpy(&myipnum, &ServerInfo.ip6, sizeof(myipnum));
- ((struct sockaddr_in6 *)&myipnum)->sin6_port = 0;
- SET_SS_FAMILY(&myipnum, AF_INET6);
- SET_SS_LEN(&myipnum, sizeof(struct sockaddr_in6));
- }
#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;
+ rb_connect_tcp(client_p->localClient->F,
+ (struct sockaddr *)&sa_connect[0],
+ GET_SS_FAMILY(&sa_bind[0]) == AF_UNSPEC ? NULL : (struct sockaddr *)&sa_bind[0],
+ ServerConfSSL(server_p) ? serv_connect_ssl_callback : serv_connect_callback,
+ client_p, ConfigFileEntry.connect_timeout);
}
- 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);
-
return 1;
}
return;
}
- del_from_cli_connid_hash(client_p);
client_p->localClient->F = xF[0];
- add_to_cli_connid_hash(client_p);
+ client_p->localClient->ssl_callback = serv_connect_ssl_open_callback;
- client_p->localClient->ssl_ctl = start_ssld_connect(F, xF[1], rb_get_fd(xF[0]));
+ client_p->localClient->ssl_ctl = start_ssld_connect(F, xF[1], connid_get(client_p));
+ if(!client_p->localClient->ssl_ctl)
+ {
+ serv_connect_callback(client_p->localClient->F, RB_ERROR, data);
+ return;
+ }
SetSSL(client_p);
- serv_connect_callback(client_p->localClient->F, RB_OK, client_p);
+}
+
+static int
+serv_connect_ssl_open_callback(struct Client *client_p, int status)
+{
+ serv_connect_callback(client_p->localClient->F, status, client_p);
+ return 1; /* suppress default exit_client handler for status != RB_OK */
}
/*
/* COMM_ERR_TIMEOUT wont have an errno associated with it,
* the others will.. --fl
*/
- if(status == RB_ERR_TIMEOUT)
+ if(status == RB_ERR_TIMEOUT || status == RB_ERROR_SSL)
{
- sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) ? L_NETWIDE : L_ALL,
+ sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
"Error connecting to %s[%s]: %s",
client_p->name,
"255.255.255.255",
else
{
errstr = strerror(rb_get_sockerr(F));
- sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) ? L_NETWIDE : L_ALL,
+ sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
"Error connecting to %s[%s]: %s (%s)",
client_p->name,
"255.255.255.255",
/* Get the C/N lines */
if((server_p = client_p->localClient->att_sconf) == NULL)
{
- sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) ? L_NETWIDE : L_ALL, "Lost connect{} block for %s",
+ sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Lost connect{} block for %s",
client_p->name);
exit_client(client_p, client_p, &me, "Lost connect{} block");
return;
}
+ if(server_p->certfp && (!client_p->certfp || rb_strcasecmp(server_p->certfp, client_p->certfp) != 0))
+ {
+ sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
+ "Connection to %s has invalid certificate fingerprint %s",
+ client_p->name, client_p->certfp);
+ ilog(L_SERVER, "Access denied, invalid certificate fingerprint %s from %s",
+ client_p->certfp, log_client_name(client_p, SHOW_IP));
+
+ exit_client(client_p, client_p, &me, "Invalid fingerprint.");
+ return;
+ }
+
/* Next, send the initial handshake */
SetHandshake(client_p);
EmptyString(server_p->spasswd) ? "*" : server_p->spasswd, TS_CURRENT, me.id);
/* pass my info to the new server */
- send_capabilities(client_p, default_server_capabs
- | (ServerConfCompressed(server_p) ? CAP_ZIP_SUPPORTED : 0)
+ send_capabilities(client_p, default_server_capabs | CAP_MASK
| (ServerConfTb(server_p) ? CAP_TB : 0));
sendto_one(client_p, "SERVER %s 1 :%s%s",
*/
if(IsAnyDead(client_p))
{
- sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) ? L_NETWIDE : L_ALL,
+ sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
"%s went dead during handshake", client_p->name);
exit_client(client_p, client_p, &me, "Went dead during handshake");
return;