From 04540f82e56283c54c4cc169158a14b4d9c0de61 Mon Sep 17 00:00:00 2001 From: Vadim Fedorenko Date: Thu, 13 Apr 2023 07:49:32 -0700 Subject: [PATCH] config: add sock_queue_timeout configuration Add sock_queue_timeout config option to have queue timeout configurable. Signed-off-by: Vadim Fedorenko --- config.h.in | 3 +++ configure | 29 ++++++++++++++------------ configure.ac | 5 ++++- services/listen_dnsport.c | 43 +++++++++++++++++++++++++++++++-------- util/config_file.c | 3 +++ util/config_file.h | 2 ++ util/configlexer.lex | 1 + util/configparser.y | 15 ++++++++++++++ util/netevent.c | 6 +++++- 9 files changed, 84 insertions(+), 23 deletions(-) diff --git a/config.h.in b/config.h.in index 6f7a062af..e7a44bf60 100644 --- a/config.h.in +++ b/config.h.in @@ -671,6 +671,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_TIME_H +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_NET_TSTAMP_H + /* Define to 1 if you have the `tzset' function. */ #undef HAVE_TZSET diff --git a/configure b/configure index f7abb5289..491228b54 100755 --- a/configure +++ b/configure @@ -813,7 +813,6 @@ infodir docdir oldincludedir includedir -runstatedir localstatedir sharedstatedir sysconfdir @@ -965,7 +964,6 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' -runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1218,15 +1216,6 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; - -runstatedir | --runstatedir | --runstatedi | --runstated \ - | --runstate | --runstat | --runsta | --runst | --runs \ - | --run | --ru | --r) - ac_prev=runstatedir ;; - -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ - | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ - | --run=* | --ru=* | --r=*) - runstatedir=$ac_optarg ;; - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1364,7 +1353,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir runstatedir + libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1517,7 +1506,6 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -14878,6 +14866,21 @@ fi done +# Check for Linux timestamping headers +for ac_header in linux/net_tstamp.h +do : + ac_fn_c_check_header_compile "$LINENO" "linux/net_tstamp.h" "ac_cv_header_linux_net_tstamp_h" "$ac_includes_default +" +if test "x$ac_cv_header_linux_net_tstamp_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LINUX_NET_TSTAMP_H 1 +_ACEOF + +fi + +done + + # check for types. # Using own tests for int64* because autoconf builtin only give 32bit. ac_fn_c_check_type "$LINENO" "int8_t" "ac_cv_type_int8_t" "$ac_includes_default" diff --git a/configure.ac b/configure.ac index 73fef5f87..fa5ca1018 100644 --- a/configure.ac +++ b/configure.ac @@ -454,7 +454,10 @@ AC_CHECK_HEADERS([netioapi.h],,, [AC_INCLUDES_DEFAULT #endif ]) -# check for types. +# Check for Linux timestamping headers +AC_CHECK_HEADERS([linux/net_tstamp.h],,, [AC_INCLUDES_DEFAULT]) + +# check for types. # Using own tests for int64* because autoconf builtin only give 32bit. AC_CHECK_TYPE(int8_t, signed char) AC_CHECK_TYPE(int16_t, short) diff --git a/services/listen_dnsport.c b/services/listen_dnsport.c index 484529034..2163a949d 100644 --- a/services/listen_dnsport.c +++ b/services/listen_dnsport.c @@ -79,7 +79,9 @@ #ifdef HAVE_NET_IF_H #include #endif - +#ifdef HAVE_LINUX_NET_TSTAMP_H +#include +#endif /** number of queued TCP connections for listen() */ #define TCP_BACKLOG 256 @@ -1114,6 +1116,24 @@ port_insert(struct listen_port** list, int s, enum listen_type ftype, return 1; } +/** set fd to receive software timestamps */ +static int +set_recvtimestamp(int s) +{ +#ifdef HAVE_LINUX_NET_TSTAMP_H + int opt = SOF_TIMESTAMPING_RX_SOFTWARE | SOF_TIMESTAMPING_SOFTWARE; + if (setsockopt(s, SOL_SOCKET, SO_TIMESTAMPNS, (void*)&opt, (socklen_t)sizeof(opt)) < 0) { + log_err("setsockopt(..., SO_TIMESTAMPNS, ...) failed: %s", + strerror(errno)); + return 0; + } + return 1; +#else + log_err("packets timestamping is not supported on this platform"); + return 0; +#endif +} + /** set fd to receive source address packet info */ static int set_recvpktinfo(int s, int family) @@ -1223,7 +1243,8 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, struct config_strlist* tls_additional_port, int https_port, struct config_strlist* proxy_protocol_port, int* reuseport, int transparent, int tcp_mss, int freebind, - int http2_nodelay, int use_systemd, int dnscrypt_port, int dscp) + int http2_nodelay, int use_systemd, int dnscrypt_port, int dscp, + int sock_queue_timeout) { int s, noip6=0; int is_https = if_is_https(ifname, port, https_port); @@ -1269,6 +1290,9 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, free(ub_sock); return 0; } + if (sock_queue_timeout && !set_recvtimestamp(s)) { + log_warn("socket timestamping is not available"); + } if(!port_insert(list, s, is_dnscrypt ?listen_type_udpancil_dnscrypt:listen_type_udpancil, is_pp2, ub_sock)) { @@ -1295,6 +1319,9 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, } return 0; } + if (sock_queue_timeout && !set_recvtimestamp(s)) { + log_warn("socket timestamping is not available"); + } if(!port_insert(list, s, is_dnscrypt ?listen_type_udp_dnscrypt:listen_type_udp, is_pp2, ub_sock)) { @@ -1809,7 +1836,7 @@ listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs, reuseport, cfg->ip_transparent, cfg->tcp_mss, cfg->ip_freebind, cfg->http_nodelay, cfg->use_systemd, - cfg->dnscrypt_port, cfg->ip_dscp)) { + cfg->dnscrypt_port, cfg->ip_dscp, cfg->sock_queue_timeout)) { listening_ports_free(list); return NULL; } @@ -1826,7 +1853,7 @@ listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs, reuseport, cfg->ip_transparent, cfg->tcp_mss, cfg->ip_freebind, cfg->http_nodelay, cfg->use_systemd, - cfg->dnscrypt_port, cfg->ip_dscp)) { + cfg->dnscrypt_port, cfg->ip_dscp, cfg->sock_queue_timeout)) { listening_ports_free(list); return NULL; } @@ -1845,7 +1872,7 @@ listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs, reuseport, cfg->ip_transparent, cfg->tcp_mss, cfg->ip_freebind, cfg->http_nodelay, cfg->use_systemd, - cfg->dnscrypt_port, cfg->ip_dscp)) { + cfg->dnscrypt_port, cfg->ip_dscp, cfg->sock_queue_timeout)) { listening_ports_free(list); return NULL; } @@ -1861,7 +1888,7 @@ listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs, reuseport, cfg->ip_transparent, cfg->tcp_mss, cfg->ip_freebind, cfg->http_nodelay, cfg->use_systemd, - cfg->dnscrypt_port, cfg->ip_dscp)) { + cfg->dnscrypt_port, cfg->ip_dscp, cfg->sock_queue_timeout)) { listening_ports_free(list); return NULL; } @@ -1879,7 +1906,7 @@ listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs, reuseport, cfg->ip_transparent, cfg->tcp_mss, cfg->ip_freebind, cfg->http_nodelay, cfg->use_systemd, - cfg->dnscrypt_port, cfg->ip_dscp)) { + cfg->dnscrypt_port, cfg->ip_dscp, cfg->sock_queue_timeout)) { listening_ports_free(list); return NULL; } @@ -1895,7 +1922,7 @@ listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs, reuseport, cfg->ip_transparent, cfg->tcp_mss, cfg->ip_freebind, cfg->http_nodelay, cfg->use_systemd, - cfg->dnscrypt_port, cfg->ip_dscp)) { + cfg->dnscrypt_port, cfg->ip_dscp, cfg->sock_queue_timeout)) { listening_ports_free(list); return NULL; } diff --git a/util/config_file.c b/util/config_file.c index 8e4d925e9..a04c8cf09 100644 --- a/util/config_file.c +++ b/util/config_file.c @@ -116,6 +116,7 @@ config_create(void) cfg->tcp_auth_query_timeout = 3 * 1000; /* 3s in millisecs */ cfg->do_tcp_keepalive = 0; cfg->tcp_keepalive_timeout = 120 * 1000; /* 120s in millisecs */ + cfg->sock_queue_timeout = 0; /* do not check timeout */ cfg->ssl_service_key = NULL; cfg->ssl_service_pem = NULL; cfg->ssl_port = UNBOUND_DNS_OVER_TLS_PORT; @@ -543,6 +544,7 @@ int config_set_option(struct config_file* cfg, const char* opt, else S_NUMBER_NONZERO("tcp-reuse-timeout:", tcp_reuse_timeout) else S_YNO("edns-tcp-keepalive:", do_tcp_keepalive) else S_NUMBER_NONZERO("edns-tcp-keepalive-timeout:", tcp_keepalive_timeout) + else S_NUMBER_OR_ZERO("sock-queue-timeout:", sock_queue_timeout) else S_YNO("ssl-upstream:", ssl_upstream) else S_YNO("tls-upstream:", ssl_upstream) else S_STR("ssl-service-key:", ssl_service_key) @@ -1066,6 +1068,7 @@ config_get_option(struct config_file* cfg, const char* opt, else O_DEC(opt, "tcp-reuse-timeout", tcp_reuse_timeout) else O_YNO(opt, "edns-tcp-keepalive", do_tcp_keepalive) else O_DEC(opt, "edns-tcp-keepalive-timeout", tcp_keepalive_timeout) + else O_DEC(opt, "sock-queue-timeout", sock_queue_timeout) else O_YNO(opt, "ssl-upstream", ssl_upstream) else O_YNO(opt, "tls-upstream", ssl_upstream) else O_STR(opt, "ssl-service-key", ssl_service_key) diff --git a/util/config_file.h b/util/config_file.h index 1590dc460..fc19790ca 100644 --- a/util/config_file.h +++ b/util/config_file.h @@ -116,6 +116,8 @@ struct config_file { int do_tcp_keepalive; /** tcp keepalive timeout, in msec */ int tcp_keepalive_timeout; + /** timeout of packets sitting in the socket queue */ + int sock_queue_timeout; /** proxy protocol ports */ struct config_strlist* proxy_protocol_port; diff --git a/util/configlexer.lex b/util/configlexer.lex index 31b69779d..dd85ecd26 100644 --- a/util/configlexer.lex +++ b/util/configlexer.lex @@ -240,6 +240,7 @@ tcp-reuse-timeout{COLON} { YDVAR(1, VAR_TCP_REUSE_TIMEOUT) } tcp-auth-query-timeout{COLON} { YDVAR(1, VAR_TCP_AUTH_QUERY_TIMEOUT) } edns-tcp-keepalive{COLON} { YDVAR(1, VAR_EDNS_TCP_KEEPALIVE) } edns-tcp-keepalive-timeout{COLON} { YDVAR(1, VAR_EDNS_TCP_KEEPALIVE_TIMEOUT) } +sock-queue-timeout{COLON} { YDVAR(1, VAR_SOCK_QUEUE_TIMEOUT) } ssl-upstream{COLON} { YDVAR(1, VAR_SSL_UPSTREAM) } tls-upstream{COLON} { YDVAR(1, VAR_SSL_UPSTREAM) } ssl-service-key{COLON} { YDVAR(1, VAR_SSL_SERVICE_KEY) } diff --git a/util/configparser.y b/util/configparser.y index 4f00ecc0d..06118e04a 100644 --- a/util/configparser.y +++ b/util/configparser.y @@ -76,6 +76,7 @@ extern struct config_parser_state* cfg_parser; %token VAR_DO_IP4 VAR_DO_IP6 VAR_PREFER_IP6 VAR_DO_UDP VAR_DO_TCP %token VAR_TCP_MSS VAR_OUTGOING_TCP_MSS VAR_TCP_IDLE_TIMEOUT %token VAR_EDNS_TCP_KEEPALIVE VAR_EDNS_TCP_KEEPALIVE_TIMEOUT +%token VAR_SOCK_QUEUE_TIMEOUT %token VAR_CHROOT VAR_USERNAME VAR_DIRECTORY VAR_LOGFILE VAR_PIDFILE %token VAR_MSG_CACHE_SIZE VAR_MSG_CACHE_SLABS VAR_NUM_QUERIES_PER_THREAD %token VAR_RRSET_CACHE_SIZE VAR_RRSET_CACHE_SLABS VAR_OUTGOING_NUM_TCP @@ -227,6 +228,7 @@ content_server: server_num_threads | server_verbosity | server_port | server_do_udp | server_do_tcp | server_tcp_mss | server_outgoing_tcp_mss | server_tcp_idle_timeout | server_tcp_keepalive | server_tcp_keepalive_timeout | + server_sock_queue_timeout | server_interface | server_chroot | server_username | server_directory | server_logfile | server_pidfile | server_msg_cache_size | server_msg_cache_slabs | @@ -974,6 +976,19 @@ server_tcp_keepalive_timeout: VAR_EDNS_TCP_KEEPALIVE_TIMEOUT STRING_ARG free($2); } ; +server_sock_queue_timeout: VAR_SOCK_QUEUE_TIMEOUT STRING_ARG + { + OUTYY(("P(server_sock_queue_timeout:%s)\n", $2)); + if(atoi($2) == 0 && strcmp($2, "0") != 0) + yyerror("number expected"); + else if (atoi($2) > 6553500) + cfg_parser->cfg->sock_queue_timeout = 6553500; + else if (atoi($2) < 1) + cfg_parser->cfg->sock_queue_timeout = 0; + else cfg_parser->cfg->sock_queue_timeout = atoi($2); + free($2); + } + ; server_tcp_upstream: VAR_TCP_UPSTREAM STRING_ARG { OUTYY(("P(server_tcp_upstream:%s)\n", $2)); diff --git a/util/netevent.c b/util/netevent.c index ca5b9e165..6ca51622b 100644 --- a/util/netevent.c +++ b/util/netevent.c @@ -72,7 +72,9 @@ #ifdef HAVE_OPENSSL_ERR_H #include #endif - +#ifdef HAVE_LINUX_NET_TSTAMP_H +#include +#endif /* -------- Start of local definitions -------- */ /** if CMSG_ALIGN is not defined on this platform, a workaround */ #ifndef CMSG_ALIGN @@ -907,6 +909,7 @@ comm_point_udp_ancil_callback(int fd, short event, void* arg) sizeof(struct in_addr)); break; #endif /* IP_PKTINFO or IP_RECVDSTADDR */ +#ifdef HAVE_LINUX_NET_TSTAMP_H } else if( cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SO_TIMESTAMPNS) { ts = (struct timespec *)CMSG_DATA(cmsg); @@ -918,6 +921,7 @@ comm_point_udp_ancil_callback(int fd, short event, void* arg) } else if( cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SO_TIMESTAMP) { memmove(&rep.c->recv_tv, CMSG_DATA(cmsg), sizeof(struct timeval)); +#endif } } -- 2.47.2