diff --git a/doc/example.conf b/doc/example.conf index 3216148..1e2dc2a 100755 --- a/doc/example.conf +++ b/doc/example.conf @@ -136,6 +136,13 @@ class "server" { }; listen { + /* defer_accept: wait for clients to send IRC handshake data before + * accepting them. if you intend to use software which depends on the + * server replying first, such as BOPM, you should disable this feature. + * otherwise, you probably want to leave it on. + */ + defer_accept = yes; + /* If you want to listen on a specific IP only, specify host. * host definitions apply only to the following port line. */ diff --git a/doc/reference.conf b/doc/reference.conf index 1641b52..69417a2 100755 --- a/doc/reference.conf +++ b/doc/reference.conf @@ -304,6 +304,13 @@ class "server" { /* listen {}: contain information about the ports ircd listens on (OLD P:) */ listen { + /* defer_accept: wait for clients to send IRC handshake data before + * accepting them. if you intend to use software which depends on the + * server replying first, such as BOPM, you should disable this feature. + * otherwise, you probably want to leave it on. + */ + defer_accept = yes; + /* port: the specific port to listen on. if no host is specified * before, it will listen on all available IPs. * diff --git a/include/listener.h b/include/listener.h index 4de298e..8a37db9 100644 --- a/include/listener.h +++ b/include/listener.h @@ -38,12 +38,13 @@ struct Listener int ref_count; /* number of connection references */ int active; /* current state of listener */ int ssl; /* ssl listener */ + int defer_accept; /* use TCP_DEFER_ACCEPT */ struct rb_sockaddr_storage addr; struct DNSQuery *dns_query; char vhost[HOSTLEN + 1]; /* virtual name of listener */ }; -extern void add_listener(int port, const char *vaddr_ip, int family, int ssl); +extern void add_listener(int port, const char *vaddr_ip, int family, int ssl, int defer_accept); 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/libratbox/configure b/libratbox/configure index 45f6077..18129ad 100755 --- a/libratbox/configure +++ b/libratbox/configure @@ -12838,7 +12838,7 @@ $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi -for ac_header in crypt.h unistd.h sys/socket.h sys/stat.h sys/time.h time.h netinet/in.h arpa/inet.h errno.h sys/uio.h spawn.h sys/poll.h sys/epoll.h sys/select.h sys/devpoll.h sys/event.h port.h signal.h sys/signalfd.h sys/timerfd.h +for ac_header in crypt.h unistd.h sys/socket.h sys/stat.h sys/time.h time.h netinet/in.h arpa/inet.h errno.h sys/uio.h spawn.h sys/poll.h sys/epoll.h sys/select.h sys/devpoll.h sys/event.h port.h signal.h sys/signalfd.h sys/timerfd.h linux/tcp.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" diff --git a/libratbox/configure.ac b/libratbox/configure.ac index d50095c..8d5a77e 100644 --- a/libratbox/configure.ac +++ b/libratbox/configure.ac @@ -105,7 +105,7 @@ AC_TYPE_UID_T dnl Checks for header files. AC_HEADER_STDC -AC_CHECK_HEADERS([crypt.h unistd.h sys/socket.h sys/stat.h sys/time.h time.h netinet/in.h arpa/inet.h errno.h sys/uio.h spawn.h sys/poll.h sys/epoll.h sys/select.h sys/devpoll.h sys/event.h port.h signal.h sys/signalfd.h sys/timerfd.h]) +AC_CHECK_HEADERS([crypt.h unistd.h sys/socket.h sys/stat.h sys/time.h time.h netinet/in.h arpa/inet.h errno.h sys/uio.h spawn.h sys/poll.h sys/epoll.h sys/select.h sys/devpoll.h sys/event.h port.h signal.h sys/signalfd.h sys/timerfd.h linux/tcp.h]) AC_HEADER_TIME dnl Networking Functions diff --git a/libratbox/include/commio-ssl.h b/libratbox/include/commio-ssl.h index fb3c6cb..93e44f1 100644 --- a/libratbox/include/commio-ssl.h +++ b/libratbox/include/commio-ssl.h @@ -27,7 +27,7 @@ int rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile); int rb_init_ssl(void); -int rb_ssl_listen(rb_fde_t *F, int backlog); +int rb_ssl_listen(rb_fde_t *F, int backlog, int defer_accept); int rb_init_prng(const char *path, prng_seed_t seed_type); int rb_get_random(void *buf, size_t length); diff --git a/libratbox/include/libratbox_config.h.in b/libratbox/include/libratbox_config.h.in index 4e585c1..888b17f 100644 --- a/libratbox/include/libratbox_config.h.in +++ b/libratbox/include/libratbox_config.h.in @@ -60,15 +60,15 @@ /* Define to 1 if you have the `gmtime_r' function. */ #undef HAVE_GMTIME_R -/* Has GnuTLS */ -#undef HAVE_GNUTLS - /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the `kevent' function. */ #undef HAVE_KEVENT +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_TCP_H + /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H diff --git a/libratbox/include/ratbox_lib.h b/libratbox/include/ratbox_lib.h index 8a05962..d5df022 100644 --- a/libratbox/include/ratbox_lib.h +++ b/libratbox/include/ratbox_lib.h @@ -13,6 +13,10 @@ #include #include +#ifdef HAVE_LINUX_TCP_H +# include +#endif + #ifdef __GNUC__ #undef alloca #define alloca __builtin_alloca diff --git a/libratbox/include/rb_commio.h b/libratbox/include/rb_commio.h index 9b28c02..a62e2b7 100644 --- a/libratbox/include/rb_commio.h +++ b/libratbox/include/rb_commio.h @@ -125,8 +125,8 @@ ssize_t rb_read(rb_fde_t *, void *buf, int count); int rb_pipe(rb_fde_t **, rb_fde_t **, const char *desc); int rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile); -int rb_ssl_listen(rb_fde_t *, int backlog); -int rb_listen(rb_fde_t *, int backlog); +int rb_ssl_listen(rb_fde_t *, int backlog, int defer_accept); +int rb_listen(rb_fde_t *, int backlog, int defer_accept); const char *rb_inet_ntop(int af, const void *src, char *dst, unsigned int size); int rb_inet_pton(int af, const char *src, void *dst); diff --git a/libratbox/src/commio.c b/libratbox/src/commio.c index 64cdfcb..036948d 100644 --- a/libratbox/src/commio.c +++ b/libratbox/src/commio.c @@ -760,11 +760,33 @@ mangle_mapped_sockaddr(struct sockaddr *in) * rb_listen() - listen on a port */ int -rb_listen(rb_fde_t *F, int backlog) +rb_listen(rb_fde_t *F, int backlog, int defer_accept) { + int result; + F->type = RB_FD_SOCKET | RB_FD_LISTEN; - /* Currently just a simple wrapper for the sake of being complete */ - return listen(F->fd, backlog); + + result = listen(F->fd, backlog); + +#ifdef TCP_DEFER_ACCEPT + if (defer_accept && !result) + { + setsockopt(F->fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &backlog, sizeof(int)); + } +#endif +#ifdef SO_ACCEPTFILTER + if (defer_accept && !result) + { + struct accept_filter_arg afa; + + memset(&afa, '\0', sizeof afa); + rb_strlcpy(afa.af_name, "dataready", sizeof afa.af_name); + (void)setsockopt(F->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, + sizeof afa); + } +#endif + + return result; } void diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index 5daf1d2..58bafdf 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -347,10 +347,14 @@ rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile) } int -rb_ssl_listen(rb_fde_t *F, int backlog) +rb_ssl_listen(rb_fde_t *F, int backlog, int defer_accept) { + int result; + + result = listen(F->fd, backlog, defer_accept); F->type = RB_FD_SOCKET | RB_FD_LISTEN | RB_FD_SSL; - return listen(F->fd, backlog); + + return result; } struct ssl_connect diff --git a/libratbox/src/nossl.c b/libratbox/src/nossl.c index d077c3f..7f66123 100644 --- a/libratbox/src/nossl.c +++ b/libratbox/src/nossl.c @@ -48,7 +48,7 @@ rb_init_ssl(void) } int -rb_ssl_listen(rb_fde_t *F, int backlog) +rb_ssl_listen(rb_fde_t *F, int backlog, int defer_accept) { errno = ENOSYS; return -1; diff --git a/libratbox/src/openssl.c b/libratbox/src/openssl.c index d954011..1606826 100644 --- a/libratbox/src/openssl.c +++ b/libratbox/src/openssl.c @@ -389,10 +389,14 @@ rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile) } int -rb_ssl_listen(rb_fde_t *F, int backlog) +rb_ssl_listen(rb_fde_t *F, int backlog, int defer_accept) { + int result; + + result = rb_listen(F, backlog, defer_accept); F->type = RB_FD_SOCKET | RB_FD_LISTEN | RB_FD_SSL; - return listen(F->fd, backlog); + + return result; } struct ssl_connect diff --git a/src/listener.c b/src/listener.c index a93ba7b..a781f60 100644 --- a/src/listener.c +++ b/src/listener.c @@ -230,7 +230,7 @@ inetport(struct Listener *listener) return 0; } - if(rb_listen(F, RATBOX_SOMAXCONN)) + if(rb_listen(F, RATBOX_SOMAXCONN, listener->defer_accept)) { ilog_error("listen()"); rb_close(F); @@ -303,7 +303,7 @@ find_listener(struct rb_sockaddr_storage *addr) * the format "255.255.255.255" */ void -add_listener(int port, const char *vhost_ip, int family, int ssl) +add_listener(int port, const char *vhost_ip, int family, int ssl, int defer_accept) { struct Listener *listener; struct rb_sockaddr_storage vaddr; @@ -376,6 +376,7 @@ add_listener(int port, const char *vhost_ip, int family, int ssl) listener->F = NULL; listener->ssl = ssl; + listener->defer_accept = defer_accept; if(inetport(listener)) listener->active = 1; diff --git a/src/newconf.c b/src/newconf.c index f5c15a0..b4ccf2d 100644 --- a/src/newconf.c +++ b/src/newconf.c @@ -31,6 +31,8 @@ #define CF_TYPE(x) ((x) & CF_MTYPE) +static int yy_defer_accept = 1; + struct TopConf *conf_cur_block; static char *conf_cur_block_name; @@ -871,7 +873,11 @@ conf_end_listen(struct TopConf *tc) return 0; } - +static void +conf_set_listen_defer_accept(void *data) +{ + yy_defer_accept = *(unsigned int *) data; +} static void conf_set_listen_port_both(void *data, int ssl) @@ -887,9 +893,9 @@ conf_set_listen_port_both(void *data, int ssl) } if(listener_address == NULL) { - add_listener(args->v.number, listener_address, AF_INET, ssl); + add_listener(args->v.number, listener_address, AF_INET, ssl, yy_defer_accept); #ifdef RB_IPV6 - add_listener(args->v.number, listener_address, AF_INET6, ssl); + add_listener(args->v.number, listener_address, AF_INET6, ssl, yy_defer_accept); #endif } else @@ -902,7 +908,7 @@ conf_set_listen_port_both(void *data, int ssl) #endif family = AF_INET; - add_listener(args->v.number, listener_address, family, ssl); + add_listener(args->v.number, listener_address, family, ssl, yy_defer_accept); } @@ -2344,6 +2350,7 @@ newconf_init() add_top_conf("privset", NULL, NULL, conf_privset_table); 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", "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", "ip", CF_QSTRING, conf_set_listen_address);