Update to nsd 4.4.0
authorflorian <florian@openbsd.org>
Wed, 16 Mar 2022 10:14:50 +0000 (10:14 +0000)
committerflorian <florian@openbsd.org>
Wed, 16 Mar 2022 10:14:50 +0000 (10:14 +0000)
tested by sthen and me
OK sthen

30 files changed:
usr.sbin/nsd/Makefile.in
usr.sbin/nsd/configlexer.lex
usr.sbin/nsd/configparser.y
usr.sbin/nsd/configure
usr.sbin/nsd/configure.ac
usr.sbin/nsd/dbaccess.c
usr.sbin/nsd/doc/ChangeLog
usr.sbin/nsd/doc/RELNOTES
usr.sbin/nsd/edns.c
usr.sbin/nsd/lookup3.c
usr.sbin/nsd/nsd-checkconf.8.in
usr.sbin/nsd/nsd-checkconf.c
usr.sbin/nsd/nsd-checkzone.8.in
usr.sbin/nsd/nsd-control-setup.sh.in
usr.sbin/nsd/nsd-control.8.in
usr.sbin/nsd/nsd.8.in
usr.sbin/nsd/nsd.conf.5.in
usr.sbin/nsd/nsd.conf.sample.in
usr.sbin/nsd/options.c
usr.sbin/nsd/options.h
usr.sbin/nsd/remote.c
usr.sbin/nsd/rrl.h
usr.sbin/nsd/server.c
usr.sbin/nsd/udb.c
usr.sbin/nsd/udb.h
usr.sbin/nsd/util.c
usr.sbin/nsd/xfrd-tcp.c
usr.sbin/nsd/xfrd-tcp.h
usr.sbin/nsd/xfrd.c
usr.sbin/nsd/xfrd.h

index 8aa4026..e28fc47 100644 (file)
@@ -586,7 +586,7 @@ cutest_udb.o: $(srcdir)/tpkg/cutest/cutest_udb.c config.h $(srcdir)/tpkg/cutest/
 cutest_udbrad.o: $(srcdir)/tpkg/cutest/cutest_udbrad.c config.h \
  $(srcdir)/tpkg/cutest/cutest.h $(srcdir)/udbradtree.h $(srcdir)/udb.h
 cutest_util.o: $(srcdir)/tpkg/cutest/cutest_util.c config.h $(srcdir)/tpkg/cutest/cutest.h \
- $(srcdir)/region-allocator.h $(srcdir)/util.h
+ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/xfrd-tcp.h
 qtest.o: $(srcdir)/tpkg/cutest/qtest.c config.h $(srcdir)/tpkg/cutest/qtest.h $(srcdir)/buffer.h \
  $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/query.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/dns.h \
  $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/packet.h $(srcdir)/tsig.h $(srcdir)/namedb.h $(srcdir)/util.h $(srcdir)/nsec3.h \
