📄 ntpdc.c
字号:
/* * ntpdc - control and monitor your ntpd daemon */#include <stdio.h>#include <ctype.h>#include <signal.h>#include <setjmp.h>#include "ntpdc.h"#include "ntp_select.h"#include "ntp_io.h"#include "ntp_stdlib.h"/* Don't include ISC's version of IPv6 variables and structures */#define ISC_IPV6_H 1#include "isc/net.h"#include "isc/result.h"#ifdef SYS_WINNT#include <Mswsock.h># include <io.h>#else# define closesocket close#endif /* SYS_WINNT */#if defined(HAVE_LIBREADLINE) || defined (HAVE_LIBEDIT)# include <readline/readline.h># include <readline/history.h>#endif /* HAVE_LIBREADLINE || HAVE_LIBEDIT */#ifdef SYS_VXWORKS/* vxWorks needs mode flag -casey*/#define open(name, flags) open(name, flags, 0777)#define SERVER_PORT_NUM 123#endif/* * Because we now potentially understand a lot of commands (and * it requires a lot of commands to talk to ntpd) we will run * interactive if connected to a terminal. */static int interactive = 0; /* set to 1 when we should prompt */static const char * prompt = "ntpdc> "; /* prompt to ask him about *//* * Keyid used for authenticated requests. Obtained on the fly. */static u_long info_auth_keyid;/* * Type of key md5 */#define KEY_TYPE_MD5 4static int info_auth_keytype = KEY_TYPE_MD5; /* MD5 */u_long current_time; /* needed by authkeys; not used */int ntpdcmain P((int, char **));/* * Built in command handler declarations */static int openhost P((const char *));static int sendpkt P((char *, int));static void growpktdata P((void));static int getresponse P((int, int, int *, int *, char **, int));static int sendrequest P((int, int, int, int, int, char *));static void getcmds P((void));static RETSIGTYPE abortcmd P((int));static void docmd P((const char *));static void tokenize P((const char *, char **, int *));static int findcmd P((char *, struct xcmd *, struct xcmd *, struct xcmd **));static int getarg P((char *, int, arg_v *));static int getnetnum P((const char *, struct sockaddr_storage *, char *, int));static void help P((struct parse *, FILE *));#ifdef QSORT_USES_VOID_Pstatic int helpsort P((const void *, const void *));#elsestatic int helpsort P((char **, char **));#endifstatic void printusage P((struct xcmd *, FILE *));static void timeout P((struct parse *, FILE *));static void my_delay P((struct parse *, FILE *));static void host P((struct parse *, FILE *));static void keyid P((struct parse *, FILE *));static void keytype P((struct parse *, FILE *));static void passwd P((struct parse *, FILE *));static void hostnames P((struct parse *, FILE *));static void setdebug P((struct parse *, FILE *));static void quit P((struct parse *, FILE *));static void version P((struct parse *, FILE *));static void warning P((const char *, const char *, const char *));static void error P((const char *, const char *, const char *));static u_long getkeyid P((const char *));/* * Built-in commands we understand */static struct xcmd builtins[] = { { "?", help, { OPT|NTP_STR, NO, NO, NO }, { "command", "", "", "" }, "tell the use and syntax of commands" }, { "help", help, { OPT|NTP_STR, NO, NO, NO }, { "command", "", "", "" }, "tell the use and syntax of commands" }, { "timeout", timeout, { OPT|NTP_UINT, NO, NO, NO }, { "msec", "", "", "" }, "set the primary receive time out" }, { "delay", my_delay, { OPT|NTP_INT, NO, NO, NO }, { "msec", "", "", "" }, "set the delay added to encryption time stamps" }, { "host", host, { OPT|NTP_STR, OPT|NTP_STR, NO, NO }, { "-4|-6", "hostname", "", "" }, "specify the host whose NTP server we talk to" }, { "passwd", passwd, { OPT|NTP_STR, NO, NO, NO }, { "", "", "", "" }, "specify a password to use for authenticated requests"}, { "hostnames", hostnames, { OPT|NTP_STR, NO, NO, NO }, { "yes|no", "", "", "" }, "specify whether hostnames or net numbers are printed"}, { "debug", setdebug, { OPT|NTP_STR, NO, NO, NO }, { "no|more|less", "", "", "" }, "set/change debugging level" }, { "quit", quit, { NO, NO, NO, NO }, { "", "", "", "" }, "exit ntpdc" }, { "exit", quit, { NO, NO, NO, NO }, { "", "", "", "" }, "exit ntpdc" }, { "keyid", keyid, { OPT|NTP_UINT, NO, NO, NO }, { "key#", "", "", "" }, "set/show keyid to use for authenticated requests" }, { "keytype", keytype, { OPT|NTP_STR, NO, NO, NO }, { "(md5|des)", "", "", "" }, "set/show key authentication type for authenticated requests (des|md5)" }, { "version", version, { NO, NO, NO, NO }, { "", "", "", "" }, "print version number" }, { 0, 0, { NO, NO, NO, NO }, { "", "", "", "" }, "" }};/* * Default values we use. */#define DEFTIMEOUT (5) /* 5 second time out */#define DEFSTIMEOUT (2) /* 2 second time out after first */#define DEFDELAY 0x51EB852 /* 20 milliseconds, l_fp fraction */#define DEFHOST "localhost" /* default host name */#define LENHOSTNAME 256 /* host name is 256 characters long */#define MAXCMDS 100 /* maximum commands on cmd line */#define MAXHOSTS 200 /* maximum hosts on cmd line */#define MAXLINE 512 /* maximum line length */#define MAXTOKENS (1+1+MAXARGS+2) /* maximum number of usable tokens */#define SCREENWIDTH 78 /* nominal screen width in columns *//* * Some variables used and manipulated locally */static struct timeval tvout = { DEFTIMEOUT, 0 }; /* time out for reads */static struct timeval tvsout = { DEFSTIMEOUT, 0 }; /* secondary time out */static l_fp delay_time; /* delay time */static char currenthost[LENHOSTNAME]; /* current host name */int showhostnames = 1; /* show host names by default */static int ai_fam_templ; /* address family */static int ai_fam_default; /* default address family */static SOCKET sockfd; /* fd socket is opened on */static int havehost = 0; /* set to 1 when host open */int s_port = 0;#if defined (SYS_WINNT) || defined (SYS_VXWORKS)char password[9];#endif /* SYS_WINNT || SYS_VXWORKS */#ifdef SYS_WINNTDWORD NumberOfBytesWritten;HANDLE TimerThreadHandle = NULL; /* 1998/06/03 - Used in ntplib/machines.c */void timer(void) { ; }; /* 1998/06/03 - Used in ntplib/machines.c */#endif /* SYS_WINNT *//* * Holds data returned from queries. We allocate INITDATASIZE * octets to begin with, increasing this as we need to. */#define INITDATASIZE (sizeof(struct resp_pkt) * 16)#define INCDATASIZE (sizeof(struct resp_pkt) * 8)static char *pktdata;static int pktdatasize;/* * These are used to help the magic with old and new versions of ntpd. */int impl_ver = IMPL_XNTPD;static int req_pkt_size = REQ_LEN_NOMAC;/* * For commands typed on the command line (with the -c option) */static int numcmds = 0;static const char *ccmds[MAXCMDS];#define ADDCMD(cp) if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp)/* * When multiple hosts are specified. */static int numhosts = 0;static const char *chosts[MAXHOSTS];#define ADDHOST(cp) if (numhosts < MAXHOSTS) chosts[numhosts++] = (cp)/* * Error codes for internal use */#define ERR_INCOMPLETE 16#define ERR_TIMEOUT 17/* * Macro definitions we use */#define ISSPACE(c) ((c) == ' ' || (c) == '\t')#define ISEOL(c) ((c) == '\n' || (c) == '\r' || (c) == '\0')#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)/* * For converting time stamps to dates */#define JAN_1970 2208988800 /* 1970 - 1900 in seconds *//* * Jump buffer for longjumping back to the command level */static jmp_buf interrupt_buf;static volatile int jump = 0;/* * Pointer to current output unit */static FILE *current_output;/* * Command table imported from ntpdc_ops.c */extern struct xcmd opcmds[];char *progname;volatile int debug;#ifdef NO_MAIN_ALLOWEDCALL(ntpdc,"ntpdc",ntpdcmain);#elseintmain( int argc, char *argv[] ){ return ntpdcmain(argc, argv);}#endif#ifdef SYS_VXWORKSvoid clear_globals(void){ extern int ntp_optind; extern char *ntp_optarg; showhostnames = 0; /* show host names by default */ ntp_optind = 0; ntp_optarg = 0; havehost = 0; /* set to 1 when host open */ numcmds = 0; numhosts = 0;}#endif/* * main - parse arguments and handle options */intntpdcmain( int argc, char *argv[] ){ int c; int errflg = 0; extern int ntp_optind; extern char *ntp_optarg; delay_time.l_ui = 0; delay_time.l_uf = DEFDELAY;#ifdef SYS_VXWORKS clear_globals(); taskPrioritySet(taskIdSelf(), 100 );#endif#ifdef SYS_WINNT if (!Win32InitSockets()) { fprintf(stderr, "No useable winsock.dll:"); exit(1); }#endif /* SYS_WINNT */ /* Check to see if we have IPv6. Otherwise force the -4 flag */ if (isc_net_probeipv6() != ISC_R_SUCCESS) { ai_fam_default = AF_INET; } progname = argv[0]; ai_fam_templ = ai_fam_default; while ((c = ntp_getopt(argc, argv, "46c:dilnps")) != EOF) switch (c) { case '4': ai_fam_templ = AF_INET; break; case '6': ai_fam_templ = AF_INET6; break; case 'c': ADDCMD(ntp_optarg); break; case 'd': ++debug; break; case 'i': interactive = 1; break; case 'l': ADDCMD("listpeers"); break; case 'n': showhostnames = 0; break; case 'p': ADDCMD("peers"); break; case 's': ADDCMD("dmpeers"); break; default: errflg++; break; } if (errflg) { (void) fprintf(stderr, "usage: %s [-46dilnps] [-c cmd] host ...\n", progname); exit(2); } if (ntp_optind == argc) { ADDHOST(DEFHOST); } else { for (; ntp_optind < argc; ntp_optind++) ADDHOST(argv[ntp_optind]); } if (numcmds == 0 && interactive == 0 && isatty(fileno(stdin)) && isatty(fileno(stderr))) { interactive = 1; }#ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */ if (interactive) (void) signal_no_reset(SIGINT, abortcmd);#endif /* SYS_WINNT */ /* * Initialize the packet data buffer */ pktdata = (char *)malloc(INITDATASIZE); if (pktdata == NULL) { (void) fprintf(stderr, "%s: malloc() failed!\n", progname); exit(1); } pktdatasize = INITDATASIZE; if (numcmds == 0) { (void) openhost(chosts[0]); getcmds(); } else { int ihost; int icmd; for (ihost = 0; ihost < numhosts; ihost++) { if (openhost(chosts[ihost])) for (icmd = 0; icmd < numcmds; icmd++) { if (numhosts > 1) printf ("--- %s ---\n",chosts[ihost]); docmd(ccmds[icmd]); } } }#ifdef SYS_WINNT WSACleanup();#endif return(0);} /* main end *//* * openhost - open a socket to a host */static intopenhost( const char *hname ){ char temphost[LENHOSTNAME]; int a_info, i; struct addrinfo hints, *ai = NULL; register const char *cp; char name[LENHOSTNAME]; char service[5]; /* * We need to get by the [] if they were entered */ cp = hname; if (*cp == '[') { cp++; for(i = 0; *cp != ']'; cp++, i++) name[i] = *cp; name[i] = '\0'; hname = name; } /* * First try to resolve it as an ip address and if that fails, * do a fullblown (dns) lookup. That way we only use the dns * when it is needed and work around some implementations that * will return an "IPv4-mapped IPv6 address" address if you * give it an IPv4 address to lookup. */ strcpy(service, "ntp"); memset((char *)&hints, 0, sizeof(struct addrinfo)); hints.ai_family = ai_fam_templ; hints.ai_protocol = IPPROTO_UDP; hints.ai_socktype = SOCK_DGRAM; hints.ai_flags = AI_NUMERICHOST; a_info = getaddrinfo(hname, service, &hints, &ai); if (a_info == EAI_NONAME#ifdef EAI_NODATA || a_info == EAI_NODATA#endif ) { hints.ai_flags = AI_CANONNAME;#ifdef AI_ADDRCONFIG hints.ai_flags |= AI_ADDRCONFIG;#endif a_info = getaddrinfo(hname, service, &hints, &ai); } /* Some older implementations don't like AI_ADDRCONFIG. */ if (a_info == EAI_BADFLAGS) { hints.ai_flags = AI_CANONNAME; a_info = getaddrinfo(hname, service, &hints, &ai); } if (a_info != 0) { (void) fprintf(stderr, "%s\n", gai_strerror(a_info)); return 0; } if (ai->ai_canonname == NULL) { strncpy(temphost, stoa((struct sockaddr_storage *)ai->ai_addr), LENHOSTNAME); temphost[LENHOSTNAME-1] = '\0'; } else { strncpy(temphost, ai->ai_canonname, LENHOSTNAME); temphost[LENHOSTNAME-1] = '\0'; } if (debug > 2) printf("Opening host %s\n", temphost); if (havehost == 1) { if (debug > 2) printf("Closing old host %s\n", currenthost); (void) closesocket(sockfd); havehost = 0; } (void) strcpy(currenthost, temphost); /* port maps to the same in both families */ s_port = ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port; #ifdef SYS_VXWORKS ((struct sockaddr_in6 *)&hostaddr)->sin6_port = htons(SERVER_PORT_NUM); if (ai->ai_family == AF_INET) *(struct sockaddr_in *)&hostaddr= *((struct sockaddr_in *)ai->ai_addr); else *(struct sockaddr_in6 *)&hostaddr= *((struct sockaddr_in6 *)ai->ai_addr);#endif /* SYS_VXWORKS */#ifdef SYS_WINNT { int optionValue = SO_SYNCHRONOUS_NONALERT; int err; err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&optionValue, sizeof(optionValue)); if (err != NO_ERROR) { (void) fprintf(stderr, "cannot open nonoverlapped sockets\n"); exit(1); } } sockfd = socket(ai->ai_family, SOCK_DGRAM, 0); if (sockfd == INVALID_SOCKET) { error("socket", "", ""); exit(-1); }#else sockfd = socket(ai->ai_family, SOCK_DGRAM, 0); if (sockfd == -1) error("socket", "", "");#endif /* SYS_WINNT */ #ifdef NEED_RCVBUF_SLOP# ifdef SO_RCVBUF { int rbufsize = INITDATASIZE + 2048; /* 2K for slop */ if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &rbufsize, sizeof(int)) == -1) error("setsockopt", "", ""); }# endif#endif#ifdef SYS_VXWORKS if (connect(sockfd, (struct sockaddr *)&hostaddr, sizeof(hostaddr)) == -1)#else if (connect(sockfd, (struct sockaddr *)ai->ai_addr, ai->ai_addrlen) == -1)#endif /* SYS_VXWORKS */ error("connect", "", ""); if (a_info) freeaddrinfo(ai); havehost = 1; req_pkt_size = REQ_LEN_NOMAC; impl_ver = IMPL_XNTPD; return 1;}/* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c *//* * sendpkt - send a packet to the remote host */static intsendpkt( char *xdata, int xdatalen ){ if (send(sockfd, xdata, (size_t)xdatalen, 0) == -1) { warning("write to %s failed", currenthost, ""); return -1; } return 0;}/* * growpktdata - grow the packet data area */static voidgrowpktdata(void){ pktdatasize += INCDATASIZE; pktdata = (char *)realloc(pktdata, (unsigned)pktdatasize); if (pktdata == 0) { (void) fprintf(stderr, "%s: realloc() failed!\n", progname); exit(1); }}/* * getresponse - get a (series of) response packet(s) and return the data */static intgetresponse( int implcode, int reqcode, int *ritems, int *rsize, char **rdata, int esize ){ struct resp_pkt rpkt; struct timeval tvo; int items; int i; int size; int datasize; char *datap; char *tmp_data; char haveseq[MAXSEQ+1]; int firstpkt; int lastseq; int numrecv; int seq; fd_set fds; int n; int pad; /* * This is pretty tricky. We may get between 1 and many packets * back in response to the request. We peel the data out of * each packet and collect it in one long block. When the last * packet in the sequence is received we'll know how many we * should have had. Note we use one long time out, should reconsider. */ *ritems = 0; *rsize = 0; firstpkt = 1; numrecv = 0; *rdata = datap = pktdata; lastseq = 999; /* too big to be a sequence number */ memset(haveseq, 0, sizeof(haveseq)); FD_ZERO(&fds); again: if (firstpkt) tvo = tvout;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -