#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;
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)
name_matched = true;
- if(rb_inet_pton_sock(client_p->sockhost, (struct sockaddr *)&client_addr) <= 0)
+ if(rb_inet_pton_sock(client_p->sockhost, &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;
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 */
* to other servers, so rewrite to our server
* name.
*/
- rb_strlcpy(operbuf, aconf->info.oper, sizeof buf);
+ rb_strlcpy(operbuf, aconf->info.oper, sizeof operbuf);
p = strrchr(operbuf, '{');
if (p != NULL &&
operbuf + sizeof operbuf - p > (ptrdiff_t)(melen + 2))
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 && 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);
+
hclientinfo.target = target_p;
call_hook(h_burst_client, &hclientinfo);
}
EmptyString(server_p->spasswd) ? "*" : server_p->spasswd, TS_CURRENT, me.id);
/* pass info to new server */
- send_capabilities(client_p, default_server_capabs
+ send_capabilities(client_p, default_server_capabs | CAP_MASK
| (ServerConfCompressed(server_p) ? CAP_ZIP_SUPPORTED : 0)
| (ServerConfTb(server_p) ? CAP_TB : 0));
{
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 sa_connect;
- struct rb_sockaddr_storage sa_bind;
+ 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;
-#ifdef RB_IPV6
- if(server_p->aftype != AF_UNSPEC
+ 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 = server_p->connect4;
- sa_bind = server_p->bind4;
+ 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 = server_p->connect6;
- sa_bind = server_p->bind6;
+ 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)
-#endif
{
- sa_connect = server_p->connect4;
- sa_bind = server_p->bind4;
+ sa_connect[0] = server_p->connect4;
+ sa_bind[0] = 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;
+ sa_connect[0] = server_p->connect6;
+ sa_bind[0] = server_p->bind6;
}
-#endif
/* log */
- 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);
+#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
return 0;
}
+ if (CurrUsers(server_p->class) >= MaxUsers(server_p->class)) {
+ sendto_realops_snomask(SNO_GENERAL, L_ALL,
+ "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(GET_SS_FAMILY(&sa_connect) == AF_UNSPEC)
- {
+ if(GET_SS_FAMILY(&sa_connect[0]) == 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)
- {
+#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;
}
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(&sa_connect, 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(GET_SS_FAMILY(&sa_bind) == AF_UNSPEC)
+ 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 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
{
- if(GET_SS_FAMILY(&sa_connect) == GET_SS_FAMILY(&ServerInfo.bind4))
- sa_bind = ServerInfo.bind4;
-#ifdef RB_IPV6
- if(GET_SS_FAMILY(&sa_connect) == GET_SS_FAMILY(&ServerInfo.bind6))
- sa_bind = ServerInfo.bind6;
#endif
+ 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);
}
-
- rb_connect_tcp(client_p->localClient->F,
- (struct sockaddr *)&sa_connect,
- GET_SS_FAMILY(&sa_bind) == AF_UNSPEC ? NULL : (struct sockaddr *)&sa_bind,
- ServerConfSSL(server_p) ? serv_connect_ssl_callback : serv_connect_callback,
- client_p, ConfigFileEntry.connect_timeout);
return 1;
}
}
client_p->localClient->F = xF[0];
- client_p->localClient->ssl_callback = serv_connect_callback;
- client_p->localClient->ssl_data = data;
+ client_p->localClient->ssl_callback = serv_connect_ssl_open_callback;
client_p->localClient->ssl_ctl = start_ssld_connect(F, xF[1], connid_get(client_p));
if(!client_p->localClient->ssl_ctl)
SetSSL(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 */
+}
+
/*
* serv_connect_callback() - complete a server connection.
*
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
+ send_capabilities(client_p, default_server_capabs | CAP_MASK
| (ServerConfCompressed(server_p) ? CAP_ZIP_SUPPORTED : 0)
| (ServerConfTb(server_p) ? CAP_TB : 0));