X-Git-Url: https://jfr.im/git/irc/rqf/shadowircd.git/blobdiff_plain/94b4fbf93a7653bd9acb52649d6a4a8d5f994d0a..05073c8113aa670155925cb8e9ccab284bc0a29b:/ssld/ssld.c diff --git a/ssld/ssld.c b/ssld/ssld.c index d7d8970..a6c6b5f 100644 --- a/ssld/ssld.c +++ b/ssld/ssld.c @@ -127,6 +127,7 @@ typedef struct _conn #define FLAG_DEAD 0x08 #define FLAG_SSL_W_WANTS_R 0x10 /* output needs to wait until input possible */ #define FLAG_SSL_R_WANTS_W 0x20 /* input needs to wait until output possible */ +#define FLAG_ZIPSSL 0x40 #define IsSSL(x) ((x)->flags & FLAG_SSL) #define IsZip(x) ((x)->flags & FLAG_ZIP) @@ -134,6 +135,7 @@ typedef struct _conn #define IsDead(x) ((x)->flags & FLAG_DEAD) #define IsSSLWWantsR(x) ((x)->flags & FLAG_SSL_W_WANTS_R) #define IsSSLRWantsW(x) ((x)->flags & FLAG_SSL_R_WANTS_W) +#define IsZipSSL(x) ((x)->flags & FLAG_ZIPSSL) #define SetSSL(x) ((x)->flags |= FLAG_SSL) #define SetZip(x) ((x)->flags |= FLAG_ZIP) @@ -141,6 +143,7 @@ typedef struct _conn #define SetDead(x) ((x)->flags |= FLAG_DEAD) #define SetSSLWWantsR(x) ((x)->flags |= FLAG_SSL_W_WANTS_R) #define SetSSLRWantsW(x) ((x)->flags |= FLAG_SSL_R_WANTS_W) +#define SetZipSSL(x) ((x)->flags |= FLAG_ZIPSSL) #define ClearSSL(x) ((x)->flags &= ~FLAG_SSL) #define ClearZip(x) ((x)->flags &= ~FLAG_ZIP) @@ -148,6 +151,7 @@ typedef struct _conn #define ClearDead(x) ((x)->flags &= ~FLAG_DEAD) #define ClearSSLWWantsR(x) ((x)->flags &= ~FLAG_SSL_W_WANTS_R) #define ClearSSLRWantsW(x) ((x)->flags &= ~FLAG_SSL_R_WANTS_W) +#define ClearZipSSL(x) ((x)->flags &= ~FLAG_ZIPSSL) #define NO_WAIT 0x0 #define WAIT_PLAIN 0x1 @@ -167,6 +171,7 @@ static void conn_mod_write_sendq(rb_fde_t *, void *data); static void conn_plain_write_sendq(rb_fde_t *, void *data); static void mod_write_ctl(rb_fde_t *, void *data); static void conn_plain_read_cb(rb_fde_t *fd, void *data); +static void conn_plain_read_shutdown_cb(rb_fde_t *fd, void *data); static void mod_cmd_write_queue(mod_ctl_t * ctl, const void *data, size_t len); static const char *remote_closed = "Remote host closed the connection"; static int ssl_ok; @@ -258,16 +263,17 @@ close_conn(conn_t * conn, int wait_plain, const char *fmt, ...) rb_close(conn->mod_fd); SetDead(conn); + if(conn->id >= 0 && !IsZipSSL(conn)) + rb_dlinkDelete(&conn->node, connid_hash(conn->id)); + if(!wait_plain || fmt == NULL) { rb_close(conn->plain_fd); - - if(conn->id >= 0) - rb_dlinkDelete(&conn->node, connid_hash(conn->id)); rb_dlinkAdd(conn, &conn->node, &dead_list); return; } - rb_setselect(conn->plain_fd, RB_SELECT_WRITE | RB_SELECT_READ, NULL, NULL); + 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); rb_vsnprintf(reason, sizeof(reason), fmt, ap); va_end(ap); @@ -537,6 +543,34 @@ conn_plain_read_cb(rb_fde_t *fd, void *data) } } +static void +conn_plain_read_shutdown_cb(rb_fde_t *fd, void *data) +{ + 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 conn_mod_read_cb(rb_fde_t *fd, void *data) { @@ -645,8 +679,16 @@ static void ssl_process_accept_cb(rb_fde_t *F, int status, struct sockaddr *addr, rb_socklen_t len, void *data) { conn_t *conn = data; + char buf[5 + RB_SSL_CERTFP_LEN]; + if(status == RB_OK) { + if(rb_get_ssl_certfp(F, &buf[5])) + { + buf[0] = 'F'; + int32_to_buf(&buf[1], conn->id); + mod_cmd_write_queue(conn->ctl, buf, sizeof buf); + } conn_mod_read_cb(conn->mod_fd, conn); conn_plain_read_cb(conn->plain_fd, conn); return; @@ -674,6 +716,16 @@ ssl_process_connect_cb(rb_fde_t *F, int status, void *data) } +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 ssl_process_accept(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) { @@ -750,17 +802,19 @@ process_stats(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) mod_cmd_write_queue(ctl, outstat, strlen(outstat) + 1); /* +1 is so we send the \0 as well */ } -#ifdef HAVE_LIBZ static void -zlib_send_zip_ready(mod_ctl_t * ctl, conn_t * conn) +change_connid(mod_ctl_t *ctl, mod_ctl_buf_t *ctlb) { - char buf[5]; - - buf[0] = 'R'; - int32_to_buf(&buf[1], conn->id); - mod_cmd_write_queue(conn->ctl, buf, sizeof(buf)); + int32_t id = buf_to_int32(&ctlb->buf[1]); + int32_t newid = buf_to_int32(&ctlb->buf[5]); + conn_t *conn = conn_find_by_id(id); + if(conn->id >= 0) + rb_dlinkDelete(&conn->node, connid_hash(conn->id)); + SetZipSSL(conn); + conn->id = newid; } +#ifdef HAVE_LIBZ static void zlib_process(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) { @@ -811,7 +865,7 @@ zlib_process(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) deflateInit(&((zlib_stream_t *) conn->stream)->outstream, level); if(recvqlen > 0) common_zlib_inflate(conn, recvq_start, recvqlen); - zlib_send_zip_ready(ctl, conn); + conn_mod_read_cb(conn->mod_fd, conn); conn_plain_read_cb(conn->plain_fd, conn); return; @@ -912,6 +966,12 @@ mod_process_cmd_recv(mod_ctl_t * ctl) { case 'A': { + if (ctl_buf->nfds != 2 || ctl_buf->buflen != 5) + { + cleanup_bad_message(ctl, ctl_buf); + break; + } + if(!ssl_ok) { send_nossl_support(ctl, ctl_buf); @@ -922,6 +982,12 @@ mod_process_cmd_recv(mod_ctl_t * ctl) } case 'C': { + if (ctl_buf->nfds != 2 || ctl_buf->buflen != 5) + { + cleanup_bad_message(ctl, ctl_buf); + break; + } + if(!ssl_ok) { send_nossl_support(ctl, ctl_buf); @@ -949,15 +1015,27 @@ mod_process_cmd_recv(mod_ctl_t * ctl) process_stats(ctl, ctl_buf); break; } + case 'Y': + { + change_connid(ctl, ctl_buf); + break; + } + #ifdef HAVE_LIBZ case 'Z': { + if (ctl_buf->nfds != 2 || ctl_buf->buflen < 6) + { + cleanup_bad_message(ctl, ctl_buf); + break; + } + /* just zlib only */ zlib_process(ctl, ctl_buf); break; } #else - case 'Y': + case 'Z': send_nozlib_support(ctl, ctl_buf); break; @@ -982,6 +1060,7 @@ 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 { @@ -999,6 +1078,9 @@ mod_read_ctl(rb_fde_t *F, void *data) { 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); @@ -1035,8 +1117,9 @@ mod_write_ctl(rb_fde_t *F, void *data) if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno))) exit(0); - rb_setselect(ctl->F, RB_SELECT_WRITE, mod_write_ctl, ctl); } + if(rb_dlink_list_length(&ctl->writeq) > 0) + rb_setselect(ctl->F, RB_SELECT_WRITE, mod_write_ctl, ctl); } @@ -1086,6 +1169,7 @@ main(int argc, char **argv) close(x); } x = open("/dev/null", O_RDWR); + if(x >= 0) { if(ctlfd != 0 && pipefd != 0)