mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-18 23:06:06 -05:00
Fast Reload Option (#1042)
* - fast-reload, add unbound-control fast_reload * - fast-reload, make a thread to service the unbound-control command. * - fast-reload, communication sockets for information transfer. * - fast-reload, fix compile for unbound-dnstap-socket. * - fast-reload, set nonblocking communication to keep the server thread responding to DNS requests. * - fast-reload, poll routine to test for readiness, timeout fails connection. * - fast-reload, detect loop in sock_poll_timeout routine. * - fast-reload, send done and exited notification. * - fast-reload, defines for constants in ipc. * - fast-reload, ipc socket recv and send resists partial reads and writes and can continue byte by byte. Also it can continue after an interrupt. * - fast-reload, send exit command to thread when done. * - fast-reload, output strings for client on string list. * - fast-reload, add newline to terminal output. * - fast-reload, send client string to remote client. * - fast-reload, better debug output. * - fast-reload, print queue structure, for output to the remote client. * - fast-reload, move print items to print queue from fast_reload_thread struct. * - fast-reload, keep list of pending print queue items in daemon struct. * - fast-reload, comment explains in_list for printq to print remainder. * - fast-reload, unit test testdata/fast_reload_thread.tdir that tests the thread output. * - fast-reload, fix test link for fast_reload_printq_list_delete function. * - fast-reload, reread config file from disk. * - fast-reload, unshare forwards, making the structure locked, with an rwlock. * - fast-reload, for nonthreaded, the unbound-control commands forward, forward_add and forward_delete should be distributed to other processes, but when threaded, they should not be distributed to other threads because the structure is not thread specific any more. * - fast-reload, unshared stub hints, making the structure locked, with an rwlock. * - fast-reload, helpful comments for hints lookup function return value. * - fast-reload, fix bug in fast reload printout, the strlist appendlist routine, and printout time statistics after the reload is done. * - fast-reload, keep track of reloadtime and deletestime and print them. * - fast-reload, keep track of constructtime and print it. * - fast-reload, construct new items. * - fast-reload, better comment. * - fast-reload, reload the config and swap trees for forwards and stub hints. * - fast-reload, in forwards_swap_tree set protection of trees with locks. * - fast-reload, in hints_swap_tree also swap the node count of the trees. * - fast-reload, reload ipc to stop and start threads. * - fast-reload, unused forward declarations removed. * - fast-reload, unit test that fast reload works with forwards and stubs. * - fast-reload, fix clang analyzer warnings. * - fast-reload, small documentation entry in unbound-control -h output. * - fast-reload, printout memory use by fast reload, in bytes. * - fast-reload, compile without threads. * - fast-reload, document fast_reload in man page. * - fast-reload, print ok when done successfully. * - fast-reload, option for fast-reload commandline, +v verbosity option, with timing and memory use output. * - fast-reload, option for fast-reload commandline, +p does not pause threads. * - fast-reload, option for fast-reload commandline, +d drops mesh queries. * - fast-reload, fix to poll every thread with nopause to make certain that resources are not held by the threads and can be deleted. * - fast-reload, fix to use atomic store for config variables with nopause. * - fast-reload, reload views. * - fast-reload, when tag defines are different, it drops the queries. * - fast-reload, fix tag define check. * - fast-reload, document that tag change causes drop of queries. * - fast-reload, fix space in documentation man page. * - fast-reload, copy respip client information to query state, put views tree in module env for lookup. * - fast-reload, nicer respip view comparison. * - fast-reload, respip global set is in module env. * - fast-reload, document that respip_client_info acl info is copied. * - fast-reload, reload the respip_set. * - fast-reload, document no pause and pick up of use_response_ip boolean. * - fast-reload, fix test compile. * - fast-reload, reload local zones. * Update locking management for iter_fwd and iter_hints methods. (#1054) fast reload, move most of the locking management to iter_fwd and iter_hints methods. The caller still has the ability to handle its own locking, if desired, for atomic operations on sets of different structs. Co-authored-by: Wouter Wijngaards <wcawijngaards@users.noreply.github.com> * - fast-reload, reload access-control. * - fast-reload, reload access control interface, such as interface-action. * - fast-reload, reload tcp-connection-limit. * - fast-reload, improve comments on acl_list and tcl_list swap tree. * - fast-reload, fixup references to old tcp connection limits in open tcp connections. * - fast-reload, fixup to clean tcp connection also for different linked order. * - fast-reload, if no tcp connection limits existed, no need to remove references for that. * - fast-reload, document more options that work and do not work. * - fast-reload, reload auth_zone and rpz data. * - fast-reload, fix auth_zones_get_mem. * - fast-reload, fix compilation of testbound for the new comm_timer_get_mem reference in remote control. * - fast-reload, change use_rpz with reload. * - fast-reload, list changes in auth zones and stop zonemd callbacks for deleted auth zones. * - fast-reload, note xtree is not swapped, and why it is not swapped. * - fast-reload, for added auth zones, pick up zone transfer and zonemd tasks. * - fast-reload, unlock xfr when done with transfer pick up. * - fast-reload, unlock z when picking up the xfr for it during transfer task pick up. * - fast-reload, pick up task changes for added, deleted and modified auth zones. * - fast-reload, remove xfr of auth zone deletion without tasks. * - fast-reload, pick up zone transfer config. * - fast-reload, the main worker thread picks up the transfer tasks and also performs setup of the xfer struct. * - fast-reload, keep writelock on newzone when auth zone changes. * - fast-reload, change cachedb_enabled setting. * - fast-reload, pick up edns-strings config. * - fast-reload, note that settings are not updated. * - fast-reload, pick up dnstap config. * - fast-reload, dnstap options that need to be loaded without +p. * - fast-reload, fix auth zone reload * - fast-reload, remove debug for auth zone test. * - fast-reload, fix auth zone reload with zone transfer. * - fast-reload, fix auth zone reload lock order. * - fast-reload, remove debug from fast reload test. * - fast-reload, remove unused function. * - fast-reload, fix the worker trust anchor probe timer lock acquisition in the probe answer callback routine for trust anchor probes. * - fast-reload, reload trust anchors. * - fast-reload, fix trust anchor reload lock on autr global data and test for trust anchor reload. * - fast-reload, adjust cache sizes. * - fast-reload, reload cache sizes when changed. * - fast-reload, reload validator env changes. * - fast-reload, reload mesh changes. * - fast-reload, check for incompatible changes. * - fast-reload, improve error text for incompatible change. * - fast-reload, fix check config option compatibility. * - fast-reload, improve error text for nopause change. * - fast-reload, fix spelling of incompatible options. * - fast-reload, reload target-fetch-policy, outbound-msg-retry, max-sent-count and max-query-restarts. * - fast-reload, check nopause config change for target-fetch-policy. * - fast-reload, reload do-not-query-address, private-address and capt-exempt. * - fast-reload, check nopause config change for do-not-query-address, private-address and capt-exempt. * - fast-reload, check fast reload not possible due to interface and outgoing-interface changes. * - fast-reload, reload nat64 settings. * - fast-reload, reload settings stored in the infra structure. * - fast-reload, fix modstack lookup and remove outgoing-range check. * - fast-reload, more explanation for config parse failure. * - fast-reload, reload worker outside network changes. * - fast-reload, detect incompatible changes in network settings. * fast-reload, commit test files. * - fast-reload, fix warnings for call types in windows compile. * - fast-reload, fix warnings and comm_point_internal for tcp wouldblock calls. * - fast-reload, extend lock checks for repeat thread ids. * - fast-reload, additional test cases, cache change and tag changes. * - fast-reload, fix documentation for auth_zone_verify_zonemd_with_key. * - fast-reload, fix copy_cfg type casts and memory leak on config parse failure. * - fast-reload, fix use of WSAPoll. * Review comments for the fast reload feature (#1259) * - fast-reload review, respip set can be null from a view. * - fast-reload review, typos. * - fast-reload review, keep clang static analyzer happy. * - fast-reload review, don't forget to copy tag_actions. * - fast-reload review, less indentation. * - fast-reload review, don't leak respip_actions when reloading. * - fast-reload review, protect NULL pointer dereference in get_mem functions. * - fast-reload review, add fast_reload_most_options.tdir to test most options with high verbosity when fast reloading. * - fast-reload review, don't skip new line on long error printouts. * - fast-reload review, typo. * - fast-reload review, use new_z for consistency. * - fast-reload review, nit for unlock ordering to make eye comparison with the lock counterpart easier. * - fast-reload review, in case of error the sockets are already closed. * - fast-reload review, identation. * - fast-reload review, add static keywords. * - fast-reload review, update unbound-control usage text. * - fast-reload review, updates to the man page. * - fast-reload, the fast-reload command is experimental. * - fast-reload, fix compile of doqclient for fast reload functions. * Changelog comment for #1042 - Merge #1042: Fast Reload. The unbound-control fast_reload is added. It reads changed config in a thread, then only briefly pauses the service threads, that keep running. DNS service is only interrupted briefly, less than a second. --------- Co-authored-by: Yorgos Thessalonikefs <yorgos@nlnetlabs.nl>
This commit is contained in:
parent
914cef75f9
commit
218f5cfc92
90 changed files with 7471 additions and 251 deletions
|
|
@ -881,7 +881,7 @@ view.lo view.o: $(srcdir)/services/view.c config.h $(srcdir)/services/view.h $(s
|
|||
$(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/services/localzone.h $(srcdir)/util/storage/dnstree.h \
|
||||
$(srcdir)/util/module.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/data/msgreply.h \
|
||||
$(srcdir)/util/data/packed_rrset.h $(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h \
|
||||
$(srcdir)/sldns/rrdef.h $(srcdir)/sldns/sbuffer.h $(srcdir)/util/config_file.h
|
||||
$(srcdir)/sldns/rrdef.h $(srcdir)/sldns/sbuffer.h $(srcdir)/util/config_file.h $(srcdir)/respip/respip.h
|
||||
rpz.lo rpz.o: $(srcdir)/services/rpz.c config.h $(srcdir)/services/rpz.h $(srcdir)/services/localzone.h \
|
||||
$(srcdir)/util/rbtree.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/util/storage/dnstree.h \
|
||||
$(srcdir)/util/module.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/data/msgreply.h \
|
||||
|
|
@ -977,7 +977,7 @@ fptr_wlist.lo fptr_wlist.o: $(srcdir)/util/fptr_wlist.c config.h $(srcdir)/util/
|
|||
$(srcdir)/validator/val_nsec3.h $(srcdir)/validator/val_sigcrypt.h $(srcdir)/validator/val_kentry.h \
|
||||
$(srcdir)/validator/val_neg.h $(srcdir)/validator/autotrust.h $(srcdir)/libunbound/libworker.h \
|
||||
$(srcdir)/libunbound/context.h $(srcdir)/util/alloc.h $(srcdir)/libunbound/unbound-event.h \
|
||||
$(srcdir)/libunbound/worker.h
|
||||
$(srcdir)/libunbound/worker.h $(srcdir)/daemon/remote.h
|
||||
locks.lo locks.o: $(srcdir)/util/locks.c config.h $(srcdir)/util/locks.h $(srcdir)/util/log.h
|
||||
log.lo log.o: $(srcdir)/util/log.c config.h $(srcdir)/util/log.h $(srcdir)/util/locks.h $(srcdir)/sldns/sbuffer.h
|
||||
mini_event.lo mini_event.o: $(srcdir)/util/mini_event.c config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h \
|
||||
|
|
@ -1313,7 +1313,10 @@ remote.lo remote.o: $(srcdir)/daemon/remote.c config.h $(srcdir)/daemon/remote.h
|
|||
$(srcdir)/validator/val_anchor.h $(srcdir)/iterator/iterator.h $(srcdir)/services/outbound_list.h \
|
||||
$(srcdir)/iterator/iter_fwd.h $(srcdir)/iterator/iter_hints.h $(srcdir)/iterator/iter_delegpt.h \
|
||||
$(srcdir)/services/outside_network.h $(srcdir)/sldns/str2wire.h $(srcdir)/sldns/parseutil.h \
|
||||
$(srcdir)/sldns/wire2str.h $(srcdir)/util/edns.h
|
||||
$(srcdir)/sldns/wire2str.h $(srcdir)/util/edns.h \
|
||||
$(srcdir)/util/locks.h $(srcdir)/util/ub_event.h \
|
||||
$(srcdir)/util/tcp_conn_limit.h $(srcdir)/util/edns.h $(srcdir)/validator/val_neg.h \
|
||||
$(srcdir)/iterator/iter_utils.h $(srcdir)/iterator/iter_donotq.h $(srcdir)/iterator/iter_priv.h
|
||||
stats.lo stats.o: $(srcdir)/daemon/stats.c config.h $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h \
|
||||
$(srcdir)/libunbound/unbound.h $(srcdir)/daemon/worker.h $(srcdir)/libunbound/worker.h $(srcdir)/sldns/sbuffer.h \
|
||||
$(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \
|
||||
|
|
|
|||
|
|
@ -663,6 +663,9 @@
|
|||
/* Define to 1 if you have the <stdarg.h> header file. */
|
||||
#undef HAVE_STDARG_H
|
||||
|
||||
/* Define to 1 if you have the <stdatomic.h> header file. */
|
||||
#undef HAVE_STDATOMIC_H
|
||||
|
||||
/* Define to 1 if you have the <stdbool.h> header file. */
|
||||
#undef HAVE_STDBOOL_H
|
||||
|
||||
|
|
|
|||
8
configure
vendored
8
configure
vendored
|
|
@ -16100,6 +16100,14 @@ then :
|
|||
|
||||
fi
|
||||
|
||||
ac_fn_c_check_header_compile "$LINENO" "stdatomic.h" "ac_cv_header_stdatomic_h" "$ac_includes_default
|
||||
"
|
||||
if test "x$ac_cv_header_stdatomic_h" = xyes
|
||||
then :
|
||||
printf "%s\n" "#define HAVE_STDATOMIC_H 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# check for types.
|
||||
# Using own tests for int64* because autoconf builtin only give 32bit.
|
||||
|
|
|
|||
|
|
@ -524,6 +524,7 @@ AC_CHECK_HEADERS([netioapi.h],,, [AC_INCLUDES_DEFAULT
|
|||
|
||||
# Check for Linux timestamping headers
|
||||
AC_CHECK_HEADERS([linux/net_tstamp.h],,, [AC_INCLUDES_DEFAULT])
|
||||
AC_CHECK_HEADERS([stdatomic.h],,, [AC_INCLUDES_DEFAULT])
|
||||
|
||||
# check for types.
|
||||
# Using own tests for int64* because autoconf builtin only give 32bit.
|
||||
|
|
|
|||
|
|
@ -816,3 +816,14 @@ log_acl_action(const char* action, struct sockaddr_storage* addr,
|
|||
(int)port);
|
||||
}
|
||||
}
|
||||
|
||||
void acl_list_swap_tree(struct acl_list* acl, struct acl_list* data)
|
||||
{
|
||||
/* swap tree and region */
|
||||
rbtree_type oldtree = acl->tree;
|
||||
struct regional* oldregion = acl->region;
|
||||
acl->tree = data->tree;
|
||||
acl->region = data->region;
|
||||
data->tree = oldtree;
|
||||
data->region = oldregion;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -201,4 +201,12 @@ const char* acl_access_to_str(enum acl_access acl);
|
|||
void log_acl_action(const char* action, struct sockaddr_storage* addr,
|
||||
socklen_t addrlen, enum acl_access acl, struct acl_addr* acladdr);
|
||||
|
||||
/**
|
||||
* Swap internal tree with preallocated entries.
|
||||
* @param acl: the acl structure.
|
||||
* @param data: the data structure used to take elements from. This contains
|
||||
* the old elements on return.
|
||||
*/
|
||||
void acl_list_swap_tree(struct acl_list* acl, struct acl_list* data);
|
||||
|
||||
#endif /* DAEMON_ACL_LIST_H */
|
||||
|
|
|
|||
|
|
@ -323,8 +323,7 @@ daemon_init(void)
|
|||
return daemon;
|
||||
}
|
||||
|
||||
static int setup_acl_for_ports(struct acl_list* list,
|
||||
struct listen_port* port_list)
|
||||
int setup_acl_for_ports(struct acl_list* list, struct listen_port* port_list)
|
||||
{
|
||||
struct acl_addr* acl_node;
|
||||
for(; port_list; port_list=port_list->next) {
|
||||
|
|
@ -717,16 +716,16 @@ daemon_fork(struct daemon* daemon)
|
|||
#endif
|
||||
|
||||
log_assert(daemon);
|
||||
if(!(daemon->views = views_create()))
|
||||
if(!(daemon->env->views = views_create()))
|
||||
fatal_exit("Could not create views: out of memory");
|
||||
/* create individual views and their localzone/data trees */
|
||||
if(!views_apply_cfg(daemon->views, daemon->cfg))
|
||||
if(!views_apply_cfg(daemon->env->views, daemon->cfg))
|
||||
fatal_exit("Could not set up views");
|
||||
|
||||
if(!acl_list_apply_cfg(daemon->acl, daemon->cfg, daemon->views))
|
||||
if(!acl_list_apply_cfg(daemon->acl, daemon->cfg, daemon->env->views))
|
||||
fatal_exit("Could not setup access control list");
|
||||
if(!acl_interface_apply_cfg(daemon->acl_interface, daemon->cfg,
|
||||
daemon->views))
|
||||
daemon->env->views))
|
||||
fatal_exit("Could not setup interface control list");
|
||||
if(!tcl_list_apply_cfg(daemon->tcl, daemon->cfg))
|
||||
fatal_exit("Could not setup TCP connection limits");
|
||||
|
|
@ -762,15 +761,15 @@ daemon_fork(struct daemon* daemon)
|
|||
fatal_exit("Could not set root or stub hints");
|
||||
|
||||
/* process raw response-ip configuration data */
|
||||
if(!(daemon->respip_set = respip_set_create()))
|
||||
if(!(daemon->env->respip_set = respip_set_create()))
|
||||
fatal_exit("Could not create response IP set");
|
||||
if(!respip_global_apply_cfg(daemon->respip_set, daemon->cfg))
|
||||
if(!respip_global_apply_cfg(daemon->env->respip_set, daemon->cfg))
|
||||
fatal_exit("Could not set up response IP set");
|
||||
if(!respip_views_apply_cfg(daemon->views, daemon->cfg,
|
||||
if(!respip_views_apply_cfg(daemon->env->views, daemon->cfg,
|
||||
&have_view_respip_cfg))
|
||||
fatal_exit("Could not set up per-view response IP sets");
|
||||
daemon->use_response_ip = !respip_set_is_empty(daemon->respip_set) ||
|
||||
have_view_respip_cfg;
|
||||
daemon->use_response_ip = !respip_set_is_empty(
|
||||
daemon->env->respip_set) || have_view_respip_cfg;
|
||||
|
||||
/* setup modules */
|
||||
daemon_setup_modules(daemon);
|
||||
|
|
@ -886,14 +885,18 @@ daemon_cleanup(struct daemon* daemon)
|
|||
daemon->env->hints = NULL;
|
||||
local_zones_delete(daemon->local_zones);
|
||||
daemon->local_zones = NULL;
|
||||
respip_set_delete(daemon->respip_set);
|
||||
daemon->respip_set = NULL;
|
||||
views_delete(daemon->views);
|
||||
daemon->views = NULL;
|
||||
respip_set_delete(daemon->env->respip_set);
|
||||
daemon->env->respip_set = NULL;
|
||||
views_delete(daemon->env->views);
|
||||
daemon->env->views = NULL;
|
||||
if(daemon->env->auth_zones)
|
||||
auth_zones_cleanup(daemon->env->auth_zones);
|
||||
/* key cache is cleared by module deinit during next daemon_fork() */
|
||||
daemon_remote_clear(daemon->rc);
|
||||
if(daemon->fast_reload_thread)
|
||||
fast_reload_thread_stop(daemon->fast_reload_thread);
|
||||
if(daemon->fast_reload_printq_list)
|
||||
fast_reload_printq_list_delete(daemon->fast_reload_printq_list);
|
||||
for(i=0; i<daemon->num; i++)
|
||||
worker_delete(daemon->workers[i]);
|
||||
free(daemon->workers);
|
||||
|
|
@ -951,6 +954,7 @@ daemon_delete(struct daemon* daemon)
|
|||
listen_desetup_locks();
|
||||
free(daemon->chroot);
|
||||
free(daemon->pidfile);
|
||||
free(daemon->cfgfile);
|
||||
free(daemon->env);
|
||||
#ifdef HAVE_SSL
|
||||
listen_sslctx_delete_ticket_keys();
|
||||
|
|
|
|||
|
|
@ -60,6 +60,8 @@ struct respip_set;
|
|||
struct shm_main_info;
|
||||
struct doq_table;
|
||||
struct cookie_secrets;
|
||||
struct fast_reload_thread;
|
||||
struct fast_reload_printq;
|
||||
|
||||
#include "dnstap/dnstap_config.h"
|
||||
#ifdef USE_DNSTAP
|
||||
|
|
@ -137,15 +139,11 @@ struct daemon {
|
|||
struct timeval time_last_stat;
|
||||
/** time when daemon started */
|
||||
struct timeval time_boot;
|
||||
/** views structure containing view tree */
|
||||
struct views* views;
|
||||
#ifdef USE_DNSTAP
|
||||
/** the dnstap environment master value, copied and changed by threads*/
|
||||
struct dt_env* dtenv;
|
||||
#endif
|
||||
struct shm_main_info* shm_info;
|
||||
/** response-ip set with associated actions and tags. */
|
||||
struct respip_set* respip_set;
|
||||
/** some response-ip tags or actions are configured if true */
|
||||
int use_response_ip;
|
||||
/** some RPZ policies are configured */
|
||||
|
|
@ -160,6 +158,17 @@ struct daemon {
|
|||
int reuse_cache;
|
||||
/** the EDNS cookie secrets from the cookie-secret-file */
|
||||
struct cookie_secrets* cookie_secrets;
|
||||
/** the fast reload thread, or NULL */
|
||||
struct fast_reload_thread* fast_reload_thread;
|
||||
/** the fast reload printq list */
|
||||
struct fast_reload_printq* fast_reload_printq_list;
|
||||
/** the fast reload option to drop mesh queries, true if so. */
|
||||
int fast_reload_drop_mesh;
|
||||
/** for fast reload, if the tcl, tcp connection limits, has
|
||||
* changes for workers */
|
||||
int fast_reload_tcl_has_changes;
|
||||
/** config file name */
|
||||
char* cfgfile;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -212,4 +221,12 @@ void daemon_delete(struct daemon* daemon);
|
|||
*/
|
||||
void daemon_apply_cfg(struct daemon* daemon, struct config_file* cfg);
|
||||
|
||||
/**
|
||||
* Setup acl list to have entries for the port list.
|
||||
* @param list: the acl interface
|
||||
* @param port_list: list of open ports, or none.
|
||||
* @return false on failure
|
||||
*/
|
||||
int setup_acl_for_ports(struct acl_list* list, struct listen_port* port_list);
|
||||
|
||||
#endif /* DAEMON_H */
|
||||
|
|
|
|||
4085
daemon/remote.c
4085
daemon/remote.c
File diff suppressed because it is too large
Load diff
167
daemon/remote.h
167
daemon/remote.h
|
|
@ -48,6 +48,7 @@
|
|||
#ifdef HAVE_OPENSSL_SSL_H
|
||||
#include <openssl/ssl.h>
|
||||
#endif
|
||||
#include "util/locks.h"
|
||||
struct config_file;
|
||||
struct listen_list;
|
||||
struct listen_port;
|
||||
|
|
@ -55,6 +56,7 @@ struct worker;
|
|||
struct comm_reply;
|
||||
struct comm_point;
|
||||
struct daemon_remote;
|
||||
struct config_strlist_head;
|
||||
|
||||
/** number of milliseconds timeout on incoming remote control handshake */
|
||||
#define REMOTE_CONTROL_TCP_TIMEOUT 120000
|
||||
|
|
@ -118,6 +120,137 @@ struct remote_stream {
|
|||
};
|
||||
typedef struct remote_stream RES;
|
||||
|
||||
/**
|
||||
* Notification status. This is exchanged between the fast reload thread
|
||||
* and the server thread, over the commpair sockets.
|
||||
*/
|
||||
enum fast_reload_notification {
|
||||
/** nothing, not used */
|
||||
fast_reload_notification_none = 0,
|
||||
/** the fast reload thread is done */
|
||||
fast_reload_notification_done = 1,
|
||||
/** the fast reload thread is done but with an error, it failed */
|
||||
fast_reload_notification_done_error = 2,
|
||||
/** the fast reload thread is told to exit by the server thread.
|
||||
* Sent on server quit while the reload is running. */
|
||||
fast_reload_notification_exit = 3,
|
||||
/** the fast reload thread has exited, after being told to exit */
|
||||
fast_reload_notification_exited = 4,
|
||||
/** the fast reload thread has information to print out */
|
||||
fast_reload_notification_printout = 5,
|
||||
/** stop as part of the reload the thread and other threads */
|
||||
fast_reload_notification_reload_stop = 6,
|
||||
/** ack the stop as part of the reload, and also ack start */
|
||||
fast_reload_notification_reload_ack = 7,
|
||||
/** resume from stop as part of the reload */
|
||||
fast_reload_notification_reload_start = 8,
|
||||
/** the fast reload thread wants the mainthread to poll workers,
|
||||
* after the reload, sent when nopause is used */
|
||||
fast_reload_notification_reload_nopause_poll = 9
|
||||
};
|
||||
|
||||
/**
|
||||
* Fast reload printout queue. Contains a list of strings, that need to be
|
||||
* printed over the file descriptor.
|
||||
*/
|
||||
struct fast_reload_printq {
|
||||
/** if this item is in a list, the previous and next */
|
||||
struct fast_reload_printq *prev, *next;
|
||||
/** if this item is in a list, it is true. */
|
||||
int in_list;
|
||||
/** list of strings to printout */
|
||||
struct config_strlist_head* to_print;
|
||||
/** the current item to print. It is malloced. NULL if none. */
|
||||
char* client_item;
|
||||
/** The length, strlen, of the client_item, that has to be sent. */
|
||||
int client_len;
|
||||
/** The number of bytes sent of client_item. */
|
||||
int client_byte_count;
|
||||
/** the comm point for the client connection, the remote control
|
||||
* client. */
|
||||
struct comm_point* client_cp;
|
||||
/** the remote control connection to print output to. */
|
||||
struct remote_stream remote;
|
||||
/** the worker that the event is added in */
|
||||
struct worker* worker;
|
||||
};
|
||||
|
||||
/**
|
||||
* Fast reload auth zone change. Keeps track if an auth zone was removed,
|
||||
* added or changed. This is needed because workers can have events for
|
||||
* dealing with auth zones, like transfers, and those have to be removed
|
||||
* too, not just the auth zone structure from the tree. */
|
||||
struct fast_reload_auth_change {
|
||||
/** next in the list of auth zone changes. */
|
||||
struct fast_reload_auth_change* next;
|
||||
/** the zone in the old config */
|
||||
struct auth_zone* old_z;
|
||||
/** the zone in the new config */
|
||||
struct auth_zone* new_z;
|
||||
/** if the zone was deleted */
|
||||
int is_deleted;
|
||||
/** if the zone was added */
|
||||
int is_added;
|
||||
/** if the zone has been changed */
|
||||
int is_changed;
|
||||
};
|
||||
|
||||
/**
|
||||
* Fast reload thread structure
|
||||
*/
|
||||
struct fast_reload_thread {
|
||||
/** the thread number for the dtio thread,
|
||||
* must be first to cast thread arg to int* in checklock code. */
|
||||
int threadnum;
|
||||
/** communication socket pair, that sends commands */
|
||||
int commpair[2];
|
||||
/** thread id, of the io thread */
|
||||
ub_thread_type tid;
|
||||
/** if the io processing has started */
|
||||
int started;
|
||||
/** if the thread has to quit */
|
||||
int need_to_quit;
|
||||
/** verbosity of the fast_reload command, the number of +v options */
|
||||
int fr_verb;
|
||||
/** option to not pause threads during reload */
|
||||
int fr_nopause;
|
||||
/** option to drop mesh queries */
|
||||
int fr_drop_mesh;
|
||||
|
||||
/** the event that listens on the remote service worker to the
|
||||
* commpair, it receives content from the fast reload thread. */
|
||||
void* service_event;
|
||||
/** if the event that listens on the remote service worker has
|
||||
* been added to the comm base. */
|
||||
int service_event_is_added;
|
||||
/** the service event can read a cmd, nonblocking, so it can
|
||||
* save the partial read cmd here */
|
||||
uint32_t service_read_cmd;
|
||||
/** the number of bytes in service_read_cmd */
|
||||
int service_read_cmd_count;
|
||||
/** the worker that the service_event is added in */
|
||||
struct worker* worker;
|
||||
|
||||
/** the printout of output to the remote client. */
|
||||
struct fast_reload_printq *printq;
|
||||
|
||||
/** lock on fr_output, to stop race when both remote control thread
|
||||
* and fast reload thread use fr_output list. */
|
||||
lock_basic_type fr_output_lock;
|
||||
/** list of strings, that the fast reload thread produces that have
|
||||
* to be printed. The remote control thread can pick them up with
|
||||
* the lock. */
|
||||
struct config_strlist_head* fr_output;
|
||||
|
||||
/** communication socket pair, to respond to the reload request */
|
||||
int commreload[2];
|
||||
|
||||
/** the list of auth zone changes. */
|
||||
struct fast_reload_auth_change* auth_zone_change_list;
|
||||
/** the old tree of auth zones, to lookup. */
|
||||
struct auth_zones* old_auth_zones;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create new remote control state for the daemon.
|
||||
* @param cfg: config file with key file settings.
|
||||
|
|
@ -203,4 +336,38 @@ int ssl_printf(RES* ssl, const char* format, ...)
|
|||
int ssl_read_line(RES* ssl, char* buf, size_t max);
|
||||
#endif /* HAVE_SSL */
|
||||
|
||||
/**
|
||||
* Start fast reload thread
|
||||
* @param ssl: the RES connection to print to.
|
||||
* @param worker: the remote servicing worker.
|
||||
* @param s: the rc_state that is servicing the remote control connection to
|
||||
* the remote control client. It needs to be moved away to stay connected
|
||||
* while the fast reload is running.
|
||||
* @param fr_verb: verbosity to print output at. 0 is nothing, 1 is some
|
||||
* and 2 is more detail.
|
||||
* @param fr_nopause: option to not pause threads during reload.
|
||||
* @param fr_drop_mesh: option to drop mesh queries.
|
||||
*/
|
||||
void fast_reload_thread_start(RES* ssl, struct worker* worker,
|
||||
struct rc_state* s, int fr_verb, int fr_nopause, int fr_drop_mesh);
|
||||
|
||||
/**
|
||||
* Stop fast reload thread
|
||||
* @param fast_reload_thread: the thread struct.
|
||||
*/
|
||||
void fast_reload_thread_stop(struct fast_reload_thread* fast_reload_thread);
|
||||
|
||||
/** fast reload thread commands to remote service thread event callback */
|
||||
void fast_reload_service_cb(int fd, short bits, void* arg);
|
||||
|
||||
/** fast reload callback for the remote control client connection */
|
||||
int fast_reload_client_callback(struct comm_point* c, void* arg, int err,
|
||||
struct comm_reply* rep);
|
||||
|
||||
/** fast reload printq delete list */
|
||||
void fast_reload_printq_list_delete(struct fast_reload_printq* list);
|
||||
|
||||
/** Pick up per worker changes after a fast reload. */
|
||||
void fast_reload_worker_pickup_changes(struct worker* worker);
|
||||
|
||||
#endif /* DAEMON_REMOTE_H */
|
||||
|
|
|
|||
|
|
@ -710,6 +710,9 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode,
|
|||
* it would succeed on SIGHUP as well */
|
||||
if(!cfg->use_syslog)
|
||||
log_init(cfg->logfile, cfg->use_syslog, cfg->chrootdir);
|
||||
daemon->cfgfile = strdup(*cfgfile);
|
||||
if(!daemon->cfgfile)
|
||||
fatal_exit("out of memory in daemon cfgfile strdup");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -371,6 +371,84 @@ worker_check_request(sldns_buffer* pkt, struct worker* worker,
|
|||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send fast-reload acknowledgement to the mainthread in one byte.
|
||||
* This signals that this worker has received the previous command.
|
||||
* The worker is waiting if that is after a reload_stop command.
|
||||
* Or the worker has briefly processed the event itself, and in doing so
|
||||
* released data pointers to old config, after a reload_poll command.
|
||||
*/
|
||||
static void
|
||||
worker_send_reload_ack(struct worker* worker)
|
||||
{
|
||||
/* If this is clipped to 8 bits because thread_num>255, then that
|
||||
* is not a problem, the receiver counts the number of bytes received.
|
||||
* The number is informative only. */
|
||||
uint8_t c = (uint8_t)worker->thread_num;
|
||||
ssize_t ret;
|
||||
while(1) {
|
||||
ret = send(worker->daemon->fast_reload_thread->commreload[1],
|
||||
(void*)&c, 1, 0);
|
||||
if(ret == -1) {
|
||||
if(
|
||||
#ifndef USE_WINSOCK
|
||||
errno == EINTR || errno == EAGAIN
|
||||
# ifdef EWOULDBLOCK
|
||||
|| errno == EWOULDBLOCK
|
||||
# endif
|
||||
#else
|
||||
WSAGetLastError() == WSAEINTR ||
|
||||
WSAGetLastError() == WSAEINPROGRESS ||
|
||||
WSAGetLastError() == WSAEWOULDBLOCK
|
||||
#endif
|
||||
)
|
||||
continue; /* Try again. */
|
||||
log_err("worker reload ack reply: send failed: %s",
|
||||
sock_strerror(errno));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** stop and wait to resume the worker */
|
||||
static void
|
||||
worker_stop_and_wait(struct worker* worker)
|
||||
{
|
||||
uint8_t* buf = NULL;
|
||||
uint32_t len = 0, cmd;
|
||||
worker_send_reload_ack(worker);
|
||||
/* wait for reload */
|
||||
if(!tube_read_msg(worker->cmd, &buf, &len, 0)) {
|
||||
log_err("worker reload read reply failed");
|
||||
return;
|
||||
}
|
||||
if(len != sizeof(uint32_t)) {
|
||||
log_err("worker reload reply, bad control msg length %d",
|
||||
(int)len);
|
||||
free(buf);
|
||||
return;
|
||||
}
|
||||
cmd = sldns_read_uint32(buf);
|
||||
free(buf);
|
||||
if(cmd == worker_cmd_quit) {
|
||||
/* quit anyway */
|
||||
verbose(VERB_ALGO, "reload reply, control cmd quit");
|
||||
comm_base_exit(worker->base);
|
||||
return;
|
||||
}
|
||||
if(cmd != worker_cmd_reload_start) {
|
||||
log_err("worker reload reply, wrong reply command");
|
||||
}
|
||||
if(worker->daemon->fast_reload_drop_mesh) {
|
||||
verbose(VERB_ALGO, "worker: drop mesh queries after reload");
|
||||
mesh_delete_all(worker->env.mesh);
|
||||
}
|
||||
fast_reload_worker_pickup_changes(worker);
|
||||
worker_send_reload_ack(worker);
|
||||
verbose(VERB_ALGO, "worker resume after reload");
|
||||
}
|
||||
|
||||
void
|
||||
worker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), uint8_t* msg,
|
||||
size_t len, int error, void* arg)
|
||||
|
|
@ -406,6 +484,15 @@ worker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), uint8_t* msg,
|
|||
verbose(VERB_ALGO, "got control cmd remote");
|
||||
daemon_remote_exec(worker);
|
||||
break;
|
||||
case worker_cmd_reload_stop:
|
||||
verbose(VERB_ALGO, "got control cmd reload_stop");
|
||||
worker_stop_and_wait(worker);
|
||||
break;
|
||||
case worker_cmd_reload_poll:
|
||||
verbose(VERB_ALGO, "got control cmd reload_poll");
|
||||
fast_reload_worker_pickup_changes(worker);
|
||||
worker_send_reload_ack(worker);
|
||||
break;
|
||||
default:
|
||||
log_err("bad command %d", (int)cmd);
|
||||
break;
|
||||
|
|
@ -600,7 +687,8 @@ apply_respip_action(struct worker* worker, const struct query_info* qinfo,
|
|||
return 1;
|
||||
|
||||
if(!respip_rewrite_reply(qinfo, cinfo, rep, encode_repp, &actinfo,
|
||||
alias_rrset, 0, worker->scratchpad, az, NULL))
|
||||
alias_rrset, 0, worker->scratchpad, az, NULL,
|
||||
worker->env.views, worker->env.respip_set))
|
||||
return 0;
|
||||
|
||||
/* xxx_deny actions mean dropping the reply, unless the original reply
|
||||
|
|
@ -761,7 +849,8 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
|
|||
} else if(partial_rep &&
|
||||
!respip_merge_cname(partial_rep, qinfo, rep, cinfo,
|
||||
must_validate, &encode_rep, worker->scratchpad,
|
||||
worker->env.auth_zones)) {
|
||||
worker->env.auth_zones, worker->env.views,
|
||||
worker->env.respip_set)) {
|
||||
goto bail_out;
|
||||
}
|
||||
if(encode_rep != rep) {
|
||||
|
|
@ -1813,7 +1902,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
|||
cinfo_tmp.tag_datas = acladdr->tag_datas;
|
||||
cinfo_tmp.tag_datas_size = acladdr->tag_datas_size;
|
||||
cinfo_tmp.view = acladdr->view;
|
||||
cinfo_tmp.respip_set = worker->daemon->respip_set;
|
||||
cinfo_tmp.view_name = NULL;
|
||||
cinfo = &cinfo_tmp;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -72,7 +72,13 @@ enum worker_commands {
|
|||
/** obtain statistics without statsclear */
|
||||
worker_cmd_stats_noreset,
|
||||
/** execute remote control command */
|
||||
worker_cmd_remote
|
||||
worker_cmd_remote,
|
||||
/** for fast-reload, perform stop */
|
||||
worker_cmd_reload_stop,
|
||||
/** for fast-reload, start again */
|
||||
worker_cmd_reload_start,
|
||||
/** for fast-reload, poll to make sure worker has released data */
|
||||
worker_cmd_reload_poll
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -192,8 +192,11 @@ static void
|
|||
dt_apply_identity(struct dt_env *env, struct config_file *cfg)
|
||||
{
|
||||
char buf[MAXHOSTNAMELEN+1];
|
||||
if (!cfg->dnstap_send_identity)
|
||||
if (!cfg->dnstap_send_identity) {
|
||||
free(env->identity);
|
||||
env->identity = NULL;
|
||||
return;
|
||||
}
|
||||
free(env->identity);
|
||||
if (cfg->dnstap_identity == NULL || cfg->dnstap_identity[0] == 0) {
|
||||
if (gethostname(buf, MAXHOSTNAMELEN) == 0) {
|
||||
|
|
@ -215,8 +218,11 @@ dt_apply_identity(struct dt_env *env, struct config_file *cfg)
|
|||
static void
|
||||
dt_apply_version(struct dt_env *env, struct config_file *cfg)
|
||||
{
|
||||
if (!cfg->dnstap_send_version)
|
||||
if (!cfg->dnstap_send_version) {
|
||||
free(env->version);
|
||||
env->version = NULL;
|
||||
return;
|
||||
}
|
||||
free(env->version);
|
||||
if (cfg->dnstap_version == NULL || cfg->dnstap_version[0] == 0)
|
||||
env->version = strdup(PACKAGE_STRING);
|
||||
|
|
@ -230,13 +236,8 @@ dt_apply_version(struct dt_env *env, struct config_file *cfg)
|
|||
}
|
||||
|
||||
void
|
||||
dt_apply_cfg(struct dt_env *env, struct config_file *cfg)
|
||||
dt_apply_logcfg(struct dt_env *env, struct config_file *cfg)
|
||||
{
|
||||
if (!cfg->dnstap)
|
||||
return;
|
||||
|
||||
dt_apply_identity(env, cfg);
|
||||
dt_apply_version(env, cfg);
|
||||
if ((env->log_resolver_query_messages = (unsigned int)
|
||||
cfg->dnstap_log_resolver_query_messages))
|
||||
{
|
||||
|
|
@ -275,6 +276,17 @@ dt_apply_cfg(struct dt_env *env, struct config_file *cfg)
|
|||
lock_basic_unlock(&env->sample_lock);
|
||||
}
|
||||
|
||||
void
|
||||
dt_apply_cfg(struct dt_env *env, struct config_file *cfg)
|
||||
{
|
||||
if (!cfg->dnstap)
|
||||
return;
|
||||
|
||||
dt_apply_identity(env, cfg);
|
||||
dt_apply_version(env, cfg);
|
||||
dt_apply_logcfg(env, cfg);
|
||||
}
|
||||
|
||||
int
|
||||
dt_init(struct dt_env *env, struct comm_base* base)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -106,6 +106,13 @@ dt_create(struct config_file* cfg);
|
|||
void
|
||||
dt_apply_cfg(struct dt_env *env, struct config_file *cfg);
|
||||
|
||||
/**
|
||||
* Apply config settings for log enable for message types.
|
||||
* @param env: dnstap environment object.
|
||||
* @param cfg: new config settings.
|
||||
*/
|
||||
void dt_apply_logcfg(struct dt_env *env, struct config_file *cfg);
|
||||
|
||||
/**
|
||||
* Initialize per-worker state in dnstap environment object.
|
||||
* @param env: dnstap environment object to initialize, created with dt_create().
|
||||
|
|
|
|||
|
|
@ -1787,6 +1787,20 @@ void remote_get_opt_ssl(char* ATTR_UNUSED(str), void* ATTR_UNUSED(arg))
|
|||
log_assert(0);
|
||||
}
|
||||
|
||||
void fast_reload_service_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
|
||||
void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
int fast_reload_client_callback(struct comm_point* ATTR_UNUSED(c),
|
||||
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
|
||||
struct comm_reply* ATTR_UNUSED(repinfo))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_NGTCP2
|
||||
void doq_client_event_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
|
||||
void* ATTR_UNUSED(arg))
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
31 March 2025: Wouter
|
||||
- iana portlist update.
|
||||
- Merge #1042: Fast Reload. The unbound-control fast_reload is added.
|
||||
It reads changed config in a thread, then only briefly pauses the
|
||||
service threads, that keep running. DNS service is only interrupted
|
||||
briefly, less than a second.
|
||||
|
||||
27 March 2025: Wouter
|
||||
- Fix unit test dname log printout typecast.
|
||||
|
|
|
|||
|
|
@ -60,6 +60,93 @@ Reload the server but try to keep the RRset and message cache if
|
|||
That means the caches sizes and the number of threads must not change between
|
||||
reloads.
|
||||
.TP
|
||||
.B fast_reload \fR[\fI+dpv\fR]
|
||||
Reload the server, but keep downtime to a minimum, so that user queries
|
||||
keep seeing service. This needs the code compiled with threads. The config
|
||||
is loaded in a thread, and prepared, then it briefly pauses the existing
|
||||
server and updates config options. The intent is that the pause does not
|
||||
impact the service of user queries. The cache is kept. Also user queries
|
||||
worked on are kept and continue, but with the new config options.
|
||||
This command is experimental at this time.
|
||||
Not all options are changed, but it changes like forwards, stubs and
|
||||
local zones. Also access-control and interface-action and similar options,
|
||||
also tcp-connection-limits, views. It can reload some define-tag changes.
|
||||
It does not work with interface, outgoing-interface changes, also not with
|
||||
remote-control, outgoing-port-permit, outgoing-port-avoid, msg-buffer-size,
|
||||
slabs options and statistics-interval changes.
|
||||
.IP
|
||||
The fast reload also works on the options: insecure-lan-zones, domain-insecure,
|
||||
trust-anchor-file, trust-anchor, trusted-key-file, auto-trust-anchor-file,
|
||||
auth-zone and its options, rpz and its options, edns-strings, respip_set,
|
||||
view and its options, access-control options, tcp-connection-limit,
|
||||
log-identity, infra-cache-numhosts, msg-cache-size, rrset-cache-size,
|
||||
key-cache-size, ratelimit-size, neg-cache-size, num-queries-per-thread,
|
||||
jostle-timeout, use-caps-for-id, unwanted-reply-threshold, tls-use-sni,
|
||||
outgoing-tcp-mss, ip-dscp, max-reuse-tcp-queries, tcp-reuse-timeout,
|
||||
tcp-auth-query-timeout, delay-close.
|
||||
.IP
|
||||
For dnstap, the options can be changed: dnstap-log-resolver-query-messages,
|
||||
dnstap-log-resolver-response-messages, dnstap-log-client-query-messages,
|
||||
dnstap-log-client-response-messages, dnstap-log-forwarder-query-messages
|
||||
and dnstap-log-forwarder-response-messages. It does not work with
|
||||
these options: dnstap-enable, dnstap-bidirectional, dnstap-socket-path,
|
||||
dnstap-ip, dnstap-tls, dnstap-tls-server-name, dnstap-tls-cert-bundle,
|
||||
dnstap-tls-client-key-file and dnstap-tls-client-cert-file. The options
|
||||
dnstap-send-identity, dnstap-send-version, dnstap-identity, and
|
||||
dnstap-version can be loaded when '+p' is not used.
|
||||
.IP
|
||||
The '+v' option makes the output verbose which includes the time it took to do
|
||||
the reload.
|
||||
With '+vv' it is more verbose which includes the amount of memory that was
|
||||
allocated temporarily to perform the reload; this amount of memory can be big
|
||||
if the config has large contents.
|
||||
In the timing output the 'reload' time is the time during which the server was
|
||||
paused.
|
||||
.IP
|
||||
The '+p' option makes the reload not pause threads, they keep running.
|
||||
Locks are acquired, but items are updated in sequence, so it is possible
|
||||
for threads to see an inconsistent state with some options from the old
|
||||
and some options from the new config, such as cache TTL parameters from the
|
||||
old config and forwards from the new config. The stubs and forwards are
|
||||
updated at the same time, so that they are viewed consistently, either old
|
||||
or new values together. The option makes the reload time take eg. 3
|
||||
microseconds instead of 0.3 milliseconds during which the worker threads are
|
||||
interrupted. So, the interruption is much shorter, at the expense of some
|
||||
inconsistency. After the reload itself, every worker thread is briefly
|
||||
contacted to make them release resources, this makes the delete timing
|
||||
a little longer, and takes up time from the remote control servicing
|
||||
worker thread.
|
||||
.IP
|
||||
With the nopause option, the reload does not work to reload some options,
|
||||
that fast reload works on without the nopause option: val-bogus-ttl,
|
||||
val-date-override, val-sig-key-min, val-sig-skew-max, val-max-restart,
|
||||
val-nsec3-keysize-iterations, target-fetch-policy, outbound-msg-retry,
|
||||
max-sent-count, max-query-restarts, do-not-query-address,
|
||||
do-not-query-localhost, private-address, private-domain, caps-exempt,
|
||||
nat64-prefix, do-nat64, infra-host-ttl, infra-keep-probing, ratelimit,
|
||||
ip-ratelimit, ip-ratelimit-cookie, wait-limit-netblock,
|
||||
wait-limit-cookie-netblock, ratelimit-below-domain, ratelimit-for-domain.
|
||||
.IP
|
||||
The '+d' option makes the reload drop queries that the worker threads are
|
||||
working on. This is like flush_requestlist. Without it the queries are kept
|
||||
so that users keep getting answers for those queries that are currently
|
||||
processed. The drop makes it so that queries during the life time of the
|
||||
query processing see only old, or only new config options.
|
||||
.IP
|
||||
When there are changes to the config tags, from \fBdefine\-tag\fR config,
|
||||
then the '+d' option is implicitly turned on with a warning printout, and
|
||||
queries are dropped.
|
||||
This is to stop references to the old tag information, by the old
|
||||
queries. If the number of tags is increased in the newly loaded config, by
|
||||
adding tags at the end, then the implicit '+d' option is not needed.
|
||||
.IP
|
||||
For response ip, that is actions associated with IP addresses, and perhaps
|
||||
intersected with access control tag and action information, those settings
|
||||
are stored with a query when it comes in based on its source IP address.
|
||||
The old information is kept with the query until the queries are done.
|
||||
This is gone when those queries are resolved and finished, or it is possible
|
||||
to flush the requestlist with '+d'.
|
||||
.TP
|
||||
.B verbosity \fInumber
|
||||
Change verbosity value for logging. Same values as \fBverbosity\fR keyword in
|
||||
\fIunbound.conf\fR(5). This new setting lasts until the server is issued
|
||||
|
|
|
|||
|
|
@ -624,3 +624,19 @@ forwards_delete_stub_hole(struct iter_forwards* fwd, uint16_t c,
|
|||
fwd_init_parents(fwd);
|
||||
if(!nolock) { lock_rw_unlock(&fwd->lock); }
|
||||
}
|
||||
|
||||
void
|
||||
forwards_swap_tree(struct iter_forwards* fwd, struct iter_forwards* data)
|
||||
{
|
||||
rbtree_type* oldtree = fwd->tree;
|
||||
if(oldtree) {
|
||||
lock_unprotect(&fwd->lock, oldtree);
|
||||
}
|
||||
if(data->tree) {
|
||||
lock_unprotect(&data->lock, data->tree);
|
||||
}
|
||||
fwd->tree = data->tree;
|
||||
data->tree = oldtree;
|
||||
lock_protect(&fwd->lock, fwd->tree, sizeof(*fwd->tree));
|
||||
lock_protect(&data->lock, data->tree, sizeof(*data->tree));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -234,4 +234,13 @@ int forwards_add_stub_hole(struct iter_forwards* fwd, uint16_t c,
|
|||
void forwards_delete_stub_hole(struct iter_forwards* fwd, uint16_t c,
|
||||
uint8_t* nm, int nolock);
|
||||
|
||||
/**
|
||||
* Swap internal tree with preallocated entries. Caller should manage
|
||||
* the locks.
|
||||
* @param fwd: the forward data structure.
|
||||
* @param data: the data structure used to take elements from. This contains
|
||||
* the old elements on return.
|
||||
*/
|
||||
void forwards_swap_tree(struct iter_forwards* fwd, struct iter_forwards* data);
|
||||
|
||||
#endif /* ITERATOR_ITER_FWD_H */
|
||||
|
|
|
|||
|
|
@ -611,3 +611,14 @@ hints_delete_stub(struct iter_hints* hints, uint16_t c, uint8_t* nm,
|
|||
name_tree_init_parents(&hints->tree);
|
||||
if(!nolock) { lock_rw_unlock(&hints->lock); }
|
||||
}
|
||||
|
||||
void
|
||||
hints_swap_tree(struct iter_hints* hints, struct iter_hints* data)
|
||||
{
|
||||
rbnode_type* oldroot = hints->tree.root;
|
||||
size_t oldcount = hints->tree.count;
|
||||
hints->tree.root = data->tree.root;
|
||||
hints->tree.count = data->tree.count;
|
||||
data->tree.root = oldroot;
|
||||
data->tree.count = oldcount;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -198,4 +198,13 @@ int hints_add_stub(struct iter_hints* hints, uint16_t c, struct delegpt* dp,
|
|||
void hints_delete_stub(struct iter_hints* hints, uint16_t c,
|
||||
uint8_t* nm, int nolock);
|
||||
|
||||
/**
|
||||
* Swap internal tree with preallocated entries. Caller should manage
|
||||
* the locks.
|
||||
* @param hints: the hints data structure.
|
||||
* @param data: the data structure used to take elements from. This contains
|
||||
* the old elements on return.
|
||||
*/
|
||||
void hints_swap_tree(struct iter_hints* hints, struct iter_hints* data);
|
||||
|
||||
#endif /* ITERATOR_ITER_HINTS_H */
|
||||
|
|
|
|||
|
|
@ -77,41 +77,73 @@
|
|||
static const char DEFAULT_NAT64_PREFIX[] = "64:ff9b::/96";
|
||||
|
||||
/** fillup fetch policy array */
|
||||
static void
|
||||
fetch_fill(struct iter_env* ie, const char* str)
|
||||
static int
|
||||
fetch_fill(int* target_fetch_policy, int max_dependency_depth, const char* str)
|
||||
{
|
||||
char* s = (char*)str, *e;
|
||||
int i;
|
||||
for(i=0; i<ie->max_dependency_depth+1; i++) {
|
||||
ie->target_fetch_policy[i] = strtol(s, &e, 10);
|
||||
if(s == e)
|
||||
fatal_exit("cannot parse fetch policy number %s", s);
|
||||
for(i=0; i<max_dependency_depth+1; i++) {
|
||||
target_fetch_policy[i] = strtol(s, &e, 10);
|
||||
if(s == e) {
|
||||
log_err("cannot parse fetch policy number %s", s);
|
||||
return 0;
|
||||
}
|
||||
s = e;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Read config string that represents the target fetch policy */
|
||||
static int
|
||||
read_fetch_policy(struct iter_env* ie, const char* str)
|
||||
int
|
||||
read_fetch_policy(int** target_fetch_policy, int* max_dependency_depth,
|
||||
const char* str)
|
||||
{
|
||||
int count = cfg_count_numbers(str);
|
||||
if(count < 1) {
|
||||
log_err("Cannot parse target fetch policy: \"%s\"", str);
|
||||
return 0;
|
||||
}
|
||||
ie->max_dependency_depth = count - 1;
|
||||
ie->target_fetch_policy = (int*)calloc(
|
||||
(size_t)ie->max_dependency_depth+1, sizeof(int));
|
||||
if(!ie->target_fetch_policy) {
|
||||
*max_dependency_depth = count - 1;
|
||||
*target_fetch_policy = (int*)calloc(
|
||||
(size_t)(*max_dependency_depth)+1, sizeof(int));
|
||||
if(!*target_fetch_policy) {
|
||||
log_err("alloc fetch policy: out of memory");
|
||||
return 0;
|
||||
}
|
||||
fetch_fill(ie, str);
|
||||
if(!fetch_fill(*target_fetch_policy, *max_dependency_depth, str))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** apply config caps whitelist items to name tree */
|
||||
static int
|
||||
struct rbtree_type*
|
||||
caps_white_create(void)
|
||||
{
|
||||
struct rbtree_type* caps_white = rbtree_create(name_tree_compare);
|
||||
if(!caps_white)
|
||||
log_err("out of memory");
|
||||
return caps_white;
|
||||
}
|
||||
|
||||
/** delete caps_whitelist element */
|
||||
static void
|
||||
caps_free(struct rbnode_type* n, void* ATTR_UNUSED(d))
|
||||
{
|
||||
if(n) {
|
||||
free(((struct name_tree_node*)n)->name);
|
||||
free(n);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
caps_white_delete(struct rbtree_type* caps_white)
|
||||
{
|
||||
if(!caps_white)
|
||||
return;
|
||||
traverse_postorder(caps_white, caps_free, NULL);
|
||||
free(caps_white);
|
||||
}
|
||||
|
||||
int
|
||||
caps_white_apply_cfg(rbtree_type* ntree, struct config_file* cfg)
|
||||
{
|
||||
struct config_strlist* p;
|
||||
|
|
@ -145,12 +177,41 @@ caps_white_apply_cfg(rbtree_type* ntree, struct config_file* cfg)
|
|||
}
|
||||
|
||||
int
|
||||
iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg)
|
||||
nat64_apply_cfg(struct iter_nat64* nat64, struct config_file* cfg)
|
||||
{
|
||||
const char *nat64_prefix;
|
||||
|
||||
nat64_prefix = cfg->nat64_prefix;
|
||||
if(!nat64_prefix)
|
||||
nat64_prefix = cfg->dns64_prefix;
|
||||
if(!nat64_prefix)
|
||||
nat64_prefix = DEFAULT_NAT64_PREFIX;
|
||||
if(!netblockstrtoaddr(nat64_prefix, 0, &nat64->nat64_prefix_addr,
|
||||
&nat64->nat64_prefix_addrlen, &nat64->nat64_prefix_net)) {
|
||||
log_err("cannot parse nat64-prefix netblock: %s", nat64_prefix);
|
||||
return 0;
|
||||
}
|
||||
if(!addr_is_ip6(&nat64->nat64_prefix_addr,
|
||||
nat64->nat64_prefix_addrlen)) {
|
||||
log_err("nat64-prefix is not IPv6: %s", cfg->nat64_prefix);
|
||||
return 0;
|
||||
}
|
||||
if(!prefixnet_is_nat64(nat64->nat64_prefix_net)) {
|
||||
log_err("nat64-prefix length it not 32, 40, 48, 56, 64 or 96: %s",
|
||||
nat64_prefix);
|
||||
return 0;
|
||||
}
|
||||
nat64->use_nat64 = cfg->do_nat64;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg)
|
||||
{
|
||||
int i;
|
||||
/* target fetch policy */
|
||||
if(!read_fetch_policy(iter_env, cfg->target_fetch_policy))
|
||||
if(!read_fetch_policy(&iter_env->target_fetch_policy,
|
||||
&iter_env->max_dependency_depth, cfg->target_fetch_policy))
|
||||
return 0;
|
||||
for(i=0; i<iter_env->max_dependency_depth+1; i++)
|
||||
verbose(VERB_QUERY, "target fetch policy for level %d is %d",
|
||||
|
|
@ -170,7 +231,7 @@ iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg)
|
|||
}
|
||||
if(cfg->caps_whitelist) {
|
||||
if(!iter_env->caps_white)
|
||||
iter_env->caps_white = rbtree_create(name_tree_compare);
|
||||
iter_env->caps_white = caps_white_create();
|
||||
if(!iter_env->caps_white || !caps_white_apply_cfg(
|
||||
iter_env->caps_white, cfg)) {
|
||||
log_err("Could not set capsforid whitelist");
|
||||
|
|
@ -179,31 +240,13 @@ iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg)
|
|||
|
||||
}
|
||||
|
||||
nat64_prefix = cfg->nat64_prefix;
|
||||
if(!nat64_prefix)
|
||||
nat64_prefix = cfg->dns64_prefix;
|
||||
if(!nat64_prefix)
|
||||
nat64_prefix = DEFAULT_NAT64_PREFIX;
|
||||
if(!netblockstrtoaddr(nat64_prefix, 0, &iter_env->nat64_prefix_addr,
|
||||
&iter_env->nat64_prefix_addrlen,
|
||||
&iter_env->nat64_prefix_net)) {
|
||||
log_err("cannot parse nat64-prefix netblock: %s", nat64_prefix);
|
||||
return 0;
|
||||
}
|
||||
if(!addr_is_ip6(&iter_env->nat64_prefix_addr,
|
||||
iter_env->nat64_prefix_addrlen)) {
|
||||
log_err("nat64-prefix is not IPv6: %s", cfg->nat64_prefix);
|
||||
return 0;
|
||||
}
|
||||
if(!prefixnet_is_nat64(iter_env->nat64_prefix_net)) {
|
||||
log_err("nat64-prefix length it not 32, 40, 48, 56, 64 or 96: %s",
|
||||
nat64_prefix);
|
||||
if(!nat64_apply_cfg(&iter_env->nat64, cfg)) {
|
||||
log_err("Could not setup nat64");
|
||||
return 0;
|
||||
}
|
||||
|
||||
iter_env->supports_ipv6 = cfg->do_ip6;
|
||||
iter_env->supports_ipv4 = cfg->do_ip4;
|
||||
iter_env->use_nat64 = cfg->do_nat64;
|
||||
iter_env->outbound_msg_retry = cfg->outbound_msg_retry;
|
||||
iter_env->max_sent_count = cfg->max_sent_count;
|
||||
iter_env->max_query_restarts = cfg->max_query_restarts;
|
||||
|
|
@ -270,7 +313,7 @@ iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env,
|
|||
if(!iter_env->supports_ipv6 && addr_is_ip6(&a->addr, a->addrlen)) {
|
||||
return -1; /* there is no ip6 available */
|
||||
}
|
||||
if(!iter_env->supports_ipv4 && !iter_env->use_nat64 &&
|
||||
if(!iter_env->supports_ipv4 && !iter_env->nat64.use_nat64 &&
|
||||
!addr_is_ip6(&a->addr, a->addrlen)) {
|
||||
return -1; /* there is no ip4 available */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ struct sock_list;
|
|||
struct ub_packed_rrset_key;
|
||||
struct module_stack;
|
||||
struct outside_network;
|
||||
struct iter_nat64;
|
||||
|
||||
/* max number of lookups in the cache for target nameserver names.
|
||||
* This stops, for large delegations, N*N lookups in the cache. */
|
||||
|
|
@ -430,6 +431,43 @@ int iter_stub_fwd_no_cache(struct module_qstate *qstate,
|
|||
void iterator_set_ip46_support(struct module_stack* mods,
|
||||
struct module_env* env, struct outside_network* outnet);
|
||||
|
||||
/**
|
||||
* Read config string that represents the target fetch policy.
|
||||
* @param target_fetch_policy: alloced on return.
|
||||
* @param max_dependency_depth: set on return.
|
||||
* @param str: the config string
|
||||
* @return false on failure.
|
||||
*/
|
||||
int read_fetch_policy(int** target_fetch_policy, int* max_dependency_depth,
|
||||
const char* str);
|
||||
|
||||
/**
|
||||
* Create caps exempt data structure.
|
||||
* @return NULL on failure.
|
||||
*/
|
||||
struct rbtree_type* caps_white_create(void);
|
||||
|
||||
/**
|
||||
* Delete caps exempt data structure.
|
||||
* @param caps_white: caps exempt tree.
|
||||
*/
|
||||
void caps_white_delete(struct rbtree_type* caps_white);
|
||||
|
||||
/**
|
||||
* Apply config caps whitelist items to name tree
|
||||
* @param ntree: caps exempt tree.
|
||||
* @param cfg: config with options.
|
||||
*/
|
||||
int caps_white_apply_cfg(struct rbtree_type* ntree, struct config_file* cfg);
|
||||
|
||||
/**
|
||||
* Apply config for nat64
|
||||
* @param nat64: the nat64 state.
|
||||
* @param cfg: config with options.
|
||||
* @return false on failure.
|
||||
*/
|
||||
int nat64_apply_cfg(struct iter_nat64* nat64, struct config_file* cfg);
|
||||
|
||||
/**
|
||||
* Limit NSEC and NSEC3 TTL in response, RFC9077
|
||||
* @param msg: dns message, the SOA record ttl is used to restrict ttls
|
||||
|
|
|
|||
|
|
@ -107,16 +107,6 @@ iter_init(struct module_env* env, int id)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/** delete caps_whitelist element */
|
||||
static void
|
||||
caps_free(struct rbnode_type* n, void* ATTR_UNUSED(d))
|
||||
{
|
||||
if(n) {
|
||||
free(((struct name_tree_node*)n)->name);
|
||||
free(n);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
iter_deinit(struct module_env* env, int id)
|
||||
{
|
||||
|
|
@ -128,10 +118,7 @@ iter_deinit(struct module_env* env, int id)
|
|||
free(iter_env->target_fetch_policy);
|
||||
priv_delete(iter_env->priv);
|
||||
donotq_delete(iter_env->donotq);
|
||||
if(iter_env->caps_white) {
|
||||
traverse_postorder(iter_env->caps_white, caps_free, NULL);
|
||||
free(iter_env->caps_white);
|
||||
}
|
||||
caps_white_delete(iter_env->caps_white);
|
||||
free(iter_env);
|
||||
env->modinfo[id] = NULL;
|
||||
}
|
||||
|
|
@ -260,7 +247,7 @@ error_supers(struct module_qstate* qstate, int id, struct module_qstate* super)
|
|||
log_err("out of memory adding missing");
|
||||
}
|
||||
delegpt_mark_neg(dpns, qstate->qinfo.qtype);
|
||||
if((dpns->got4 == 2 || (!ie->supports_ipv4 && !ie->use_nat64)) &&
|
||||
if((dpns->got4 == 2 || (!ie->supports_ipv4 && !ie->nat64.use_nat64)) &&
|
||||
(dpns->got6 == 2 || !ie->supports_ipv6)) {
|
||||
dpns->resolved = 1; /* mark as failed */
|
||||
target_count_increase_nx(super_iq, 1);
|
||||
|
|
@ -1725,7 +1712,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
|||
*/
|
||||
if(iter_dp_is_useless(&qstate->qinfo, qstate->query_flags,
|
||||
iq->dp, ie->supports_ipv4, ie->supports_ipv6,
|
||||
ie->use_nat64)) {
|
||||
ie->nat64.use_nat64)) {
|
||||
int have_dp = 0;
|
||||
if(!can_have_last_resort(qstate->env, iq->dp->name, iq->dp->namelen, iq->qchase.qclass, &have_dp, &iq->dp, qstate->region)) {
|
||||
if(have_dp) {
|
||||
|
|
@ -2089,7 +2076,7 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq,
|
|||
if(mesh_jostle_exceeded(qstate->env->mesh)) {
|
||||
/* If no ip4 query is possible, that makes
|
||||
* this ns resolved. */
|
||||
if(!((ie->supports_ipv4 || ie->use_nat64) &&
|
||||
if(!((ie->supports_ipv4 || ie->nat64.use_nat64) &&
|
||||
((ns->lame && !ns->done_pside4) ||
|
||||
(!ns->lame && !ns->got4)))) {
|
||||
ns->resolved = 1;
|
||||
|
|
@ -2098,7 +2085,7 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq,
|
|||
}
|
||||
}
|
||||
/* Send the A request. */
|
||||
if((ie->supports_ipv4 || ie->use_nat64) &&
|
||||
if((ie->supports_ipv4 || ie->nat64.use_nat64) &&
|
||||
((ns->lame && !ns->done_pside4) ||
|
||||
(!ns->lame && !ns->got4))) {
|
||||
if(!generate_target_query(qstate, iq, id,
|
||||
|
|
@ -2270,14 +2257,14 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
|
|||
/* if this nameserver is at a delegation point, but that
|
||||
* delegation point is a stub and we cannot go higher, skip*/
|
||||
if( ((ie->supports_ipv6 && !ns->done_pside6) ||
|
||||
((ie->supports_ipv4 || ie->use_nat64) && !ns->done_pside4)) &&
|
||||
((ie->supports_ipv4 || ie->nat64.use_nat64) && !ns->done_pside4)) &&
|
||||
!can_have_last_resort(qstate->env, ns->name, ns->namelen,
|
||||
iq->qchase.qclass, NULL, NULL, NULL)) {
|
||||
log_nametypeclass(VERB_ALGO, "cannot pside lookup ns "
|
||||
"because it is also a stub/forward,",
|
||||
ns->name, LDNS_RR_TYPE_NS, iq->qchase.qclass);
|
||||
if(ie->supports_ipv6) ns->done_pside6 = 1;
|
||||
if(ie->supports_ipv4 || ie->use_nat64) ns->done_pside4 = 1;
|
||||
if(ie->supports_ipv4 || ie->nat64.use_nat64) ns->done_pside4 = 1;
|
||||
continue;
|
||||
}
|
||||
/* query for parent-side A and AAAA for nameservers */
|
||||
|
|
@ -2302,7 +2289,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
if((ie->supports_ipv4 || ie->use_nat64) && !ns->done_pside4) {
|
||||
if((ie->supports_ipv4 || ie->nat64.use_nat64) && !ns->done_pside4) {
|
||||
/* Send the A request. */
|
||||
if(!generate_parentside_target_query(qstate, iq, id,
|
||||
ns->name, ns->namelen,
|
||||
|
|
@ -2571,7 +2558,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
|||
}
|
||||
if(!ie->supports_ipv6)
|
||||
delegpt_no_ipv6(iq->dp);
|
||||
if(!ie->supports_ipv4 && !ie->use_nat64)
|
||||
if(!ie->supports_ipv4 && !ie->nat64.use_nat64)
|
||||
delegpt_no_ipv4(iq->dp);
|
||||
delegpt_log(VERB_ALGO, iq->dp);
|
||||
|
||||
|
|
@ -3070,9 +3057,9 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
|||
real_addr = target->addr;
|
||||
real_addrlen = target->addrlen;
|
||||
|
||||
if(ie->use_nat64 && target->addr.ss_family == AF_INET) {
|
||||
addr_to_nat64(&target->addr, &ie->nat64_prefix_addr,
|
||||
ie->nat64_prefix_addrlen, ie->nat64_prefix_net,
|
||||
if(ie->nat64.use_nat64 && target->addr.ss_family == AF_INET) {
|
||||
addr_to_nat64(&target->addr, &ie->nat64.nat64_prefix_addr,
|
||||
ie->nat64.nat64_prefix_addrlen, ie->nat64.nat64_prefix_net,
|
||||
&real_addr, &real_addrlen);
|
||||
log_name_addr(VERB_QUERY, "applied NAT64:",
|
||||
iq->dp->name, &real_addr, real_addrlen);
|
||||
|
|
@ -3882,7 +3869,7 @@ processTargetResponse(struct module_qstate* qstate, int id,
|
|||
} else {
|
||||
verbose(VERB_ALGO, "iterator TargetResponse failed");
|
||||
delegpt_mark_neg(dpns, qstate->qinfo.qtype);
|
||||
if((dpns->got4 == 2 || (!ie->supports_ipv4 && !ie->use_nat64)) &&
|
||||
if((dpns->got4 == 2 || (!ie->supports_ipv4 && !ie->nat64.use_nat64)) &&
|
||||
(dpns->got6 == 2 || !ie->supports_ipv6)) {
|
||||
dpns->resolved = 1; /* fail the target */
|
||||
/* do not count cached answers */
|
||||
|
|
|
|||
|
|
@ -46,8 +46,6 @@
|
|||
#include "util/data/msgreply.h"
|
||||
#include "util/module.h"
|
||||
struct delegpt;
|
||||
struct iter_hints;
|
||||
struct iter_forwards;
|
||||
struct iter_donotq;
|
||||
struct iter_prep_list;
|
||||
struct iter_priv;
|
||||
|
|
@ -108,15 +106,9 @@ extern int BLACKLIST_PENALTY;
|
|||
#define EMPTY_NODATA_RETRY_COUNT 2
|
||||
|
||||
/**
|
||||
* Global state for the iterator.
|
||||
* Iterator global state for nat64.
|
||||
*/
|
||||
struct iter_env {
|
||||
/** A flag to indicate whether or not we have an IPv6 route */
|
||||
int supports_ipv6;
|
||||
|
||||
/** A flag to indicate whether or not we have an IPv4 route */
|
||||
int supports_ipv4;
|
||||
|
||||
struct iter_nat64 {
|
||||
/** A flag to locally apply NAT64 to make IPv4 addrs into IPv6 */
|
||||
int use_nat64;
|
||||
|
||||
|
|
@ -128,6 +120,20 @@ struct iter_env {
|
|||
|
||||
/** CIDR mask length of NAT64 prefix */
|
||||
int nat64_prefix_net;
|
||||
};
|
||||
|
||||
/**
|
||||
* Global state for the iterator.
|
||||
*/
|
||||
struct iter_env {
|
||||
/** A flag to indicate whether or not we have an IPv6 route */
|
||||
int supports_ipv6;
|
||||
|
||||
/** A flag to indicate whether or not we have an IPv4 route */
|
||||
int supports_ipv4;
|
||||
|
||||
/** State for nat64 */
|
||||
struct iter_nat64 nat64;
|
||||
|
||||
/** A set of inetaddrs that should never be queried. */
|
||||
struct iter_donotq* donotq;
|
||||
|
|
|
|||
|
|
@ -1059,6 +1059,20 @@ void dtio_mainfdcallback(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
|
|||
}
|
||||
#endif
|
||||
|
||||
void fast_reload_service_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
|
||||
void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
int fast_reload_client_callback(struct comm_point* ATTR_UNUSED(c),
|
||||
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
|
||||
struct comm_reply* ATTR_UNUSED(repinfo))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_NGTCP2
|
||||
void doq_client_event_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
|
||||
void* ATTR_UNUSED(arg))
|
||||
|
|
|
|||
|
|
@ -105,6 +105,7 @@ respip_sockaddr_find_or_create(struct respip_set* set, struct sockaddr_storage*
|
|||
socklen_t addrlen, int net, int create, const char* ipstr)
|
||||
{
|
||||
struct resp_addr* node;
|
||||
log_assert(set);
|
||||
node = (struct resp_addr*)addr_tree_find(&set->ip_tree, addr, addrlen, net);
|
||||
if(!node && create) {
|
||||
node = regional_alloc_zero(set->region, sizeof(*node));
|
||||
|
|
@ -128,6 +129,7 @@ void
|
|||
respip_sockaddr_delete(struct respip_set* set, struct resp_addr* node)
|
||||
{
|
||||
struct resp_addr* prev;
|
||||
log_assert(set);
|
||||
prev = (struct resp_addr*)rbtree_previous((struct rbnode_type*)node);
|
||||
lock_rw_destroy(&node->lock);
|
||||
(void)rbtree_delete(&set->ip_tree, node);
|
||||
|
|
@ -146,6 +148,7 @@ respip_find_or_create(struct respip_set* set, const char* ipstr, int create)
|
|||
struct sockaddr_storage addr;
|
||||
int net;
|
||||
socklen_t addrlen;
|
||||
log_assert(set);
|
||||
|
||||
if(!netblockstrtoaddr(ipstr, 0, &addr, &addrlen, &net)) {
|
||||
log_err("cannot parse netblock: '%s'", ipstr);
|
||||
|
|
@ -160,6 +163,7 @@ respip_tag_cfg(struct respip_set* set, const char* ipstr,
|
|||
const uint8_t* taglist, size_t taglen)
|
||||
{
|
||||
struct resp_addr* node;
|
||||
log_assert(set);
|
||||
|
||||
if(!(node=respip_find_or_create(set, ipstr, 1)))
|
||||
return 0;
|
||||
|
|
@ -183,6 +187,7 @@ respip_action_cfg(struct respip_set* set, const char* ipstr,
|
|||
{
|
||||
struct resp_addr* node;
|
||||
enum respip_action action;
|
||||
log_assert(set);
|
||||
|
||||
if(!(node=respip_find_or_create(set, ipstr, 1)))
|
||||
return 0;
|
||||
|
|
@ -325,6 +330,7 @@ static int
|
|||
respip_data_cfg(struct respip_set* set, const char* ipstr, const char* rrstr)
|
||||
{
|
||||
struct resp_addr* node;
|
||||
log_assert(set);
|
||||
|
||||
node=respip_find_or_create(set, ipstr, 0);
|
||||
if(!node || node->action == respip_none) {
|
||||
|
|
@ -344,6 +350,7 @@ respip_set_apply_cfg(struct respip_set* set, char* const* tagname, int num_tags,
|
|||
struct config_strbytelist* p;
|
||||
struct config_str2list* pa;
|
||||
struct config_str2list* pd;
|
||||
log_assert(set);
|
||||
|
||||
set->tagname = tagname;
|
||||
set->num_tags = num_tags;
|
||||
|
|
@ -609,6 +616,7 @@ respip_addr_lookup(const struct reply_info *rep, struct respip_set* rs,
|
|||
struct resp_addr* ra;
|
||||
struct sockaddr_storage ss;
|
||||
socklen_t addrlen;
|
||||
log_assert(rs);
|
||||
|
||||
lock_rw_rdlock(&rs->lock);
|
||||
for(i=0; i<rep->an_numrrsets; i++) {
|
||||
|
|
@ -867,7 +875,8 @@ respip_rewrite_reply(const struct query_info* qinfo,
|
|||
const struct respip_client_info* cinfo, const struct reply_info* rep,
|
||||
struct reply_info** new_repp, struct respip_action_info* actinfo,
|
||||
struct ub_packed_rrset_key** alias_rrset, int search_only,
|
||||
struct regional* region, struct auth_zones* az, int* rpz_passthru)
|
||||
struct regional* region, struct auth_zones* az, int* rpz_passthru,
|
||||
struct views* views, struct respip_set* ipset)
|
||||
{
|
||||
const uint8_t* ctaglist;
|
||||
size_t ctaglen;
|
||||
|
|
@ -876,7 +885,6 @@ respip_rewrite_reply(const struct query_info* qinfo,
|
|||
struct config_strlist** tag_datas;
|
||||
size_t tag_datas_size;
|
||||
struct view* view = NULL;
|
||||
struct respip_set* ipset = NULL;
|
||||
size_t rrset_id = 0, rr_id = 0;
|
||||
enum respip_action action = respip_none;
|
||||
int tag = -1;
|
||||
|
|
@ -899,8 +907,20 @@ respip_rewrite_reply(const struct query_info* qinfo,
|
|||
tag_actions_size = cinfo->tag_actions_size;
|
||||
tag_datas = cinfo->tag_datas;
|
||||
tag_datas_size = cinfo->tag_datas_size;
|
||||
view = cinfo->view;
|
||||
ipset = cinfo->respip_set;
|
||||
if(cinfo->view) {
|
||||
view = cinfo->view;
|
||||
lock_rw_rdlock(&view->lock);
|
||||
} else if(cinfo->view_name) {
|
||||
view = views_find_view(views, cinfo->view_name, 0);
|
||||
if(!view) {
|
||||
/* If the view no longer exists, the rewrite can not
|
||||
* be processed further. */
|
||||
verbose(VERB_ALGO, "respip: failed because view %s no "
|
||||
"longer exists", cinfo->view_name);
|
||||
return 0;
|
||||
}
|
||||
/* The view is rdlocked by views_find_view. */
|
||||
}
|
||||
|
||||
log_assert(ipset);
|
||||
|
||||
|
|
@ -915,7 +935,6 @@ respip_rewrite_reply(const struct query_info* qinfo,
|
|||
* Note also that we assume 'view' is valid in this function, which
|
||||
* should be safe (see unbound bug #1191) */
|
||||
if(view) {
|
||||
lock_rw_rdlock(&view->lock);
|
||||
if(view->respip_set) {
|
||||
if((raddr = respip_addr_lookup(rep,
|
||||
view->respip_set, &rrset_id, &rr_id))) {
|
||||
|
|
@ -1101,7 +1120,8 @@ respip_operate(struct module_qstate* qstate, enum module_ev event, int id,
|
|||
qstate->client_info, qstate->return_msg->rep,
|
||||
&new_rep, &actinfo, &alias_rrset, 0,
|
||||
qstate->region, qstate->env->auth_zones,
|
||||
&qstate->rpz_passthru)) {
|
||||
&qstate->rpz_passthru, qstate->env->views,
|
||||
qstate->env->respip_set)) {
|
||||
goto servfail;
|
||||
}
|
||||
if(actinfo.action != respip_none) {
|
||||
|
|
@ -1149,7 +1169,8 @@ respip_merge_cname(struct reply_info* base_rep,
|
|||
const struct query_info* qinfo, const struct reply_info* tgt_rep,
|
||||
const struct respip_client_info* cinfo, int must_validate,
|
||||
struct reply_info** new_repp, struct regional* region,
|
||||
struct auth_zones* az)
|
||||
struct auth_zones* az, struct views* views,
|
||||
struct respip_set* respip_set)
|
||||
{
|
||||
struct reply_info* new_rep;
|
||||
struct reply_info* tmp_rep = NULL; /* just a placeholder */
|
||||
|
|
@ -1176,7 +1197,7 @@ respip_merge_cname(struct reply_info* base_rep,
|
|||
|
||||
/* see if the target reply would be subject to a response-ip action. */
|
||||
if(!respip_rewrite_reply(qinfo, cinfo, tgt_rep, &tmp_rep, &actinfo,
|
||||
&alias_rrset, 1, region, az, NULL))
|
||||
&alias_rrset, 1, region, az, NULL, views, respip_set))
|
||||
return 0;
|
||||
if(actinfo.action != respip_none) {
|
||||
log_info("CNAME target of redirect response-ip action would "
|
||||
|
|
@ -1229,7 +1250,8 @@ respip_inform_super(struct module_qstate* qstate, int id,
|
|||
if(!respip_merge_cname(super->return_msg->rep, &qstate->qinfo,
|
||||
qstate->return_msg->rep, super->client_info,
|
||||
super->env->need_to_validate, &new_rep, super->region,
|
||||
qstate->env->auth_zones))
|
||||
qstate->env->auth_zones, qstate->env->views,
|
||||
qstate->env->respip_set))
|
||||
goto fail;
|
||||
super->return_msg->rep = new_rep;
|
||||
return;
|
||||
|
|
@ -1326,3 +1348,35 @@ respip_inform_print(struct respip_action_info* respip_actinfo, uint8_t* qname,
|
|||
(actionstr) ? actionstr : "inform", srcip, port);
|
||||
log_nametypeclass(NO_VERBOSE, txt, qname, qtype, qclass);
|
||||
}
|
||||
|
||||
size_t respip_set_get_mem(struct respip_set* set)
|
||||
{
|
||||
size_t m;
|
||||
if(!set) return 0;
|
||||
m = sizeof(*set);
|
||||
lock_rw_rdlock(&set->lock);
|
||||
m += regional_get_mem(set->region);
|
||||
lock_rw_unlock(&set->lock);
|
||||
return m;
|
||||
}
|
||||
|
||||
void
|
||||
respip_set_swap_tree(struct respip_set* respip_set,
|
||||
struct respip_set* data)
|
||||
{
|
||||
rbnode_type* oldroot = respip_set->ip_tree.root;
|
||||
size_t oldcount = respip_set->ip_tree.count;
|
||||
struct regional* oldregion = respip_set->region;
|
||||
char* const* oldtagname = respip_set->tagname;
|
||||
int oldnum_tags = respip_set->num_tags;
|
||||
respip_set->ip_tree.root = data->ip_tree.root;
|
||||
respip_set->ip_tree.count = data->ip_tree.count;
|
||||
respip_set->region = data->region;
|
||||
respip_set->tagname = data->tagname;
|
||||
respip_set->num_tags = data->num_tags;
|
||||
data->ip_tree.root = oldroot;
|
||||
data->ip_tree.count = oldcount;
|
||||
data->region = oldregion;
|
||||
data->tagname = oldtagname;
|
||||
data->num_tags = oldnum_tags;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,8 @@
|
|||
struct respip_set {
|
||||
struct regional* region;
|
||||
struct rbtree_type ip_tree;
|
||||
lock_rw_type lock; /* lock on the respip tree */
|
||||
lock_rw_type lock; /* lock on the respip tree. It is ordered
|
||||
after views and before hints, stubs and local zones. */
|
||||
char* const* tagname; /* shallow copy of tag names, for logging */
|
||||
int num_tags; /* number of tagname entries */
|
||||
};
|
||||
|
|
@ -59,7 +60,6 @@ struct respip_addr_info;
|
|||
* This is essentially a subset of acl_addr (except for respip_set) but
|
||||
* defined as a separate structure to avoid dependency on the daemon-specific
|
||||
* structure.
|
||||
* respip_set is supposed to refer to the response-ip set for the global view.
|
||||
*/
|
||||
struct respip_client_info {
|
||||
uint8_t* taglist;
|
||||
|
|
@ -68,8 +68,12 @@ struct respip_client_info {
|
|||
size_t tag_actions_size;
|
||||
struct config_strlist** tag_datas;
|
||||
size_t tag_datas_size;
|
||||
/** The view for the action, during cache callback that is by
|
||||
* pointer. */
|
||||
struct view* view;
|
||||
struct respip_set* respip_set;
|
||||
/** If from module query state, the view pointer is NULL, but the
|
||||
* name is stored in reference to the view. */
|
||||
char* view_name;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -149,13 +153,16 @@ int respip_views_apply_cfg(struct views* vs, struct config_file* cfg,
|
|||
* on error.
|
||||
* @param region: allocator to build *new_repp.
|
||||
* @param az: auth zones containing RPZ information.
|
||||
* @param views: views tree to lookup view used.
|
||||
* @param respip_set: the respip set for the global view.
|
||||
* @return 1 on success, 0 on error.
|
||||
*/
|
||||
int respip_merge_cname(struct reply_info* base_rep,
|
||||
const struct query_info* qinfo, const struct reply_info* tgt_rep,
|
||||
const struct respip_client_info* cinfo, int must_validate,
|
||||
struct reply_info** new_repp, struct regional* region,
|
||||
struct auth_zones* az);
|
||||
struct auth_zones* az, struct views* views,
|
||||
struct respip_set* respip_set);
|
||||
|
||||
/**
|
||||
* See if any IP-based action should apply to any IP address of AAAA/A answer
|
||||
|
|
@ -178,6 +185,8 @@ int respip_merge_cname(struct reply_info* base_rep,
|
|||
* @param region: allocator to build *new_repp.
|
||||
* @param rpz_passthru: keeps track of query state can have passthru that
|
||||
* stops further rpz processing. Or NULL for cached answer processing.
|
||||
* @param views: views tree to lookup view used.
|
||||
* @param ipset: the respip set for the global view.
|
||||
* @return 1 on success, 0 on error.
|
||||
*/
|
||||
int respip_rewrite_reply(const struct query_info* qinfo,
|
||||
|
|
@ -186,7 +195,7 @@ int respip_rewrite_reply(const struct query_info* qinfo,
|
|||
struct respip_action_info* actinfo,
|
||||
struct ub_packed_rrset_key** alias_rrset,
|
||||
int search_only, struct regional* region, struct auth_zones* az,
|
||||
int* rpz_passthru);
|
||||
int* rpz_passthru, struct views* views, struct respip_set* ipset);
|
||||
|
||||
/**
|
||||
* Get the response-ip function block.
|
||||
|
|
@ -302,4 +311,18 @@ respip_sockaddr_delete(struct respip_set* set, struct resp_addr* node);
|
|||
|
||||
struct ub_packed_rrset_key*
|
||||
respip_copy_rrset(const struct ub_packed_rrset_key* key, struct regional* region);
|
||||
|
||||
/** Get memory usage of respip set tree. The routine locks and unlocks the
|
||||
* set for reading. */
|
||||
size_t respip_set_get_mem(struct respip_set* set);
|
||||
|
||||
/**
|
||||
* Swap internal tree with preallocated entries. Caller should manage
|
||||
* the locks.
|
||||
* @param respip_set: response ip tree
|
||||
* @param data: preallocated information.
|
||||
*/
|
||||
void respip_set_swap_tree(struct respip_set* respip_set,
|
||||
struct respip_set* data);
|
||||
|
||||
#endif /* RESPIP_RESPIP_H */
|
||||
|
|
|
|||
|
|
@ -2317,9 +2317,6 @@ auth_free_masters(struct auth_master* list)
|
|||
}
|
||||
}
|
||||
|
||||
/** delete auth xfer structure
|
||||
* @param xfr: delete this xfer and its tasks.
|
||||
*/
|
||||
void
|
||||
auth_xfer_delete(struct auth_xfer* xfr)
|
||||
{
|
||||
|
|
@ -7006,6 +7003,18 @@ xfr_set_timeout(struct auth_xfer* xfr, struct module_env* env,
|
|||
comm_timer_set(xfr->task_nextprobe->timer, &tv);
|
||||
}
|
||||
|
||||
void auth_xfer_pickup_initial_zone(struct auth_xfer* x, struct module_env* env)
|
||||
{
|
||||
/* set lease_time, because we now have timestamp in env,
|
||||
* (not earlier during startup and apply_cfg), and this
|
||||
* notes the start time when the data was acquired */
|
||||
if(x->have_zone)
|
||||
x->lease_time = *env->now;
|
||||
if(x->task_nextprobe && x->task_nextprobe->worker == NULL) {
|
||||
xfr_set_timeout(x, env, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/** initial pick up of worker timeouts, ties events to worker event loop */
|
||||
void
|
||||
auth_xfer_pickup_initial(struct auth_zones* az, struct module_env* env)
|
||||
|
|
@ -7014,14 +7023,7 @@ auth_xfer_pickup_initial(struct auth_zones* az, struct module_env* env)
|
|||
lock_rw_wrlock(&az->lock);
|
||||
RBTREE_FOR(x, struct auth_xfer*, &az->xtree) {
|
||||
lock_basic_lock(&x->lock);
|
||||
/* set lease_time, because we now have timestamp in env,
|
||||
* (not earlier during startup and apply_cfg), and this
|
||||
* notes the start time when the data was acquired */
|
||||
if(x->have_zone)
|
||||
x->lease_time = *env->now;
|
||||
if(x->task_nextprobe && x->task_nextprobe->worker == NULL) {
|
||||
xfr_set_timeout(x, env, 0, 1);
|
||||
}
|
||||
auth_xfer_pickup_initial_zone(x, env);
|
||||
lock_basic_unlock(&x->lock);
|
||||
}
|
||||
lock_rw_unlock(&az->lock);
|
||||
|
|
@ -8580,3 +8582,161 @@ void auth_zones_pickup_zonemd_verify(struct auth_zones* az,
|
|||
}
|
||||
lock_rw_unlock(&az->lock);
|
||||
}
|
||||
|
||||
/** Get memory usage of auth rrset */
|
||||
static size_t
|
||||
auth_rrset_get_mem(struct auth_rrset* rrset)
|
||||
{
|
||||
size_t m = sizeof(*rrset) + packed_rrset_sizeof(rrset->data);
|
||||
return m;
|
||||
}
|
||||
|
||||
/** Get memory usage of auth data */
|
||||
static size_t
|
||||
auth_data_get_mem(struct auth_data* node)
|
||||
{
|
||||
size_t m = sizeof(*node) + node->namelen;
|
||||
struct auth_rrset* rrset;
|
||||
for(rrset = node->rrsets; rrset; rrset = rrset->next) {
|
||||
m += auth_rrset_get_mem(rrset);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
/** Get memory usage of auth zone */
|
||||
static size_t
|
||||
auth_zone_get_mem(struct auth_zone* z)
|
||||
{
|
||||
size_t m = sizeof(*z) + z->namelen;
|
||||
struct auth_data* node;
|
||||
if(z->zonefile)
|
||||
m += strlen(z->zonefile)+1;
|
||||
RBTREE_FOR(node, struct auth_data*, &z->data) {
|
||||
m += auth_data_get_mem(node);
|
||||
}
|
||||
if(z->rpz)
|
||||
m += rpz_get_mem(z->rpz);
|
||||
return m;
|
||||
}
|
||||
|
||||
/** Get memory usage of list of auth addr */
|
||||
static size_t
|
||||
auth_addrs_get_mem(struct auth_addr* list)
|
||||
{
|
||||
size_t m = 0;
|
||||
struct auth_addr* a;
|
||||
for(a = list; a; a = a->next) {
|
||||
m += sizeof(*a);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
/** Get memory usage of list of primaries for auth xfer */
|
||||
static size_t
|
||||
auth_primaries_get_mem(struct auth_master* list)
|
||||
{
|
||||
size_t m = 0;
|
||||
struct auth_master* n;
|
||||
for(n = list; n; n = n->next) {
|
||||
m += sizeof(*n);
|
||||
m += auth_addrs_get_mem(n->list);
|
||||
if(n->host)
|
||||
m += strlen(n->host)+1;
|
||||
if(n->file)
|
||||
m += strlen(n->file)+1;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
/** Get memory usage or list of auth chunks */
|
||||
static size_t
|
||||
auth_chunks_get_mem(struct auth_chunk* list)
|
||||
{
|
||||
size_t m = 0;
|
||||
struct auth_chunk* chunk;
|
||||
for(chunk = list; chunk; chunk = chunk->next) {
|
||||
m += sizeof(*chunk) + chunk->len;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
/** Get memory usage of auth xfer */
|
||||
static size_t
|
||||
auth_xfer_get_mem(struct auth_xfer* xfr)
|
||||
{
|
||||
size_t m = sizeof(*xfr) + xfr->namelen;
|
||||
|
||||
/* auth_nextprobe */
|
||||
m += comm_timer_get_mem(xfr->task_nextprobe->timer);
|
||||
|
||||
/* auth_probe */
|
||||
m += auth_primaries_get_mem(xfr->task_probe->masters);
|
||||
m += comm_point_get_mem(xfr->task_probe->cp);
|
||||
m += comm_timer_get_mem(xfr->task_probe->timer);
|
||||
|
||||
/* auth_transfer */
|
||||
m += auth_chunks_get_mem(xfr->task_transfer->chunks_first);
|
||||
m += auth_primaries_get_mem(xfr->task_transfer->masters);
|
||||
m += comm_point_get_mem(xfr->task_transfer->cp);
|
||||
m += comm_timer_get_mem(xfr->task_transfer->timer);
|
||||
|
||||
/* allow_notify_list */
|
||||
m += auth_primaries_get_mem(xfr->allow_notify_list);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
/** Get memory usage of auth zones ztree */
|
||||
static size_t
|
||||
az_ztree_get_mem(struct auth_zones* az)
|
||||
{
|
||||
size_t m = 0;
|
||||
struct auth_zone* z;
|
||||
RBTREE_FOR(z, struct auth_zone*, &az->ztree) {
|
||||
lock_rw_rdlock(&z->lock);
|
||||
m += auth_zone_get_mem(z);
|
||||
lock_rw_unlock(&z->lock);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
/** Get memory usage of auth zones xtree */
|
||||
static size_t
|
||||
az_xtree_get_mem(struct auth_zones* az)
|
||||
{
|
||||
size_t m = 0;
|
||||
struct auth_xfer* xfr;
|
||||
RBTREE_FOR(xfr, struct auth_xfer*, &az->xtree) {
|
||||
lock_basic_lock(&xfr->lock);
|
||||
m += auth_xfer_get_mem(xfr);
|
||||
lock_basic_unlock(&xfr->lock);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
size_t auth_zones_get_mem(struct auth_zones* zones)
|
||||
{
|
||||
size_t m;
|
||||
if(!zones) return 0;
|
||||
m = sizeof(*zones);
|
||||
lock_rw_rdlock(&zones->rpz_lock);
|
||||
lock_rw_rdlock(&zones->lock);
|
||||
m += az_ztree_get_mem(zones);
|
||||
m += az_xtree_get_mem(zones);
|
||||
lock_rw_unlock(&zones->lock);
|
||||
lock_rw_unlock(&zones->rpz_lock);
|
||||
return m;
|
||||
}
|
||||
|
||||
void xfr_disown_tasks(struct auth_xfer* xfr, struct worker* worker)
|
||||
{
|
||||
if(xfr->task_nextprobe->worker == worker) {
|
||||
xfr_nextprobe_disown(xfr);
|
||||
}
|
||||
if(xfr->task_probe->worker == worker) {
|
||||
xfr_probe_disown(xfr);
|
||||
}
|
||||
if(xfr->task_transfer->worker == worker) {
|
||||
xfr_transfer_disown(xfr);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,7 +70,8 @@ struct auth_chunk;
|
|||
* Authoritative zones, shared.
|
||||
*/
|
||||
struct auth_zones {
|
||||
/** lock on the authzone trees */
|
||||
/** lock on the authzone trees. It is locked after views, respip,
|
||||
* local_zones and before fwds and stubs. */
|
||||
lock_rw_type lock;
|
||||
/** rbtree of struct auth_zone */
|
||||
rbtree_type ztree;
|
||||
|
|
@ -207,7 +208,9 @@ struct auth_xfer {
|
|||
* one of the tasks.
|
||||
* Once it has the task assigned to it, the worker can access the
|
||||
* other elements of the task structure without a lock, because that
|
||||
* is necessary for the eventloop and callbacks from that. */
|
||||
* is necessary for the eventloop and callbacks from that.
|
||||
* The auth_zone->lock is locked before this lock.
|
||||
*/
|
||||
lock_basic_type lock;
|
||||
|
||||
/** zone name, in uncompressed wireformat */
|
||||
|
|
@ -783,4 +786,33 @@ void auth_zonemd_dnskey_lookup_callback(void* arg, int rcode,
|
|||
void auth_zones_pickup_zonemd_verify(struct auth_zones* az,
|
||||
struct module_env* env);
|
||||
|
||||
/** Get memory usage for auth zones. The routine locks and unlocks
|
||||
* for reading. */
|
||||
size_t auth_zones_get_mem(struct auth_zones* zones);
|
||||
|
||||
/**
|
||||
* Initial pick up of the auth zone nextprobe timeout and that turns
|
||||
* into further zone transfer work, if any. Also sets the lease time.
|
||||
* @param x: xfer structure, locked by caller.
|
||||
* @param env: environment of the worker that picks up the task.
|
||||
*/
|
||||
void auth_xfer_pickup_initial_zone(struct auth_xfer* x,
|
||||
struct module_env* env);
|
||||
|
||||
/**
|
||||
* Delete auth xfer structure
|
||||
* @param xfr: delete this xfer and its tasks.
|
||||
*/
|
||||
void auth_xfer_delete(struct auth_xfer* xfr);
|
||||
|
||||
/**
|
||||
* Disown tasks from the xfr that belong to this worker.
|
||||
* Only tasks for the worker in question, the comm point and timer
|
||||
* delete functions need to run in the thread of that worker to be
|
||||
* able to delete the callback from the event base.
|
||||
* @param xfr: xfr structure
|
||||
* @param worker: the worker for which to stop tasks.
|
||||
*/
|
||||
void xfr_disown_tasks(struct auth_xfer* xfr, struct worker* worker);
|
||||
|
||||
#endif /* SERVICES_AUTHZONE_H */
|
||||
|
|
|
|||
94
services/cache/infra.c
vendored
94
services/cache/infra.c
vendored
|
|
@ -161,7 +161,7 @@ rate_deldatafunc(void* d, void* ATTR_UNUSED(arg))
|
|||
|
||||
/** find or create element in domainlimit tree */
|
||||
static struct domain_limit_data* domain_limit_findcreate(
|
||||
struct infra_cache* infra, char* name)
|
||||
struct rbtree_type* domain_limits, char* name)
|
||||
{
|
||||
uint8_t* nm;
|
||||
int labs;
|
||||
|
|
@ -177,8 +177,8 @@ static struct domain_limit_data* domain_limit_findcreate(
|
|||
labs = dname_count_labels(nm);
|
||||
|
||||
/* can we find it? */
|
||||
d = (struct domain_limit_data*)name_tree_find(&infra->domain_limits,
|
||||
nm, nmlen, labs, LDNS_RR_CLASS_IN);
|
||||
d = (struct domain_limit_data*)name_tree_find(domain_limits, nm,
|
||||
nmlen, labs, LDNS_RR_CLASS_IN);
|
||||
if(d) {
|
||||
free(nm);
|
||||
return d;
|
||||
|
|
@ -197,8 +197,8 @@ static struct domain_limit_data* domain_limit_findcreate(
|
|||
d->node.dclass = LDNS_RR_CLASS_IN;
|
||||
d->lim = -1;
|
||||
d->below = -1;
|
||||
if(!name_tree_insert(&infra->domain_limits, &d->node, nm, nmlen,
|
||||
labs, LDNS_RR_CLASS_IN)) {
|
||||
if(!name_tree_insert(domain_limits, &d->node, nm, nmlen, labs,
|
||||
LDNS_RR_CLASS_IN)) {
|
||||
log_err("duplicate element in domainlimit tree");
|
||||
free(nm);
|
||||
free(d);
|
||||
|
|
@ -208,19 +208,19 @@ static struct domain_limit_data* domain_limit_findcreate(
|
|||
}
|
||||
|
||||
/** insert rate limit configuration into lookup tree */
|
||||
static int infra_ratelimit_cfg_insert(struct infra_cache* infra,
|
||||
static int infra_ratelimit_cfg_insert(struct rbtree_type* domain_limits,
|
||||
struct config_file* cfg)
|
||||
{
|
||||
struct config_str2list* p;
|
||||
struct domain_limit_data* d;
|
||||
for(p = cfg->ratelimit_for_domain; p; p = p->next) {
|
||||
d = domain_limit_findcreate(infra, p->str);
|
||||
d = domain_limit_findcreate(domain_limits, p->str);
|
||||
if(!d)
|
||||
return 0;
|
||||
d->lim = atoi(p->str2);
|
||||
}
|
||||
for(p = cfg->ratelimit_below_domain; p; p = p->next) {
|
||||
d = domain_limit_findcreate(infra, p->str);
|
||||
d = domain_limit_findcreate(domain_limits, p->str);
|
||||
if(!d)
|
||||
return 0;
|
||||
d->below = atoi(p->str2);
|
||||
|
|
@ -228,24 +228,21 @@ static int infra_ratelimit_cfg_insert(struct infra_cache* infra,
|
|||
return 1;
|
||||
}
|
||||
|
||||
/** setup domain limits tree (0 on failure) */
|
||||
static int
|
||||
setup_domain_limits(struct infra_cache* infra, struct config_file* cfg)
|
||||
int
|
||||
setup_domain_limits(struct rbtree_type* domain_limits, struct config_file* cfg)
|
||||
{
|
||||
name_tree_init(&infra->domain_limits);
|
||||
if(!infra_ratelimit_cfg_insert(infra, cfg)) {
|
||||
name_tree_init(domain_limits);
|
||||
if(!infra_ratelimit_cfg_insert(domain_limits, cfg)) {
|
||||
return 0;
|
||||
}
|
||||
name_tree_init_parents(&infra->domain_limits);
|
||||
name_tree_init_parents(domain_limits);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** find or create element in wait limit netblock tree */
|
||||
static struct wait_limit_netblock_info*
|
||||
wait_limit_netblock_findcreate(struct infra_cache* infra, char* str,
|
||||
int cookie)
|
||||
wait_limit_netblock_findcreate(struct rbtree_type* tree, char* str)
|
||||
{
|
||||
rbtree_type* tree;
|
||||
struct sockaddr_storage addr;
|
||||
int net;
|
||||
socklen_t addrlen;
|
||||
|
|
@ -257,10 +254,6 @@ wait_limit_netblock_findcreate(struct infra_cache* infra, char* str,
|
|||
}
|
||||
|
||||
/* can we find it? */
|
||||
if(cookie)
|
||||
tree = &infra->wait_limits_cookie_netblock;
|
||||
else
|
||||
tree = &infra->wait_limits_netblock;
|
||||
d = (struct wait_limit_netblock_info*)addr_tree_find(tree, &addr,
|
||||
addrlen, net);
|
||||
if(d)
|
||||
|
|
@ -282,19 +275,21 @@ wait_limit_netblock_findcreate(struct infra_cache* infra, char* str,
|
|||
|
||||
/** insert wait limit information into lookup tree */
|
||||
static int
|
||||
infra_wait_limit_netblock_insert(struct infra_cache* infra,
|
||||
struct config_file* cfg)
|
||||
infra_wait_limit_netblock_insert(rbtree_type* wait_limits_netblock,
|
||||
rbtree_type* wait_limits_cookie_netblock, struct config_file* cfg)
|
||||
{
|
||||
struct config_str2list* p;
|
||||
struct wait_limit_netblock_info* d;
|
||||
for(p = cfg->wait_limit_netblock; p; p = p->next) {
|
||||
d = wait_limit_netblock_findcreate(infra, p->str, 0);
|
||||
d = wait_limit_netblock_findcreate(wait_limits_netblock,
|
||||
p->str);
|
||||
if(!d)
|
||||
return 0;
|
||||
d->limit = atoi(p->str2);
|
||||
}
|
||||
for(p = cfg->wait_limit_cookie_netblock; p; p = p->next) {
|
||||
d = wait_limit_netblock_findcreate(infra, p->str, 1);
|
||||
d = wait_limit_netblock_findcreate(wait_limits_cookie_netblock,
|
||||
p->str);
|
||||
if(!d)
|
||||
return 0;
|
||||
d->limit = atoi(p->str2);
|
||||
|
|
@ -302,16 +297,17 @@ infra_wait_limit_netblock_insert(struct infra_cache* infra,
|
|||
return 1;
|
||||
}
|
||||
|
||||
/** setup wait limits tree (0 on failure) */
|
||||
static int
|
||||
setup_wait_limits(struct infra_cache* infra, struct config_file* cfg)
|
||||
int
|
||||
setup_wait_limits(rbtree_type* wait_limits_netblock,
|
||||
rbtree_type* wait_limits_cookie_netblock, struct config_file* cfg)
|
||||
{
|
||||
addr_tree_init(&infra->wait_limits_netblock);
|
||||
addr_tree_init(&infra->wait_limits_cookie_netblock);
|
||||
if(!infra_wait_limit_netblock_insert(infra, cfg))
|
||||
addr_tree_init(wait_limits_netblock);
|
||||
addr_tree_init(wait_limits_cookie_netblock);
|
||||
if(!infra_wait_limit_netblock_insert(wait_limits_netblock,
|
||||
wait_limits_cookie_netblock, cfg))
|
||||
return 0;
|
||||
addr_tree_init_parents(&infra->wait_limits_netblock);
|
||||
addr_tree_init_parents(&infra->wait_limits_cookie_netblock);
|
||||
addr_tree_init_parents(wait_limits_netblock);
|
||||
addr_tree_init_parents(wait_limits_cookie_netblock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -344,11 +340,12 @@ infra_create(struct config_file* cfg)
|
|||
return NULL;
|
||||
}
|
||||
/* insert config data into ratelimits */
|
||||
if(!setup_domain_limits(infra, cfg)) {
|
||||
if(!setup_domain_limits(&infra->domain_limits, cfg)) {
|
||||
infra_delete(infra);
|
||||
return NULL;
|
||||
}
|
||||
if(!setup_wait_limits(infra, cfg)) {
|
||||
if(!setup_wait_limits(&infra->wait_limits_netblock,
|
||||
&infra->wait_limits_cookie_netblock, cfg)) {
|
||||
infra_delete(infra);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -373,12 +370,29 @@ static void domain_limit_free(rbnode_type* n, void* ATTR_UNUSED(arg))
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
domain_limits_free(struct rbtree_type* domain_limits)
|
||||
{
|
||||
if(!domain_limits)
|
||||
return;
|
||||
traverse_postorder(domain_limits, domain_limit_free, NULL);
|
||||
}
|
||||
|
||||
/** delete wait_limit_netblock_info entries */
|
||||
static void wait_limit_netblock_del(rbnode_type* n, void* ATTR_UNUSED(arg))
|
||||
{
|
||||
free(n);
|
||||
}
|
||||
|
||||
void
|
||||
wait_limits_free(struct rbtree_type* wait_limits_tree)
|
||||
{
|
||||
if(!wait_limits_tree)
|
||||
return;
|
||||
traverse_postorder(wait_limits_tree, wait_limit_netblock_del,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
infra_delete(struct infra_cache* infra)
|
||||
{
|
||||
|
|
@ -386,12 +400,10 @@ infra_delete(struct infra_cache* infra)
|
|||
return;
|
||||
slabhash_delete(infra->hosts);
|
||||
slabhash_delete(infra->domain_rates);
|
||||
traverse_postorder(&infra->domain_limits, domain_limit_free, NULL);
|
||||
domain_limits_free(&infra->domain_limits);
|
||||
slabhash_delete(infra->client_ip_rates);
|
||||
traverse_postorder(&infra->wait_limits_netblock,
|
||||
wait_limit_netblock_del, NULL);
|
||||
traverse_postorder(&infra->wait_limits_cookie_netblock,
|
||||
wait_limit_netblock_del, NULL);
|
||||
wait_limits_free(&infra->wait_limits_netblock);
|
||||
wait_limits_free(&infra->wait_limits_cookie_netblock);
|
||||
free(infra);
|
||||
}
|
||||
|
||||
|
|
@ -422,7 +434,7 @@ infra_adjust(struct infra_cache* infra, struct config_file* cfg)
|
|||
/* reapply domain limits */
|
||||
traverse_postorder(&infra->domain_limits, domain_limit_free,
|
||||
NULL);
|
||||
if(!setup_domain_limits(infra, cfg)) {
|
||||
if(!setup_domain_limits(&infra->domain_limits, cfg)) {
|
||||
infra_delete(infra);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
15
services/cache/infra.h
vendored
15
services/cache/infra.h
vendored
|
|
@ -515,6 +515,21 @@ void infra_wait_limit_inc(struct infra_cache* infra, struct comm_reply* rep,
|
|||
void infra_wait_limit_dec(struct infra_cache* infra, struct comm_reply* rep,
|
||||
struct config_file* cfg);
|
||||
|
||||
/** setup wait limits tree (0 on failure) */
|
||||
int setup_wait_limits(struct rbtree_type* wait_limits_netblock,
|
||||
struct rbtree_type* wait_limits_cookie_netblock,
|
||||
struct config_file* cfg);
|
||||
|
||||
/** Free the wait limits and wait cookie limits tree. */
|
||||
void wait_limits_free(struct rbtree_type* wait_limits_tree);
|
||||
|
||||
/** setup domain limits tree (0 on failure) */
|
||||
int setup_domain_limits(struct rbtree_type* domain_limits,
|
||||
struct config_file* cfg);
|
||||
|
||||
/** Free the domain limits tree. */
|
||||
void domain_limits_free(struct rbtree_type* domain_limits);
|
||||
|
||||
/** exported for unit test */
|
||||
int still_useful_timeout();
|
||||
|
||||
|
|
|
|||
|
|
@ -2220,3 +2220,35 @@ void local_zones_del_data(struct local_zones* zones,
|
|||
|
||||
lock_rw_unlock(&z->lock);
|
||||
}
|
||||
|
||||
/** Get memory usage for local_zone */
|
||||
static size_t
|
||||
local_zone_get_mem(struct local_zone* z)
|
||||
{
|
||||
size_t m = sizeof(*z);
|
||||
lock_rw_rdlock(&z->lock);
|
||||
m += z->namelen + z->taglen + regional_get_mem(z->region);
|
||||
lock_rw_unlock(&z->lock);
|
||||
return m;
|
||||
}
|
||||
|
||||
size_t local_zones_get_mem(struct local_zones* zones)
|
||||
{
|
||||
struct local_zone* z;
|
||||
size_t m;
|
||||
if(!zones) return 0;
|
||||
m = sizeof(*zones);
|
||||
lock_rw_rdlock(&zones->lock);
|
||||
RBTREE_FOR(z, struct local_zone*, &zones->ztree) {
|
||||
m += local_zone_get_mem(z);
|
||||
}
|
||||
lock_rw_unlock(&zones->lock);
|
||||
return m;
|
||||
}
|
||||
|
||||
void local_zones_swap_tree(struct local_zones* zones, struct local_zones* data)
|
||||
{
|
||||
rbtree_type oldtree = zones->ztree;
|
||||
zones->ztree = data->ztree;
|
||||
data->ztree = oldtree;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -642,6 +642,20 @@ local_zone_enter_rr(struct local_zone* z, uint8_t* nm, size_t nmlen,
|
|||
struct local_data*
|
||||
local_zone_find_data(struct local_zone* z, uint8_t* nm, size_t nmlen, int nmlabs);
|
||||
|
||||
/** Get memory usage for local_zones tree. The routine locks and unlocks
|
||||
* the tree for reading. */
|
||||
size_t local_zones_get_mem(struct local_zones* zones);
|
||||
|
||||
/**
|
||||
* Swap internal tree with preallocated entries. Caller should manage
|
||||
* the locks.
|
||||
* @param zones: the local zones structure.
|
||||
* @param data: the data structure used to take elements from. This contains
|
||||
* the old elements on return.
|
||||
*/
|
||||
void local_zones_swap_tree(struct local_zones* zones,
|
||||
struct local_zones* data);
|
||||
|
||||
/** Enter a new zone; returns with WRlock
|
||||
* Made public for unit testing
|
||||
* @param zones: the local zones tree
|
||||
|
|
|
|||
144
services/mesh.c
144
services/mesh.c
|
|
@ -77,6 +77,20 @@
|
|||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
/** Compare two views by name */
|
||||
static int
|
||||
view_name_compare(const char* v_a, const char* v_b)
|
||||
{
|
||||
if(v_a == NULL && v_b == NULL)
|
||||
return 0;
|
||||
/* The NULL name is smaller than if the name is set. */
|
||||
if(v_a == NULL)
|
||||
return -1;
|
||||
if(v_b == NULL)
|
||||
return 1;
|
||||
return strcmp(v_a, v_b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two response-ip client info entries for the purpose of mesh state
|
||||
* compare. It returns 0 if ci_a and ci_b are considered equal; otherwise
|
||||
|
|
@ -132,12 +146,14 @@ client_info_compare(const struct respip_client_info* ci_a,
|
|||
}
|
||||
if(ci_a->tag_datas != ci_b->tag_datas)
|
||||
return ci_a->tag_datas < ci_b->tag_datas ? -1 : 1;
|
||||
if(ci_a->view != ci_b->view)
|
||||
return ci_a->view < ci_b->view ? -1 : 1;
|
||||
/* For the unbound daemon these should be non-NULL and identical,
|
||||
* but we check that just in case. */
|
||||
if(ci_a->respip_set != ci_b->respip_set)
|
||||
return ci_a->respip_set < ci_b->respip_set ? -1 : 1;
|
||||
if(ci_a->view || ci_a->view_name || ci_b->view || ci_b->view_name) {
|
||||
/* Compare the views by name. */
|
||||
cmp = view_name_compare(
|
||||
(ci_a->view?ci_a->view->name:ci_a->view_name),
|
||||
(ci_b->view?ci_b->view->name:ci_b->view_name));
|
||||
if(cmp != 0)
|
||||
return cmp;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -870,6 +886,72 @@ void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e,
|
|||
mesh_run(mesh, e->qstate->mesh_info, event, e);
|
||||
}
|
||||
|
||||
/** copy strlist to region */
|
||||
static struct config_strlist*
|
||||
cfg_region_strlist_copy(struct regional* region, struct config_strlist* list)
|
||||
{
|
||||
struct config_strlist* result = NULL, *last = NULL, *s = list;
|
||||
while(s) {
|
||||
struct config_strlist* n = regional_alloc_zero(region,
|
||||
sizeof(*n));
|
||||
if(!n)
|
||||
return NULL;
|
||||
n->str = regional_strdup(region, s->str);
|
||||
if(!n->str)
|
||||
return NULL;
|
||||
if(last)
|
||||
last->next = n;
|
||||
else result = n;
|
||||
last = n;
|
||||
s = s->next;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Copy the client info to the query region. */
|
||||
static struct respip_client_info*
|
||||
mesh_copy_client_info(struct regional* region, struct respip_client_info* cinfo)
|
||||
{
|
||||
size_t i;
|
||||
struct respip_client_info* client_info;
|
||||
client_info = regional_alloc_init(region, cinfo, sizeof(*cinfo));
|
||||
if(!client_info)
|
||||
return NULL;
|
||||
/* Copy the client_info so that if the configuration changes,
|
||||
* then the data stays valid. */
|
||||
client_info->taglist = regional_alloc_init(region, cinfo->taglist,
|
||||
cinfo->taglen);
|
||||
if(!client_info->taglist)
|
||||
return NULL;
|
||||
client_info->tag_actions = regional_alloc_init(region, cinfo->tag_actions,
|
||||
cinfo->tag_actions_size);
|
||||
if(!client_info->tag_actions)
|
||||
return NULL;
|
||||
client_info->tag_datas = regional_alloc_zero(region,
|
||||
sizeof(struct config_strlist*)*cinfo->tag_datas_size);
|
||||
if(!client_info->tag_datas)
|
||||
return NULL;
|
||||
for(i=0; i<cinfo->tag_datas_size; i++) {
|
||||
if(cinfo->tag_datas[i]) {
|
||||
client_info->tag_datas[i] = cfg_region_strlist_copy(
|
||||
region, cinfo->tag_datas[i]);
|
||||
if(!client_info->tag_datas[i])
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if(cinfo->view) {
|
||||
/* Do not copy the view pointer but store a name instead.
|
||||
* The name is looked up later when done, this means that
|
||||
* the view tree can be changed, by reloads. */
|
||||
client_info->view = NULL;
|
||||
client_info->view_name = regional_strdup(region,
|
||||
cinfo->view->name);
|
||||
if(!client_info->view_name)
|
||||
return NULL;
|
||||
}
|
||||
return client_info;
|
||||
}
|
||||
|
||||
struct mesh_state*
|
||||
mesh_state_create(struct module_env* env, struct query_info* qinfo,
|
||||
struct respip_client_info* cinfo, uint16_t qflags, int prime,
|
||||
|
|
@ -910,8 +992,7 @@ mesh_state_create(struct module_env* env, struct query_info* qinfo,
|
|||
return NULL;
|
||||
}
|
||||
if(cinfo) {
|
||||
mstate->s.client_info = regional_alloc_init(region, cinfo,
|
||||
sizeof(*cinfo));
|
||||
mstate->s.client_info = mesh_copy_client_info(region, cinfo);
|
||||
if(!mstate->s.client_info) {
|
||||
alloc_reg_release(env->alloc, region);
|
||||
return NULL;
|
||||
|
|
@ -1686,6 +1767,25 @@ struct mesh_state* mesh_area_find(struct mesh_area* mesh,
|
|||
return result;
|
||||
}
|
||||
|
||||
/** remove mesh state callback */
|
||||
int mesh_state_del_cb(struct mesh_state* s, mesh_cb_func_type cb, void* cb_arg)
|
||||
{
|
||||
struct mesh_cb* r, *prev = NULL;
|
||||
r = s->cb_list;
|
||||
while(r) {
|
||||
if(r->cb == cb && r->cb_arg == cb_arg) {
|
||||
/* Delete this entry. */
|
||||
/* It was allocated in the s.region, so no free. */
|
||||
if(prev) prev->next = r->next;
|
||||
else s->cb_list = r->next;
|
||||
return 1;
|
||||
}
|
||||
prev = r;
|
||||
r = r->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mesh_state_add_cb(struct mesh_state* s, struct edns_data* edns,
|
||||
sldns_buffer* buf, mesh_cb_func_type cb, void* cb_arg,
|
||||
uint16_t qid, uint16_t qflags)
|
||||
|
|
@ -2151,7 +2251,8 @@ apply_respip_action(struct module_qstate* qstate,
|
|||
return 1;
|
||||
|
||||
if(!respip_rewrite_reply(qinfo, cinfo, rep, encode_repp, actinfo,
|
||||
alias_rrset, 0, qstate->region, az, NULL))
|
||||
alias_rrset, 0, qstate->region, az, NULL, qstate->env->views,
|
||||
qstate->env->respip_set))
|
||||
return 0;
|
||||
|
||||
/* xxx_deny actions mean dropping the reply, unless the original reply
|
||||
|
|
@ -2226,7 +2327,8 @@ mesh_serve_expired_callback(void* arg)
|
|||
} else if(partial_rep &&
|
||||
!respip_merge_cname(partial_rep, &qstate->qinfo, msg->rep,
|
||||
qstate->client_info, must_validate, &encode_rep, qstate->region,
|
||||
qstate->env->auth_zones)) {
|
||||
qstate->env->auth_zones, qstate->env->views,
|
||||
qstate->env->respip_set)) {
|
||||
return;
|
||||
}
|
||||
if(!encode_rep || alias_rrset) {
|
||||
|
|
@ -2380,3 +2482,25 @@ int mesh_jostle_exceeded(struct mesh_area* mesh)
|
|||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void mesh_remove_callback(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
uint16_t qflags, mesh_cb_func_type cb, void* cb_arg)
|
||||
{
|
||||
struct mesh_state* s = NULL;
|
||||
s = mesh_area_find(mesh, NULL, qinfo, qflags&(BIT_RD|BIT_CD), 0, 0);
|
||||
if(!s) return;
|
||||
if(!mesh_state_del_cb(s, cb, cb_arg)) return;
|
||||
|
||||
/* It was in the list and removed. */
|
||||
log_assert(mesh->num_reply_addrs > 0);
|
||||
mesh->num_reply_addrs--;
|
||||
if(!s->reply_list && !s->cb_list) {
|
||||
/* was a reply state, not anymore */
|
||||
log_assert(mesh->num_reply_states > 0);
|
||||
mesh->num_reply_states--;
|
||||
}
|
||||
if(!s->reply_list && !s->cb_list &&
|
||||
s->super_set.count == 0) {
|
||||
mesh->num_detached_states++;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -706,4 +706,17 @@ int mesh_jostle_exceeded(struct mesh_area* mesh);
|
|||
*/
|
||||
void mesh_respond_serve_expired(struct mesh_state* mstate);
|
||||
|
||||
/**
|
||||
* Remove callback from mesh. Removes the callback from the state.
|
||||
* The state itself is left to run. Searches for the pointer values.
|
||||
*
|
||||
* @param mesh: the mesh.
|
||||
* @param qinfo: query from client.
|
||||
* @param qflags: flags from client query.
|
||||
* @param cb: callback function.
|
||||
* @param cb_arg: callback user arg.
|
||||
*/
|
||||
void mesh_remove_callback(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
uint16_t qflags, mesh_cb_func_type cb, void* cb_arg);
|
||||
|
||||
#endif /* SERVICES_MESH_H */
|
||||
|
|
|
|||
|
|
@ -2792,3 +2792,31 @@ void rpz_disable(struct rpz* r)
|
|||
return;
|
||||
r->disabled = 1;
|
||||
}
|
||||
|
||||
/** Get memory usage for clientip_synthesized_rrset. Ignores memory usage
|
||||
* of locks. */
|
||||
static size_t
|
||||
rpz_clientip_synthesized_set_get_mem(struct clientip_synthesized_rrset* set)
|
||||
{
|
||||
size_t m = sizeof(*set);
|
||||
lock_rw_rdlock(&set->lock);
|
||||
m += regional_get_mem(set->region);
|
||||
lock_rw_unlock(&set->lock);
|
||||
return m;
|
||||
}
|
||||
|
||||
size_t rpz_get_mem(struct rpz* r)
|
||||
{
|
||||
size_t m = sizeof(*r);
|
||||
if(r->taglist)
|
||||
m += r->taglistlen;
|
||||
if(r->log_name)
|
||||
m += strlen(r->log_name) + 1;
|
||||
m += regional_get_mem(r->region);
|
||||
m += local_zones_get_mem(r->local_zones);
|
||||
m += local_zones_get_mem(r->nsdname_zones);
|
||||
m += respip_set_get_mem(r->respip_set);
|
||||
m += rpz_clientip_synthesized_set_get_mem(r->client_set);
|
||||
m += rpz_clientip_synthesized_set_get_mem(r->ns_set);
|
||||
return m;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -269,4 +269,11 @@ void rpz_enable(struct rpz* r);
|
|||
*/
|
||||
void rpz_disable(struct rpz* r);
|
||||
|
||||
/**
|
||||
* Get memory usage of rpz. Caller must manage locks.
|
||||
* @param r: RPZ struct.
|
||||
* @return memory usage.
|
||||
*/
|
||||
size_t rpz_get_mem(struct rpz* r);
|
||||
|
||||
#endif /* SERVICES_RPZ_H */
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@
|
|||
#include "services/view.h"
|
||||
#include "services/localzone.h"
|
||||
#include "util/config_file.h"
|
||||
#include "respip/respip.h"
|
||||
|
||||
int
|
||||
view_cmp(const void* v1, const void* v2)
|
||||
|
|
@ -66,11 +67,6 @@ views_create(void)
|
|||
return v;
|
||||
}
|
||||
|
||||
/* \noop (ignore this comment for doxygen)
|
||||
* This prototype is defined in in respip.h, but we want to avoid
|
||||
* unnecessary dependencies */
|
||||
void respip_set_delete(struct respip_set *set);
|
||||
|
||||
void
|
||||
view_delete(struct view* v)
|
||||
{
|
||||
|
|
@ -247,3 +243,38 @@ void views_print(struct views* v)
|
|||
/* TODO implement print */
|
||||
(void)v;
|
||||
}
|
||||
|
||||
size_t views_get_mem(struct views* vs)
|
||||
{
|
||||
struct view* v;
|
||||
size_t m;
|
||||
if(!vs) return 0;
|
||||
m = sizeof(struct views);
|
||||
lock_rw_rdlock(&vs->lock);
|
||||
RBTREE_FOR(v, struct view*, &vs->vtree) {
|
||||
m += view_get_mem(v);
|
||||
}
|
||||
lock_rw_unlock(&vs->lock);
|
||||
return m;
|
||||
}
|
||||
|
||||
size_t view_get_mem(struct view* v)
|
||||
{
|
||||
size_t m = sizeof(*v);
|
||||
lock_rw_rdlock(&v->lock);
|
||||
m += getmem_str(v->name);
|
||||
m += local_zones_get_mem(v->local_zones);
|
||||
m += respip_set_get_mem(v->respip_set);
|
||||
lock_rw_unlock(&v->lock);
|
||||
return m;
|
||||
}
|
||||
|
||||
void views_swap_tree(struct views* vs, struct views* data)
|
||||
{
|
||||
rbnode_type* oldroot = vs->vtree.root;
|
||||
size_t oldcount = vs->vtree.count;
|
||||
vs->vtree.root = data->vtree.root;
|
||||
vs->vtree.count = data->vtree.count;
|
||||
data->vtree.root = oldroot;
|
||||
data->vtree.count = oldcount;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,8 @@ struct respip_set;
|
|||
* Views storage, shared.
|
||||
*/
|
||||
struct views {
|
||||
/** lock on the view tree */
|
||||
/** lock on the view tree. When locking order, the views lock
|
||||
* is before the forwards,hints,anchors,localzones lock. */
|
||||
lock_rw_type lock;
|
||||
/** rbtree of struct view */
|
||||
rbtree_type vtree;
|
||||
|
|
@ -135,4 +136,27 @@ void views_print(struct views* v);
|
|||
*/
|
||||
struct view* views_find_view(struct views* vs, const char* name, int write);
|
||||
|
||||
/**
|
||||
* Calculate memory usage of views.
|
||||
* @param vs: the views tree. The routine locks and unlocks the structure
|
||||
* for reading.
|
||||
* @return memory in bytes.
|
||||
*/
|
||||
size_t views_get_mem(struct views* vs);
|
||||
|
||||
/**
|
||||
* Calculate memory usage of view.
|
||||
* @param v: the view. The routine locks and unlocks the structure for reading.
|
||||
* @return memory in bytes.
|
||||
*/
|
||||
size_t view_get_mem(struct view* v);
|
||||
|
||||
/**
|
||||
* Swap internal tree with preallocated entries. Caller should manage
|
||||
* the locks.
|
||||
* @param vs: views tree
|
||||
* @param data: preallocated information.
|
||||
*/
|
||||
void views_swap_tree(struct views* vs, struct views* data);
|
||||
|
||||
#endif /* SERVICES_VIEW_H */
|
||||
|
|
|
|||
|
|
@ -109,6 +109,16 @@ usage(void)
|
|||
printf(" That means the caches sizes and\n");
|
||||
printf(" the number of threads must not\n");
|
||||
printf(" change between reloads.\n");
|
||||
printf(" fast_reload [+dpv] reloads the server but only briefly stops\n");
|
||||
printf(" server processing, keeps cache, and changes\n");
|
||||
printf(" most options; check unbound-control(8).\n");
|
||||
printf(" +d drops running queries to keep consistency\n");
|
||||
printf(" on changed options while reloading.\n");
|
||||
printf(" +p does not pause threads for even faster\n");
|
||||
printf(" reload but less options are supported\n");
|
||||
printf(" ; check unbound-control(8).\n");
|
||||
printf(" +v verbose output, it will include duration needed.\n");
|
||||
printf(" +vv more verbose output, it will include memory needed.\n");
|
||||
printf(" stats print statistics\n");
|
||||
printf(" stats_noreset peek at statistics\n");
|
||||
#ifdef HAVE_SHMGET
|
||||
|
|
|
|||
|
|
@ -256,6 +256,20 @@ void dtio_mainfdcallback(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
|
|||
}
|
||||
#endif
|
||||
|
||||
void fast_reload_service_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
|
||||
void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
int fast_reload_client_callback(struct comm_point* ATTR_UNUSED(c),
|
||||
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
|
||||
struct comm_reply* ATTR_UNUSED(repinfo))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_NGTCP2
|
||||
void doq_client_event_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
|
||||
void* ATTR_UNUSED(arg))
|
||||
|
|
|
|||
|
|
@ -64,6 +64,9 @@ static int key_deleted = 0;
|
|||
static ub_thread_key_type thr_debug_key;
|
||||
/** the list of threads, so all threads can be examined. NULL if unused. */
|
||||
static struct thr_check* thread_infos[THRDEBUG_MAX_THREADS];
|
||||
/** stored maximum lock number for threads, when a thread is restarted the
|
||||
* number is kept track of, because the new locks get new id numbers. */
|
||||
static int thread_lockcount[THRDEBUG_MAX_THREADS];
|
||||
/** do we check locking order */
|
||||
int check_locking_order = 1;
|
||||
/** the pid of this runset, reasonably unique. */
|
||||
|
|
@ -698,10 +701,20 @@ open_lockorder(struct thr_check* thr)
|
|||
char buf[24];
|
||||
time_t t;
|
||||
snprintf(buf, sizeof(buf), "%s.%d", output_name, thr->num);
|
||||
thr->order_info = fopen(buf, "w");
|
||||
if(!thr->order_info)
|
||||
fatal_exit("could not open %s: %s", buf, strerror(errno));
|
||||
thr->locks_created = 0;
|
||||
thr->locks_created = thread_lockcount[thr->num];
|
||||
if(thr->locks_created == 0) {
|
||||
thr->order_info = fopen(buf, "w");
|
||||
if(!thr->order_info)
|
||||
fatal_exit("could not open %s: %s", buf, strerror(errno));
|
||||
} else {
|
||||
/* There is already a file to append on with the previous
|
||||
* thread information. */
|
||||
thr->order_info = fopen(buf, "a");
|
||||
if(!thr->order_info)
|
||||
fatal_exit("could not open for append %s: %s", buf, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
t = time(NULL);
|
||||
/* write: <time_stamp> <runpid> <thread_num> */
|
||||
if(fwrite(&t, sizeof(t), 1, thr->order_info) != 1 ||
|
||||
|
|
@ -728,6 +741,7 @@ static void* checklock_main(void* arg)
|
|||
if(check_locking_order)
|
||||
open_lockorder(thr);
|
||||
ret = thr->func(thr->arg);
|
||||
thread_lockcount[thr->num] = thr->locks_created;
|
||||
thread_infos[thr->num] = NULL;
|
||||
if(check_locking_order)
|
||||
fclose(thr->order_info);
|
||||
|
|
|
|||
|
|
@ -2699,3 +2699,17 @@ void dtio_mainfdcallback(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
|
|||
log_assert(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
void fast_reload_service_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
|
||||
void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
int fast_reload_client_callback(struct comm_point* ATTR_UNUSED(c),
|
||||
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
|
||||
struct comm_reply* ATTR_UNUSED(repinfo))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1484,6 +1484,11 @@ size_t comm_point_get_mem(struct comm_point* ATTR_UNUSED(c))
|
|||
return 0;
|
||||
}
|
||||
|
||||
size_t comm_timer_get_mem(struct comm_timer* ATTR_UNUSED(timer))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t serviced_get_mem(struct serviced_query* ATTR_UNUSED(c))
|
||||
{
|
||||
return 0;
|
||||
|
|
@ -1994,4 +1999,24 @@ void http2_stream_remove_mesh_state(struct http2_stream* ATTR_UNUSED(h2_stream))
|
|||
{
|
||||
}
|
||||
|
||||
void fast_reload_service_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(event),
|
||||
void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
void fast_reload_thread_stop(
|
||||
struct fast_reload_thread* ATTR_UNUSED(fast_reload_thread))
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
int fast_reload_client_callback(struct comm_point* ATTR_UNUSED(c),
|
||||
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
|
||||
struct comm_reply* ATTR_UNUSED(repinfo))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********** End of Dummy routines ***********/
|
||||
|
|
|
|||
|
|
@ -601,6 +601,17 @@ void listen_desetup_locks(void)
|
|||
/* nothing */
|
||||
}
|
||||
|
||||
void fast_reload_printq_list_delete(
|
||||
struct fast_reload_printq* ATTR_UNUSED(list))
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
void fast_reload_worker_pickup_changes(struct worker* ATTR_UNUSED(worker))
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
#ifdef HAVE_NGTCP2
|
||||
void* quic_sslctx_create(char* ATTR_UNUSED(key), char* ATTR_UNUSED(pem),
|
||||
char* ATTR_UNUSED(verifypem))
|
||||
|
|
|
|||
2
testdata/fast_reload_fwd.tdir/auth1.zone
vendored
Normal file
2
testdata/fast_reload_fwd.tdir/auth1.zone
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
@ SOA ns root 1 3600 300 7200 3600
|
||||
www A 1.2.3.4
|
||||
2
testdata/fast_reload_fwd.tdir/auth2.zone
vendored
Normal file
2
testdata/fast_reload_fwd.tdir/auth2.zone
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
@ SOA ns root 1 3600 300 7200 3600
|
||||
www A 1.2.3.5
|
||||
107
testdata/fast_reload_fwd.tdir/fast_reload_fwd.conf
vendored
Normal file
107
testdata/fast_reload_fwd.tdir/fast_reload_fwd.conf
vendored
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
server:
|
||||
verbosity: 4
|
||||
num-threads: 1
|
||||
interface: 127.0.0.1
|
||||
port: @PORT@
|
||||
use-syslog: no
|
||||
directory: ""
|
||||
pidfile: "unbound.pid"
|
||||
chroot: ""
|
||||
username: ""
|
||||
do-not-query-localhost: no
|
||||
trust-anchor: "ta1.example.com DS 55566 8 2 9c148338951ce1c3b5cd3da532f3d90dfcf92595148022f2c2fd98e5deee90af"
|
||||
trust-anchor: "ta2.example.com DS 55566 8 2 9c148338951ce1c3b5cd3da532f3d90dfcf92595148022f2c2fd98e5deee90af"
|
||||
trust-anchor: "ta3.example.com DS 55566 8 2 9c148338951ce1c3b5cd3da532f3d90dfcf92595148022f2c2fd98e5deee90af"
|
||||
domain-insecure: "insec1.ta1.example.com"
|
||||
domain-insecure: "insec2.ta1.example.com"
|
||||
domain-insecure: "insec3.ta1.example.com"
|
||||
|
||||
forward-zone:
|
||||
name: "."
|
||||
forward-addr: "127.0.0.1@12345"
|
||||
|
||||
remote-control:
|
||||
control-enable: yes
|
||||
control-interface: @CONTROL_PATH@/controlpipe.@CONTROL_PID@
|
||||
control-use-cert: no
|
||||
|
||||
forward-zone:
|
||||
name: "example1.org"
|
||||
forward-addr: "127.0.0.1@@NS1_PORT@"
|
||||
|
||||
forward-zone:
|
||||
name: "example2.org"
|
||||
forward-addr: "127.0.0.1@@NS1_PORT@"
|
||||
|
||||
forward-zone:
|
||||
name: "example3.org"
|
||||
forward-addr: "127.0.0.1@@NS1_PORT@"
|
||||
|
||||
forward-zone:
|
||||
name: "example4.org"
|
||||
forward-addr: "127.0.0.1@@NS2_PORT@"
|
||||
|
||||
forward-zone:
|
||||
name: "example5.org"
|
||||
forward-addr: "127.0.0.1@@NS2_PORT@"
|
||||
|
||||
forward-zone:
|
||||
name: "example6.org"
|
||||
forward-addr: "127.0.0.1@@NS2_PORT@"
|
||||
|
||||
stub-zone:
|
||||
name: "stub1.org"
|
||||
stub-addr: "127.0.0.1@@NS1_PORT@"
|
||||
stub-prime: no
|
||||
|
||||
stub-zone:
|
||||
name: "stub2.org"
|
||||
stub-addr: "127.0.0.1@@NS1_PORT@"
|
||||
stub-prime: no
|
||||
|
||||
stub-zone:
|
||||
name: "stub3.org"
|
||||
stub-addr: "127.0.0.1@@NS1_PORT@"
|
||||
stub-prime: no
|
||||
|
||||
stub-zone:
|
||||
name: "stub4.org"
|
||||
stub-addr: "127.0.0.1@@NS2_PORT@"
|
||||
stub-prime: no
|
||||
|
||||
stub-zone:
|
||||
name: "stub5.org"
|
||||
stub-addr: "127.0.0.1@@NS2_PORT@"
|
||||
stub-prime: no
|
||||
|
||||
stub-zone:
|
||||
name: "stub6.org"
|
||||
stub-addr: "127.0.0.1@@NS2_PORT@"
|
||||
stub-prime: no
|
||||
|
||||
auth-zone:
|
||||
name: "auth1.org"
|
||||
zonefile: "auth1.zone"
|
||||
|
||||
auth-zone:
|
||||
name: "auth2.org"
|
||||
zonefile: "auth1.zone"
|
||||
|
||||
auth-zone:
|
||||
name: "auth3.org"
|
||||
zonefile: "auth1.zone"
|
||||
|
||||
auth-zone:
|
||||
name: "auth5.org"
|
||||
zonefile: "auth5.zone"
|
||||
primary: 127.0.0.1@@NS1_PORT@
|
||||
|
||||
auth-zone:
|
||||
name: "auth6.org"
|
||||
zonefile: "auth6.zone"
|
||||
primary: 127.0.0.1@@NS1_PORT@
|
||||
|
||||
auth-zone:
|
||||
name: "auth7.org"
|
||||
zonefile: "auth7.zone"
|
||||
primary: 127.0.0.1@@NS1_PORT@
|
||||
108
testdata/fast_reload_fwd.tdir/fast_reload_fwd.conf2
vendored
Normal file
108
testdata/fast_reload_fwd.tdir/fast_reload_fwd.conf2
vendored
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
server:
|
||||
verbosity: 4
|
||||
num-threads: 1
|
||||
interface: 127.0.0.1
|
||||
port: @PORT@
|
||||
use-syslog: no
|
||||
directory: ""
|
||||
pidfile: "unbound.pid"
|
||||
chroot: ""
|
||||
username: ""
|
||||
do-not-query-localhost: no
|
||||
trust-anchor: "ta1.example.com DS 55566 8 2 9c148338951ce1c3b5cd3da532f3d90dfcf92595148022f2c2fd98e5deee90af"
|
||||
trust-anchor: "ta3.example.com DS 55567 8 2 9c148338951ce1c3b5cd3da532f3d90dfcf92595148022f2c2fd98e5deee90af"
|
||||
trust-anchor: "ta4.example.com DS 55566 8 2 9c148338951ce1c3b5cd3da532f3d90dfcf92595148022f2c2fd98e5deee90af"
|
||||
domain-insecure: "insec1.ta1.example.com"
|
||||
domain-insecure: "insec3.ta1.example.com"
|
||||
domain-insecure: "insec4.ta1.example.com"
|
||||
|
||||
forward-zone:
|
||||
name: "."
|
||||
# No addresses makes the server return SERVFAIL for deleted zones.
|
||||
#forward-addr: "127.0.0.1@12345"
|
||||
|
||||
remote-control:
|
||||
control-enable: yes
|
||||
control-interface: @CONTROL_PATH@/controlpipe.@CONTROL_PID@
|
||||
control-use-cert: no
|
||||
|
||||
forward-zone:
|
||||
name: "example1.org"
|
||||
forward-addr: "127.0.0.1@@NS2_PORT@"
|
||||
|
||||
forward-zone:
|
||||
name: "example2.org"
|
||||
forward-addr: "127.0.0.1@@NS1_PORT@"
|
||||
|
||||
forward-zone:
|
||||
name: "example3.org"
|
||||
forward-addr: "127.0.0.1@@NS2_PORT@"
|
||||
|
||||
forward-zone:
|
||||
name: "example4.org"
|
||||
forward-addr: "127.0.0.1@@NS1_PORT@"
|
||||
|
||||
forward-zone:
|
||||
name: "example5.org"
|
||||
forward-addr: "127.0.0.1@@NS2_PORT@"
|
||||
|
||||
forward-zone:
|
||||
name: "example6.org"
|
||||
forward-addr: "127.0.0.1@@NS1_PORT@"
|
||||
|
||||
stub-zone:
|
||||
name: "stub1.org"
|
||||
stub-addr: "127.0.0.1@@NS2_PORT@"
|
||||
stub-prime: no
|
||||
|
||||
stub-zone:
|
||||
name: "stub2.org"
|
||||
stub-addr: "127.0.0.1@@NS1_PORT@"
|
||||
stub-prime: no
|
||||
|
||||
stub-zone:
|
||||
name: "stub3.org"
|
||||
stub-addr: "127.0.0.1@@NS2_PORT@"
|
||||
stub-prime: no
|
||||
|
||||
stub-zone:
|
||||
name: "stub4.org"
|
||||
stub-addr: "127.0.0.1@@NS1_PORT@"
|
||||
stub-prime: no
|
||||
|
||||
stub-zone:
|
||||
name: "stub5.org"
|
||||
stub-addr: "127.0.0.1@@NS2_PORT@"
|
||||
stub-prime: no
|
||||
|
||||
stub-zone:
|
||||
name: "stub6.org"
|
||||
stub-addr: "127.0.0.1@@NS1_PORT@"
|
||||
stub-prime: no
|
||||
|
||||
auth-zone:
|
||||
name: "auth1.org"
|
||||
zonefile: "auth1.zone"
|
||||
|
||||
auth-zone:
|
||||
name: "auth3.org"
|
||||
zonefile: "auth2.zone"
|
||||
|
||||
auth-zone:
|
||||
name: "auth4.org"
|
||||
zonefile: "auth2.zone"
|
||||
|
||||
auth-zone:
|
||||
name: "auth5.org"
|
||||
zonefile: "auth5.zone"
|
||||
primary: 127.0.0.1@@NS1_PORT@
|
||||
|
||||
auth-zone:
|
||||
name: "auth7.org"
|
||||
zonefile: "auth7.zone"
|
||||
primary: 127.0.0.1@@NS2_PORT@
|
||||
|
||||
auth-zone:
|
||||
name: "auth8.org"
|
||||
zonefile: "auth8.zone"
|
||||
primary: 127.0.0.1@@NS1_PORT@
|
||||
16
testdata/fast_reload_fwd.tdir/fast_reload_fwd.dsc
vendored
Normal file
16
testdata/fast_reload_fwd.tdir/fast_reload_fwd.dsc
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
BaseName: fast_reload_fwd
|
||||
Version: 1.0
|
||||
Description: Test fast reload change of forwards and stubs.
|
||||
CreationDate: Thu Jan 22 11:55:55 CET 2024
|
||||
Maintainer: dr. W.C.A. Wijngaards
|
||||
Category:
|
||||
Component:
|
||||
CmdDepends:
|
||||
Depends:
|
||||
Help:
|
||||
Pre: fast_reload_fwd.pre
|
||||
Post: fast_reload_fwd.post
|
||||
Test: fast_reload_fwd.test
|
||||
AuxFiles:
|
||||
Passed:
|
||||
Failure:
|
||||
339
testdata/fast_reload_fwd.tdir/fast_reload_fwd.ns1
vendored
Normal file
339
testdata/fast_reload_fwd.tdir/fast_reload_fwd.ns1
vendored
Normal file
|
|
@ -0,0 +1,339 @@
|
|||
; match A records and return a reply indicating it is this server.
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www.example1.org. IN A
|
||||
SECTION ANSWER
|
||||
www.example1.org. IN A 1.2.3.1
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www.example2.org. IN A
|
||||
SECTION ANSWER
|
||||
www.example2.org. IN A 1.2.3.1
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www.example3.org. IN A
|
||||
SECTION ANSWER
|
||||
www.example3.org. IN A 1.2.3.1
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www.example4.org. IN A
|
||||
SECTION ANSWER
|
||||
www.example4.org. IN A 1.2.3.1
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www.example5.org. IN A
|
||||
SECTION ANSWER
|
||||
www.example5.org. IN A 1.2.3.1
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www.example6.org. IN A
|
||||
SECTION ANSWER
|
||||
www.example6.org. IN A 1.2.3.1
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www2.example1.org. IN A
|
||||
SECTION ANSWER
|
||||
www2.example1.org. IN A 1.2.3.1
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www2.example2.org. IN A
|
||||
SECTION ANSWER
|
||||
www2.example2.org. IN A 1.2.3.1
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www2.example3.org. IN A
|
||||
SECTION ANSWER
|
||||
www2.example3.org. IN A 1.2.3.1
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www2.example4.org. IN A
|
||||
SECTION ANSWER
|
||||
www2.example4.org. IN A 1.2.3.1
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www2.example5.org. IN A
|
||||
SECTION ANSWER
|
||||
www2.example5.org. IN A 1.2.3.1
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www2.example6.org. IN A
|
||||
SECTION ANSWER
|
||||
www2.example6.org. IN A 1.2.3.1
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www.stub1.org. IN A
|
||||
SECTION ANSWER
|
||||
www.stub1.org. IN A 1.2.3.1
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www.stub2.org. IN A
|
||||
SECTION ANSWER
|
||||
www.stub2.org. IN A 1.2.3.1
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www.stub3.org. IN A
|
||||
SECTION ANSWER
|
||||
www.stub3.org. IN A 1.2.3.1
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www.stub4.org. IN A
|
||||
SECTION ANSWER
|
||||
www.stub4.org. IN A 1.2.3.1
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www.stub5.org. IN A
|
||||
SECTION ANSWER
|
||||
www.stub5.org. IN A 1.2.3.1
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www.stub6.org. IN A
|
||||
SECTION ANSWER
|
||||
www.stub6.org. IN A 1.2.3.1
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www2.stub1.org. IN A
|
||||
SECTION ANSWER
|
||||
www2.stub1.org. IN A 1.2.3.1
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www2.stub2.org. IN A
|
||||
SECTION ANSWER
|
||||
www2.stub2.org. IN A 1.2.3.1
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www2.stub3.org. IN A
|
||||
SECTION ANSWER
|
||||
www2.stub3.org. IN A 1.2.3.1
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www2.stub4.org. IN A
|
||||
SECTION ANSWER
|
||||
www2.stub4.org. IN A 1.2.3.1
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www2.stub5.org. IN A
|
||||
SECTION ANSWER
|
||||
www2.stub5.org. IN A 1.2.3.1
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www2.stub6.org. IN A
|
||||
SECTION ANSWER
|
||||
www2.stub6.org. IN A 1.2.3.1
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
auth5.org. IN SOA
|
||||
SECTION ANSWER
|
||||
auth5.org. SOA ns root 1 3600 300 7200 3600
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
auth5.org. IN AXFR
|
||||
SECTION ANSWER
|
||||
auth5.org. SOA ns root 1 3600 300 7200 3600
|
||||
www.auth5.org. A 1.2.3.4
|
||||
auth5.org. SOA ns root 1 3600 300 7200 3600
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
auth6.org. IN SOA
|
||||
SECTION ANSWER
|
||||
auth6.org. SOA ns root 1 3600 300 7200 3600
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
auth6.org. IN AXFR
|
||||
SECTION ANSWER
|
||||
auth6.org. SOA ns root 1 3600 300 7200 3600
|
||||
www.auth6.org. A 1.2.3.4
|
||||
auth6.org. SOA ns root 1 3600 300 7200 3600
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
auth7.org. IN SOA
|
||||
SECTION ANSWER
|
||||
auth7.org. SOA ns root 1 3600 300 7200 3600
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
auth7.org. IN AXFR
|
||||
SECTION ANSWER
|
||||
auth7.org. SOA ns root 1 3600 300 7200 3600
|
||||
www.auth7.org. A 1.2.3.4
|
||||
auth7.org. SOA ns root 1 3600 300 7200 3600
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
auth8.org. IN SOA
|
||||
SECTION ANSWER
|
||||
auth8.org. SOA ns root 1 3600 300 7200 3600
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
auth8.org. IN AXFR
|
||||
SECTION ANSWER
|
||||
auth8.org. SOA ns root 1 3600 300 7200 3600
|
||||
www.auth8.org. A 1.2.3.4
|
||||
auth8.org. SOA ns root 1 3600 300 7200 3600
|
||||
ENTRY_END
|
||||
|
||||
; match anything and return a reply
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode
|
||||
ADJUST copy_id copy_query
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
example.org. IN SOA
|
||||
SECTION AUTHORITY
|
||||
example.org. IN SOA ns1.example.org. hostmaster.example.org. 1 3600 900 86400 3600
|
||||
ENTRY_END
|
||||
285
testdata/fast_reload_fwd.tdir/fast_reload_fwd.ns2
vendored
Normal file
285
testdata/fast_reload_fwd.tdir/fast_reload_fwd.ns2
vendored
Normal file
|
|
@ -0,0 +1,285 @@
|
|||
; match A records and return a reply indicating it is this server.
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www.example1.org. IN A
|
||||
SECTION ANSWER
|
||||
www.example1.org. IN A 1.2.3.2
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www.example2.org. IN A
|
||||
SECTION ANSWER
|
||||
www.example2.org. IN A 1.2.3.2
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www.example3.org. IN A
|
||||
SECTION ANSWER
|
||||
www.example3.org. IN A 1.2.3.2
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www.example4.org. IN A
|
||||
SECTION ANSWER
|
||||
www.example4.org. IN A 1.2.3.2
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www.example5.org. IN A
|
||||
SECTION ANSWER
|
||||
www.example5.org. IN A 1.2.3.2
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www.example6.org. IN A
|
||||
SECTION ANSWER
|
||||
www.example6.org. IN A 1.2.3.2
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www2.example1.org. IN A
|
||||
SECTION ANSWER
|
||||
www2.example1.org. IN A 1.2.3.2
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www2.example2.org. IN A
|
||||
SECTION ANSWER
|
||||
www2.example2.org. IN A 1.2.3.2
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www2.example3.org. IN A
|
||||
SECTION ANSWER
|
||||
www2.example3.org. IN A 1.2.3.2
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www2.example4.org. IN A
|
||||
SECTION ANSWER
|
||||
www2.example4.org. IN A 1.2.3.2
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www2.example5.org. IN A
|
||||
SECTION ANSWER
|
||||
www2.example5.org. IN A 1.2.3.2
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www2.example6.org. IN A
|
||||
SECTION ANSWER
|
||||
www2.example6.org. IN A 1.2.3.2
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www.stub1.org. IN A
|
||||
SECTION ANSWER
|
||||
www.stub1.org. IN A 1.2.3.2
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www.stub2.org. IN A
|
||||
SECTION ANSWER
|
||||
www.stub2.org. IN A 1.2.3.2
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www.stub3.org. IN A
|
||||
SECTION ANSWER
|
||||
www.stub3.org. IN A 1.2.3.2
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www.stub4.org. IN A
|
||||
SECTION ANSWER
|
||||
www.stub4.org. IN A 1.2.3.2
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www.stub5.org. IN A
|
||||
SECTION ANSWER
|
||||
www.stub5.org. IN A 1.2.3.2
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www.stub6.org. IN A
|
||||
SECTION ANSWER
|
||||
www.stub6.org. IN A 1.2.3.2
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www2.stub1.org. IN A
|
||||
SECTION ANSWER
|
||||
www2.stub1.org. IN A 1.2.3.2
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www2.stub2.org. IN A
|
||||
SECTION ANSWER
|
||||
www2.stub2.org. IN A 1.2.3.2
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www2.stub3.org. IN A
|
||||
SECTION ANSWER
|
||||
www2.stub3.org. IN A 1.2.3.2
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www2.stub4.org. IN A
|
||||
SECTION ANSWER
|
||||
www2.stub4.org. IN A 1.2.3.2
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www2.stub5.org. IN A
|
||||
SECTION ANSWER
|
||||
www2.stub5.org. IN A 1.2.3.2
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
www2.stub6.org. IN A
|
||||
SECTION ANSWER
|
||||
www2.stub6.org. IN A 1.2.3.2
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
auth7.org. IN SOA
|
||||
SECTION ANSWER
|
||||
auth7.org. SOA ns root 2 3600 300 7200 3600
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
auth7.org. IN AXFR
|
||||
SECTION ANSWER
|
||||
auth7.org. SOA ns root 2 3600 300 7200 3600
|
||||
www.auth7.org. A 1.2.3.5
|
||||
auth7.org. SOA ns root 2 3600 300 7200 3600
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
auth7.org. IN IXFR
|
||||
SECTION ANSWER
|
||||
auth7.org. SOA ns root 2 3600 300 7200 3600
|
||||
www.auth7.org. A 1.2.3.5
|
||||
auth7.org. SOA ns root 2 3600 300 7200 3600
|
||||
ENTRY_END
|
||||
|
||||
; match anything and return a reply
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode
|
||||
ADJUST copy_id copy_query
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
example.org. IN SOA
|
||||
SECTION AUTHORITY
|
||||
example.org. IN SOA ns1.example.org. hostmaster.example.org. 1 3600 900 86400 3600
|
||||
ENTRY_END
|
||||
25
testdata/fast_reload_fwd.tdir/fast_reload_fwd.post
vendored
Normal file
25
testdata/fast_reload_fwd.tdir/fast_reload_fwd.post
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# #-- fast_reload_fwd.post --#
|
||||
# source the master var file when it's there
|
||||
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
|
||||
# source the test var file when it's there
|
||||
[ -f .tpkg.var.test ] && source .tpkg.var.test
|
||||
#
|
||||
# do your teardown here
|
||||
PRE="../.."
|
||||
. ../common.sh
|
||||
kill_pid $NS1_PID
|
||||
kill_pid $NS2_PID
|
||||
if test -f unbound.pid; then
|
||||
kill_pid $UNBOUND_PID
|
||||
fi
|
||||
rm -f $CONTROL_PATH/controlpipe.$CONTROL_PID
|
||||
echo
|
||||
echo "> ns1.log"
|
||||
cat ns1.log
|
||||
echo
|
||||
echo "> ns2.log"
|
||||
cat ns2.log
|
||||
echo
|
||||
echo "> unbound.log"
|
||||
cat unbound.log
|
||||
exit 0
|
||||
56
testdata/fast_reload_fwd.tdir/fast_reload_fwd.pre
vendored
Normal file
56
testdata/fast_reload_fwd.tdir/fast_reload_fwd.pre
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
# #-- fast_reload_fwd.pre--#
|
||||
# source the master var file when it's there
|
||||
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
|
||||
# use .tpkg.var.test for in test variable passing
|
||||
[ -f .tpkg.var.test ] && source .tpkg.var.test
|
||||
|
||||
PRE="../.."
|
||||
. ../common.sh
|
||||
# if no threads; exit
|
||||
if grep -e "define HAVE_PTHREAD 1" -e "define HAVE_SOLARIS_THREADS 1" -e "define HAVE_WINDOWS_THREADS 1" $PRE/config.h; then
|
||||
echo "have threads"
|
||||
else
|
||||
skip_test "no threads"
|
||||
fi
|
||||
if grep -e "define ENABLE_LOCK_CHECKS 1" $PRE/config.h; then
|
||||
get_make
|
||||
echo "> (cd $PRE ; $MAKE lock-verify)"
|
||||
(cd $PRE ; $MAKE lock-verify)
|
||||
fi
|
||||
|
||||
get_random_port 3
|
||||
UNBOUND_PORT=$RND_PORT
|
||||
NS1_PORT=$(($RND_PORT + 1))
|
||||
NS2_PORT=$(($RND_PORT + 2))
|
||||
echo "UNBOUND_PORT=$UNBOUND_PORT" >> .tpkg.var.test
|
||||
echo "NS1_PORT=$NS1_PORT" >> .tpkg.var.test
|
||||
echo "NS2_PORT=$NS2_PORT" >> .tpkg.var.test
|
||||
|
||||
# make config files
|
||||
CONTROL_PATH=/tmp
|
||||
CONTROL_PID=$$
|
||||
sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's/@NS1_PORT\@/'$NS1_PORT'/' -e 's/@NS2_PORT\@/'$NS2_PORT'/' -e 's?@CONTROL_PATH\@?'$CONTROL_PATH'?' -e 's/@CONTROL_PID@/'$CONTROL_PID'/' < fast_reload_fwd.conf > ub.conf
|
||||
sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's/@NS1_PORT\@/'$NS1_PORT'/' -e 's/@NS2_PORT\@/'$NS2_PORT'/' -e 's?@CONTROL_PATH\@?'$CONTROL_PATH'?' -e 's/@CONTROL_PID@/'$CONTROL_PID'/' < fast_reload_fwd.conf2 > ub.conf2
|
||||
|
||||
# start forwarders
|
||||
get_ldns_testns
|
||||
$LDNS_TESTNS -p $NS1_PORT fast_reload_fwd.ns1 >ns1.log 2>&1 &
|
||||
NS1_PID=$!
|
||||
echo "NS1_PID=$NS1_PID" >> .tpkg.var.test
|
||||
|
||||
$LDNS_TESTNS -p $NS2_PORT fast_reload_fwd.ns2 >ns2.log 2>&1 &
|
||||
NS2_PID=$!
|
||||
echo "NS2_PID=$NS2_PID" >> .tpkg.var.test
|
||||
|
||||
# start unbound in the background
|
||||
PRE="../.."
|
||||
$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
|
||||
UNBOUND_PID=$!
|
||||
echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
|
||||
echo "CONTROL_PATH=$CONTROL_PATH" >> .tpkg.var.test
|
||||
echo "CONTROL_PID=$CONTROL_PID" >> .tpkg.var.test
|
||||
|
||||
cat .tpkg.var.test
|
||||
wait_ldns_testns_up ns1.log
|
||||
wait_ldns_testns_up ns2.log
|
||||
wait_unbound_up unbound.log
|
||||
320
testdata/fast_reload_fwd.tdir/fast_reload_fwd.test
vendored
Normal file
320
testdata/fast_reload_fwd.tdir/fast_reload_fwd.test
vendored
Normal file
|
|
@ -0,0 +1,320 @@
|
|||
# #-- fast_reload_fwd.test --#
|
||||
# source the master var file when it's there
|
||||
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
|
||||
# use .tpkg.var.test for in test variable passing
|
||||
[ -f .tpkg.var.test ] && source .tpkg.var.test
|
||||
|
||||
PRE="../.."
|
||||
. ../common.sh
|
||||
|
||||
echo "> unbound-control status"
|
||||
$PRE/unbound-control -c ub.conf status
|
||||
if test $? -ne 0; then
|
||||
echo "wrong exit value."
|
||||
exit 1
|
||||
else
|
||||
echo "exit value: OK"
|
||||
fi
|
||||
|
||||
# test that the forwards and stubs point to the right upstream.
|
||||
for x in example1.org example2.org example3.org stub1.org stub2.org stub3.org; do
|
||||
echo ""
|
||||
echo "dig www.$x [upstream is NS1]"
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.$x A 2>&1 | tee outfile
|
||||
if grep "1.2.3.1" outfile; then
|
||||
echo "response OK"
|
||||
else
|
||||
echo "www.$x got the wrong answer"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
for x in example4.org example5.org example6.org stub4.org stub5.org stub6.org; do
|
||||
echo ""
|
||||
echo "dig www.$x [upstream is NS2]"
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.$x A 2>&1 | tee outfile
|
||||
if grep "1.2.3.2" outfile; then
|
||||
echo "response OK"
|
||||
else
|
||||
echo "www.$x got the wrong answer"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
for x in auth1.org auth2.org auth3.org auth5.org auth6.org auth7.org; do
|
||||
echo ""
|
||||
echo "dig www.$x [auth is 1.2.3.4]"
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.$x A 2>&1 | tee outfile
|
||||
if grep "1.2.3.4" outfile; then
|
||||
echo "response OK"
|
||||
else
|
||||
echo "www.$x got the wrong answer"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "> list_insecure"
|
||||
$PRE/unbound-control -c ub.conf list_insecure 2>&1 | tee output
|
||||
if test $? -ne 0; then
|
||||
echo "wrong exit value."
|
||||
exit 1
|
||||
fi
|
||||
if grep "insec1.ta1.example.com" output >/dev/null; then :; else
|
||||
echo "wrong output"
|
||||
exit 1
|
||||
fi
|
||||
if grep "insec2.ta1.example.com" output >/dev/null; then :; else
|
||||
echo "wrong output"
|
||||
exit 1
|
||||
fi
|
||||
if grep "insec3.ta1.example.com" output >/dev/null; then :; else
|
||||
echo "wrong output"
|
||||
exit 1
|
||||
fi
|
||||
echo ""
|
||||
echo "> trustanchor.unbound"
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT trustanchor.unbound CH TXT 2>&1 | tee outfile
|
||||
if grep "ta1.example.com. 55566" outfile >/dev/null; then :; else
|
||||
echo "wrong output ta1"
|
||||
exit 1
|
||||
fi
|
||||
if grep "ta2.example.com. 55566" outfile >/dev/null; then :; else
|
||||
echo "wrong output"
|
||||
exit 1
|
||||
fi
|
||||
if grep "ta3.example.com. 55566" outfile >/dev/null; then :; else
|
||||
echo "wrong output"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "> replace config file ub.conf"
|
||||
mv ub.conf ub.conf.orig
|
||||
mv ub.conf2 ub.conf
|
||||
echo ""
|
||||
echo "> unbound-control fast_reload"
|
||||
$PRE/unbound-control -c ub.conf fast_reload +vv 2>&1 | tee output
|
||||
if test $? -ne 0; then
|
||||
echo "wrong exit value."
|
||||
exit 1
|
||||
else
|
||||
echo "exit value: OK"
|
||||
fi
|
||||
|
||||
# for the previous digs to www.x the cached value should remain the same
|
||||
# but for new lookups, to www2.x the new upstream should be used.
|
||||
for x in example1.org example2.org example3.org stub1.org stub2.org stub3.org; do
|
||||
echo ""
|
||||
echo "dig www.$x [upstream is NS1]"
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.$x A 2>&1 | tee outfile
|
||||
if grep "1.2.3.1" outfile; then
|
||||
echo "response OK"
|
||||
else
|
||||
echo "www.$x got the wrong answer"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
for x in example4.org example5.org example6.org stub4.org stub5.org stub6.org; do
|
||||
echo ""
|
||||
echo "dig www.$x [upstream is NS2]"
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.$x A 2>&1 | tee outfile
|
||||
if grep "1.2.3.2" outfile; then
|
||||
echo "response OK"
|
||||
else
|
||||
echo "www.$x got the wrong answer"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# new lookups for www2 go to the upstream.
|
||||
for x in example2.org example4.org example6.org stub2.org stub4.org stub6.org; do
|
||||
echo ""
|
||||
echo "dig www2.$x [upstream is NS1]"
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www2.$x A 2>&1 | tee outfile
|
||||
if grep "1.2.3.1" outfile; then
|
||||
echo "response OK"
|
||||
else
|
||||
echo "www2.$x got the wrong answer"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
for x in example1.org example3.org example5.org stub1.org stub3.org stub5.org; do
|
||||
echo ""
|
||||
echo "dig www2.$x [upstream is NS2]"
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www2.$x A 2>&1 | tee outfile
|
||||
if grep "1.2.3.2" outfile; then
|
||||
echo "response OK"
|
||||
else
|
||||
echo "www2.$x got the wrong answer"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# auth is unchanged, or at ns1.
|
||||
for x in auth1.org auth5.org auth8.org; do
|
||||
echo ""
|
||||
echo "dig www.$x [auth is 1.2.3.4]"
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.$x A 2>&1 | tee outfile
|
||||
if grep "1.2.3.4" outfile; then
|
||||
echo "response OK"
|
||||
else
|
||||
echo "www.$x got the wrong answer"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# deleted auth
|
||||
for x in auth2.org auth6.org; do
|
||||
echo ""
|
||||
echo "dig www.$x [auth is deleted]"
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.$x A 2>&1 | tee outfile
|
||||
if grep "SERVFAIL" outfile; then
|
||||
echo "response OK"
|
||||
else
|
||||
echo "www.$x got the wrong answer"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# changed and added auth
|
||||
for x in auth3.org auth4.org auth7.org; do
|
||||
echo ""
|
||||
echo "dig www.$x [auth is 1.2.3.5]"
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.$x A 2>&1 | tee outfile
|
||||
if grep "1.2.3.5" outfile; then
|
||||
echo "response OK"
|
||||
else
|
||||
echo "www.$x got the wrong answer"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "> list_insecure"
|
||||
$PRE/unbound-control -c ub.conf list_insecure 2>&1 | tee output
|
||||
if test $? -ne 0; then
|
||||
echo "wrong exit value."
|
||||
exit 1
|
||||
fi
|
||||
if grep "insec1.ta1.example.com" output >/dev/null; then :; else
|
||||
echo "wrong output"
|
||||
exit 1
|
||||
fi
|
||||
if grep "insec2.ta1.example.com" output >/dev/null; then
|
||||
echo "wrong output"
|
||||
exit 1
|
||||
fi
|
||||
if grep "insec3.ta1.example.com" output >/dev/null; then :; else
|
||||
echo "wrong output"
|
||||
exit 1
|
||||
fi
|
||||
if grep "insec4.ta1.example.com" output >/dev/null; then :; else
|
||||
echo "wrong output"
|
||||
exit 1
|
||||
fi
|
||||
echo ""
|
||||
echo "> trustanchor.unbound"
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT trustanchor.unbound CH TXT 2>&1 | tee outfile
|
||||
if grep "ta1.example.com. 55566" outfile >/dev/null; then :; else
|
||||
echo "wrong output"
|
||||
exit 1
|
||||
fi
|
||||
if grep "ta2.example.com. 55566" outfile >/dev/null; then
|
||||
echo "wrong output"
|
||||
exit 1
|
||||
fi
|
||||
if grep "ta3.example.com. 55566" outfile >/dev/null; then
|
||||
echo "wrong output"
|
||||
exit 1
|
||||
fi
|
||||
if grep "ta3.example.com. 55567" outfile >/dev/null; then :; else
|
||||
echo "wrong output"
|
||||
exit 1
|
||||
fi
|
||||
if grep "ta4.example.com. 55566" outfile >/dev/null; then :; else
|
||||
echo "wrong output"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "> test change: add tag1 tag2"
|
||||
cp ub.conf ub.conf.orig2
|
||||
echo "server:" >> ub.conf
|
||||
echo ' define-tag: "tag1 tag2"' >> ub.conf
|
||||
echo "> unbound-control fast_reload"
|
||||
$PRE/unbound-control -c ub.conf fast_reload +vv 2>&1 | tee output
|
||||
if test $? -ne 0; then
|
||||
echo "wrong exit value."
|
||||
exit 1
|
||||
else
|
||||
echo "exit value: OK"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "> test change: change to tag2 tag3"
|
||||
cp ub.conf.orig2 ub.conf
|
||||
echo "server:" >> ub.conf
|
||||
echo ' define-tag: "tag2 tag3"' >> ub.conf
|
||||
echo "> unbound-control fast_reload"
|
||||
$PRE/unbound-control -c ub.conf fast_reload +vv 2>&1 | tee output
|
||||
if test $? -ne 0; then
|
||||
echo "wrong exit value."
|
||||
exit 1
|
||||
else
|
||||
echo "exit value: OK"
|
||||
fi
|
||||
if grep "tags have changed" output; then
|
||||
echo "output OK"
|
||||
else
|
||||
echo "wrong output"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "> test change: change cache size"
|
||||
cp ub.conf.orig2 ub.conf
|
||||
echo "server:" >> ub.conf
|
||||
echo " msg-cache-size: 10m" >> ub.conf
|
||||
echo " rrset-cache-size: 5m" >> ub.conf
|
||||
echo "> unbound-control fast_reload"
|
||||
$PRE/unbound-control -c ub.conf fast_reload +vv 2>&1 | tee output
|
||||
if test $? -ne 0; then
|
||||
echo "wrong exit value."
|
||||
exit 1
|
||||
else
|
||||
echo "exit value: OK"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "> test change: change nothing, +p too"
|
||||
$PRE/unbound-control -c ub.conf fast_reload +vv +p 2>&1 | tee output
|
||||
if test $? -ne 0; then
|
||||
echo "wrong exit value."
|
||||
exit 1
|
||||
else
|
||||
echo "exit value: OK"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "> stop unbound"
|
||||
kill_pid $UNBOUND_PID
|
||||
if test -f unbound.pid; then sleep 1; fi
|
||||
if test -f unbound.pid; then sleep 1; fi
|
||||
if test -f unbound.pid; then sleep 1; fi
|
||||
if test -f unbound.pid; then echo "unbound.pid still there"; fi
|
||||
# check the locks.
|
||||
function locktest() {
|
||||
if test -x $PRE/lock-verify -a -f ublocktrace.0; then
|
||||
$PRE/lock-verify ublocktrace.*
|
||||
if test $? -ne 0; then
|
||||
echo "lock-verify error"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
locktest
|
||||
|
||||
exit 0
|
||||
3
testdata/fast_reload_most_options.tdir/auth.nlnetlabs.nl.zone
vendored
Normal file
3
testdata/fast_reload_most_options.tdir/auth.nlnetlabs.nl.zone
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
$ORIGIN auth.nlnetlabs.nl.
|
||||
$TTL 60
|
||||
@ IN SOA a b 1 2 3 4 5
|
||||
143
testdata/fast_reload_most_options.tdir/fast_reload_most_options.conf
vendored
Normal file
143
testdata/fast_reload_most_options.tdir/fast_reload_most_options.conf
vendored
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
# Try to define values for options that don't have "default" options that would
|
||||
# trigger fast-reload functionality.
|
||||
server:
|
||||
verbosity: 4
|
||||
num-threads: 4
|
||||
interface: 127.0.0.1
|
||||
interface: lo
|
||||
port: @PORT@
|
||||
interface-action: lo allow
|
||||
use-syslog: no
|
||||
directory: ""
|
||||
pidfile: "unbound.pid"
|
||||
chroot: ""
|
||||
username: ""
|
||||
do-not-query-localhost: no
|
||||
|
||||
module-config: "respip validator iterator"
|
||||
|
||||
outgoing-interface: 127.0.0.1
|
||||
outgoing-port-avoid: "3200-3208"
|
||||
|
||||
define-tag: "tag1 tag2 tag3"
|
||||
|
||||
do-nat64: yes
|
||||
nat64-prefix: 64:ff9b::0/96
|
||||
dns64-prefix: 64:ff9b::0/96
|
||||
dns64-ignore-aaaa: "ignore-aaaa.nlnetlabs.nl"
|
||||
|
||||
edns-tcp-keepalive: yes
|
||||
|
||||
response-ip: 192.0.2.0 always_refuse
|
||||
access-control: 127.0.0.0/8 allow
|
||||
access-control: ::1 allow
|
||||
access-control-tag: 192.0.2.0/24 "tag2 tag3"
|
||||
interface-tag: lo "tag2 tag3"
|
||||
access-control-tag-action: 192.0.2.0/24 tag3 always_refuse
|
||||
interface-tag-action: lo tag3 always_refuse
|
||||
access-control-tag-data: 192.0.2.0/24 tag2 "A 127.0.0.1"
|
||||
interface-tag-data: lo tag2 "A 127.0.0.1"
|
||||
access-control-view: 192.0.2.0/24 viewname
|
||||
interface-view: lo viewname
|
||||
|
||||
nsid: "ascii_something"
|
||||
|
||||
http-user-agent: "httpuseragent"
|
||||
|
||||
caps-exempt: "nlnetlabs.nl"
|
||||
|
||||
private-address: 10.0.0.0/8
|
||||
private-address: 172.16.0.0/12
|
||||
private-address: 192.168.0.0/16
|
||||
private-address: 169.254.0.0/16
|
||||
private-address: fd00::/8
|
||||
private-address: fe80::/10
|
||||
private-address: ::ffff:0:0/96
|
||||
|
||||
private-domain: "nlnetlabs.nl"
|
||||
|
||||
unwanted-reply-threshold: 10000000
|
||||
|
||||
do-not-query-address: 1.1.1.1
|
||||
do-not-query-address: 8.8.8.8
|
||||
do-not-query-address: 9.9.9.9
|
||||
|
||||
do-not-query-localhost: no
|
||||
|
||||
trust-anchor: "jelte.nlnetlabs.nl. DS 42860 5 1 14D739EB566D2B1A5E216A0BA4D17FA9B038BE4A"
|
||||
|
||||
domain-insecure: "nlnetlabs.nl"
|
||||
|
||||
serve-expired: yes
|
||||
serve-expired-client-timeout: 1800
|
||||
|
||||
val-log-level: 2
|
||||
|
||||
local-zone: refuse.nlnetlabs.nl. refuse
|
||||
local-zone: override.nlnetlabs.nl. deny
|
||||
local-zone: tag.nlnetlabs.nl. transparent
|
||||
local-data: "data.nlnetlabs.nl. TXT localdata"
|
||||
local-data-ptr: "192.0.2.3 reverse.nlnetlabs.nl."
|
||||
local-zone-tag: "tag.nlnetlabs.nl" "tag2 tag3"
|
||||
local-zone-override: "override.nlnetlabs.nl" 192.0.2.0/24 refuse
|
||||
|
||||
|
||||
ratelimit: 100
|
||||
ratelimit-below-domain: ratelimit.nlnetlabs.nl 1000
|
||||
ip-ratelimit: 100
|
||||
|
||||
tcp-connection-limit: 192.0.2.0/24 12
|
||||
|
||||
answer-cookie: yes
|
||||
cookie-secret: "000102030405060708090a0b0c0d0e0f"
|
||||
|
||||
ede: yes
|
||||
ede-serve-expired: yes
|
||||
|
||||
remote-control:
|
||||
control-enable: yes
|
||||
control-interface: @CONTROL_PATH@/controlpipe.@CONTROL_PID@
|
||||
control-use-cert: no
|
||||
|
||||
stub-zone:
|
||||
name: "stub.nlnetlabs.nl"
|
||||
stub-addr: 192.0.2.68
|
||||
stub-prime: no
|
||||
stub-first: no
|
||||
stub-tcp-upstream: no
|
||||
stub-tls-upstream: no
|
||||
stub-no-cache: no
|
||||
|
||||
forward-zone:
|
||||
name: "forward.nlnetlabs.nl"
|
||||
forward-addr: 192.0.2.68
|
||||
forward-first: no
|
||||
forward-tcp-upstream: no
|
||||
forward-tls-upstream: no
|
||||
forward-no-cache: no
|
||||
|
||||
auth-zone:
|
||||
name: "auth.nlnetlabs.nl"
|
||||
for-downstream: yes
|
||||
for-upstream: yes
|
||||
zonemd-check: no
|
||||
zonemd-reject-absence: no
|
||||
zonefile: "auth.nlnetlabs.nl.zone"
|
||||
|
||||
view:
|
||||
name: "viewname"
|
||||
local-zone: "view.nlnetlabs.nl" redirect
|
||||
local-data: "view.nlnetlabs.nl A 192.0.2.3"
|
||||
local-data-ptr: "192.0.2.3 view.nlnetlabs.nl"
|
||||
view-first: no
|
||||
|
||||
rpz:
|
||||
name: "rpz.nlnetlabs.nl"
|
||||
zonefile: "rpz.nlnetlabs.nl.zone"
|
||||
rpz-action-override: cname
|
||||
rpz-cname-override: www.example.org
|
||||
rpz-log: yes
|
||||
rpz-log-name: "example policy"
|
||||
rpz-signal-nxdomain-ra: no
|
||||
for-downstream: no
|
||||
tags: "tag3"
|
||||
16
testdata/fast_reload_most_options.tdir/fast_reload_most_options.dsc
vendored
Normal file
16
testdata/fast_reload_most_options.tdir/fast_reload_most_options.dsc
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
BaseName: fast_reload_most_options
|
||||
Version: 1.0
|
||||
Description: Test fast reload on high verbosity with most options.
|
||||
CreationDate: Fri 28 Feb 2025 15:55:15 CET
|
||||
Maintainer: Yorgos Thessalonikefs
|
||||
Category:
|
||||
Component:
|
||||
CmdDepends:
|
||||
Depends:
|
||||
Help:
|
||||
Pre: fast_reload_most_options.pre
|
||||
Post: fast_reload_most_options.post
|
||||
Test: fast_reload_most_options.test
|
||||
AuxFiles:
|
||||
Passed:
|
||||
Failure:
|
||||
11
testdata/fast_reload_most_options.tdir/fast_reload_most_options.post
vendored
Normal file
11
testdata/fast_reload_most_options.tdir/fast_reload_most_options.post
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# #-- fast_reload_most_options.post --#
|
||||
# source the master var file when it's there
|
||||
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
|
||||
# source the test var file when it's there
|
||||
[ -f .tpkg.var.test ] && source .tpkg.var.test
|
||||
#
|
||||
# do your teardown here
|
||||
. ../common.sh
|
||||
kill_pid $UNBOUND_PID
|
||||
rm -f $CONTROL_PATH/controlpipe.$CONTROL_PID
|
||||
cat unbound.log
|
||||
33
testdata/fast_reload_most_options.tdir/fast_reload_most_options.pre
vendored
Normal file
33
testdata/fast_reload_most_options.tdir/fast_reload_most_options.pre
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# #-- fast_reload_most_options.pre--#
|
||||
# source the master var file when it's there
|
||||
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
|
||||
# use .tpkg.var.test for in test variable passing
|
||||
[ -f .tpkg.var.test ] && source .tpkg.var.test
|
||||
|
||||
PRE="../.."
|
||||
. ../common.sh
|
||||
# if no threads; exit
|
||||
if grep -e "define HAVE_PTHREAD 1" -e "define HAVE_SOLARIS_THREADS 1" -e "define HAVE_WINDOWS_THREADS 1" $PRE/config.h; then
|
||||
echo "have threads"
|
||||
else
|
||||
skip_test "no threads"
|
||||
fi
|
||||
|
||||
get_random_port 1
|
||||
UNBOUND_PORT=$RND_PORT
|
||||
echo "UNBOUND_PORT=$UNBOUND_PORT" >> .tpkg.var.test
|
||||
|
||||
# make config file
|
||||
CONTROL_PATH=/tmp
|
||||
CONTROL_PID=$$
|
||||
sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's?@CONTROL_PATH\@?'$CONTROL_PATH'?' -e 's/@CONTROL_PID@/'$CONTROL_PID'/' < fast_reload_most_options.conf > ub.conf
|
||||
# start unbound in the background
|
||||
PRE="../.."
|
||||
$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
|
||||
UNBOUND_PID=$!
|
||||
echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
|
||||
echo "CONTROL_PATH=$CONTROL_PATH" >> .tpkg.var.test
|
||||
echo "CONTROL_PID=$CONTROL_PID" >> .tpkg.var.test
|
||||
|
||||
cat .tpkg.var.test
|
||||
wait_unbound_up unbound.log
|
||||
42
testdata/fast_reload_most_options.tdir/fast_reload_most_options.test
vendored
Normal file
42
testdata/fast_reload_most_options.tdir/fast_reload_most_options.test
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# #-- fast_reload_most_options.test --#
|
||||
# source the master var file when it's there
|
||||
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
|
||||
# use .tpkg.var.test for in test variable passing
|
||||
[ -f .tpkg.var.test ] && source .tpkg.var.test
|
||||
|
||||
PRE="../.."
|
||||
. ../common.sh
|
||||
|
||||
echo "> unbound-control status"
|
||||
$PRE/unbound-control -c ub.conf status
|
||||
if test $? -ne 0; then
|
||||
echo "wrong exit value."
|
||||
exit 1
|
||||
else
|
||||
echo "exit value: OK"
|
||||
fi
|
||||
|
||||
for i in {1..10}
|
||||
do
|
||||
|
||||
echo "> unbound-control fast_reload +vvdp ($i)"
|
||||
$PRE/unbound-control -c ub.conf fast_reload +vvdp 2>&1 | tee output
|
||||
if test $? -ne 0; then
|
||||
echo "wrong exit value."
|
||||
exit 1
|
||||
else
|
||||
echo "exit value: OK"
|
||||
fi
|
||||
wait_logfile unbound.log "start fast reload thread" 60
|
||||
wait_logfile unbound.log "stop fast reload thread" 60
|
||||
wait_logfile unbound.log "joined with fastreload thread" 60
|
||||
|
||||
if grep "ok" output; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "output not correct"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
exit 0
|
||||
5
testdata/fast_reload_most_options.tdir/rpz.nlnetlabs.nl.zone
vendored
Normal file
5
testdata/fast_reload_most_options.tdir/rpz.nlnetlabs.nl.zone
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
$ORIGIN rpz.nlnetlabs.nl.
|
||||
$TTL 60
|
||||
@ IN SOA a b 1 2 3 4 5
|
||||
nxdomain.nlnetlabs.nl IN CNAME .
|
||||
rpzdata.nlnetlabs.nl IN A 0.0.0.0
|
||||
20
testdata/fast_reload_thread.tdir/fast_reload_thread.conf
vendored
Normal file
20
testdata/fast_reload_thread.tdir/fast_reload_thread.conf
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
server:
|
||||
verbosity: 4
|
||||
num-threads: 1
|
||||
interface: 127.0.0.1
|
||||
port: @PORT@
|
||||
use-syslog: no
|
||||
directory: ""
|
||||
pidfile: "unbound.pid"
|
||||
chroot: ""
|
||||
username: ""
|
||||
do-not-query-localhost: no
|
||||
|
||||
forward-zone:
|
||||
name: "."
|
||||
forward-addr: "127.0.0.1@12345"
|
||||
|
||||
remote-control:
|
||||
control-enable: yes
|
||||
control-interface: @CONTROL_PATH@/controlpipe.@CONTROL_PID@
|
||||
control-use-cert: no
|
||||
16
testdata/fast_reload_thread.tdir/fast_reload_thread.dsc
vendored
Normal file
16
testdata/fast_reload_thread.tdir/fast_reload_thread.dsc
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
BaseName: fast_reload_thread
|
||||
Version: 1.0
|
||||
Description: Test fast reload thread output.
|
||||
CreationDate: Thu Jan 4 09:25:55 CET 2024
|
||||
Maintainer: dr. W.C.A. Wijngaards
|
||||
Category:
|
||||
Component:
|
||||
CmdDepends:
|
||||
Depends:
|
||||
Help:
|
||||
Pre: fast_reload_thread.pre
|
||||
Post: fast_reload_thread.post
|
||||
Test: fast_reload_thread.test
|
||||
AuxFiles:
|
||||
Passed:
|
||||
Failure:
|
||||
11
testdata/fast_reload_thread.tdir/fast_reload_thread.post
vendored
Normal file
11
testdata/fast_reload_thread.tdir/fast_reload_thread.post
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# #-- fast_reload_thread.post --#
|
||||
# source the master var file when it's there
|
||||
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
|
||||
# source the test var file when it's there
|
||||
[ -f .tpkg.var.test ] && source .tpkg.var.test
|
||||
#
|
||||
# do your teardown here
|
||||
. ../common.sh
|
||||
kill_pid $UNBOUND_PID
|
||||
rm -f $CONTROL_PATH/controlpipe.$CONTROL_PID
|
||||
cat unbound.log
|
||||
34
testdata/fast_reload_thread.tdir/fast_reload_thread.pre
vendored
Normal file
34
testdata/fast_reload_thread.tdir/fast_reload_thread.pre
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# #-- fast_reload_thread.pre--#
|
||||
# source the master var file when it's there
|
||||
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
|
||||
# use .tpkg.var.test for in test variable passing
|
||||
[ -f .tpkg.var.test ] && source .tpkg.var.test
|
||||
|
||||
PRE="../.."
|
||||
. ../common.sh
|
||||
# if no threads; exit
|
||||
if grep -e "define HAVE_PTHREAD 1" -e "define HAVE_SOLARIS_THREADS 1" -e "define HAVE_WINDOWS_THREADS 1" $PRE/config.h; then
|
||||
echo "have threads"
|
||||
else
|
||||
skip_test "no threads"
|
||||
fi
|
||||
|
||||
get_random_port 1
|
||||
UNBOUND_PORT=$RND_PORT
|
||||
echo "UNBOUND_PORT=$UNBOUND_PORT" >> .tpkg.var.test
|
||||
|
||||
# make config file
|
||||
CONTROL_PATH=/tmp
|
||||
CONTROL_PID=$$
|
||||
sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's?@CONTROL_PATH\@?'$CONTROL_PATH'?' -e 's/@CONTROL_PID@/'$CONTROL_PID'/' < fast_reload_thread.conf > ub.conf
|
||||
# start unbound in the background
|
||||
PRE="../.."
|
||||
$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
|
||||
UNBOUND_PID=$!
|
||||
echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
|
||||
echo "CONTROL_PATH=$CONTROL_PATH" >> .tpkg.var.test
|
||||
echo "CONTROL_PID=$CONTROL_PID" >> .tpkg.var.test
|
||||
|
||||
cat .tpkg.var.test
|
||||
wait_unbound_up unbound.log
|
||||
|
||||
38
testdata/fast_reload_thread.tdir/fast_reload_thread.test
vendored
Normal file
38
testdata/fast_reload_thread.tdir/fast_reload_thread.test
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# #-- fast_reload_thread.test --#
|
||||
# source the master var file when it's there
|
||||
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
|
||||
# use .tpkg.var.test for in test variable passing
|
||||
[ -f .tpkg.var.test ] && source .tpkg.var.test
|
||||
|
||||
PRE="../.."
|
||||
. ../common.sh
|
||||
|
||||
echo "> unbound-control status"
|
||||
$PRE/unbound-control -c ub.conf status
|
||||
if test $? -ne 0; then
|
||||
echo "wrong exit value."
|
||||
exit 1
|
||||
else
|
||||
echo "exit value: OK"
|
||||
fi
|
||||
|
||||
echo "> unbound-control fast_reload"
|
||||
$PRE/unbound-control -c ub.conf fast_reload 2>&1 | tee output
|
||||
if test $? -ne 0; then
|
||||
echo "wrong exit value."
|
||||
exit 1
|
||||
else
|
||||
echo "exit value: OK"
|
||||
fi
|
||||
wait_logfile unbound.log "start fast reload thread" 60
|
||||
wait_logfile unbound.log "stop fast reload thread" 60
|
||||
wait_logfile unbound.log "joined with fastreload thread" 60
|
||||
|
||||
if grep "ok" output; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "output not correct"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
|
@ -1731,6 +1731,7 @@ config_delete(struct config_file* cfg)
|
|||
config_del_strarray(cfg->tagname, cfg->num_tags);
|
||||
config_del_strbytelist(cfg->local_zone_tags);
|
||||
config_del_strbytelist(cfg->respip_tags);
|
||||
config_deldblstrlist(cfg->respip_actions);
|
||||
config_deldblstrlist(cfg->acl_view);
|
||||
config_del_strbytelist(cfg->acl_tags);
|
||||
config_deltrplstrlist(cfg->acl_tag_actions);
|
||||
|
|
@ -2834,6 +2835,13 @@ if_is_dnscrypt(const char* ifname, int default_port, int dnscrypt_port)
|
|||
#endif
|
||||
}
|
||||
|
||||
size_t
|
||||
getmem_str(char* str)
|
||||
{
|
||||
if(!str) return 0;
|
||||
return strlen(str)+1;
|
||||
}
|
||||
|
||||
int
|
||||
if_is_quic(const char* ifname, int default_port, int quic_port)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1454,4 +1454,7 @@ int cfg_has_quic(struct config_file* cfg);
|
|||
#define LINUX_IP_LOCAL_PORT_RANGE_PATH "/proc/sys/net/ipv4/ip_local_port_range"
|
||||
#endif
|
||||
|
||||
/** get memory for string */
|
||||
size_t getmem_str(char* str);
|
||||
|
||||
#endif /* UTIL_CONFIG_FILE_H */
|
||||
|
|
|
|||
23
util/edns.c
23
util/edns.c
|
|
@ -131,6 +131,29 @@ edns_string_addr_lookup(rbtree_type* tree, struct sockaddr_storage* addr,
|
|||
return (struct edns_string_addr*)addr_tree_lookup(tree, addr, addrlen);
|
||||
}
|
||||
|
||||
size_t
|
||||
edns_strings_get_mem(struct edns_strings* edns_strings)
|
||||
{
|
||||
if(!edns_strings) return 0;
|
||||
return regional_get_mem(edns_strings->region) + sizeof(*edns_strings);
|
||||
}
|
||||
|
||||
void
|
||||
edns_strings_swap_tree(struct edns_strings* edns_strings,
|
||||
struct edns_strings* data)
|
||||
{
|
||||
rbtree_type tree = edns_strings->client_strings;
|
||||
uint16_t opcode = edns_strings->client_string_opcode;
|
||||
struct regional* region = edns_strings->region;
|
||||
|
||||
edns_strings->client_strings = data->client_strings;
|
||||
edns_strings->client_string_opcode = data->client_string_opcode;
|
||||
edns_strings->region = data->region;
|
||||
data->client_strings = tree;
|
||||
data->client_string_opcode = opcode;
|
||||
data->region = region;
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
edns_cookie_server_hash(const uint8_t* in, const uint8_t* secret, int v4,
|
||||
uint8_t* hash)
|
||||
|
|
|
|||
16
util/edns.h
16
util/edns.h
|
|
@ -141,6 +141,22 @@ struct edns_string_addr*
|
|||
edns_string_addr_lookup(rbtree_type* tree, struct sockaddr_storage* addr,
|
||||
socklen_t addrlen);
|
||||
|
||||
/**
|
||||
* Get memory usage of edns strings.
|
||||
* @param edns_strings: the edns strings
|
||||
* @return memory usage
|
||||
*/
|
||||
size_t edns_strings_get_mem(struct edns_strings* edns_strings);
|
||||
|
||||
/**
|
||||
* Swap internal tree with preallocated entries.
|
||||
* @param edns_strings: the edns strings structure.
|
||||
* @param data: the data structure used to take elements from. This contains
|
||||
* the old elements on return.
|
||||
*/
|
||||
void edns_strings_swap_tree(struct edns_strings* edns_strings,
|
||||
struct edns_strings* data);
|
||||
|
||||
/**
|
||||
* Compute the interoperable DNS cookie (RFC9018) hash.
|
||||
* @param in: buffer input for the hash generation. It needs to be:
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@
|
|||
#include "libunbound/worker.h"
|
||||
#include "util/tube.h"
|
||||
#include "util/config_file.h"
|
||||
#include "daemon/remote.h"
|
||||
#ifdef UB_ON_WINDOWS
|
||||
#include "winrc/win_svc.h"
|
||||
#endif
|
||||
|
|
@ -121,6 +122,7 @@ fptr_whitelist_comm_point_raw(comm_point_callback_type *fptr)
|
|||
else if(fptr == &tube_handle_write) return 1;
|
||||
else if(fptr == &remote_accept_callback) return 1;
|
||||
else if(fptr == &remote_control_callback) return 1;
|
||||
else if(fptr == &fast_reload_client_callback) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -188,6 +190,7 @@ fptr_whitelist_event(void (*fptr)(int, short, void *))
|
|||
#ifdef HAVE_NGTCP2
|
||||
else if(fptr == &comm_point_doq_callback) return 1;
|
||||
#endif
|
||||
else if(fptr == &fast_reload_service_cb) return 1;
|
||||
#ifdef USE_DNSTAP
|
||||
else if(fptr == &dtio_output_cb) return 1;
|
||||
else if(fptr == &dtio_cmd_cb) return 1;
|
||||
|
|
|
|||
|
|
@ -177,6 +177,7 @@ struct val_anchors;
|
|||
struct val_neg_cache;
|
||||
struct iter_forwards;
|
||||
struct iter_hints;
|
||||
struct views;
|
||||
struct respip_set;
|
||||
struct respip_client_info;
|
||||
struct respip_addr_info;
|
||||
|
|
@ -524,6 +525,10 @@ struct module_env {
|
|||
* data structure.
|
||||
*/
|
||||
struct iter_hints* hints;
|
||||
/** views structure containing view tree */
|
||||
struct views* views;
|
||||
/** response-ip set with associated actions and tags. */
|
||||
struct respip_set* respip_set;
|
||||
/** module specific data. indexed by module id. */
|
||||
void* modinfo[MAX_MODULE];
|
||||
|
||||
|
|
|
|||
|
|
@ -314,6 +314,11 @@ struct ub_event_base* comm_base_internal(struct comm_base* b)
|
|||
return b->eb->base;
|
||||
}
|
||||
|
||||
struct ub_event* comm_point_internal(struct comm_point* c)
|
||||
{
|
||||
return c->ev->ev;
|
||||
}
|
||||
|
||||
/** see if errno for udp has to be logged or not uses globals */
|
||||
static int
|
||||
udp_send_errno_needs_log(struct sockaddr* addr, socklen_t addrlen)
|
||||
|
|
@ -6917,8 +6922,9 @@ comm_timer_is_set(struct comm_timer* timer)
|
|||
}
|
||||
|
||||
size_t
|
||||
comm_timer_get_mem(struct comm_timer* ATTR_UNUSED(timer))
|
||||
comm_timer_get_mem(struct comm_timer* timer)
|
||||
{
|
||||
if(!timer) return 0;
|
||||
return sizeof(struct internal_timer);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -547,6 +547,14 @@ void comm_base_set_slow_accept_handlers(struct comm_base* b,
|
|||
*/
|
||||
struct ub_event_base* comm_base_internal(struct comm_base* b);
|
||||
|
||||
/**
|
||||
* Access internal event structure. It is for use with
|
||||
* ub_winsock_tcp_wouldblock on windows.
|
||||
* @param c: comm point.
|
||||
* @return event.
|
||||
*/
|
||||
struct ub_event* comm_point_internal(struct comm_point* c);
|
||||
|
||||
/**
|
||||
* Create an UDP comm point. Calls malloc.
|
||||
* setups the structure with the parameters you provide.
|
||||
|
|
|
|||
|
|
@ -562,6 +562,36 @@ lruhash_update_space_used(struct lruhash* table, void* cb_arg, int diff_size)
|
|||
}
|
||||
}
|
||||
|
||||
void lruhash_update_space_max(struct lruhash* table, void* cb_arg, size_t max)
|
||||
{
|
||||
struct lruhash_entry *reclaimlist = NULL;
|
||||
|
||||
fptr_ok(fptr_whitelist_hash_sizefunc(table->sizefunc));
|
||||
fptr_ok(fptr_whitelist_hash_delkeyfunc(table->delkeyfunc));
|
||||
fptr_ok(fptr_whitelist_hash_deldatafunc(table->deldatafunc));
|
||||
fptr_ok(fptr_whitelist_hash_markdelfunc(table->markdelfunc));
|
||||
|
||||
if(cb_arg == NULL) cb_arg = table->cb_arg;
|
||||
|
||||
/* update space max */
|
||||
lock_quick_lock(&table->lock);
|
||||
table->space_max = max;
|
||||
|
||||
if(table->space_used > table->space_max)
|
||||
reclaim_space(table, &reclaimlist);
|
||||
|
||||
lock_quick_unlock(&table->lock);
|
||||
|
||||
/* finish reclaim if any (outside of critical region) */
|
||||
while(reclaimlist) {
|
||||
struct lruhash_entry* n = reclaimlist->overflow_next;
|
||||
void* d = reclaimlist->data;
|
||||
(*table->delkeyfunc)(reclaimlist->key, cb_arg);
|
||||
(*table->deldatafunc)(d, cb_arg);
|
||||
reclaimlist = n;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
lruhash_traverse(struct lruhash* h, int wr,
|
||||
void (*func)(struct lruhash_entry*, void*), void* arg)
|
||||
|
|
|
|||
|
|
@ -314,6 +314,16 @@ void lruhash_setmarkdel(struct lruhash* table, lruhash_markdelfunc_type md);
|
|||
void lruhash_update_space_used(struct lruhash* table, void* cb_override,
|
||||
int diff_size);
|
||||
|
||||
/**
|
||||
* Update the max space for the hashtable.
|
||||
*
|
||||
* @param table: hash table.
|
||||
* @param cb_override: if not NULL overrides the cb_arg for deletefunc.
|
||||
* @param max: the new max.
|
||||
*/
|
||||
void lruhash_update_space_max(struct lruhash* table, void* cb_override,
|
||||
size_t max);
|
||||
|
||||
/************************* getdns functions ************************/
|
||||
/*** these are used by getdns only and not by unbound. ***/
|
||||
|
||||
|
|
|
|||
|
|
@ -267,3 +267,12 @@ void get_slabhash_stats(struct slabhash* sh, long long* num, long long* collisio
|
|||
if (collisions != NULL)
|
||||
*collisions = max_collisions;
|
||||
}
|
||||
|
||||
void slabhash_adjust_size(struct slabhash* sl, size_t max)
|
||||
{
|
||||
size_t space_max = max / sl->size;
|
||||
size_t i;
|
||||
for(i=0; i<sl->size; i++) {
|
||||
lruhash_update_space_max(sl->array[i], NULL, space_max);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -221,6 +221,13 @@ size_t count_slabhash_entries(struct slabhash* table);
|
|||
void get_slabhash_stats(struct slabhash* table,
|
||||
long long* entries_count, long long* max_collisions);
|
||||
|
||||
/**
|
||||
* Adjust size of slabhash memory max
|
||||
* @param table: slabbed hash table
|
||||
* @param max: new max memory
|
||||
*/
|
||||
void slabhash_adjust_size(struct slabhash* table, size_t max);
|
||||
|
||||
/* --- test representation --- */
|
||||
/** test structure contains test key */
|
||||
struct slabhash_testkey {
|
||||
|
|
|
|||
|
|
@ -192,3 +192,14 @@ tcl_list_get_mem(struct tcl_list* tcl)
|
|||
if(!tcl) return 0;
|
||||
return sizeof(*tcl) + regional_get_mem(tcl->region);
|
||||
}
|
||||
|
||||
void tcl_list_swap_tree(struct tcl_list* tcl, struct tcl_list* data)
|
||||
{
|
||||
/* swap tree and region */
|
||||
rbtree_type oldtree = tcl->tree;
|
||||
struct regional* oldregion = tcl->region;
|
||||
tcl->tree = data->tree;
|
||||
tcl->region = data->region;
|
||||
data->tree = oldtree;
|
||||
data->region = oldregion;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,4 +127,13 @@ tcl_addr_lookup(struct tcl_list* tcl, struct sockaddr_storage* addr,
|
|||
*/
|
||||
size_t tcl_list_get_mem(struct tcl_list* tcl);
|
||||
|
||||
/**
|
||||
* Swap internal tree with preallocated entries. Caller should manage
|
||||
* tcl_addr item locks.
|
||||
* @param tcl: the tcp connection list structure.
|
||||
* @param data: the data structure used to take elements from. This contains
|
||||
* the old elements on return.
|
||||
*/
|
||||
void tcl_list_swap_tree(struct tcl_list* tcl, struct tcl_list* data);
|
||||
|
||||
#endif /* DAEMON_TCP_CONN_LIMIT_H */
|
||||
|
|
|
|||
|
|
@ -2035,25 +2035,40 @@ wait_probe_time(struct val_anchors* anchors)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/** reset worker timer */
|
||||
/** reset worker timer, at the time from wait_probe_time. */
|
||||
static void
|
||||
reset_worker_timer(struct module_env* env)
|
||||
reset_worker_timer_at(struct module_env* env, time_t next)
|
||||
{
|
||||
struct timeval tv;
|
||||
#ifndef S_SPLINT_S
|
||||
time_t next = (time_t)wait_probe_time(env->anchors);
|
||||
/* in case this is libunbound, no timer */
|
||||
if(!env->probe_timer)
|
||||
return;
|
||||
if(next > *env->now)
|
||||
tv.tv_sec = (time_t)(next - *env->now);
|
||||
else tv.tv_sec = 0;
|
||||
#else
|
||||
(void)next;
|
||||
#endif
|
||||
tv.tv_usec = 0;
|
||||
comm_timer_set(env->probe_timer, &tv);
|
||||
verbose(VERB_ALGO, "scheduled next probe in " ARG_LL "d sec", (long long)tv.tv_sec);
|
||||
}
|
||||
|
||||
/** reset worker timer. This routine manages the locks on acquiring the
|
||||
* next time for the timer. */
|
||||
static void
|
||||
reset_worker_timer(struct module_env* env)
|
||||
{
|
||||
time_t next;
|
||||
if(!env->anchors)
|
||||
return;
|
||||
lock_basic_lock(&env->anchors->lock);
|
||||
next = wait_probe_time(env->anchors);
|
||||
lock_basic_unlock(&env->anchors->lock);
|
||||
reset_worker_timer_at(env, next);
|
||||
}
|
||||
|
||||
/** set next probe for trust anchor */
|
||||
static int
|
||||
set_next_probe(struct module_env* env, struct trust_anchor* tp,
|
||||
|
|
@ -2092,7 +2107,7 @@ set_next_probe(struct module_env* env, struct trust_anchor* tp,
|
|||
verbose(VERB_ALGO, "next probe set in %d seconds",
|
||||
(int)tp->autr->next_probe_time - (int)*env->now);
|
||||
if(mold != mnew) {
|
||||
reset_worker_timer(env);
|
||||
reset_worker_timer_at(env, mnew);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -2147,7 +2162,7 @@ autr_tp_remove(struct module_env* env, struct trust_anchor* tp,
|
|||
autr_point_delete(del_tp);
|
||||
}
|
||||
if(mold != mnew) {
|
||||
reset_worker_timer(env);
|
||||
reset_worker_timer_at(env, mnew);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1173,17 +1173,53 @@ anchors_lookup(struct val_anchors* anchors,
|
|||
return result;
|
||||
}
|
||||
|
||||
/** Get memory usage of assembled key rrset */
|
||||
static size_t
|
||||
assembled_rrset_get_mem(struct ub_packed_rrset_key* pkey)
|
||||
{
|
||||
size_t s;
|
||||
if(!pkey)
|
||||
return 0;
|
||||
s = sizeof(*pkey) + pkey->rk.dname_len;
|
||||
if(pkey->entry.data) {
|
||||
struct packed_rrset_data* pd = (struct packed_rrset_data*)
|
||||
pkey->entry.data;
|
||||
s += sizeof(*pd) + pd->count * (sizeof(size_t)+sizeof(time_t)+
|
||||
sizeof(uint8_t*));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
size_t
|
||||
anchors_get_mem(struct val_anchors* anchors)
|
||||
{
|
||||
struct trust_anchor *ta;
|
||||
size_t s = sizeof(*anchors);
|
||||
if(!anchors)
|
||||
return 0;
|
||||
struct ta_key *k;
|
||||
size_t s;
|
||||
if(!anchors) return 0;
|
||||
s = sizeof(*anchors);
|
||||
lock_basic_lock(&anchors->lock);
|
||||
RBTREE_FOR(ta, struct trust_anchor*, anchors->tree) {
|
||||
lock_basic_lock(&ta->lock);
|
||||
s += sizeof(*ta) + ta->namelen;
|
||||
/* keys and so on */
|
||||
for(k = ta->keylist; k; k = k->next) {
|
||||
s += sizeof(*k) + k->len;
|
||||
}
|
||||
s += assembled_rrset_get_mem(ta->ds_rrset);
|
||||
s += assembled_rrset_get_mem(ta->dnskey_rrset);
|
||||
if(ta->autr) {
|
||||
struct autr_ta* p;
|
||||
s += sizeof(*ta->autr);
|
||||
if(ta->autr->file)
|
||||
s += strlen(ta->autr->file);
|
||||
for(p = ta->autr->keys; p; p=p->next) {
|
||||
s += sizeof(*p) + p->rr_len;
|
||||
}
|
||||
}
|
||||
lock_basic_unlock(&ta->lock);
|
||||
}
|
||||
lock_basic_unlock(&anchors->lock);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
|
@ -1346,3 +1382,22 @@ anchors_find_any_noninsecure(struct val_anchors* anchors)
|
|||
lock_basic_unlock(&anchors->lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
anchors_swap_tree(struct val_anchors* anchors, struct val_anchors* data)
|
||||
{
|
||||
rbtree_type* oldtree;
|
||||
rbtree_type oldprobe;
|
||||
|
||||
if(!anchors || !data)
|
||||
return; /* If anchors is NULL, there is no validation. */
|
||||
|
||||
oldtree = anchors->tree;
|
||||
oldprobe = anchors->autr->probe;
|
||||
|
||||
anchors->tree = data->tree;
|
||||
anchors->autr->probe = data->autr->probe;
|
||||
|
||||
data->tree = oldtree;
|
||||
data->autr->probe = oldprobe;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ struct sldns_buffer;
|
|||
* on a trust anchor and look it up again to delete it.
|
||||
*/
|
||||
struct val_anchors {
|
||||
/** lock on trees */
|
||||
/** lock on trees. It is locked in order after stubs. */
|
||||
lock_basic_type lock;
|
||||
/**
|
||||
* Anchors are store in this tree. Sort order is chosen, so that
|
||||
|
|
@ -248,4 +248,12 @@ int anchor_has_keytag(struct val_anchors* anchors, uint8_t* name, int namelabs,
|
|||
*/
|
||||
struct trust_anchor* anchors_find_any_noninsecure(struct val_anchors* anchors);
|
||||
|
||||
/**
|
||||
* Swap internal tree with preallocated entries.
|
||||
* @param anchors: anchor storage.
|
||||
* @param data: the data structure used to take elements from. This contains
|
||||
* the old elements on return.
|
||||
*/
|
||||
void anchors_swap_tree(struct val_anchors* anchors, struct val_anchors* data);
|
||||
|
||||
#endif /* VALIDATOR_VAL_ANCHOR_H */
|
||||
|
|
|
|||
|
|
@ -1554,3 +1554,12 @@ val_neg_getmsg(struct val_neg_cache* neg, struct query_info* qinfo,
|
|||
lock_basic_unlock(&neg->lock);
|
||||
return msg;
|
||||
}
|
||||
|
||||
void
|
||||
val_neg_adjust_size(struct val_neg_cache* neg, size_t max)
|
||||
{
|
||||
lock_basic_lock(&neg->lock);
|
||||
neg->max = max;
|
||||
neg_make_space(neg, 0);
|
||||
lock_basic_unlock(&neg->lock);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -299,4 +299,11 @@ struct val_neg_zone* neg_create_zone(struct val_neg_cache* neg,
|
|||
*/
|
||||
void val_neg_zone_take_inuse(struct val_neg_zone* zone);
|
||||
|
||||
/**
|
||||
* Adjust the size of the negative cache.
|
||||
* @param neg: negative cache
|
||||
* @param max: new size for max mem.
|
||||
*/
|
||||
void val_neg_adjust_size(struct val_neg_cache* neg, size_t max);
|
||||
|
||||
#endif /* VALIDATOR_VAL_NEG_H */
|
||||
|
|
|
|||
|
|
@ -91,50 +91,98 @@ update_reason_bogus(struct reply_info* rep, sldns_ede_code reason_bogus)
|
|||
|
||||
/** fill up nsec3 key iterations config entry */
|
||||
static int
|
||||
fill_nsec3_iter(struct val_env* ve, char* s, int c)
|
||||
fill_nsec3_iter(size_t** keysize, size_t** maxiter, char* s, int c)
|
||||
{
|
||||
char* e;
|
||||
int i;
|
||||
free(ve->nsec3_keysize);
|
||||
free(ve->nsec3_maxiter);
|
||||
ve->nsec3_keysize = (size_t*)calloc((size_t)c, sizeof(size_t));
|
||||
ve->nsec3_maxiter = (size_t*)calloc((size_t)c, sizeof(size_t));
|
||||
if(!ve->nsec3_keysize || !ve->nsec3_maxiter) {
|
||||
*keysize = (size_t*)calloc((size_t)c, sizeof(size_t));
|
||||
*maxiter = (size_t*)calloc((size_t)c, sizeof(size_t));
|
||||
if(!*keysize || !*maxiter) {
|
||||
free(*keysize);
|
||||
*keysize = NULL;
|
||||
free(*maxiter);
|
||||
*maxiter = NULL;
|
||||
log_err("out of memory");
|
||||
return 0;
|
||||
}
|
||||
for(i=0; i<c; i++) {
|
||||
ve->nsec3_keysize[i] = (size_t)strtol(s, &e, 10);
|
||||
(*keysize)[i] = (size_t)strtol(s, &e, 10);
|
||||
if(s == e) {
|
||||
log_err("cannot parse: %s", s);
|
||||
free(*keysize);
|
||||
*keysize = NULL;
|
||||
free(*maxiter);
|
||||
*maxiter = NULL;
|
||||
return 0;
|
||||
}
|
||||
s = e;
|
||||
ve->nsec3_maxiter[i] = (size_t)strtol(s, &e, 10);
|
||||
(*maxiter)[i] = (size_t)strtol(s, &e, 10);
|
||||
if(s == e) {
|
||||
log_err("cannot parse: %s", s);
|
||||
free(*keysize);
|
||||
*keysize = NULL;
|
||||
free(*maxiter);
|
||||
*maxiter = NULL;
|
||||
return 0;
|
||||
}
|
||||
s = e;
|
||||
if(i>0 && ve->nsec3_keysize[i-1] >= ve->nsec3_keysize[i]) {
|
||||
if(i>0 && (*keysize)[i-1] >= (*keysize)[i]) {
|
||||
log_err("nsec3 key iterations not ascending: %d %d",
|
||||
(int)ve->nsec3_keysize[i-1],
|
||||
(int)ve->nsec3_keysize[i]);
|
||||
(int)(*keysize)[i-1], (int)(*keysize)[i]);
|
||||
free(*keysize);
|
||||
*keysize = NULL;
|
||||
free(*maxiter);
|
||||
*maxiter = NULL;
|
||||
return 0;
|
||||
}
|
||||
verbose(VERB_ALGO, "validator nsec3cfg keysz %d mxiter %d",
|
||||
(int)ve->nsec3_keysize[i], (int)ve->nsec3_maxiter[i]);
|
||||
(int)(*keysize)[i], (int)(*maxiter)[i]);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
val_env_parse_key_iter(char* val_nsec3_key_iterations, size_t** keysize,
|
||||
size_t** maxiter, int* keyiter_count)
|
||||
{
|
||||
int c;
|
||||
c = cfg_count_numbers(val_nsec3_key_iterations);
|
||||
if(c < 1 || (c&1)) {
|
||||
log_err("validator: unparsable or odd nsec3 key "
|
||||
"iterations: %s", val_nsec3_key_iterations);
|
||||
return 0;
|
||||
}
|
||||
*keyiter_count = c/2;
|
||||
if(!fill_nsec3_iter(keysize, maxiter, val_nsec3_key_iterations, c/2)) {
|
||||
log_err("validator: cannot apply nsec3 key iterations");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
val_env_apply_cfg(struct val_env* val_env, struct config_file* cfg,
|
||||
size_t* keysize, size_t* maxiter, int keyiter_count)
|
||||
{
|
||||
free(val_env->nsec3_keysize);
|
||||
free(val_env->nsec3_maxiter);
|
||||
val_env->nsec3_keysize = keysize;
|
||||
val_env->nsec3_maxiter = maxiter;
|
||||
val_env->nsec3_keyiter_count = keyiter_count;
|
||||
val_env->bogus_ttl = (uint32_t)cfg->bogus_ttl;
|
||||
val_env->date_override = cfg->val_date_override;
|
||||
val_env->skew_min = cfg->val_sig_skew_min;
|
||||
val_env->skew_max = cfg->val_sig_skew_max;
|
||||
val_env->max_restart = cfg->val_max_restart;
|
||||
}
|
||||
|
||||
/** apply config settings to validator */
|
||||
static int
|
||||
val_apply_cfg(struct module_env* env, struct val_env* val_env,
|
||||
struct config_file* cfg)
|
||||
{
|
||||
int c;
|
||||
val_env->bogus_ttl = (uint32_t)cfg->bogus_ttl;
|
||||
size_t* keysize=NULL, *maxiter=NULL;
|
||||
int keyiter_count = 0;
|
||||
if(!env->anchors)
|
||||
env->anchors = anchors_create();
|
||||
if(!env->anchors) {
|
||||
|
|
@ -154,21 +202,11 @@ val_apply_cfg(struct module_env* env, struct val_env* val_env,
|
|||
log_err("validator: error in trustanchors config");
|
||||
return 0;
|
||||
}
|
||||
val_env->date_override = cfg->val_date_override;
|
||||
val_env->skew_min = cfg->val_sig_skew_min;
|
||||
val_env->skew_max = cfg->val_sig_skew_max;
|
||||
val_env->max_restart = cfg->val_max_restart;
|
||||
c = cfg_count_numbers(cfg->val_nsec3_key_iterations);
|
||||
if(c < 1 || (c&1)) {
|
||||
log_err("validator: unparsable or odd nsec3 key "
|
||||
"iterations: %s", cfg->val_nsec3_key_iterations);
|
||||
return 0;
|
||||
}
|
||||
val_env->nsec3_keyiter_count = c/2;
|
||||
if(!fill_nsec3_iter(val_env, cfg->val_nsec3_key_iterations, c/2)) {
|
||||
log_err("validator: cannot apply nsec3 key iterations");
|
||||
if(!val_env_parse_key_iter(cfg->val_nsec3_key_iterations,
|
||||
&keysize, &maxiter, &keyiter_count)) {
|
||||
return 0;
|
||||
}
|
||||
val_env_apply_cfg(val_env, cfg, keysize, maxiter, keyiter_count);
|
||||
if (env->neg_cache)
|
||||
val_env->neg_cache = env->neg_cache;
|
||||
if(!val_env->neg_cache)
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ struct key_entry_key;
|
|||
struct val_neg_cache;
|
||||
struct config_strlist;
|
||||
struct comm_timer;
|
||||
struct config_file;
|
||||
|
||||
/**
|
||||
* This is the TTL to use when a trust anchor fails to prime. A trust anchor
|
||||
|
|
@ -280,4 +281,26 @@ size_t val_get_mem(struct module_env* env, int id);
|
|||
/** Timer callback for msg signatures continue timer */
|
||||
void validate_suspend_timer_cb(void* arg);
|
||||
|
||||
/**
|
||||
* Parse the val_nsec3_key_iterations string.
|
||||
* @param val_nsec3_key_iterations: the string with nsec3 iterations config.
|
||||
* @param keysize: returns malloced key size array on success.
|
||||
* @param maxiter: returns malloced max iterations array on success.
|
||||
* @param keyiter_count: returns size of keysize and maxiter arrays.
|
||||
* @return false if it does not parse correctly.
|
||||
*/
|
||||
int val_env_parse_key_iter(char* val_nsec3_key_iterations, size_t** keysize,
|
||||
size_t** maxiter, int* keyiter_count);
|
||||
|
||||
/**
|
||||
* Apply config to validator env
|
||||
* @param val_env: validator env.
|
||||
* @param cfg: config
|
||||
* @param keysize: nsec3 key size array.
|
||||
* @param maxiter: nsec3 max iterations array.
|
||||
* @param keyiter_count: size of keysize and maxiter arrays.
|
||||
*/
|
||||
void val_env_apply_cfg(struct val_env* val_env, struct config_file* cfg,
|
||||
size_t* keysize, size_t* maxiter, int keyiter_count);
|
||||
|
||||
#endif /* VALIDATOR_VALIDATOR_H */
|
||||
|
|
|
|||
Loading…
Reference in a new issue