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.3 2004/03/13 21:08:39 eirikn 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(char *hostname)
84: {
85: int i;
86: int trials;
87: struct timeval tout, now;
88: fd_set ready;
89: struct sockaddr from;
90: int fromlen;
91: unsigned long sec;
92:
93: /* wait 2 seconds between 10 tries */
94: tout.tv_sec = 2;
95: tout.tv_usec = 0;
96: for (trials = 0; trials < 10; trials++) {
97: /* ask for the time */
98: sec = 0;
99: if (sendto(sock, &sec, sizeof(sec), 0,
100: (struct sockaddr*)&dayaddr, sizeof(dayaddr)) < 0) {
101: warn("sendto(sock)");
102: return 0;
103: }
104:
105: for (;;) {
106: FD_ZERO(&ready);
107: FD_SET(sock, &ready);
108: i = select(sock+1, &ready, (fd_set *)0,
109: (fd_set *)0, &tout);
110: if (i < 0) {
111: if (errno == EINTR)
112: continue;
113: warn("select(date read)");
114: return 0;
115: }
116: if (0 == i)
117: break;
118:
119: fromlen = sizeof(from);
120: if (recvfrom(sock,&sec,sizeof(sec),0,
121: &from,&fromlen) < 0) {
122: warn("recvfrom(date read)");
123: return 0;
124: }
125:
126: sec = ntohl(sec);
127: if (sec < BU) {
128: warnx("%s says it is before 1970: %lu",
129: hostname, sec);
130: return 0;
131: }
132: sec -= BU;
133:
134: (void)gettimeofday(&now, (struct timezone*)0);
135: return (sec - now.tv_sec);
136: }
137: }
138:
139: /* if we get here, we tried too many times */
140: warnx("%s will not tell us the date", hostname);
141: return 0;
142: }
143:
144:
145: /*
146: * Clockdiff computes the difference between the time of the machine on
147: * which it is called and the time of the machines given as argument.
148: * The time differences measured by clockdiff are obtained using a sequence
149: * of ICMP TSTAMP messages which are returned to the sender by the IP module
150: * in the remote machine.
151: * In order to compare clocks of machines in different time zones, the time
152: * is transmitted (as a 32-bit value) in milliseconds since midnight UT.
153: * If a hosts uses a different time format, it should set the high order
154: * bit of the 32-bit quantity it transmits.
155: * However, VMS apparently transmits the time in milliseconds since midnight
156: * local time (rather than GMT) without setting the high order bit.
157: * Furthermore, it does not understand daylight-saving time. This makes
158: * clockdiff behaving inconsistently with hosts running VMS.
159: *
160: * In order to reduce the sensitivity to the variance of message transmission
161: * time, clockdiff sends a sequence of messages. Yet, measures between
162: * two `distant' hosts can be affected by a small error. The error can,
163: * however, be reduced by increasing the number of messages sent in each
164: * measurement.
165: */
166: void
167: clockdiff(int argc, char *argv[])
168: {
169: int measure_status;
170: extern int measure(u_long, u_long, char *, struct sockaddr_in*, int);
171: int avg_cnt;
172: long avg;
173: struct servent *sp;
174:
175: if (argc < 2) {
176: printf("usage: timedc clockdiff host ...\n");
177: return;
178: }
179:
180: if (gethostname(myname, sizeof(myname) - 1) < 0)
181: err(1, "gethostname");
182:
183: /* get the address for the date ready */
184: sp = getservbyname(DATE_PORT, DATE_PROTO);
185: if (!sp) {
186: warnx("%s/%s is an unknown service", DATE_PORT, DATE_PROTO);
187: dayaddr.sin_port = 0;
188: } else {
189: dayaddr.sin_port = sp->s_port;
190: }
191:
192: while (argc > 1) {
193: argc--; argv++;
194: hp = gethostbyname(*argv);
195: if (hp == NULL) {
196: warnx("%s: %s", *argv, hstrerror(h_errno));
197: continue;
198: }
199:
200: server.sin_family = hp->h_addrtype;
201: bcopy(hp->h_addr, &server.sin_addr.s_addr, hp->h_length);
202: for (avg_cnt = 0, avg = 0; avg_cnt < 16; avg_cnt++) {
203: measure_status = measure(10000,100, *argv, &server, 1);
204: if (measure_status != GOOD)
205: break;
206: avg += measure_delta;
207: }
208: if (measure_status == GOOD)
209: measure_delta = avg/avg_cnt;
210:
211: switch (measure_status) {
212: case HOSTDOWN:
213: printf("%s is down\n", hp->h_name);
214: continue;
215: case NONSTDTIME:
216: printf("%s transmitts a non-standard time format\n",
217: hp->h_name);
218: continue;
219: case UNREACHABLE:
220: printf("%s is unreachable\n", hp->h_name);
221: continue;
222: }
223:
224: /*
225: * Try to get the date only after using ICMP timestamps to
226: * get the time. This is because the date protocol
227: * is optional.
228: */
229: if (dayaddr.sin_port != 0) {
230: dayaddr.sin_family = hp->h_addrtype;
231: bcopy(hp->h_addr, &dayaddr.sin_addr.s_addr,
232: hp->h_length);
233: avg = daydiff(*argv);
234: if (avg > SECDAY) {
235: printf("time on %s is %ld days ahead %s\n",
236: hp->h_name, avg/SECDAY, myname);
237: continue;
238: } else if (avg < -SECDAY) {
239: printf("time on %s is %ld days behind %s\n",
240: hp->h_name, -avg/SECDAY, myname);
241: continue;
242: }
243: }
244:
245: if (measure_delta > 0) {
246: printf("time on %s is %d ms. ahead of time on %s\n",
247: hp->h_name, measure_delta, myname);
248: } else if (measure_delta == 0) {
249: printf("%s and %s have the same time\n",
250: hp->h_name, myname);
251: } else {
252: printf("time on %s is %d ms. behind time on %s\n",
253: hp->h_name, -measure_delta, myname);
254: }
255: }
256: return;
257: }
258:
259:
260: /*
261: * finds location of master timedaemon
262: */
263: void
264: msite(int argc, char *argv[])
265: {
266: int cc;
267: fd_set ready;
268: struct sockaddr_in dest;
269: int i, length;
270: struct sockaddr_in from;
271: struct timeval tout;
272: struct tsp msg;
273: struct servent *srvp;
274: char *tgtname;
275:
276: if (argc < 1) {
277: printf("usage: timedc msite [host ...]\n");
278: return;
279: }
280:
281: srvp = getservbyname("timed", "udp");
282: if (srvp == 0) {
283: warnx("udp/timed: unknown service");
284: return;
285: }
286: dest.sin_port = srvp->s_port;
287: dest.sin_family = AF_INET;
288:
289: if (gethostname(myname, sizeof(myname) - 1) < 0)
290: err(1, "gethostname");
291: i = 1;
292: do {
293: tgtname = (i >= argc) ? myname : argv[i];
294: hp = gethostbyname(tgtname);
295: if (hp == 0) {
296: warnx("%s: %s", tgtname, hstrerror(h_errno));
297: continue;
298: }
299: bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length);
300:
301: (void)strlcpy(msg.tsp_name, myname, sizeof(msg.tsp_name));
302: msg.tsp_type = TSP_MSITE;
303: msg.tsp_vers = TSPVERSION;
304: bytenetorder(&msg);
305: if (sendto(sock, &msg, sizeof(struct tsp), 0,
306: (struct sockaddr*)&dest,
307: sizeof(struct sockaddr)) < 0) {
308: warn("sendto");
309: continue;
310: }
311:
312: tout.tv_sec = 15;
313: tout.tv_usec = 0;
314: FD_ZERO(&ready);
315: FD_SET(sock, &ready);
316: if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0,
317: &tout)) {
318: length = sizeof(from);
319: cc = recvfrom(sock, &msg, sizeof(struct tsp), 0,
320: (struct sockaddr *)&from, &length);
321: if (cc < 0) {
322: warn("recvfrom");
323: continue;
324: }
325: /*
326: * The 4.3BSD protocol spec had a 32-byte tsp_name field, and
327: * this is still OS-dependent. Demand that the packet is at
328: * least long enough to hold a 4.3BSD packet.
329: */
330: if (cc < (sizeof(struct tsp) - MAXHOSTNAMELEN + 32)) {
331: fprintf(stderr,
332: "short packet (%u/%u bytes) from %s\n",
333: cc, sizeof(struct tsp) - MAXHOSTNAMELEN + 32,
334: inet_ntoa(from.sin_addr));
335: continue;
336: }
337: bytehostorder(&msg);
338: if (msg.tsp_type == TSP_ACK) {
339: printf("master timedaemon at %s is %s\n",
340: tgtname, msg.tsp_name);
341: } else {
342: if (msg.tsp_type >= TSPTYPENUMBER)
343: printf("unknown ack received: %u\n",
344: msg.tsp_type);
345: else
346: printf("wrong ack received: %s\n",
347: tsptype[msg.tsp_type]);
348: }
349: } else {
350: printf("communication error with %s\n", tgtname);
351: }
352: } while (++i < argc);
353: }
354:
355: /*
356: * quits timedc
357: */
358: void
359: quit(void)
360: {
361:
362: exit(0);
363: }
364:
365:
366: /*
367: * Causes the election timer to expire on the selected hosts
368: * It sends just one udp message per machine, relying on
369: * reliability of communication channel.
370: */
371: void
372: testing(int argc, char *argv[])
373: {
374: struct servent *srvp;
375: struct sockaddr_in sin;
376: struct tsp msg;
377:
378: if (argc < 2) {
379: printf("usage: timedc election host1 [host2 ...]\n");
380: return;
381: }
382:
383: srvp = getservbyname("timed", "udp");
384: if (srvp == 0) {
385: warnx("udp/timed: unknown service");
386: return;
387: }
388:
389: while (argc > 1) {
390: argc--; argv++;
391: hp = gethostbyname(*argv);
392: if (hp == NULL) {
393: warnx("%s: %s", *argv, hstrerror(h_errno));
394: argc--; argv++;
395: continue;
396: }
397: sin.sin_port = srvp->s_port;
398: sin.sin_family = hp->h_addrtype;
399: bcopy(hp->h_addr, &sin.sin_addr.s_addr, hp->h_length);
400:
401: msg.tsp_type = TSP_TEST;
402: msg.tsp_vers = TSPVERSION;
403: if (gethostname(myname, sizeof(myname) - 1) < 0)
404: err(1, "gethostname");
405: (void)strlcpy(msg.tsp_name, myname, sizeof(msg.tsp_name));
406: bytenetorder(&msg);
407: if (sendto(sock, &msg, sizeof(struct tsp), 0,
408: (struct sockaddr*)&sin,
409: sizeof(struct sockaddr)) < 0) {
410: warn("sendto");
411: }
412: }
413: }
414:
415:
416: /*
417: * Enables or disables tracing on local timedaemon
418: */
419: void
420: tracing(int argc, char *argv[])
421: {
422: int onflag;
423: int length;
424: int cc;
425: fd_set ready;
426: struct sockaddr_in dest;
427: struct sockaddr_in from;
428: struct timeval tout;
429: struct tsp msg;
430: struct servent *srvp;
431:
432: if (argc != 2) {
433: printf("usage: timedc trace { on | off }\n");
434: return;
435: }
436:
437: srvp = getservbyname("timed", "udp");
438: if (srvp == 0) {
439: warnx("udp/timed: unknown service");
440: return;
441: }
442: dest.sin_port = srvp->s_port;
443: dest.sin_family = AF_INET;
444:
445: if (gethostname(myname, sizeof(myname) - 1) < 0)
446: err(1, "gethostname");
447: hp = gethostbyname(myname);
448: bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length);
449:
450: if (strcmp(argv[1], "on") == 0) {
451: msg.tsp_type = TSP_TRACEON;
452: onflag = ON;
453: } else {
454: msg.tsp_type = TSP_TRACEOFF;
455: onflag = OFF;
456: }
457:
458: (void)strcpy(msg.tsp_name, myname);
459: msg.tsp_vers = TSPVERSION;
460: bytenetorder(&msg);
461: if (sendto(sock, &msg, sizeof(struct tsp), 0,
462: (struct sockaddr*)&dest, sizeof(struct sockaddr)) < 0) {
463: warn("sendto");
464: return;
465: }
466:
467: tout.tv_sec = 5;
468: tout.tv_usec = 0;
469: FD_ZERO(&ready);
470: FD_SET(sock, &ready);
471: if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) {
472: length = sizeof(from);
473: cc = recvfrom(sock, &msg, sizeof(struct tsp), 0,
474: (struct sockaddr *)&from, &length);
475: if (cc < 0) {
476: warn("recvfrom");
477: return;
478: }
479: /*
480: * The 4.3BSD protocol spec had a 32-byte tsp_name field, and
481: * this is still OS-dependent. Demand that the packet is at
482: * least long enough to hold a 4.3BSD packet.
483: */
484: if (cc < (sizeof(struct tsp) - MAXHOSTNAMELEN + 32)) {
485: fprintf(stderr, "short packet (%u/%u bytes) from %s\n",
486: cc, sizeof(struct tsp) - MAXHOSTNAMELEN + 32,
487: inet_ntoa(from.sin_addr));
488: return;
489: }
490: bytehostorder(&msg);
491: if (msg.tsp_type == TSP_ACK)
492: if (onflag)
493: printf("timed tracing enabled\n");
494: else
495: printf("timed tracing disabled\n");
496: else {
497: if (msg.tsp_type >= TSPTYPENUMBER)
498: printf("unknown ack received: %u\n",
499: msg.tsp_type);
500: else
501: printf("wrong ack received: %s\n",
502: tsptype[msg.tsp_type]);
503: }
504: } else
505: printf("communication error\n");
506: }
507:
508: int
509: priv_resources(void)
510: {
511: int port;
512: struct sockaddr_in sin;
513:
514: sock = socket(AF_INET, SOCK_DGRAM, 0);
515: if (sock < 0) {
516: warn("opening socket");
517: return(-1);
518: }
519:
520: sin.sin_family = AF_INET;
521: sin.sin_addr.s_addr = 0;
522: for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) {
523: sin.sin_port = htons((u_short)port);
524: if (bind(sock, (struct sockaddr*)&sin, sizeof (sin)) >= 0)
525: break;
526: if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) {
527: warn("bind");
528: (void) close(sock);
529: return(-1);
530: }
531: }
532: if (port == IPPORT_RESERVED / 2) {
533: warnx("all reserved ports in use");
534: (void) close(sock);
535: return(-1);
536: }
537:
538: sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
539: if (sock_raw < 0) {
540: warn("opening raw socket");
541: (void) close(sock);
542: return(-1);
543: }
544: return(1);
545: }