1: #if !defined(lint) && defined(DOSCCS) 2: static char *RCSid = "$Source: /usr/src/new/ntp/ntpdc.c,v $ $Revision: 3.4.1.8 $ $Date: 95/01/27 17:31:26 $"; 3: #endif 4: 5: /* 6: * $Log: ntpdc.c,v $ 7: * Revision 3.4.1.8 95/01/27 17:31:26 sms 8: * Fix name clockinfo name collision with sysctl.h 9: * 10: * Revision 3.4.1.7 89/05/18 18:31:26 louie 11: * A few cosmetic changes for ntpd.c 12: * 13: * Revision 3.4.1.6 89/05/03 15:17:27 louie 14: * ntpdc now will display addional peer flags which indicate how far through 15: * the clock selection process a peer was considered. 16: * 17: * Revision 3.4.1.5 89/04/08 10:38:06 louie 18: * Minor cosmetic changes and removed dead debug code from ntpd.c 19: * 20: * Revision 3.4.1.4 89/03/29 12:41:56 louie 21: * Check for success sending query before trying to listen for answers. Will 22: * catch case of no server running and an ICMP port unreachable being returned. 23: * 24: * Revision 3.4.1.3 89/03/22 18:29:53 louie 25: * patch3: Use new RCS headers. 26: * 27: * Revision 3.4.1.2 89/03/22 18:04:18 louie 28: * Display dispersion in milliseconds. The peer->refid field was being ntohl()'ed 29: * when it should have stayed in network byte order. 30: * 31: * Revision 3.4.1.1 89/03/20 00:13:41 louie 32: * patch1: Delete unused variables. Display interface address in numeric form 33: * patch1: for local address, rather than symbolically. For multiple host 34: * patch1: queries, the name of the host is emitted prior to the data for that 35: * patch1: host. 36: * 37: * Revision 3.4 89/03/17 18:37:16 louie 38: * Latest test release. 39: * 40: * Revision 3.3.1.1 89/03/17 18:27:43 louie 41: * Fix version number mismatch error message. 42: * 43: * Revision 3.3 89/03/15 14:20:00 louie 44: * New baseline for next release. 45: * 46: * Revision 3.2.1.2 89/03/15 14:03:02 louie 47: * The logical used to receive replies has been revised considerably. Each packet 48: * in the reply from the ntpd program carries the total number of packets in the 49: * reply as well as a sequence number for this packet. Thus, we know how many 50: * packets to expect, and which one's we're received already. A new UDP socket 51: * is used for each host to prevent the replies from being mixed. This was 52: * a problem when querying an old ntpd which returned 7 bad version packets.. 53: * Use "%f" rather than "%lf" in format strings. 54: * 55: * Revision 3.2.1.1 89/03/10 12:28:24 louie 56: * Clean up output fomatting somewhat. 57: * 58: * Revision 3.2 89/03/07 18:27:52 louie 59: * Cosmetic changes and bug fixes. Note that this version is likely to be 60: * slightly incompatible with previous versions because the definitions of 61: * the flage bits (PEER_FL_*) in ntp.h have changed. 62: * 63: * A future version of this program will have a considerably different 64: * packet format when Version 2 support is added. 65: * 66: * Revision 3.1.1.1 89/02/15 09:01:39 louie 67: * Bugfixes to previous release version. 68: * 69: * 70: * Revision 3.1 89/01/30 14:43:16 louie 71: * Second UNIX NTP test release. 72: * 73: * Revision 3.0 88/12/12 15:57:28 louie 74: * Test release of new UNIX NTP software. This version should conform to the 75: * revised NTP protocol specification. 76: * 77: */ 78: 79: #include <sys/types.h> 80: #include <sys/param.h> 81: #include <signal.h> 82: #include <sys/uio.h> 83: #include <sys/socket.h> 84: #include <sys/time.h> 85: #include <netinet/in.h> 86: #include <netinet/udp.h> 87: #include <errno.h> 88: #include <stdio.h> 89: #include <netdb.h> 90: #include <strings.h> 91: #include <arpa/inet.h> 92: #include "ntp.h" 93: 94: #define WTIME 10 /* Time to wait for all responses */ 95: #define STIME 500000 /* usec to wait for another response */ 96: #define MAXPACKETSIZE 1500 97: 98: extern int errno; 99: int debug; 100: int s; 101: int timedout, timeout(); 102: int nflag, vflag, tflag; 103: 104: struct sockaddr_in sin = {AF_INET}; 105: 106: char packet[MAXPACKETSIZE]; 107: #ifndef MAXHOSTNAMELEN 108: #define MAXHOSTNAMELEN 64 109: #endif 110: char LocalHostName[MAXHOSTNAMELEN+1]; /* our hostname */ 111: char *LocalDomain; /* our local domain name */ 112: 113: 114: main(argc, argv) 115: int argc; 116: char *argv[]; 117: { 118: char *p; 119: #ifdef pdp11 120: int on = 4*1024; 121: #else 122: int on = 48*1024; 123: #endif 124: 125: (void) gethostname(LocalHostName, sizeof LocalHostName); 126: if (p = index(LocalHostName, '.')) { 127: *p++ = '\0'; 128: LocalDomain = p; 129: } 130: else 131: LocalDomain = ""; 132: 133: if (argc < 2) { 134: usage: 135: printf("usage: %s [ -v ][ -n ] hosts...\n", argv[0]); 136: exit(1); 137: } 138: 139: argv++, argc--; 140: if (*argv[0] == '-') { 141: switch (argv[0][1]) { 142: case 'n': 143: nflag++; 144: break; 145: case 't': 146: tflag++; 147: break; 148: case 'v': 149: vflag++; 150: break; 151: default: 152: goto usage; 153: } 154: argc--, argv++; 155: } 156: if (argc > 1) 157: printf("--- %s ---\n", *argv); 158: 159: while (argc > 0) { 160: /* 161: * Get a new socket each time - this will cause us to ignore 162: * packets from the previously queried host. 163: */ 164: s = socket(AF_INET, SOCK_DGRAM, 0); 165: if (s < 0) { 166: perror("socket"); 167: exit(2); 168: } 169: #ifdef SO_RCVBUF 170: if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &on, sizeof (on)) < 0) { 171: fprintf(stderr, "setsockopt SO_RCVBUF\n"); 172: } 173: #endif 174: if (query(*argv)) 175: answer(*argv); 176: close(s); 177: argv++; 178: if (argc-- > 1) 179: printf("--- %s ---\n", *argv); 180: } 181: 182: } 183: 184: answer(host) 185: char *host; 186: { 187: register struct ntpinfo *msg = (struct ntpinfo *) packet; 188: register struct xclockinfo *n; 189: struct sockaddr_in from; 190: int fromlen = sizeof(from); 191: int count, cc; 192: fd_set bits; 193: struct timeval shorttime; 194: int first = 1; 195: long replies = 0; 196: 197: /* 198: * Listen for returning packets; may be more than one packet per 199: * host. 200: */ 201: FD_ZERO(&bits); 202: FD_SET(s, &bits); 203: shorttime.tv_sec = 0; 204: shorttime.tv_usec = STIME; 205: (void) signal(SIGALRM, timeout); 206: (void) alarm(WTIME); 207: timedout = 0; 208: while ((first || replies) && 209: (!timedout || select(FD_SETSIZE, &bits, (fd_set *) 0, 210: (fd_set *) 0, &shorttime) > 0)) { 211: if ((cc = recvfrom(s, packet, sizeof(packet), 0, 212: (struct sockaddr *)&from, &fromlen)) <= 0) { 213: if (cc == 0 || errno == EINTR) 214: continue; 215: fflush(stdout); 216: perror(host); 217: (void) close(s); 218: return; 219: } 220: FD_SET(s, &bits); 221: 222: if (msg->type != INFO_REPLY) 223: return; 224: 225: if (msg->version != NTPDC_VERSION) { 226: printf("ntpd(%d) - ntpdc(%d) version mismatch\n", 227: msg->version, NTPDC_VERSION); 228: alarm(0); 229: return; 230: } 231: 232: if (first) { 233: first = 0; 234: replies = (1L << msg->npkts) - 1; 235: if (!vflag) { 236: if (tflag) 237: printf(" Address Reference Strat Poll Reach Delay Offset Disp\n"); 238: else 239: printf(" (rem) Address (lcl) Strat Poll Reach Delay Offset Disp\n"); 240: printf("==========================================================================\n"); 241: } 242: } 243: replies &= ~(1L << msg->seq); 244: n = (struct xclockinfo *)&msg[1]; 245: for (count = msg->count; count > 0; count--) { 246: if(vflag) 247: print_verbose(n); 248: else 249: print_terse(n); 250: n++; 251: } 252: } 253: alarm(0); 254: if (replies) 255: printf("Timed out waiting for replies\n"); 256: } 257: 258: int 259: query(host) 260: char *host; 261: { 262: struct sockaddr_in watcher; 263: register struct ntpdata *msg = (struct ntpdata *) packet; 264: struct hostent *hp; 265: static struct servent *sp = NULL; 266: long HostAddr; 267: 268: bzero((char *) &watcher, sizeof(watcher)); 269: watcher.sin_family = AF_INET; 270: HostAddr = inet_addr(host); 271: watcher.sin_addr.s_addr = (u_long) HostAddr; 272: if (HostAddr == -1) { 273: hp = gethostbyname(host); 274: if (hp == 0) { 275: fprintf(stderr,"%s: unknown\n", host); 276: return 0; 277: } 278: bcopy(hp->h_addr, (char *) &watcher.sin_addr, hp->h_length); 279: } 280: sp = getservbyname("ntp", "udp"); 281: if (sp == 0) { 282: fprintf(stderr,"udp/ntp: service unknown, using default %d\n", 283: NTP_PORT); 284: watcher.sin_port = htons(NTP_PORT); 285: } else 286: watcher.sin_port = sp->s_port; 287: msg->status = NTPVERSION_1; 288: msg->stratum = INFO_QUERY; 289: if (connect(s, (struct sockaddr *) &watcher, sizeof(watcher))) { 290: perror("connect"); 291: return 0; 292: } 293: if (send(s, packet, sizeof(struct ntpdata), 0) < 0) { 294: perror("send"); 295: return 0; 296: } 297: return 1; 298: } 299: 300: timeout() 301: { 302: timedout = 1; 303: } 304: 305: print_terse (n) 306: struct xclockinfo *n; 307: { 308: int i; 309: double offset[PEER_SHIFT], delay[PEER_SHIFT], dsp,del,off; 310: char c; 311: char *cvthname(); 312: int flags; 313: 314: sin.sin_addr.s_addr = n->net_address; 315: for (i = 0; i < PEER_SHIFT; i++) { 316: delay[i] = (double) ((long) (ntohl(n->info_filter.delay[i])/1000.0)); 317: offset[i] = (double) ((long) (ntohl(n->info_filter.offset[i])/1000.0)); 318: } 319: dsp = (long) ntohl(n->estdisp); /* leave in milliseconds */ 320: del = (long) ntohl(n->estdelay); /* leave in milliseconds */ 321: off = (long) ntohl(n->estoffset); /* leave in milliseconds */ 322: c = ' '; 323: flags = ntohs(n->flags); 324: if (flags & PEER_FL_CONFIG) 325: c = '-'; /* mark pre-configured */ 326: if (flags & PEER_FL_SANE) 327: c = '.'; /* passed sanity check */ 328: if (flags & PEER_FL_CANDIDATE) 329: c = '+'; /* made candidate list */ 330: if (flags & PEER_FL_SELECTED) 331: c = '*'; /* mark peer selection */ 332: sin.sin_addr.s_addr = n->net_address; 333: printf("%c%-15.15s ", c, cvthname(&sin)); 334: if (tflag) { 335: if (n->stratum == 1 || n->stratum == 0) { 336: printf("%-4.4s ", (char *) &n->refid); 337: } else { 338: sin.sin_addr.s_addr = (u_long) n->refid; 339: printf("%-16.16s ", cvthname(&sin)); 340: } 341: } else { 342: sin.sin_addr.s_addr = n->my_address; 343: printf("%-16.16s ", sin.sin_addr.s_addr ? 344: inet_ntoa(sin.sin_addr) : "wildcard"); 345: } 346: printf("%2d %4d %03o %8.1f %8.1f %8.1f\n", 347: n->stratum, (int)ntohl((u_long)n->timer), 348: ntohs(n->reach) & SHIFT_MASK, del, off, dsp); 349: } 350: 351: print_verbose(n) 352: struct xclockinfo *n; 353: { 354: int i; 355: struct in_addr clock_host; 356: double offset[PEER_SHIFT], delay[PEER_SHIFT], dsp,del,off; 357: char *cvthname(); 358: 359: sin.sin_addr.s_addr = n->net_address; 360: for (i = 0; i < PEER_SHIFT; i++) { 361: delay[i] = (double) (long) ntohl(n->info_filter.delay[i]); 362: offset[i] = (double) (long) ntohl(n->info_filter.offset[i]); 363: } 364: dsp = (double) ((long) ntohl(n->estdisp)); /* in milliseconds */ 365: del = (double) ((long) ntohl(n->estdelay)); /* in milliseconds */ 366: off = (double) ((long) ntohl(n->estoffset)); /* in milliseconds */ 367: printf("Neighbor address %s port:%d", 368: inet_ntoa(sin.sin_addr), (int)ntohs(n->port)); 369: sin.sin_addr.s_addr = n->my_address; 370: printf(" local address %s\n", inet_ntoa(sin.sin_addr)); 371: printf("Reach: 0%o stratum: %d, precision: %d\n", 372: ntohs(n->reach) & SHIFT_MASK, n->stratum, n->precision); 373: printf("dispersion: %f, flags: %x, leap: %x\n", 374: dsp, 375: ntohs(n->flags), 376: n->leap); 377: if (n->stratum == 1 || n->stratum == 0) { 378: printf("Reference clock ID: %.4s", (char *)&n->refid); 379: } else { 380: clock_host.s_addr = (u_long) n->refid; 381: printf("Reference clock ID: [%s]", inet_ntoa(clock_host)); 382: } 383: printf(" timestamp: %08lx.%08lx\n", ntohl(n->reftime.int_part), 384: ntohl(n->reftime.fraction)); 385: 386: printf("hpoll: %d, ppoll: %d, timer: %d, sent: %d received: %d\n", 387: n->hpoll, n->ppoll, 388: (int)ntohl((u_long)n->timer), 389: (int)ntohl(n->pkt_sent), 390: (int)ntohl(n->pkt_rcvd)); 391: printf("Delay(ms) "); 392: for (i = 0; i < PEER_SHIFT; i++) 393: printf("%7.2f ", delay[i]); 394: printf("\n"); 395: printf("Offset(ms) "); 396: for (i = 0; i < PEER_SHIFT; i++) 397: printf("%7.2f ", offset[i]); 398: printf("\n"); 399: printf("\n\tdelay: %f offset: %f dsp %f\n", del, off, dsp); 400: printf("\n"); 401: } 402: /* 403: * Return a printable representation of a host address. 404: */ 405: char * 406: cvthname(f) 407: struct sockaddr_in *f; 408: { 409: struct hostent *hp; 410: register char *p; 411: extern char *inet_ntoa(); 412: 413: if (f->sin_family != AF_INET) { 414: printf("Malformed from address\n"); 415: return ("???"); 416: } 417: if (!nflag) 418: hp = gethostbyaddr(&f->sin_addr, sizeof(struct in_addr), 419: f->sin_family); 420: else 421: return (inet_ntoa(f->sin_addr)); 422: 423: if (hp == 0) 424: return (inet_ntoa(f->sin_addr)); 425: 426: if ((p = index(hp->h_name, '.')) && strcmp(p + 1, LocalDomain) == 0) 427: *p = '\0'; 428: return (hp->h_name); 429: }