diff --git a/daemon/daemon.c b/daemon/daemon.c index a9cc25c67..72cd0dc82 100644 --- a/daemon/daemon.c +++ b/daemon/daemon.c @@ -633,6 +633,25 @@ static void close_other_pipes(struct daemon* daemon, int thr) } #endif /* THREADS_DISABLED */ +/** + * Function to set the thread local log ID. + * Either the internal thread number, or the LWP ID on Linux based on + * configuration. + */ +static void +set_log_thread_id(struct worker* worker, struct config_file* cfg) +{ + (void)cfg; + log_assert(worker); +#if defined(HAVE_GETTID) && !defined(THREADS_DISABLED) + worker->thread_tid = gettid(); + if(cfg->log_thread_id) + log_thread_set(&worker->thread_tid); + else +#endif + log_thread_set(&worker->thread_num); +} + /** * Function to start one thread. * @param arg: user argument. @@ -643,7 +662,7 @@ thread_start(void* arg) { struct worker* worker = (struct worker*)arg; int port_num = 0; - log_thread_set(&worker->thread_num); + set_log_thread_id(worker, worker->daemon->cfg); ub_thread_blocksigs(); #ifdef THREADS_DISABLED /* close pipe ends used by main */ @@ -803,9 +822,13 @@ daemon_fork(struct daemon* daemon) fatal_exit("RPZ requires the respip module"); /* first create all the worker structures, so we can pass - * them to the newly created threads. + * them to the newly created threads. */ daemon_create_workers(daemon); + /* Set it for the first (main) worker since it does not take part in + * the thread_start() procedure. + */ + set_log_thread_id(daemon->workers[0], daemon->cfg); #if defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP) /* in libev the first inited base gets signals */ diff --git a/daemon/remote.c b/daemon/remote.c index 8600a9965..2bcc4012f 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -5972,6 +5972,7 @@ fr_atomic_copy_cfg(struct config_file* oldcfg, struct config_file* cfg, COPY_VAR_int(log_servfail); COPY_VAR_ptr(log_identity); COPY_VAR_int(log_destaddr); + COPY_VAR_int(log_thread_id); COPY_VAR_int(hide_identity); COPY_VAR_int(hide_version); COPY_VAR_int(hide_trustanchor); @@ -6634,7 +6635,14 @@ static void* fast_reload_thread_main(void* arg) struct fast_reload_thread* fast_reload_thread = (struct fast_reload_thread*)arg; struct timeval time_start, time_read, time_construct, time_reload, time_end; - log_thread_set(&fast_reload_thread->threadnum); + +#if defined(HAVE_GETTID) && !defined(THREADS_DISABLED) + fast_reload_thread->thread_tid = gettid(); + if(fast_reload_thread->thread_tid_log) + log_thread_set(&fast_reload_thread->thread_tid); + else +#endif + log_thread_set(&fast_reload_thread->threadnum); verbose(VERB_ALGO, "start fast reload thread"); if(fast_reload_thread->fr_verb >= 1) { @@ -7022,6 +7030,9 @@ fast_reload_thread_setup(struct worker* worker, int fr_verb, int fr_nopause, lock_basic_init(&fr->fr_output_lock); lock_protect(&fr->fr_output_lock, fr->fr_output, sizeof(*fr->fr_output)); +#ifdef HAVE_GETTID + fr->thread_tid_log = worker->env.cfg->log_thread_id; +#endif return 1; } diff --git a/daemon/remote.h b/daemon/remote.h index 064d7b7fc..77c00a597 100644 --- a/daemon/remote.h +++ b/daemon/remote.h @@ -206,6 +206,12 @@ struct fast_reload_thread { int commpair[2]; /** thread id, of the io thread */ ub_thread_type tid; +#ifdef HAVE_GETTID + /** thread tid, the LWP id */ + pid_t thread_tid; + /** if logging should include the LWP id */ + int thread_tid_log; +#endif /** if the io processing has started */ int started; /** if the thread has to quit */ diff --git a/daemon/worker.c b/daemon/worker.c index 229905195..71b90df49 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -2202,9 +2202,6 @@ worker_init(struct worker* worker, struct config_file *cfg, struct dt_env* dtenv = &worker->dtenv; #else void* dtenv = NULL; -#endif -#ifdef HAVE_GETTID - worker->thread_tid = gettid(); #endif worker->need_to_exit = 0; worker->base = comm_base_create(do_sigs); diff --git a/dnstap/dtstream.c b/dnstap/dtstream.c index 39d43403b..30db6f219 100644 --- a/dnstap/dtstream.c +++ b/dnstap/dtstream.c @@ -448,6 +448,9 @@ int dt_io_thread_apply_cfg(struct dt_io_thread* dtio, struct config_file *cfg) dtio->tls_use_sni = cfg->tls_use_sni; #endif /* HAVE_SSL */ } +#ifdef HAVE_GETTID + dtio->thread_tid_log = cfg->log_thread_id; +#endif return 1; } @@ -2130,7 +2133,14 @@ static void* dnstap_io(void* arg) struct dt_io_thread* dtio = (struct dt_io_thread*)arg; time_t secs = 0; struct timeval now; - log_thread_set(&dtio->threadnum); + +#if defined(HAVE_GETTID) && !defined(THREADS_DISABLED) + dtio->thread_tid = gettid(); + if(dtio->thread_tid_log) + log_thread_set(&dtio->thread_tid); + else +#endif + log_thread_set(&dtio->threadnum); /* setup */ verbose(VERB_ALGO, "start dnstap io thread"); diff --git a/dnstap/dtstream.h b/dnstap/dtstream.h index f87d6dc8d..4c0a6285f 100644 --- a/dnstap/dtstream.h +++ b/dnstap/dtstream.h @@ -131,6 +131,12 @@ struct dt_io_thread { struct dt_io_list_item* io_list_iter; /** thread id, of the io thread */ ub_thread_type tid; +#ifdef HAVE_GETTID + /** thread tid, the LWP id */ + pid_t thread_tid; + /** if logging should include the LWP id */ + int thread_tid_log; +#endif /** if the io processing has started */ int started; /** ssl context for the io thread, for tls connections. type SSL_CTX* */ diff --git a/doc/Changelog b/doc/Changelog index bc6eaa2d6..08609fddc 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,21 @@ +27 January 2026: Wouter + - Add test for allow-notify with a host name. + +26 January 2026: Wouter + - Fix that allow-notify entries with hostnames are copied after IPv4 + and IPv6 lookup. + - Fix to not skip allow-notify hostname lookups when there are only + urls. + +23 January 2026: Yorgos + - Merge #1396: Log Linux thread ID. + - On Linux systems log the system-wide unique thread ID instead of + Unbound's internal thread counter. + - Introduce the 'log-thread-id' configuration option to manage logging + the system-wide Linux thread ID for easier debugging with system + tools. + - Update generated man pages. + 22 January 2026: Wouter - Fix that fast reload copies the iter_scrub_ns, iter_scrub_cname and max_global_quota options. diff --git a/doc/example.conf.in b/doc/example.conf.in index b31a26134..c9a2c6300 100644 --- a/doc/example.conf.in +++ b/doc/example.conf.in @@ -496,6 +496,10 @@ server: # print log lines that say why queries return SERVFAIL to clients. # log-servfail: no + # log system-wide Linux thread ID, insted of Unbound's internal thread + # counter. Only on Linux and only when threads are available. + # log-thread-id: no + # the pid file. Can be an absolute path outside of chroot/work dir. # pidfile: "@UNBOUND_PIDFILE@" diff --git a/doc/libunbound.3.in b/doc/libunbound.3.in index 204cda20c..a4fa56d38 100644 --- a/doc/libunbound.3.in +++ b/doc/libunbound.3.in @@ -416,6 +416,6 @@ on a function return with file read failure. .SH AUTHOR Unbound developers are mentioned in the CREDITS file in the distribution. .SH COPYRIGHT -1999-2025, NLnet Labs +1999-2026, NLnet Labs .\" Generated by docutils manpage writer. . diff --git a/doc/unbound-anchor.8.in b/doc/unbound-anchor.8.in index 5c8c02fef..9da4fd852 100644 --- a/doc/unbound-anchor.8.in +++ b/doc/unbound-anchor.8.in @@ -304,6 +304,6 @@ Signature on the root key information. .SH AUTHOR Unbound developers are mentioned in the CREDITS file in the distribution. .SH COPYRIGHT -1999-2025, NLnet Labs +1999-2026, NLnet Labs .\" Generated by docutils manpage writer. . diff --git a/doc/unbound-checkconf.8.in b/doc/unbound-checkconf.8.in index 1d17573e9..113901ca8 100644 --- a/doc/unbound-checkconf.8.in +++ b/doc/unbound-checkconf.8.in @@ -88,6 +88,6 @@ Unbound configuration file. .SH AUTHOR Unbound developers are mentioned in the CREDITS file in the distribution. .SH COPYRIGHT -1999-2025, NLnet Labs +1999-2026, NLnet Labs .\" Generated by docutils manpage writer. . diff --git a/doc/unbound-control.8.in b/doc/unbound-control.8.in index 433b37354..5fcf055d0 100644 --- a/doc/unbound-control.8.in +++ b/doc/unbound-control.8.in @@ -978,6 +978,10 @@ Number of requests in the request list that were overwritten by newer entries. This happens if there is a flood of queries that recursive processing and the server has a hard time. +The counter is increased when during the flood the +\fI\%jostle\-timeout\fP +allows a query to be removed in favor of a new incoming query. +The older query is then dropped to make space. .UNINDENT .INDENT 0.0 .TP @@ -985,6 +989,12 @@ the server has a hard time. Queries that were dropped because the request list was full. This happens if a flood of queries need recursive processing, and the server can not keep up. +The counter is increased when during the flood there is no space +to be made with the jostle out of an older query, and the new query +is dropped. +Since no older queries are removed, see +\fI\%jostle\-timeout\fP setting, there +is no space for the new query. .UNINDENT .INDENT 0.0 .TP @@ -1570,6 +1580,6 @@ directory with private keys (\fBunbound_server.key\fP and .SH AUTHOR Unbound developers are mentioned in the CREDITS file in the distribution. .SH COPYRIGHT -1999-2025, NLnet Labs +1999-2026, NLnet Labs .\" Generated by docutils manpage writer. . diff --git a/doc/unbound-host.1.in b/doc/unbound-host.1.in index f8a5ca0ae..cccf63117 100644 --- a/doc/unbound-host.1.in +++ b/doc/unbound-host.1.in @@ -185,6 +185,6 @@ encountered a fatal error. .SH AUTHOR Unbound developers are mentioned in the CREDITS file in the distribution. .SH COPYRIGHT -1999-2025, NLnet Labs +1999-2026, NLnet Labs .\" Generated by docutils manpage writer. . diff --git a/doc/unbound.8.in b/doc/unbound.8.in index 863092ac0..ea5a50d68 100644 --- a/doc/unbound.8.in +++ b/doc/unbound.8.in @@ -32,7 +32,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] unbound \- Unbound DNS validating resolver @version@. .SH SYNOPSIS .sp -\fBunbound\fP [\fB\-hdpv\fP] [\fB\-c \fP] +\fBunbound\fP [\fB\-hdpVv\fP] [\fB\-c \fP] .SH DESCRIPTION .sp \fBunbound\fP is a caching DNS resolver. @@ -118,6 +118,6 @@ Show the version number and build options, and exit. .SH AUTHOR Unbound developers are mentioned in the CREDITS file in the distribution. .SH COPYRIGHT -1999-2025, NLnet Labs +1999-2026, NLnet Labs .\" Generated by docutils manpage writer. . diff --git a/doc/unbound.conf.5.in b/doc/unbound.conf.5.in index cc8559fe0..55f86c17f 100644 --- a/doc/unbound.conf.5.in +++ b/doc/unbound.conf.5.in @@ -1450,6 +1450,9 @@ The port number on which to provide DNS\-over\-QUIC service. Only interfaces configured with that port number as @number get the QUIC service. The interface uses QUIC for the UDP traffic on that port number. +If it is set to 0, the server does not init QUIC code, and QUIC is +disabled. +This is similar to if QUIC is not in use, but then explicitly. .sp Default: 853 .UNINDENT @@ -1927,6 +1930,16 @@ Default: no .UNINDENT .INDENT 0.0 .TP +.B log\-thread\-id: \fI\fP +(Only on Linux and only when threads are available) +Logs the system\-wide Linux thread ID instead of Unbound\(aqs internal thread +counter. +Can be useful when debugging with system tools. +.sp +Default: no +.UNINDENT +.INDENT 0.0 +.TP .B pidfile: \fI\fP The process id is written to the file. Default is \fB\(dq@UNBOUND_PIDFILE@\(dq\fP\&. @@ -5918,6 +5931,6 @@ Default is to log to \fIsyslog(3)\fP\&. .SH AUTHOR Unbound developers are mentioned in the CREDITS file in the distribution. .SH COPYRIGHT -1999-2025, NLnet Labs +1999-2026, NLnet Labs .\" Generated by docutils manpage writer. . diff --git a/doc/unbound.conf.rst b/doc/unbound.conf.rst index 9ec4a9e0b..953ed04a3 100644 --- a/doc/unbound.conf.rst +++ b/doc/unbound.conf.rst @@ -1306,9 +1306,9 @@ These options are part of the ``server:`` section. Only interfaces configured with that port number as @number get the QUIC service. The interface uses QUIC for the UDP traffic on that port number. - If the quic-port is set to 0, the server does not init quic code, - and quic is disabled. - This is similar to if quic is not in use, but then explicitly. + If it is set to 0, the server does not init QUIC code, and QUIC is + disabled. + This is similar to if QUIC is not in use, but then explicitly. Default: 853 @@ -1717,6 +1717,15 @@ These options are part of the ``server:`` section. Default: no +@@UAHL@unbound.conf@log-thread-id@@: ** + (Only on Linux and only when threads are available) + Logs the system-wide Linux thread ID instead of Unbound's internal thread + counter. + Can be useful when debugging with system tools. + + Default: no + + @@UAHL@unbound.conf@pidfile@@: ** The process id is written to the file. Default is :file:`"@UNBOUND_PIDFILE@"`. diff --git a/services/authzone.c b/services/authzone.c index fde1aca77..b6705dd79 100644 --- a/services/authzone.c +++ b/services/authzone.c @@ -4189,6 +4189,22 @@ auth_master_copy(struct auth_master* o) return m; } +/** append the master to the copied list. */ +static int +auth_master_copy_and_append(struct auth_master* p, struct auth_master** list, + struct auth_master** last) +{ + struct auth_master* m = auth_master_copy(p); + if(!m) { + return 0; + } + m->next = NULL; + if(*last) (*last)->next = m; + if(!*list) *list = m; + *last = m; + return 1; +} + /** copy the master addresses from the task_probe lookups to the allow_notify * list of masters */ static void @@ -4197,17 +4213,27 @@ probe_copy_masters_for_allow_notify(struct auth_xfer* xfr) struct auth_master* list = NULL, *last = NULL; struct auth_master* p; /* build up new list with copies */ - for(p = xfr->task_transfer->masters; p; p=p->next) { - struct auth_master* m = auth_master_copy(p); - if(!m) { + /* The list in task probe has been looked up before the list in + * task transfer. */ + for(p = xfr->task_probe->masters; p; p=p->next) { + if(!auth_master_copy_and_append(p, &list, &last)) { + auth_free_masters(list); + /* failed because of malloc failure, use old list */ + return; + } + } + /* The list in task transfer also contains the http entries. */ + for(p = xfr->task_transfer->masters; p; p=p->next) { + /* Copy the http entries from this lookup. The allow_notify + * entries are not looked up from this list. The other + * ones are already in from the probe lookups. */ + if(!p->http) + continue; + if(!auth_master_copy_and_append(p, &list, &last)) { auth_free_masters(list); /* failed because of malloc failure, use old list */ return; } - m->next = NULL; - if(last) last->next = m; - if(!list) list = m; - last = m; } /* success, replace list */ auth_free_masters(xfr->allow_notify_list); @@ -7013,6 +7039,18 @@ xfr_probe_lookup_host(struct auth_xfer* xfr, struct module_env* env) return 1; } +/** return true if there are probe (SOA UDP query) targets in the master list*/ +static int +have_probe_targets(struct auth_master* list) +{ + struct auth_master* p; + for(p=list; p; p = p->next) { + if(!p->allow_notify && p->host) + return 1; + } + return 0; +} + /** move to sending the probe packets, next if fails. task_probe */ static void xfr_probe_send_or_end(struct auth_xfer* xfr, struct module_env* env) @@ -7052,6 +7090,16 @@ xfr_probe_send_or_end(struct auth_xfer* xfr, struct module_env* env) verbose(VERB_ALGO, "auth zone %s probe: finished only_lookup", zname); } xfr_probe_disown(xfr); + if(!have_probe_targets(xfr->task_probe->masters)) { + /* If there are no masters to probe, go to transfer. */ + if(xfr->task_transfer->worker == NULL) { + xfr_start_transfer(xfr, env, NULL); + return; + } + /* The transfer is already in progress. */ + lock_basic_unlock(&xfr->lock); + return; + } if(xfr->task_nextprobe->worker == NULL) xfr_set_timeout(xfr, env, 0, 0); lock_basic_unlock(&xfr->lock); @@ -7208,18 +7256,6 @@ auth_xfer_timer(void* arg) } } -/** return true if there are probe (SOA UDP query) targets in the master list*/ -static int -have_probe_targets(struct auth_master* list) -{ - struct auth_master* p; - for(p=list; p; p = p->next) { - if(!p->allow_notify && p->host) - return 1; - } - return 0; -} - /** start task_probe if possible, if no masters for probe start task_transfer * returns true if task has been started, and false if the task is already * in progress. */ @@ -7231,7 +7267,9 @@ xfr_start_probe(struct auth_xfer* xfr, struct module_env* env, * progress (due to notify)) */ if(xfr->task_probe->worker == NULL) { if(!have_probe_targets(xfr->task_probe->masters) && - !(xfr->task_probe->only_lookup && + xfr->task_probe->masters != NULL) + xfr->task_probe->only_lookup = 1; + if(!(xfr->task_probe->only_lookup && xfr->task_probe->masters != NULL)) { /* useless to pick up task_probe, no masters to * probe. Instead attempt to pick up task transfer */ diff --git a/testdata/auth_notify_lookup.rpl b/testdata/auth_notify_lookup.rpl new file mode 100644 index 000000000..72faa1305 --- /dev/null +++ b/testdata/auth_notify_lookup.rpl @@ -0,0 +1,341 @@ +; config options +server: + target-fetch-policy: "0 0 0 0 0" + access-control: 1.2.3.0/24 allow + +auth-zone: + name: "example.com." + ## zonefile (or none). + ## zonefile: "example.com.zone" + ## master by IP address or hostname + ## can list multiple masters, each on one line. + ## master: + master: 1.2.3.44 + ## this is as a hostname, to test the hostname lookup. + allow-notify: svr.example.org + ## url for http fetch + ## url: + ## queries from downstream clients get authoritative answers. + ## for-downstream: yes + for-downstream: yes + ## queries are used to fetch authoritative answers from this zone, + ## instead of unbound itself sending queries there. + ## for-upstream: yes + for-upstream: yes + ## on failures with for-upstream, fallback to sending queries to + ## the authority servers + ## fallback-enabled: no + + ## this line generates zonefile: \n"/tmp/xxx.example.com"\n + zonefile: +TEMPFILE_NAME example.com + ## this is the inline file /tmp/xxx.example.com + ## the tempfiles are deleted when the testrun is over. +TEMPFILE_CONTENTS example.com +example.com. 3600 IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600 +TEMPFILE_END + +stub-zone: + name: "." + stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. +CONFIG_END + +SCENARIO_BEGIN Test authority zone with lookup for a NOTIFY +; The allow-notify is specified as a hostname. + +; K.ROOT-SERVERS.NET. +RANGE_BEGIN 0 100 + ADDRESS 193.0.14.129 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +. IN NS +SECTION ANSWER +. IN NS K.ROOT-SERVERS.NET. +SECTION ADDITIONAL +K.ROOT-SERVERS.NET. IN A 193.0.14.129 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +com. IN NS +SECTION AUTHORITY +com. IN NS a.gtld-servers.net. +SECTION ADDITIONAL +a.gtld-servers.net. IN A 192.5.6.30 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +org. IN NS +SECTION AUTHORITY +org. IN NS ns.org. +SECTION ADDITIONAL +ns.org. IN A 1.2.3.45 +ENTRY_END +RANGE_END + +; a.gtld-servers.net. +RANGE_BEGIN 0 100 + ADDRESS 192.5.6.30 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +com. IN NS +SECTION ANSWER +com. IN NS a.gtld-servers.net. +SECTION ADDITIONAL +a.gtld-servers.net. IN A 192.5.6.30 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +example.com. IN NS +SECTION AUTHORITY +example.com. IN NS ns.example.com. +SECTION ADDITIONAL +ns.example.com. IN A 1.2.3.44 +ENTRY_END +RANGE_END + +; ns.org +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.45 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +org. IN NS +SECTION ANSWER +org. IN NS ns.org. +SECTION ADDITIONAL +ns.org. IN A 1.2.3.45 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +example.org. IN NS +SECTION AUTHORITY +example.org. IN NS ns.example.org. +SECTION ADDITIONAL +ns.example.org. IN A 1.2.3.46 +ENTRY_END +RANGE_END + +; ns.example.net. +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.44 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.net. IN NS +SECTION ANSWER +example.net. IN NS ns.example.net. +SECTION ADDITIONAL +ns.example.net. IN A 1.2.3.44 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +ns.example.net. IN A +SECTION ANSWER +ns.example.net. IN A 1.2.3.44 +SECTION AUTHORITY +example.net. IN NS ns.example.net. +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +ns.example.net. IN AAAA +SECTION AUTHORITY +example.net. IN NS ns.example.net. +SECTION ADDITIONAL +www.example.net. IN A 1.2.3.44 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.com. IN NS +SECTION ANSWER +example.com. IN NS ns.example.net. +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +www.example.com. IN A 10.20.30.40 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.com. IN SOA +SECTION ANSWER +; serial, refresh, retry, expire, minimum +example.com. IN SOA ns.example.com. hostmaster.example.com. 2 3600 900 86400 3600 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOTIMPL +SECTION QUESTION +example.com. IN IXFR +SECTION ANSWER +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +example.com. IN AXFR +SECTION ANSWER +example.com. IN SOA ns.example.com. hostmaster.example.com. 2 3600 900 86400 3600 +example.com. IN NS ns.example.net. +EXTRA_PACKET +REPLY QR AA NOERROR +SECTION QUESTION +example.com. IN AXFR +SECTION ANSWER +www.example.com. IN A 1.2.3.4 +example.com. IN SOA ns.example.com. hostmaster.example.com. 2 3600 900 86400 3600 +ENTRY_END +RANGE_END + +; ns.example.org. +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.46 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +example.org. IN NS +SECTION ANSWER +example.org. IN NS ns.example.org. +SECTION ADDITIONAL +ns.example.org. IN A 1.2.3.46 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +svr.example.org. IN A +SECTION ANSWER +svr.example.org. IN A 1.2.3.47 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +svr.example.org. IN AAAA +SECTION AUTHORITY +example.org. IN SOA ns.example.com. hostmaster.example.com. 2 3600 900 86400 3600 +ENTRY_END +RANGE_END + +; lookups for notify hostnames. +STEP 1 TIME_PASSES ELAPSE 0 + +; now the query +STEP 2 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.example.com. IN A +ENTRY_END + +; recursion happens here. +STEP 20 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR AA RD RA NXDOMAIN +SECTION QUESTION +www.example.com. IN A +SECTION AUTHORITY +example.com. 3600 IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600 +ENTRY_END + +; NOTIFY example.com +STEP 30 QUERY ADDRESS 1.2.3.47 +ENTRY_BEGIN +REPLY NOTIFY +SECTION QUESTION +example.com. IN SOA +ENTRY_END +; notify reply +STEP 40 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RA NOTIFY NOERROR +SECTION QUESTION +example.com. IN SOA +SECTION ANSWER +ENTRY_END + +STEP 50 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.example.com. IN A +ENTRY_END + +; recursion happens here. +STEP 60 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR AA RD RA NOERROR +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +www.example.com. IN A 1.2.3.4 +ENTRY_END + +; the zonefile was updated with new contents +STEP 70 CHECK_TEMPFILE example.com +FILE_BEGIN +example.com. 3600 IN SOA ns.example.com. hostmaster.example.com. 2 3600 900 86400 3600 +example.com. 3600 IN NS ns.example.net. +www.example.com. 3600 IN A 1.2.3.4 +FILE_END + +SCENARIO_END diff --git a/util/config_file.c b/util/config_file.c index 8fd0abba9..8f3e46289 100644 --- a/util/config_file.c +++ b/util/config_file.c @@ -148,6 +148,7 @@ config_create(void) cfg->log_local_actions = 0; cfg->log_servfail = 0; cfg->log_destaddr = 0; + cfg->log_thread_id = 0; #ifndef USE_WINSOCK # ifdef USE_MINI_EVENT /* select max 1024 sockets */ @@ -748,6 +749,7 @@ int config_set_option(struct config_file* cfg, const char* opt, else S_YNO("log-local-actions:", log_local_actions) else S_YNO("log-servfail:", log_servfail) else S_YNO("log-destaddr:", log_destaddr) + else S_YNO("log-thread-id:", log_thread_id) else S_YNO("val-permissive-mode:", val_permissive_mode) else S_YNO("aggressive-nsec:", aggressive_nsec) else S_YNO("ignore-cd-flag:", ignore_cd) @@ -1205,6 +1207,7 @@ config_get_option(struct config_file* cfg, const char* opt, else O_YNO(opt, "log-local-actions", log_local_actions) else O_YNO(opt, "log-servfail", log_servfail) else O_YNO(opt, "log-destaddr", log_destaddr) + else O_YNO(opt, "log-thread-id", log_thread_id) else O_STR(opt, "pidfile", pidfile) else O_YNO(opt, "hide-identity", hide_identity) else O_YNO(opt, "hide-version", hide_version) diff --git a/util/config_file.h b/util/config_file.h index ebdc1b34d..aff3fd78b 100644 --- a/util/config_file.h +++ b/util/config_file.h @@ -367,6 +367,8 @@ struct config_file { char* log_identity; /** log dest addr for log_replies */ int log_destaddr; + /** log linux thread ID */ + int log_thread_id; /** do not report identity (id.server, hostname.bind) */ int hide_identity; diff --git a/util/configlexer.lex b/util/configlexer.lex index 22f98e464..566de49ab 100644 --- a/util/configlexer.lex +++ b/util/configlexer.lex @@ -441,6 +441,7 @@ log-tag-queryreply{COLON} { YDVAR(1, VAR_LOG_TAG_QUERYREPLY) } log-local-actions{COLON} { YDVAR(1, VAR_LOG_LOCAL_ACTIONS) } log-servfail{COLON} { YDVAR(1, VAR_LOG_SERVFAIL) } log-destaddr{COLON} { YDVAR(1, VAR_LOG_DESTADDR) } +log-thread-id{COLON} { YDVAR(1, VAR_LOG_THREAD_ID) } local-zone{COLON} { YDVAR(2, VAR_LOCAL_ZONE) } local-data{COLON} { YDVAR(1, VAR_LOCAL_DATA) } local-data-ptr{COLON} { YDVAR(1, VAR_LOCAL_DATA_PTR) } diff --git a/util/configparser.y b/util/configparser.y index f159b8cec..d9a7cd839 100644 --- a/util/configparser.y +++ b/util/configparser.y @@ -216,7 +216,7 @@ extern struct config_parser_state* cfg_parser; %token VAR_LOG_DESTADDR VAR_CACHEDB_CHECK_WHEN_SERVE_EXPIRED %token VAR_COOKIE_SECRET_FILE VAR_ITER_SCRUB_NS VAR_ITER_SCRUB_CNAME %token VAR_MAX_GLOBAL_QUOTA VAR_HARDEN_UNVERIFIED_GLUE VAR_LOG_TIME_ISO -%token VAR_ITER_SCRUB_PROMISCUOUS +%token VAR_ITER_SCRUB_PROMISCUOUS VAR_LOG_THREAD_ID %% toplevelvars: /* empty */ | toplevelvars toplevelvar ; @@ -288,7 +288,7 @@ content_server: server_num_threads | server_verbosity | server_port | server_edns_buffer_size | server_prefetch | server_prefetch_key | server_so_sndbuf | server_harden_below_nxdomain | server_ignore_cd_flag | server_log_queries | server_log_replies | server_tcp_upstream | server_ssl_upstream | - server_log_local_actions | + server_log_local_actions | server_log_thread_id | server_ssl_service_key | server_ssl_service_pem | server_ssl_port | server_https_port | server_http_endpoint | server_http_max_streams | server_http_query_buffer_size | server_http_response_buffer_size | @@ -1350,6 +1350,15 @@ server_log_destaddr: VAR_LOG_DESTADDR STRING_ARG free($2); } ; +server_log_thread_id: VAR_LOG_THREAD_ID STRING_ARG + { + OUTYY(("P(server_log_thread_id:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->log_thread_id = (strcmp($2, "yes")==0); + free($2); + } + ; server_log_local_actions: VAR_LOG_LOCAL_ACTIONS STRING_ARG { OUTYY(("P(server_log_local_actions:%s)\n", $2)); diff --git a/util/log.c b/util/log.c index b75cf065f..f2beafc87 100644 --- a/util/log.c +++ b/util/log.c @@ -174,10 +174,10 @@ void log_thread_set(int* num) int log_thread_get(void) { - unsigned int* tid; + int* tid; if(!key_created) return 0; - tid = (unsigned int*)ub_thread_key_get(logkey); - return (int)(tid?*tid:0); + tid = ub_thread_key_get(logkey); + return (tid?*tid:0); } void log_ident_set(const char* id) @@ -229,7 +229,7 @@ log_vmsg(int pri, const char* type, const char *format, va_list args) { char message[MAXSYSLOGMSGLEN]; - unsigned int* tid = (unsigned int*)ub_thread_key_get(logkey); + int tid = log_thread_get(); time_t now; #if defined(HAVE_STRFTIME) && defined(HAVE_LOCALTIME_R) char tmbuf[32]; @@ -241,8 +241,8 @@ log_vmsg(int pri, const char* type, vsnprintf(message, sizeof(message), format, args); #ifdef HAVE_SYSLOG_H if(logging_to_syslog) { - syslog(pri, "[%d:%x] %s: %s", - (int)getpid(), tid?*tid:0, type, message); + syslog(pri, "[%d:%d] %s: %s", + (int)getpid(), tid, type, message); return; } #elif defined(UB_ON_WINDOWS) @@ -263,8 +263,8 @@ log_vmsg(int pri, const char* type, tp=MSG_GENERIC_SUCCESS; wt=EVENTLOG_SUCCESS; } - snprintf(m, sizeof(m), "[%s:%x] %s: %s", - ident, tid?*tid:0, type, message); + snprintf(m, sizeof(m), "[%s:%d] %s: %s", + ident, tid, type, message); s = RegisterEventSource(NULL, SERVICE_NAME); if(!s) return; ReportEvent(s, wt, 0, tp, NULL, 1, 0, &str, NULL); @@ -294,9 +294,9 @@ log_vmsg(int pri, const char* type, tzbuf[3] = ':'; tzbuf[6] = 0; } - fprintf(logfile, "%s.%3.3d%s %s[%d:%x] %s: %s\n", + fprintf(logfile, "%s.%3.3d%s %s[%d:%d] %s: %s\n", tmbuf, (int)tv.tv_usec/1000, tzbuf, - ident, (int)getpid(), tid?*tid:0, type, message); + ident, (int)getpid(), tid, type, message); #ifdef UB_ON_WINDOWS /* line buffering does not work on windows */ fflush(logfile); @@ -310,19 +310,19 @@ log_vmsg(int pri, const char* type, if(log_time_asc && strftime(tmbuf, sizeof(tmbuf), "%b %d %H:%M:%S", localtime_r(&now, &tm))%(sizeof(tmbuf)) != 0) { /* %sizeof buf!=0 because old strftime returned max on error */ - fprintf(logfile, "%s %s[%d:%x] %s: %s\n", tmbuf, - ident, (int)getpid(), tid?*tid:0, type, message); + fprintf(logfile, "%s %s[%d:%d] %s: %s\n", tmbuf, + ident, (int)getpid(), tid, type, message); } else #elif defined(UB_ON_WINDOWS) if(log_time_asc && GetTimeFormat(LOCALE_USER_DEFAULT, 0, NULL, NULL, tmbuf, sizeof(tmbuf)) && GetDateFormat(LOCALE_USER_DEFAULT, 0, NULL, NULL, dtbuf, sizeof(dtbuf))) { - fprintf(logfile, "%s %s %s[%d:%x] %s: %s\n", dtbuf, tmbuf, - ident, (int)getpid(), tid?*tid:0, type, message); + fprintf(logfile, "%s %s %s[%d:%d] %s: %s\n", dtbuf, tmbuf, + ident, (int)getpid(), tid, type, message); } else #endif - fprintf(logfile, "[" ARG_LL "d] %s[%d:%x] %s: %s\n", (long long)now, - ident, (int)getpid(), tid?*tid:0, type, message); + fprintf(logfile, "[" ARG_LL "d] %s[%d:%d] %s: %s\n", (long long)now, + ident, (int)getpid(), tid, type, message); #ifdef UB_ON_WINDOWS /* line buffering does not work on windows */ fflush(logfile);