1: /*-
2: * Copyright (c) 1985, 1993
3: * The Regents of the University of California. All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. All advertising materials mentioning features or use of this software
14: * must display the following acknowledgement:
15: * This product includes software developed by the University of
16: * California, Berkeley and its contributors.
17: * 4. Neither the name of the University nor the names of its contributors
18: * may be used to endorse or promote products derived from this software
19: * without specific prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31: * SUCH DAMAGE.
32: *
33: * @(#)cmds.c 8.1 (Berkeley) 6/6/93
34: * $FreeBSD: src/usr.sbin/timed/timedc/cmds.c,v 1.6.2.2 2001/08/31 08:02:06 kris Exp $
35: * $DragonFly: src/usr.sbin/timed/timedc/cmds.c,v 1.2 2003/06/17 04:30:03 dillon Exp $
36: */
37:
38: #include "timedc.h"
39: #include <sys/file.h>
40:
41: #include <netinet/in_systm.h>
42: #include <netinet/ip.h>
43: #include <netinet/ip_icmp.h>
44:
45: #include <err.h>
46: #include <stdlib.h>
47: #include <strings.h>
48: #include <unistd.h>
49:
50: #define TSPTYPES
51: #include <protocols/timed.h>
52:
53: #ifdef sgi
54: #include <bstring.h>
55: #include <sys/clock.h>
56: #else
57: #define SECHR (60*60)
58: #define SECDAY (24*SECHR)
59: #endif /* sgi */
60:
61: # define DATE_PROTO "udp"
62: # define DATE_PORT "time"
63:
64:
65: int sock;
66: int sock_raw;
67: char myname[MAXHOSTNAMELEN];
68: struct hostent *hp;
69: struct sockaddr_in server;
70: struct sockaddr_in dayaddr;
71: extern int measure_delta;
72:
73: void bytenetorder(struct tsp *);
74: void bytehostorder(struct tsp *);
75:
76:
77: #define BU (2208988800UL) /* seconds before UNIX epoch */
78:
79:
80: /* compute the difference between our date and another machine
81: */
82: static int /* difference in days from our time */
83: daydiff(hostname)
84: char *hostname;
85: {
86: int i;
87: int trials;
88: struct timeval tout, now;
89: fd_set ready;
90: struct sockaddr from;
91: int fromlen;
92: unsigned long sec;
93:
94:
95: /* wait 2 seconds between 10 tries */
96: tout.tv_sec = 2;
97: tout.tv_usec = 0;
98: for (trials = 0; trials < 10; trials++) {
99: /* ask for the time */
100: sec = 0;
101: if (sendto(sock, &sec, sizeof(sec), 0,
102: (struct sockaddr*)&dayaddr, sizeof(dayaddr)) < 0) {
103: warn("sendto(sock)");
104: return 0;
105: }
106:
107: for (;;) {
108: FD_ZERO(&ready);
109: FD_SET(sock, &ready);
110: i = select(sock+1, &ready, (fd_set *)0,
111: (fd_set *)0, &tout);
112: if (i < 0) {
113: if (errno == EINTR)
114: continue;
115: warn("select(date read)");
116: return 0;
117: }
118: if (0 == i)
119: break;
120:
121: fromlen = sizeof(from);
122: if (recvfrom(sock,&sec,sizeof(sec),0,
123: &from,&fromlen) < 0) {
124: warn("recvfrom(date read)");
125: return 0;
126: }
127:
128: sec = ntohl(sec);
129: if (sec < BU) {
130: warnx("%s says it is before 1970: %lu",
131: hostname, sec);
132: return 0;
133: }
134: sec -= BU;
135:
136: (void)gettimeofday(&now, (struct timezone*)0);
137: return (sec - now.tv_sec);
138: }
139: }
140:
141: /* if we get here, we tried too many times */
142: warnx("%s will not tell us the date", hostname);
143: return 0;
144: }
145:
146:
147: /*
148: * Clockdiff computes the difference between the time of the machine on
149: * which it is called and the time of the machines given as argument.
150: * The time differences measured by clockdiff are obtained using a sequence
151: * of ICMP TSTAMP messages which are returned to the sender by the IP module
152: * in the remote machine.
153: * In order to compare clocks of machines in different time zones, the time
154: * is transmitted (as a 32-bit value) in milliseconds since midnight UT.
155: * If a hosts uses a different time format, it should set the high order
156: * bit of the 32-bit quantity it transmits.
157: * However, VMS apparently transmits the time in milliseconds since midnight
158: * local time (rather than GMT) without setting the high order bit.
159: * Furthermore, it does not understand daylight-saving time. This makes
160: * clockdiff behaving inconsistently with hosts running VMS.
161: *
162: * In order to reduce the sensitivity to the variance of message transmission
163: * time, clockdiff sends a sequence of messages. Yet, measures between
164: * two `distant' hosts can be affected by a small error. The error can,
165: * however, be reduced by increasing the number of messages sent in each
166: * measurement.
167: */
168: void
169: clockdiff(argc, argv)
170: int argc;
171: char *argv[];
172: {
173: int measure_status;
174: extern int measure(u_long, u_long, char *, struct sockaddr_in*, int);
175: register int avg_cnt;
176: register long avg;
177: struct servent *sp;
178:
179: if (argc < 2) {
180: printf("usage: timedc clockdiff host ...\n");
181: return;
182: }
183:
184: if (gethostname(myname, sizeof(myname) - 1) < 0)
185: err(1, "gethostname");
186:
187: /* get the address for the date ready */
188: sp = getservbyname(DATE_PORT, DATE_PROTO);
189: if (!sp) {
190: warnx("%s/%s is an unknown service", DATE_PORT, DATE_PROTO);
191: dayaddr.sin_port = 0;
192: } else {
193: dayaddr.sin_port = sp->s_port;
194: }
195:
196: while (argc > 1) {
197: argc--; argv++;
198: hp = gethostbyname(*argv);
199: if (hp == NULL) {
200: warnx("%s: %s", *argv, hstrerror(h_errno));
201: continue;
202: }
203:
204: server.sin_family = hp->h_addrtype;
205: bcopy(hp->h_addr, &server.sin_addr.s_addr, hp->h_length);
206: for (avg_cnt = 0, avg = 0; avg_cnt < 16; avg_cnt++) {
207: measure_status = measure(10000,100, *argv, &server, 1);
208: if (measure_status != GOOD)
209: break;
210: avg += measure_delta;
211: }
212: if (measure_status == GOOD)
213: measure_delta = avg/avg_cnt;
214:
215: switch (measure_status) {
216: case HOSTDOWN:
217: printf("%s is down\n", hp->h_name);
218: continue;
219: case NONSTDTIME:
220: printf("%s transmitts a non-standard time format\n",
221: hp->h_name);
222: continue;
223: case UNREACHABLE:
224: printf("%s is unreachable\n", hp->h_name);
225: continue;
226: }
227:
228: /*
229: * Try to get the date only after using ICMP timestamps to
230: * get the time. This is because the date protocol
231: * is optional.
232: */
233: if (dayaddr.sin_port != 0) {
234: dayaddr.sin_family = hp->h_addrtype;
235: bcopy(hp->h_addr, &dayaddr.sin_addr.s_addr,
236: hp->h_length);
237: avg = daydiff(*argv);
238: if (avg > SECDAY) {
239: printf("time on %s is %ld days ahead %s\n",
240: hp->h_name, avg/SECDAY, myname);
241: continue;
242: } else if (avg < -SECDAY) {
243: printf("time on %s is %ld days behind %s\n",
244: hp->h_name, -avg/SECDAY, myname);
245: continue;
246: }
247: }
248:
249: if (measure_delta > 0) {
250: printf("time on %s is %d ms. ahead of time on %s\n",
251: hp->h_name, measure_delta, myname);
252: } else if (measure_delta == 0) {
253: printf("%s and %s have the same time\n",
254: hp->h_name, myname);
255: } else {
256: printf("time on %s is %d ms. behind time on %s\n",
257: hp->h_name, -measure_delta, myname);
258: }
259: }
260: return;
261: }
262:
263:
264: /*
265: * finds location of master timedaemon
266: */
267: void
268: msite(argc, argv)
269: int argc;
270: char *argv[];
271: {
272: int cc;
273: fd_set ready;
274: struct sockaddr_in dest;
275: int i, length;
276: struct sockaddr_in from;
277: struct timeval tout;
278: struct tsp msg;
279: struct servent *srvp;
280: char *tgtname;
281:
282: if (argc < 1) {
283: printf("usage: timedc msite [host ...]\n");
284: return;
285: }
286:
287: srvp = getservbyname("timed", "udp");
288: if (srvp == 0) {
289: warnx("udp/timed: unknown service");
290: return;
291: }
292: dest.sin_port = srvp->s_port;
293: dest.sin_family = AF_INET;
294:
295: if (gethostname(myname, sizeof(myname) - 1) < 0)
296: err(1, "gethostname");
297: i = 1;
298: do {
299: tgtname = (i >= argc) ? myname : argv[i];
300: hp = gethostbyname(tgtname);
301: if (hp == 0) {
302: warnx("%s: %s", tgtname, hstrerror(h_errno));
303: continue;
304: }
305: bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length);
306:
307: (void)strlcpy(msg.tsp_name, myname, sizeof(msg.tsp_name));
308: msg.tsp_type = TSP_MSITE;
309: msg.tsp_vers = TSPVERSION;
310: bytenetorder(&msg);
311: if (sendto(sock, &msg, sizeof(struct tsp), 0,
312: (struct sockaddr*)&dest,
313: sizeof(struct sockaddr)) < 0) {
314: warn("sendto");
315: continue;
316: }
317:
318: tout.tv_sec = 15;
319: tout.tv_usec = 0;
320: FD_ZERO(&ready);
321: FD_SET(sock, &ready);
322: if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0,
323: &tout)) {
324: length = sizeof(from);
325: cc = recvfrom(sock, &msg, sizeof(struct tsp), 0,
326: (struct sockaddr *)&from, &length);
327: if (cc < 0) {
328: warn("recvfrom");
329: continue;
330: }
331: /*
332: * The 4.3BSD protocol spec had a 32-byte tsp_name field, and
333: * this is still OS-dependent. Demand that the packet is at
334: * least long enough to hold a 4.3BSD packet.
335: */
336: if (cc < (sizeof(struct tsp) - MAXHOSTNAMELEN + 32)) {
337: fprintf(stderr,
338: "short packet (%u/%u bytes) from %s\n",
339: cc, sizeof(struct tsp) - MAXHOSTNAMELEN + 32,
340: inet_ntoa(from.sin_addr));
341: continue;
342: }
343: bytehostorder(&msg);
344: if (msg.tsp_type == TSP_ACK) {
345: printf("master timedaemon at %s is %s\n",
346: tgtname, msg.tsp_name);
347: } else {
348: if (msg.tsp_type >= TSPTYPENUMBER)
349: printf("unknown ack received: %u\n",
350: msg.tsp_type);
351: else
352: printf("wrong ack received: %s\n",
353: tsptype[msg.tsp_type]);
354: }
355: } else {
356: printf("communication error with %s\n", tgtname);
357: }
358: } while (++i < argc);
359: }
360:
361: /*
362: * quits timedc
363: */
364: void
365: quit()
366: {
367: exit(0);
368: }
369:
370:
371: /*
372: * Causes the election timer to expire on the selected hosts
373: * It sends just one udp message per machine, relying on
374: * reliability of communication channel.
375: */
376: void
377: testing(argc, argv)
378: int argc;
379: char *argv[];
380: {
381: struct servent *srvp;
382: struct sockaddr_in sin;
383: struct tsp msg;
384:
385: if (argc < 2) {
386: printf("usage: timedc election host1 [host2 ...]\n");
387: return;
388: }
389:
390: srvp = getservbyname("timed", "udp");
391: if (srvp == 0) {
392: warnx("udp/timed: unknown service");
393: return;
394: }
395:
396: while (argc > 1) {
397: argc--; argv++;
398: hp = gethostbyname(*argv);
399: if (hp == NULL) {
400: warnx("%s: %s", *argv, hstrerror(h_errno));
401: argc--; argv++;
402: continue;
403: }
404: sin.sin_port = srvp->s_port;
405: sin.sin_family = hp->h_addrtype;
406: bcopy(hp->h_addr, &sin.sin_addr.s_addr, hp->h_length);
407:
408: msg.tsp_type = TSP_TEST;
409: msg.tsp_vers = TSPVERSION;
410: if (gethostname(myname, sizeof(myname) - 1) < 0)
411: err(1, "gethostname");
412: (void)strlcpy(msg.tsp_name, myname, sizeof(msg.tsp_name));
413: bytenetorder(&msg);
414: if (sendto(sock, &msg, sizeof(struct tsp), 0,
415: (struct sockaddr*)&sin,
416: sizeof(struct sockaddr)) < 0) {
417: warn("sendto");
418: }
419: }
420: }
421:
422:
423: /*
424: * Enables or disables tracing on local timedaemon
425: */
426: void
427: tracing(argc, argv)
428: int argc;
429: char *argv[];
430: {
431: int onflag;
432: int length;
433: int cc;
434: fd_set ready;
435: struct sockaddr_in dest;
436: struct sockaddr_in from;
437: struct timeval tout;
438: struct tsp msg;
439: struct servent *srvp;
440:
441: if (argc != 2) {
442: printf("usage: timedc trace { on | off }\n");
443: return;
444: }
445:
446: srvp = getservbyname("timed", "udp");
447: if (srvp == 0) {
448: warnx("udp/timed: unknown service");
449: return;
450: }
451: dest.sin_port = srvp->s_port;
452: dest.sin_family = AF_INET;
453:
454: if (gethostname(myname, sizeof(myname) - 1) < 0)
455: err(1, "gethostname");
456: hp = gethostbyname(myname);
457: bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length);
458:
459: if (strcmp(argv[1], "on") == 0) {
460: msg.tsp_type = TSP_TRACEON;
461: onflag = ON;
462: } else {
463: msg.tsp_type = TSP_TRACEOFF;
464: onflag = OFF;
465: }
466:
467: (void)strcpy(msg.tsp_name, myname);
468: msg.tsp_vers = TSPVERSION;
469: bytenetorder(&msg);
470: if (sendto(sock, &msg, sizeof(struct tsp), 0,
471: (struct sockaddr*)&dest, sizeof(struct sockaddr)) < 0) {
472: warn("sendto");
473: return;
474: }
475:
476: tout.tv_sec = 5;
477: tout.tv_usec = 0;
478: FD_ZERO(&ready);
479: FD_SET(sock, &ready);
480: if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) {
481: length = sizeof(from);
482: cc = recvfrom(sock, &msg, sizeof(struct tsp), 0,
483: (struct sockaddr *)&from, &length);
484: if (cc < 0) {
485: warn("recvfrom");
486: return;
487: }
488: /*
489: * The 4.3BSD protocol spec had a 32-byte tsp_name field, and
490: * this is still OS-dependent. Demand that the packet is at
491: * least long enough to hold a 4.3BSD packet.
492: */
493: if (cc < (sizeof(struct tsp) - MAXHOSTNAMELEN + 32)) {
494: fprintf(stderr, "short packet (%u/%u bytes) from %s\n",
495: cc, sizeof(struct tsp) - MAXHOSTNAMELEN + 32,
496: inet_ntoa(from.sin_addr));
497: return;
498: }
499: bytehostorder(&msg);
500: if (msg.tsp_type == TSP_ACK)
501: if (onflag)
502: printf("timed tracing enabled\n");
503: else
504: printf("timed tracing disabled\n");
505: else {
506: if (msg.tsp_type >= TSPTYPENUMBER)
507: printf("unknown ack received: %u\n",
508: msg.tsp_type);
509: else
510: printf("wrong ack received: %s\n",
511: tsptype[msg.tsp_type]);
512: }
513: } else
514: printf("communication error\n");
515: }
516:
517: int
518: priv_resources()
519: {
520: int port;
521: struct sockaddr_in sin;
522:
523: sock = socket(AF_INET, SOCK_DGRAM, 0);
524: if (sock < 0) {
525: warn("opening socket");
526: return(-1);
527: }
528:
529: sin.sin_family = AF_INET;
530: sin.sin_addr.s_addr = 0;
531: for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) {
532: sin.sin_port = htons((u_short)port);
533: if (bind(sock, (struct sockaddr*)&sin, sizeof (sin)) >= 0)
534: break;
535: if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) {
536: warn("bind");
537: (void) close(sock);
538: return(-1);
539: }
540: }
541: if (port == IPPORT_RESERVED / 2) {
542: warnx("all reserved ports in use");
543: (void) close(sock);
544: return(-1);
545: }
546:
547: sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
548: if (sock_raw < 0) {
549: warn("opening raw socket");
550: (void) close(sock);
551: return(-1);
552: }
553: return(1);
554: }