Compare commits

...
43 Commits
Author SHA1 Message Date
W.C.A. Wijngaards cd0a585fbe Merge branch 'master' into auth-load-thread 2026-10-13 15:56:17 +02:00
W.C.A. Wijngaards 7c624d1dcd - auth-load-thread, fix pick up of active transfer after full list.
Add unit test for list of auth transfers.
2026-10-09 15:55:21 +02:00
W.C.A. Wijngaards e23010c18e - auth-load-thread, more generic result handling of the thread. 2026-10-09 09:47:13 +02:00
W.C.A. Wijngaards ddcbc291fe - auth-load-thread, delete threads postorder. 2026-10-07 11:48:21 +02:00
W.C.A. Wijngaards a119b1abc6 - auth-load-thread, init tree after stopping authloadthreads for worker. 2026-10-07 11:26:17 +02:00
W.C.A. Wijngaards f62214e714 - auth-load-thread, account write threads, unit test for zonefile write. 2026-10-07 11:10:16 +02:00
W.C.A. Wijngaards 3d1aaae57a - auth-load-thread, track thread in worker tree insertion. Remove unused
lines from compare function.
2026-10-07 10:30:57 +02:00
W.C.A. Wijngaards 614dcbf675 - auth-load-thread, quit auth load threads on exit and reload, and also
when fast_reload changes or deletes a zone.
2026-10-06 16:51:23 +02:00
W.C.A. Wijngaards add0065c43 - auth-load-thread, write to zonefile polls for thread quit. 2026-10-06 15:07:54 +02:00
W.C.A. Wijngaards 3d53f08bd8 - auth-load-thread, write to zonefile with thread. 2026-10-06 14:39:41 +02:00
W.C.A. Wijngaards 0dcd4cd2e8 - auth-load-thread, fix unit test for auth load rpz threads check. 2026-10-06 11:45:57 +02:00
W.C.A. Wijngaards b449d6f713 - auth-load-thread, documentation for auth-task-threads and tests disable
when there is no threading.
2026-10-06 11:44:29 +02:00
W.C.A. Wijngaards 6932ae18f5 - auth-load-thread, swap rpz contents, not config. Test for auth load rpz. 2026-10-06 11:29:54 +02:00
W.C.A. Wijngaards e2537840ba - auth-load-thread, setup RPZ after IXFR and AXFR processing. 2026-10-06 10:38:32 +02:00
W.C.A. Wijngaards b425be8e10 - auth-load-thread, resume waiting transfers. 2026-10-06 09:54:03 +02:00
W.C.A. Wijngaards bb408e503c - auth-load-thread, add num auth transfers and wait_transfer list. 2026-10-05 16:44:10 +02:00
W.C.A. Wijngaards 8942d11bb3 - auth-load-thread, fix for merge and http chunk list delete. 2026-10-05 09:19:59 +02:00
W.C.A. Wijngaards cb027ae649 Merge branch 'master' into auth-load-thread 2026-10-05 09:02:28 +02:00
W.C.A. Wijngaards 48d0aea60a - auth-load-thread, unit test for auth_load_http. 2026-08-11 16:50:24 +02:00
W.C.A. Wijngaards 17bbcac979 - auth-load-thread, fix buffer free in http processing. 2026-08-11 16:50:00 +02:00
W.C.A. Wijngaards fd8ebbb19c Merge branch 'master' into auth-load-thread 2026-08-11 16:23:20 +02:00
W.C.A. Wijngaards 2adbbea365 - auth-load-thread, print thread details in log at high verbosity, 8. 2026-08-11 16:23:03 +02:00
W.C.A. Wijngaards 156c00a727 Merge branch 'master' into auth-load-thread 2026-08-10 16:42:59 +02:00
W.C.A. Wijngaards d753f95956 - auth-load-thread, print time taken during auth load processing. 2026-08-10 16:42:04 +02:00
W.C.A. Wijngaards 61d6c0e766 - auth-load-thread, implement active thread counter for auth load threads. 2026-07-07 17:21:16 +02:00
W.C.A. Wijngaards b4daa2d0fa - auth-load-thread, use define for constant for number of records before poll. 2026-07-07 16:26:42 +02:00
W.C.A. Wijngaards 425b701fb9 - auth-load-thread, fix memory leak on alloc failure when appending rrset
copy for ixfr main zone data copy.
2026-07-03 16:39:28 +02:00
W.C.A. Wijngaards 0a5cde80f1 - auth-load-thread, auth-task-threads: num config option that enables and
disables the auth load thread.
2026-07-03 14:03:15 +02:00
W.C.A. Wijngaards 58ede90fdb Merge branch 'master' into auth-load-thread 2026-07-02 15:28:24 +02:00
W.C.A. Wijngaards 55ae8da032 - auth-load-thread, basic test and fixes so it works. 2026-07-02 11:10:06 +02:00
W.C.A. Wijngaards 6bd86df72e - auth-load-thread, simplify cleanup in end transfer load process. 2026-07-02 08:55:13 +02:00
W.C.A. Wijngaards 0efd3605cc Merge branch 'master' into auth-load-thread 2026-07-01 16:54:55 +02:00
W.C.A. Wijngaards a2f2f53ef9 - auth-load-thread, process end of successful transfer. 2026-07-01 16:54:36 +02:00
W.C.A. Wijngaards b5a03093f6 - auth-load-thread, check for quit during the processing. 2026-07-01 14:41:40 +02:00
W.C.A. Wijngaards 8eba898135 - auth-load-thread, process AXFR, by loading, swap in, delete of old. 2026-07-01 14:27:31 +02:00
W.C.A. Wijngaards 56f66de89f - auth-load-thread, process IXFR, by making a copy, adjust changes, swap in. 2026-07-01 13:05:19 +02:00
W.C.A. Wijngaards 2fbaee2255 - auth-load-thread, process transfer content and swap result back in. 2026-06-30 16:53:27 +02:00
W.C.A. Wijngaards a122490461 - auth-load-thread, poll for quit and process load transfer end. 2026-06-29 16:52:20 +02:00
W.C.A. Wijngaards 7826b4f306 Merge branch 'master' into auth-load-thread 2026-06-29 16:00:01 +02:00
W.C.A. Wijngaards 380994219f - auth-load-thread, make and run auth load thread. 2026-06-26 17:11:12 +02:00
W.C.A. Wijngaards 153accb8de - auth-load-thread, put create_socketpair and sock_poll_timeout into
util/net_help.h
2026-06-26 15:22:08 +02:00
W.C.A. Wijngaards 7bb1c62263 - auth-load-thread, add authload.c to Makefile.in. 2026-06-26 14:27:12 +02:00
W.C.A. Wijngaards 1578b6e180 - auth-load-thread, add services/authload.c and services/authload.h 2026-06-26 14:00:04 +02:00
55 changed files with 3990 additions and 524 deletions
+4 -2
View File
@@ -125,7 +125,7 @@ services/localzone.c services/mesh.c services/modstack.c services/view.c \
services/rpz.c util/rfc_1982.c \
services/outbound_list.c services/outside_network.c util/alloc.c \
util/config_file.c util/configlexer.c util/configparser.c \
util/shm_side/shm_main.c services/authzone.c \
util/shm_side/shm_main.c services/authzone.c services/authload.c \
util/fptr_wlist.c util/locks.c util/log.c util/mini_event.c util/module.c \
util/netevent.c util/net_help.c util/random.c util/rbtree.c util/regional.c \
util/rtt.c util/siphash.c util/edns.c util/storage/dnstree.c util/storage/lookup3.c \
@@ -152,7 +152,8 @@ autotrust.lo val_anchor.lo rpz.lo rfc_1982.lo proxy_protocol.lo \
validator.lo val_kcache.lo val_kentry.lo val_neg.lo val_nsec3.lo val_nsec.lo \
val_secalgo.lo val_sigcrypt.lo val_utils.lo dns64.lo $(CACHEDB_OBJ) authzone.lo \
$(SUBNET_OBJ) $(PYTHONMOD_OBJ) $(CHECKLOCK_OBJ) $(DNSTAP_OBJ) $(DNSCRYPT_OBJ) \
$(IPSECMOD_OBJ) $(IPSET_OBJ) $(DYNLIBMOD_OBJ) respip.lo timeval_func.lo
$(IPSECMOD_OBJ) $(IPSET_OBJ) $(DYNLIBMOD_OBJ) respip.lo timeval_func.lo \
authload.lo
COMMON_OBJ_WITHOUT_UB_EVENT=$(COMMON_OBJ_WITHOUT_NETCALL) netevent.lo listen_dnsport.lo \
outside_network.lo
COMMON_OBJ=$(COMMON_OBJ_WITHOUT_UB_EVENT) ub_event.lo
@@ -721,6 +722,7 @@ depend:
ipset.lo ipset.o: $(srcdir)/ipset/ipset.c
doqclient.lo doqclient.o: $(srcdir)/testcode/doqclient.c
unitdoq.lo unitdoq.o: $(srcdir)/testcode/unitdoq.c
authload.lo authload.o: $(srcdir)/services/authload.c
# Dependencies
dns.lo dns.o: $(srcdir)/services/cache/dns.c config.h $(srcdir)/iterator/iter_delegpt.h $(srcdir)/util/log.h \
+14
View File
@@ -86,6 +86,7 @@
#include "services/view.h"
#include "services/modstack.h"
#include "services/authzone.h"
#include "services/authload.h"
#include "util/module.h"
#include "util/random.h"
#include "util/tube.h"
@@ -590,6 +591,17 @@ daemon_init(void)
free(daemon);
return NULL;
}
if(!(daemon->auth_load_info = auth_load_info_create())) {
edns_strings_delete(daemon->env->edns_strings);
auth_zones_delete(daemon->env->auth_zones);
acl_list_delete(daemon->acl_interface);
acl_list_delete(daemon->acl);
tcl_list_delete(daemon->tcl);
edns_known_options_delete(daemon->env);
free(daemon->env);
free(daemon);
return NULL;
}
return daemon;
}
@@ -1164,6 +1176,7 @@ daemon_fork(struct daemon* daemon)
/* we exited! a signal happened! Stop other threads */
daemon_stop_others(daemon);
auth_load_stop_threads(daemon);
/* Shutdown SHM */
shm_main_shutdown(daemon);
@@ -1262,6 +1275,7 @@ daemon_delete(struct daemon* daemon)
edns_strings_delete(daemon->env->edns_strings);
auth_zones_delete(daemon->env->auth_zones);
}
auth_load_info_delete(daemon->auth_load_info);
ub_randfree(daemon->rand);
alloc_clear(&daemon->superalloc);
acl_list_delete(daemon->acl);
+3
View File
@@ -62,6 +62,7 @@ struct doq_table;
struct cookie_secrets;
struct fast_reload_thread;
struct fast_reload_printq;
struct auth_load_general_info;
struct shared_ports;
#include "dnstap/dnstap_config.h"
@@ -191,6 +192,8 @@ struct daemon {
int fast_reload_tcl_has_changes;
/** config file name */
char* cfgfile;
/** Auth load threads, the number of active threads. */
struct auth_load_general_info* auth_load_info;
};
/**
+11 -369
View File
@@ -73,6 +73,7 @@
#include "services/mesh.h"
#include "services/localzone.h"
#include "services/authzone.h"
#include "services/authload.h"
#include "services/rpz.h"
#include "util/storage/slabhash.h"
#include "util/fptr_wlist.h"
@@ -115,9 +116,6 @@
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
/* just for portability */
#ifdef SQ
@@ -4466,92 +4464,6 @@ int remote_control_callback(struct comm_point* c, void* arg, int err,
return 0;
}
/**
* This routine polls a socket for readiness.
* @param fd: file descriptor, -1 uses no fd for a timer only.
* @param timeout: time in msec to wait. 0 means nonblocking test,
* -1 waits blocking for events.
* @param pollin: check for input event.
* @param pollout: check for output event.
* @param event: output variable, set to true if the event happens.
* It is false if there was an error or timeout.
* @return false is system call failure, also logged.
*/
static int
sock_poll_timeout(int fd, int timeout, int pollin, int pollout, int* event)
{
int loopcount = 0;
/* Loop if the system call returns an errno to do so, like EINTR. */
log_assert(pollin || pollout);
while(1) {
struct pollfd p, *fds;
int nfds, ret;
if(++loopcount > IPC_LOOP_MAX) {
log_err("sock_poll_timeout: loop");
if(event)
*event = 0;
return 0;
}
if(fd == -1) {
fds = NULL;
nfds = 0;
} else {
fds = &p;
nfds = 1;
memset(&p, 0, sizeof(p));
p.fd = fd;
#ifndef USE_WINSOCK
p.events = POLLERR
| POLLHUP
;
#endif
if(pollin)
p.events |= POLLIN;
if(pollout)
p.events |= POLLOUT;
}
#ifndef USE_WINSOCK
ret = poll(fds, nfds, timeout);
#else
if(fds == NULL) {
Sleep(timeout);
ret = 0;
} else {
ret = WSAPoll(fds, nfds, timeout);
}
#endif
if(ret == -1) {
#ifndef USE_WINSOCK
if(
errno == EINTR || errno == EAGAIN
# ifdef EWOULDBLOCK
|| errno == EWOULDBLOCK
# endif
) continue; /* Try again. */
#endif
/* For WSAPoll we only get errors here:
* o WSAENETDOWN
* o WSAEFAULT
* o WSAEINVAL
* o WSAENOBUFS
*/
log_err("poll: %s", sock_strerror(errno));
if(event)
*event = 0;
return 0;
} else if(ret == 0) {
/* Timeout */
if(event)
*event = 0;
return 1;
}
break;
}
if(event)
*event = 1;
return 1;
}
/** fast reload convert fast reload notification status to string */
static const char*
fr_notification_to_string(enum fast_reload_notification status)
@@ -6365,6 +6277,7 @@ fr_atomic_copy_cfg(struct config_file* oldcfg, struct config_file* cfg,
COPY_VAR_ptr(acls);
COPY_VAR_int(donotquery_localhost);
COPY_VAR_ptr(tcp_connection_limits);
COPY_VAR_int(auth_task_threads);
COPY_VAR_int(harden_short_bufsize);
COPY_VAR_int(harden_large_queries);
COPY_VAR_int(harden_glue);
@@ -7156,286 +7069,6 @@ done_error:
}
#endif /* !THREADS_DISABLED */
/** create a socketpair for bidirectional communication, false on failure */
static int
create_socketpair(int* pair, struct ub_randstate* rand)
{
#ifndef USE_WINSOCK
if(socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
log_err("socketpair: %s", strerror(errno));
return 0;
}
(void)rand;
#else
struct sockaddr_in addr, baddr, accaddr, connaddr;
socklen_t baddrlen, accaddrlen, connaddrlen;
uint8_t localhost[] = {127, 0, 0, 1};
uint8_t nonce[16], recvnonce[16];
size_t i;
int lst, pollin_event, bcount, loopcount;
int connect_poll_timeout = 200; /* msec to wait for connection */
ssize_t ret;
pair[0] = -1;
pair[1] = -1;
for(i=0; i<sizeof(nonce); i++) {
nonce[i] = ub_random_max(rand, 256);
}
lst = socket(AF_INET, SOCK_STREAM, 0);
if(lst == -1) {
log_err("create_socketpair: socket: %s", sock_strerror(errno));
return 0;
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = 0;
memcpy(&addr.sin_addr, localhost, 4);
if(bind(lst, (struct sockaddr*)&addr, (socklen_t)sizeof(addr))
== -1) {
log_err("create socketpair: bind: %s", sock_strerror(errno));
sock_close(lst);
return 0;
}
if(listen(lst, 12) == -1) {
log_err("create socketpair: listen: %s", sock_strerror(errno));
sock_close(lst);
return 0;
}
pair[1] = socket(AF_INET, SOCK_STREAM, 0);
if(pair[1] == -1) {
log_err("create socketpair: socket: %s", sock_strerror(errno));
sock_close(lst);
return 0;
}
baddrlen = (socklen_t)sizeof(baddr);
if(getsockname(lst, (struct sockaddr*)&baddr, &baddrlen) == -1) {
log_err("create socketpair: getsockname: %s",
sock_strerror(errno));
sock_close(lst);
sock_close(pair[1]);
pair[1] = -1;
return 0;
}
if(baddrlen > (socklen_t)sizeof(baddr)) {
log_err("create socketpair: getsockname returned addr too big");
sock_close(lst);
sock_close(pair[1]);
pair[1] = -1;
return 0;
}
/* the socket is blocking */
if(connect(pair[1], (struct sockaddr*)&baddr, baddrlen) == -1) {
log_err("create socketpair: connect: %s",
sock_strerror(errno));
sock_close(lst);
sock_close(pair[1]);
pair[1] = -1;
return 0;
}
if(!sock_poll_timeout(lst, connect_poll_timeout, 1, 0, &pollin_event)) {
log_err("create socketpair: poll for accept failed: %s",
sock_strerror(errno));
sock_close(lst);
sock_close(pair[1]);
pair[1] = -1;
return 0;
}
if(!pollin_event) {
log_err("create socketpair: poll timeout for accept");
sock_close(lst);
sock_close(pair[1]);
pair[1] = -1;
return 0;
}
accaddrlen = (socklen_t)sizeof(accaddr);
pair[0] = accept(lst, (struct sockaddr*)&accaddr, &accaddrlen);
if(pair[0] == -1) {
log_err("create socketpair: accept: %s", sock_strerror(errno));
sock_close(lst);
sock_close(pair[1]);
pair[1] = -1;
return 0;
}
if(accaddrlen > (socklen_t)sizeof(accaddr)) {
log_err("create socketpair: accept returned addr too big");
sock_close(lst);
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
if(accaddr.sin_family != AF_INET ||
memcmp(localhost, &accaddr.sin_addr, 4) != 0) {
log_err("create socketpair: accept from wrong address");
sock_close(lst);
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
connaddrlen = (socklen_t)sizeof(connaddr);
if(getsockname(pair[1], (struct sockaddr*)&connaddr, &connaddrlen)
== -1) {
log_err("create socketpair: getsockname connectedaddr: %s",
sock_strerror(errno));
sock_close(lst);
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
if(connaddrlen > (socklen_t)sizeof(connaddr)) {
log_err("create socketpair: getsockname connectedaddr returned addr too big");
sock_close(lst);
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
if(connaddr.sin_family != AF_INET ||
memcmp(localhost, &connaddr.sin_addr, 4) != 0) {
log_err("create socketpair: getsockname connectedaddr returned wrong address");
sock_close(lst);
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
if(accaddr.sin_port != connaddr.sin_port) {
log_err("create socketpair: accept from wrong port");
sock_close(lst);
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
sock_close(lst);
loopcount = 0;
bcount = 0;
while(1) {
if(++loopcount > IPC_LOOP_MAX) {
log_err("create socketpair: send failed due to loop");
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
ret = send(pair[1], (void*)(nonce+bcount),
sizeof(nonce)-bcount, 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("create socketpair: send: %s", sock_strerror(errno));
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
} else if(ret+(ssize_t)bcount != sizeof(nonce)) {
bcount += ret;
if((size_t)bcount < sizeof(nonce))
continue;
}
break;
}
if(!sock_poll_timeout(pair[0], connect_poll_timeout, 1, 0, &pollin_event)) {
log_err("create socketpair: poll failed: %s",
sock_strerror(errno));
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
if(!pollin_event) {
log_err("create socketpair: poll timeout for recv");
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
loopcount = 0;
bcount = 0;
while(1) {
if(++loopcount > IPC_LOOP_MAX) {
log_err("create socketpair: recv failed due to loop");
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
ret = recv(pair[0], (void*)(recvnonce+bcount),
sizeof(nonce)-bcount, 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("create socketpair: recv: %s", sock_strerror(errno));
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
} else if(ret == 0) {
log_err("create socketpair: stream closed");
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
} else if(ret+(ssize_t)bcount != sizeof(nonce)) {
bcount += ret;
if((size_t)bcount < sizeof(nonce))
continue;
}
break;
}
if(memcmp(nonce, recvnonce, sizeof(nonce)) != 0) {
log_err("create socketpair: recv wrong nonce");
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
#endif
return 1;
}
/** fast reload thread. setup the thread info */
static int
fast_reload_thread_setup(struct worker* worker, int fr_verb, int fr_nopause,
@@ -7812,6 +7445,13 @@ auth_zone_zonemd_stop_lookup(struct auth_zone* z, struct mesh_area* mesh)
{
struct query_info qinfo;
uint16_t qflags = BIT_RD;
if(z->zonemd_transfer_active) {
auth_load_info_release_transfer_in_progress(
z->zonemd_callback_env);
auth_load_schedule_waiting_pickup(z->zonemd_callback_env);
z->zonemd_transfer_active = 0;
}
qinfo.qname_len = z->namelen;
qinfo.qname = z->name;
qinfo.qclass = z->dclass;
@@ -7893,6 +7533,8 @@ fr_worker_auth_del(struct worker* worker, struct fast_reload_auth_change* item,
released = 1;
xfr_disown_tasks(xfr, worker);
}
auth_load_del_zone_tasks(worker, xfr->name, xfr->namelen,
xfr->dclass);
lock_basic_unlock(&xfr->lock);
}
+2
View File
@@ -59,6 +59,7 @@
#include "services/cache/infra.h"
#include "services/cache/dns.h"
#include "services/authzone.h"
#include "services/authload.h"
#include "services/mesh.h"
#include "services/localzone.h"
#include "services/rpz.h"
@@ -2262,6 +2263,7 @@ worker_create(struct daemon* daemon, int id)
free(worker);
return NULL;
}
rbtree_init(&worker->auth_load_tree, auth_load_tree_cmp);
explicit_bzero(&seed, sizeof(seed));
return worker;
}
+3
View File
@@ -47,6 +47,7 @@
#include "util/netevent.h"
#include "util/locks.h"
#include "util/alloc.h"
#include "util/rbtree.h"
#include "util/data/msgreply.h"
#include "util/data/msgparse.h"
#include "daemon/stats.h"
@@ -135,6 +136,8 @@ struct worker {
#endif
/** reuse existing cache on reload if other conditions allow it. */
int reuse_cache;
/** tree of auth load threads, attached to this worker. */
rbtree_type auth_load_tree;
};
/**
+2
View File
@@ -1171,6 +1171,8 @@ server:
# Timeout in milliseconds for TCP queries to auth servers.
# tcp-auth-query-timeout: 3000
# Number of threads to use to load auth-zones (and RPZ). 0 disables.
# auth-task-threads: 0
# Python config section. To enable:
# o use --with-pythonmodule to configure before compiling.
+18
View File
@@ -3520,6 +3520,24 @@ These options are part of the ``server:`` section.
Default: no
@@UAHL@unbound.conf@auth-task-threads@@: *<number of threads>*
If nonzero, the number of threads to start to process zone transfers
for authority zones, and also RPZ zones.
The zone transfer is processed in a thread, that does not interrupt
the resolver.
For RPZ zones that means the old RPZ zone continues to be used, while
the task is processed.
The thread allocates the new zone data, and this keeps another copy of
the zone data in memory during processing.
The result is swapped into the resolver when the thread is done.
The value 0 disables the threading, one of the worker threads performs
the processing. Without threading enabled, use the value 0.
Default: 0
.. _unbound.conf.remote:
Remote Control Options
+49
View File
@@ -0,0 +1,49 @@
/*
* libunbound/authload.h - prototypes for auth load methods.
*
* Copyright (c) 2026, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
*
* This file declares the methods that must be implemented to use the
* auth load service.
*/
#ifndef LIBUNBOUND_AUTHLOAD_H
#define LIBUNBOUND_AUTHLOAD_H
/** The worker routine that services the auth load connection. */
void worker_auth_load_service_cb(int fd, short bits, void* arg);
#endif /* LIBUNBOUND_AUTHLOAD_H */
+1542
View File
File diff suppressed because it is too large Load Diff
+301
View File
@@ -0,0 +1,301 @@
/*
* services/authload.h - authoritative zone load thread
*
* Copyright (c) 2026, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
*
* This file contains the auth load thread. This loads authority zone
* and RPZ zone information in a thread, in a separate memory structure.
* When it is done, the information is swapped over to the running server.
*/
#ifndef SERVICES_AUTHLOAD_H
#define SERVICES_AUTHLOAD_H
#include "util/locks.h"
#include "util/rbtree.h"
struct worker;
struct daemon;
struct auth_xfer;
struct module_env;
struct auth_load_task;
struct comm_timer;
/**
* General information for auth load threads. The number of active threads.
*/
struct auth_load_general_info {
/** lock on this structure. It is after the auth_zones lock, and
* after the auth_xfer locks. */
lock_basic_type lock;
/** The number of active auth load threads. */
int num_auth_load_threads;
/** The number of active downloads, zone transfers in progress.
* These are going to need an auth load thread when done. The counter
* is decremented when the thread and transfer have completed. */
int num_auth_transfers;
/** The auth zone xfer transfer wait list */
struct auth_xfer* wait_transfer_list;
/** The last item of the wait_transfer list. */
struct auth_xfer* wait_transfer_last;
/** To resume from a waiting item, the callback, at zero timeout is
* used. That breaks out of callbacks and handles the items there.
* If the timer is set, this is true. */
int resume_timer_enabled;
/** The resume timer for the wait_transfer list. */
struct comm_timer* resume_timer;
/** The worker env for the resume timer. It is set in the event base
* of that worker. */
struct module_env* resume_env;
};
/**
* The types of notifications that the auth load thread sends around.
*/
enum auth_load_notification_type {
/** This is sent to make the auth load thread perform exit */
auth_load_notification_exit
};
/**
* The auth load thread. The thread runs to load authority zone information
* and RPZ information into memory. It loads into a copy. Then that is swapped
* over to the running server. This keeps the server responsive while the
* information is loaded.
*/
struct auth_load_thread {
/** the thread number for the thread,
* must be first to cast thread arg to int* in checklock code. */
int threadnum;
/** thread id, of the io thread */
ub_thread_type tid;
#ifdef HAVE_GETTID
/** thread tid, the LWP id */
pid_t thread_tid;
/** if logging should include the LWP id */
int thread_tid_log;
#endif
/** communication socket pair, that sends commands */
int commpair[2];
/** if the thread has to quit */
int need_to_quit;
/** the event that listens on the worker to commpair,
* it receives content from the auth load thread. */
void* service_event;
/** if the event that listens on the worker has
* been added to the comm base. */
int service_event_is_added;
/** the worker that the auth load is connected to */
struct worker* worker;
/** if the thread is inserted in the tree at the worker. */
int tree_inserted;
/** the rbtree node for the worker tree of auth load threads. */
rbnode_type node;
/** The task that the thread is working on */
struct auth_load_task* task;
};
/**
* The types of tasks that the auth load can perform.
*/
enum auth_load_task_type {
AUTH_LOAD_TASK_TRANSFER,
AUTH_LOAD_TASK_ZONEFILE_READ,
AUTH_LOAD_TASK_ZONEFILE_WRITE,
AUTH_LOAD_TASK_HTTPCHUNKS
};
/**
* The task for the auth load. The task can be to load a zone transfer, AXFR,
* IXFR, from zonefile, and from a http read, from chunks.
*/
struct auth_load_task {
/** The type of the task */
enum auth_load_task_type task_type;
/** The task is connected with this worker */
struct worker* worker;
/** The zone name */
uint8_t* name;
/** The zone namelen */
size_t namelen;
/** The zone class */
uint16_t dclass;
/** name of the host that the transfer comes from. */
char* host;
/** file part of the url that the transfer comes from, or NULL. */
char* file;
/** Set if the host is http transfer, if false it is AXFR or IXFR. */
int on_http;
/** Set if the transfer is doing IXFR */
int on_ixfr;
/** Set if the transfer is an IXFR but we detected an AXFR contents */
int on_ixfr_is_axfr;
/** The zone is an rpz zone. */
int is_rpz;
/** Set if the ixfr failed. (So that there can be backoff to AXFR). */
int ixfr_fail;
/** current serial (from SOA), if we have no zone, 0
* This is for checking the IXFR result. */
uint32_t serial;
/** the data chunks, or NULL, to process. */
struct auth_chunk* chunks_first;
/** last data chunk */
struct auth_chunk* chunks_last;
/** size of data in data chunks. */
size_t chunks_total;
/** time taken for the task */
struct timeval time_taken;
/** time taken for the reload part of the task */
struct timeval time_reload;
/** memory used for the task */
size_t mem_used;
};
/**
* Add a new task to be performed by the auth load thread.
* It starts a thread.
* @param xfr: zone transfer to start for.
* @param worker: worker that is connected to the task.
* @return false on failure.
*/
int auth_load_add_task_xfr(struct auth_xfer* xfr, struct worker* worker);
/**
* Add a new task to be performed by the auth load thread.
* It starts a thread. This writes to zonefile.
* @param name: name of zone, wireformat.
* @param namelen: length of name.
* @param dclass: class of the zone.
* @param env: the module env.
* @param chunk_list: for writes after http, the chunk list with data.
* @return false on failure to create the thread.
*/
int auth_load_add_task_write(uint8_t* name, size_t namelen, uint16_t dclass,
struct module_env* env, struct auth_chunk* chunk_list);
/** See if there is a quit signal, true if so. */
int auth_load_thread_poll_for_quit(struct auth_load_thread* thr);
/**
* Create auth load info structure.
* @return NULL on failure.
*/
struct auth_load_general_info* auth_load_info_create(void);
/**
* Delete auth load info structure.
* @param auth_load_info: to delete.
*/
void auth_load_info_delete(struct auth_load_general_info* auth_load_info);
/**
* Grab a new thread from the auth load count.
* @param env: with auth_load_info with the active thread count.
* and config file, with configured maximum.
* @return false on failure, like too many active, true if successful.
*/
int auth_load_info_grab_thread(struct module_env* env);
/**
* Release thread from auth load count. It is done.
* @param env: with auth_load_info with the active thread count.
*/
void auth_load_info_release_thread(struct module_env* env);
/**
* Grab a new transfer in progress, this is limited by the auth load count.
* @param env: with auth_load_info with the active transfer number.
* and config file, with configured maximum.
* @return false on failure, like too many active, true if successful.
*/
int auth_load_info_grab_transfer_in_progress(struct module_env* env);
/**
* Release transfer from active count. It is done.
* @param env: with auth_load_info with the active transfer count.
*/
void auth_load_info_release_transfer_in_progress(struct module_env* env);
/**
* Make transfer active in the in progress transfer count.
* @param xfr: the xfr is in progress
* @return false if not possible.
*/
int xfr_transfer_grab_active(struct auth_xfer* xfr);
/**
* Release active transfer from in progress transfer count.
* @param xfr: the xfr is no longer in progress.
*/
void xfr_transfer_release_active(struct auth_xfer* xfr);
/**
* Add transfer to wait_transfer list. It can not become active right now.
* @param xfr: the xfr is put on the wait_transfer list.
*/
void xfr_transfer_wait_active(struct auth_xfer* xfr);
/**
* Remove xfr from wait_transfer list
* @param xfr: the xfr is removed from the wait_transfer list.
*/
void xfr_transfer_remove_wait_transfer_list(struct auth_xfer* xfr);
/** The timer callback for the wait_transfer resume timer. */
void auth_load_resume_timer_cb(void* arg);
/** Schedule pick up of waiting transfers. */
void auth_load_schedule_waiting_pickup(struct module_env* env);
/** Compare auth load tree entries, in the worker auth load tree. */
int auth_load_tree_cmp(const void* a, const void* b);
/** Delete tasks for the zone. The write and xfr tasks for that name, class
* are sent a quit signal, and the thread is joined, as it exits. */
void auth_load_del_zone_tasks(struct worker* worker, uint8_t* name,
size_t namelen, uint16_t dclass);
/** Stop all the auth load threads. */
void auth_load_stop_threads(struct daemon* daemon);
#endif /* SERVICES_AUTHLOAD_H */
+567 -143
View File
File diff suppressed because it is too large Load Diff
+66 -1
View File
@@ -65,6 +65,7 @@ struct auth_probe;
struct auth_transfer;
struct auth_master;
struct auth_chunk;
struct auth_load_thread;
/**
* Authoritative zones, shared.
@@ -150,6 +151,8 @@ struct auth_zone {
int zonemd_callback_perform_write;
/** chunklist to write for chunked transfer. */
struct auth_chunk* perform_write_chunk_list;
/** The zonemd transfer is an active transfer (for auth load info) */
int zonemd_transfer_active;
/** zone has been deleted */
int zone_deleted;
/** deletelist pointer, unused normally except during delete */
@@ -404,6 +407,15 @@ struct auth_transfer {
size_t chunks_total;
/** start time of the transfer */
struct timeval start_time;
/** if the transfer is active and in the in progress count. */
int active_transfer;
/** if the transfer is on the wait_transfer list (it waits to
* become active). */
int on_wait_transfer_list;
/** If on the wait_transfer list, the previous list item. */
struct auth_xfer* wait_transfer_prev;
/** If on the wait_transfer list, the next list item. */
struct auth_xfer* wait_transfer_next;
/** list of upstream masters for this zone, from config */
struct auth_master* masters;
@@ -545,7 +557,15 @@ void auth_zones_delete(struct auth_zones* az);
/**
* Write auth zone data to file, in zonefile format.
*/
int auth_zone_write_file(struct auth_zone* z, const char* fname);
int auth_zone_write_file(struct auth_zone* z, const char* fname,
struct auth_load_thread* thr);
/** write to zonefile after zone has updated, reacquires z readlock.
* The chunk list is freed on return.
* If the zone is gone, chunk_list is freed (if non NULL). */
void zone_write_after_update_reacq(uint8_t* name, size_t namelen,
uint16_t dclass, struct module_env* env,
struct auth_chunk* chunk_list, struct auth_load_thread* thr);
/**
* Use auth zones to lookup the answer to a query.
@@ -861,4 +881,49 @@ int chunkline_count_parens(struct sldns_buffer* buf, size_t start);
/** Clear data in auth zone */
void auth_zone_clear_data(struct auth_zone* z);
/** Get memory usage of auth zone */
size_t auth_zone_get_mem(struct auth_zone* z);
/** create domain with the given name */
struct auth_data* az_domain_create(struct auth_zone* z, uint8_t* nm,
size_t nmlen);
/** helper traverse to delete zones */
void auth_data_del(rbnode_type* n, void* arg);
/** Pick up xfr task from wait_transfer resumption. xfr is locked on entry,
* unlocked at return. */
void xfr_pick_up_transfer(struct auth_xfer* xfr, struct module_env* env);
/** Handle the end of an auth load task. */
void xfr_process_load_end_transfer(struct auth_xfer* xfr,
struct module_env* env, uint8_t status, int ixfr_fail,
struct timeval* time_taken, struct timeval* time_reload,
size_t mem_used, size_t chunks_total, struct auth_chunk* chunk_list);
/** Handle the end of an auth load task to write. */
void auth_zone_process_load_end_write(struct module_env* env);
/** Log preview of http transfer */
void xfr_http_preview(const char* file, struct auth_chunk* chunk_list);
/** Check syntax of first part of the http download */
int xfr_http_syntax_check(uint8_t* name, size_t namelen, uint16_t dclass,
const char* host, const char* file, struct auth_chunk* chunk_list,
struct sldns_buffer* scratch_buffer);
/** Apply http transfer to auth_zone */
int xfr_apply_http(uint8_t* name, size_t namelen, const char* host,
const char* file, struct auth_chunk* chunk_list, struct auth_zone* z,
struct sldns_buffer* scratch_buffer, struct auth_load_thread* thr);
/** Apply IXFR transfer to auth_zone */
int xfr_apply_ixfr(struct auth_chunk* chunk_list, uint32_t xfr_serial,
struct auth_zone* z, struct sldns_buffer* scratch_buffer,
struct auth_load_thread* thr);
/** Apply AXFR transfer to auth_zone */
int xfr_apply_axfr(struct auth_chunk* chunk_list, struct auth_zone* z,
struct sldns_buffer* scratch_buffer, struct auth_load_thread* thr);
#endif /* SERVICES_AUTHZONE_H */
+33 -8
View File
@@ -588,16 +588,11 @@ rpz_apply_cfg_elements(struct rpz* r, struct config_auth* p)
}
struct rpz*
rpz_create(struct config_auth* p)
rpz_create_empty(void)
{
struct rpz* r = calloc(1, sizeof(*r));
if(!r)
goto err;
r->region = regional_create_custom(sizeof(struct regional));
if(!r->region) {
goto err;
}
return NULL;
if(!(r->local_zones = local_zones_create())){
goto err;
@@ -621,6 +616,35 @@ rpz_create(struct config_auth* p)
if(r->ns_set == NULL) {
goto err;
}
return r;
err:
if(r) {
if(r->local_zones)
local_zones_delete(r->local_zones);
if(r->nsdname_zones)
local_zones_delete(r->nsdname_zones);
if(r->respip_set)
respip_set_delete(r->respip_set);
if(r->client_set != NULL)
rpz_clientip_synthesized_set_delete(r->client_set);
if(r->ns_set != NULL)
rpz_clientip_synthesized_set_delete(r->ns_set);
free(r);
}
return NULL;
}
struct rpz*
rpz_create(struct config_auth* p)
{
struct rpz* r = rpz_create_empty();
if(!r)
goto err;
r->region = regional_create_custom(sizeof(struct regional));
if(!r->region) {
goto err;
}
if(!rpz_apply_cfg_elements(r, p))
goto err;
@@ -2870,7 +2894,8 @@ size_t rpz_get_mem(struct rpz* r)
m += r->taglistlen;
if(r->log_name)
m += strlen(r->log_name) + 1;
m += regional_get_mem(r->region);
if(r->region)
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);
+3
View File
@@ -219,6 +219,9 @@ void rpz_delete(struct rpz* r);
*/
int rpz_clear(struct rpz* r);
/** Create empty RPZ structure, useful as a proxy for entering data. */
struct rpz* rpz_create_empty(void);
/**
* Create RPZ. RPZ must be added to linked list after creation.
* @return: the newly created RPZ
+3
View File
@@ -264,6 +264,9 @@ setup_config(FILE* in, int* lineno, int* pass_argc, char* pass_argv[])
fprintf(cfg, " pidfile: \"\"\n");
fprintf(cfg, " val-log-level: 2\n");
fprintf(cfg, " log-servfail: yes\n");
/* the extra thread needs pipe communication that is not available
* from fake_event calls. So auth-task-threads: 0 disables them. */
fprintf(cfg, " auth-task-threads: 0\n");
fprintf(cfg, "remote-control: control-enable: no\n");
while(fgets(line, MAX_LINE_LEN-1, in)) {
parse = line;
+1 -1
View File
@@ -735,7 +735,7 @@ check_read_exact(const char* name, const char* zone)
z = authtest_addzone(az, name, fname);
unit_assert(z);
outf = create_tmp_file(NULL);
if(!auth_zone_write_file(z, outf)) {
if(!auth_zone_write_file(z, outf, NULL)) {
fatal_exit("write file failed for %s", fname);
}
checkfile(fname, outf);
+18
View File
@@ -0,0 +1,18 @@
server:
verbosity: 8
# num-threads: 1
interface: 127.0.0.1
port: @PORT@
use-syslog: no
directory: ""
pidfile: "unbound.pid"
chroot: ""
username: ""
do-not-query-localhost: no
auth-task-threads: 1
auth-zone:
name: "example.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
+16
View File
@@ -0,0 +1,16 @@
BaseName: auth_load
Version: 1.0
Description: Perform AXFR for authority zone with auth load thread
CreationDate: Thu 2 Jul 09:35:40 CEST 2026
Maintainer: dr. W.C.A. Wijngaards
Category:
Component:
CmdDepends:
Depends:
Help:
Pre: auth_load.pre
Post: auth_load.post
Test: auth_load.test
AuxFiles:
Passed:
Failure:
+12
View File
@@ -0,0 +1,12 @@
# #-- auth_load.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 $FWD_PID
kill_pid $UNBOUND_PID
cat fwd.log
cat unbound.log
+39
View File
@@ -0,0 +1,39 @@
# #-- auth_load.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 2
UNBOUND_PORT=$RND_PORT
FWD_PORT=$(($RND_PORT + 1))
echo "UNBOUND_PORT=$UNBOUND_PORT" >> .tpkg.var.test
echo "FWD_PORT=$FWD_PORT" >> .tpkg.var.test
# start forwarder
get_ldns_testns
$LDNS_TESTNS -p $FWD_PORT auth_load.testns >fwd.log 2>&1 &
FWD_PID=$!
echo "FWD_PID=$FWD_PID" >> .tpkg.var.test
# make config file
sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's/@TOPORT\@/'$FWD_PORT'/' < auth_load.conf > ub.conf
# start unbound in the background
$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
#valgrind --leak-check=full --show-reachable=yes $PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
UNBOUND_PID=$!
echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
cat .tpkg.var.test
wait_ldns_testns_up fwd.log
wait_unbound_up unbound.log
+55
View File
@@ -0,0 +1,55 @@
# #-- auth_load.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="../.."
# do the test
echo "> dig www.example.com."
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
if grep SERVFAIL outfile; then
echo "> try again"
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 3
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 3
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
echo "> check answer"
if grep "1.2.3.4" outfile; then
echo "OK"
else
echo "Not OK"
exit 1
fi
if grep "auth zone example.com. details" unbound.log; then
echo "OK"
else
echo "not OK"
exit 1
fi
exit 0
+27
View File
@@ -0,0 +1,27 @@
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
example.com. IN SOA
SECTION ANSWER
example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
example.com. IN AXFR
SECTION ANSWER
example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600
example.com. IN NS ns.example.net.
EXTRA_PACKET
REPLY QR AA NOERROR
SECTION QUESTION
example.com. IN AXFR
SECTION ANSWER
www.example.com. IN A 1.2.3.4
example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600
ENTRY_END
@@ -0,0 +1,3 @@
example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600
example.com. IN NS ns.example.net.
www.example.com. IN A 1.2.3.4
+18
View File
@@ -0,0 +1,18 @@
server:
verbosity: 8
# num-threads: 1
interface: 127.0.0.1
port: @PORT@
use-syslog: no
directory: ""
pidfile: "unbound.pid"
chroot: ""
username: ""
do-not-query-localhost: no
auth-task-threads: 1
auth-zone:
name: "example.com"
for-upstream: yes
for-downstream: yes
url: "https://127.0.0.1:@TOPORT@/example.com.zone"
+16
View File
@@ -0,0 +1,16 @@
BaseName: auth_load_http
Version: 1.0
Description: Perform http transfer for authority zone with auth load thread
CreationDate: Tue 11 Aug 16:00:00 CEST 2026
Maintainer: dr. W.C.A. Wijngaards
Category:
Component:
CmdDepends:
Depends:
Help:
Pre: auth_load_http.pre
Post: auth_load_http.post
Test: auth_load_http.test
AuxFiles:
Passed:
Failure:
+12
View File
@@ -0,0 +1,12 @@
# #-- auth_load_http.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
kill_pid $PETAL_PID
cat petal.log
cat unbound.log
+40
View File
@@ -0,0 +1,40 @@
# #-- auth_load_http.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 2
UNBOUND_PORT=$RND_PORT
PETAL_PORT=$(($RND_PORT + 1))
echo "UNBOUND_PORT=$UNBOUND_PORT" >> .tpkg.var.test
echo "PETAL_PORT=$PETAL_PORT" >> .tpkg.var.test
get_make
(cd $PRE; $MAKE petal)
# start https daemon
$PRE/petal -v -a "127.0.0.1" -p $PETAL_PORT >petal.log 2>&1 &
PETAL_PID=$!
echo "PETAL_PID=$PETAL_PID" >> .tpkg.var.test
wait_petal_up petal.log
# make config file
sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's/@TOPORT\@/'$PETAL_PORT'/' < auth_load_http.conf > ub.conf
# start unbound in the background
$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
#valgrind --leak-check=full --show-reachable=yes $PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
UNBOUND_PID=$!
echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
cat .tpkg.var.test
wait_unbound_up unbound.log
+55
View File
@@ -0,0 +1,55 @@
# #-- auth_load_http.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="../.."
# do the test
echo "> dig www.example.com."
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
if grep SERVFAIL outfile; then
echo "> try again"
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 3
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 3
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
echo "> check answer"
if grep "1.2.3.4" outfile; then
echo "OK"
else
echo "Not OK"
exit 1
fi
if grep "auth zone example.com. details" unbound.log; then
echo "OK"
else
echo "not OK"
exit 1
fi
exit 0
+21
View File
@@ -0,0 +1,21 @@
-----BEGIN RSA PRIVATE KEY-----
MIIDfQIBAAKBwQC1xQ/Kca6zszZbcCtdOTIH2Uy2gOy/DfabMUU7TmNPm0dVE0NJ
RuN+Rm304SonpwghfP2/ULZNnuDgpG03/32yI7k/VzG6iA4hiF7tT/KAAWC/+2l1
QCsawCV2bSrFK0VhcZr7ALqXd8vkDaQ867K029ypjOQtAJ85qdO3mERy7TGtdUcu
O6hLeVet419YeQ2F8cfNxn63d7bOzNGLPW5xwaCd3UcgD+Ib0k4xfFvbinvPQUeU
J/i4YDWexFYSL+ECAwEAAQKBwCLXXQl+9O+5AEhSnd1Go1Jh0pSA7eBJOuXQcebG
Rb7ykp+6C4G2NtDziwwPRNdI6wQQQ0sym18RfyVQHydGr78/nbiIbB3HCn5e92Mh
mefzW6ow9Kvm2txLzGKA1lvoyRbNm81jnG/eygi3u7Nqd5PNv+4dHj2RkTlmxOeh
qnDMVP5md8uZPv6lYNnrnIzvLCR5vnPNdVwn89AqzI85IcDZdy0R9ZX4NBbsDgAU
6ig6uXuRXvSGiyJ/OUXSrnogaQJhAOjvkHUhVZQkPOxO90TNH4j0GdKKtbSWxIdz
lKfuJeBAEqs0TL+C6vbS81Xw3W1alyDdUBk3rJMOBqW6Ryq5HNL+j5H+Jfsh7fvc
Yle+5wHGci0P9zCFZCrY8It7n9XFIwJhAMfEi6oJa2G8waPJ1bQhxka82Tf9pnKM
XCn/1BBOFjVIx5F842cpA+zp5a62GENTGYPQTTRBB/2/ZwnW5aIkrlg54AtmbqBZ
Oh+2kJdJQD/tfoVmc5soUE2ScTHadK5RKwJhAN4w9kjkXS+MSZjX0kIMsBIBVkhh
C+aREjJqa9ir7/Ey7RvmLXdYuCxtGLRXp7/R8+rjcK49Tx6O+IRJZe042mfhbq3C
EhS1Tr86f4xXix9EXlDhs9bSxrOgcAN9Dv/opQJhAK7eBcPaav0rVfYh/8emqQHS
3fJ9Pu6WnzbEksWTFS2ff9KDGCx9YspIFJ5TF/oXDAaumGZdZrlgirm6O1kr8tGY
F97i04PZl1+bWAaWQH+1TUNI43m2WFUPE7coG2tb8QJgcddDg9VlXliZqgcETZfJ
kJmYETxrcSn3ao6v116N8yxhEgUgjkmsCTiFgx36iDVnXwK6PIt+sIu8MC7eYNa3
berrv/M21K0LRn20IWRxvUobG070weHCAgkko7fTWgr2
-----END RSA PRIVATE KEY-----
+14
View File
@@ -0,0 +1,14 @@
-----BEGIN CERTIFICATE-----
MIICFzCCAUACCQDO660L5y5LGDANBgkqhkiG9w0BAQUFADAQMQ4wDAYDVQQDEwVw
ZXRhbDAeFw0xMDA5MzAxMzQzMDFaFw0zMDA2MTcxMzQzMDFaMBAxDjAMBgNVBAMT
BXBldGFsMIHfMA0GCSqGSIb3DQEBAQUAA4HNADCByQKBwQC1xQ/Kca6zszZbcCtd
OTIH2Uy2gOy/DfabMUU7TmNPm0dVE0NJRuN+Rm304SonpwghfP2/ULZNnuDgpG03
/32yI7k/VzG6iA4hiF7tT/KAAWC/+2l1QCsawCV2bSrFK0VhcZr7ALqXd8vkDaQ8
67K029ypjOQtAJ85qdO3mERy7TGtdUcuO6hLeVet419YeQ2F8cfNxn63d7bOzNGL
PW5xwaCd3UcgD+Ib0k4xfFvbinvPQUeUJ/i4YDWexFYSL+ECAwEAATANBgkqhkiG
9w0BAQUFAAOBwQBBkX9KDP2RXbg+xPmdJ4P6CwvA5x1LZwC++ydVx4NlvT0pWicD
ZUnXjcWAJlkeOuUBAqFG7WHTrXpUUAjmdqFVq2yFjteUYBdrFz0RDB2jM9feeKYO
mTgxdZyT9a6humxCxt5VfgT02axLjm/2AqCyFPMbf4PASoJDln01AEuZLZ8Xl2gV
bYHMnHTGoD1Hu6FNEzRgkMC6XT8X3YjHvzQhpc/qL5wEfEsinQGdX4twsuWbf8xd
q7miNnkO8vd0maw=
-----END CERTIFICATE-----
+103
View File
@@ -0,0 +1,103 @@
server:
verbosity: 8
num-threads: 1
interface: 127.0.0.1
port: @PORT@
use-syslog: no
directory: ""
pidfile: "unbound.pid"
chroot: ""
username: ""
do-not-query-localhost: no
auth-task-threads: 2
auth-zone:
name: "example1.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
auth-zone:
name: "example2.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
auth-zone:
name: "example3.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
auth-zone:
name: "example4.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
auth-zone:
name: "example5.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
auth-zone:
name: "example6.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
auth-zone:
name: "example7.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
auth-zone:
name: "example8.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
auth-zone:
name: "example9.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
auth-zone:
name: "example10.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
auth-zone:
name: "example11.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
auth-zone:
name: "example12.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
auth-zone:
name: "example13.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
auth-zone:
name: "example14.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
auth-zone:
name: "example15.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
+16
View File
@@ -0,0 +1,16 @@
BaseName: auth_load_list
Version: 1.0
Description: Perform more transfers than the auth load thread count
CreationDate: Fri 9 Jul 15:00:00 CEST 2026
Maintainer: dr. W.C.A. Wijngaards
Category:
Component:
CmdDepends:
Depends:
Help:
Pre: auth_load_list.pre
Post: auth_load_list.post
Test: auth_load_list.test
AuxFiles:
Passed:
Failure:
+12
View File
@@ -0,0 +1,12 @@
# #-- auth_load_list.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 $FWD_PID
kill_pid $UNBOUND_PID
cat fwd.log
cat unbound.log
+74
View File
@@ -0,0 +1,74 @@
# #-- auth_load_list.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 2
UNBOUND_PORT=$RND_PORT
FWD_PORT=$(($RND_PORT + 1))
echo "UNBOUND_PORT=$UNBOUND_PORT" >> .tpkg.var.test
echo "FWD_PORT=$FWD_PORT" >> .tpkg.var.test
# start forwarder
# create auth_load_list.testns
for((i=1; i<16; i++)); do
cat >>auth_load_list.testns <<EOF
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
example$i.com. IN SOA
SECTION ANSWER
example$i.com. IN SOA ns.example$i.com. hostmaster.example$i.com. 1 3600 900 86400 3600
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
example$i.com. IN AXFR
SECTION ANSWER
example$i.com. IN SOA ns.example$i.com. hostmaster.example$i.com. 1 3600 900 86400 3600
example$i.com. IN NS ns.example.net.
EXTRA_PACKET
REPLY QR AA NOERROR
SECTION QUESTION
example$i.com. IN AXFR
SECTION ANSWER
www.example$i.com. IN A 1.2.3.4
example$i.com. IN SOA ns.example$i.com. hostmaster.example$i.com. 1 3600 900 86400 3600
ENTRY_END
EOF
done
get_ldns_testns
$LDNS_TESTNS -p $FWD_PORT auth_load_list.testns >fwd.log 2>&1 &
FWD_PID=$!
echo "FWD_PID=$FWD_PID" >> .tpkg.var.test
# make config file
sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's/@TOPORT\@/'$FWD_PORT'/' < auth_load_list.conf > ub.conf
# start unbound in the background
$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
#valgrind --leak-check=full --show-reachable=yes $PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
UNBOUND_PID=$!
echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
cat .tpkg.var.test
wait_ldns_testns_up fwd.log
wait_unbound_up unbound.log
+60
View File
@@ -0,0 +1,60 @@
# #-- auth_load_list.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="../.."
# do the test
for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do
name="www.example$i.com"
echo ""
echo "> dig $name"
dig @127.0.0.1 -p $UNBOUND_PORT $name | tee outfile
if grep SERVFAIL outfile; then
echo "> try again"
dig @127.0.0.1 -p $UNBOUND_PORT $name | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT $name | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT $name | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT $name | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 3
dig @127.0.0.1 -p $UNBOUND_PORT $name | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 3
dig @127.0.0.1 -p $UNBOUND_PORT $name | tee outfile
fi
echo "> check answer"
if grep "1.2.3.4" outfile; then
echo "OK"
else
echo "Not OK"
exit 1
fi
if grep "auth zone example$i.com. details" unbound.log; then
echo "OK"
else
echo "not OK"
exit 1
fi
done
echo "loop done"
exit 0
+26
View File
@@ -0,0 +1,26 @@
server:
verbosity: 8
# num-threads: 1
interface: 127.0.0.1
port: @PORT@
use-syslog: no
directory: ""
pidfile: "unbound.pid"
module-config: "respip validator iterator"
chroot: ""
username: ""
do-not-query-localhost: no
auth-task-threads: 1
log-queries: yes
log-replies: yes
forward-zone:
name: "."
forward-addr: "127.0.0.1@@TOPORT@"
rpz:
name: "rpz.example.com"
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
rpz-log: yes
rpz-log-name: "rpz.example.com"
+16
View File
@@ -0,0 +1,16 @@
BaseName: auth_load_rpz
Version: 1.0
Description: Load RPZ zone with auth load thread
CreationDate: Tue 6 Oct 10:00:00 CEST 2026
Maintainer: dr. W.C.A. Wijngaards
Category:
Component:
CmdDepends:
Depends:
Help:
Pre: auth_load_rpz.pre
Post: auth_load_rpz.post
Test: auth_load_rpz.test
AuxFiles:
Passed:
Failure:
+12
View File
@@ -0,0 +1,12 @@
# #-- auth_load_rpz.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 $FWD_PID
kill_pid $UNBOUND_PID
cat fwd.log
cat unbound.log
+39
View File
@@ -0,0 +1,39 @@
# #-- auth_load_rpz.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 2
UNBOUND_PORT=$RND_PORT
FWD_PORT=$(($RND_PORT + 1))
echo "UNBOUND_PORT=$UNBOUND_PORT" >> .tpkg.var.test
echo "FWD_PORT=$FWD_PORT" >> .tpkg.var.test
# start forwarder
get_ldns_testns
$LDNS_TESTNS -p $FWD_PORT auth_load_rpz.testns >fwd.log 2>&1 &
FWD_PID=$!
echo "FWD_PID=$FWD_PID" >> .tpkg.var.test
# make config file
sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's/@TOPORT\@/'$FWD_PORT'/' < auth_load_rpz.conf > ub.conf
# start unbound in the background
$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
#valgrind --leak-check=full --show-reachable=yes $PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
UNBOUND_PID=$!
echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
cat .tpkg.var.test
wait_ldns_testns_up fwd.log
wait_unbound_up unbound.log
+56
View File
@@ -0,0 +1,56 @@
# #-- auth_load_rpz.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="../.."
# do the test
# The answer is rewritten by RPZ, that is loaded in the auth load thread.
echo "> dig www.example.com."
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
if grep SERVFAIL outfile; then
echo "> try again"
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 3
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 3
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
echo "> check answer"
if grep "1.2.3.4" outfile; then
echo "OK"
else
echo "Not OK"
exit 1
fi
if grep "auth zone rpz.example.com. details" unbound.log; then
echo "OK"
else
echo "not OK"
exit 1
fi
exit 0
+22
View File
@@ -0,0 +1,22 @@
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
rpz.example.com. IN SOA
SECTION ANSWER
rpz.example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
rpz.example.com. IN AXFR
SECTION ANSWER
rpz.example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600
rpz.example.com. IN NS ns.example.net.
www.example.com.rpz.example.com. IN A 1.2.3.4
rpz.example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600
ENTRY_END
+27
View File
@@ -0,0 +1,27 @@
server:
verbosity: 8
# num-threads: 1
interface: 127.0.0.1
port: @PORT@
use-syslog: no
directory: ""
pidfile: "unbound.pid"
module-config: "respip validator iterator"
chroot: ""
username: ""
do-not-query-localhost: no
auth-task-threads: 1
log-queries: yes
log-replies: yes
forward-zone:
name: "."
forward-addr: "127.0.0.1@@TOPORT@"
rpz:
name: "rpz.example.com"
zonefile: "auth_load_write.zone"
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
rpz-log: yes
rpz-log-name: "rpz.example.com"
+16
View File
@@ -0,0 +1,16 @@
BaseName: auth_load_write
Version: 1.0
Description: Write zonefile with auth load thread
CreationDate: Wed 7 Oct 10:00:00 CEST 2026
Maintainer: dr. W.C.A. Wijngaards
Category:
Component:
CmdDepends:
Depends:
Help:
Pre: auth_load_write.pre
Post: auth_load_write.post
Test: auth_load_write.test
AuxFiles:
Passed:
Failure:
+12
View File
@@ -0,0 +1,12 @@
# #-- auth_load_write.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 $FWD_PID
kill_pid $UNBOUND_PID
cat fwd.log
cat unbound.log
+39
View File
@@ -0,0 +1,39 @@
# #-- auth_load_write.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 2
UNBOUND_PORT=$RND_PORT
FWD_PORT=$(($RND_PORT + 1))
echo "UNBOUND_PORT=$UNBOUND_PORT" >> .tpkg.var.test
echo "FWD_PORT=$FWD_PORT" >> .tpkg.var.test
# start forwarder
get_ldns_testns
$LDNS_TESTNS -p $FWD_PORT auth_load_write.testns >fwd.log 2>&1 &
FWD_PID=$!
echo "FWD_PID=$FWD_PID" >> .tpkg.var.test
# make config file
sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's/@TOPORT\@/'$FWD_PORT'/' < auth_load_write.conf > ub.conf
# start unbound in the background
$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
#valgrind --leak-check=full --show-reachable=yes $PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
UNBOUND_PID=$!
echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
cat .tpkg.var.test
wait_ldns_testns_up fwd.log
wait_unbound_up unbound.log
+70
View File
@@ -0,0 +1,70 @@
# #-- auth_load_write.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
# do the test
# The answer is rewritten by RPZ, that is loaded in the auth load thread.
echo "> dig www.example.com."
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
if grep SERVFAIL outfile; then
echo "> try again"
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 3
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 3
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
echo "> check answer"
if grep "1.2.3.4" outfile; then
echo "OK"
else
echo "Not OK"
exit 1
fi
if grep "auth zone rpz.example.com. details" unbound.log; then
echo "OK"
else
echo "not OK"
exit 1
fi
wait_logfile unbound.log "write zonefile auth_load_write.zone for rpz.example.com." 10
grep "write zonefile" unbound.log
echo "> auth_load_write.zone"
cat auth_load_write.zone
echo ""
if grep "text a b c d" auth_load_write.zone; then
echo "OK"
else
echo "not OK"
exit 1
fi
exit 0
+23
View File
@@ -0,0 +1,23 @@
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
rpz.example.com. IN SOA
SECTION ANSWER
rpz.example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
rpz.example.com. IN AXFR
SECTION ANSWER
rpz.example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600
rpz.example.com. IN NS ns.example.net.
www.example.com.rpz.example.com. IN A 1.2.3.4
txt.example.com.rpz.example.com. IN TXT "text a b c d"
rpz.example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600
ENTRY_END
+4
View File
@@ -243,6 +243,7 @@ config_create(void)
cfg->views = NULL;
cfg->acls = NULL;
cfg->tcp_connection_limits = NULL;
cfg->auth_task_threads = 0;
cfg->harden_short_bufsize = 1;
cfg->harden_large_queries = 0;
cfg->harden_glue = 1;
@@ -460,6 +461,7 @@ struct config_file* config_create_forlib(void)
cfg->neg_cache_size = 100 * 1024;
cfg->donotquery_localhost = 0; /* allow, so that you can ask a
forward nameserver running on localhost */
cfg->auth_task_threads = 0; /* no extra threads to spawn in library */
cfg->val_log_level = 2; /* to fill why_bogus with */
cfg->val_log_squelch = 1;
cfg->minimal_responses = 0;
@@ -746,6 +748,7 @@ int config_set_option(struct config_file* cfg, const char* opt,
else S_SIZET_OR_ZERO("unwanted-reply-threshold:", unwanted_threshold)
else S_STRLIST("private-address:", private_address)
else S_STRLIST("private-domain:", private_domain)
else S_NUMBER_OR_ZERO("auth-task-threads:", auth_task_threads)
else S_YNO("do-not-query-localhost:", donotquery_localhost)
else S_STRLIST("do-not-query-address:", donotqueryaddrs)
else S_STRLIST("auto-trust-anchor-file:", auto_trust_anchor_file_list)
@@ -1293,6 +1296,7 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_LST(opt, "root-hints", root_hints)
else O_LS2(opt, "access-control", acls)
else O_LS2(opt, "tcp-connection-limit", tcp_connection_limits)
else O_DEC(opt, "auth-task-threads", auth_task_threads)
else O_LST(opt, "do-not-query-address", donotqueryaddrs)
else O_LST(opt, "private-address", private_address)
else O_LST(opt, "private-domain", private_domain)
+2
View File
@@ -291,6 +291,8 @@ struct config_file {
/** list of tcp connection limitss, linked list */
struct config_str2list* tcp_connection_limits;
/** auth task threads, or 0 disabled. */
int auth_task_threads;
/** harden against very small edns buffer sizes */
int harden_short_bufsize;
+1
View File
@@ -596,6 +596,7 @@ name-v4{COLON} { YDVAR(1, VAR_IPSET_NAME_V4) }
name-v6{COLON} { YDVAR(1, VAR_IPSET_NAME_V6) }
udp-upstream-without-downstream{COLON} { YDVAR(1, VAR_UDP_UPSTREAM_WITHOUT_DOWNSTREAM) }
tcp-connection-limit{COLON} { YDVAR(2, VAR_TCP_CONNECTION_LIMIT) }
auth-task-threads{COLON} { YDVAR(1, VAR_AUTH_TASK_THREADS) }
answer-cookie{COLON} { YDVAR(1, VAR_ANSWER_COOKIE ) }
cookie-secret{COLON} { YDVAR(1, VAR_COOKIE_SECRET) }
cookie-secret-file{COLON} { YDVAR(1, VAR_COOKIE_SECRET_FILE) }
+11
View File
@@ -193,6 +193,7 @@ extern struct config_parser_state* cfg_parser;
%token VAR_FALLBACK_ENABLED VAR_TLS_ADDITIONAL_PORT VAR_LOW_RTT VAR_LOW_RTT_PERMIL
%token VAR_FAST_SERVER_PERMIL VAR_FAST_SERVER_NUM
%token VAR_ALLOW_NOTIFY VAR_TLS_WIN_CERT VAR_TCP_CONNECTION_LIMIT
%token VAR_AUTH_TASK_THREADS
%token VAR_ANSWER_COOKIE VAR_COOKIE_SECRET VAR_IP_RATELIMIT_COOKIE
%token VAR_FORWARD_NO_CACHE VAR_STUB_NO_CACHE VAR_LOG_SERVFAIL VAR_DENY_ANY
%token VAR_UNKNOWN_SERVER_TIME_LIMIT VAR_LOG_TAG_QUERYREPLY
@@ -345,6 +346,7 @@ content_server: server_num_threads | server_verbosity | server_port |
server_tls_cert_bundle | server_tls_additional_port | server_low_rtt |
server_fast_server_permil | server_fast_server_num | server_tls_win_cert |
server_tcp_connection_limit | server_log_servfail | server_deny_any |
server_auth_task_threads |
server_unknown_server_time_limit | server_log_tag_queryreply |
server_discard_timeout | server_wait_limit | server_wait_limit_cookie |
server_wait_limit_netblock | server_wait_limit_cookie_netblock |
@@ -4211,6 +4213,15 @@ server_tcp_connection_limit: VAR_TCP_CONNECTION_LIMIT STRING_ARG STRING_ARG
}
}
;
server_auth_task_threads: VAR_AUTH_TASK_THREADS STRING_ARG
{
OUTYY(("P(server_auth_task_threads:%s)\n", $2));
if(atoi($2) == 0 && strcmp($2, "0") != 0)
yyerror("number expected");
else cfg_parser->cfg->auth_task_threads = atoi($2);
free($2);
}
;
server_answer_cookie: VAR_ANSWER_COOKIE STRING_ARG
{
OUTYY(("P(server_answer_cookie:%s)\n", $2));
+5
View File
@@ -51,6 +51,7 @@
#include "services/mesh.h"
#include "services/localzone.h"
#include "services/authzone.h"
#include "services/authload.h"
#include "services/cache/infra.h"
#include "services/cache/rrset.h"
#include "services/view.h"
@@ -72,6 +73,7 @@
#include "libunbound/libworker.h"
#include "libunbound/context.h"
#include "libunbound/worker.h"
#include "libunbound/authload.h"
#include "util/tube.h"
#include "util/config_file.h"
#include "daemon/remote.h"
@@ -146,6 +148,7 @@ fptr_whitelist_comm_timer(void (*fptr)(void*))
else if(fptr == &auth_xfer_timer) return 1;
else if(fptr == &auth_xfer_probe_timer_callback) return 1;
else if(fptr == &auth_xfer_transfer_timer_callback) return 1;
else if(fptr == &auth_load_resume_timer_cb) return 1;
else if(fptr == &mesh_serve_expired_callback) return 1;
else if(fptr == &serviced_timer_cb) return 1;
#ifdef USE_DNSTAP
@@ -193,6 +196,7 @@ fptr_whitelist_event(void (*fptr)(int, short, void *))
else if(fptr == &comm_point_doq_callback) return 1;
#endif
else if(fptr == &fast_reload_service_cb) return 1;
else if(fptr == &worker_auth_load_service_cb) return 1;
#ifdef USE_DNSTAP
else if(fptr == &dtio_output_cb) return 1;
else if(fptr == &dtio_cmd_cb) return 1;
@@ -264,6 +268,7 @@ fptr_whitelist_rbtree_cmp(int (*fptr) (const void *, const void *))
else if(fptr == &auth_zone_cmp) return 1;
else if(fptr == &auth_data_cmp) return 1;
else if(fptr == &auth_xfer_cmp) return 1;
else if(fptr == &auth_load_tree_cmp) return 1;
#ifdef HAVE_NGTCP2
else if(fptr == &doq_conn_cmp) return 1;
else if(fptr == &doq_conid_cmp) return 1;
+360
View File
@@ -58,6 +58,9 @@
#include "sldns/wire2str.h"
#include "sldns/str2wire.h"
#include <fcntl.h>
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
#ifdef HAVE_OPENSSL_SSL_H
#include <openssl/ssl.h>
#include <openssl/evp.h>
@@ -92,6 +95,9 @@ int RRSET_ROUNDROBIN = 1;
/** log tag queries with name instead of 'info' for filtering */
int LOG_TAG_QUERYREPLY = 0;
/** What number of loop iterations is too much for sock poll retries */
#define SOCK_POLL_LOOP_MAX 200
#ifdef HAVE_SSL
static struct tls_session_ticket_key {
unsigned char *key_name;
@@ -2083,3 +2089,357 @@ hex_pton(const char* src, uint8_t* target, size_t targsize)
}
return t-target;
}
int
sock_poll_timeout(int fd, int timeout, int pollin, int pollout, int* event)
{
int loopcount = 0;
/* Loop if the system call returns an errno to do so, like EINTR. */
log_assert(pollin || pollout);
while(1) {
struct pollfd p, *fds;
int nfds, ret;
if(++loopcount > SOCK_POLL_LOOP_MAX) {
log_err("sock_poll_timeout: loop");
if(event)
*event = 0;
return 0;
}
if(fd == -1) {
fds = NULL;
nfds = 0;
} else {
fds = &p;
nfds = 1;
memset(&p, 0, sizeof(p));
p.fd = fd;
#ifndef USE_WINSOCK
p.events = POLLERR
| POLLHUP
;
#endif
if(pollin)
p.events |= POLLIN;
if(pollout)
p.events |= POLLOUT;
}
#ifndef USE_WINSOCK
ret = poll(fds, nfds, timeout);
#else
if(fds == NULL) {
Sleep(timeout);
ret = 0;
} else {
ret = WSAPoll(fds, nfds, timeout);
}
#endif
if(ret == -1) {
#ifndef USE_WINSOCK
if(
errno == EINTR || errno == EAGAIN
# ifdef EWOULDBLOCK
|| errno == EWOULDBLOCK
# endif
) continue; /* Try again. */
#endif
/* For WSAPoll we only get errors here:
* o WSAENETDOWN
* o WSAEFAULT
* o WSAEINVAL
* o WSAENOBUFS
*/
log_err("poll: %s", sock_strerror(errno));
if(event)
*event = 0;
return 0;
} else if(ret == 0) {
/* Timeout */
if(event)
*event = 0;
return 1;
}
break;
}
if(event)
*event = 1;
return 1;
}
int
create_socketpair(int* pair, struct ub_randstate* rand)
{
#ifndef USE_WINSOCK
if(socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
log_err("socketpair: %s", strerror(errno));
return 0;
}
(void)rand;
#else
struct sockaddr_in addr, baddr, accaddr, connaddr;
socklen_t baddrlen, accaddrlen, connaddrlen;
uint8_t localhost[] = {127, 0, 0, 1};
uint8_t nonce[16], recvnonce[16];
size_t i;
int lst, pollin_event, bcount, loopcount;
int connect_poll_timeout = 200; /* msec to wait for connection */
ssize_t ret;
pair[0] = -1;
pair[1] = -1;
for(i=0; i<sizeof(nonce); i++) {
nonce[i] = ub_random_max(rand, 256);
}
lst = socket(AF_INET, SOCK_STREAM, 0);
if(lst == -1) {
log_err("create_socketpair: socket: %s", sock_strerror(errno));
return 0;
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = 0;
memcpy(&addr.sin_addr, localhost, 4);
if(bind(lst, (struct sockaddr*)&addr, (socklen_t)sizeof(addr))
== -1) {
log_err("create socketpair: bind: %s", sock_strerror(errno));
sock_close(lst);
return 0;
}
if(listen(lst, 12) == -1) {
log_err("create socketpair: listen: %s", sock_strerror(errno));
sock_close(lst);
return 0;
}
pair[1] = socket(AF_INET, SOCK_STREAM, 0);
if(pair[1] == -1) {
log_err("create socketpair: socket: %s", sock_strerror(errno));
sock_close(lst);
return 0;
}
baddrlen = (socklen_t)sizeof(baddr);
if(getsockname(lst, (struct sockaddr*)&baddr, &baddrlen) == -1) {
log_err("create socketpair: getsockname: %s",
sock_strerror(errno));
sock_close(lst);
sock_close(pair[1]);
pair[1] = -1;
return 0;
}
if(baddrlen > (socklen_t)sizeof(baddr)) {
log_err("create socketpair: getsockname returned addr too big");
sock_close(lst);
sock_close(pair[1]);
pair[1] = -1;
return 0;
}
/* the socket is blocking */
if(connect(pair[1], (struct sockaddr*)&baddr, baddrlen) == -1) {
log_err("create socketpair: connect: %s",
sock_strerror(errno));
sock_close(lst);
sock_close(pair[1]);
pair[1] = -1;
return 0;
}
if(!sock_poll_timeout(lst, connect_poll_timeout, 1, 0, &pollin_event)) {
log_err("create socketpair: poll for accept failed: %s",
sock_strerror(errno));
sock_close(lst);
sock_close(pair[1]);
pair[1] = -1;
return 0;
}
if(!pollin_event) {
log_err("create socketpair: poll timeout for accept");
sock_close(lst);
sock_close(pair[1]);
pair[1] = -1;
return 0;
}
accaddrlen = (socklen_t)sizeof(accaddr);
pair[0] = accept(lst, (struct sockaddr*)&accaddr, &accaddrlen);
if(pair[0] == -1) {
log_err("create socketpair: accept: %s", sock_strerror(errno));
sock_close(lst);
sock_close(pair[1]);
pair[1] = -1;
return 0;
}
if(accaddrlen > (socklen_t)sizeof(accaddr)) {
log_err("create socketpair: accept returned addr too big");
sock_close(lst);
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
if(accaddr.sin_family != AF_INET ||
memcmp(localhost, &accaddr.sin_addr, 4) != 0) {
log_err("create socketpair: accept from wrong address");
sock_close(lst);
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
connaddrlen = (socklen_t)sizeof(connaddr);
if(getsockname(pair[1], (struct sockaddr*)&connaddr, &connaddrlen)
== -1) {
log_err("create socketpair: getsockname connectedaddr: %s",
sock_strerror(errno));
sock_close(lst);
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
if(connaddrlen > (socklen_t)sizeof(connaddr)) {
log_err("create socketpair: getsockname connectedaddr returned addr too big");
sock_close(lst);
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
if(connaddr.sin_family != AF_INET ||
memcmp(localhost, &connaddr.sin_addr, 4) != 0) {
log_err("create socketpair: getsockname connectedaddr returned wrong address");
sock_close(lst);
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
if(accaddr.sin_port != connaddr.sin_port) {
log_err("create socketpair: accept from wrong port");
sock_close(lst);
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
sock_close(lst);
loopcount = 0;
bcount = 0;
while(1) {
if(++loopcount > SOCK_POLL_LOOP_MAX) {
log_err("create socketpair: send failed due to loop");
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
ret = send(pair[1], (void*)(nonce+bcount),
sizeof(nonce)-bcount, 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("create socketpair: send: %s", sock_strerror(errno));
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
} else if(ret+(ssize_t)bcount != sizeof(nonce)) {
bcount += ret;
if((size_t)bcount < sizeof(nonce))
continue;
}
break;
}
if(!sock_poll_timeout(pair[0], connect_poll_timeout, 1, 0, &pollin_event)) {
log_err("create socketpair: poll failed: %s",
sock_strerror(errno));
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
if(!pollin_event) {
log_err("create socketpair: poll timeout for recv");
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
loopcount = 0;
bcount = 0;
while(1) {
if(++loopcount > SOCK_POLL_LOOP_MAX) {
log_err("create socketpair: recv failed due to loop");
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
ret = recv(pair[0], (void*)(recvnonce+bcount),
sizeof(nonce)-bcount, 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("create socketpair: recv: %s", sock_strerror(errno));
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
} else if(ret == 0) {
log_err("create socketpair: stream closed");
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
} else if(ret+(ssize_t)bcount != sizeof(nonce)) {
bcount += ret;
if((size_t)bcount < sizeof(nonce))
continue;
}
break;
}
if(memcmp(nonce, recvnonce, sizeof(nonce)) != 0) {
log_err("create socketpair: recv wrong nonce");
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
#endif
return 1;
}
+16
View File
@@ -604,4 +604,20 @@ ssize_t hex_ntop(uint8_t const *src, size_t srclength, char *target,
/** Convert hexadecimal data to binary. */
ssize_t hex_pton(const char* src, uint8_t* target, size_t targsize);
/**
* This routine polls a socket for readiness.
* @param fd: file descriptor, -1 uses no fd for a timer only.
* @param timeout: time in msec to wait. 0 means nonblocking test,
* -1 waits blocking for events.
* @param pollin: check for input event.
* @param pollout: check for output event.
* @param event: output variable, set to true if the event happens.
* It is false if there was an error or timeout.
* @return false is system call failure, also logged.
*/
int sock_poll_timeout(int fd, int timeout, int pollin, int pollout, int* event);
/** create a socketpair for bidirectional communication, false on failure */
int create_socketpair(int* pair, struct ub_randstate* rand);
#endif /* NET_HELP_H */