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$");
48 #include <sys/ioctl.h>
50 #include "pathnames.h"
52 #include <sys/types.h>
53 #include <sys/times.h>
56 int sock, sock_raw = -1;
58 u_short sequence; /* sequence number */
62 int nslavenets; /* nets were I could be a slave */
63 int nmasternets; /* nets were I could be a master */
64 int nignorednets; /* ignored nets */
65 int nnets; /* nets I am connected to */
67 FILE *fd; /* trace file FD */
71 struct netinfo *nettab = 0;
72 struct netinfo *slavenet;
83 struct hosttbl hosttbl[NHOSTS+1]; /* known hosts */
85 static struct goodhost { /* hosts that we trust */
86 char name[MAXHOSTNAMELEN];
87 struct goodhost *next;
91 static char *goodgroup; /* net group of trusted hosts */
92 static void checkignorednets(void);
93 static void pickslavenet(struct netinfo *);
94 static void add_good_host(char *, int);
95 static void usage(void);
98 * The timedaemons synchronize the clocks of hosts in a local area network.
99 * One daemon runs as master, all the others as slaves. The master
100 * performs the task of computing clock differences and sends correction
101 * values to the slaves.
102 * Slaves start an election to choose a new master when the latter disappears
103 * because of a machine crash, network partition, or when killed.
104 * A resolution protocol is used to kill all but one of the masters
105 * that happen to exist in segments of a partitioned network when the
106 * network partition is fixed.
108 * Authors: Riccardo Gusella & Stefano Zatti
110 * overhauled at Silicon Graphics
113 main(int argc, char *argv[])
118 struct timeval ntime;
119 struct servent *srvp;
120 char buf[BUFSIZ], *cp, *cplim;
122 struct ifreq ifreq, ifreqf, *ifr;
123 register struct netinfo *ntp;
124 struct netinfo *ntip;
125 struct netinfo *savefromnet;
126 struct netent *nentp;
128 struct sockaddr_in server;
142 while ((c = getopt(argc, argv, "Mtdn:i:F:G:P:")) != -1) {
154 errx(1, "-i and -n make no sense together");
163 errx(1, "-i and -n make no sense together");
171 add_good_host(optarg,1);
172 while (optind < argc && argv[optind][0] != '-')
173 add_good_host(argv[optind++], 1);
181 errx(1, "only one net group");
193 /* If we care about which machine is the master, then we must
194 * be willing to be a master
196 if (0 != goodgroup || 0 != goodhosts)
199 if (gethostname(hostname, sizeof(hostname) - 1) < 0)
200 err(1, "gethostname");
208 if (goodhosts != 0) /* trust ourself */
209 add_good_host(hostname,1);
211 srvp = getservbyname("timed", "udp");
213 errx(1, "timed/udp: unknown service");
215 bzero(&server, sizeof(struct sockaddr_in));
216 server.sin_port = srvp->s_port;
217 server.sin_family = AF_INET;
218 sock = socket(AF_INET, SOCK_DGRAM, 0);
221 if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&on,
223 err(1, "setsockopt");
224 if (bind(sock, (struct sockaddr*)&server, sizeof(server))) {
225 if (errno == EADDRINUSE)
226 warnx("time daemon already running");
232 /* choose a unique seed for random number generation */
233 (void)gettimeofday(&ntime, NULL);
234 srandom(ntime.tv_sec + ntime.tv_usec);
236 sequence = random(); /* initial seq number */
238 /* rounds kernel variable time to multiple of 5 ms. */
240 ntime.tv_usec = -((ntime.tv_usec/1000) % 5) * 1000;
241 (void)adjtime(&ntime, (struct timeval *)0);
243 for (nt = nets; nt; nt = nt->next) {
244 nentp = getnetbyname(nt->name);
246 nt->net = inet_network(nt->name);
247 if (nt->net != INADDR_NONE)
248 nentp = getnetbyaddr(nt->net, AF_INET);
251 nt->net = nentp->n_net;
252 } else if (nt->net == INADDR_NONE) {
253 errx(1, "unknown net %s", nt->name);
254 } else if (nt->net == INADDR_ANY) {
255 errx(1, "bad net %s", nt->name);
257 warnx("warning: %s unknown in /etc/networks",
261 if (0 == (nt->net & 0xff000000))
263 if (0 == (nt->net & 0xff000000))
265 if (0 == (nt->net & 0xff000000))
268 ifc.ifc_len = sizeof(buf);
270 if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0)
271 err(1, "get interface configuration");
273 #define size(p) max((p).sa_len, sizeof(p))
274 cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */
275 for (cp = buf; cp < cplim;
276 cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) {
277 ifr = (struct ifreq *)cp;
278 if (ifr->ifr_addr.sa_family != AF_INET)
281 ntp = (struct netinfo*)malloc(sizeof(struct netinfo));
282 bzero(ntp,sizeof(*ntp));
283 ntp->my_addr=((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
284 ntp->status = NOMASTER;
288 if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreqf) < 0) {
289 warn("get interface flags");
292 if ((ifreqf.ifr_flags & IFF_UP) == 0)
294 if ((ifreqf.ifr_flags & IFF_BROADCAST) == 0 &&
295 (ifreqf.ifr_flags & IFF_POINTOPOINT) == 0) {
300 if (ioctl(sock, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
304 ntp->mask = ((struct sockaddr_in *)
305 &ifreq.ifr_addr)->sin_addr.s_addr;
307 if (ifreqf.ifr_flags & IFF_BROADCAST) {
308 if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
309 warn("get broadaddr");
312 ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_broadaddr;
313 /* What if the broadcast address is all ones?
314 * So we cannot just mask ntp->dest_addr. */
315 ntp->net = ntp->my_addr;
316 ntp->net.s_addr &= ntp->mask;
318 if (ioctl(sock, SIOCGIFDSTADDR,
319 (char *)&ifreq) < 0) {
320 warn("get destaddr");
323 ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_dstaddr;
324 ntp->net = ntp->dest_addr.sin_addr;
327 ntp->dest_addr.sin_port = port;
329 for (nt = nets; nt; nt = nt->next) {
330 if (ntp->net.s_addr == htonl(nt->net))
333 if ((nflag && !nt) || (iflag && nt))
337 if (nettab == NULL) {
346 (void) free((char *)ntp);
348 errx(1, "no network usable");
350 /* microseconds to delay before responding to a broadcast */
351 delay1 = casual(1, 100*1000);
353 /* election timer delay in secs. */
354 delay2 = casual(MINTOUT, MAXTOUT);
361 openlog("timed", LOG_CONS|LOG_PID, LOG_DAEMON);
364 * keep returning here
366 ret = setjmp(jmpenv);
367 savefromnet = fromnet;
378 /* Just lost our master */
380 slavenet->status = election(slavenet);
381 if (!slavenet || slavenet->status == MASTER) {
385 makeslave(slavenet); /* prune extras */
390 /* Just been told to quit */
392 pickslavenet(savefromnet);
397 if (!(status & MASTER) && sock_raw != -1) {
398 /* sock_raw is not being used now */
399 (void)close(sock_raw);
403 if (status == MASTER)
409 if (sock_raw != -1) {
410 (void)close(sock_raw);
415 /* we just lost our master or were told to quit */
418 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
419 if (ntp->status == MASTER) {
421 ntp->status = NOMASTER;
439 "usage: timed [-dtM] [-i net|-n net] [-F host1 host2 ...] [-G netgp]\n");
442 "usage: timed [-dtM] [-i net|-n net] [-F host1 host2 ...]\n");
448 * suppress an upstart, untrustworthy, self-appointed master
451 suppress(struct sockaddr_in *addr, char *name, struct netinfo *net)
453 struct sockaddr_in tgt;
454 char tname[MAXHOSTNAMELEN];
456 static struct timeval wait;
459 fprintf(fd, "suppress: %s\n", name);
461 (void)strcpy(tname, name);
463 while (0 != readmsg(TSP_ANY, ANYADDR, &wait, net)) {
465 fprintf(fd, "suppress:\tdiscarded packet from %s\n",
469 syslog(LOG_NOTICE, "suppressing false master %s", tname);
470 msg.tsp_type = TSP_QUIT;
471 (void)strcpy(msg.tsp_name, hostname);
472 (void)acksend(&msg, &tgt, tname, TSP_ACK, 0, 1);
476 lookformaster(struct netinfo *ntp)
478 struct tsp resp, conflict, *answer;
479 struct timeval ntime;
480 char mastername[MAXHOSTNAMELEN];
481 struct sockaddr_in masteraddr;
486 /* look for master */
487 resp.tsp_type = TSP_MASTERREQ;
488 (void)strcpy(resp.tsp_name, hostname);
489 answer = acksend(&resp, &ntp->dest_addr, ANYADDR,
490 TSP_MASTERACK, ntp, 0);
491 if (answer != 0 && !good_host_name(answer->tsp_name)) {
492 suppress(&from, answer->tsp_name, ntp);
493 ntp->status = NOMASTER;
498 * Various conditions can cause conflict: races between
499 * two just started timedaemons when no master is
500 * present, or timedaemons started during an election.
501 * A conservative approach is taken. Give up and became a
502 * slave, postponing election of a master until first
505 ntime.tv_sec = ntime.tv_usec = 0;
506 answer = readmsg(TSP_MASTERREQ, ANYADDR, &ntime, ntp);
508 if (!good_host_name(answer->tsp_name)) {
509 suppress(&from, answer->tsp_name, ntp);
510 ntp->status = NOMASTER;
515 ntime.tv_sec = ntime.tv_usec = 0;
516 answer = readmsg(TSP_MASTERUP, ANYADDR, &ntime, ntp);
518 if (!good_host_name(answer->tsp_name)) {
519 suppress(&from, answer->tsp_name, ntp);
520 ntp->status = NOMASTER;
525 ntime.tv_sec = ntime.tv_usec = 0;
526 answer = readmsg(TSP_ELECTION, ANYADDR, &ntime, ntp);
528 if (!good_host_name(answer->tsp_name)) {
529 suppress(&from, answer->tsp_name, ntp);
530 ntp->status = NOMASTER;
536 ntp->status = MASTER;
538 ntp->status = NOMASTER;
543 (void)strcpy(mastername, answer->tsp_name);
547 * If network has been partitioned, there might be other
548 * masters; tell the one we have just acknowledged that
549 * it has to gain control over the others.
552 ntime.tv_usec = 300000;
553 answer = readmsg(TSP_MASTERACK, ANYADDR, &ntime, ntp);
555 * checking also not to send CONFLICT to ack'ed master
556 * due to duplicated MASTERACKs
558 if (answer != NULL &&
559 strcmp(answer->tsp_name, mastername) != 0) {
560 conflict.tsp_type = TSP_CONFLICT;
561 (void)strcpy(conflict.tsp_name, hostname);
562 if (!acksend(&conflict, &masteraddr, mastername,
565 "error on sending TSP_CONFLICT");
571 * based on the current network configuration, set the status, and count
580 nmasternets = nslavenets = nnets = nignorednets = 0;
582 fprintf(fd, "Net status:\n");
583 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
584 switch ((int)ntp->status) {
597 fprintf(fd, "\t%-16s", inet_ntoa(ntp->net));
598 switch ((int)ntp->status) {
600 fprintf(fd, "NOMASTER\n");
603 fprintf(fd, "MASTER\n");
606 fprintf(fd, "SLAVE\n");
609 fprintf(fd, "IGNORE\n");
612 fprintf(fd, "invalid state %d\n",
618 status |= ntp->status;
623 "\tnets=%d masters=%d slaves=%d ignored=%d delay2=%ld\n",
624 nnets, nmasternets, nslavenets, nignorednets, delay2);
628 makeslave(struct netinfo *net)
630 register struct netinfo *ntp;
632 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
633 if (ntp->status == SLAVE && ntp != net)
634 ntp->status = IGNORE;
640 * Try to become master over ignored nets..
643 checkignorednets(void)
645 register struct netinfo *ntp;
647 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
648 if (!Mflag && ntp->status == SLAVE)
651 if (ntp->status == IGNORE || ntp->status == NOMASTER) {
653 if (!Mflag && ntp->status == SLAVE)
660 * choose a good network on which to be a slave
661 * The ignored networks must have already been checked.
662 * Take a hint about for a good network.
665 pickslavenet(struct netinfo *ntp)
667 if (slavenet != 0 && slavenet->status == SLAVE) {
668 makeslave(slavenet); /* prune extras */
672 if (ntp == 0 || ntp->status != SLAVE) {
673 for (ntp = nettab; ntp != 0; ntp = ntp->next) {
674 if (ntp->status == SLAVE)
682 * returns a random number in the range [inf, sup]
685 casual(long inf, long sup)
689 value = ((double)(random() & 0x7fffffff)) / (0x7fffffff*1.0);
690 return(inf + (sup - inf)*value);
699 return (ctime(&tv_sec));
703 addnetname(char *name)
705 register struct nets **netlist = &nets;
708 netlist = &((*netlist)->next);
709 *netlist = (struct nets *)malloc(sizeof **netlist);
711 errx(1, "malloc failed");
712 bzero((char *)*netlist, sizeof(**netlist));
713 (*netlist)->name = name;
716 /* note a host as trustworthy
717 * perm 1=not part of the netgroup
720 add_good_host(char *name, int perm)
722 register struct goodhost *ghp;
723 register struct hostent *hentp;
725 ghp = (struct goodhost*)malloc(sizeof(*ghp));
727 syslog(LOG_ERR, "malloc failed");
731 bzero((char*)ghp, sizeof(*ghp));
732 (void)strncpy(&ghp->name[0], name, sizeof(ghp->name));
733 ghp->next = goodhosts;
737 hentp = gethostbyname(name);
738 if (0 == hentp && perm)
739 warnx("unknown host %s", name);
743 /* update our image of the net-group of trustworthy hosts
746 get_goodgroup(int force)
748 # define NG_DELAY (30*60*CLK_TCK) /* 30 minutes */
749 static unsigned long last_update = -NG_DELAY;
750 unsigned long new_update;
751 struct goodhost *ghp, **ghpp;
754 char *mach, *usr, *dom;
759 /* if no netgroup, then we are finished */
760 if (goodgroup == 0 || !Mflag)
763 /* Do not chatter with the netgroup master too often.
765 new_update = times(&tm);
766 if (new_update < last_update + NG_DELAY
769 last_update = new_update;
771 /* forget the old temporary entries */
773 while (0 != (ghp = *ghpp)) {
783 /* quit now if we are not one of the trusted masters
785 if (!innetgr(goodgroup, &hostname[0], 0,0)) {
787 (void)fprintf(fd, "get_goodgroup: %s not in %s\n",
788 &hostname[0], goodgroup);
792 (void)fprintf(fd, "get_goodgroup: %s in %s\n",
793 &hostname[0], goodgroup);
795 /* mark the entire netgroup as trusted */
796 (void)setnetgrent(goodgroup);
797 while (getnetgrent(&mach,&usr,&dom)) {
799 add_good_host(mach,0);
803 /* update list of slaves */
804 for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
805 htp->good = good_host_name(&htp->name[0]);
811 /* see if a machine is trustworthy
813 int /* 1=trust hp to change our date */
814 good_host_name(char *name)
816 register struct goodhost *ghp = goodhosts;
819 if (!ghp || !Mflag) /* trust everyone if no one named */
824 if (c == ghp->name[0]
825 && !strcasecmp(name, ghp->name))
826 return 1; /* found him, so say so */
827 } while (0 != (ghp = ghp->next));
829 if (!strcasecmp(name,hostname)) /* trust ourself */
832 return 0; /* did not find him */