📄 ntp_intres.c
字号:
/* * ripped off from ../ntpres/ntpres.c by Greg Troxel 4/2/92 * routine callable from ntpd, rather than separate program * also, key info passed in via a global, so no key file needed. *//* * ntpres - process configuration entries which require use of the resolver * * This is meant to be run by ntpd on the fly. It is not guaranteed * to work properly if run by hand. This is actually a quick hack to * stave off violence from people who hate using numbers in the * configuration file (at least I hope the rest of the daemon is * better than this). Also might provide some ideas about how one * might go about autoconfiguring an NTP distribution network. * */#ifdef HAVE_CONFIG_H# include <config.h>#endif#include "ntp_machine.h"#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 <signal.h>/**/#include <netinet/in.h>#include <arpa/inet.h>/**/#ifdef HAVE_SYS_PARAM_H# include <sys/param.h> /* MAXHOSTNAMELEN (often) */#endif#include <isc/net.h>#include <isc/result.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 conf_entry { struct conf_entry *ce_next; char *ce_name; /* name we are trying to resolve */ struct conf_peer ce_config; /* configuration info for peer */ struct sockaddr_storage peer_store; /* address info for both fams */};#define ce_peeraddr ce_config.peeraddr#define ce_peeraddr6 ce_config.peeraddr6#define ce_hmode ce_config.hmode#define ce_version ce_config.version#define ce_minpoll ce_config.minpoll#define ce_maxpoll ce_config.maxpoll#define ce_flags ce_config.flags#define ce_ttl ce_config.ttl#define ce_keyid ce_config.keyid#define ce_keystr ce_config.keystr/* * confentries is a pointer to the list of configuration entries * we have left to do. */static struct conf_entry *confentries = 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 2static 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/* * Input processing. The data on each line in the configuration file * is supposed to consist of entries in the following order */#define TOK_HOSTNAME 0#define TOK_HMODE 1#define TOK_VERSION 2#define TOK_MINPOLL 3#define TOK_MAXPOLL 4#define TOK_FLAGS 5#define TOK_TTL 6#define TOK_KEYID 7#define TOK_KEYSTR 8#define NUMTOK 9#define MAXLINESIZE 512/* * File descriptor for ntp request code. */static SOCKET sockfd = INVALID_SOCKET; /* NT uses SOCKET *//* stuff to be filled in by caller */keyid_t req_keyid; /* request keyid */char *req_file; /* name of the file with configuration info *//* end stuff to be filled in */static RETSIGTYPE bong P((int));static void checkparent P((void));static void removeentry P((struct conf_entry *));static void addentry P((char *, int, int, int, int, u_int, int, keyid_t, char *));static int findhostaddr P((struct conf_entry *));static void openntp P((void));static int request P((struct conf_peer *));static char * nexttoken P((char **));static void readconf P((FILE *, char *));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[MAXHOSTNAMELEN]; /* Name to look up (if 1st byte is not 0) */};struct ntp_res_c_pkt { /* Control packet: */ char name[MAXHOSTNAMELEN]; u_int32 paddr; int mode; int version; int minpoll; int maxpoll; u_int flags; int ttl; keyid_t keyid; u_char keystr[MAXFILENAME];};static void resolver_exit P((int));/* * Call here instead of just exiting */static void resolver_exit (int code){#ifdef SYS_WINNT ExitThread (code); /* Just to kill the thread not the process */#else exit (code); /* fill the forked process */#endif}/* * ntp_res_recv: Process an answer from the resolver */voidntp_res_recv(void){ /* We have data ready on our descriptor. It may be an EOF, meaning the resolver process went away. Otherwise, it will be an "answer". */}/* * ntp_intres needs; * * req_key(???), req_keyid, req_file valid * syslog still open */voidntp_intres(void){ FILE *in;#ifdef HAVE_SIGSUSPEND sigset_t set; sigemptyset(&set);#endif /* HAVE_SIGSUSPEND */#ifdef DEBUG if (debug > 1) { msyslog(LOG_INFO, "NTP_INTRES running"); }#endif /* check out auth stuff */ if (sys_authenticate) { if (!authistrusted(req_keyid)) { msyslog(LOG_ERR, "invalid request keyid %08x", req_keyid ); resolver_exit(1); } } /* * Read the configuration info * {this is bogus, since we are forked, but it is easier * to keep this code - gdt} */ if ((in = fopen(req_file, "r")) == NULL) { msyslog(LOG_ERR, "can't open configuration file %s: %m", req_file); resolver_exit(1); } readconf(in, req_file); (void) fclose(in); if (!debug ) (void) unlink(req_file); /* * Sleep a little to make sure the server is completely up */ sleep(SLEEPTIME); /* * Make a first cut at resolving the bunch */ doconfigure(1); if (confentries == NULL) { resolver_exit(0); } /* * 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 (confentries == NULL) resolver_exit(0); checkparent(); if (resolve_timer == 0) { if (resolve_value < MAXRESOLVE) resolve_value <<= 1; resolve_timer = resolve_value;#ifdef DEBUG if (debug > 2) 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 if (debug > 2) 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 RETSIGTYPEbong( 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 voidcheckparent(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"); resolver_exit(0); }#endif /* SYS_WINNT && SYS_VXWORKS*/}/* * removeentry - we are done with an entry, remove it from the list */static voidremoveentry( struct conf_entry *entry ){ register struct conf_entry *ce; ce = confentries; if (ce == entry) { confentries = ce->ce_next; return; } while (ce != NULL) { if (ce->ce_next == entry) { ce->ce_next = entry->ce_next; return; } ce = ce->ce_next; }}/* * addentry - add an entry to the configuration list */static voidaddentry( char *name, int mode, int version, int minpoll, int maxpoll, u_int flags, int ttl, keyid_t keyid, char *keystr ){ register char *cp; register struct conf_entry *ce; unsigned int len;#ifdef DEBUG if (debug > 1) msyslog(LOG_INFO, "intres: <%s> %d %d %d %d %x %d %x %s\n", name, mode, version, minpoll, maxpoll, flags, ttl, keyid, keystr);#endif len = strlen(name) + 1; cp = (char *)emalloc(len); memmove(cp, name, len); ce = (struct conf_entry *)emalloc(sizeof(struct conf_entry)); ce->ce_name = cp; ce->ce_peeraddr = 0;#ifdef ISC_PLATFORM_HAVEIPV6 ce->ce_peeraddr6 = in6addr_any;#endif ANYSOCK(&ce->peer_store); ce->ce_hmode = (u_char)mode; ce->ce_version = (u_char)version; ce->ce_minpoll = (u_char)minpoll; ce->ce_maxpoll = (u_char)maxpoll; ce->ce_flags = (u_char)flags; ce->ce_ttl = (u_char)ttl; ce->ce_keyid = keyid; strncpy((char *)ce->ce_keystr, keystr, MAXFILENAME); ce->ce_next = NULL; if (confentries == NULL) { confentries = ce; } else { register struct conf_entry *cep; for (cep = confentries; cep->ce_next != NULL; cep = cep->ce_next) /* nothing */; cep->ce_next = ce; }}/* * findhostaddr - resolve a host name into an address (Or vice-versa) * * Given one of {ce_peeraddr,ce_name}, find the other one. * It returns 1 for "success" and 0 for an uncorrectable failure. * Note that "success" includes try again errors. You can tell that you * got a "try again" since {ce_peeraddr,ce_name} will still be zero. */static intfindhostaddr( struct conf_entry *entry ){ struct addrinfo *addr; struct addrinfo hints; int error; checkparent(); /* make sure our guy is still running */ if (entry->ce_name != NULL && !SOCKNUL(&entry->peer_store)) { /* HMS: Squawk? */ msyslog(LOG_ERR, "findhostaddr: both ce_name and ce_peeraddr are defined..."); return 1; } if (entry->ce_name == NULL && SOCKNUL(&entry->peer_store)) { msyslog(LOG_ERR, "findhostaddr: both ce_name and ce_peeraddr are undefined!"); return 0; } if (entry->ce_name) {#ifdef DEBUG if (debug > 2) msyslog(LOG_INFO, "findhostaddr: Resolving <%s>", entry->ce_name);#endif /* DEBUG */ memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; /* * If the IPv6 stack is not available look only for IPv4 addresses */ if (isc_net_probeipv6() != ISC_R_SUCCESS) hints.ai_family = AF_INET; error = getaddrinfo(entry->ce_name, NULL, &hints, &addr); if (error == 0) { entry->peer_store = *((struct sockaddr_storage*)(addr->ai_addr)); if (entry->peer_store.ss_family == AF_INET) { entry->ce_peeraddr = GET_INADDR(entry->peer_store); entry->ce_config.v6_flag = 0; } else { entry->ce_peeraddr6 = GET_INADDR6(entry->peer_store); entry->ce_config.v6_flag = 1; } } } else {#ifdef DEBUG if (debug > 2) msyslog(LOG_INFO, "findhostaddr: Resolving %s>", stoa(&entry->peer_store));#endif entry->ce_name = emalloc(MAXHOSTNAMELEN); error = getnameinfo((const struct sockaddr *)&entry->peer_store, SOCKLEN(&entry->peer_store), (char *)&entry->ce_name, MAXHOSTNAMELEN, NULL, 0, 0); } if (error != 0) { /* * If the resolver is in use, see if the failure is * temporary. If so, return success. */ if (error == EAI_AGAIN) return (1); return (0); } if (entry->ce_name) {#ifdef DEBUG if (debug > 2) msyslog(LOG_INFO, "findhostaddr: name resolved.");#endif#ifdef DEBUG if (debug > 2) msyslog(LOG_INFO, "findhostaddr: address resolved.");#endif } return (1);}/* * openntp - open a socket to the ntp server */static void
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -