summaryrefslogtreecommitdiffstats
path: root/contrib/ntp/ntptrace/ntptrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/ntp/ntptrace/ntptrace.c')
-rw-r--r--contrib/ntp/ntptrace/ntptrace.c784
1 files changed, 784 insertions, 0 deletions
diff --git a/contrib/ntp/ntptrace/ntptrace.c b/contrib/ntp/ntptrace/ntptrace.c
new file mode 100644
index 0000000..d7a4140
--- /dev/null
+++ b/contrib/ntp/ntptrace/ntptrace.c
@@ -0,0 +1,784 @@
+/*
+ * ntptrace - show the chain from an NTP host leading back to
+ * its source of time
+ *
+ * Jeffrey Mogul DECWRL 13 January 1993
+ *
+ * Inspired by a script written by Glenn Trewitt
+ *
+ * Large portions stolen from ntpdate.c
+ */
+#include <stdio.h>
+#include <signal.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/signal.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#if defined(SYS_HPUX)
+#include <utmp.h>
+#endif
+
+#include "ntp_fp.h"
+#include "ntp.h"
+#include "ntp_io.h"
+#include "ntp_unixtime.h"
+#include "ntptrace.h"
+#include "ntp_string.h"
+#include "ntp_syslog.h"
+#include "ntp_select.h"
+#include "ntp_stdlib.h"
+#include "recvbuff.h"
+/*
+ * only 16 stratums, so this is more than enough.
+ */
+int maxhosts = 20;
+
+/*
+ * Debugging flag
+ */
+volatile int debug = 0;
+
+#ifndef SYS_VXWORKS
+int nonames = 0; /* if set, don't print hostnames */
+#else
+int nonames = 1; /* if set, don't print hostnames */
+#endif
+/*
+ * Program name.
+ */
+char *progname;
+
+/*
+ * Systemwide parameters and flags
+ */
+int sys_retries = 5; /* # of retry attempts per server */
+int sys_timeout = 2; /* timeout time, in seconds */
+struct server **sys_servers; /* the server list */
+int sys_numservers = 0; /* number of servers to poll */
+int sys_maxservers = NTP_MAXSTRATUM+1; /* max number of servers to deal with */
+int sys_version = NTP_OLDVERSION; /* version to poll with */
+
+
+/*
+ * File descriptor masks etc. for call to select
+ */
+int fd;
+fd_set fdmask;
+
+/*
+ * Miscellaneous flags
+ */
+int verbose = 0;
+int always_step = 0;
+
+int ntptracemain P((int, char **));
+static void DoTrace P((struct server *));
+static void DoTransmit P((struct server *));
+static int DoReceive P((struct server *));
+static int ReceiveBuf P((struct server *, struct recvbuf *));
+static struct server *addserver P((struct in_addr *));
+static struct server *addservbyname P((const char *));
+static void setup_io P((void));
+static void sendpkt P((struct sockaddr_in *, struct pkt *, int));
+static int getipaddr P((const char *, u_int32 *));
+static int decodeipaddr P((const char *, u_int32 *));
+static void printserver P((struct server *, FILE *));
+static void printrefid P((FILE *, struct server *));
+
+#ifdef SYS_WINNT
+int on = 1;
+WORD wVersionRequested;
+WSADATA wsaData;
+
+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 */
+
+void
+input_handler(l_fp * x)
+{ ;
+}
+
+#ifdef NO_MAIN_ALLOWED
+CALL(ntptrace,"ntptrace",ntptracemain);
+#endif
+
+/*
+ * Main program. Initialize us and loop waiting for I/O and/or
+ * timer expiries.
+ */
+#ifndef NO_MAIN_ALLOWED
+int
+main(
+ int argc,
+ char *argv[]
+ )
+{
+ return ntptracemain(argc, argv);
+}
+#endif
+
+int
+ntptracemain(
+ int argc,
+ char *argv[]
+ )
+{
+ struct server *firstserver;
+ int errflg;
+ int c;
+
+ errflg = 0;
+ progname = argv[0];
+
+ /*
+ * Decode argument list
+ */
+ while ((c = ntp_getopt(argc, argv, "dm:no:r:t:v")) != EOF)
+ switch (c) {
+ case 'd':
+ ++debug;
+ break;
+ case 'm':
+ maxhosts = atoi(ntp_optarg);
+ break;
+ case 'n':
+ nonames = 1;
+ break;
+ case 'o':
+ sys_version = atoi(ntp_optarg);
+ break;
+ case 'r':
+ sys_retries = atoi(ntp_optarg);
+ if (sys_retries < 1) {
+ (void)fprintf(stderr,
+ "%s: retries (%d) too small\n",
+ progname, sys_retries);
+ errflg++;
+ }
+ break;
+ case 't':
+ sys_timeout = atoi(ntp_optarg);
+ if (sys_timeout < 1) {
+ (void)fprintf(stderr,
+ "%s: timeout (%d) too short\n",
+ progname, sys_timeout);
+ errflg++;
+ }
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case '?':
+ ++errflg;
+ break;
+ default:
+ break;
+ }
+
+ if (errflg || (argc - ntp_optind) > 1) {
+ (void) fprintf(stderr,
+ "usage: %s [-dnv] [-m maxhosts] [-o version#] [-r retries] [-t timeout] [server]\n",
+ progname);
+ exit(2);
+ }
+
+#ifdef SYS_WINNT
+ wVersionRequested = MAKEWORD(1,1);
+ if (WSAStartup(wVersionRequested, &wsaData)) {
+ msyslog(LOG_ERR, "No useable winsock.dll: %m");
+ exit(1);
+ }
+#endif /* SYS_WINNT */
+
+ sys_servers = (struct server **)
+ emalloc(sys_maxservers * sizeof(struct server *));
+
+ if (debug) {
+#ifdef HAVE_SETVBUF
+ static char buf[BUFSIZ];
+ setvbuf(stdout, buf, _IOLBF, BUFSIZ);
+#else
+ setlinebuf(stdout);
+#endif
+ }
+
+ if (debug || verbose)
+ msyslog(LOG_NOTICE, "%s", Version);
+
+ if ((argc - ntp_optind) == 1)
+ firstserver = addservbyname(argv[ntp_optind]);
+ else
+ firstserver = addservbyname("localhost");
+
+ if (firstserver == NULL) {
+ /* a message has already been printed */
+ exit(2);
+ }
+
+ /*
+ * Initialize the time of day routines and the I/O subsystem
+ */
+ setup_io();
+
+ DoTrace(firstserver);
+
+#ifdef SYS_WINNT
+ WSACleanup();
+#endif
+ return(0);
+} /* main end */
+
+
+static void
+DoTrace(
+ register struct server *server
+ )
+{
+ int retries = sys_retries;
+
+ if (!verbose) {
+ if (nonames)
+ printf("%s: ", ntoa(&server->srcadr));
+ else
+ printf("%s: ", ntohost(&server->srcadr));
+ fflush(stdout);
+ }
+ while (retries-- > 0) {
+ DoTransmit(server);
+ if (DoReceive(server))
+ return;
+ }
+ if (verbose) {
+ if (nonames)
+ printf("%s:\t*Timeout*\n", ntoa(&server->srcadr));
+ else
+ printf("%s:\t*Timeout*\n", ntohost(&server->srcadr));
+ }
+ else
+ printf("\t*Timeout*\n");
+}
+
+/*
+ * Dotransmit - transmit a packet to the given server
+ */
+static void
+DoTransmit(
+ register struct server *server
+ )
+{
+ struct pkt xpkt;
+
+ if (debug)
+ printf("DoTransmit(%s)\n", ntoa(&server->srcadr));
+
+ /*
+ * Fill in the packet and let 'er rip.
+ */
+ xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOTINSYNC,
+ sys_version, MODE_CLIENT);
+ xpkt.stratum = STRATUM_TO_PKT(STRATUM_UNSPEC);
+ xpkt.ppoll = NTP_MINPOLL;
+ xpkt.precision = NTPTRACE_PRECISION;
+ xpkt.rootdelay = htonl(NTPTRACE_DISTANCE);
+ xpkt.rootdispersion = htonl(NTPTRACE_DISP);
+ xpkt.refid = htonl(NTPTRACE_REFID);
+ L_CLR(&xpkt.reftime);
+ L_CLR(&xpkt.org);
+ L_CLR(&xpkt.rec);
+
+ /*
+ * just timestamp packet and send it away.
+ */
+ get_systime(&(server->xmt));
+ HTONL_FP(&server->xmt, &xpkt.xmt);
+ sendpkt(&(server->srcadr), &xpkt, LEN_PKT_NOMAC);
+
+ if (debug)
+ printf("DoTransmit to %s\n", ntoa(&(server->srcadr)));
+}
+
+/*
+ * DoReceive - attempt to receive a packet from a specific server
+ */
+static int
+DoReceive(
+ register struct server *server
+ )
+{
+ register int n;
+ fd_set fds;
+ struct timeval timeout;
+ l_fp ts;
+ register struct recvbuf *rb;
+ int fromlen;
+ int status;
+
+ /*
+ * Loop until we see the packet we want or until we time out
+ */
+ for (;;) {
+ fds = fdmask;
+ timeout.tv_sec = sys_timeout;
+ timeout.tv_usec = 0;
+ n = select(fd+1, &fds, (fd_set *)0, (fd_set *)0, &timeout);
+
+ if (n == 0) { /* timed out */
+ if (debug)
+ printf("timeout\n");
+ return(0);
+ }
+ else if (n == -1) {
+ msyslog(LOG_ERR, "select() error: %m");
+ return(0);
+ }
+ get_systime(&ts);
+
+ if (free_recvbuffs() == 0) {
+ msyslog(LOG_ERR, "no buffers");
+ exit(1);
+ }
+
+ rb = get_free_recv_buffer();
+
+ fromlen = sizeof(struct sockaddr_in);
+ rb->recv_length = recvfrom(fd, (char *)&rb->recv_pkt,
+ sizeof(rb->recv_pkt), 0,
+ (struct sockaddr *)&rb->recv_srcadr, &fromlen);
+ if (rb->recv_length == -1) {
+ freerecvbuf(rb);
+ continue;
+ }
+
+ /*
+ * Got one. Mark how and when it got here,
+ * put it on the full list.
+ */
+ rb->recv_time = ts;
+ add_full_recv_buffer(rb);
+
+ status = ReceiveBuf(server, rb);
+
+ freerecvbuf(rb);
+
+ return(status);
+ }
+}
+
+/*
+ * receive - receive and process an incoming frame
+ * Return 1 on success, 0 on failure
+ */
+static int
+ReceiveBuf(
+ struct server *server,
+ struct recvbuf *rbufp
+ )
+{
+ register struct pkt *rpkt;
+ register s_fp di;
+ l_fp t10, t23;
+ l_fp org;
+ l_fp rec;
+ l_fp ci;
+ struct server *nextserver;
+ struct in_addr nextia;
+
+
+ if (debug) {
+ printf("ReceiveBuf(%s, ", ntoa(&server->srcadr));
+ printf("%s)\n", ntoa(&rbufp->recv_srcadr));
+ }
+
+ /*
+ * Check to see if the packet basically looks like something
+ * intended for us.
+ */
+ if (rbufp->recv_length < LEN_PKT_NOMAC) {
+ if (debug)
+ printf("receive: packet length %d\n",
+ rbufp->recv_length);
+ return(0); /* funny length packet */
+ }
+ if (rbufp->recv_srcadr.sin_addr.s_addr != server->srcadr.sin_addr.s_addr) {
+ if (debug)
+ printf("receive: wrong server\n");
+ return(0); /* funny length packet */
+ }
+
+ rpkt = &(rbufp->recv_pkt);
+
+ if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION) {
+ if (debug)
+ printf("receive: version %d\n", PKT_VERSION(rpkt->li_vn_mode));
+ return(0);
+ }
+ if (PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) {
+ if (debug)
+ printf("receive: version %d\n", PKT_VERSION(rpkt->li_vn_mode));
+ return(0);
+ }
+
+ if ((PKT_MODE(rpkt->li_vn_mode) != MODE_SERVER
+ && PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE)
+ || rpkt->stratum > NTP_MAXSTRATUM) {
+ if (debug)
+ printf("receive: mode %d stratum %d\n",
+ PKT_MODE(rpkt->li_vn_mode), rpkt->stratum);
+ return(0);
+ }
+
+ /*
+ * Decode the org timestamp and make sure we're getting a response
+ * to our last request.
+ */
+ NTOHL_FP(&rpkt->org, &org);
+ if (!L_ISEQU(&org, &server->xmt)) {
+ if (debug)
+ printf("receive: pkt.org and peer.xmt differ\n");
+ return(0);
+ }
+
+ /*
+ * Looks good. Record info from the packet.
+ */
+
+ server->leap = PKT_LEAP(rpkt->li_vn_mode);
+ server->stratum = PKT_TO_STRATUM(rpkt->stratum);
+ server->precision = rpkt->precision;
+ server->rootdelay = ntohl(rpkt->rootdelay);
+ server->rootdispersion = ntohl(rpkt->rootdispersion);
+ server->refid = rpkt->refid;
+ NTOHL_FP(&rpkt->reftime, &server->reftime);
+ NTOHL_FP(&rpkt->rec, &rec);
+ NTOHL_FP(&rpkt->xmt, &server->org);
+
+ /*
+ * Make sure the server is at least somewhat sane. If not, try
+ * again.
+ */
+ if (L_ISZERO(&rec) || !L_ISHIS(&server->org, &rec)) {
+ return(0);
+ }
+
+ /*
+ * Calculate the round trip delay (di) and the clock offset (ci).
+ * We use the equations (reordered from those in the spec):
+ *
+ * d = (t2 - t3) - (t1 - t0)
+ * c = ((t2 - t3) + (t1 - t0)) / 2
+ */
+ t10 = server->org; /* pkt.xmt == t1 */
+ L_SUB(&t10, &rbufp->recv_time); /* recv_time == t0*/
+
+ t23 = rec; /* pkt.rec == t2 */
+ L_SUB(&t23, &org); /* pkt->org == t3 */
+
+ /* now have (t2 - t3) and (t0 - t1). Calculate (ci) and (di) */
+ ci = t10;
+ L_ADD(&ci, &t23);
+ L_RSHIFT(&ci);
+
+ /*
+ * Calculate di in t23 in full precision, then truncate
+ * to an s_fp.
+ */
+ L_SUB(&t23, &t10);
+ di = LFPTOFP(&t23);
+
+ server->offset = ci;
+ server->delay = di;
+
+ printserver(server, stdout);
+
+ /*
+ * End of recursion if we reach stratum 1 or a local refclock
+ */
+ if ((server->stratum <= 1) || (--maxhosts <= 0) || ((server->refid & 0xff) == 127))
+ return(1);
+
+ nextia.s_addr = server->refid;
+ nextserver = addserver(&nextia);
+ if (nextserver)
+ DoTrace(nextserver);
+ return(1);
+}
+
+/* XXX ELIMINATE addserver (almost) identical to ntpdate.c, ntptrace.c */
+/*
+ * addserver - Allocate a new structure for server.
+ * Returns a pointer to that structure.
+ */
+static struct server *
+addserver(
+ struct in_addr *iap
+ )
+{
+ register struct server *server;
+ static int toomany = 0;
+
+ if (sys_numservers >= sys_maxservers) {
+ if (!toomany) {
+ toomany = 1;
+ msyslog(LOG_ERR,
+ "too many servers (> %d) specified, remainder not used",
+ sys_maxservers);
+ }
+ return(NULL);
+ }
+
+ server = (struct server *)emalloc(sizeof(struct server));
+ memset((char *)server, 0, sizeof(struct server));
+
+ server->srcadr.sin_family = AF_INET;
+ server->srcadr.sin_addr = *iap;
+ server->srcadr.sin_port = htons(NTP_PORT);
+
+ sys_servers[sys_numservers++] = server;
+
+ return(server);
+}
+
+
+/*
+ * addservbyname - determine a server's address and allocate a new structure
+ * for it. Returns a pointer to that structure.
+ */
+static struct server *
+addservbyname(
+ const char *serv
+ )
+{
+ u_int32 ipaddr;
+ struct in_addr ia;
+
+ if (!getipaddr(serv, &ipaddr)) {
+ msyslog(LOG_ERR, "can't find host %s\n", serv);
+ return(NULL);
+ }
+
+ ia.s_addr = ipaddr;
+ return(addserver(&ia));
+}
+
+
+static void
+setup_io(void)
+{
+ /*
+ * Init buffer free list and stat counters
+ */
+ init_recvbuff(sys_maxservers + 2);
+
+ /* create a datagram (UDP) socket */
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0))
+#ifndef SYS_WINNT
+ < 0
+#else
+ == INVALID_SOCKET
+#endif
+ ) {
+ msyslog(LOG_ERR, "socket() failed: %m");
+ exit(1);
+ /*NOTREACHED*/
+ }
+
+ FD_ZERO(&fdmask);
+ FD_SET(fd, &fdmask);
+}
+
+
+
+/* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */
+/*
+ * sendpkt - send a packet to the specified destination
+ */
+static void
+sendpkt(
+ struct sockaddr_in *dest,
+ struct pkt *pkt,
+ int len
+ )
+{
+ int cc;
+
+ cc = sendto(fd, (char *)pkt, len, 0, (struct sockaddr *)dest,
+ sizeof(struct sockaddr_in));
+ if (cc == -1) {
+#ifndef SYS_WINNT
+ if (errno != EWOULDBLOCK && errno != ENOBUFS)
+#else /* SYS_WINNT */
+ int iSockErr = WSAGetLastError();
+ if (iSockErr != WSAEWOULDBLOCK && iSockErr != WSAENOBUFS)
+#endif /* SYS_WINNT */
+ msyslog(LOG_ERR, "sendto(%s): %m", ntoa(dest));
+ }
+}
+
+/*
+ * getipaddr - given a host name, return its host address
+ */
+static int
+getipaddr(
+ const char *host,
+ u_int32 *num
+ )
+{
+ struct hostent *hp;
+
+ if (decodeipaddr(host, num)) {
+ return 1;
+ } else if ((hp = gethostbyname(host)) != 0) {
+ memmove((char *)num, hp->h_addr, sizeof(long));
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * decodeipaddr - return a host address (this is crude, but careful)
+ */
+static int
+decodeipaddr(
+ const char *num,
+ u_int32 *ipaddr
+ )
+{
+ register const char *cp;
+ register char *bp;
+ register int i;
+ register int temp;
+ char buf[80]; /* will core dump on really stupid stuff */
+
+ cp = num;
+ *ipaddr = 0;
+ for (i = 0; i < 4; i++) {
+ bp = buf;
+ while (isdigit((int)*cp))
+ *bp++ = *cp++;
+ if (bp == buf)
+ break;
+
+ if (i < 3) {
+ if (*cp++ != '.')
+ break;
+ } else if (*cp != '\0')
+ break;
+
+ *bp = '\0';
+ temp = atoi(buf);
+ if (temp > 255)
+ break;
+ *ipaddr <<= 8;
+ *ipaddr += temp;
+ }
+
+ if (i < 4)
+ return 0;
+ *ipaddr = htonl(*ipaddr);
+ return 1;
+}
+
+
+/* XXX ELIMINATE printserver similar in ntptrace.c, ntpdate.c */
+/*
+ * printserver - print detail information for a server
+ */
+static void
+printserver(
+ register struct server *pp,
+ FILE *fp
+ )
+{
+ u_fp synchdist;
+
+ synchdist = pp->rootdispersion + (pp->rootdelay/2);
+
+ if (!verbose) {
+ (void) fprintf(fp, "stratum %d, offset %s, synch distance %s",
+ pp->stratum, lfptoa(&pp->offset, 6), ufptoa(synchdist, 5));
+ if (pp->stratum == 1) {
+ (void) fprintf(fp, ", refid ");
+ printrefid(fp, pp);
+ }
+ (void) fprintf(fp, "\n");
+ return;
+ }
+
+ (void) fprintf(fp, "server %s, port %d\n", ntoa(&pp->srcadr),
+ ntohs(pp->srcadr.sin_port));
+
+ (void) fprintf(fp, "stratum %d, precision %d, leap %c%c\n",
+ pp->stratum, pp->precision, pp->leap & 0x2 ? '1' : '0',
+ pp->leap & 0x1 ? '1' : '0');
+
+ (void) fprintf(fp, "refid ");
+ printrefid(fp, pp);
+
+ (void) fprintf(fp, " delay %s, dispersion %s ", fptoa(pp->delay, 5),
+ ufptoa(pp->dispersion, 5));
+ (void) fprintf(fp, "offset %s\n", lfptoa(&pp->offset, 6));
+ (void) fprintf(fp, "rootdelay %s, rootdispersion %s",
+ ufptoa(pp->rootdelay, 5), ufptoa(pp->rootdispersion, 5));
+ (void) fprintf(fp, ", synch dist %s\n", ufptoa(synchdist, 5));
+
+ (void) fprintf(fp, "reference time: %s\n",
+ prettydate(&pp->reftime));
+ (void) fprintf(fp, "originate timestamp: %s\n",
+ prettydate(&pp->org));
+ (void) fprintf(fp, "transmit timestamp: %s\n",
+ prettydate(&pp->xmt));
+
+ (void) fprintf(fp, "\n");
+
+}
+
+static void
+printrefid(
+ FILE *fp,
+ struct server *pp
+ )
+{
+ char junk[5];
+ char *str;
+
+ if (pp->stratum == 1) {
+ junk[4] = 0;
+ memmove(junk, (char *)&pp->refid, 4);
+ str = junk;
+ (void) fprintf(fp, "'%s'", str);
+ } else {
+ if (nonames) {
+ str = numtoa(pp->refid);
+ (void) fprintf(fp, "[%s]", str);
+ }
+ else {
+ str = numtohost(pp->refid);
+ (void) fprintf(fp, "%s", str);
+ }
+ }
+}
+
+#if !defined(HAVE_VSPRINTF)
+int
+vsprintf(
+ char *str,
+ const char *fmt,
+ va_list ap
+ )
+{
+ FILE f;
+ int len;
+
+ f._flag = _IOWRT+_IOSTRG;
+ f._ptr = str;
+ f._cnt = 32767;
+ len = _doprnt(fmt, ap, &f);
+ *f._ptr = 0;
+ return (len);
+}
+#endif
OpenPOWER on IntegriCloud