Hi, I would like to propose this patchset allowing to set maximum TTL value for incoming requests. This is not a usual use case, but I'm interested (maybe others too) to have this in place. The real use case would be like this one http://blog.donatas.net/blog/2017/04/20/http-request-validation/. TL;DR: if you want to deny requests bypassing proxy layer (in this case Apache operates as a backend). Hence set TTLimit to 1 and Apache will be able to handle requests coming almost from the local network, because packets with TTL usually come from local networks. commit 5b28a17bdf8a86fa4cccc9a76ce474e5afdb434e Author: ton31337 <donatas.abraitis@gmail.com> Date: Mon Jun 12 17:36:13 2017 +0300 Add `TTLimit` security check feature diff --git a/include/ap_listen.h b/include/ap_listen.h index 58c2574..e20c566 100644 --- a/include/ap_listen.h +++ b/include/ap_listen.h @@ -133,6 +133,7 @@ AP_DECLARE_NONSTD(int) ap_close_selected_listeners(ap_slave_t *); * LISTEN_COMMANDS in their command_rec table so that these functions are * called. */ +AP_DECLARE_NONSTD(const char *) ap_set_ttl_limit(cmd_parms *cmd, void *dummy, const char *arg); AP_DECLARE_NONSTD(const char *) ap_set_listenbacklog(cmd_parms *cmd, void *dummy, const char *arg); AP_DECLARE_NONSTD(const char *) ap_set_listencbratio(cmd_parms *cmd, void *dummy, const char *arg); AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, @@ -144,6 +145,8 @@ AP_DECLARE_NONSTD(const char *) ap_set_receive_buffer_size(cmd_parms *cmd, const char *arg); #define LISTEN_COMMANDS \ +AP_INIT_TAKE1("TTLimit", ap_set_ttl_limit, NULL, RSRC_CONF, \ + "Maximum TTL value which will be accepted"), \ AP_INIT_TAKE1("ListenBacklog", ap_set_listenbacklog, NULL, RSRC_CONF, \ "Maximum length of the queue of pending connections, as used by listen(2)"), \ AP_INIT_TAKE1("ListenCoresBucketsRatio", ap_set_listencbratio, NULL, RSRC_CONF, \ diff --git a/server/listen.c b/server/listen.c index 98cd117..bc498e3 100644 --- a/server/listen.c +++ b/server/listen.c @@ -186,6 +186,21 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server) return stat; } + if (ap_ttl_limit) { + int thesock; + apr_os_sock_get(&thesock, s); + if (setsockopt(thesock, IPPROTO_IP, IP_TTL, + &ap_ttl_limit, sizeof(int)) < 0) { + stat = apr_get_netos_error(); + ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, APLOGNO(02638) + "make_sock: for address %pI, apr_socket_opt_set: " + "(IP_TTL)", + server->bind_addr); + apr_socket_close(s); + return stat; + } + } + #ifdef WIN32 /* I seriously doubt that this would work on Unix; I have doubts that * it entirely solves the problem on Win32. However, since setting @@ -758,6 +773,7 @@ AP_DECLARE(void) ap_listen_pre_config(void) ap_listen_buckets = NULL; ap_num_listen_buckets = 0; ap_listenbacklog = DEFAULT_LISTENBACKLOG; + ap_ttl_limit = 255; ap_listencbratio = 0; /* Check once whether or not SO_REUSEPORT is supported. */ @@ -863,6 +879,26 @@ AP_DECLARE_NONSTD(const char *) ap_set_listenbacklog(cmd_parms *cmd, return NULL; } +AP_DECLARE_NONSTD(const char *) ap_set_ttl_limit(cmd_parms *cmd, + void *dummy, + const char *arg) +{ + int b; + const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); + + if (err != NULL) { + return err; + } + + b = atoi(arg); + if (b < 1 || b > 255) { + return "TTLimit > 0 and TTLimit < 255"; + } + + ap_ttl_limit = b; + return NULL; +} + AP_DECLARE_NONSTD(const char *) ap_set_listencbratio(cmd_parms *cmd, void *dummy, const char *arg) Waiting for comments, D.
Created attachment 35048 [details] TTLimit directive
Any updates on this?
Attached patch would be completed by a patch to document the new directive. Somewhere in docs/manual/mod/mpm_common.xml
Created attachment 37264 [details] TTLimit.patch
Thanks, Nick. Added a patch.
Created attachment 37265 [details] TTLimit.patch
Created attachment 37267 [details] TTLimit.patch
The latest patch works as expected: root@donatas-laptop:/home/donatas/httpd-2.4.43# grep TTLimit /usr/local/apache2/conf/httpd.conf TTLimit 5 root@donatas-laptop:/home/donatas/httpd-2.4.43# strace -esetsockopt /usr/local/apache2/bin/httpd -f /usr/local/apache2/conf/httpd.conf setsockopt(3, SOL_SOCKET, SO_REUSEPORT, [1], 4) = 0 setsockopt(4, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 setsockopt(4, SOL_SOCKET, SO_KEEPALIVE, [1], 4) = 0 setsockopt(4, SOL_IPV6, IPV6_V6ONLY, [0], 4) = 0 setsockopt(4, SOL_SOCKET, SO_SNDBUF, [1024], 4) = 0 setsockopt(4, SOL_TCP, TCP_NODELAY, [1], 4) = 0 setsockopt(4, SOL_IP, IP_TTL, [5], 4) = 0 setsockopt(4, SOL_TCP, TCP_DEFER_ACCEPT, [30], 4) = 0 +++ exited with 1 +++ root@donatas-laptop:/home/donatas/httpd-2.4.43#
Nick, all good with this?
Sorry, just revisited this. Thanks for bugging me! The "Usage" in your docs patch looks more like an application - your application - than an explanation of the feature itself. Do you mind if I reword it a little: say it sets the socket option, and make your text an example of why someone might use it? I think that's what's meant anyway, but if I hadn't read your posts (and blog) I might find it confusing!
Hi, Nick, that works for me if you adopt it how it's needed ;-)