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 * 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.
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
33 * @(#) Copyright (c) 1985, 1993 The Regents of the University of California. All rights reserved.
34 * @(#)timed.c 8.1 (Berkeley) 6/6/93
35 * $FreeBSD: src/usr.sbin/timed/timed/timed.c,v 1.9 1999/08/28 01:20:19 peter Exp $
42 #include <sys/ioctl.h>
44 #include "pathnames.h"
46 #include <sys/types.h>
47 #include <sys/times.h>
50 int sock, sock_raw = -1;
52 u_short sequence; /* sequence number */
56 int nslavenets; /* nets were I could be a slave */
57 int nmasternets; /* nets were I could be a master */
58 int nignorednets; /* ignored nets */
59 int nnets; /* nets I am connected to */
61 FILE *fd; /* trace file FD */
65 struct netinfo *nettab = NULL;
66 struct netinfo *slavenet;
77 struct hosttbl hosttbl[NHOSTS+1]; /* known hosts */
79 static struct goodhost { /* hosts that we trust */
80 char name[MAXHOSTNAMELEN];
81 struct goodhost *next;
85 static char *goodgroup; /* net group of trusted hosts */
86 static void checkignorednets(void);
87 static void pickslavenet(struct netinfo *);
88 static void add_good_host(char *, int);
89 static void usage(void);
92 * The timedaemons synchronize the clocks of hosts in a local area network.
93 * One daemon runs as master, all the others as slaves. The master
94 * performs the task of computing clock differences and sends correction
95 * values to the slaves.
96 * Slaves start an election to choose a new master when the latter disappears
97 * because of a machine crash, network partition, or when killed.
98 * A resolution protocol is used to kill all but one of the masters
99 * that happen to exist in segments of a partitioned network when the
100 * network partition is fixed.
102 * Authors: Riccardo Gusella & Stefano Zatti
104 * overhauled at Silicon Graphics
107 main(int argc, char *argv[])
112 struct timeval ntime;
113 struct servent *srvp;
114 char buf[BUFSIZ], *cp, *cplim;
116 struct ifreq ifreq, ifreqf, *ifr;
118 struct netinfo *ntip;
119 struct netinfo *savefromnet;
120 struct netent *nentp;
122 struct sockaddr_in server;
132 while ((c = getopt(argc, argv, "Mtdn:i:F:G:P:")) != -1) {
144 errx(1, "-i and -n make no sense together");
153 errx(1, "-i and -n make no sense together");
161 add_good_host(optarg,1);
162 while (optind < argc && argv[optind][0] != '-')
163 add_good_host(argv[optind++], 1);
170 if (goodgroup != NULL)
171 errx(1, "only one net group");
182 /* If we care about which machine is the master, then we must
183 * be willing to be a master
185 if (NULL != goodgroup || NULL != goodhosts)
188 if (gethostname(hostname, sizeof(hostname) - 1) < 0)
189 err(1, "gethostname");
197 if (goodhosts != NULL) /* trust ourself */
198 add_good_host(hostname,1);
200 srvp = getservbyname("timed", "udp");
202 errx(1, "unknown service 'timed/udp'");
204 bzero(&server, sizeof(struct sockaddr_in));
205 server.sin_port = srvp->s_port;
206 server.sin_family = AF_INET;
207 sock = socket(AF_INET, SOCK_DGRAM, 0);
210 if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&on,
212 err(1, "setsockopt");
213 if (bind(sock, (struct sockaddr*)&server, sizeof(server))) {
214 if (errno == EADDRINUSE)
215 warnx("time daemon already running");
221 /* choose a unique seed for random number generation */
222 gettimeofday(&ntime, 0);
223 srandom(ntime.tv_sec + ntime.tv_usec);
225 sequence = random(); /* initial seq number */
227 /* rounds kernel variable time to multiple of 5 ms. */
229 ntime.tv_usec = -((ntime.tv_usec/1000) % 5) * 1000;
230 adjtime(&ntime, NULL);
232 for (nt = nets; nt; nt = nt->next) {
233 nentp = getnetbyname(nt->name);
235 nt->net = inet_network(nt->name);
236 if (nt->net != (long)INADDR_NONE)
237 nentp = getnetbyaddr(nt->net, AF_INET);
240 nt->net = nentp->n_net;
241 } else if (nt->net == (long)INADDR_NONE) {
242 errx(1, "unknown net %s", nt->name);
243 } else if (nt->net == (long)INADDR_ANY) {
244 errx(1, "bad net %s", nt->name);
246 warnx("warning: %s unknown in /etc/networks",
250 if (0 == (nt->net & 0xff000000))
252 if (0 == (nt->net & 0xff000000))
254 if (0 == (nt->net & 0xff000000))
257 ifc.ifc_len = sizeof(buf);
259 if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0)
260 err(1, "get interface configuration");
263 #define size(p) max((p).sa_len, sizeof(p))
264 cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */
265 for (cp = buf; cp < cplim;
266 cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) {
267 ifr = (struct ifreq *)cp;
268 if (ifr->ifr_addr.sa_family != AF_INET)
271 ntp = (struct netinfo*)malloc(sizeof(struct netinfo));
272 bzero(ntp,sizeof(*ntp));
273 ntp->my_addr=((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
274 ntp->status = NOMASTER;
278 if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreqf) < 0) {
279 warn("get interface flags");
282 if ((ifreqf.ifr_flags & IFF_UP) == 0)
284 if ((ifreqf.ifr_flags & IFF_BROADCAST) == 0 &&
285 (ifreqf.ifr_flags & IFF_POINTOPOINT) == 0) {
290 if (ioctl(sock, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
294 ntp->mask = ((struct sockaddr_in *)
295 &ifreq.ifr_addr)->sin_addr.s_addr;
297 if (ifreqf.ifr_flags & IFF_BROADCAST) {
298 if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
299 warn("get broadaddr");
302 ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_broadaddr;
303 /* What if the broadcast address is all ones?
304 * So we cannot just mask ntp->dest_addr. */
305 ntp->net = ntp->my_addr;
306 ntp->net.s_addr &= ntp->mask;
308 if (ioctl(sock, SIOCGIFDSTADDR,
309 (char *)&ifreq) < 0) {
310 warn("get destaddr");
313 ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_dstaddr;
314 ntp->net = ntp->dest_addr.sin_addr;
317 ntp->dest_addr.sin_port = port;
319 for (nt = nets; nt; nt = nt->next) {
320 if (ntp->net.s_addr == htonl(nt->net))
323 if ((nflag && !nt) || (iflag && nt))
327 if (nettab == NULL) {
338 errx(1, "no network usable");
341 /* microseconds to delay before responding to a broadcast */
342 delay1 = casual(1, 100*1000);
344 /* election timer delay in secs. */
345 delay2 = casual(MINTOUT, MAXTOUT);
353 openlog("timed", LOG_CONS|LOG_PID, LOG_DAEMON);
356 * keep returning here
358 ret = setjmp(jmpenv);
359 savefromnet = fromnet;
370 /* Just lost our master */
371 if (slavenet != NULL)
372 slavenet->status = election(slavenet);
373 if (!slavenet || slavenet->status == MASTER) {
377 makeslave(slavenet); /* prune extras */
382 /* Just been told to quit */
384 pickslavenet(savefromnet);
389 if (!(status & MASTER) && sock_raw != -1) {
390 /* sock_raw is not being used now */
395 if (status == MASTER)
401 if (sock_raw != -1) {
407 /* we just lost our master or were told to quit */
410 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
411 if (ntp->status == MASTER)
413 ntp->status = NOMASTER;
431 "usage: timed [-dtM] [-i net|-n net] [-F host1 host2 ...] [-G netgp]\n");
434 "usage: timed [-dtM] [-i net|-n net] [-F host1 host2 ...]\n");
440 * suppress an upstart, untrustworthy, self-appointed master
443 suppress(struct sockaddr_in *addr, char *name, struct netinfo *net)
445 struct sockaddr_in tgt;
446 char tname[MAXHOSTNAMELEN];
448 static struct timeval wait;
451 fprintf(fd, "suppress: %s\n", name);
453 strlcpy(tname, name, sizeof(tname));
455 while (0 != readmsg(TSP_ANY, ANYADDR, &wait, net)) {
457 fprintf(fd, "suppress:\tdiscarded packet from %s\n",
461 syslog(LOG_NOTICE, "suppressing false master %s", tname);
462 msg.tsp_type = TSP_QUIT;
463 strlcpy(msg.tsp_name, hostname, sizeof(msg.tsp_name));
464 acksend(&msg, &tgt, tname, TSP_ACK, 0, 1);
468 lookformaster(struct netinfo *ntp)
470 struct tsp resp, conflict, *answer;
471 struct timeval ntime;
472 char mastername[MAXHOSTNAMELEN];
473 struct sockaddr_in masteraddr;
478 /* look for master */
479 resp.tsp_type = TSP_MASTERREQ;
480 strlcpy(resp.tsp_name, hostname, sizeof(resp.tsp_name));
481 answer = acksend(&resp, &ntp->dest_addr, ANYADDR,
482 TSP_MASTERACK, ntp, 0);
483 if (answer != NULL && !good_host_name(answer->tsp_name)) {
484 suppress(&from, answer->tsp_name, ntp);
485 ntp->status = NOMASTER;
488 if (answer == NULL) {
490 * Various conditions can cause conflict: races between
491 * two just started timedaemons when no master is
492 * present, or timedaemons started during an election.
493 * A conservative approach is taken. Give up and became a
494 * slave, postponing election of a master until first
497 ntime.tv_sec = ntime.tv_usec = 0;
498 answer = readmsg(TSP_MASTERREQ, ANYADDR, &ntime, ntp);
499 if (answer != NULL) {
500 if (!good_host_name(answer->tsp_name)) {
501 suppress(&from, answer->tsp_name, ntp);
502 ntp->status = NOMASTER;
507 ntime.tv_sec = ntime.tv_usec = 0;
508 answer = readmsg(TSP_MASTERUP, ANYADDR, &ntime, ntp);
509 if (answer != NULL) {
510 if (!good_host_name(answer->tsp_name)) {
511 suppress(&from, answer->tsp_name, ntp);
512 ntp->status = NOMASTER;
517 ntime.tv_sec = ntime.tv_usec = 0;
518 answer = readmsg(TSP_ELECTION, ANYADDR, &ntime, ntp);
519 if (answer != NULL) {
520 if (!good_host_name(answer->tsp_name)) {
521 suppress(&from, answer->tsp_name, ntp);
522 ntp->status = NOMASTER;
528 ntp->status = MASTER;
530 ntp->status = NOMASTER;
535 strlcpy(mastername, answer->tsp_name, sizeof(mastername));
539 * If network has been partitioned, there might be other
540 * masters; tell the one we have just acknowledged that
541 * it has to gain control over the others.
544 ntime.tv_usec = 300000;
545 answer = readmsg(TSP_MASTERACK, ANYADDR, &ntime, ntp);
547 * checking also not to send CONFLICT to ack'ed master
548 * due to duplicated MASTERACKs
550 if (answer != NULL &&
551 strcmp(answer->tsp_name, mastername) != 0) {
552 conflict.tsp_type = TSP_CONFLICT;
553 strlcpy(conflict.tsp_name, hostname, sizeof(conflict.tsp_name));
554 if (!acksend(&conflict, &masteraddr, mastername,
557 "error on sending TSP_CONFLICT");
563 * based on the current network configuration, set the status, and count
572 nmasternets = nslavenets = nnets = nignorednets = 0;
574 fprintf(fd, "Net status:\n");
575 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
576 switch ((int)ntp->status) {
589 fprintf(fd, "\t%-16s", inet_ntoa(ntp->net));
590 switch ((int)ntp->status) {
592 fprintf(fd, "NOMASTER\n");
595 fprintf(fd, "MASTER\n");
598 fprintf(fd, "SLAVE\n");
601 fprintf(fd, "IGNORE\n");
604 fprintf(fd, "invalid state %d\n",
610 status |= ntp->status;
615 "\tnets=%d masters=%d slaves=%d ignored=%d delay2=%ld\n",
616 nnets, nmasternets, nslavenets, nignorednets, delay2);
620 makeslave(struct netinfo *net)
624 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
625 if (ntp->status == SLAVE && ntp != net)
626 ntp->status = IGNORE;
632 * Try to become master over ignored nets..
635 checkignorednets(void)
639 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
640 if (!Mflag && ntp->status == SLAVE)
643 if (ntp->status == IGNORE || ntp->status == NOMASTER) {
645 if (!Mflag && ntp->status == SLAVE)
652 * choose a good network on which to be a slave
653 * The ignored networks must have already been checked.
654 * Take a hint about for a good network.
657 pickslavenet(struct netinfo *ntp)
660 if (slavenet != NULL && slavenet->status == SLAVE) {
661 makeslave(slavenet); /* prune extras */
665 if (ntp == NULL || ntp->status != SLAVE) {
666 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
667 if (ntp->status == SLAVE)
675 * returns a random number in the range [inf, sup]
678 casual(long inf, long sup)
682 value = ((double)(random() & 0x7fffffff)) / (0x7fffffff*1.0);
683 return(inf + (sup - inf)*value);
692 gettimeofday(&tv, NULL);
694 return (ctime(&tv_sec));
698 addnetname(char *name)
700 struct nets **netlist = &nets;
703 netlist = &((*netlist)->next);
704 *netlist = (struct nets *)malloc(sizeof **netlist);
705 if (*netlist == NULL)
706 errx(1, "malloc failed");
707 bzero((char *)*netlist, sizeof(**netlist));
708 (*netlist)->name = name;
711 /* note a host as trustworthy */
713 add_good_host(char *name,
714 int perm) /* 1=not part of the netgroup */
716 struct goodhost *ghp;
717 struct hostent *hentp;
719 ghp = (struct goodhost*)malloc(sizeof(*ghp));
721 syslog(LOG_ERR, "malloc failed");
725 bzero((char*)ghp, sizeof(*ghp));
726 strlcpy(&ghp->name[0], name, sizeof(ghp->name));
727 ghp->next = goodhosts;
731 hentp = gethostbyname(name);
732 if (NULL == hentp && perm)
733 warnx("unknown host %s", name);
737 /* update our image of the net-group of trustworthy hosts
740 get_goodgroup(int force)
742 # define NG_DELAY (30*60*CLK_TCK) /* 30 minutes */
743 static unsigned long last_update = -NG_DELAY;
744 unsigned long new_update;
745 struct goodhost *ghp, **ghpp;
748 char *mach, *usr, *dom;
753 /* if no netgroup, then we are finished */
754 if (goodgroup == NULL || !Mflag)
757 /* Do not chatter with the netgroup master too often.
759 new_update = times(&tm);
760 if (new_update < last_update + NG_DELAY
763 last_update = new_update;
765 /* forget the old temporary entries */
767 while (NULL != (ghp = *ghpp)) {
777 /* quit now if we are not one of the trusted masters
779 if (!innetgr(goodgroup, &hostname[0], 0,0)) {
781 fprintf(fd, "get_goodgroup: %s not in %s\n",
782 &hostname[0], goodgroup);
786 fprintf(fd, "get_goodgroup: %s in %s\n",
787 &hostname[0], goodgroup);
789 /* mark the entire netgroup as trusted */
790 setnetgrent(goodgroup);
791 while (getnetgrent(&mach,&usr,&dom)) {
793 add_good_host(mach,0);
797 /* update list of slaves */
798 for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
799 htp->good = good_host_name(&htp->name[0]);
805 /* see if a machine is trustworthy
807 int /* 1=trust hp to change our date */
808 good_host_name(char *name)
810 struct goodhost *ghp = goodhosts;
813 if (!ghp || !Mflag) /* trust everyone if no one named */
818 if (c == ghp->name[0]
819 && !strcasecmp(name, ghp->name))
820 return 1; /* found him, so say so */
821 } while (NULL != (ghp = ghp->next));
823 if (!strcasecmp(name,hostname)) /* trust ourself */
826 return 0; /* did not find him */