2 * ntptrace - show the chain from an NTP host leading back to
5 * Jeffrey Mogul DECWRL 13 January 1993
7 * Inspired by a script written by Glenn Trewitt
9 * Large portions stolen from ntpdate.c
15 #include <sys/types.h>
16 #include <sys/signal.h>
17 #include <sys/ioctl.h>
19 #include <sys/resource.h>
28 #include "ntp_unixtime.h"
30 #include "ntp_string.h"
31 #include "ntp_syslog.h"
32 #include "ntp_select.h"
33 #include "ntp_stdlib.h"
36 * only 16 stratums, so this is more than enough.
43 volatile int debug = 0;
46 int nonames = 0; /* if set, don't print hostnames */
48 int nonames = 1; /* if set, don't print hostnames */
56 * Systemwide parameters and flags
58 int sys_retries = 5; /* # of retry attempts per server */
59 int sys_timeout = 2; /* timeout time, in seconds */
60 struct server **sys_servers; /* the server list */
61 int sys_numservers = 0; /* number of servers to poll */
62 int sys_maxservers = NTP_MAXSTRATUM+1; /* max number of servers to deal with */
63 int sys_version = NTP_OLDVERSION; /* version to poll with */
67 * File descriptor masks etc. for call to select
78 int ntptracemain P((int, char **));
79 static void DoTrace P((struct server *));
80 static void DoTransmit P((struct server *));
81 static int DoReceive P((struct server *));
82 static int ReceiveBuf P((struct server *, struct recvbuf *));
83 static struct server *addserver P((struct in_addr *));
84 static struct server *addservbyname P((const char *));
85 static void setup_io P((void));
86 static void sendpkt P((struct sockaddr_in *, struct pkt *, int));
87 static int getipaddr P((const char *, u_int32 *));
88 static int decodeipaddr P((const char *, u_int32 *));
89 static void printserver P((struct server *, FILE *));
90 static void printrefid P((FILE *, struct server *));
91 void input_handler P((l_fp * x));
95 WORD wVersionRequested;
98 HANDLE TimerThreadHandle = NULL; /* 1998/06/03 - Used in ntplib/machines.c */
99 void timer(void) { ; }; /* 1998/06/03 - Used in ntplib/machines.c */
100 #endif /* SYS_WINNT */
103 input_handler(l_fp * x)
107 #ifdef NO_MAIN_ALLOWED
108 CALL(ntptrace,"ntptrace",ntptracemain);
112 * Main program. Initialize us and loop waiting for I/O and/or
115 #ifndef NO_MAIN_ALLOWED
122 return ntptracemain(argc, argv);
132 struct server *firstserver;
140 * Decode argument list
142 while ((c = ntp_getopt(argc, argv, "dm:no:r:t:v")) != EOF)
148 maxhosts = atoi(ntp_optarg);
154 sys_version = atoi(ntp_optarg);
157 sys_retries = atoi(ntp_optarg);
158 if (sys_retries < 1) {
159 (void)fprintf(stderr,
160 "%s: retries (%d) too small\n",
161 progname, sys_retries);
166 sys_timeout = atoi(ntp_optarg);
167 if (sys_timeout < 1) {
168 (void)fprintf(stderr,
169 "%s: timeout (%d) too short\n",
170 progname, sys_timeout);
184 if (errflg || (argc - ntp_optind) > 1) {
185 (void) fprintf(stderr,
186 "usage: %s [-dnv] [-m maxhosts] [-o version#] [-r retries] [-t timeout] [server]\n",
192 wVersionRequested = MAKEWORD(1,1);
193 if (WSAStartup(wVersionRequested, &wsaData)) {
194 msyslog(LOG_ERR, "No useable winsock.dll: %m");
197 #endif /* SYS_WINNT */
199 sys_servers = (struct server **)
200 emalloc(sys_maxservers * sizeof(struct server *));
204 static char buf[BUFSIZ];
205 setvbuf(stdout, buf, _IOLBF, BUFSIZ);
211 if (debug || verbose)
212 msyslog(LOG_NOTICE, "%s", Version);
214 if ((argc - ntp_optind) == 1)
215 firstserver = addservbyname(argv[ntp_optind]);
217 firstserver = addservbyname("localhost");
219 if (firstserver == NULL) {
220 /* a message has already been printed */
225 * Initialize the time of day routines and the I/O subsystem
229 DoTrace(firstserver);
240 register struct server *server
243 int retries = sys_retries;
247 printf("%s: ", ntoa(&server->srcadr));
249 printf("%s: ", ntohost(&server->srcadr));
252 while (retries-- > 0) {
254 if (DoReceive(server))
259 printf("%s:\t*Timeout*\n", ntoa(&server->srcadr));
261 printf("%s:\t*Timeout*\n", ntohost(&server->srcadr));
264 printf("\t*Timeout*\n");
268 * Dotransmit - transmit a packet to the given server
272 register struct server *server
278 printf("DoTransmit(%s)\n", ntoa(&server->srcadr));
281 * Fill in the packet and let 'er rip.
283 xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOTINSYNC,
284 sys_version, MODE_CLIENT);
285 xpkt.stratum = STRATUM_TO_PKT(STRATUM_UNSPEC);
286 xpkt.ppoll = NTP_MINPOLL;
287 xpkt.precision = NTPTRACE_PRECISION;
288 xpkt.rootdelay = htonl(NTPTRACE_DISTANCE);
289 xpkt.rootdispersion = htonl(NTPTRACE_DISP);
290 xpkt.refid = htonl(NTPTRACE_REFID);
291 L_CLR(&xpkt.reftime);
296 * just timestamp packet and send it away.
298 get_systime(&(server->xmt));
299 HTONL_FP(&server->xmt, &xpkt.xmt);
300 sendpkt(&(server->srcadr), &xpkt, LEN_PKT_NOMAC);
303 printf("DoTransmit to %s\n", ntoa(&(server->srcadr)));
307 * DoReceive - attempt to receive a packet from a specific server
311 register struct server *server
316 struct timeval timeout;
318 register struct recvbuf *rb;
323 * Loop until we see the packet we want or until we time out
327 timeout.tv_sec = sys_timeout;
329 n = select(fd+1, &fds, (fd_set *)0, (fd_set *)0, &timeout);
331 if (n == 0) { /* timed out */
337 msyslog(LOG_ERR, "select() error: %m");
342 if (free_recvbuffs() == 0) {
343 msyslog(LOG_ERR, "no buffers");
347 rb = get_free_recv_buffer();
349 fromlen = sizeof(struct sockaddr_in);
350 rb->recv_length = recvfrom(fd, (char *)&rb->recv_pkt,
351 sizeof(rb->recv_pkt), 0,
352 (struct sockaddr *)&rb->recv_srcadr, &fromlen);
353 if (rb->recv_length == -1) {
359 * Got one. Mark how and when it got here,
360 * put it on the full list.
363 add_full_recv_buffer(rb);
365 status = ReceiveBuf(server, rb);
374 * receive - receive and process an incoming frame
375 * Return 1 on success, 0 on failure
379 struct server *server,
380 struct recvbuf *rbufp
383 register struct pkt *rpkt;
389 struct server *nextserver;
390 struct in_addr nextia;
394 printf("ReceiveBuf(%s, ", ntoa(&server->srcadr));
395 printf("%s)\n", ntoa(&rbufp->recv_srcadr));
399 * Check to see if the packet basically looks like something
402 if (rbufp->recv_length < LEN_PKT_NOMAC) {
404 printf("receive: packet length %d\n",
406 return(0); /* funny length packet */
408 if (rbufp->recv_srcadr.sin_addr.s_addr != server->srcadr.sin_addr.s_addr) {
410 printf("receive: wrong server\n");
411 return(0); /* funny length packet */
414 rpkt = &(rbufp->recv_pkt);
416 if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION) {
418 printf("receive: version %d\n", PKT_VERSION(rpkt->li_vn_mode));
421 if (PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) {
423 printf("receive: version %d\n", PKT_VERSION(rpkt->li_vn_mode));
427 if ((PKT_MODE(rpkt->li_vn_mode) != MODE_SERVER
428 && PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE)
429 || rpkt->stratum > NTP_MAXSTRATUM) {
431 printf("receive: mode %d stratum %d\n",
432 PKT_MODE(rpkt->li_vn_mode), rpkt->stratum);
437 * Decode the org timestamp and make sure we're getting a response
438 * to our last request.
440 NTOHL_FP(&rpkt->org, &org);
441 if (!L_ISEQU(&org, &server->xmt)) {
443 printf("receive: pkt.org and peer.xmt differ\n");
448 * Looks good. Record info from the packet.
451 server->leap = PKT_LEAP(rpkt->li_vn_mode);
452 server->stratum = PKT_TO_STRATUM(rpkt->stratum);
453 server->precision = rpkt->precision;
454 server->rootdelay = ntohl(rpkt->rootdelay);
455 server->rootdispersion = ntohl(rpkt->rootdispersion);
456 server->refid = rpkt->refid;
457 NTOHL_FP(&rpkt->reftime, &server->reftime);
458 NTOHL_FP(&rpkt->rec, &rec);
459 NTOHL_FP(&rpkt->xmt, &server->org);
462 * Make sure the server is at least somewhat sane. If not, try
465 if (L_ISZERO(&rec) || !L_ISHIS(&server->org, &rec)) {
470 * Calculate the round trip delay (di) and the clock offset (ci).
471 * We use the equations (reordered from those in the spec):
473 * d = (t2 - t3) - (t1 - t0)
474 * c = ((t2 - t3) + (t1 - t0)) / 2
476 t10 = server->org; /* pkt.xmt == t1 */
477 L_SUB(&t10, &rbufp->recv_time); /* recv_time == t0*/
479 t23 = rec; /* pkt.rec == t2 */
480 L_SUB(&t23, &org); /* pkt->org == t3 */
482 /* now have (t2 - t3) and (t0 - t1). Calculate (ci) and (di) */
488 * Calculate di in t23 in full precision, then truncate
497 printserver(server, stdout);
500 * End of recursion if we reach stratum 1 or a local refclock
502 if ((server->stratum <= 1) || (--maxhosts <= 0) || ((server->refid & 0xff) == 127))
505 nextia.s_addr = server->refid;
506 nextserver = addserver(&nextia);
512 /* XXX ELIMINATE addserver (almost) identical to ntpdate.c, ntptrace.c */
514 * addserver - Allocate a new structure for server.
515 * Returns a pointer to that structure.
517 static struct server *
522 register struct server *server;
523 static int toomany = 0;
525 if (sys_numservers >= sys_maxservers) {
529 "too many servers (> %d) specified, remainder not used",
535 server = (struct server *)emalloc(sizeof(struct server));
536 memset((char *)server, 0, sizeof(struct server));
538 server->srcadr.sin_family = AF_INET;
539 server->srcadr.sin_addr = *iap;
540 server->srcadr.sin_port = htons(NTP_PORT);
542 sys_servers[sys_numservers++] = server;
549 * addservbyname - determine a server's address and allocate a new structure
550 * for it. Returns a pointer to that structure.
552 static struct server *
560 if (!getipaddr(serv, &ipaddr)) {
561 msyslog(LOG_ERR, "can't find host %s\n", serv);
566 return(addserver(&ia));
574 * Init buffer free list and stat counters
576 init_recvbuff(sys_maxservers + 2);
578 /* create a datagram (UDP) socket */
579 if ((fd = socket(AF_INET, SOCK_DGRAM, 0))
586 msyslog(LOG_ERR, "socket() failed: %m");
597 /* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */
599 * sendpkt - send a packet to the specified destination
603 struct sockaddr_in *dest,
610 cc = sendto(fd, (char *)pkt, len, 0, (struct sockaddr *)dest,
611 sizeof(struct sockaddr_in));
614 if (errno != EWOULDBLOCK && errno != ENOBUFS)
615 #else /* SYS_WINNT */
616 int iSockErr = WSAGetLastError();
617 if (iSockErr != WSAEWOULDBLOCK && iSockErr != WSAENOBUFS)
618 #endif /* SYS_WINNT */
619 msyslog(LOG_ERR, "sendto(%s): %m", ntoa(dest));
624 * getipaddr - given a host name, return its host address
634 if (decodeipaddr(host, num)) {
636 } else if ((hp = gethostbyname(host)) != 0) {
637 memmove((char *)num, hp->h_addr, sizeof(long));
644 * decodeipaddr - return a host address (this is crude, but careful)
652 register const char *cp;
656 char buf[80]; /* will core dump on really stupid stuff */
660 for (i = 0; i < 4; i++) {
662 while (isdigit((int)*cp))
670 } else if (*cp != '\0')
683 *ipaddr = htonl(*ipaddr);
688 /* XXX ELIMINATE printserver similar in ntptrace.c, ntpdate.c */
690 * printserver - print detail information for a server
694 register struct server *pp,
700 synchdist = pp->rootdispersion + (pp->rootdelay/2);
703 (void) fprintf(fp, "stratum %d, offset %s, synch distance %s",
704 pp->stratum, lfptoa(&pp->offset, 6), ufptoa(synchdist, 5));
705 if (pp->stratum == 1) {
706 (void) fprintf(fp, ", refid ");
709 (void) fprintf(fp, "\n");
713 (void) fprintf(fp, "server %s, port %d\n", ntoa(&pp->srcadr),
714 ntohs(pp->srcadr.sin_port));
716 (void) fprintf(fp, "stratum %d, precision %d, leap %c%c\n",
717 pp->stratum, pp->precision, pp->leap & 0x2 ? '1' : '0',
718 pp->leap & 0x1 ? '1' : '0');
720 (void) fprintf(fp, "refid ");
723 (void) fprintf(fp, " delay %s, dispersion %s ", fptoa(pp->delay, 5),
724 ufptoa(pp->dispersion, 5));
725 (void) fprintf(fp, "offset %s\n", lfptoa(&pp->offset, 6));
726 (void) fprintf(fp, "rootdelay %s, rootdispersion %s",
727 ufptoa(pp->rootdelay, 5), ufptoa(pp->rootdispersion, 5));
728 (void) fprintf(fp, ", synch dist %s\n", ufptoa(synchdist, 5));
730 (void) fprintf(fp, "reference time: %s\n",
731 prettydate(&pp->reftime));
732 (void) fprintf(fp, "originate timestamp: %s\n",
733 prettydate(&pp->org));
734 (void) fprintf(fp, "transmit timestamp: %s\n",
735 prettydate(&pp->xmt));
737 (void) fprintf(fp, "\n");
750 if (pp->stratum == 1) {
752 memmove(junk, (char *)&pp->refid, 4);
754 (void) fprintf(fp, "'%s'", str);
757 str = numtoa(pp->refid);
758 (void) fprintf(fp, "[%s]", str);
761 str = numtohost(pp->refid);
762 (void) fprintf(fp, "%s", str);
767 #if !defined(HAVE_VSPRINTF)
778 f._flag = _IOWRT+_IOSTRG;
781 len = _doprnt(fmt, ap, &f);