diff options
Diffstat (limited to 'contrib/ntp/ntpd/ntp_resolver.c')
-rw-r--r-- | contrib/ntp/ntpd/ntp_resolver.c | 987 |
1 files changed, 987 insertions, 0 deletions
diff --git a/contrib/ntp/ntpd/ntp_resolver.c b/contrib/ntp/ntpd/ntp_resolver.c new file mode 100644 index 0000000..84b2583 --- /dev/null +++ b/contrib/ntp/ntpd/ntp_resolver.c @@ -0,0 +1,987 @@ +/* +** Ancestor was ripped off from ../ntpres/ntpres.c by Greg Troxel 4/2/92 +** +** The previous resolver only needed to do forward lookups, and all names +** were known before we started the resolver process. +** +** The new code must be able to handle reverse lookups, and the requests can +** show up at any time. +** +** Here's the drill for the new logic. +** +** We want to be able to do forward or reverse lookups. Forward lookups +** require one set of information to be sent back to the daemon, reverse +** lookups require a different set of information. The caller knows this. +** +** The daemon must not block. This includes communicating with the resolver +** process (if the resolver process is a separate task). +** +** Current resolver code blocks waiting for the response, so the +** alternatives are: +** +** - Find a nonblocking resolver library +** - Do each (initial) lookup in a separate process +** - - subsequent lookups *could* be handled by a different process that has +** a queue of pending requests +** +** We could use nonblocking lookups in a separate process (just to help out +** with timers). +** +** If we don't have nonblocking resolver calls we have more opportunities +** for denial-of-service problems. +** +** - too many fork()s +** - communications path +** +*/ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_request.h" +#include "ntp_stdlib.h" +#include "ntp_syslog.h" + +#include <stdio.h> +#include <ctype.h> +#include <netdb.h> +#include <signal.h> + +#include <netinet/in.h> +#include <arpa/inet.h> + +#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) + +/* + * Each item we are to resolve and configure gets one of these + * structures defined for it. + */ +struct dns_entry { + int de_done; +#define DE_NAME 001 +#define DE_ADDR 002 +#define DE_NA (DE_NAME | DE_ADDR) +#define DE_PENDING 000 +#define DE_GOT 010 +#define DE_FAIL 020 +#define DE_RESULT (DE_PENDING | DE_GOT | DE_FAIL) + struct dns_entry *de_next; + struct info_dns_assoc de_info; /* DNS info for peer */ +}; +#define de_associd de_info.associd +#define de_peeraddr de_info.peeraddr +#define de_hostname de_info.hostname + +/* + * dns_entries is a pointer to the list of configuration entries + * we have left to do. + */ +static struct dns_entry *dns_entries = NULL; + +/* + * We take an interrupt every thirty seconds, at which time we decrement + * config_timer and resolve_timer. The former is set to 2, so we retry + * unsucessful reconfigurations every minute. The latter is set to + * an exponentially increasing value which starts at 2 and increases to + * 32. When this expires we retry failed name resolutions. + * + * We sleep SLEEPTIME seconds before doing anything, to give the server + * time to arrange itself. + */ +#define MINRESOLVE 2 +#define MAXRESOLVE 32 +#define CONFIG_TIME 2 +#define ALARM_TIME 30 + +#define SLEEPTIME 2 + +static volatile int config_timer = 0; +static volatile int resolve_timer = 0; + +static int resolve_value; /* next value of resolve timer */ + +/* + * Big hack attack + */ +#define LOCALHOST 0x7f000001 /* 127.0.0.1, in hex, of course */ +#define SKEWTIME 0x08000000 /* 0.03125 seconds as a l_fp fraction */ + +/* + * Select time out. Set to 2 seconds. The server is on the local machine, + * after all. + */ +#define TIMEOUT_SEC 2 +#define TIMEOUT_USEC 0 + +/* + * File descriptor for ntp request code. + */ +static int sockfd = -1; + +/* + * Pipe descriptors + */ +int p_fd[2] = { -1, -1 }; + +/* stuff to be filled in by caller */ + +extern keyid_t req_keyid; /* request keyid */ + +/* end stuff to be filled in */ + +void ntp_res P((void)); +static RETSIGTYPE bong P((int)); +static void checkparent P((void)); +static void removeentry P((struct dns_entry *)); +static void addentry P((char *, u_int32, u_short)); +static void findhostaddr P((struct dns_entry *)); +static void openntp P((void)); +static int tell_ntpd P((struct info_dns_assoc *)); +static void doconfigure P((int)); + +struct ntp_res_t_pkt { /* Tagged packet: */ + void *tag; /* For the caller */ + u_int32 paddr; /* IP to look up, or 0 */ + char name[NTP_MAXHOSTNAME]; /* Name to look up (if 1st byte is not 0) */ +}; + +struct ntp_res_c_pkt { /* Control packet: */ + char name[NTP_MAXHOSTNAME]; + u_int32 paddr; + int mode; + int version; + int minpoll; + int maxpoll; + int flags; + int ttl; + keyid_t keyid; + u_char keystr[MAXFILENAME]; +}; + +/* + * ntp_res_name + */ + +void +ntp_res_name( + u_int32 paddr, /* Address to resolve */ + u_short associd /* Association ID */ + ) +{ + pid_t pid; + + /* + * fork. + * - parent returns + * - child stuffs data and calls ntp_res() + */ + + for (pid = -1; pid == -1;) { +#ifdef RES_TEST + pid = 0; +#else + pid = fork(); +#endif + if (pid == -1) { + msyslog(LOG_ERR, "ntp_res_name: fork() failed: %m"); + sleep(2); + } + } + switch (pid) { + case -1: /* Error */ + msyslog(LOG_INFO, "ntp_res_name: error..."); + /* Can't happen */ + break; + + case 0: /* Child */ + closelog(); + kill_asyncio(); + (void) signal_no_reset(SIGCHLD, SIG_DFL); +#ifndef LOG_DAEMON + openlog("ntp_res", LOG_PID); +# else /* LOG_DAEMON */ +# ifndef LOG_NTP +# define LOG_NTP LOG_DAEMON +# endif + openlog("ntp_res_name", LOG_PID | LOG_NDELAY, LOG_NTP); +#endif + + addentry(NULL, paddr, associd); + ntp_res(); + break; + + default: /* Parent */ + /* Nothing to do. (In Real Life, this never happens.) */ + return; + } +} + +/* + * ntp_res needs; + * + * req_key(???), req_keyid valid + * syslog still open + */ + +void +ntp_res(void) +{ +#ifdef HAVE_SIGSUSPEND + sigset_t set; + + sigemptyset(&set); +#endif /* HAVE_SIGSUSPEND */ + +#ifdef DEBUG + if (debug) { + msyslog(LOG_INFO, "NTP_RESOLVER running"); + } +#endif + + /* check out auth stuff */ + if (sys_authenticate) { + if (!authistrusted(req_keyid)) { + msyslog(LOG_ERR, "invalid request keyid %08x", + req_keyid ); + exit(1); + } + } + + /* + * Make a first cut at resolving the bunch + */ + doconfigure(1); + if (dns_entries == NULL) { + if (debug) { + msyslog(LOG_INFO, "NTP_RESOLVER done!"); + } +#if defined SYS_WINNT + ExitThread(0); /* Don't want to kill whole NT process */ +#else + exit(0); /* done that quick */ +#endif + } + + /* + * Here we've got some problem children. Set up the timer + * and wait for it. + */ + resolve_value = resolve_timer = MINRESOLVE; + config_timer = CONFIG_TIME; +#ifndef SYS_WINNT + (void) signal_no_reset(SIGALRM, bong); + alarm(ALARM_TIME); +#endif /* SYS_WINNT */ + + for (;;) { + if (dns_entries == NULL) + exit(0); + + checkparent(); + + if (resolve_timer == 0) { + if (resolve_value < MAXRESOLVE) + resolve_value <<= 1; + resolve_timer = resolve_value; +#ifdef DEBUG + msyslog(LOG_INFO, "resolve_timer: 0->%d", resolve_timer); +#endif + config_timer = CONFIG_TIME; + doconfigure(1); + continue; + } else if (config_timer == 0) { + config_timer = CONFIG_TIME; +#ifdef DEBUG + msyslog(LOG_INFO, "config_timer: 0->%d", config_timer); +#endif + doconfigure(0); + continue; + } +#ifndef SYS_WINNT + /* + * There is a race in here. Is okay, though, since + * all it does is delay things by 30 seconds. + */ +# ifdef HAVE_SIGSUSPEND + sigsuspend(&set); +# else + sigpause(0); +# endif /* HAVE_SIGSUSPEND */ +#else + if (config_timer > 0) + config_timer--; + if (resolve_timer > 0) + resolve_timer--; + sleep(ALARM_TIME); +#endif /* SYS_WINNT */ + } +} + + +#ifndef SYS_WINNT +/* + * bong - service and reschedule an alarm() interrupt + */ +static RETSIGTYPE +bong( + int sig + ) +{ + if (config_timer > 0) + config_timer--; + if (resolve_timer > 0) + resolve_timer--; + alarm(ALARM_TIME); +} +#endif /* SYS_WINNT */ + +/* + * checkparent - see if our parent process is still running + * + * No need to worry in the Windows NT environment whether the + * main thread is still running, because if it goes + * down it takes the whole process down with it (in + * which case we won't be running this thread either) + * Turn function into NOP; + */ + +static void +checkparent(void) +{ +#if !defined (SYS_WINNT) && !defined (SYS_VXWORKS) + + /* + * If our parent (the server) has died we will have been + * inherited by init. If so, exit. + */ + if (getppid() == 1) { + msyslog(LOG_INFO, "parent died before we finished, exiting"); + exit(0); + } +#endif /* SYS_WINNT && SYS_VXWORKS*/ +} + + +/* + * removeentry - we are done with an entry, remove it from the list + */ +static void +removeentry( + struct dns_entry *entry + ) +{ + register struct dns_entry *de; + + de = dns_entries; + if (de == entry) { + dns_entries = de->de_next; + return; + } + + while (de != NULL) { + if (de->de_next == entry) { + de->de_next = entry->de_next; + return; + } + de = de->de_next; + } +} + + +/* + * addentry - add an entry to the configuration list + */ +static void +addentry( + char *name, + u_int32 paddr, + u_short associd + ) +{ + register struct dns_entry *de; + +#ifdef DEBUG + if (debug > 1) { + struct in_addr si; + + si.s_addr = paddr; + msyslog(LOG_INFO, + "ntp_res_name: <%s> %s associd %d\n", + (name) ? name : "", inet_ntoa(si), associd); + } +#endif + + de = (struct dns_entry *)emalloc(sizeof(struct dns_entry)); + if (name) { + strncpy(de->de_hostname, name, sizeof de->de_hostname); + de->de_done = DE_PENDING | DE_ADDR; + } else { + de->de_hostname[0] = 0; + de->de_done = DE_PENDING | DE_NAME; + } + de->de_peeraddr = paddr; + de->de_associd = associd; + de->de_next = NULL; + + if (dns_entries == NULL) { + dns_entries = de; + } else { + register struct dns_entry *dep; + + for (dep = dns_entries; dep->de_next != NULL; + dep = dep->de_next) + /* nothing */; + dep->de_next = de; + } +} + + +/* + * findhostaddr - resolve a host name into an address (Or vice-versa) + * + * sets entry->de_done appropriately when we're finished. We're finished if + * we either successfully look up the missing name or address, or if we get a + * "permanent" failure on the lookup. + * + */ +static void +findhostaddr( + struct dns_entry *entry + ) +{ + struct hostent *hp; + + checkparent(); /* make sure our guy is still running */ + + /* + * The following should never trip - this subroutine isn't + * called if hostname and peeraddr are "filled". + */ + if (entry->de_hostname[0] && entry->de_peeraddr) { + struct in_addr si; + + si.s_addr = entry->de_peeraddr; + msyslog(LOG_ERR, "findhostaddr: both de_hostname and de_peeraddr are defined: <%s>/%s: state %#x", + &entry->de_hostname[0], inet_ntoa(si), entry->de_done); + return; + } + + /* + * The following should never trip. + */ + if (!entry->de_hostname[0] && !entry->de_peeraddr) { + msyslog(LOG_ERR, "findhostaddr: both de_hostname and de_peeraddr are undefined!"); + entry->de_done |= DE_FAIL; + return; + } + + if (entry->de_hostname[0]) { +#ifdef DEBUG + if (debug > 2) + msyslog(LOG_INFO, "findhostaddr: Resolving <%s>", + &entry->de_hostname[0]); +#endif /* DEBUG */ + hp = gethostbyname(&entry->de_hostname[0]); + } else { +#ifdef DEBUG + if (debug > 2) { + struct in_addr si; + + si.s_addr = entry->de_peeraddr; + msyslog(LOG_INFO, "findhostaddr: Resolving %s", + inet_ntoa(si)); + } +#endif + hp = gethostbyaddr((const char *)&entry->de_peeraddr, + sizeof entry->de_peeraddr, + AF_INET); + } + + if (hp == NULL) { + /* + * Bail if we should TRY_AGAIN. + * Otherwise, we have a permanent failure. + */ + if (h_errno == TRY_AGAIN) + return; + entry->de_done |= DE_FAIL; + } else { + entry->de_done |= DE_GOT; + } + + if (entry->de_done & DE_GOT) { + switch (entry->de_done & DE_NA) { + case DE_NAME: +#ifdef DEBUG + if (debug > 2) + msyslog(LOG_INFO, + "findhostaddr: name resolved."); +#endif + /* + * Use the first address. We don't have any way to + * tell preferences and older gethostbyname() + * implementations only return one. + */ + memmove((char *)&(entry->de_peeraddr), + (char *)hp->h_addr, + sizeof(struct in_addr)); + break; + case DE_ADDR: +#ifdef DEBUG + if (debug > 2) + msyslog(LOG_INFO, + "findhostaddr: address resolved."); +#endif + strncpy(&entry->de_hostname[0], hp->h_name, + sizeof entry->de_hostname); + break; + default: + msyslog(LOG_ERR, "findhostaddr: Bogus de_done: %#x", + entry->de_done); + break; + } + } else { +#ifdef DEBUG + if (debug > 2) { + struct in_addr si; + const char *hes; +#ifndef HAVE_HSTRERROR + char hnum[20]; + + switch (h_errno) { + case HOST_NOT_FOUND: + hes = "Authoritive Answer Host not found"; + break; + case TRY_AGAIN: + hes = "Non-Authoritative Host not found, or SERVERFAIL"; + break; + case NO_RECOVERY: + hes = "Non recoverable errors, FORMERR, REFUSED, NOTIMP"; + break; + case NO_DATA: + hes = "Valid name, no data record of requested type"; + break; + default: + snprintf(hnum, sizeof hnum, "%d", h_errno); + hes = hnum; + break; + } +#else + hes = hstrerror(h_errno); +#endif + + si.s_addr = entry->de_peeraddr; + msyslog(LOG_INFO, + "findhostaddr: Failed resolution on <%s>/%s: %s", + entry->de_hostname, inet_ntoa(si), hes); + } +#endif + /* Send a NAK message back to the daemon */ + } + return; +} + + +/* + * openntp - open a socket to the ntp server + */ +static void +openntp(void) +{ + struct sockaddr_in saddr; + + if (sockfd >= 0) + return; + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd == -1) { + msyslog(LOG_ERR, "socket() failed: %m"); + exit(1); + } + + memset((char *)&saddr, 0, sizeof(saddr)); + saddr.sin_family = AF_INET; + saddr.sin_port = htons(NTP_PORT); /* trash */ + saddr.sin_addr.s_addr = htonl(LOCALHOST); /* garbage */ + + /* + * Make the socket non-blocking. We'll wait with select() + */ +#ifndef SYS_WINNT +# if defined(O_NONBLOCK) + if (fcntl(sockfd, F_SETFL, O_NONBLOCK) == -1) { + msyslog(LOG_ERR, "fcntl(O_NONBLOCK) failed: %m"); + exit(1); + } +# else +# if defined(FNDELAY) + if (fcntl(sockfd, F_SETFL, FNDELAY) == -1) { + msyslog(LOG_ERR, "fcntl(FNDELAY) failed: %m"); + exit(1); + } +# else +# include "Bletch: NEED NON BLOCKING IO" +# endif /* FNDDELAY */ +# endif /* O_NONBLOCK */ +#else /* SYS_WINNT */ + { + int on = 1; + + if (ioctlsocket(sockfd,FIONBIO,(u_long *) &on) == SOCKET_ERROR) { + msyslog(LOG_ERR, "ioctlsocket(FIONBIO) fails: %m"); + exit(1); /* Windows NT - set socket in non-blocking mode */ + } + } +#endif /* SYS_WINNT */ + + if (connect(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) { + msyslog(LOG_ERR, "openntp: connect() failed: %m"); + exit(1); + } +} + + +/* + * tell_ntpd: Tell ntpd what we discovered. + */ +static int +tell_ntpd( + struct info_dns_assoc *conf + ) +{ + fd_set fdset; + struct timeval tvout; + struct req_pkt reqpkt; + l_fp ts; + int n; +#ifdef SYS_WINNT + HANDLE hReadWriteEvent = NULL; + BOOL ret; + DWORD NumberOfBytesWritten, NumberOfBytesRead, dwWait; + OVERLAPPED overlap; +#endif /* SYS_WINNT */ + + checkparent(); /* make sure our guy is still running */ + + if (sockfd < 0) + openntp(); + +#ifdef SYS_WINNT + hReadWriteEvent = CreateEvent(NULL, FALSE, FALSE, NULL); +#endif /* SYS_WINNT */ + + /* + * Try to clear out any previously received traffic so it + * doesn't fool us. Note the socket is nonblocking. + */ + tvout.tv_sec = 0; + tvout.tv_usec = 0; + FD_ZERO(&fdset); + FD_SET(sockfd, &fdset); + while (select(sockfd + 1, &fdset, (fd_set *)0, (fd_set *)0, &tvout) > + 0) { + recv(sockfd, (char *)&reqpkt, REQ_LEN_MAC, 0); + FD_ZERO(&fdset); + FD_SET(sockfd, &fdset); + } + + /* + * Make up a request packet with the configuration info + */ + memset((char *)&reqpkt, 0, sizeof(reqpkt)); + + reqpkt.rm_vn_mode = RM_VN_MODE(0, 0, 0); + reqpkt.auth_seq = AUTH_SEQ(1, 0); /* authenticated, no seq */ + reqpkt.implementation = IMPL_XNTPD; /* local implementation */ + reqpkt.request = REQ_HOSTNAME_ASSOCID; /* Hostname for associd */ + reqpkt.err_nitems = ERR_NITEMS(0, 1); /* one item */ + reqpkt.mbz_itemsize = MBZ_ITEMSIZE(sizeof(struct info_dns_assoc)); + memmove(reqpkt.data, (char *)conf, sizeof(struct info_dns_assoc)); + reqpkt.keyid = htonl(req_keyid); + + get_systime(&ts); + L_ADDUF(&ts, SKEWTIME); + HTONL_FP(&ts, &reqpkt.tstamp); + n = 0; + if (sys_authenticate) + n = authencrypt(req_keyid, (u_int32 *)&reqpkt, REQ_LEN_NOMAC); + + /* + * Done. Send it. + */ +#ifndef SYS_WINNT + n = send(sockfd, (char *)&reqpkt, (unsigned)(REQ_LEN_NOMAC + n), 0); + if (n < 0) { + msyslog(LOG_ERR, "send to NTP server failed: %m"); + return 0; /* maybe should exit */ + } +#else + /* In the NT world, documentation seems to indicate that there + * exist _write and _read routines that can be used to do blocking + * I/O on sockets. Problem is these routines require a socket + * handle obtained through the _open_osf_handle C run-time API + * of which there is no explanation in the documentation. We need + * nonblocking write's and read's anyway for our purpose here. + * We're therefore forced to deviate a little bit from the Unix + * model here and use the ReadFile and WriteFile Win32 I/O API's + * on the socket + */ + overlap.Offset = overlap.OffsetHigh = (DWORD)0; + overlap.hEvent = hReadWriteEvent; + ret = WriteFile((HANDLE)sockfd, (char *)&reqpkt, REQ_LEN_NOMAC + n, + (LPDWORD)&NumberOfBytesWritten, (LPOVERLAPPED)&overlap); + if ((ret == FALSE) && (GetLastError() != ERROR_IO_PENDING)) { + msyslog(LOG_ERR, "send to NTP server failed: %m"); + return 0; + } + dwWait = WaitForSingleObject(hReadWriteEvent, (DWORD) TIMEOUT_SEC * 1000); + if ((dwWait == WAIT_FAILED) || (dwWait == WAIT_TIMEOUT)) { + if (dwWait == WAIT_FAILED) + msyslog(LOG_ERR, "WaitForSingleObject failed: %m"); + return 0; + } +#endif /* SYS_WINNT */ + + + /* + * Wait for a response. A weakness of the mode 7 protocol used + * is that there is no way to associate a response with a + * particular request, i.e. the response to this configuration + * request is indistinguishable from that to any other. I should + * fix this some day. In any event, the time out is fairly + * pessimistic to make sure that if an answer is coming back + * at all, we get it. + */ + for (;;) { + FD_ZERO(&fdset); + FD_SET(sockfd, &fdset); + tvout.tv_sec = TIMEOUT_SEC; + tvout.tv_usec = TIMEOUT_USEC; + + n = select(sockfd + 1, &fdset, (fd_set *)0, + (fd_set *)0, &tvout); + + if (n < 0) + { + msyslog(LOG_ERR, "select() fails: %m"); + return 0; + } + else if (n == 0) + { + if(debug) + msyslog(LOG_INFO, "select() returned 0."); + return 0; + } + +#ifndef SYS_WINNT + n = recv(sockfd, (char *)&reqpkt, REQ_LEN_MAC, 0); + if (n <= 0) { + if (n < 0) { + msyslog(LOG_ERR, "recv() fails: %m"); + return 0; + } + continue; + } +#else /* Overlapped I/O used on non-blocking sockets on Windows NT */ + ret = ReadFile((HANDLE)sockfd, (char *)&reqpkt, (DWORD)REQ_LEN_MAC, + (LPDWORD)&NumberOfBytesRead, (LPOVERLAPPED)&overlap); + if ((ret == FALSE) && (GetLastError() != ERROR_IO_PENDING)) { + msyslog(LOG_ERR, "ReadFile() fails: %m"); + return 0; + } + dwWait = WaitForSingleObject(hReadWriteEvent, (DWORD) TIMEOUT_SEC * 1000); + if ((dwWait == WAIT_FAILED) || (dwWait == WAIT_TIMEOUT)) { + if (dwWait == WAIT_FAILED) { + msyslog(LOG_ERR, "WaitForSingleObject fails: %m"); + return 0; + } + continue; + } + n = NumberOfBytesRead; +#endif /* SYS_WINNT */ + + /* + * Got one. Check through to make sure it is what + * we expect. + */ + if (n < RESP_HEADER_SIZE) { + msyslog(LOG_ERR, "received runt response (%d octets)", + n); + continue; + } + + if (!ISRESPONSE(reqpkt.rm_vn_mode)) { +#ifdef DEBUG + if (debug > 1) + msyslog(LOG_INFO, "received non-response packet"); +#endif + continue; + } + + if (ISMORE(reqpkt.rm_vn_mode)) { +#ifdef DEBUG + if (debug > 1) + msyslog(LOG_INFO, "received fragmented packet"); +#endif + continue; + } + + if ( ( (INFO_VERSION(reqpkt.rm_vn_mode) < 2) + || (INFO_VERSION(reqpkt.rm_vn_mode) > NTP_VERSION)) + || INFO_MODE(reqpkt.rm_vn_mode) != MODE_PRIVATE) { +#ifdef DEBUG + if (debug > 1) + msyslog(LOG_INFO, + "version (%d/%d) or mode (%d/%d) incorrect", + INFO_VERSION(reqpkt.rm_vn_mode), + NTP_VERSION, + INFO_MODE(reqpkt.rm_vn_mode), + MODE_PRIVATE); +#endif + continue; + } + + if (INFO_SEQ(reqpkt.auth_seq) != 0) { +#ifdef DEBUG + if (debug > 1) + msyslog(LOG_INFO, + "nonzero sequence number (%d)", + INFO_SEQ(reqpkt.auth_seq)); +#endif + continue; + } + + if (reqpkt.implementation != IMPL_XNTPD || + reqpkt.request != REQ_HOSTNAME_ASSOCID) { +#ifdef DEBUG + if (debug > 1) + msyslog(LOG_INFO, + "implementation (%d/%d) or request (%d/%d) incorrect", + reqpkt.implementation, IMPL_XNTPD, + reqpkt.request, REQ_HOSTNAME_ASSOCID); +#endif + continue; + } + + if (INFO_NITEMS(reqpkt.err_nitems) != 0 || + INFO_MBZ(reqpkt.mbz_itemsize) != 0 || + INFO_ITEMSIZE(reqpkt.mbz_itemsize) != 0) { +#ifdef DEBUG + if (debug > 1) + msyslog(LOG_INFO, + "nitems (%d) mbz (%d) or itemsize (%d) nonzero", + INFO_NITEMS(reqpkt.err_nitems), + INFO_MBZ(reqpkt.mbz_itemsize), + INFO_ITEMSIZE(reqpkt.mbz_itemsize)); +#endif + continue; + } + + n = INFO_ERR(reqpkt.err_nitems); + switch (n) { + case INFO_OKAY: + /* success */ + return 1; + + case INFO_ERR_IMPL: + msyslog(LOG_ERR, + "server reports implementation mismatch!!"); + return 0; + + case INFO_ERR_REQ: + msyslog(LOG_ERR, + "server claims configuration request is unknown"); + return 0; + + case INFO_ERR_FMT: + msyslog(LOG_ERR, + "server indicates a format error occurred(!!)"); + return 0; + + case INFO_ERR_NODATA: + msyslog(LOG_ERR, + "server indicates no data available (shouldn't happen)"); + return 0; + + case INFO_ERR_AUTH: + msyslog(LOG_ERR, + "server returns a permission denied error"); + return 0; + + default: + msyslog(LOG_ERR, + "server returns unknown error code %d", n); + return 0; + } + } +} + + +/* + * doconfigure - attempt to resolve names/addresses + */ +static void +doconfigure( + int dores + ) +{ + register struct dns_entry *de; + register struct dns_entry *deremove; + char *done_msg = ""; + + de = dns_entries; + while (de != NULL) { +#ifdef DEBUG + if (debug > 1) { + struct in_addr si; + + si.s_addr = de->de_peeraddr; + msyslog(LOG_INFO, + "doconfigure: name: <%s> peeraddr: %s", + de->de_hostname, inet_ntoa(si)); + } +#endif + if (dores && (de->de_hostname[0] == 0 || de->de_peeraddr == 0)) { + findhostaddr(de); + } + + switch (de->de_done & DE_RESULT) { + case DE_PENDING: + done_msg = ""; + break; + case DE_GOT: + done_msg = "succeeded"; + break; + case DE_FAIL: + done_msg = "failed"; + break; + default: + done_msg = "(error - shouldn't happen)"; + break; + } + if (done_msg[0]) { + /* Send the answer */ + if (tell_ntpd(&de->de_info)) { + struct in_addr si; + + si.s_addr = de->de_peeraddr; +#ifdef DEBUG + if (debug > 1) { + msyslog(LOG_INFO, + "DNS resolution on <%s>/%s %s", + de->de_hostname, inet_ntoa(si), + done_msg); + } +#endif + deremove = de; + de = deremove->de_next; + removeentry(deremove); + } + } else { + de = de->de_next; + } + } +} |