2 * Copyright (c) 1985, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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 * 4. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 static const char copyright[] =
32 "@(#) Copyright (c) 1985, 1993\n\
33 The Regents of the University of California. All rights reserved.\n";
38 static char sccsid[] = "@(#)timed.c 8.1 (Berkeley) 6/6/93";
42 #include <sys/cdefs.h>
43 __FBSDID("$FreeBSD$");
49 #include <sys/ioctl.h>
51 #include "pathnames.h"
53 #include <sys/types.h>
54 #include <sys/times.h>
57 int sock, sock_raw = -1;
59 u_short sequence; /* sequence number */
63 int nslavenets; /* nets were I could be a slave */
64 int nmasternets; /* nets were I could be a master */
65 int nignorednets; /* ignored nets */
66 int nnets; /* nets I am connected to */
68 FILE *fd; /* trace file FD */
72 struct netinfo *nettab = 0;
73 struct netinfo *slavenet;
84 struct hosttbl hosttbl[NHOSTS+1]; /* known hosts */
86 static struct goodhost { /* hosts that we trust */
87 char name[MAXHOSTNAMELEN];
88 struct goodhost *next;
92 static char *goodgroup; /* net group of trusted hosts */
93 static void checkignorednets(void);
94 static void pickslavenet(struct netinfo *);
95 static void add_good_host(char *, int);
96 static void usage(void);
99 * The timedaemons synchronize the clocks of hosts in a local area network.
100 * One daemon runs as master, all the others as slaves. The master
101 * performs the task of computing clock differences and sends correction
102 * values to the slaves.
103 * Slaves start an election to choose a new master when the latter disappears
104 * because of a machine crash, network partition, or when killed.
105 * A resolution protocol is used to kill all but one of the masters
106 * that happen to exist in segments of a partitioned network when the
107 * network partition is fixed.
109 * Authors: Riccardo Gusella & Stefano Zatti
111 * overhauled at Silicon Graphics
121 struct timeval ntime;
122 struct servent *srvp;
123 char buf[BUFSIZ], *cp, *cplim;
125 struct ifreq ifreq, ifreqf, *ifr;
126 register struct netinfo *ntp;
127 struct netinfo *ntip;
128 struct netinfo *savefromnet;
129 struct netent *nentp;
131 struct sockaddr_in server;
145 while ((c = getopt(argc, argv, "Mtdn:i:F:G:P:")) != -1) {
157 errx(1, "-i and -n make no sense together");
166 errx(1, "-i and -n make no sense together");
174 add_good_host(optarg,1);
175 while (optind < argc && argv[optind][0] != '-')
176 add_good_host(argv[optind++], 1);
184 errx(1, "only one net group");
196 /* If we care about which machine is the master, then we must
197 * be willing to be a master
199 if (0 != goodgroup || 0 != goodhosts)
202 if (gethostname(hostname, sizeof(hostname) - 1) < 0)
203 err(1, "gethostname");
211 if (goodhosts != 0) /* trust ourself */
212 add_good_host(hostname,1);
214 srvp = getservbyname("timed", "udp");
216 errx(1, "timed/udp: unknown service");
218 bzero(&server, sizeof(struct sockaddr_in));
219 server.sin_port = srvp->s_port;
220 server.sin_family = AF_INET;
221 sock = socket(AF_INET, SOCK_DGRAM, 0);
224 if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&on,
226 err(1, "setsockopt");
227 if (bind(sock, (struct sockaddr*)&server, sizeof(server))) {
228 if (errno == EADDRINUSE)
229 warnx("time daemon already running");
235 /* choose a unique seed for random number generation */
236 (void)gettimeofday(&ntime, 0);
237 srandom(ntime.tv_sec + ntime.tv_usec);
239 sequence = random(); /* initial seq number */
241 /* rounds kernel variable time to multiple of 5 ms. */
243 ntime.tv_usec = -((ntime.tv_usec/1000) % 5) * 1000;
244 (void)adjtime(&ntime, (struct timeval *)0);
246 for (nt = nets; nt; nt = nt->next) {
247 nentp = getnetbyname(nt->name);
249 nt->net = inet_network(nt->name);
250 if (nt->net != INADDR_NONE)
251 nentp = getnetbyaddr(nt->net, AF_INET);
254 nt->net = nentp->n_net;
255 } else if (nt->net == INADDR_NONE) {
256 errx(1, "unknown net %s", nt->name);
257 } else if (nt->net == INADDR_ANY) {
258 errx(1, "bad net %s", nt->name);
260 warnx("warning: %s unknown in /etc/networks",
264 if (0 == (nt->net & 0xff000000))
266 if (0 == (nt->net & 0xff000000))
268 if (0 == (nt->net & 0xff000000))
271 ifc.ifc_len = sizeof(buf);
273 if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0)
274 err(1, "get interface configuration");
276 #define size(p) max((p).sa_len, sizeof(p))
277 cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */
278 for (cp = buf; cp < cplim;
279 cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) {
280 ifr = (struct ifreq *)cp;
281 if (ifr->ifr_addr.sa_family != AF_INET)
284 ntp = (struct netinfo*)malloc(sizeof(struct netinfo));
285 bzero(ntp,sizeof(*ntp));
286 ntp->my_addr=((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
287 ntp->status = NOMASTER;
291 if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreqf) < 0) {
292 warn("get interface flags");
295 if ((ifreqf.ifr_flags & IFF_UP) == 0)
297 if ((ifreqf.ifr_flags & IFF_BROADCAST) == 0 &&
298 (ifreqf.ifr_flags & IFF_POINTOPOINT) == 0) {
303 if (ioctl(sock, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
307 ntp->mask = ((struct sockaddr_in *)
308 &ifreq.ifr_addr)->sin_addr.s_addr;
310 if (ifreqf.ifr_flags & IFF_BROADCAST) {
311 if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
312 warn("get broadaddr");
315 ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_broadaddr;
316 /* What if the broadcast address is all ones?
317 * So we cannot just mask ntp->dest_addr. */
318 ntp->net = ntp->my_addr;
319 ntp->net.s_addr &= ntp->mask;
321 if (ioctl(sock, SIOCGIFDSTADDR,
322 (char *)&ifreq) < 0) {
323 warn("get destaddr");
326 ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_dstaddr;
327 ntp->net = ntp->dest_addr.sin_addr;
330 ntp->dest_addr.sin_port = port;
332 for (nt = nets; nt; nt = nt->next) {
333 if (ntp->net.s_addr == htonl(nt->net))
336 if ((nflag && !nt) || (iflag && nt))
340 if (nettab == NULL) {
349 (void) free((char *)ntp);
351 errx(1, "no network usable");
353 /* microseconds to delay before responding to a broadcast */
354 delay1 = casual(1, 100*1000);
356 /* election timer delay in secs. */
357 delay2 = casual(MINTOUT, MAXTOUT);
364 openlog("timed", LOG_CONS|LOG_PID, LOG_DAEMON);
367 * keep returning here
369 ret = setjmp(jmpenv);
370 savefromnet = fromnet;
381 /* Just lost our master */
383 slavenet->status = election(slavenet);
384 if (!slavenet || slavenet->status == MASTER) {
388 makeslave(slavenet); /* prune extras */
393 /* Just been told to quit */
395 pickslavenet(savefromnet);
400 if (!(status & MASTER) && sock_raw != -1) {
401 /* sock_raw is not being used now */
402 (void)close(sock_raw);
406 if (status == MASTER)
412 if (sock_raw != -1) {
413 (void)close(sock_raw);
418 /* we just lost our master or were told to quit */
421 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
422 if (ntp->status == MASTER) {
424 ntp->status = NOMASTER;
442 "usage: timed [-dtM] [-i net|-n net] [-F host1 host2 ...] [-G netgp]\n");
445 "usage: timed [-dtM] [-i net|-n net] [-F host1 host2 ...]\n");
451 * suppress an upstart, untrustworthy, self-appointed master
454 suppress(addr, name,net)
455 struct sockaddr_in *addr;
459 struct sockaddr_in tgt;
460 char tname[MAXHOSTNAMELEN];
462 static struct timeval wait;
465 fprintf(fd, "suppress: %s\n", name);
467 (void)strcpy(tname, name);
469 while (0 != readmsg(TSP_ANY, ANYADDR, &wait, net)) {
471 fprintf(fd, "suppress:\tdiscarded packet from %s\n",
475 syslog(LOG_NOTICE, "suppressing false master %s", tname);
476 msg.tsp_type = TSP_QUIT;
477 (void)strcpy(msg.tsp_name, hostname);
478 (void)acksend(&msg, &tgt, tname, TSP_ACK, 0, 1);
485 struct tsp resp, conflict, *answer;
486 struct timeval ntime;
487 char mastername[MAXHOSTNAMELEN];
488 struct sockaddr_in masteraddr;
493 /* look for master */
494 resp.tsp_type = TSP_MASTERREQ;
495 (void)strcpy(resp.tsp_name, hostname);
496 answer = acksend(&resp, &ntp->dest_addr, ANYADDR,
497 TSP_MASTERACK, ntp, 0);
498 if (answer != 0 && !good_host_name(answer->tsp_name)) {
499 suppress(&from, answer->tsp_name, ntp);
500 ntp->status = NOMASTER;
505 * Various conditions can cause conflict: races between
506 * two just started timedaemons when no master is
507 * present, or timedaemons started during an election.
508 * A conservative approach is taken. Give up and became a
509 * slave, postponing election of a master until first
512 ntime.tv_sec = ntime.tv_usec = 0;
513 answer = readmsg(TSP_MASTERREQ, ANYADDR, &ntime, ntp);
515 if (!good_host_name(answer->tsp_name)) {
516 suppress(&from, answer->tsp_name, ntp);
517 ntp->status = NOMASTER;
522 ntime.tv_sec = ntime.tv_usec = 0;
523 answer = readmsg(TSP_MASTERUP, ANYADDR, &ntime, ntp);
525 if (!good_host_name(answer->tsp_name)) {
526 suppress(&from, answer->tsp_name, ntp);
527 ntp->status = NOMASTER;
532 ntime.tv_sec = ntime.tv_usec = 0;
533 answer = readmsg(TSP_ELECTION, ANYADDR, &ntime, ntp);
535 if (!good_host_name(answer->tsp_name)) {
536 suppress(&from, answer->tsp_name, ntp);
537 ntp->status = NOMASTER;
543 ntp->status = MASTER;
545 ntp->status = NOMASTER;
550 (void)strcpy(mastername, answer->tsp_name);
554 * If network has been partitioned, there might be other
555 * masters; tell the one we have just acknowledged that
556 * it has to gain control over the others.
559 ntime.tv_usec = 300000;
560 answer = readmsg(TSP_MASTERACK, ANYADDR, &ntime, ntp);
562 * checking also not to send CONFLICT to ack'ed master
563 * due to duplicated MASTERACKs
565 if (answer != NULL &&
566 strcmp(answer->tsp_name, mastername) != 0) {
567 conflict.tsp_type = TSP_CONFLICT;
568 (void)strcpy(conflict.tsp_name, hostname);
569 if (!acksend(&conflict, &masteraddr, mastername,
572 "error on sending TSP_CONFLICT");
578 * based on the current network configuration, set the status, and count
587 nmasternets = nslavenets = nnets = nignorednets = 0;
589 fprintf(fd, "Net status:\n");
590 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
591 switch ((int)ntp->status) {
604 fprintf(fd, "\t%-16s", inet_ntoa(ntp->net));
605 switch ((int)ntp->status) {
607 fprintf(fd, "NOMASTER\n");
610 fprintf(fd, "MASTER\n");
613 fprintf(fd, "SLAVE\n");
616 fprintf(fd, "IGNORE\n");
619 fprintf(fd, "invalid state %d\n",
625 status |= ntp->status;
630 "\tnets=%d masters=%d slaves=%d ignored=%d delay2=%ld\n",
631 nnets, nmasternets, nslavenets, nignorednets, delay2);
638 register struct netinfo *ntp;
640 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
641 if (ntp->status == SLAVE && ntp != net)
642 ntp->status = IGNORE;
648 * Try to become master over ignored nets..
653 register struct netinfo *ntp;
655 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
656 if (!Mflag && ntp->status == SLAVE)
659 if (ntp->status == IGNORE || ntp->status == NOMASTER) {
661 if (!Mflag && ntp->status == SLAVE)
668 * choose a good network on which to be a slave
669 * The ignored networks must have already been checked.
670 * Take a hint about for a good network.
676 if (slavenet != 0 && slavenet->status == SLAVE) {
677 makeslave(slavenet); /* prune extras */
681 if (ntp == 0 || ntp->status != SLAVE) {
682 for (ntp = nettab; ntp != 0; ntp = ntp->next) {
683 if (ntp->status == SLAVE)
691 * returns a random number in the range [inf, sup]
699 value = ((double)(random() & 0x7fffffff)) / (0x7fffffff*1.0);
700 return(inf + (sup - inf)*value);
709 (void)gettimeofday(&tv, (struct timezone *)0);
711 return (ctime(&tv_sec));
718 register struct nets **netlist = &nets;
721 netlist = &((*netlist)->next);
722 *netlist = (struct nets *)malloc(sizeof **netlist);
724 errx(1, "malloc failed");
725 bzero((char *)*netlist, sizeof(**netlist));
726 (*netlist)->name = name;
729 /* note a host as trustworthy */
731 add_good_host(name, perm)
733 int perm; /* 1=not part of the netgroup */
735 register struct goodhost *ghp;
736 register struct hostent *hentp;
738 ghp = (struct goodhost*)malloc(sizeof(*ghp));
740 syslog(LOG_ERR, "malloc failed");
744 bzero((char*)ghp, sizeof(*ghp));
745 (void)strncpy(&ghp->name[0], name, sizeof(ghp->name));
746 ghp->next = goodhosts;
750 hentp = gethostbyname(name);
751 if (0 == hentp && perm)
752 warnx("unknown host %s", name);
756 /* update our image of the net-group of trustworthy hosts
762 # define NG_DELAY (30*60*CLK_TCK) /* 30 minutes */
763 static unsigned long last_update = -NG_DELAY;
764 unsigned long new_update;
765 struct goodhost *ghp, **ghpp;
768 char *mach, *usr, *dom;
773 /* if no netgroup, then we are finished */
774 if (goodgroup == 0 || !Mflag)
777 /* Do not chatter with the netgroup master too often.
779 new_update = times(&tm);
780 if (new_update < last_update + NG_DELAY
783 last_update = new_update;
785 /* forget the old temporary entries */
787 while (0 != (ghp = *ghpp)) {
797 /* quit now if we are not one of the trusted masters
799 if (!innetgr(goodgroup, &hostname[0], 0,0)) {
801 (void)fprintf(fd, "get_goodgroup: %s not in %s\n",
802 &hostname[0], goodgroup);
806 (void)fprintf(fd, "get_goodgroup: %s in %s\n",
807 &hostname[0], goodgroup);
809 /* mark the entire netgroup as trusted */
810 (void)setnetgrent(goodgroup);
811 while (getnetgrent(&mach,&usr,&dom)) {
813 add_good_host(mach,0);
817 /* update list of slaves */
818 for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
819 htp->good = good_host_name(&htp->name[0]);
825 /* see if a machine is trustworthy
827 int /* 1=trust hp to change our date */
831 register struct goodhost *ghp = goodhosts;
834 if (!ghp || !Mflag) /* trust everyone if no one named */
839 if (c == ghp->name[0]
840 && !strcasecmp(name, ghp->name))
841 return 1; /* found him, so say so */
842 } while (0 != (ghp = ghp->next));
844 if (!strcasecmp(name,hostname)) /* trust ourself */
847 return 0; /* did not find him */