diff --git a/.gitignore b/.gitignore index b0faaa4e1..cf95ee57f 100644 --- a/.gitignore +++ b/.gitignore @@ -55,7 +55,6 @@ ircd/ircd_lexer.c ircd/version.c ircd/version.c.last ssld/ssld -wsockd/wsockd testsuite/ircd.pid.* tools/solanum-mkpasswd tools/solanum-mkfingerprint diff --git a/Makefile.am b/Makefile.am index 19e7b3966..282460c36 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,7 +9,6 @@ endif SUBDIRS += ircd \ ssld \ - wsockd \ authd \ bandb \ tests \ diff --git a/NEWS.md b/NEWS.md index 8da753b5c..e3970ca68 100644 --- a/NEWS.md +++ b/NEWS.md @@ -76,6 +76,7 @@ bolded warnings in the full release notes below. be disconnected on registration ### misc +- **Breaking:** WebSocket support has been removed. - **Breaking:** WEBIRC now processes the "secure" option as specified by IRCv3. Web gateways that do not set this option will need to be updated or their connections will show as insecure. - Successfully changing IP with WEBIRC now drops an identd username diff --git a/configure.ac b/configure.ac index 1651ef647..eff0bad96 100644 --- a/configure.ac +++ b/configure.ac @@ -624,7 +624,6 @@ AC_CONFIG_FILES( \ authd/Makefile \ bandb/Makefile \ ssld/Makefile \ - wsockd/Makefile \ extensions/Makefile \ ircd/Makefile \ modules/Makefile \ diff --git a/doc/ircd.conf.example b/doc/ircd.conf.example index a3c03984c..57dc8459b 100644 --- a/doc/ircd.conf.example +++ b/doc/ircd.conf.example @@ -160,12 +160,6 @@ listen { #host = "2001:db8:2::6"; #port = 5000, 6665 .. 6669; #sslport = 6697; - - /* wsock: listeners defined with this option enabled will be websocket listeners, - * and will not accept normal clients. - */ - wsock = yes; - sslport = 9999; }; /* auth {}: allow users to connect to the ircd (OLD I:) diff --git a/doc/reference.conf b/doc/reference.conf index b0f907a08..435ca45d5 100644 --- a/doc/reference.conf +++ b/doc/reference.conf @@ -336,12 +336,6 @@ listen { host = "2001:db8:2::6"; port = 7002; sslport = 9002; - - /* wsock: listeners defined with this option enabled will be websocket listeners, - * and will not accept normal clients. - */ - wsock = yes; - sslport = 9999; }; /* auth {}: allow users to connect to the ircd (OLD I:) */ diff --git a/include/client.h b/include/client.h index bf7ca79b5..b9823ad24 100644 --- a/include/client.h +++ b/include/client.h @@ -62,7 +62,6 @@ struct LocalUser; struct PreClient; struct ListClient; struct scache_entry; -struct ws_ctl; typedef int SSL_OPEN_CB(struct Client *, int status); @@ -264,7 +263,6 @@ struct LocalUser struct _ssl_ctl *ssl_ctl; /* which ssl daemon we're associate with */ struct _ssl_ctl *z_ctl; /* second ctl for ssl+zlib */ - struct ws_ctl *ws_ctl; /* ctl for wsockd */ SSL_OPEN_CB *ssl_callback; /* ssl connection is now open */ uint32_t localflags; uint16_t cork_count; /* used for corking/uncorking connections */ diff --git a/include/listener.h b/include/listener.h index f251e3146..0a679c98b 100644 --- a/include/listener.h +++ b/include/listener.h @@ -39,13 +39,12 @@ struct Listener int ssl; /* ssl listener */ int defer_accept; /* use TCP_DEFER_ACCEPT */ bool sctp; /* use SCTP */ - int wsock; /* wsock listener */ struct rb_sockaddr_storage addr[2]; char vhost[(HOSTLEN * 2) + 1]; /* virtual name of listener */ }; -extern void add_tcp_listener(int port, const char *vaddr_ip, int family, int ssl, int defer_accept, int wsock); -extern void add_sctp_listener(int port, const char *vaddr_ip1, const char *vaddr_ip2, int ssl, int wsock); +extern void add_tcp_listener(int port, const char *vaddr_ip, int family, int ssl, int defer_accept); +extern void add_sctp_listener(int port, const char *vaddr_ip1, const char *vaddr_ip2, int ssl); extern void close_listener(struct Listener *listener); extern void close_listeners(void); extern const char *get_listener_name(const struct Listener *listener); diff --git a/include/s_conf.h b/include/s_conf.h index cd50de438..5cb5bdf9f 100644 --- a/include/s_conf.h +++ b/include/s_conf.h @@ -323,7 +323,6 @@ struct server_info char *ssl_dh_params; char *ssl_cipher_list; int ssld_count; - int wsockd_count; }; struct admin_info diff --git a/include/wsproc.h b/include/wsproc.h deleted file mode 100644 index 08b58bb8f..000000000 --- a/include/wsproc.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * wsproc.h: An interface to the solanum websocket helper daemon - * Copyright (C) 2007 Aaron Sethman - * Copyright (C) 2007 ircd-ratbox development team - * Copyright (C) 2016 Ariadne Conill - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 - * USA - */ - -#ifndef INCLUDED_wsproc_h -#define INCLUDED_wsproc_h - -struct ws_ctl; -typedef struct ws_ctl ws_ctl_t; - -enum wsockd_status { - WSOCKD_ACTIVE, - WSOCKD_SHUTDOWN, - WSOCKD_DEAD, -}; - -void init_wsockd(void); -void restart_wsockd(void); -int start_wsockd(int count); -ws_ctl_t *start_wsockd_accept(rb_fde_t *wsF, rb_fde_t *plainF, uint32_t id); -void wsockd_decrement_clicount(ws_ctl_t *ctl); -int get_wsockd_count(void); -void wsockd_foreach_info(void (*func)(void *data, pid_t pid, int cli_count, enum wsockd_status status), void *data); - -#endif - diff --git a/ircd/Makefile.am b/ircd/Makefile.am index 4c0a0d24b..ec2c37870 100644 --- a/ircd/Makefile.am +++ b/ircd/Makefile.am @@ -59,8 +59,8 @@ libircd_la_SOURCES = \ supported.c \ tgchange.c \ version.c \ - whowas.c \ - wsproc.c + whowas.c + libircd_la_LDFLAGS = $(EXTRA_FLAGS) -avoid-version -no-undefined libircd_la_LIBADD = @LIBLTDL@ -L$(top_srcdir)/librb/src -lrb libircd_LTLIBRARIES = libircd.la diff --git a/ircd/client.c b/ircd/client.c index 9482b37c5..71905dc9d 100644 --- a/ircd/client.c +++ b/ircd/client.c @@ -51,7 +51,6 @@ #include "scache.h" #include "rb_dictionary.h" #include "sslproc.h" -#include "wsproc.h" #include "s_assert.h" #define DEBUG_EXITED_CLIENTS @@ -307,9 +306,6 @@ free_local_client(struct Client *client_p) rb_free(client_p->localClient->cipher_string); - if (client_p->localClient->ws_ctl != NULL) - wsockd_decrement_clicount(client_p->localClient->ws_ctl); - rb_bh_free(lclient_heap, client_p->localClient); client_p->localClient = NULL; } diff --git a/ircd/ircd.c b/ircd/ircd.c index 582964e8c..8b2aeee2f 100644 --- a/ircd/ircd.c +++ b/ircd/ircd.c @@ -59,7 +59,6 @@ #include "patchlevel.h" #include "serno.h" #include "sslproc.h" -#include "wsproc.h" #include "chmode.h" #include "privilege.h" #include "bandbi.h" @@ -668,7 +667,6 @@ solanum_main(int argc, char * const argv[]) init_bandb(); init_ssld(); - init_wsockd(); rehash_bans(); diff --git a/ircd/listener.c b/ircd/listener.c index 02b6dabdc..870f57d00 100644 --- a/ircd/listener.c +++ b/ircd/listener.c @@ -39,7 +39,6 @@ #include "reject.h" #include "hostmask.h" #include "sslproc.h" -#include "wsproc.h" #include "hash.h" #include "s_assert.h" #include "logger.h" @@ -285,7 +284,7 @@ find_listener(struct rb_sockaddr_storage *addr, int sctp) * the format "255.255.255.255" */ void -add_tcp_listener(int port, const char *vhost_ip, int family, int ssl, int defer_accept, int wsock) +add_tcp_listener(int port, const char *vhost_ip, int family, int ssl, int defer_accept) { struct Listener *listener; struct rb_sockaddr_storage vaddr[ARRAY_SIZE(listener->addr)]; @@ -347,7 +346,6 @@ add_tcp_listener(int port, const char *vhost_ip, int family, int ssl, int defer_ listener->ssl = ssl; listener->defer_accept = defer_accept; listener->sctp = 0; - listener->wsock = wsock; if (inetport(listener)) { listener->active = 1; @@ -362,7 +360,7 @@ add_tcp_listener(int port, const char *vhost_ip, int family, int ssl, int defer_ * vhost_ip1/2 - if non-null must contain a valid IP address string */ void -add_sctp_listener(int port, const char *vhost_ip1, const char *vhost_ip2, int ssl, int wsock) +add_sctp_listener(int port, const char *vhost_ip1, const char *vhost_ip2, int ssl) { struct Listener *listener; struct rb_sockaddr_storage vaddr[ARRAY_SIZE(listener->addr)]; @@ -417,7 +415,6 @@ add_sctp_listener(int port, const char *vhost_ip1, const char *vhost_ip2, int ss listener->ssl = ssl; listener->defer_accept = 0; listener->sctp = 1; - listener->wsock = wsock; if (inetport(listener)) { listener->active = 1; @@ -538,26 +535,6 @@ add_connection(struct Listener *listener, rb_fde_t *F, struct sockaddr *sai, str SetSecure(new_client); } - if (listener->wsock) - { - rb_fde_t *xF[2]; - if(rb_socketpair(AF_UNIX, SOCK_STREAM, 0, &xF[0], &xF[1], "Incoming wsockd Connection") == -1) - { - SetIOError(new_client); - exit_client(new_client, new_client, new_client, "Fatal Error"); - return; - } - new_client->localClient->ws_ctl = start_wsockd_accept(F, xF[1], connid_get(new_client)); /* this will close F for us */ - if(new_client->localClient->ws_ctl == NULL) - { - SetIOError(new_client); - exit_client(new_client, new_client, new_client, "Service Unavailable"); - return; - } - F = xF[0]; - new_client->localClient->F = F; - } - new_client->localClient->listener = listener; ++listener->ref_count; diff --git a/ircd/newconf.c b/ircd/newconf.c index 55a474d4f..99796eb31 100644 --- a/ircd/newconf.c +++ b/ircd/newconf.c @@ -30,7 +30,6 @@ #include "ircd.h" #include "snomask.h" #include "sslproc.h" -#include "wsproc.h" #include "privilege.h" #include "chmode.h" #include "certfp.h" @@ -38,7 +37,6 @@ #define CF_TYPE(x) ((x) & CF_MTYPE) static int yy_defer_accept = 1; -static int yy_wsock = 0; struct TopConf *conf_cur_block; static char *conf_cur_block_name = NULL; @@ -890,7 +888,6 @@ conf_begin_listen(struct TopConf *tc) rb_free(listener_address[i]); listener_address[i] = NULL; } - yy_wsock = 0; yy_defer_accept = 0; return 0; } @@ -902,7 +899,6 @@ conf_end_listen(struct TopConf *tc) rb_free(listener_address[i]); listener_address[i] = NULL; } - yy_wsock = 0; yy_defer_accept = 0; return 0; } @@ -913,12 +909,6 @@ conf_set_listen_defer_accept(void *data) yy_defer_accept = *(unsigned int *) data; } -static void -conf_set_listen_wsock(void *data) -{ - yy_wsock = *(unsigned int *) data; -} - static void conf_set_listen_port_both(void *data, int ssl, int sctp) { @@ -935,8 +925,8 @@ conf_set_listen_port_both(void *data, int ssl, int sctp) if (sctp) { conf_report_error("listener::sctp_port has no addresses -- ignoring."); } else { - add_tcp_listener(args->v.number, NULL, AF_INET, ssl, ssl || yy_defer_accept, yy_wsock); - add_tcp_listener(args->v.number, NULL, AF_INET6, ssl, ssl || yy_defer_accept, yy_wsock); + add_tcp_listener(args->v.number, NULL, AF_INET, ssl, ssl || yy_defer_accept); + add_tcp_listener(args->v.number, NULL, AF_INET6, ssl, ssl || yy_defer_accept); } } else @@ -949,12 +939,12 @@ conf_set_listen_port_both(void *data, int ssl, int sctp) if (sctp) { #ifdef HAVE_LIBSCTP - add_sctp_listener(args->v.number, listener_address[0], listener_address[1], ssl, yy_wsock); + add_sctp_listener(args->v.number, listener_address[0], listener_address[1], ssl); #else conf_report_error("Warning -- ignoring listener::sctp_port -- SCTP support not available."); #endif } else { - add_tcp_listener(args->v.number, listener_address[0], family, ssl, ssl || yy_defer_accept, yy_wsock); + add_tcp_listener(args->v.number, listener_address[0], family, ssl, ssl || yy_defer_accept); } } } @@ -2851,7 +2841,6 @@ newconf_init() add_top_conf("listen", conf_begin_listen, conf_end_listen, NULL); add_conf_item("listen", "defer_accept", CF_YESNO, conf_set_listen_defer_accept); - add_conf_item("listen", "wsock", CF_YESNO, conf_set_listen_wsock); add_conf_item("listen", "port", CF_INT | CF_FLIST, conf_set_listen_port); add_conf_item("listen", "sslport", CF_INT | CF_FLIST, conf_set_listen_sslport); add_conf_item("listen", "sctp_port", CF_INT | CF_FLIST, conf_set_listen_sctp_port); diff --git a/ircd/s_conf.c b/ircd/s_conf.c index 87f18785c..560d1ba7c 100644 --- a/ircd/s_conf.c +++ b/ircd/s_conf.c @@ -46,7 +46,6 @@ #include "cache.h" #include "privilege.h" #include "sslproc.h" -#include "wsproc.h" #include "bandbi.h" #include "operhash.h" #include "chmode.h" @@ -907,9 +906,6 @@ validate_conf(void) if(ServerInfo.ssld_count < 1) ServerInfo.ssld_count = 1; - /* XXX: configurable? */ - ServerInfo.wsockd_count = 1; - if(!rb_setup_ssl_server(ServerInfo.ssl_cert, ServerInfo.ssl_private_key, ServerInfo.ssl_dh_params, ServerInfo.ssl_cipher_list)) { ilog(L_MAIN, "WARNING: Unable to setup SSL."); @@ -926,12 +922,6 @@ validate_conf(void) start_ssldaemon(start); } - if(ServerInfo.wsockd_count > get_wsockd_count()) - { - int start = ServerInfo.wsockd_count - get_wsockd_count(); - start_wsockd(start); - } - /* General conf */ if (ConfigFileEntry.default_operstring == NULL) ConfigFileEntry.default_operstring = rb_strdup("is an IRC operator"); diff --git a/ircd/wsproc.c b/ircd/wsproc.c deleted file mode 100644 index 973826b10..000000000 --- a/ircd/wsproc.c +++ /dev/null @@ -1,583 +0,0 @@ -/* - * sslproc.c: An interface to wsockd - * Copyright (C) 2007 Aaron Sethman - * Copyright (C) 2007 ircd-ratbox development team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 - * USA - */ - -#include -#include "stdinc.h" - - -#include "s_conf.h" -#include "logger.h" -#include "listener.h" -#include "wsproc.h" -#include "s_serv.h" -#include "ircd.h" -#include "hash.h" -#include "client.h" -#include "send.h" -#include "packet.h" - -static void ws_read_ctl(rb_fde_t * F, void *data); -static int wsockd_count; - -#define MAXPASSFD 4 -#define READSIZE 1024 -typedef struct _ws_ctl_buf -{ - rb_dlink_node node; - char *buf; - size_t buflen; - rb_fde_t *F[MAXPASSFD]; - int nfds; -} ws_ctl_buf_t; - - -struct ws_ctl -{ - rb_dlink_node node; - int cli_count; - rb_fde_t *F; - rb_fde_t *P; - pid_t pid; - rb_dlink_list readq; - rb_dlink_list writeq; - uint8_t shutdown; - uint8_t dead; -}; - -static rb_dlink_list wsock_daemons; - -static inline uint32_t -buf_to_uint32(char *buf) -{ - uint32_t x; - memcpy(&x, buf, sizeof(x)); - return x; -} - -static inline void -uint32_to_buf(char *buf, uint32_t x) -{ - memcpy(buf, &x, sizeof(x)); - return; -} - -static ws_ctl_t * -allocate_ws_daemon(rb_fde_t * F, rb_fde_t * P, int pid) -{ - ws_ctl_t *ctl; - - if(F == NULL || pid < 0) - return NULL; - ctl = rb_malloc(sizeof(ws_ctl_t)); - ctl->F = F; - ctl->P = P; - ctl->pid = pid; - wsockd_count++; - rb_dlinkAdd(ctl, &ctl->node, &wsock_daemons); - return ctl; -} - -static void -free_ws_daemon(ws_ctl_t * ctl) -{ - rb_dlink_node *ptr; - ws_ctl_buf_t *ctl_buf; - int x; - if(ctl->cli_count) - return; - - RB_DLINK_FOREACH(ptr, ctl->readq.head) - { - ctl_buf = ptr->data; - for(x = 0; x < ctl_buf->nfds; x++) - rb_close(ctl_buf->F[x]); - - rb_free(ctl_buf->buf); - rb_free(ctl_buf); - } - - RB_DLINK_FOREACH(ptr, ctl->writeq.head) - { - ctl_buf = ptr->data; - for(x = 0; x < ctl_buf->nfds; x++) - rb_close(ctl_buf->F[x]); - - rb_free(ctl_buf->buf); - rb_free(ctl_buf); - } - rb_close(ctl->F); - rb_close(ctl->P); - rb_dlinkDelete(&ctl->node, &wsock_daemons); - rb_free(ctl); -} - -static char *wsockd_path; - -static int wsockd_spin_count = 0; -static time_t last_spin; -static int wsockd_wait = 0; - -void -restart_wsockd(void) -{ - rb_dlink_node *ptr, *next; - ws_ctl_t *ctl; - - RB_DLINK_FOREACH_SAFE(ptr, next, wsock_daemons.head) - { - ctl = ptr->data; - if(ctl->dead) - continue; - if(ctl->shutdown) - continue; - ctl->shutdown = 1; - wsockd_count--; - if(!ctl->cli_count) - { - rb_kill(ctl->pid, SIGKILL); - free_ws_daemon(ctl); - } - } - - start_wsockd(ServerInfo.wsockd_count); -} - -#if 0 -static void -ws_killall(void) -{ - rb_dlink_node *ptr, *next; - ws_ctl_t *ctl; - RB_DLINK_FOREACH_SAFE(ptr, next, wsock_daemons.head) - { - ctl = ptr->data; - if(ctl->dead) - continue; - ctl->dead = 1; - if(!ctl->shutdown) - wsockd_count--; - rb_kill(ctl->pid, SIGKILL); - if(!ctl->cli_count) - free_ws_daemon(ctl); - } -} -#endif - -static void -ws_dead(ws_ctl_t * ctl) -{ - if(ctl->dead) - return; - - ctl->dead = 1; - rb_kill(ctl->pid, SIGKILL); /* make sure the process is really gone */ - - if(!ctl->shutdown) - { - wsockd_count--; - ilog(L_MAIN, "wsockd helper died - attempting to restart"); - sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "wsockd helper died - attempting to restart"); - start_wsockd(1); - } -} - -static void -ws_do_pipe(rb_fde_t * F, void *data) -{ - int retlen; - ws_ctl_t *ctl = data; - retlen = rb_write(F, "0", 1); - if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno))) - { - ws_dead(ctl); - return; - } - rb_setselect(F, RB_SELECT_READ, ws_do_pipe, data); -} - -static void -restart_wsockd_event(void *unused) -{ - wsockd_spin_count = 0; - last_spin = 0; - wsockd_wait = 0; - if(ServerInfo.wsockd_count > get_wsockd_count()) - { - int start = ServerInfo.wsockd_count - get_wsockd_count(); - ilog(L_MAIN, "Attempting to restart wsockd processes"); - sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Attempting to restart wsockd processes"); - start_wsockd(start); - } -} - -int -start_wsockd(int count) -{ - rb_fde_t *F1, *F2; - rb_fde_t *P1, *P2; - char fullpath[PATH_MAX + 1]; - char fdarg[6]; - const char *parv[2]; - char buf[128]; - char s_pid[10]; - pid_t pid; - int started = 0, i; - - if(wsockd_wait) - return 0; - - if(wsockd_spin_count > 20 && (rb_current_time() - last_spin < 5)) - { - ilog(L_MAIN, "wsockd helper is spinning - will attempt to restart in 1 minute"); - sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, - "wsockd helper is spinning - will attempt to restart in 1 minute"); - rb_event_add("restart_wsockd_event", restart_wsockd_event, NULL, 60); - wsockd_wait = 1; - return 0; - } - - wsockd_spin_count++; - last_spin = rb_current_time(); - - if(wsockd_path == NULL) - { - snprintf(fullpath, sizeof(fullpath), "%s/wsockd", ircd_paths[IRCD_PATH_LIBEXEC]); - - if(access(fullpath, X_OK) == -1) - { - snprintf(fullpath, sizeof(fullpath), "%s/bin/wsockd", ConfigFileEntry.dpath); - if(access(fullpath, X_OK) == -1) - { - ilog(L_MAIN, - "Unable to execute wsockd in %s or %s/bin", - ircd_paths[IRCD_PATH_LIBEXEC], ConfigFileEntry.dpath); - return 0; - } - } - wsockd_path = rb_strdup(fullpath); - } - rb_strlcpy(buf, "-ircd wsockd daemon", sizeof(buf)); - parv[0] = buf; - parv[1] = NULL; - - for(i = 0; i < count; i++) - { - ws_ctl_t *ctl; - if(rb_socketpair(AF_UNIX, SOCK_DGRAM, 0, &F1, &F2, "wsockd handle passing socket") == -1) - { - ilog(L_MAIN, "Unable to create wsockd - rb_socketpair failed: %s", strerror(errno)); - return started; - } - - rb_set_buffers(F1, READBUF_SIZE); - rb_set_buffers(F2, READBUF_SIZE); - snprintf(fdarg, sizeof(fdarg), "%d", rb_get_fd(F2)); - rb_setenv("CTL_FD", fdarg, 1); - if(rb_pipe(&P1, &P2, "wsockd pipe") == -1) - { - ilog(L_MAIN, "Unable to create wsockd - rb_pipe failed: %s", strerror(errno)); - return started; - } - snprintf(fdarg, sizeof(fdarg), "%d", rb_get_fd(P1)); - rb_setenv("CTL_PIPE", fdarg, 1); - snprintf(s_pid, sizeof(s_pid), "%d", (int)getpid()); - rb_setenv("CTL_PPID", s_pid, 1); - - rb_clear_cloexec(F2); - rb_clear_cloexec(P1); - - pid = rb_spawn_process(wsockd_path, (const char **) parv); - if(pid == -1) - { - ilog(L_MAIN, "Unable to create wsockd: %s\n", strerror(errno)); - rb_close(F1); - rb_close(F2); - rb_close(P1); - rb_close(P2); - return started; - } - started++; - rb_close(F2); - rb_close(P1); - ctl = allocate_ws_daemon(F1, P2, pid); - ws_read_ctl(ctl->F, ctl); - ws_do_pipe(P2, ctl); - - } - ilog(L_MAIN, "wsockd helper started"); - sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "wsockd helper started"); - return started; -} - -static void -ws_process_dead_fd(ws_ctl_t * ctl, ws_ctl_buf_t * ctl_buf) -{ - struct Client *client_p; - char reason[256]; - uint32_t fd; - - if(ctl_buf->buflen < 6) - return; /* bogus message..drop it.. XXX should warn here */ - - fd = buf_to_uint32(&ctl_buf->buf[1]); - rb_strlcpy(reason, &ctl_buf->buf[5], sizeof(reason)); - client_p = find_cli_connid_hash(fd); - if(client_p == NULL) - return; - if(IsAnyServer(client_p) || IsRegistered(client_p)) - { - /* read any last moment ERROR, QUIT or the like -- jilles */ - if (!strcmp(reason, "Remote host closed the connection")) - read_packet(client_p->localClient->F, client_p); - if (IsAnyDead(client_p)) - return; - } - exit_client(client_p, client_p, &me, reason); -} - - -static void -ws_process_cmd_recv(ws_ctl_t * ctl) -{ - rb_dlink_node *ptr, *next; - ws_ctl_buf_t *ctl_buf; - - if(ctl->dead) - return; - - RB_DLINK_FOREACH_SAFE(ptr, next, ctl->readq.head) - { - ctl_buf = ptr->data; - switch (*ctl_buf->buf) - { - case 'D': - ws_process_dead_fd(ctl, ctl_buf); - break; - default: - ilog(L_MAIN, "Received invalid command from wsockd: %s", ctl_buf->buf); - sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Received invalid command from wsockd"); - break; - } - rb_dlinkDelete(ptr, &ctl->readq); - rb_free(ctl_buf->buf); - rb_free(ctl_buf); - } - -} - - -static void -ws_read_ctl(rb_fde_t * F, void *data) -{ - ws_ctl_buf_t *ctl_buf; - ws_ctl_t *ctl = data; - int retlen; - - if(ctl->dead) - return; - do - { - ctl_buf = rb_malloc(sizeof(ws_ctl_buf_t)); - ctl_buf->buf = rb_malloc(READSIZE); - retlen = rb_recv_fd_buf(ctl->F, ctl_buf->buf, READSIZE, ctl_buf->F, 4); - ctl_buf->buflen = retlen; - if(retlen <= 0) - { - rb_free(ctl_buf->buf); - rb_free(ctl_buf); - } - else - rb_dlinkAddTail(ctl_buf, &ctl_buf->node, &ctl->readq); - } - while(retlen > 0); - - if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno))) - { - ws_dead(ctl); - return; - } - ws_process_cmd_recv(ctl); - rb_setselect(ctl->F, RB_SELECT_READ, ws_read_ctl, ctl); -} - -static ws_ctl_t * -which_wsockd(void) -{ - ws_ctl_t *ctl, *lowest = NULL; - rb_dlink_node *ptr; - - RB_DLINK_FOREACH(ptr, wsock_daemons.head) - { - ctl = ptr->data; - if(ctl->dead) - continue; - if(ctl->shutdown) - continue; - if(lowest == NULL) - { - lowest = ctl; - continue; - } - if(ctl->cli_count < lowest->cli_count) - lowest = ctl; - } - - return (lowest); -} - -static void -ws_write_ctl(rb_fde_t * F, void *data) -{ - ws_ctl_t *ctl = data; - ws_ctl_buf_t *ctl_buf; - rb_dlink_node *ptr, *next; - int retlen, x; - - if(ctl->dead) - return; - - RB_DLINK_FOREACH_SAFE(ptr, next, ctl->writeq.head) - { - ctl_buf = ptr->data; - /* in theory unix sock_dgram shouldn't ever short write this.. */ - retlen = rb_send_fd_buf(ctl->F, ctl_buf->F, ctl_buf->nfds, ctl_buf->buf, ctl_buf->buflen, ctl->pid); - if(retlen > 0) - { - rb_dlinkDelete(ptr, &ctl->writeq); - for(x = 0; x < ctl_buf->nfds; x++) - rb_close(ctl_buf->F[x]); - rb_free(ctl_buf->buf); - rb_free(ctl_buf); - - } - if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno))) - { - ws_dead(ctl); - return; - } - else - { - rb_setselect(ctl->F, RB_SELECT_WRITE, ws_write_ctl, ctl); - } - } -} - -static void -ws_cmd_write_queue(ws_ctl_t * ctl, rb_fde_t ** F, int count, const void *buf, size_t buflen) -{ - ws_ctl_buf_t *ctl_buf; - int x; - - /* don't bother */ - if(ctl->dead) - return; - - ctl_buf = rb_malloc(sizeof(ws_ctl_buf_t)); - ctl_buf->buf = rb_malloc(buflen); - memcpy(ctl_buf->buf, buf, buflen); - ctl_buf->buflen = buflen; - - for(x = 0; x < count && x < MAXPASSFD; x++) - { - ctl_buf->F[x] = F[x]; - } - ctl_buf->nfds = count; - rb_dlinkAddTail(ctl_buf, &ctl_buf->node, &ctl->writeq); - ws_write_ctl(ctl->F, ctl); -} - -ws_ctl_t * -start_wsockd_accept(rb_fde_t * sslF, rb_fde_t * plainF, uint32_t id) -{ - rb_fde_t *F[2]; - ws_ctl_t *ctl; - char buf[5]; - F[0] = sslF; - F[1] = plainF; - - buf[0] = 'A'; - uint32_to_buf(&buf[1], id); - ctl = which_wsockd(); - if(!ctl) - return NULL; - ctl->cli_count++; - ws_cmd_write_queue(ctl, F, 2, buf, sizeof(buf)); - return ctl; -} - -void -wsockd_decrement_clicount(ws_ctl_t * ctl) -{ - if(ctl == NULL) - return; - - ctl->cli_count--; - if(ctl->shutdown && !ctl->cli_count) - { - ctl->dead = 1; - rb_kill(ctl->pid, SIGKILL); - } - if(ctl->dead && !ctl->cli_count) - { - free_ws_daemon(ctl); - } -} - -static void -cleanup_dead_ws(void *unused) -{ - rb_dlink_node *ptr, *next; - ws_ctl_t *ctl; - RB_DLINK_FOREACH_SAFE(ptr, next, wsock_daemons.head) - { - ctl = ptr->data; - if(ctl->dead && !ctl->cli_count) - { - free_ws_daemon(ctl); - } - } -} - -int -get_wsockd_count(void) -{ - return wsockd_count; -} - -void -wsockd_foreach_info(void (*func)(void *data, pid_t pid, int cli_count, enum wsockd_status status), void *data) -{ - rb_dlink_node *ptr, *next; - ws_ctl_t *ctl; - RB_DLINK_FOREACH_SAFE(ptr, next, wsock_daemons.head) - { - ctl = ptr->data; - func(data, ctl->pid, ctl->cli_count, - ctl->dead ? WSOCKD_DEAD : - (ctl->shutdown ? WSOCKD_SHUTDOWN : WSOCKD_ACTIVE)); - } -} - -void -init_wsockd(void) -{ - rb_event_addish("cleanup_dead_ws", cleanup_dead_ws, NULL, 60); -} diff --git a/tests/Makefile.am b/tests/Makefile.am index 2c958e6f8..3bac3099f 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -39,7 +39,6 @@ check-local: $(check_PROGRAMS) \ ../authd/authd \ ../bandb/bandb \ ../ssld/ssld \ - ../wsockd/wsockd \ $(patsubst ../modules/%.c,../modules/.libs/%.so,$(wildcard ../modules/*.c)) \ $(patsubst ../modules/core/%.c,../modules/core/.libs/%.so,$(wildcard ../modules/core/*.c)) diff --git a/tests/client_util.c b/tests/client_util.c index 322f3c567..75381a870 100644 --- a/tests/client_util.c +++ b/tests/client_util.c @@ -40,7 +40,6 @@ static struct Listener fake_listener = { .ssl = 1, .defer_accept = 0, .sctp = false, - .wsock = 0, .addr = { { .ss_family = AF_INET6 }, { .ss_family = AF_INET6 }, diff --git a/tests/runtime/bin/wsockd b/tests/runtime/bin/wsockd deleted file mode 120000 index 0331b1666..000000000 --- a/tests/runtime/bin/wsockd +++ /dev/null @@ -1 +0,0 @@ -../../../wsockd/wsockd \ No newline at end of file diff --git a/wsockd/Makefile.am b/wsockd/Makefile.am deleted file mode 100644 index 706600ead..000000000 --- a/wsockd/Makefile.am +++ /dev/null @@ -1,7 +0,0 @@ -pkglibexec_PROGRAMS = wsockd -AM_CFLAGS=$(WARNFLAGS) -AM_CPPFLAGS = -I../include -I../librb/include - - -wsockd_SOURCES = wsockd.c sha1.c -wsockd_LDADD = ../librb/src/librb.la diff --git a/wsockd/sha1.c b/wsockd/sha1.c deleted file mode 100644 index ba710affb..000000000 --- a/wsockd/sha1.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Based on the SHA-1 C implementation by Steve Reid - * 100% Public Domain - * - * Test Vectors (from FIPS PUB 180-1) - * "abc" - * A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D - * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" - * 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 - * A million repetitions of "a" - * 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F - */ - -#include "stdinc.h" -#include // for htonl() -#include "sha1.h" - -#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) - -// blk0() and blk() perform the initial expand. blk0() deals with host endianess -#define blk0(i) (block[i] = htonl(block[i])) -#define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15]^block[(i+2)&15]^block[i&15],1)) - -// (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1 -#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); -#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); -#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); - -// hash a single 512-bit block. this is the core of the algorithm -static uint32_t sha1_transform(SHA1 *sha1, const uint8_t buffer[SHA1_BLOCK_LENGTH]) { - uint32_t a, b, c, d, e; - uint32_t block[SHA1_BLOCK_LENGTH / 4]; - - memcpy(&block, buffer, SHA1_BLOCK_LENGTH); - - // copy sha1->state[] to working variables - a = sha1->state[0]; - b = sha1->state[1]; - c = sha1->state[2]; - d = sha1->state[3]; - e = sha1->state[4]; - - // 4 rounds of 20 operations each (loop unrolled) - R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); - R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); - R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); - R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); - R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); - - R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); - R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); - R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); - R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); - R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); - - R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); - R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); - R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); - R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); - R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); - - R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); - R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); - R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); - R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); - R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); - - // add the working variables back into sha1->state[] - sha1->state[0] += a; - sha1->state[1] += b; - sha1->state[2] += c; - sha1->state[3] += d; - sha1->state[4] += e; - - // wipe variables - a = b = c = d = e = 0; - - return a; // return a to avoid dead-store warning from clang static analyzer -} - -void sha1_init(SHA1 *sha1) { - sha1->state[0] = 0x67452301; - sha1->state[1] = 0xEFCDAB89; - sha1->state[2] = 0x98BADCFE; - sha1->state[3] = 0x10325476; - sha1->state[4] = 0xC3D2E1F0; - sha1->count = 0; -} - -void sha1_update(SHA1 *sha1, const uint8_t *data, size_t length) { - size_t i, j; - - j = (size_t)((sha1->count >> 3) & 63); - sha1->count += (length << 3); - - if ((j + length) > 63) { - i = 64 - j; - - memcpy(&sha1->buffer[j], data, i); - sha1_transform(sha1, sha1->buffer); - - for (; i + 63 < length; i += 64) { - sha1_transform(sha1, &data[i]); - } - - j = 0; - } else { - i = 0; - } - - memcpy(&sha1->buffer[j], &data[i], length - i); -} - -void sha1_final(SHA1 *sha1, uint8_t digest[SHA1_DIGEST_LENGTH]) { - uint32_t i; - uint8_t count[8]; - - for (i = 0; i < 8; i++) { - // this is endian independent - count[i] = (uint8_t)((sha1->count >> ((7 - (i & 7)) * 8)) & 255); - } - - sha1_update(sha1, (uint8_t *)"\200", 1); - - while ((sha1->count & 504) != 448) { - sha1_update(sha1, (uint8_t *)"\0", 1); - } - - sha1_update(sha1, count, 8); - - for (i = 0; i < SHA1_DIGEST_LENGTH; i++) { - digest[i] = (uint8_t)((sha1->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); - } - - memset(sha1, 0, sizeof(*sha1)); -} diff --git a/wsockd/sha1.h b/wsockd/sha1.h deleted file mode 100644 index cdd7d0823..000000000 --- a/wsockd/sha1.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Based on the SHA-1 C implementation by Steve Reid - * 100% Public Domain - */ - -#ifndef SHA1_H -#define SHA1_H - -#include -#include - -#define SHA1_BLOCK_LENGTH 64 -#define SHA1_DIGEST_LENGTH 20 - -typedef struct { - uint32_t state[5]; - uint64_t count; - uint8_t buffer[SHA1_BLOCK_LENGTH]; -} SHA1; - -void sha1_init(SHA1 *sha1); -void sha1_update(SHA1 *sha1, const uint8_t *data, size_t length); -void sha1_final(SHA1 *sha1, uint8_t digest[SHA1_DIGEST_LENGTH]); - -#endif // SHA1_H diff --git a/wsockd/wsockd.c b/wsockd/wsockd.c deleted file mode 100644 index 66fa4efc2..000000000 --- a/wsockd/wsockd.c +++ /dev/null @@ -1,1003 +0,0 @@ -/* - * wsockd.c: solanum websockets helper - * Copyright (C) 2007 Aaron Sethman - * Copyright (C) 2007 ircd-ratbox development team - * Copyright (C) 2016 Ariadne Conill - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 - * USA - */ - -#include "stdinc.h" -#include "sha1.h" - -#define MAXPASSFD 4 -#ifndef READBUF_SIZE -#define READBUF_SIZE 16384 -#endif - -#define WEBSOCKET_SERVER_KEY "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" -#define WEBSOCKET_ANSWER_STRING_1 "HTTP/1.1 101 Switching Protocols\r\nAccess-Control-Allow-Origin: *\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: " -#define WEBSOCKET_ANSWER_STRING_2 "\r\n\r\n" - -static void setup_signals(void); -static pid_t ppid; - -static inline uint32_t -buf_to_uint32(uint8_t *buf) -{ - uint32_t x; - memcpy(&x, buf, sizeof(x)); - return x; -} - -static inline void -uint32_to_buf(uint8_t *buf, uint32_t x) -{ - memcpy(buf, &x, sizeof(x)); - return; -} - -typedef struct _mod_ctl_buf -{ - rb_dlink_node node; - uint8_t *buf; - size_t buflen; - rb_fde_t *F[MAXPASSFD]; - int nfds; -} mod_ctl_buf_t; - -typedef struct _mod_ctl -{ - rb_dlink_node node; - int cli_count; - rb_fde_t *F; - rb_fde_t *F_pipe; - rb_dlink_list readq; - rb_dlink_list writeq; -} mod_ctl_t; - -static mod_ctl_t *mod_ctl; - -typedef struct _conn -{ - rb_dlink_node node; - mod_ctl_t *ctl; - - rawbuf_head_t *modbuf_out; - rawbuf_head_t *modbuf_in; - - buf_head_t plainbuf_out; - buf_head_t plainbuf_in; - - uint32_t id; - - rb_fde_t *mod_fd; - rb_fde_t *plain_fd; - uint64_t mod_out; - uint64_t mod_in; - uint64_t plain_in; - uint64_t plain_out; - uint8_t flags; - - char client_key[37]; /* maximum 36 bytes + nul */ -} conn_t; - -#define WEBSOCKET_OPCODE_TEXT_FRAME 1 - -#define WEBSOCKET_MASK_LENGTH 4 - -#define WEBSOCKET_MAX_UNEXTENDED_PAYLOAD_DATA_LENGTH 125 - -typedef struct { - uint8_t opcode_rsv_fin; // opcode: 4, rsv1: 1, rsv2: 1, rsv3: 1, fin: 1 - uint8_t payload_length_mask; // payload_length: 7, mask: 1 -} ws_frame_hdr_t; - -#define WEBSOCKET_FRAME_HDR_INIT ((ws_frame_hdr_t) { 0, 0 }) - -typedef struct { - ws_frame_hdr_t header; - uint8_t payload_data[WEBSOCKET_MAX_UNEXTENDED_PAYLOAD_DATA_LENGTH]; -} ws_frame_payload_t; - -typedef struct { - ws_frame_hdr_t header; -} ws_frame_t; - -typedef struct { - ws_frame_hdr_t header; - uint16_t payload_length_extended; -} ws_frame_ext_t; - -#define WEBSOCKET_FRAME_EXT_INIT ((ws_frame_ext_t) { WEBSOCKET_FRAME_HDR_INIT, 0 }) - -typedef struct { - ws_frame_hdr_t header; - uint64_t payload_length_extended; -} ws_frame_ext2_t; - -static inline void -ws_frame_set_opcode(ws_frame_hdr_t *header, int opcode) -{ - header->opcode_rsv_fin &= ~0xF; - header->opcode_rsv_fin |= opcode & 0xF; -} - -static inline void -ws_frame_set_fin(ws_frame_hdr_t *header, int fin) -{ - header->opcode_rsv_fin &= ~(0x1 << 7); - header->opcode_rsv_fin |= (fin << 7) & (0x1 << 7); -} - -static void close_conn(conn_t * conn, int wait_plain, const char *fmt, ...); -static void conn_mod_read_cb(rb_fde_t *fd, void *data); -static void conn_plain_read_cb(rb_fde_t *fd, void *data); -static void conn_plain_process_recvq(conn_t *conn); - -#define FLAG_CORK 0x01 -#define FLAG_DEAD 0x02 -#define FLAG_WSOCK 0x04 -#define FLAG_KEYED 0x08 - -#define IsCork(x) ((x)->flags & FLAG_CORK) -#define IsDead(x) ((x)->flags & FLAG_DEAD) -#define IsKeyed(x) ((x)->flags & FLAG_KEYED) - -#define SetCork(x) ((x)->flags |= FLAG_CORK) -#define SetDead(x) ((x)->flags |= FLAG_DEAD) -#define SetWS(x) ((x)->flags |= FLAG_WSOCK) -#define SetKeyed(x) ((x)->flags |= FLAG_KEYED) - -#define ClearCork(x) ((x)->flags &= ~FLAG_CORK) - -#define NO_WAIT 0x0 -#define WAIT_PLAIN 0x1 - -#define CONN_HASH_SIZE 2000 -#define connid_hash(x) (&connid_hash_table[(x % CONN_HASH_SIZE)]) - -static const char *remote_closed = "Remote host closed the connection"; - -static rb_dlink_list connid_hash_table[CONN_HASH_SIZE]; -static rb_dlink_list dead_list; - -static void conn_plain_read_shutdown_cb(rb_fde_t *fd, void *data); - -static void -dummy_handler(int sig) -{ - return; -} - -static void -setup_signals() -{ - struct sigaction act; - - act.sa_flags = 0; - act.sa_handler = SIG_IGN; - sigemptyset(&act.sa_mask); - sigaddset(&act.sa_mask, SIGPIPE); - sigaddset(&act.sa_mask, SIGALRM); -#ifdef SIGTRAP - sigaddset(&act.sa_mask, SIGTRAP); -#endif - -#ifdef SIGWINCH - sigaddset(&act.sa_mask, SIGWINCH); - sigaction(SIGWINCH, &act, 0); -#endif - sigaction(SIGPIPE, &act, 0); -#ifdef SIGTRAP - sigaction(SIGTRAP, &act, 0); -#endif - - act.sa_handler = dummy_handler; - sigaction(SIGALRM, &act, 0); -} - -static int -maxconn(void) -{ - struct rlimit limit; - - if(!getrlimit(RLIMIT_NOFILE, &limit)) - { - return limit.rlim_cur; - } - return MAXCONNECTIONS; -} - -static void -conn_add_id_hash(conn_t * conn, uint32_t id) -{ - conn->id = id; - rb_dlinkAdd(conn, &conn->node, connid_hash(id)); -} - -static void -free_conn(conn_t * conn) -{ - rb_linebuf_donebuf(&conn->plainbuf_in); - rb_linebuf_donebuf(&conn->plainbuf_out); - - rb_free_rawbuffer(conn->modbuf_in); - rb_free_rawbuffer(conn->modbuf_out); - - rb_free(conn); -} - -static void -clean_dead_conns(void *unused) -{ - conn_t *conn; - rb_dlink_node *ptr, *next; - - RB_DLINK_FOREACH_SAFE(ptr, next, dead_list.head) - { - conn = ptr->data; - free_conn(conn); - } - - dead_list.tail = dead_list.head = NULL; -} - -static void -conn_plain_write_sendq(rb_fde_t *fd, void *data) -{ - conn_t *conn = data; - int retlen; - - if(IsDead(conn)) - return; - - while((retlen = rb_linebuf_flush(fd, &conn->plainbuf_out)) > 0) - conn->plain_out += retlen; - - if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno))) - { - close_conn(data, NO_WAIT, NULL); - return; - } - - if(rb_linebuf_alloclen(&conn->plainbuf_out) > 0) - rb_setselect(conn->plain_fd, RB_SELECT_WRITE, conn_plain_write_sendq, conn); - else - rb_setselect(conn->plain_fd, RB_SELECT_WRITE, NULL, NULL); -} - -static void -conn_mod_write_sendq(rb_fde_t *fd, void *data) -{ - conn_t *conn = data; - const char *err; - int retlen; - - if(IsDead(conn)) - return; - - while((retlen = rb_rawbuf_flush(conn->modbuf_out, fd)) > 0) - conn->mod_out += retlen; - - if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno))) - { - if(retlen == 0) - close_conn(conn, WAIT_PLAIN, "%s", remote_closed); - err = strerror(errno); - close_conn(conn, WAIT_PLAIN, "Write error: %s", err); - return; - } - - if(rb_rawbuf_length(conn->modbuf_out) > 0) - rb_setselect(conn->mod_fd, RB_SELECT_WRITE, conn_mod_write_sendq, conn); - else - rb_setselect(conn->mod_fd, RB_SELECT_WRITE, NULL, NULL); - - if(IsCork(conn) && rb_rawbuf_length(conn->modbuf_out) == 0) - { - ClearCork(conn); - conn_plain_read_cb(conn->plain_fd, conn); - } -} - -static void -conn_mod_write(conn_t * conn, void *data, size_t len) -{ - if(IsDead(conn)) /* no point in queueing to a dead man */ - return; - rb_rawbuf_append(conn->modbuf_out, data, len); -} - -static void -conn_mod_write_short_frame(conn_t * conn, void *data, int len) -{ - ws_frame_hdr_t hdr = WEBSOCKET_FRAME_HDR_INIT; - - ws_frame_set_opcode(&hdr, WEBSOCKET_OPCODE_TEXT_FRAME); - ws_frame_set_fin(&hdr, 1); - hdr.payload_length_mask = (len + 2) & 0x7f; - - conn_mod_write(conn, &hdr, sizeof(hdr)); - conn_mod_write(conn, data, len); - conn_mod_write(conn, "\r\n", 2); -} - -static void -conn_mod_write_long_frame(conn_t * conn, void *data, int len) -{ - ws_frame_ext_t hdr = WEBSOCKET_FRAME_EXT_INIT; - - ws_frame_set_opcode(&hdr.header, WEBSOCKET_OPCODE_TEXT_FRAME); - ws_frame_set_fin(&hdr.header, 1); - hdr.header.payload_length_mask = 126; - hdr.payload_length_extended = htons(len + 2); - - conn_mod_write(conn, &hdr, sizeof(hdr)); - conn_mod_write(conn, data, len); - conn_mod_write(conn, "\r\n", 2); -} - -static void -conn_mod_write_frame(conn_t *conn, void *data, int len) -{ - if(IsDead(conn)) /* no point in queueing to a dead man */ - return; - - if (len < 123) - { - conn_mod_write_short_frame(conn, data, len); - return; - } - - conn_mod_write_long_frame(conn, data, len); -} - -static void -mod_write_ctl(rb_fde_t *F, void *data) -{ - mod_ctl_t *ctl = data; - mod_ctl_buf_t *ctl_buf; - rb_dlink_node *ptr, *next; - int retlen, x; - - RB_DLINK_FOREACH_SAFE(ptr, next, ctl->writeq.head) - { - ctl_buf = ptr->data; - retlen = rb_send_fd_buf(ctl->F, ctl_buf->F, ctl_buf->nfds, ctl_buf->buf, - ctl_buf->buflen, ppid); - if(retlen > 0) - { - rb_dlinkDelete(ptr, &ctl->writeq); - for(x = 0; x < ctl_buf->nfds; x++) - rb_close(ctl_buf->F[x]); - rb_free(ctl_buf->buf); - rb_free(ctl_buf); - - } - if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno))) - exit(0); - - } - if(rb_dlink_list_length(&ctl->writeq) > 0) - rb_setselect(ctl->F, RB_SELECT_WRITE, mod_write_ctl, ctl); -} - -static void -mod_cmd_write_queue(mod_ctl_t * ctl, const void *data, size_t len) -{ - mod_ctl_buf_t *ctl_buf; - ctl_buf = rb_malloc(sizeof(mod_ctl_buf_t)); - ctl_buf->buf = rb_malloc(len); - ctl_buf->buflen = len; - memcpy(ctl_buf->buf, data, len); - ctl_buf->nfds = 0; - rb_dlinkAddTail(ctl_buf, &ctl_buf->node, &ctl->writeq); - mod_write_ctl(ctl->F, ctl); -} - -static void -close_conn(conn_t * conn, int wait_plain, const char *fmt, ...) -{ - va_list ap; - char reason[128]; /* must always be under 250 bytes */ - uint8_t buf[256]; - int len; - if(IsDead(conn)) - return; - - if (IsKeyed(conn)) - conn_plain_process_recvq(conn); - - rb_rawbuf_flush(conn->modbuf_out, conn->mod_fd); - rb_linebuf_flush(conn->plain_fd, &conn->plainbuf_out); - rb_close(conn->mod_fd); - SetDead(conn); - - rb_dlinkDelete(&conn->node, connid_hash(conn->id)); - - if(!wait_plain || fmt == NULL) - { - rb_close(conn->plain_fd); - rb_dlinkAdd(conn, &conn->node, &dead_list); - return; - } - - rb_setselect(conn->plain_fd, RB_SELECT_READ, conn_plain_read_shutdown_cb, conn); - rb_setselect(conn->plain_fd, RB_SELECT_WRITE, NULL, NULL); - - va_start(ap, fmt); - vsnprintf(reason, sizeof(reason), fmt, ap); - va_end(ap); - - buf[0] = 'D'; - uint32_to_buf(&buf[1], conn->id); - rb_strlcpy((char *) &buf[5], reason, sizeof(buf) - 5); - len = (strlen(reason) + 1) + 5; - mod_cmd_write_queue(conn->ctl, buf, len); -} - -static conn_t * -make_conn(mod_ctl_t * ctl, rb_fde_t *mod_fd, rb_fde_t *plain_fd) -{ - conn_t *conn = rb_malloc(sizeof(conn_t)); - conn->ctl = ctl; - conn->mod_fd = mod_fd; - conn->plain_fd = plain_fd; - conn->id = -1; - rb_set_nb(mod_fd); - rb_set_nb(plain_fd); - - rb_linebuf_newbuf(&conn->plainbuf_in); - rb_linebuf_newbuf(&conn->plainbuf_out); - - conn->modbuf_in = rb_new_rawbuffer(); - conn->modbuf_out = rb_new_rawbuffer(); - - return conn; -} - -static void -cleanup_bad_message(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) -{ - int i; - - /* XXX should log this somehow */ - for (i = 0; i < ctlb->nfds; i++) - rb_close(ctlb->F[i]); -} - -static void -ws_frame_unmask(char *msg, int length, uint8_t maskval[WEBSOCKET_MASK_LENGTH]) -{ - int i; - - for (i = 0; i < length; i++) - msg[i] = msg[i] ^ maskval[i % 4]; -} - -static void -conn_mod_process_frame(conn_t *conn, ws_frame_hdr_t *hdr, int masked) -{ - char msg[WEBSOCKET_MAX_UNEXTENDED_PAYLOAD_DATA_LENGTH]; - uint8_t maskval[WEBSOCKET_MASK_LENGTH]; - int dolen; - - /* if we're masked, we get to collect the masking key for this frame */ - if (masked) - { - dolen = rb_rawbuf_get(conn->modbuf_in, maskval, sizeof(maskval)); - if (!dolen) - { - close_conn(conn, WAIT_PLAIN, "websocket error: fault unpacking unmask key"); - return; - } - } - - dolen = rb_rawbuf_get(conn->modbuf_in, msg, hdr->payload_length_mask); - if (!dolen) - { - close_conn(conn, WAIT_PLAIN, "websocket error: fault unpacking message"); - return; - } - - if (masked) - ws_frame_unmask(msg, dolen, maskval); - - rb_linebuf_parse(&conn->plainbuf_out, msg, dolen, 1); -} - -static void -conn_mod_process_large(conn_t *conn, ws_frame_hdr_t *hdr, int masked) -{ - char msg[READBUF_SIZE]; - uint16_t msglen; - uint8_t maskval[WEBSOCKET_MASK_LENGTH]; - int dolen; - - memset(msg, 0, sizeof msg); - - dolen = rb_rawbuf_get(conn->modbuf_in, &msglen, sizeof(msglen)); - if (!dolen) - { - close_conn(conn, WAIT_PLAIN, "websocket error: fault unpacking message size"); - return; - } - - msglen = ntohs(msglen); - - if (masked) - { - dolen = rb_rawbuf_get(conn->modbuf_in, maskval, sizeof(maskval)); - if (!dolen) - { - close_conn(conn, WAIT_PLAIN, "websocket error: fault unpacking unmask key"); - return; - } - } - - dolen = rb_rawbuf_get(conn->modbuf_in, msg, msglen); - if (!dolen) - { - close_conn(conn, WAIT_PLAIN, "websocket error: fault unpacking message"); - return; - } - - if (masked) - ws_frame_unmask(msg, dolen, maskval); - - rb_linebuf_parse(&conn->plainbuf_out, msg, dolen, 1); -} - -static void -conn_mod_process_huge(conn_t *conn, ws_frame_hdr_t *hdr, int masked) -{ - /* XXX implement me */ -} - -static void -conn_mod_process(conn_t *conn) -{ - ws_frame_hdr_t hdr; - - while (1) - { - int masked; - int dolen = rb_rawbuf_get(conn->modbuf_in, &hdr, sizeof(hdr)); - if (dolen != sizeof(hdr)) - break; - - masked = (hdr.payload_length_mask >> 7) == 1; - - hdr.payload_length_mask &= 0x7f; - switch (hdr.payload_length_mask) - { - case 126: - conn_mod_process_large(conn, &hdr, masked); - break; - case 127: - conn_mod_process_huge(conn, &hdr, masked); - break; - default: - conn_mod_process_frame(conn, &hdr, masked); - break; - } - } - - conn_plain_write_sendq(conn->plain_fd, conn); -} - -static void -conn_mod_handshake_process(conn_t *conn) -{ - char inbuf[READBUF_SIZE]; - - memset(inbuf, 0, sizeof inbuf); - - while (1) - { - char *p = NULL; - - int dolen = rb_rawbuf_get(conn->modbuf_in, inbuf, sizeof inbuf); - if (!dolen) - break; - - if ((p = rb_strcasestr(inbuf, "Sec-WebSocket-Key:")) != NULL) - { - char *start, *end; - - start = p + strlen("Sec-WebSocket-Key:"); - - for (; start < (inbuf + READBUF_SIZE) && *start; start++) - { - if (*start != ' ' && *start != '\t') - break; - } - - for (end = start; end < (inbuf + READBUF_SIZE) && *end; end++) - { - if (*end == '\r' || *end == '\n') - { - *end = '\0'; - break; - } - } - - rb_strlcpy(conn->client_key, start, sizeof(conn->client_key)); - SetKeyed(conn); - } - } - - if (IsKeyed(conn)) - { - SHA1 sha1; - uint8_t digest[SHA1_DIGEST_LENGTH]; - char *resp; - - sha1_init(&sha1); - sha1_update(&sha1, (uint8_t *) conn->client_key, strlen(conn->client_key)); - sha1_update(&sha1, (uint8_t *) WEBSOCKET_SERVER_KEY, strlen(WEBSOCKET_SERVER_KEY)); - sha1_final(&sha1, digest); - - resp = (char *) rb_base64_encode(digest, SHA1_DIGEST_LENGTH); - - conn_mod_write(conn, WEBSOCKET_ANSWER_STRING_1, strlen(WEBSOCKET_ANSWER_STRING_1)); - conn_mod_write(conn, resp, strlen(resp)); - conn_mod_write(conn, WEBSOCKET_ANSWER_STRING_2, strlen(WEBSOCKET_ANSWER_STRING_2)); - - rb_free(resp); - } - - conn_mod_write_sendq(conn->mod_fd, conn); -} - -static void -conn_mod_read_cb(rb_fde_t *fd, void *data) -{ - char inbuf[READBUF_SIZE]; - - memset(inbuf, 0, sizeof inbuf); - - conn_t *conn = data; - int length = 0; - if (conn == NULL) - return; - - if (IsDead(conn)) - return; - - while (1) - { - if (IsDead(conn)) - return; - - length = rb_read(fd, inbuf, sizeof(inbuf)); - - if (length < 0) - { - if (rb_ignore_errno(errno)) - { - rb_setselect(fd, RB_SELECT_READ, conn_mod_read_cb, conn); - conn_plain_write_sendq(conn->plain_fd, conn); - } - else - close_conn(conn, NO_WAIT, "Connection closed"); - - return; - } - else if (length == 0) - { - close_conn(conn, NO_WAIT, "Connection closed"); - return; - } - - rb_rawbuf_append(conn->modbuf_in, inbuf, length); - if (!IsKeyed(conn)) - conn_mod_handshake_process(conn); - else - conn_mod_process(conn); - - if ((size_t) length < sizeof(inbuf)) - { - rb_setselect(fd, RB_SELECT_READ, conn_mod_read_cb, conn); - return; - } - } -} - -static bool -plain_check_cork(conn_t * conn) -{ - if(rb_rawbuf_length(conn->modbuf_out) >= 4096) - { - /* if we have over 4k pending outbound, don't read until - * we've cleared the queue */ - SetCork(conn); - rb_setselect(conn->plain_fd, RB_SELECT_READ, NULL, NULL); - /* try to write */ - if (IsKeyed(conn)) - conn_mod_write_sendq(conn->mod_fd, conn); - return true; - } - - return false; -} - -static void -conn_plain_process_recvq(conn_t *conn) -{ - char inbuf[READBUF_SIZE]; - - memset(inbuf, 0, sizeof inbuf); - - while (1) - { - int dolen = rb_linebuf_get(&conn->plainbuf_in, inbuf, sizeof inbuf, LINEBUF_COMPLETE, LINEBUF_PARSED); - if (!dolen) - break; - - conn_mod_write_frame(conn, inbuf, dolen); - } - - if (IsKeyed(conn)) - conn_mod_write_sendq(conn->mod_fd, conn); -} - -static void -conn_plain_read_cb(rb_fde_t *fd, void *data) -{ - char inbuf[READBUF_SIZE]; - - memset(inbuf, 0, sizeof inbuf); - - conn_t *conn = data; - int length = 0; - if(conn == NULL) - return; - - if(IsDead(conn)) - return; - - if(plain_check_cork(conn)) - return; - - while(1) - { - if(IsDead(conn)) - return; - - length = rb_read(conn->plain_fd, inbuf, sizeof(inbuf)); - - if(length == 0 || (length < 0 && !rb_ignore_errno(errno))) - { - close_conn(conn, NO_WAIT, NULL); - return; - } - - if(length < 0) - { - rb_setselect(conn->plain_fd, RB_SELECT_READ, conn_plain_read_cb, conn); - if (IsKeyed(conn)) - conn_plain_process_recvq(conn); - return; - } - conn->plain_in += length; - - (void) rb_linebuf_parse(&conn->plainbuf_in, inbuf, length, 0); - - if(IsDead(conn)) - return; - if(plain_check_cork(conn)) - return; - } -} - -static void -conn_plain_read_shutdown_cb(rb_fde_t *fd, void *data) -{ - char inbuf[READBUF_SIZE]; - conn_t *conn = data; - int length = 0; - - if(conn == NULL) - return; - - while(1) - { - length = rb_read(conn->plain_fd, inbuf, sizeof(inbuf)); - - if(length == 0 || (length < 0 && !rb_ignore_errno(errno))) - { - rb_close(conn->plain_fd); - rb_dlinkAdd(conn, &conn->node, &dead_list); - return; - } - - if(length < 0) - { - rb_setselect(conn->plain_fd, RB_SELECT_READ, conn_plain_read_shutdown_cb, conn); - return; - } - } -} - -static void -wsock_process(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) -{ - conn_t *conn; - uint32_t id; - - conn = make_conn(ctl, ctlb->F[0], ctlb->F[1]); - - id = buf_to_uint32(&ctlb->buf[1]); - conn_add_id_hash(conn, id); - SetWS(conn); - - if(rb_get_type(conn->mod_fd) & RB_FD_UNKNOWN) - rb_set_type(conn->mod_fd, RB_FD_SOCKET); - - if(rb_get_type(conn->plain_fd) == RB_FD_UNKNOWN) - rb_set_type(conn->plain_fd, RB_FD_SOCKET); - - conn_mod_read_cb(conn->mod_fd, conn); - conn_plain_read_cb(conn->plain_fd, conn); -} - -static void -mod_process_cmd_recv(mod_ctl_t * ctl) -{ - rb_dlink_node *ptr, *next; - mod_ctl_buf_t *ctl_buf; - - RB_DLINK_FOREACH_SAFE(ptr, next, ctl->readq.head) - { - ctl_buf = ptr->data; - - switch (*ctl_buf->buf) - { - case 'A': - { - if (ctl_buf->nfds != 2 || ctl_buf->buflen != 5) - { - cleanup_bad_message(ctl, ctl_buf); - break; - } - wsock_process(ctl, ctl_buf); - break; - } - default: - break; - /* Log unknown commands */ - } - rb_dlinkDelete(ptr, &ctl->readq); - rb_free(ctl_buf->buf); - rb_free(ctl_buf); - } - -} - -static void -mod_read_ctl(rb_fde_t *F, void *data) -{ - mod_ctl_buf_t *ctl_buf; - mod_ctl_t *ctl = data; - int retlen; - int i; - - do - { - ctl_buf = rb_malloc(sizeof(mod_ctl_buf_t)); - ctl_buf->buf = rb_malloc(READBUF_SIZE); - ctl_buf->buflen = READBUF_SIZE; - retlen = rb_recv_fd_buf(ctl->F, ctl_buf->buf, ctl_buf->buflen, ctl_buf->F, - MAXPASSFD); - if(retlen <= 0) - { - rb_free(ctl_buf->buf); - rb_free(ctl_buf); - } - else - { - ctl_buf->buflen = retlen; - rb_dlinkAddTail(ctl_buf, &ctl_buf->node, &ctl->readq); - for (i = 0; i < MAXPASSFD && ctl_buf->F[i] != NULL; i++) - ; - ctl_buf->nfds = i; - } - } - while(retlen > 0); - - if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno))) - exit(0); - - mod_process_cmd_recv(ctl); - rb_setselect(ctl->F, RB_SELECT_READ, mod_read_ctl, ctl); -} - -static void -read_pipe_ctl(rb_fde_t *F, void *data) -{ - char inbuf[READBUF_SIZE]; - int retlen; - while((retlen = rb_read(F, inbuf, sizeof(inbuf))) > 0) - { - ;; /* we don't do anything with the pipe really, just care if the other process dies.. */ - } - if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno))) - exit(0); - rb_setselect(F, RB_SELECT_READ, read_pipe_ctl, NULL); -} - -int -main(int argc, char **argv) -{ - const char *s_ctlfd, *s_pipe, *s_pid; - int ctlfd, pipefd, maxfd, x; - maxfd = maxconn(); - - s_ctlfd = getenv("CTL_FD"); - s_pipe = getenv("CTL_PIPE"); - s_pid = getenv("CTL_PPID"); - - if(s_ctlfd == NULL || s_pipe == NULL || s_pid == NULL) - { - fprintf(stderr, - "This is the solanum wsockd for internal ircd use.\n"); - fprintf(stderr, - "You aren't supposed to run me directly. Exiting.\n"); - exit(1); - } - - ctlfd = atoi(s_ctlfd); - pipefd = atoi(s_pipe); - ppid = atoi(s_pid); - - for(x = 0; x < maxfd; x++) - { - if(x != ctlfd && x != pipefd && x > 2) - close(x); - } - x = open("/dev/null", O_RDWR); - - if(x >= 0) - { - if(ctlfd != 0 && pipefd != 0) - dup2(x, 0); - if(ctlfd != 1 && pipefd != 1) - dup2(x, 1); - if(ctlfd != 2 && pipefd != 2) - dup2(x, 2); - if(x > 2) - close(x); - } - - setup_signals(); - rb_lib_init(NULL, NULL, NULL, 0, maxfd, 1024, 4096); - rb_linebuf_init(4096); - rb_init_rawbuffers(4096); - - mod_ctl = rb_malloc(sizeof(mod_ctl_t)); - mod_ctl->F = rb_open(ctlfd, RB_FD_SOCKET, "ircd control socket"); - mod_ctl->F_pipe = rb_open(pipefd, RB_FD_PIPE, "ircd pipe"); - rb_set_nb(mod_ctl->F); - rb_set_nb(mod_ctl->F_pipe); - rb_event_addish("clean_dead_conns", clean_dead_conns, NULL, 10); - read_pipe_ctl(mod_ctl->F_pipe, NULL); - mod_read_ctl(mod_ctl->F, mod_ctl); - - rb_lib_loop(0); - return 0; -}