Add outgoing SCTP connect support
This commit is contained in:
parent
c6ad9b0c5f
commit
6003ce763c
7 changed files with 174 additions and 41 deletions
|
@ -210,12 +210,14 @@ struct server_conf
|
|||
#define SERVER_AUTOCONN 0x0020
|
||||
#define SERVER_SSL 0x0040
|
||||
#define SERVER_NO_EXPORT 0x0080
|
||||
#define SERVER_SCTP 0x0100
|
||||
|
||||
#define ServerConfIllegal(x) ((x)->flags & SERVER_ILLEGAL)
|
||||
#define ServerConfEncrypted(x) ((x)->flags & SERVER_ENCRYPTED)
|
||||
#define ServerConfCompressed(x) ((x)->flags & SERVER_COMPRESSED)
|
||||
#define ServerConfTb(x) ((x)->flags & SERVER_TB)
|
||||
#define ServerConfAutoconn(x) ((x)->flags & SERVER_AUTOCONN)
|
||||
#define ServerConfSCTP(x) ((x)->flags & SERVER_SCTP)
|
||||
#define ServerConfSSL(x) ((x)->flags & SERVER_SSL)
|
||||
#define ServerConfNoExport(x) ((x)->flags & SERVER_NO_EXPORT)
|
||||
|
||||
|
|
|
@ -361,6 +361,7 @@ static struct mode_table connect_table[] = {
|
|||
{ "compressed", SERVER_COMPRESSED },
|
||||
{ "encrypted", SERVER_ENCRYPTED },
|
||||
{ "topicburst", SERVER_TB },
|
||||
{ "sctp", SERVER_SCTP },
|
||||
{ "ssl", SERVER_SSL },
|
||||
{ "no-export", SERVER_NO_EXPORT },
|
||||
{ NULL, 0 },
|
||||
|
|
101
ircd/s_serv.c
101
ircd/s_serv.c
|
@ -1031,8 +1031,8 @@ int
|
|||
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;
|
||||
|
||||
|
@ -1040,8 +1040,10 @@ serv_connect(struct server_conf *server_p, struct Client *by)
|
|||
if(server_p == NULL)
|
||||
return 0;
|
||||
|
||||
SET_SS_FAMILY(&sa_connect, AF_UNSPEC);
|
||||
SET_SS_FAMILY(&sa_bind, 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
|
||||
|
@ -1049,30 +1051,48 @@ serv_connect(struct server_conf *server_p, struct Client *by)
|
|||
{
|
||||
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)
|
||||
{
|
||||
sa_connect = server_p->connect4;
|
||||
sa_bind = server_p->bind4;
|
||||
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 = server_p->connect6;
|
||||
sa_bind = server_p->bind6;
|
||||
sa_connect[0] = server_p->connect6;
|
||||
sa_bind[0] = server_p->bind6;
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
@ -1099,13 +1119,17 @@ serv_connect(struct server_conf *server_p, struct Client *by)
|
|||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
@ -1126,7 +1150,8 @@ serv_connect(struct server_conf *server_p, struct Client *by)
|
|||
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
|
||||
|
@ -1161,19 +1186,31 @@ serv_connect(struct server_conf *server_p, struct Client *by)
|
|||
SetConnecting(client_p);
|
||||
rb_dlinkAddTail(client_p, &client_p->node, &global_client_list);
|
||||
|
||||
if(GET_SS_FAMILY(&sa_bind) == AF_UNSPEC)
|
||||
{
|
||||
if(GET_SS_FAMILY(&sa_connect) == GET_SS_FAMILY(&ServerInfo.bind4))
|
||||
sa_bind = ServerInfo.bind4;
|
||||
if(GET_SS_FAMILY(&sa_connect) == GET_SS_FAMILY(&ServerInfo.bind6))
|
||||
sa_bind = ServerInfo.bind6;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
#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
|
||||
{
|
||||
#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);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -126,6 +126,7 @@ void rb_settimeout(rb_fde_t *, time_t, PF *, void *);
|
|||
void rb_checktimeouts(void *);
|
||||
void rb_connect_tcp(rb_fde_t *, struct sockaddr *, struct sockaddr *, CNCB *, void *, int);
|
||||
void rb_connect_tcp_ssl(rb_fde_t *, struct sockaddr *, struct sockaddr *, CNCB *, void *, int);
|
||||
void rb_connect_sctp(rb_fde_t *, struct sockaddr_storage *connect_addrs, size_t connect_len, struct sockaddr_storage *bind_addrs, size_t bind_len, CNCB *, void *, int);
|
||||
int rb_connect_sockaddr(rb_fde_t *, struct sockaddr *addr, int len);
|
||||
|
||||
const char *rb_errstr(int status);
|
||||
|
|
|
@ -459,6 +459,25 @@ rb_bind(rb_fde_t *F, struct sockaddr *addr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBSCTP
|
||||
static int
|
||||
rb_sctp_bindx_only(rb_fde_t *F, struct sockaddr_storage *addrs, size_t len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
if (GET_SS_FAMILY(&addrs[i]) == AF_UNSPEC)
|
||||
continue;
|
||||
|
||||
ret = sctp_bindx(F->fd, (struct sockaddr *)&addrs[i], 1, SCTP_BINDX_ADD_ADDR);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
rb_sctp_bindx(rb_fde_t *F, struct sockaddr_storage *addrs, size_t len)
|
||||
{
|
||||
|
@ -472,14 +491,9 @@ rb_sctp_bindx(rb_fde_t *F, struct sockaddr_storage *addrs, size_t len)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
if (GET_SS_FAMILY(&addrs[i]) == AF_UNSPEC)
|
||||
continue;
|
||||
|
||||
ret = sctp_bindx(F->fd, (struct sockaddr *)&addrs[i], 1, SCTP_BINDX_ADD_ADDR);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
ret = rb_sctp_bindx_only(F, addrs, len);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
#else
|
||||
|
@ -647,6 +661,81 @@ rb_connect_tcp(rb_fde_t *F, struct sockaddr *dest,
|
|||
rb_connect_callback(F, RB_OK);
|
||||
}
|
||||
|
||||
void
|
||||
rb_connect_sctp(rb_fde_t *F, struct sockaddr_storage *dest, size_t dest_len,
|
||||
struct sockaddr_storage *clocal, size_t clocal_len,
|
||||
CNCB *callback, void *data, int timeout)
|
||||
{
|
||||
#ifdef HAVE_LIBSCTP
|
||||
uint8_t packed_dest[sizeof(struct sockaddr_storage) * dest_len];
|
||||
uint8_t *p = &packed_dest[0];
|
||||
size_t n = 0;
|
||||
int retval;
|
||||
|
||||
if (F == NULL)
|
||||
return;
|
||||
|
||||
lrb_assert(callback);
|
||||
F->connect = rb_malloc(sizeof(struct conndata));
|
||||
F->connect->callback = callback;
|
||||
F->connect->data = data;
|
||||
|
||||
if ((F->type & RB_FD_SCTP) == 0) {
|
||||
rb_connect_callback(F, RB_ERR_CONNECT);
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < dest_len; i++) {
|
||||
if (GET_SS_FAMILY(&dest[i]) == AF_INET6) {
|
||||
memcpy(p, &dest[i], sizeof(struct sockaddr_in6));
|
||||
n++;
|
||||
p += sizeof(struct sockaddr_in6);
|
||||
} else if (GET_SS_FAMILY(&dest[i]) == AF_INET) {
|
||||
memcpy(p, &dest[i], sizeof(struct sockaddr_in));
|
||||
n++;
|
||||
p += sizeof(struct sockaddr_in);
|
||||
}
|
||||
}
|
||||
dest_len = n;
|
||||
|
||||
memcpy(&F->connect->hostaddr, &dest[0], sizeof(F->connect->hostaddr));
|
||||
|
||||
if ((clocal_len > 0) && (rb_sctp_bindx_only(F, clocal, clocal_len) < 0)) {
|
||||
/* Failure, call the callback with RB_ERR_BIND */
|
||||
rb_connect_callback(F, RB_ERR_BIND);
|
||||
/* ... and quit */
|
||||
return;
|
||||
}
|
||||
|
||||
rb_settimeout(F, timeout, rb_connect_timeout, NULL);
|
||||
|
||||
retval = sctp_connectx(F->fd, (struct sockaddr *)packed_dest, dest_len, NULL);
|
||||
/* Error? */
|
||||
if (retval < 0) {
|
||||
/*
|
||||
* If we get EISCONN, then we've already connect()ed the socket,
|
||||
* which is a good thing.
|
||||
* -- adrian
|
||||
*/
|
||||
rb_get_errno();
|
||||
if (errno == EISCONN) {
|
||||
rb_connect_callback(F, RB_OK);
|
||||
} else if (rb_ignore_errno(errno)) {
|
||||
/* Ignore error? Reschedule */
|
||||
rb_setselect(F, RB_SELECT_CONNECT, rb_connect_outcome, NULL);
|
||||
} else {
|
||||
/* Error? Fail with RB_ERR_CONNECT */
|
||||
rb_connect_callback(F, RB_ERR_CONNECT);
|
||||
}
|
||||
return;
|
||||
}
|
||||
/* If we get here, we've succeeded, so call with RB_OK */
|
||||
rb_connect_callback(F, RB_OK);
|
||||
#else
|
||||
rb_connect_callback(F, RB_ERR_CONNECT);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* rb_connect_callback() - call the callback, and continue with life
|
||||
*/
|
||||
|
|
|
@ -18,6 +18,7 @@ rb_close
|
|||
rb_connect_sockaddr
|
||||
rb_connect_tcp
|
||||
rb_connect_tcp_ssl
|
||||
rb_connect_sctp
|
||||
rb_count_rb_linebuf_memory
|
||||
rb_crypt
|
||||
rb_ctime
|
||||
|
|
|
@ -315,7 +315,7 @@ stats_hash(struct Client *source_p)
|
|||
static void
|
||||
stats_connect(struct Client *source_p)
|
||||
{
|
||||
static char buf[5];
|
||||
static char buf[BUFSIZE];
|
||||
struct server_conf *server_p;
|
||||
char *s;
|
||||
rb_dlink_node *ptr;
|
||||
|
@ -342,6 +342,8 @@ stats_connect(struct Client *source_p)
|
|||
{
|
||||
if(ServerConfAutoconn(server_p))
|
||||
*s++ = 'A';
|
||||
if(ServerConfSCTP(server_p))
|
||||
*s++ = 'M';
|
||||
if(ServerConfSSL(server_p))
|
||||
*s++ = 'S';
|
||||
if(ServerConfTb(server_p))
|
||||
|
|
Loading…
Reference in a new issue