Merge conflicts.
MFC after: 1 month
This commit is contained in:
parent
17de533074
commit
8fe9403f63
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=106166
@ -400,6 +400,9 @@ static u_char clocktypes[] = {
|
||||
CTL_SST_TS_LF, /* REFCLK_FG (37) */
|
||||
CTL_SST_TS_UHF, /* REFCLK_HOPF_SERIAL (38) */
|
||||
CTL_SST_TS_UHF, /* REFCLK_HOPF_PCI (39) */
|
||||
CTL_SST_TS_LF, /* REFCLK_JJY (40) */
|
||||
CTL_SST_TS_UHF, /* REFCLK_TT560 (41) */
|
||||
CTL_SST_TS_UHF, /* REFCLK_ZYFER (42) */
|
||||
};
|
||||
|
||||
|
||||
|
@ -311,11 +311,7 @@ receive(
|
||||
#endif
|
||||
if (restrict_mask & RES_IGNORE)
|
||||
return; /* no anything */
|
||||
if (!(SRCPORT(&rbufp->recv_srcadr) == NTP_PORT ||
|
||||
SRCPORT(&rbufp->recv_srcadr) >= IPPORT_RESERVED)) {
|
||||
sys_badlength++;
|
||||
return; /* invalid port */
|
||||
}
|
||||
|
||||
pkt = &rbufp->recv_pkt;
|
||||
if (PKT_VERSION(pkt->li_vn_mode) == NTP_VERSION) {
|
||||
sys_newversionpkt++; /* new version */
|
||||
@ -2508,7 +2504,8 @@ int
|
||||
default_get_precision(void)
|
||||
{
|
||||
struct timeval tp;
|
||||
#if !defined(SYS_WINNT) && !defined(VMS) && !defined(_SEQUENT_)
|
||||
#if !defined(SYS_WINNT) && !defined(VMS) && !defined(_SEQUENT_) && \
|
||||
!defined(MPE)
|
||||
struct timezone tzp;
|
||||
#elif defined(VMS) || defined(_SEQUENT_)
|
||||
struct timezone {
|
||||
|
@ -1,987 +0,0 @@
|
||||
/*
|
||||
** 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;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user