1
/* servers.c - manage a set of dns servers
3
Copyright (C) 2000, 2001 Thomas Moestl
4
Copyright (C) 2002, 2003, 2005, 2007, 2009 Paul A. Rombouts
6
This file is part of the pdnsd package.
8
pdnsd is free software; you can redistribute it and/or modify
9
it under the terms of the GNU General Public License as published by
10
the Free Software Foundation; either version 3 of the License, or
11
(at your option) any later version.
13
pdnsd is distributed in the hope that it will be useful,
14
but WITHOUT ANY WARRANTY; without even the implied warranty of
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
GNU General Public License for more details.
18
You should have received a copy of the GNU General Public License
19
along with pdnsd; see the file COPYING. If not, see
20
<http://www.gnu.org/licenses/>.
29
#include <sys/types.h>
31
#include <sys/resource.h>
48
#include "dns_query.h"
50
#if !defined(lint) && !defined(NO_RCSIDS)
51
static char rcsid[]="$Id: servers.c,v 1.19 2002/07/19 21:14:19 tmm Exp $";
55
* We may be a little over-strict with locks here. Never mind...
56
* Also, there may be some code-redundancy regarding uptests. It saves some locks, though.
59
static pthread_mutex_t servers_lock = PTHREAD_MUTEX_INITIALIZER;
60
static pthread_cond_t server_data_cond = PTHREAD_COND_INITIALIZER;
61
static pthread_cond_t server_test_cond = PTHREAD_COND_INITIALIZER;
62
static int server_data_users = 0, server_status_ping = 0;
63
/* Used to notify the server status thread that it should discontinue uptests. */
64
volatile int signal_interrupt=0;
65
#define statusintsig SIGHUP
67
static short retest_flag=0;
71
static void sigint_handler(int signum);
74
* Execute an individual uptest. Call with locks applied
76
static int uptest (servparm_t *serv, int j)
78
int ret=0, count_running_ping=0;
79
pdnsd_a *s_addr= PDNSD_A2_TO_A(&DA_INDEX(serv->atup_a,j).a);
81
DEBUG_PDNSDA_MSG("performing uptest (type=%s) for %s\n",const_name(serv->uptest),PDNSDA2STR(s_addr));
83
/* Unlock the mutex because some of the tests may take a while. */
85
if((serv->uptest==C_PING || serv->uptest==C_QUERY) && pthread_equal(pthread_self(),servstat_thrid)) {
86
/* Inform other threads that a ping is in progress. */
90
pthread_mutex_unlock(&servers_lock);
92
switch (serv->uptest) {
95
ret=DA_INDEX(serv->atup_a,j).is_up;
98
ret=ping(is_inaddr_any(&serv->ping_a) ? s_addr : &serv->ping_a, serv->ping_timeout,PINGREPEAT)!=-1;
103
ret=if_up(serv->interface);
104
#if (TARGET==TARGET_LINUX)
106
if(serv->uptest==C_DEV)
107
ret=dev_up(serv->interface,serv->device);
108
else if (serv->uptest==C_DIALD)
109
ret=dev_up("diald",serv->device);
116
if ((pid=fork())==-1) {
117
DEBUG_MSG("Could not fork to perform exec uptest: %s\n",strerror(errno));
119
} else if (pid==0) { /* child */
121
* If we ran as setuid or setgid, do not inherit this to the
122
* command. This is just a last guard. Running pdnsd as setuid()
123
* or setgid() is a no-no.
125
if (setgid(getgid()) == -1 || setuid(getuid()) == -1) {
126
log_error("Could not reset uid or gid: %s",strerror(errno));
129
/* Try to setuid() to a different user as specified. Good when you
130
don't want the test command to run as root */
131
if (!run_as(serv->uptest_usr)) {
135
struct rlimit rl; int i;
137
* Mark all open fd's FD_CLOEXEC for paranoia reasons.
139
if (getrlimit(RLIMIT_NOFILE, &rl) == -1) {
140
log_error("getrlimit() failed: %s",strerror(errno));
143
for (i = 0; i < rl.rlim_max; i++) {
144
if (fcntl(i, F_SETFD, FD_CLOEXEC) == -1 && errno != EBADF) {
145
log_error("fcntl(F_SETFD) failed: %s",strerror(errno));
150
execl("/bin/sh", "uptest_sh","-c",serv->uptest_cmd,(char *)NULL);
151
_exit(1); /* failed execl */
152
} else { /* parent */
154
pid_t wpid = waitpid(pid,&status,0);
156
if(WIFEXITED(status)) {
157
int exitstatus=WEXITSTATUS(status);
158
DEBUG_MSG("uptest command \"%s\" exited with status %d\n",
159
serv->uptest_cmd, exitstatus);
163
else if(WIFSIGNALED(status)) {
164
DEBUG_MSG("uptest command \"%s\" was terminated by signal %d\n",
165
serv->uptest_cmd, WTERMSIG(status));
168
DEBUG_MSG("status of uptest command \"%s\" is of unkown type (0x%x)\n",
169
serv->uptest_cmd, status);
175
DEBUG_MSG("Error while waiting for uptest command \"%s\" to terminate: "
176
"waitpid for pid %d failed: %s\n",
177
serv->uptest_cmd, pid, strerror(errno));
180
DEBUG_MSG("Error while waiting for uptest command \"%s\" to terminate: "
181
"waitpid returned %d, expected pid %d\n",
182
serv->uptest_cmd, wpid, pid);
189
ret=query_uptest(s_addr, serv->port,
190
serv->timeout>=global.timeout?serv->timeout:global.timeout,
192
} /* end of switch */
194
pthread_mutex_lock(&servers_lock);
195
if(count_running_ping)
196
--server_status_ping;
197
PDNSD_ASSERT(server_data_users>0, "server_data_users non-positive before attempt to decrement it");
198
if (--server_data_users==0) pthread_cond_broadcast(&server_data_cond);
200
DEBUG_PDNSDA_MSG("result of uptest for %s: %s\n",
206
static int scheme_ok(servparm_t *serv)
208
if (serv->scheme[0]) {
211
int sc = open(global.scheme_file, O_RDONLY);
215
nschm = read(sc, schm, sizeof(schm)-1);
220
s = strchr(schm, '\n');
224
if (fnmatch(serv->scheme, schm, 0))
230
/* Internal server test. Call with locks applied.
231
May test a single server ip or several collectively.
233
static void retest(int i, int j)
236
servparm_t *srv=&DA_INDEX(servers,i);
237
int nsrvs=DA_NEL(srv->atup_a);
241
if(j<nsrvs) nsrvs=j+1; /* test just one */
244
j=0; /* test a range of servers */
247
if(!scheme_ok(srv)) {
251
atup_t *at=&DA_INDEX(srv->atup_a,j);
256
else if(srv->uptest==C_NONE) {
260
DA_INDEX(srv->atup_a,j).i_ts=s_ts;
263
else if(srv->uptest==C_QUERY || (srv->uptest==C_PING && is_inaddr_any(&srv->ping_a))) { /* test each ip address separately */
265
atup_t *at=&DA_INDEX(srv->atup_a,j);
267
at->is_up=uptest(srv,j);
273
else { /* test ip addresses collectively */
279
atup_t *at=&DA_INDEX(srv->atup_a,j);
281
if(signal_interrupt && srv->uptest==C_PING)
289
/* This is called by the server status thread to discover the addresses of root servers.
290
Call with server_lock applied.
292
static addr2_array resolv_rootserver_addrs(atup_array a, int port, time_t timeout)
294
addr2_array retval=NULL;
296
/* Unlock the mutex because this may take a while. */
298
pthread_mutex_unlock(&servers_lock);
300
retval= dns_rootserver_resolv(a,port,timeout);
302
pthread_mutex_lock(&servers_lock);
303
PDNSD_ASSERT(server_data_users>0, "server_data_users non-positive before attempt to decrement it");
304
if (--server_data_users==0) pthread_cond_broadcast(&server_data_cond);
310
* Refresh the server status by pinging or testing the interface in the given interval.
311
* Note that you may get inaccuracies in the dimension of the ping timeout or the runtime
312
* of your uptest command if you have uptest=ping or uptest=exec for at least one server.
313
* This happens when all the uptests for the first n servers take more time than the inteval
314
* of n+1 (or 0 when n+1>servnum). I do not think that these delays are critical, so I did
315
* not to anything about that (because that may also be costly).
317
void *servstat_thread(void *p)
319
struct sigaction action;
322
/* (void)p; */ /* To inhibit "unused variable" warning */
326
pthread_mutex_lock(&servers_lock);
327
/* servstat_thrid=pthread_self(); */
330
action.sa_handler = sigint_handler;
331
sigemptyset(&action.sa_mask);
333
if(sigaction(statusintsig, &action, NULL) == 0) {
336
sigaddset(&smask, statusintsig);
337
pthread_sigmask(SIG_UNBLOCK,&smask,NULL);
340
log_warn("Cannot install signal handler for server status thread: %s\n",strerror(errno));
351
servparm_t *sp=&DA_INDEX(servers,i);
353
if(sp->rootserver==2) {
354
/* First get addresses of root servers. */
359
time_t now=time(NULL);
360
m=DA_NEL(sp->atup_a);
362
DA_INDEX(sp->atup_a,j).i_ts=now;
363
} else if(sp->uptest==C_PING || sp->uptest==C_QUERY) {
364
/* Skip ping or query tests until after discovery. */
366
one_up= DA_NEL(sp->atup_a);
368
time_t now=time(NULL);
369
m=DA_NEL(sp->atup_a);
371
atup_t *at=&DA_INDEX(sp->atup_a,j);
372
if(at->is_up || at->i_ts==0)
381
m=DA_NEL(sp->atup_a);
383
if(DA_INDEX(sp->atup_a,j).is_up) {
391
if (needs_intermittent_testing(sp)) keep_testing=1;
395
DEBUG_MSG("Attempting to discover root servers for server section #%d.\n",i);
396
adrs=resolv_rootserver_addrs(sp->atup_a,sp->port,sp->timeout);
400
struct timespec timeout;
402
DEBUG_MSG("Filling server section #%d with %d root server addresses.\n",i,l);
403
gettimeofday(&now,NULL);
404
timeout.tv_sec = now.tv_sec + 60; /* time out after 60 seconds */
405
timeout.tv_nsec = now.tv_usec * 1000;
406
while (server_data_users>0) {
407
if(pthread_cond_timedwait(&server_data_cond, &servers_lock, &timeout) == ETIMEDOUT) {
408
DEBUG_MSG("Timed out while waiting for exclusive access to server data"
409
" to set root server addresses of server section #%d\n",i);
415
ata = DA_CREATE(atup_array, l);
417
log_warn("Out of memory in servstat_thread() while discovering root servers.");
423
atup_t *at = &DA_INDEX(ata,j);
424
at->a = DA_INDEX(adrs,j);
425
at->is_up=sp->preset;
426
at->i_ts= sp->interval<0 ? time(NULL): 0;
431
/* Successfully set IP addresses for this server section. */
435
DEBUG_MSG("Failed to discover root servers in servstat_thread() (server section #%d).\n",i);
436
if(adrs) da_free(adrs);
437
if(DA_NEL(sp->atup_a)) keep_testing=1;
442
if (needs_testing(sp)) keep_testing=1;
443
m=DA_NEL(sp->atup_a);
445
if(DA_INDEX(sp->atup_a,j).i_ts)
446
goto individual_tests;
447
/* Test collectively */
448
if(!signal_interrupt) retest(i,-1);
452
for(j=0; !signal_interrupt && j<m; ++j) {
453
time_t ts=DA_INDEX(sp->atup_a,j).i_ts, now;
455
if (ts==0 /* Always test servers with timestamp 0 */ ||
456
(needs_intermittent_testing(sp) &&
457
((now=time(NULL))-ts>sp->interval ||
458
ts>now /* kluge for clock skew */)))
464
} while(!signal_interrupt && retest_flag);
468
/* Break the loop and exit the thread if it is no longer needed. */
469
if(!keep_testing) break;
473
struct timespec timeout;
477
gettimeofday(&now,NULL);
478
minwait=3600; /* Check at least once every hour. */
481
servparm_t *sp=&DA_INDEX(servers,i);
482
int j,m=DA_NEL(sp->atup_a);
484
time_t ts= DA_INDEX(sp->atup_a,j).i_ts;
486
/* Test servers with timestamp 0 without delay */
487
if(minwait > 0) minwait=0;
489
else if(needs_intermittent_testing(sp)) {
490
time_t wait= ts + sp->interval - now.tv_sec;
491
if(wait < minwait) minwait=wait;
495
timeout.tv_sec = now.tv_sec;
497
timeout.tv_sec += minwait;
498
timeout.tv_nsec = now.tv_usec * 1000 + 500000000; /* wait at least half a second. */
499
if(timeout.tv_nsec>=1000000000) {
500
timeout.tv_nsec -= 1000000000;
503
/* While we wait for a server_test_cond condition or a timeout
504
the servers_lock mutex is unlocked, so other threads can access
507
retval=pthread_cond_timedwait(&server_test_cond, &servers_lock, &timeout);
508
DEBUG_MSG("Server status thread woke up (%s signal).\n",
509
retval==0?"test condition":retval==ETIMEDOUT?"timer":retval==EINTR?"interrupt":"error");
513
/* server status thread no longer needed. */
514
servstat_thrid=main_thrid;
515
pthread_mutex_unlock(&servers_lock);
516
DEBUG_MSG("Server status thread exiting.\n");
521
* Start the server status thread.
523
int start_servstat_thread()
527
int rv=pthread_create(&stt,&attr_detached,servstat_thread,NULL);
529
log_warn("Failed to start server status thread: %s",strerror(rv));
532
log_info(2,"Server status thread started.");
538
* This can be used to mark a server (or a list of nadr servers) up (up=1) or down (up=0),
539
* or to schedule an immediate retest (up=-1).
540
* We can't always use indices to identify a server, because we allow run-time
541
* configuration of server addresses, so the servers are identified by their IP addresses.
543
void sched_server_test(pdnsd_a *sa, int nadr, int up)
547
pthread_mutex_lock(&servers_lock);
550
/* This obviously isn't very efficient, but nadr should be small
551
and anything else would introduce considerable overhead */
552
for(k=0;k<nadr;++k) {
553
pdnsd_a *sak= &sa[k];
554
int i,n=DA_NEL(servers);
556
servparm_t *sp=&DA_INDEX(servers,i);
557
int j,m=DA_NEL(sp->atup_a);
559
atup_t *at=&DA_INDEX(sp->atup_a,j);
560
if(equiv_inaddr2(sak,&at->a)) {
564
DEBUG_PDNSDA_MSG("Marked server %s %s.\n",PDNSDA2STR(sak),up?"up":"down");
567
/* A test may take a while, and we don't want to hold
568
up the calling thread.
569
Instead we set the timestamp to zero and signal
570
a condition which should wake up the server test thread.
579
if(signal_test) pthread_cond_signal(&server_test_cond);
581
pthread_mutex_unlock(&servers_lock);
584
/* Mark a set of servers up or down or schedule uptests.
585
* If i>=0 only the server section with index i is scanned,
586
* if i<0 all sections are scanned.
587
* Only sections matching label are actually set. A NULL label matches
589
* up=1 or up=0 means mark server up or down, up=-1 means retest.
591
* A non-zero return value indicates an error.
593
int mark_servers(int i, char *label, int up)
595
int retval=0,n,signal_test;
597
pthread_mutex_lock(&servers_lock);
602
/* just one section */
606
i=0; /* scan all sections */
609
servparm_t *sp=&DA_INDEX(servers,i);
610
if(!label || (sp->label && !strcmp(sp->label,label))) {
611
int j,m=DA_NEL(sp->atup_a);
613
/* If a section with undiscovered root servers is marked up, signal a test. */
614
if(m && sp->rootserver>1 && up>0) signal_test=1;
617
atup_t *at=&DA_INDEX(sp->atup_a,j);
623
/* A test may take a while, and we don't want to hold
624
up the calling thread.
625
Instead we set the timestamp to zero and signal
626
a condition which should wake up the server test thread.
635
if(pthread_equal(servstat_thrid,main_thrid))
636
retval=start_servstat_thread();
639
retval=pthread_cond_signal(&server_test_cond);
643
pthread_mutex_unlock(&servers_lock);
648
* Test called by the dns query handlers to handle interval=onquery cases.
654
pthread_mutex_lock(&servers_lock);
659
servparm_t *sp=&DA_INDEX(servers,i);
660
if (sp->interval==-1) {
661
if(sp->rootserver<=1)
664
/* We leave root-server discovery to the server status thread */
665
int j,m=DA_NEL(sp->atup_a);
667
DA_INDEX(sp->atup_a,j).i_ts=0;
675
if(pthread_equal(servstat_thrid,main_thrid))
676
start_servstat_thread();
679
if((rv=pthread_cond_signal(&server_test_cond))) {
680
DEBUG_MSG("test_onquery(): couldn't signal server status thread: %s\n",strerror(rv));
685
pthread_mutex_unlock(&servers_lock);
688
/* non-exclusive lock, for read only access to server data. */
689
void lock_server_data()
691
pthread_mutex_lock(&servers_lock);
693
pthread_mutex_unlock(&servers_lock);
696
void unlock_server_data()
698
pthread_mutex_lock(&servers_lock);
699
PDNSD_ASSERT(server_data_users>0, "server_data_users non-positive before attempt to decrement it");
700
if (--server_data_users==0) pthread_cond_broadcast(&server_data_cond);
701
pthread_mutex_unlock(&servers_lock);
704
/* Try to obtain an exclusive lock, needed for modifying server data.
705
Return 1 on success, 0 on failure (time out after tm seconds).
707
int exclusive_lock_server_data(int tm)
710
struct timespec timeout;
712
pthread_mutex_lock(&servers_lock);
713
if(server_status_ping>0 && !pthread_equal(servstat_thrid,main_thrid)) {
715
/* Try to interrupt server status thread to prevent delays. */
716
DEBUG_MSG("Sending server status thread an interrupt signal.\n");
717
if((err=pthread_kill(servstat_thrid,statusintsig))) {
718
DEBUG_MSG("pthread_kill failed: %s\n",strerror(err));
721
gettimeofday(&now,NULL);
722
timeout.tv_sec = now.tv_sec + tm; /* time out after tm seconds */
723
timeout.tv_nsec = now.tv_usec * 1000;
724
while (server_data_users>0) {
725
if(pthread_cond_timedwait(&server_data_cond, &servers_lock, &timeout) == ETIMEDOUT) {
726
pthread_mutex_unlock(&servers_lock);
732
/* Call this to free the lock obtained with exclusive_lock_server_data().
733
If retest is nonzero, the server-status thread is reactivated to check
734
which servers are up. This is useful in case the configuration has changed.
736
void exclusive_unlock_server_data(int retest)
739
if(pthread_equal(servstat_thrid,main_thrid))
740
start_servstat_thread();
742
pthread_cond_signal(&server_test_cond);
744
pthread_mutex_unlock(&servers_lock);
748
Change addresses of servers during runtime.
749
i is the number of the server section to change.
750
ar should point to an array of IP addresses (may be NULL).
751
up=1 or up=0 means mark server up or down afterwards,
754
A non-zero return value indicates an error.
756
int change_servers(int i, addr_array ar, int up)
758
int retval=0,j,change,signal_test;
762
pthread_mutex_lock(&servers_lock);
767
sp=&DA_INDEX(servers,i);
768
if(n != DA_NEL(sp->atup_a) || sp->rootserver>1)
773
if(!same_inaddr2(&DA_INDEX(ar,j),&DA_INDEX(sp->atup_a,j).a)) {
779
/* we need exclusive access to the server data to make the changes */
781
struct timespec timeout;
784
if(server_status_ping>0 && !pthread_equal(servstat_thrid,main_thrid)) {
786
/* Try to interrupt server status thread to prevent delays. */
787
DEBUG_MSG("Sending server status thread an interrupt signal.\n");
788
if((err=pthread_kill(servstat_thrid,statusintsig))) {
789
DEBUG_MSG("pthread_kill failed: %s\n",strerror(err));
793
DEBUG_MSG("Changing IPs of server section #%d\n",i);
794
gettimeofday(&now,NULL);
795
timeout.tv_sec = now.tv_sec + 60; /* time out after 60 seconds */
796
timeout.tv_nsec = now.tv_usec * 1000;
797
while (server_data_users>0) {
798
if(pthread_cond_timedwait(&server_data_cond, &servers_lock, &timeout) == ETIMEDOUT) {
804
ata= DA_CREATE(atup_array, n);
806
log_warn("Out of memory in change_servers().");
812
/* Stop trying to discover rootservers
813
if we set the addresses using this routine. */
814
if(sp->rootserver>1) sp->rootserver=1;
818
atup_t *at = &DA_INDEX(sp->atup_a,j);
820
SET_PDNSD_A2(&at->a, &DA_INDEX(ar,j));
821
at->is_up=sp->preset;
827
else if(change || at->i_ts) {
828
/* A test may take a while, and we don't want to hold
829
up the calling thread.
830
Instead we set the timestamp to zero and signal
831
a condition which should wake up the server test thread.
839
if(pthread_equal(servstat_thrid,main_thrid))
840
retval=start_servstat_thread();
843
retval=pthread_cond_signal(&server_test_cond);
848
pthread_mutex_unlock(&servers_lock);
854
The signal handler for the signal to tell the server status thread to discontinue testing.
856
static void sigint_handler(int signum)