index d5fcd58..a168834 100644 (file)
@@ -297,6 +297,8 @@ tls-cert-bundle{COLON}      { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_CERT_BUNDLE;
 answer-cookie{COLON}   { LEXOUT(("v(%s) ", yytext)); return VAR_ANSWER_COOKIE;}
 cookie-secret{COLON}   { LEXOUT(("v(%s) ", yytext)); return VAR_COOKIE_SECRET;}
 cookie-secret-file{COLON}      { LEXOUT(("v(%s) ", yytext)); return VAR_COOKIE_SECRET_FILE;}
+xfrd-tcp-max{COLON}    { LEXOUT(("v(%s) ", yytext)); return VAR_XFRD_TCP_MAX;}
+xfrd-tcp-pipeline{COLON}       { LEXOUT(("v(%s) ", yytext)); return VAR_XFRD_TCP_PIPELINE;}
 {NEWLINE}              { LEXOUT(("NL\n")); cfg_parser->line++;}
 
 servers={UNQUOTEDLETTER}*      {
index 70e54cf..0815a0a 100644 (file)
@@ -119,6 +119,8 @@ static int parse_range(const char *str, long long *low, long long *high);
 %token VAR_XFRD_CPU_AFFINITY
 %token <llng> VAR_SERVER_CPU_AFFINITY
 %token VAR_DROP_UPDATES
+%token VAR_XFRD_TCP_MAX
+%token VAR_XFRD_TCP_PIPELINE
 
 /* dnstap */
 %token VAR_DNSTAP
@@ -454,6 +456,10 @@ server_option:
     { cfg_parser->opt->cookie_secret = region_strdup(cfg_parser->opt->region, $2); }
   | VAR_COOKIE_SECRET_FILE STRING
     { cfg_parser->opt->cookie_secret_file = region_strdup(cfg_parser->opt->region, $2); }
+  | VAR_XFRD_TCP_MAX number
+    { cfg_parser->opt->xfrd_tcp_max = (int)$2; }
+  | VAR_XFRD_TCP_PIPELINE number
+    { cfg_parser->opt->xfrd_tcp_pipeline = (int)$2; }
   | VAR_CPU_AFFINITY cpus
     {
       cfg_parser->opt->cpu_affinity = $2;
index ca313c8..0a5938d 100644 (file)
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for NSD 4.3.9.
+# Generated by GNU Autoconf 2.69 for NSD 4.4.0.
 #
 # Report bugs to <nsd-bugs@nlnetlabs.nl>.
 #
@@ -580,8 +580,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='NSD'
 PACKAGE_TARNAME='nsd'
-PACKAGE_VERSION='4.3.9'
-PACKAGE_STRING='NSD 4.3.9'
+PACKAGE_VERSION='4.4.0'
+PACKAGE_STRING='NSD 4.4.0'
 PACKAGE_BUGREPORT='nsd-bugs@nlnetlabs.nl'
 PACKAGE_URL=''
 
@@ -1328,7 +1328,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures NSD 4.3.9 to adapt to many kinds of systems.
+\`configure' configures NSD 4.4.0 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1390,7 +1390,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of NSD 4.3.9:";;
+     short | recursive ) echo "Configuration of NSD 4.4.0:";;
    esac
   cat <<\_ACEOF
 
@@ -1563,7 +1563,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-NSD configure 4.3.9
+NSD configure 4.4.0
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2272,7 +2272,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by NSD $as_me 4.3.9, which was
+It was created by NSD $as_me 4.4.0, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -11155,7 +11155,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by NSD $as_me 4.3.9, which was
+This file was extended by NSD $as_me 4.4.0, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -11217,7 +11217,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-NSD config.status 4.3.9
+NSD config.status 4.4.0
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
index 94a2e1e..979b9ec 100644 (file)
@@ -5,7 +5,7 @@ dnl
 sinclude(acx_nlnetlabs.m4)
 sinclude(dnstap/dnstap.m4)
 
-AC_INIT([NSD],[4.3.9],[nsd-bugs@nlnetlabs.nl])
+AC_INIT([NSD],[4.4.0],[nsd-bugs@nlnetlabs.nl])
 AC_CONFIG_HEADERS([config.h])
 
 #
index 4291451..4849481 100644 (file)
@@ -491,7 +491,7 @@ namedb_open (const char* filename, struct nsd_options* opt)
 #endif /* HAVE_MMAP */
 }
 
-/** the the file mtime stat (or nonexist or error) */
+/** get the file mtime stat (or nonexist or error) */
 int
 file_get_mtime(const char* file, struct timespec* mtime, int* nonexist)
 {
index 0075ef7..24b6e09 100644 (file)
@@ -1,9 +1,54 @@
+10 February 2022: Wouter
+       - Tag for 4.4.0rc1 release.
+
+9 February 2022: Wouter
+       - Fix unit tests for nds-control-setup exit code and the
+         xfrd-tcp-max default.
+
+7 February 2022: Wouter
+       - Merge #207 Sync nsd-control-setup with unbound-control-setup to
+         generate certificates with SANs.
+
+28 January 2022: Wouter
+       - Fix #206: build with --without-ssl fails.
+
+27 January 2022: Wouter
+       - current code branch continues as version 4.4.0, because of added
+         feature.
+
+26 January 2022: Wouter
+       - Merge #193: Lower memory usage of the XFRD process by default.
+         Instead of preallocating all elements, they are allocated when used.
+         There are options for managing the memory usage, defaults are the
+         same as before. xfrd-tcp-max sets the number of sockets for tcp
+         connections that xfrd can make to download zone contents. And
+         xfrd-tcp-pipeline the number of simultaneous transfers over the
+         same connection.
+
+12 January 2022: Wouter
+       - Fix to document nsd-checkzone -p in the man page for nsd-checkzone.
+
+7 January 2022: Wouter
+       - Fix to change file mode before changing file owner for the
+         nsd-control unix socket file.
+
+3 January 2022: Wouter
+       - Merge #204 from jonathangray: correct some spelling mistakes.
+
+15 December 2021: Wouter
+       - Fix #200: nsd-checkzone succeeds even with incorrect serial in SOA
+         record.
+
 2 December 2021: Wouter
        - Fix socket_partitioning unit test for FreeBSD.
        - Fix SVCB test to work around older dig with drill.
+       - Fix unit test to not syslog setlogin failures.
 
 1 December 2021: Wouter
        - Set up for branch for 4.3.9 release.
+         This became release 4.3.9 on 9 Dec 2021 and included the changes
+         until the SVCB fix on 2 dec 2021, but not the setlogin fix.
+         The main branch continues as 4.3.10.
        - Fix unit tests for new answer-cookie default.
 
 30 November 2021: Wouter
index 176d762..aa64918 100644 (file)
@@ -1,5 +1,28 @@
 NSD RELEASE NOTES
 
+4.4.0
+================
+FEATURES:
+       - Merge #193: Lower memory usage of the XFRD process by default.
+         Instead of preallocating all elements, they are allocated when used.
+         There are options for managing the memory usage, defaults are the
+         same as before. xfrd-tcp-max sets the number of sockets for tcp
+         connections that xfrd can make to download zone contents. And
+         xfrd-tcp-pipeline the number of simultaneous transfers over the
+         same connection.
+BUG FIXES:
+       - Fix #200: nsd-checkzone succeeds even with incorrect serial in SOA
+         record.
+       - Merge #204 from jonathangray: correct some spelling mistakes.
+       - Fix to change file mode before changing file owner for the
+         nsd-control unix socket file.
+       - Fix to document nsd-checkzone -p in the man page for nsd-checkzone.
+       - Fix #206: build with --without-ssl fails.
+       - Merge #207 Sync nsd-control-setup with unbound-control-setup to
+         generate certificates with SANs.
+       - Fix unit tests for nds-control-setup exit code and the
+         xfrd-tcp-max default.
+
 4.3.9
 ================
 BUG FIXES:
index c7fc39d..478ec68 100644 (file)
 #include "nsd.h"
 #include "query.h"
 
+#if !defined(HAVE_SSL) || !defined(HAVE_CRYPTO_MEMCMP)
+/* we need fixed time compare, pull it in from tsig.c */
+#define CRYPTO_memcmp memcmp_fixedtime
+int memcmp_fixedtime(const void *s1, const void *s2, size_t n);
+#endif
+
 void
 edns_init_data(edns_data_type *data, uint16_t max_length)
 {
index 9602ffa..9b47d15 100644 (file)
@@ -872,7 +872,7 @@ void driver2()
     {
       for (j=0; j<8; ++j)   /*------------------------ for each input bit, */
       {
-       for (m=1; m<8; ++m) /*------------ for serveral possible initvals, */
+       for (m=1; m<8; ++m) /*------------ for several possible initvals, */
        {
          for (l=0; l<HASHSTATE; ++l)
            e[l]=f[l]=g[l]=h[l]=x[l]=y[l]=~((uint32_t)0);
index d97e021..60fb069 100644 (file)
@@ -1,4 +1,4 @@
-.TH "nsd\-checkconf" "8" "Dec  9, 2021" "NLnet Labs" "nsd 4.3.9"
+.TH "nsd\-checkconf" "8" "Feb 17, 2022" "NLnet Labs" "nsd 4.4.0"
 .\" Copyright (c) 2001\-2008, NLnet Labs. All rights reserved.
 .\" See LICENSE for the license.
 .SH "NAME"
index 342b308..b9c9472 100644 (file)
@@ -433,6 +433,8 @@ config_print_zone(nsd_options_type* opt, const char* k, int s, const char *o,
                SERV_GET_INT(tcp_timeout, o);
                SERV_GET_INT(tcp_mss, o);
                SERV_GET_INT(outgoing_tcp_mss, o);
+               SERV_GET_INT(xfrd_tcp_max, o);
+               SERV_GET_INT(xfrd_tcp_pipeline, o);
                SERV_GET_INT(ipv4_edns_size, o);
                SERV_GET_INT(ipv6_edns_size, o);
                SERV_GET_INT(statistics, o);
@@ -581,6 +583,8 @@ config_test_print_server(nsd_options_type* opt)
        printf("\ttcp-timeout: %d\n", opt->tcp_timeout);
        printf("\ttcp-mss: %d\n", opt->tcp_mss);
        printf("\toutgoing-tcp-mss: %d\n", opt->outgoing_tcp_mss);
+       printf("\txfrd-tcp-max: %d\n", opt->xfrd_tcp_max);
+       printf("\txfrd-tcp-pipeline: %d\n", opt->xfrd_tcp_pipeline);
        printf("\tipv4-edns-size: %d\n", (int) opt->ipv4_edns_size);
        printf("\tipv6-edns-size: %d\n", (int) opt->ipv6_edns_size);
        print_string_var("pidfile:", opt->pidfile);
index c43a34a..bc2cb47 100644 (file)
@@ -1,4 +1,4 @@
-.TH "nsd\-checkzone" "8" "Dec  9, 2021" "NLnet Labs" "nsd 4.3.9"
+.TH "nsd\-checkzone" "8" "Feb 17, 2022" "NLnet Labs" "nsd 4.4.0"
 .\" Copyright (c) 2014, NLnet Labs. All rights reserved.
 .\" See LICENSE for the license.
 .SH "NAME"
@@ -25,6 +25,12 @@ The name of the zone to check, eg. "example.com".
 .TP
 .I zonefile
 The file to read, eg. "zones/example.com.zone.signed".
+.TP
+.B \-p
+Print the zone contents to stdout if the zone is ok. This prints the
+contents as it has been parsed, not literally a copy of the input, but
+as printed by the formatting routines in NSD, much like the nsd-control
+command write does.
 .SH "SEE ALSO"
 \fInsd\fR(8), \fInsd-checkconf\fR(8)
 .SH "AUTHORS"
index ab9b1ea..d1cc038 100644 (file)
@@ -43,7 +43,7 @@ SERVERNAME=nsd
 CLIENTNAME=nsd-control
 
 # validity period for certificates
-DAYS=3650
+DAYS=7200
 
 # size of keys in bits
 BITS=3072
@@ -86,9 +86,7 @@ fatal() {
 usage() {
     cat <<EOF
 usage: $0 OPTIONS
-
 OPTIONS
-
 -d <dir>  used directory to store keys and certificates (default: $DESTDIR)
 -h        show help notice
 -r        recreate certificates
@@ -99,7 +97,7 @@ OPTIND=1
 while getopts 'd:hr' arg; do
     case "$arg" in
       d) DESTDIR="$OPTARG" ;;
-      h) usage; exit 0 ;;
+      h) usage; exit 1 ;;
       r) RECREATE=1 ;;
       ?) fatal "'$arg' unknown option" ;;
     esac
@@ -122,13 +120,19 @@ if [ ! -f "$SVR_BASE.key" ]; then
 fi
 
 cat >server.cnf <<EOF
+[req]
 default_bits=$BITS
 default_md=$HASH
 prompt=no
 distinguished_name=req_distinguished_name
-
+x509_extensions=v3_ca
 [req_distinguished_name]
 commonName=$SERVERNAME
+[v3_ca]
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid:always,issuer:always
+basicConstraints=critical,CA:TRUE,pathlen:0
+subjectAltName=DNS:$SERVERNAME
 EOF
 
 [ -f server.cnf ] || fatal "cannot create openssl configuration"
@@ -159,9 +163,12 @@ default_bits=$BITS
 default_md=$HASH
 prompt=no
 distinguished_name=req_distinguished_name
-
+req_extensions=v3_req
 [req_distinguished_name]
 commonName=$CLIENTNAME
+[v3_req]
+basicConstraints=critical,CA:FALSE
+subjectAltName=DNS:$CLIENTNAME
 EOF
 
 [ -f client.cnf ] || fatal "cannot create openssl configuration"
@@ -183,6 +190,8 @@ if [ ! -f "$CTL_BASE.pem" -o $RECREATE -eq 1 ]; then
                   -CAkey "$SVR_BASE.key" \
                   -CAcreateserial \
                   -$HASH \
+                  -extfile client.cnf \
+                  -extensions v3_req \
                   -out "$CTL_BASE.pem"
 
     [ ! -f "CTL_BASE.pem" ] || fatal "cannot create signed client certificate"
@@ -199,7 +208,6 @@ cleanup
 
 echo "Setup success. Certificates created. Enable in nsd.conf file to use"
 
-
 # create trusted usage pem
 # openssl x509 -in $CTL_BASE.pem -addtrust clientAuth -out $CTL_BASE"_trust.pem"
 
index 6051468..8242eeb 100644 (file)
@@ -1,4 +1,4 @@
-.TH "nsd\-control" "8" "Dec  9, 2021" "NLnet Labs" "nsd 4.3.9"
+.TH "nsd\-control" "8" "Feb 17, 2022" "NLnet Labs" "nsd 4.4.0"
 .\" Copyright (c) 2011, NLnet Labs. All rights reserved.
 .\" See LICENSE for the license.
 .SH "NAME"
index 48682e9..9edbf09 100644 (file)
@@ -1,9 +1,9 @@
-.TH "NSD" "8" "Dec  9, 2021" "NLnet Labs" "NSD 4.3.9"
+.TH "NSD" "8" "Feb 17, 2022" "NLnet Labs" "NSD 4.4.0"
 .\" Copyright (c) 2001\-2008, NLnet Labs. All rights reserved.
 .\" See LICENSE for the license.
 .SH "NAME"
 .B nsd
-\- Name Server Daemon (NSD) version 4.3.9.
+\- Name Server Daemon (NSD) version 4.4.0.
 .SH "SYNOPSIS"
 .B nsd
 .RB [ \-4 ] 
index cf05f08..f1299c1 100644 (file)
@@ -1,4 +1,4 @@
-.TH "nsd.conf" "5" "Dec  9, 2021" "NLnet Labs" "nsd 4.3.9"
+.TH "nsd.conf" "5" "Feb 17, 2022" "NLnet Labs" "nsd 4.4.0"
 .\" Copyright (c) 2001\-2008, NLnet Labs. All rights reserved.
 .\" See LICENSE for the license.
 .SH "NAME"
@@ -298,13 +298,29 @@ negotiation between server and client.
 .TP
 .B outgoing\-tcp\-mss:\fR <number>
 Maximum segment size (MSS) of TCP socket for outgoing XFR request
-to other namesevers. Value lower than
+to other nameservers. Value lower than
 common MSS on Ethernet (1220 for example) will
 address path MTU problem.
 Note that not all platform supports socket option to set MSS (TCP_MAXSEG).
 Default is system default MSS determined by interface MTU and
 negotiation between NSD and other servers.
 .TP
+.B xfrd\-tcp\-max:\fR <number>
+Number of sockets for xfrd to use for outgoing zone transfers. Default 128.
+Increase it to allow more zone transfer sockets, like to 256.
+To save memory, this can be lowered, set it lower together with some other
+settings to have reduced memory footprint for NSD. xfrd\-tcp\-max: 32
+and xfrd\-tcp\-pipeline: 128 and rrl\-size: 1000
+.IP
+This reduces memory footprint, other memory usage is caused mainly by
+the server\-count setting, the number of server processes, and the
+tcp\-count setting, which keeps buffers per server process, and by the
+size of the zone data.
+.TP
+.B xfrd\-tcp\-pipeline:\fR <number>
+Number of simultaneous outgoing zone transfers that are possible on the
+tcp sockets of xfrd. Max is 65536, default is 128.
+.TP
 .B ipv4\-edns\-size:\fR <number>
 Preferred EDNS buffer size for IPv4.  Default 1232.
 .TP
@@ -493,7 +509,7 @@ With the value 0 the rate is unlimited.
 .\" rrlend
 .TP
 .B answer\-cookie:\fR <yes or no>
-Enable to answer to requests containig DNS Cookies as specified in RFC7873.
+Enable to answer to requests containing DNS Cookies as specified in RFC7873.
 Default is yes.
 .TP
 .B cookie\-secret:\fR <128 bit hex string>
index 9758c37..0e006ba 100644 (file)
@@ -174,6 +174,15 @@ server:
        # Default is 0, system default MSS.
        # outgoing-tcp-mss: 0
 
+       # reduce these settings to save memory for NSD, to about
+       # xfrd-tcp-max: 32 and xfrd-tcp-pipeline: 128, also rrl-size: 1000
+       # other memory is determined by server-count, tcp-count and zone data
+       # max number of sockets used for outgoing zone transfers.
+       # Increase this to allow more sockets for zone transfers.
+       # xfrd-tcp-max: 128
+       # max number of simultaneous outgoing zone transfers over one socket.
+       # xfrd-tcp-pipeline: 128
+
        # Preferred EDNS buffer size for IPv4.
        # ipv4-edns-size: 1232
 
@@ -378,7 +387,7 @@ remote-control:
        #request-xfr: 192.0.2.2 the_tsig_key_name
        #request-xfr: 192.0.2.2 the_tsig_key_name the_tls_auth_name
        # Attention: You cannot use UDP and AXFR together. AXFR is always over
-       # TCP. If you use UDP, we higly recommend you to deploy TSIG.
+       # TCP. If you use UDP, we highly recommend you to deploy TSIG.
        # Allow AXFR fallback if the master does not support IXFR. Default
        # is yes.
        #allow-axfr-fallback: yes
index d8fe022..c684698 100644 (file)
@@ -91,6 +91,8 @@ nsd_options_create(region_type* region)
        opt->port = UDP_PORT;
 /* deprecated? opt->port = TCP_PORT; */
        opt->reuseport = 0;
+       opt->xfrd_tcp_max = 128;
+       opt->xfrd_tcp_pipeline = 128;
        opt->statistics = 0;
        opt->chroot = 0;
        opt->username = USER;
index f1c57ae..54357c8 100644 (file)
@@ -112,6 +112,10 @@ struct nsd_options {
        int minimal_responses;
        int refuse_any;
        int reuseport;
+       /* max number of xfrd tcp sockets */
+       int xfrd_tcp_max;
+       /* max number of simultaneous requests on xfrd tcp socket */
+       int xfrd_tcp_pipeline;
 
        /* private key file for TLS */
        char* tls_service_key;
index 81ec53f..c94a1d9 100644 (file)
@@ -436,6 +436,9 @@ add_open(struct daemon_remote* rc, struct nsd_options* cfg, const char* ip,
                 */
                if(fd != -1) {
 #ifdef HAVE_CHOWN
+                       if(chmod(ip, (mode_t)(S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) == -1) {
+                               VERBOSITY(3, (LOG_INFO, "cannot chmod control socket %s: %s", ip, strerror(errno)));
+                       }
                        if (cfg->username && cfg->username[0] &&
                                nsd.uid != (uid_t)-1) {
                                if(chown(ip, nsd.uid, nsd.gid) == -1)
@@ -443,9 +446,6 @@ add_open(struct daemon_remote* rc, struct nsd_options* cfg, const char* ip,
                                          (unsigned)nsd.uid, (unsigned)nsd.gid,
                                          ip, strerror(errno)));
                        }
-                       if(chmod(ip, (mode_t)(S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) == -1) {
-                               VERBOSITY(3, (LOG_INFO, "cannot chmod control socket %s: %s", ip, strerror(errno)));
-                       }
 #else
                        (void)cfg;
 #endif
index 8dbc318..b08d65f 100644 (file)
@@ -51,7 +51,7 @@ void rrl_mmap_init(int numch, size_t numbuck, size_t lm, size_t wlm, size_t sm,
  */
 void rrl_init(size_t ch);
 
-/** deinit (for this child server processs) */
+/** deinit (for this child server process) */
 void rrl_deinit(size_t ch);
 
 /** deinit mmaps for n children */
index f7a2f53..1e29ccc 100644 (file)
@@ -367,7 +367,7 @@ static void report_tcp_fastopen_config() {
        }
        if (!(tcp_fastopen_value & TCP_FASTOPEN_SERVER_BIT_MASK)) {
                log_msg(LOG_WARNING, "Error: TCP Fast Open support is available and configured in NSD by default.\n");
-               log_msg(LOG_WARNING, "However the kernel paramenters are not configured to support TCP_FASTOPEN in server mode.\n");
+               log_msg(LOG_WARNING, "However the kernel parameters are not configured to support TCP_FASTOPEN in server mode.\n");
                log_msg(LOG_WARNING, "To enable TFO use the command:");
                log_msg(LOG_WARNING, "  'sudo sysctl -w net.ipv4.tcp_fastopen=2' for pure server mode or\n");
                log_msg(LOG_WARNING, "  'sudo sysctl -w net.ipv4.tcp_fastopen=3' for both client and server mode\n");
index fb129b8..1131fb4 100644 (file)
@@ -1149,7 +1149,7 @@ grow_extra_check(udb_alloc* alloc, uint64_t ge)
        return ge;
 }
 
-/** see if free space is enogh to warrant shrink (while file is open) */
+/** see if free space is enough to warrant shrink (while file is open) */
 static int
 enough_free(udb_alloc* alloc)
 {
index 3ee9864..b3f495d 100644 (file)
@@ -198,7 +198,7 @@ struct udb_base {
        udb_ptr** ram_hash;
        /** size of the current udb_ptr hashtable array */
        size_t ram_size;
-       /** mask for the curren udb_ptr hashtable lookups */
+       /** mask for the current udb_ptr hashtable lookups */
        int ram_mask;
        /** number of ptrs in ram, used to decide when to grow */
        size_t ram_num;
index 4595423..7afe34e 100644 (file)
@@ -529,7 +529,7 @@ strtoserial(const char* nptr, const char** endptr)
                        i += (**endptr - '0');
                        break;
                default:
-                       break;
+                       return 0;
                }
        }
        serial += i;
index a71c195..df9caaf 100644 (file)
@@ -156,12 +156,15 @@ xfrd_pipe_cmp(const void* a, const void* b)
        return (uintptr_t)x < (uintptr_t)y ? -1 : 1;
 }
 
-struct xfrd_tcp_set* xfrd_tcp_set_create(struct region* region, const char *tls_cert_bundle)
+struct xfrd_tcp_set* xfrd_tcp_set_create(struct region* region, const char *tls_cert_bundle, int tcp_max, int tcp_pipeline)
 {
        int i;
        struct xfrd_tcp_set* tcp_set = region_alloc(region,
                sizeof(struct xfrd_tcp_set));
        memset(tcp_set, 0, sizeof(struct xfrd_tcp_set));
+       tcp_set->tcp_state = NULL;
+       tcp_set->tcp_max = tcp_max;
+       tcp_set->tcp_pipeline = tcp_pipeline;
        tcp_set->tcp_count = 0;
        tcp_set->tcp_waiting_first = 0;
        tcp_set->tcp_waiting_last = 0;
@@ -180,27 +183,191 @@ struct xfrd_tcp_set* xfrd_tcp_set_create(struct region* region, const char *tls_
        (void)tls_cert_bundle;
        log_msg(LOG_INFO, "xfrd: No TLS 1.3 support - XFR-over-TLS not available");
 #endif
-       for(i=0; i<XFRD_MAX_TCP; i++)
-               tcp_set->tcp_state[i] = xfrd_tcp_pipeline_create(region);
+       tcp_set->tcp_state = region_alloc(region,
+               sizeof(*tcp_set->tcp_state)*tcp_set->tcp_max);
+       for(i=0; i<tcp_set->tcp_max; i++)
+               tcp_set->tcp_state[i] = xfrd_tcp_pipeline_create(region,
+                       tcp_pipeline);
        tcp_set->pipetree = rbtree_create(region, &xfrd_pipe_cmp);
        return tcp_set;
 }
 
+static int pipeline_id_compare(const void* x, const void* y)
+{
+       struct xfrd_tcp_pipeline_id* a = (struct xfrd_tcp_pipeline_id*)x;
+       struct xfrd_tcp_pipeline_id* b = (struct xfrd_tcp_pipeline_id*)y;
+       if(a->id < b->id)
+               return -1;
+       if(a->id > b->id)
+               return 1;
+       return 0;
+}
+
+void pick_id_values(uint16_t* array, int num, int max)
+{
+       uint8_t inserted[65536];
+       int j, done;
+       if(num == 65536) {
+               /* all of them, loop and insert */
+               int i;
+               for(i=0; i<num; i++)
+                       array[i] = (uint16_t)i;
+               return;
+       }
+       assert(max <= 65536);
+       /* This uses the Robert Floyd sampling algorithm */
+       /* keep track if values are already inserted, using the bitmap
+        * in insert array */
+       memset(inserted, 0, sizeof(inserted[0])*max);
+       done=0;
+       for(j = max-num; j<max; j++) {
+               /* random generate creates from 0..arg-1 */
+               int t;
+               if(j+1 <= 1)
+                       t = 0;
+               else    t = random_generate(j+1);
+               if(!inserted[t]) {
+                       array[done++]=t;
+                       inserted[t] = 1;
+               } else {
+                       array[done++]=j;
+                       inserted[j] = 1;
+               }
+       }
+}
+
+static void
+clear_pipeline_entry(struct xfrd_tcp_pipeline* tp, rbnode_type* node)
+{
+       struct xfrd_tcp_pipeline_id *n;
+       if(node == NULL || node == RBTREE_NULL)
+               return;
+       clear_pipeline_entry(tp, node->left);
+       node->left = NULL;
+       clear_pipeline_entry(tp, node->right);
+       node->right = NULL;
+       /* move the node into the free list */
+       n = (struct xfrd_tcp_pipeline_id*)node;
+       n->next_free = tp->pipe_id_free_list;
+       tp->pipe_id_free_list = n;
+}
+
+static void
+xfrd_tcp_pipeline_cleanup(struct xfrd_tcp_pipeline* tp)
+{
+       /* move entries into free list */
+       clear_pipeline_entry(tp, tp->zone_per_id->root);
+       /* clear the tree */
+       tp->zone_per_id->count = 0;
+       tp->zone_per_id->root = RBTREE_NULL;
+}
+
+static void
+xfrd_tcp_pipeline_init(struct xfrd_tcp_pipeline* tp)
+{
+       tp->key.node.key = tp;
+       tp->key.num_unused = tp->pipe_num;
+       tp->key.num_skip = 0;
+       tp->tcp_send_first = NULL;
+       tp->tcp_send_last = NULL;
+       xfrd_tcp_pipeline_cleanup(tp);
+       pick_id_values(tp->unused, tp->pipe_num, 65536);
+}
+
 struct xfrd_tcp_pipeline*
-xfrd_tcp_pipeline_create(region_type* region)
+xfrd_tcp_pipeline_create(region_type* region, int tcp_pipeline)
 {
        int i;
        struct xfrd_tcp_pipeline* tp = (struct xfrd_tcp_pipeline*)
                region_alloc_zero(region, sizeof(*tp));
-       tp->key.num_unused = ID_PIPE_NUM;
-       assert(sizeof(tp->unused)/sizeof(tp->unused[0]) == ID_PIPE_NUM);
-       for(i=0; i<ID_PIPE_NUM; i++)
-               tp->unused[i] = (uint16_t)i;
+       if(tcp_pipeline < 0)
+               tcp_pipeline = 0;
+       if(tcp_pipeline > 65536)
+               tcp_pipeline = 65536; /* max 16 bit ID numbers */
+       tp->pipe_num = tcp_pipeline;
+       tp->key.num_unused = tp->pipe_num;
+       tp->zone_per_id = rbtree_create(region, &pipeline_id_compare);
+       tp->pipe_id_free_list = NULL;
+       for(i=0; i<tp->pipe_num; i++) {
+               struct xfrd_tcp_pipeline_id* n = (struct xfrd_tcp_pipeline_id*)
+                       region_alloc_zero(region, sizeof(*n));
+               n->next_free = tp->pipe_id_free_list;
+               tp->pipe_id_free_list = n;
+       }
+       tp->unused = (uint16_t*)region_alloc_zero(region,
+               sizeof(tp->unused[0])*tp->pipe_num);
        tp->tcp_r = xfrd_tcp_create(region, QIOBUFSZ);
        tp->tcp_w = xfrd_tcp_create(region, 512);
+       xfrd_tcp_pipeline_init(tp);
        return tp;
 }
 
+static struct xfrd_zone*
+xfrd_tcp_pipeline_lookup_id(struct xfrd_tcp_pipeline* tp, uint16_t id)
+{
+       struct xfrd_tcp_pipeline_id key;
+       rbnode_type* n;
+       memset(&key, 0, sizeof(key));
+       key.node.key = &key;
+       key.id = id;
+       n = rbtree_search(tp->zone_per_id, &key);
+       if(n && n != RBTREE_NULL) {
+               return ((struct xfrd_tcp_pipeline_id*)n)->zone;
+       }
+       return NULL;
+}
+
+static void
+xfrd_tcp_pipeline_insert_id(struct xfrd_tcp_pipeline* tp, uint16_t id,
+       struct xfrd_zone* zone)
+{
+       struct xfrd_tcp_pipeline_id* n;
+       /* because there are tp->pipe_num preallocated entries, and we have
+        * only tp->pipe_num id values, the list cannot be empty now. */
+       assert(tp->pipe_id_free_list != NULL);
+       /* pick up next free xfrd_tcp_pipeline_id node */
+       n = tp->pipe_id_free_list;
+       tp->pipe_id_free_list = n->next_free;
+       n->next_free = NULL;
+       memset(&n->node, 0, sizeof(n->node));
+       n->node.key = n;
+       n->id = id;
+       n->zone = zone;
+       rbtree_insert(tp->zone_per_id, &n->node);
+}
+
+static void
+xfrd_tcp_pipeline_remove_id(struct xfrd_tcp_pipeline* tp, uint16_t id)
+{
+       struct xfrd_tcp_pipeline_id key;
+       rbnode_type* node;
+       memset(&key, 0, sizeof(key));
+       key.node.key = &key;
+       key.id = id;
+       node = rbtree_delete(tp->zone_per_id, &key);
+       if(node && node != RBTREE_NULL) {
+               struct xfrd_tcp_pipeline_id* n =
+                       (struct xfrd_tcp_pipeline_id*)node;
+               n->next_free = tp->pipe_id_free_list;
+               tp->pipe_id_free_list = n;
+       }
+}
+
+static void
+xfrd_tcp_pipeline_skip_id(struct xfrd_tcp_pipeline* tp, uint16_t id)
+{
+       struct xfrd_tcp_pipeline_id key;
+       rbnode_type* n;
+       memset(&key, 0, sizeof(key));
+       key.node.key = &key;
+       key.id = id;
+       n = rbtree_search(tp->zone_per_id, &key);
+       if(n && n != RBTREE_NULL) {
+               struct xfrd_tcp_pipeline_id* zid = (struct xfrd_tcp_pipeline_id*)n;
+               zid->zone = TCP_NULL_SKIP;
+       }
+}
+
 void
 xfrd_setup_packet(buffer_type* packet,
        uint16_t type, uint16_t klass, const dname_type* dname, uint16_t qid)
@@ -346,7 +513,7 @@ pipeline_find(struct xfrd_tcp_set* set, xfrd_zone_type* zone)
        struct xfrd_tcp_pipeline_key k, *key=&k;
        key->node.key = key;
        key->ip_len = xfrd_acl_sockaddr_to(zone->master, &key->ip);
-       key->num_unused = ID_PIPE_NUM;
+       key->num_unused = set->tcp_pipeline;
        /* lookup existing tcp transfer to the master with highest unused */
        if(rbtree_find_less_equal(set->pipetree, key, &sme)) {
                /* exact match, strange, fully unused tcp cannot be open */
@@ -407,11 +574,12 @@ tcp_pipe_sendlist_popfirst(struct xfrd_tcp_pipeline* tp, xfrd_zone_type* zone)
 
 /* remove zone from tcp pipe ID map */
 static void
-tcp_pipe_id_remove(struct xfrd_tcp_pipeline* tp, xfrd_zone_type* zone)
+tcp_pipe_id_remove(struct xfrd_tcp_pipeline* tp, xfrd_zone_type* zone,
+       int alsotree)
 {
-       assert(tp->key.num_unused < ID_PIPE_NUM && tp->key.num_unused >= 0);
-       assert(tp->id[zone->query_id] == zone);
-       tp->id[zone->query_id] = NULL;
+       assert(tp->key.num_unused < tp->pipe_num && tp->key.num_unused >= 0);
+       if(alsotree)
+               xfrd_tcp_pipeline_remove_id(tp, zone->query_id);
        tp->unused[tp->key.num_unused] = zone->query_id;
        /* must remove and re-add for sort order in tree */
        (void)rbtree_delete(xfrd->tcp_set->pipetree, &tp->key.node);
@@ -423,22 +591,25 @@ tcp_pipe_id_remove(struct xfrd_tcp_pipeline* tp, xfrd_zone_type* zone)
 static void
 xfrd_tcp_pipe_stop(struct xfrd_tcp_pipeline* tp)
 {
-       int i, conn = -1;
-       assert(tp->key.num_unused < ID_PIPE_NUM); /* at least one 'in-use' */
-       assert(ID_PIPE_NUM - tp->key.num_unused > tp->key.num_skip); /* at least one 'nonskip' */
+       struct xfrd_tcp_pipeline_id* zid;
+       int conn = -1;
+       assert(tp->key.num_unused < tp->pipe_num); /* at least one 'in-use' */
+       assert(tp->pipe_num - tp->key.num_unused > tp->key.num_skip); /* at least one 'nonskip' */
        /* need to retry for all the zones connected to it */
        /* these could use different lists and go to a different nextmaster*/
-       for(i=0; i<ID_PIPE_NUM; i++) {
-               if(tp->id[i] && tp->id[i] != TCP_NULL_SKIP) {
-                       xfrd_zone_type* zone = tp->id[i];
+       RBTREE_FOR(zid, struct xfrd_tcp_pipeline_id*, tp->zone_per_id) {
+               xfrd_zone_type* zone = zid->zone;
+               if(zone && zone != TCP_NULL_SKIP) {
+                       assert(zone->query_id == zid->id);
                        conn = zone->tcp_conn;
                        zone->tcp_conn = -1;
                        zone->tcp_waiting = 0;
                        tcp_pipe_sendlist_remove(tp, zone);
-                       tcp_pipe_id_remove(tp, zone);
+                       tcp_pipe_id_remove(tp, zone, 0);
                        xfrd_set_refresh_now(zone);
                }
        }
+       xfrd_tcp_pipeline_cleanup(tp);
        assert(conn != -1);
        /* now release the entire tcp pipe */
        xfrd_tcp_pipe_release(xfrd->tcp_set, tp, conn);
@@ -508,7 +679,7 @@ pipeline_setup_new_zone(struct xfrd_tcp_set* set, struct xfrd_tcp_pipeline* tp,
        idx = random_generate(tp->key.num_unused);
        zone->query_id = tp->unused[idx];
        tp->unused[idx] = tp->unused[tp->key.num_unused-1];
-       tp->id[zone->query_id] = zone;
+       xfrd_tcp_pipeline_insert_id(tp, zone->query_id, zone);
        /* decrement unused counter, and fixup tree */
        (void)rbtree_delete(set->pipetree, &tp->key.node);
        tp->key.num_unused--;
@@ -538,12 +709,12 @@ xfrd_tcp_obtain(struct xfrd_tcp_set* set, xfrd_zone_type* zone)
        assert(zone->tcp_conn == -1);
        assert(zone->tcp_waiting == 0);
 
-       if(set->tcp_count < XFRD_MAX_TCP) {
+       if(set->tcp_count < set->tcp_max) {
                int i;
                assert(!set->tcp_waiting_first);
                set->tcp_count ++;
                /* find a free tcp_buffer */
-               for(i=0; i<XFRD_MAX_TCP; i++) {
+               for(i=0; i<set->tcp_max; i++) {
                        if(set->tcp_state[i]->tcp_r->fd == -1) {
                                zone->tcp_conn = i;
                                break;
@@ -568,15 +739,7 @@ xfrd_tcp_obtain(struct xfrd_tcp_set* set, xfrd_zone_type* zone)
                        return;
                }
                /* ip and ip_len set by tcp_open */
-               tp->key.node.key = tp;
-               tp->key.num_unused = ID_PIPE_NUM;
-               tp->key.num_skip = 0;
-               tp->tcp_send_first = NULL;
-               tp->tcp_send_last = NULL;
-               memset(tp->id, 0, sizeof(tp->id));
-               for(i=0; i<ID_PIPE_NUM; i++) {
-                       tp->unused[i] = i;
-               }
+               xfrd_tcp_pipeline_init(tp);
 
                /* insert into tree */
                (void)rbtree_insert(set->pipetree, &tp->key.node);
@@ -590,7 +753,7 @@ xfrd_tcp_obtain(struct xfrd_tcp_set* set, xfrd_zone_type* zone)
                int i;
                if(zone->zone_handler.ev_fd != -1)
                        xfrd_udp_release(zone);
-               for(i=0; i<XFRD_MAX_TCP; i++) {
+               for(i=0; i<set->tcp_max; i++) {
                        if(set->tcp_state[i] == tp)
                                zone->tcp_conn = i;
                }
@@ -602,7 +765,7 @@ xfrd_tcp_obtain(struct xfrd_tcp_set* set, xfrd_zone_type* zone)
 
        /* wait, at end of line */
        DEBUG(DEBUG_XFRD,2, (LOG_INFO, "xfrd: max number of tcp "
-               "connections (%d) reached.", XFRD_MAX_TCP));
+               "connections (%d) reached.", set->tcp_max));
        zone->tcp_waiting_next = 0;
        zone->tcp_waiting_prev = set->tcp_waiting_last;
        zone->tcp_waiting = 1;
@@ -1312,7 +1475,7 @@ xfrd_tcp_read(struct xfrd_tcp_pipeline* tp)
                tcp_conn_ready_for_reading(tcp);
                return;
        }
-       zone = tp->id[ID(tcp->packet)];
+       zone = xfrd_tcp_pipeline_lookup_id(tp, ID(tcp->packet));
        if(!zone || zone == TCP_NULL_SKIP) {
                /* no zone for this id? skip it */
                DEBUG(DEBUG_XFRD,1, (LOG_INFO,
@@ -1333,7 +1496,7 @@ xfrd_tcp_read(struct xfrd_tcp_pipeline* tp)
                        break;
                case xfrd_packet_newlease:
                        /* set to skip if more packets with this ID */
-                       tp->id[zone->query_id] = TCP_NULL_SKIP;
+                       xfrd_tcp_pipeline_skip_id(tp, zone->query_id);
                        tp->key.num_skip++;
                        /* fall through to remove zone from tp */
                        /* fallthrough */
@@ -1356,7 +1519,7 @@ xfrd_tcp_read(struct xfrd_tcp_pipeline* tp)
                case xfrd_packet_tcp:
                default:
                        /* set to skip if more packets with this ID */
-                       tp->id[zone->query_id] = TCP_NULL_SKIP;
+                       xfrd_tcp_pipeline_skip_id(tp, zone->query_id);
                        tp->key.num_skip++;
                        xfrd_tcp_release(xfrd->tcp_set, zone);
                        /* query next server */
@@ -1380,8 +1543,8 @@ xfrd_tcp_release(struct xfrd_tcp_set* set, xfrd_zone_type* zone)
        /* remove from tcp_send list */
        tcp_pipe_sendlist_remove(tp, zone);
        /* remove it from the ID list */
-       if(tp->id[zone->query_id] != TCP_NULL_SKIP)
-               tcp_pipe_id_remove(tp, zone);
+       if(xfrd_tcp_pipeline_lookup_id(tp, zone->query_id) != TCP_NULL_SKIP)
+               tcp_pipe_id_remove(tp, zone, 1);
        DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: released tcp pipe now %d unused",
                tp->key.num_unused));
        /* if pipe was full, but no more, then see if waiting element is
@@ -1410,7 +1573,7 @@ xfrd_tcp_release(struct xfrd_tcp_set* set, xfrd_zone_type* zone)
        }
 
        /* if all unused, or only skipped leftover, close the pipeline */
-       if(tp->key.num_unused >= ID_PIPE_NUM || tp->key.num_skip >= ID_PIPE_NUM - tp->key.num_unused)
+       if(tp->key.num_unused >= tp->pipe_num || tp->key.num_skip >= tp->pipe_num - tp->key.num_unused)
                xfrd_tcp_pipe_release(set, tp, conn);
 }
 
@@ -1446,9 +1609,7 @@ xfrd_tcp_pipe_release(struct xfrd_tcp_set* set, struct xfrd_tcp_pipeline* tp,
        /* a waiting zone can use the free tcp slot (to another server) */
        /* if that zone fails to set-up or connect, we try to start the next
         * waiting zone in the list */
-       while(set->tcp_count == XFRD_MAX_TCP && set->tcp_waiting_first) {
-               int i;
-
+       while(set->tcp_count == set->tcp_max && set->tcp_waiting_first) {
                /* pop first waiting process */
                xfrd_zone_type* zone = set->tcp_waiting_first;
                /* start it */
@@ -1467,15 +1628,7 @@ xfrd_tcp_pipe_release(struct xfrd_tcp_set* set, struct xfrd_tcp_pipeline* tp,
                }
                /* re-init this tcppipe */
                /* ip and ip_len set by tcp_open */
-               tp->key.node.key = tp;
-               tp->key.num_unused = ID_PIPE_NUM;
-               tp->key.num_skip = 0;
-               tp->tcp_send_first = NULL;
-               tp->tcp_send_last = NULL;
-               memset(tp->id, 0, sizeof(tp->id));
-               for(i=0; i<ID_PIPE_NUM; i++) {
-                       tp->unused[i] = i;
-               }
+               xfrd_tcp_pipeline_init(tp);
 
                /* insert into tree */
                (void)rbtree_insert(set->pipetree, &tp->key.node);
index 60d3e23..ab20cf7 100644 (file)
@@ -31,8 +31,12 @@ typedef struct xfrd_tcp_set xfrd_tcp_set_type;
  * A set of xfrd tcp connections.
  */
 struct xfrd_tcp_set {
-       /* tcp connections, each has packet and read/wr state */
-       struct xfrd_tcp_pipeline *tcp_state[XFRD_MAX_TCP];
+       /* tcp connections, array, each has packet and read/wr state */
+       struct xfrd_tcp_pipeline **tcp_state;
+       /* max number of tcp connections, size of tcp_state array */
+       int tcp_max;
+       /* max number of simultaneous connections on a tcp_pipeline */
+       int tcp_pipeline;
        /* number of TCP connections in use. */
        int tcp_count;
        /* TCP timeout. */
@@ -74,8 +78,21 @@ struct xfrd_tcp {
 /* use illegal pointer value to denote skipped ID number.
  * if this does not work, we can allocate with malloc */
 #define TCP_NULL_SKIP ((struct xfrd_zone*)-1)
-/* the number of ID values (16 bits) for a pipeline */
-#define ID_PIPE_NUM 65536
+
+/**
+ * The per-id zone pointers, with TCP_NULL_SKIP or a zone pointer for the
+ * ID value.
+ */
+struct xfrd_tcp_pipeline_id {
+       /** rbtree node as first member, this is the key. */
+       rbnode_type node;
+       /** the ID of this member */
+       uint16_t id;
+       /** zone pointer or TCP_NULL_SKIP */
+       struct xfrd_zone* zone;
+       /** next free in free list */
+       struct xfrd_tcp_pipeline_id* next_free;
+};
 
 /**
  * The tcp pipeline key structure. By ip_len, ip, num_unused and unique by
@@ -138,23 +155,31 @@ struct xfrd_tcp_pipeline {
        /* list of queries that want to send, first to get write event,
         * if NULL, no write event interest */
        struct xfrd_zone* tcp_send_first, *tcp_send_last;
-       /* the unused and id arrays must be last in the structure */
-       /* per-ID number the queries that have this ID number, every
+
+       /* size of the id and unused arrays. */
+       int pipe_num;
+       /* list of free xfrd_tcp_pipeline_id nodes, these are not in the
+        * zone_per_id tree. preallocated at pipe_num amount. */
+       struct xfrd_tcp_pipeline_id* pipe_id_free_list;
+       /* The xfrd_zone pointers, per id number.
+        * The key is struct xfrd_tcp_pipeline_id.
+        * per-ID number the queries that have this ID number, every
         * query owns one ID numbers (until it is done). NULL: unused
         * When a query is done but not all answer-packets have been
         * consumed for that ID number, the rest is skipped, this
         * is denoted with the pointer-value TCP_NULL_SKIP, the ids that
         * are skipped are not on the unused list.  They may be
         * removed once the last answer packet is skipped.
-        * ID_PIPE_NUM-num_unused values in the id array are nonNULL (either
+        * pipe_num-num_unused values are in the tree (either
         * a zone pointer or SKIP) */
-       struct xfrd_zone* id[ID_PIPE_NUM];
-       /* unused ID numbers; the first part of the array contains the IDs */
-       uint16_t unused[ID_PIPE_NUM];
+       rbtree_type* zone_per_id;
+       /* Array of uint16_t, with ID values.
+        * unused ID numbers; the first part of the array contains the IDs */
+       uint16_t* unused;
 };
 
 /* create set of tcp connections */
-struct xfrd_tcp_set* xfrd_tcp_set_create(struct region* region, const char *tls_cert_bundle);
+struct xfrd_tcp_set* xfrd_tcp_set_create(struct region* region, const char *tls_cert_bundle, int tcp_max, int tcp_pipeline);
 
 /* init tcp state */
 struct xfrd_tcp* xfrd_tcp_create(struct region* region, size_t bufsize);
@@ -219,6 +244,9 @@ socklen_t xfrd_acl_sockaddr_frm(struct acl_options* acl,
 #endif /* INET6 */
 
 /* create pipeline tcp structure */
-struct xfrd_tcp_pipeline* xfrd_tcp_pipeline_create(region_type* region);
+struct xfrd_tcp_pipeline* xfrd_tcp_pipeline_create(region_type* region,
+       int tcp_pipeline);
+/* pick num uint16_t values, from 0..max-1, store in array */
+void pick_id_values(uint16_t* array, int num, int max);
 
 #endif /* XFRD_TCP_H */
index c40e8ca..a9e1558 100644 (file)
@@ -196,7 +196,7 @@ xfrd_init(int socket, struct nsd* nsd, int shortsoa, int reload_active,
        daemon_remote_attach(xfrd->nsd->rc, xfrd);
 #endif
 
-       xfrd->tcp_set = xfrd_tcp_set_create(xfrd->region, nsd->options->tls_cert_bundle);
+       xfrd->tcp_set = xfrd_tcp_set_create(xfrd->region, nsd->options->tls_cert_bundle, nsd->options->xfrd_tcp_max, nsd->options->xfrd_tcp_pipeline);
        xfrd->tcp_set->tcp_timeout = nsd->tcp_timeout;
 #if !defined(HAVE_ARC4RANDOM) && !defined(HAVE_GETRANDOM)
        srandom((unsigned long) getpid() * (unsigned long) time(NULL));
index a3e68ff..b4edf66 100644 (file)
@@ -239,9 +239,10 @@ enum xfrd_packet_result {
    And it should be below FD_SETSIZE, to be able to select() on replies.
    Note that also some sockets are used for writing the ixfr.db, xfrd.state
    files and for the pipes to the main parent process.
+
+   For xfrd_tcp_max, 128 is the default number of TCP AXFR/IXFR concurrent
+   connections. Each entry has 64Kb buffer preallocated.
 */
-#define XFRD_MAX_TCP 128 /* max number of TCP AXFR/IXFR concurrent connections.*/
-                       /* Each entry has 64Kb buffer preallocated.*/
 #define XFRD_MAX_UDP 128 /* max number of UDP sockets at a time for IXFR */
 #define XFRD_MAX_UDP_NOTIFY 128 /* max concurrent UDP sockets for NOTIFY */
 
@@ -364,7 +365,7 @@ void xfrd_deactivate_zone(xfrd_zone_type* z);
 /*
  * Make a new request to next master server.
  * uses next_master if set (and a fresh set of rounds).
- * otherwised, starts new round of requests if none started already.
+ * otherwise, starts new round of requests if none started already.
  * starts next round of requests if at last master.
  * if too many rounds of requests, sets timer for next retry.
  */