]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ntp/ntptrace/ntptrace.c
Virgin import of ntpd 4.0.99b
[FreeBSD/FreeBSD.git] / contrib / ntp / ntptrace / ntptrace.c
1 /*
2  * ntptrace - show the chain from an NTP host leading back to
3  *      its source of time
4  *
5  *      Jeffrey Mogul   DECWRL  13 January 1993
6  *
7  *      Inspired by a script written by Glenn Trewitt
8  *
9  *      Large portions stolen from ntpdate.c
10  */
11 #include <stdio.h>
12 #include <signal.h>
13 #include <ctype.h>
14 #include <netdb.h>
15 #include <sys/types.h>
16 #include <sys/signal.h>
17 #include <sys/ioctl.h>
18 #include <sys/time.h>
19 #include <sys/resource.h>
20
21 #if defined(SYS_HPUX)
22 #include <utmp.h>
23 #endif
24
25 #include "ntp_fp.h"
26 #include "ntp.h"
27 #include "ntp_io.h"
28 #include "ntp_unixtime.h"
29 #include "ntptrace.h"
30 #include "ntp_string.h"
31 #include "ntp_syslog.h"
32 #include "ntp_select.h"
33 #include "ntp_stdlib.h"
34 #include "recvbuff.h"
35 /*
36  * only 16 stratums, so this is more than enough.
37  */
38 int maxhosts = 20;  
39
40 /*
41  * Debugging flag
42  */
43 volatile int debug = 0;
44
45 #ifndef SYS_VXWORKS
46 int nonames = 0;                        /* if set, don't print hostnames */
47 #else
48 int nonames = 1;                        /* if set, don't print hostnames */
49 #endif
50 /*
51  * Program name.
52  */
53 char *progname;
54
55 /*
56  * Systemwide parameters and flags
57  */
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 */
64
65
66 /*
67  * File descriptor masks etc. for call to select
68  */
69 int fd;
70 fd_set fdmask;
71
72 /*
73  * Miscellaneous flags
74  */
75 int verbose = 0;
76 int always_step = 0;
77
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));
92
93 #ifdef SYS_WINNT
94 int on = 1;
95 WORD wVersionRequested;
96 WSADATA wsaData;
97
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 */
101
102 void
103 input_handler(l_fp * x)
104 { ;
105 }
106
107 #ifdef NO_MAIN_ALLOWED
108 CALL(ntptrace,"ntptrace",ntptracemain);
109 #endif
110
111 /*
112  * Main program.  Initialize us and loop waiting for I/O and/or
113  * timer expiries.
114  */
115 #ifndef NO_MAIN_ALLOWED
116 int
117 main(
118         int argc,
119         char *argv[]
120         )
121 {
122         return ntptracemain(argc, argv);
123 }
124 #endif
125
126 int
127 ntptracemain(
128         int argc,
129         char *argv[]
130         )
131 {
132         struct server *firstserver;
133         int errflg;
134         int c;
135
136         errflg = 0;
137         progname = argv[0];
138
139         /*
140          * Decode argument list
141          */
142         while ((c = ntp_getopt(argc, argv, "dm:no:r:t:v")) != EOF)
143             switch (c) {
144                 case 'd':
145                     ++debug;
146                     break;
147                 case 'm':
148                     maxhosts = atoi(ntp_optarg);
149                     break;
150                 case 'n':
151                     nonames = 1;
152                     break;
153                 case 'o':
154                     sys_version = atoi(ntp_optarg);
155                     break;
156                 case 'r':
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);
162                             errflg++;
163                     }
164                     break;
165                 case 't':
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);
171                             errflg++;
172                     }
173                     break;
174                 case 'v':
175                     verbose = 1;
176                     break;
177                 case '?':
178                     ++errflg;
179                     break;
180                 default:
181                     break;
182             }
183         
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",
187                                progname);
188                 exit(2);
189         }
190
191 #ifdef SYS_WINNT
192         wVersionRequested = MAKEWORD(1,1);
193         if (WSAStartup(wVersionRequested, &wsaData)) {
194                 msyslog(LOG_ERR, "No useable winsock.dll: %m");
195                 exit(1);
196         }
197 #endif /* SYS_WINNT */
198
199         sys_servers = (struct server **)
200                 emalloc(sys_maxservers * sizeof(struct server *));
201
202         if (debug) {
203 #ifdef HAVE_SETVBUF
204                 static char buf[BUFSIZ];
205                 setvbuf(stdout, buf, _IOLBF, BUFSIZ);
206 #else
207                 setlinebuf(stdout);
208 #endif
209         }
210
211         if (debug || verbose)
212             msyslog(LOG_NOTICE, "%s", Version);
213
214         if ((argc - ntp_optind) == 1)
215             firstserver = addservbyname(argv[ntp_optind]);
216         else
217             firstserver = addservbyname("localhost");
218                 
219         if (firstserver == NULL) {
220                 /* a message has already been printed */
221                 exit(2);
222         }
223
224         /*
225          * Initialize the time of day routines and the I/O subsystem
226          */
227         setup_io();
228         
229         DoTrace(firstserver);
230
231 #ifdef SYS_WINNT
232         WSACleanup();
233 #endif
234         return(0);
235 } /* main end */
236
237
238 static void
239 DoTrace(
240         register struct server *server
241         )
242 {
243         int retries = sys_retries;
244
245         if (!verbose) {
246                 if (nonames)
247                     printf("%s: ", ntoa(&server->srcadr));
248                 else
249                     printf("%s: ", ntohost(&server->srcadr));
250                 fflush(stdout);
251         }
252         while (retries-- > 0) {
253                 DoTransmit(server);
254                 if (DoReceive(server))
255                     return;
256         }
257         if (verbose) {
258                 if (nonames)
259                     printf("%s:\t*Timeout*\n", ntoa(&server->srcadr));
260                 else
261                     printf("%s:\t*Timeout*\n", ntohost(&server->srcadr));
262         }
263         else
264             printf("\t*Timeout*\n");
265 }
266
267 /*
268  * Dotransmit - transmit a packet to the given server
269  */
270 static void
271 DoTransmit(
272         register struct server *server
273         )
274 {
275         struct pkt xpkt;
276
277         if (debug)
278             printf("DoTransmit(%s)\n", ntoa(&server->srcadr));
279
280         /*
281          * Fill in the packet and let 'er rip.
282          */
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);
292         L_CLR(&xpkt.org);
293         L_CLR(&xpkt.rec);
294
295         /*
296          * just timestamp packet and send it away.
297          */
298         get_systime(&(server->xmt));
299         HTONL_FP(&server->xmt, &xpkt.xmt);
300         sendpkt(&(server->srcadr), &xpkt, LEN_PKT_NOMAC);
301
302         if (debug)
303             printf("DoTransmit to %s\n", ntoa(&(server->srcadr)));
304 }
305
306 /*
307  * DoReceive - attempt to receive a packet from a specific server
308  */
309 static int
310 DoReceive(
311         register struct server *server
312         )
313 {
314         register int n;
315         fd_set fds;
316         struct timeval timeout;
317         l_fp ts;
318         register struct recvbuf *rb;
319         int fromlen;
320         int status;
321
322         /*
323          * Loop until we see the packet we want or until we time out
324          */
325         for (;;) {
326                 fds = fdmask;
327                 timeout.tv_sec = sys_timeout;
328                 timeout.tv_usec = 0;
329                 n = select(fd+1, &fds, (fd_set *)0, (fd_set *)0, &timeout);
330             
331                 if (n == 0) {   /* timed out */
332                         if (debug)
333                             printf("timeout\n");
334                         return(0);
335                 }
336                 else if (n == -1) {
337                         msyslog(LOG_ERR, "select() error: %m");
338                         return(0);
339                 }
340                 get_systime(&ts);
341             
342                 if (free_recvbuffs() == 0) {
343                         msyslog(LOG_ERR, "no buffers");
344                         exit(1);
345                 }
346
347                 rb = get_free_recv_buffer();
348
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) {
354                         freerecvbuf(rb);
355                         continue;
356                 }
357
358                 /*
359                  * Got one.  Mark how and when it got here,
360                  * put it on the full list.
361                  */
362                 rb->recv_time = ts;
363                 add_full_recv_buffer(rb);
364
365                 status = ReceiveBuf(server, rb);
366
367                 freerecvbuf(rb);
368             
369                 return(status);
370         }
371 }
372
373 /*
374  * receive - receive and process an incoming frame
375  *      Return 1 on success, 0 on failure
376  */
377 static int
378 ReceiveBuf(
379         struct server *server,
380         struct recvbuf *rbufp
381         )
382 {
383         register struct pkt *rpkt;
384         register s_fp di;
385         l_fp t10, t23;
386         l_fp org;
387         l_fp rec;
388         l_fp ci;
389         struct server *nextserver;
390         struct in_addr nextia;
391         
392
393         if (debug) {
394                 printf("ReceiveBuf(%s, ", ntoa(&server->srcadr));
395                 printf("%s)\n", ntoa(&rbufp->recv_srcadr));
396         }
397
398         /*
399          * Check to see if the packet basically looks like something
400          * intended for us.
401          */
402         if (rbufp->recv_length < LEN_PKT_NOMAC) {
403                 if (debug)
404                     printf("receive: packet length %d\n",
405                            rbufp->recv_length);
406                 return(0);              /* funny length packet */
407         }
408         if (rbufp->recv_srcadr.sin_addr.s_addr != server->srcadr.sin_addr.s_addr) {
409                 if (debug)
410                     printf("receive: wrong server\n");
411                 return(0);              /* funny length packet */
412         }
413
414         rpkt = &(rbufp->recv_pkt);
415
416         if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION) {
417                 if (debug)
418                     printf("receive: version %d\n", PKT_VERSION(rpkt->li_vn_mode));
419                 return(0);
420         }
421         if (PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) {
422                 if (debug)
423                     printf("receive: version %d\n", PKT_VERSION(rpkt->li_vn_mode));
424                 return(0);
425         }
426
427         if ((PKT_MODE(rpkt->li_vn_mode) != MODE_SERVER
428              && PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE)
429             || rpkt->stratum > NTP_MAXSTRATUM) {
430                 if (debug)
431                     printf("receive: mode %d stratum %d\n",
432                            PKT_MODE(rpkt->li_vn_mode), rpkt->stratum);
433                 return(0);
434         }
435         
436         /*
437          * Decode the org timestamp and make sure we're getting a response
438          * to our last request.
439          */
440         NTOHL_FP(&rpkt->org, &org);
441         if (!L_ISEQU(&org, &server->xmt)) {
442                 if (debug)
443                     printf("receive: pkt.org and peer.xmt differ\n");
444                 return(0);
445         }
446         
447         /*
448          * Looks good.  Record info from the packet.
449          */
450
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);
460
461         /*
462          * Make sure the server is at least somewhat sane.  If not, try
463          * again.
464          */
465         if (L_ISZERO(&rec) || !L_ISHIS(&server->org, &rec)) {
466                 return(0);
467         }
468
469         /*
470          * Calculate the round trip delay (di) and the clock offset (ci).
471          * We use the equations (reordered from those in the spec):
472          *
473          * d = (t2 - t3) - (t1 - t0)
474          * c = ((t2 - t3) + (t1 - t0)) / 2
475          */
476         t10 = server->org;              /* pkt.xmt == t1 */
477         L_SUB(&t10, &rbufp->recv_time); /* recv_time == t0*/
478
479         t23 = rec;                      /* pkt.rec == t2 */
480         L_SUB(&t23, &org);              /* pkt->org == t3 */
481
482         /* now have (t2 - t3) and (t0 - t1).  Calculate (ci) and (di) */
483         ci = t10;
484         L_ADD(&ci, &t23);
485         L_RSHIFT(&ci);
486
487         /*
488          * Calculate di in t23 in full precision, then truncate
489          * to an s_fp.
490          */
491         L_SUB(&t23, &t10);
492         di = LFPTOFP(&t23);
493
494         server->offset = ci;
495         server->delay = di;
496
497         printserver(server, stdout);
498
499         /*
500          * End of recursion if we reach stratum 1 or a local refclock
501          */
502         if ((server->stratum <= 1) || (--maxhosts <= 0) || ((server->refid & 0xff) == 127))
503             return(1);
504
505         nextia.s_addr = server->refid;
506         nextserver = addserver(&nextia);
507         if (nextserver)
508           DoTrace(nextserver);
509         return(1);
510 }
511
512 /* XXX ELIMINATE addserver (almost) identical to ntpdate.c, ntptrace.c */
513 /*
514  * addserver - Allocate a new structure for server.
515  *              Returns a pointer to that structure.
516  */
517 static struct server *
518 addserver(
519         struct in_addr *iap
520         )
521 {
522         register struct server *server;
523         static int toomany = 0;
524
525         if (sys_numservers >= sys_maxservers) {
526                 if (!toomany) {
527                         toomany = 1;
528                         msyslog(LOG_ERR,
529                                 "too many servers (> %d) specified, remainder not used",
530                                 sys_maxservers);
531                 }
532                 return(NULL);
533         }
534
535         server = (struct server *)emalloc(sizeof(struct server));
536         memset((char *)server, 0, sizeof(struct server));
537
538         server->srcadr.sin_family = AF_INET;
539         server->srcadr.sin_addr = *iap;
540         server->srcadr.sin_port = htons(NTP_PORT);
541
542         sys_servers[sys_numservers++] = server;
543         
544         return(server);
545 }
546
547
548 /*
549  * addservbyname - determine a server's address and allocate a new structure
550  *             for it.  Returns a pointer to that structure.
551  */
552 static struct server *
553 addservbyname(
554         const char *serv
555         )
556 {
557         u_int32 ipaddr;
558         struct in_addr ia;
559
560         if (!getipaddr(serv, &ipaddr)) {
561                 msyslog(LOG_ERR, "can't find host %s\n", serv);
562                 return(NULL);
563         }
564
565         ia.s_addr = ipaddr;
566         return(addserver(&ia));
567 }
568
569
570 static void
571 setup_io(void)
572 {
573         /*
574          * Init buffer free list and stat counters
575          */
576         init_recvbuff(sys_maxservers + 2);
577
578         /* create a datagram (UDP) socket */
579         if ((fd = socket(AF_INET, SOCK_DGRAM, 0))
580 #ifndef SYS_WINNT
581             < 0
582 #else
583             == INVALID_SOCKET
584 #endif
585             ) {
586                 msyslog(LOG_ERR, "socket() failed: %m");
587                 exit(1);
588                 /*NOTREACHED*/
589         }
590
591         FD_ZERO(&fdmask);
592         FD_SET(fd, &fdmask);
593 }
594
595
596
597 /* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */
598 /*
599  * sendpkt - send a packet to the specified destination
600  */
601 static void
602 sendpkt(
603         struct sockaddr_in *dest,
604         struct pkt *pkt,
605         int len
606         )
607 {
608         int cc;
609
610         cc = sendto(fd, (char *)pkt, len, 0, (struct sockaddr *)dest,
611                     sizeof(struct sockaddr_in));
612         if (cc == -1) {
613 #ifndef SYS_WINNT
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));
620         }
621 }
622
623 /*
624  * getipaddr - given a host name, return its host address
625  */
626 static int
627 getipaddr(
628         const char *host,
629         u_int32 *num
630         )
631 {
632         struct hostent *hp;
633
634         if (decodeipaddr(host, num)) {
635                 return 1;
636         } else if ((hp = gethostbyname(host)) != 0) {
637                 memmove((char *)num, hp->h_addr, sizeof(long));
638                 return 1;
639         }
640         return 0;
641 }
642
643 /*
644  * decodeipaddr - return a host address (this is crude, but careful)
645  */
646 static int
647 decodeipaddr(
648         const char *num,
649         u_int32 *ipaddr
650         )
651 {
652         register const char *cp;
653         register char *bp;
654         register int i;
655         register int temp;
656         char buf[80];           /* will core dump on really stupid stuff */
657
658         cp = num;
659         *ipaddr = 0;
660         for (i = 0; i < 4; i++) {
661                 bp = buf;
662                 while (isdigit((int)*cp))
663                     *bp++ = *cp++;
664                 if (bp == buf)
665                     break;
666
667                 if (i < 3) {
668                         if (*cp++ != '.')
669                             break;
670                 } else if (*cp != '\0')
671                     break;
672
673                 *bp = '\0';
674                 temp = atoi(buf);
675                 if (temp > 255)
676                     break;
677                 *ipaddr <<= 8;
678                 *ipaddr += temp;
679         }
680         
681         if (i < 4)
682             return 0;
683         *ipaddr = htonl(*ipaddr);
684         return 1;
685 }
686
687
688 /* XXX ELIMINATE printserver similar in ntptrace.c, ntpdate.c */
689 /*
690  * printserver - print detail information for a server
691  */
692 static void
693 printserver(
694         register struct server *pp,
695         FILE *fp
696         )
697 {
698         u_fp synchdist;
699
700         synchdist = pp->rootdispersion + (pp->rootdelay/2);
701
702         if (!verbose) {
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 ");
707                         printrefid(fp, pp);
708                 }
709                 (void) fprintf(fp, "\n");
710                 return;
711         }
712
713         (void) fprintf(fp, "server %s, port %d\n", ntoa(&pp->srcadr),
714             ntohs(pp->srcadr.sin_port));
715
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');
719         
720         (void) fprintf(fp, "refid ");
721         printrefid(fp, pp);
722
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));
729         
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));
736
737         (void) fprintf(fp, "\n");
738
739 }
740
741 static void
742 printrefid(
743         FILE *fp,
744         struct server *pp
745         )
746 {
747         char junk[5];
748         char *str;
749
750         if (pp->stratum == 1) {
751                 junk[4] = 0;
752                 memmove(junk, (char *)&pp->refid, 4);
753                 str = junk;
754                 (void) fprintf(fp, "'%s'", str);
755         } else {
756                 if (nonames) {
757                         str = numtoa(pp->refid);
758                         (void) fprintf(fp, "[%s]", str);
759                 }
760                 else {
761                         str = numtohost(pp->refid);
762                         (void) fprintf(fp, "%s", str);
763                 }
764         }
765 }
766
767 #if !defined(HAVE_VSPRINTF)
768 int
769 vsprintf(
770         char *str,
771         const char *fmt,
772         va_list ap
773         )
774 {
775         FILE f;
776         int len;
777
778         f._flag = _IOWRT+_IOSTRG;
779         f._ptr = str;
780         f._cnt = 32767;
781         len = _doprnt(fmt, ap, &f);
782         *f._ptr = 0;
783         return (len);
784 }
785 #endif