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 $
36 * $DragonFly: src/usr.sbin/timed/timed/timed.c,v 1.8 2004/09/05 02:20:15 dillon Exp $
43 #include <sys/ioctl.h>
45 #include "pathnames.h"
47 #include <sys/types.h>
48 #include <sys/times.h>
51 int sock
, sock_raw
= -1;
53 u_short sequence
; /* sequence number */
57 int nslavenets
; /* nets were I could be a slave */
58 int nmasternets
; /* nets were I could be a master */
59 int nignorednets
; /* ignored nets */
60 int nnets
; /* nets I am connected to */
62 FILE *fd
; /* trace file FD */
66 struct netinfo
*nettab
= 0;
67 struct netinfo
*slavenet
;
78 struct hosttbl hosttbl
[NHOSTS
+1]; /* known hosts */
80 static struct goodhost
{ /* hosts that we trust */
81 char name
[MAXHOSTNAMELEN
];
82 struct goodhost
*next
;
86 static char *goodgroup
; /* net group of trusted hosts */
87 static void checkignorednets(void);
88 static void pickslavenet(struct netinfo
*);
89 static void add_good_host(char *, int);
90 static void usage(void);
93 * The timedaemons synchronize the clocks of hosts in a local area network.
94 * One daemon runs as master, all the others as slaves. The master
95 * performs the task of computing clock differences and sends correction
96 * values to the slaves.
97 * Slaves start an election to choose a new master when the latter disappears
98 * because of a machine crash, network partition, or when killed.
99 * A resolution protocol is used to kill all but one of the masters
100 * that happen to exist in segments of a partitioned network when the
101 * network partition is fixed.
103 * Authors: Riccardo Gusella & Stefano Zatti
105 * overhauled at Silicon Graphics
108 main(int argc
, char *argv
[])
113 struct timeval ntime
;
114 struct servent
*srvp
;
115 char buf
[BUFSIZ
], *cp
, *cplim
;
117 struct ifreq ifreq
, ifreqf
, *ifr
;
119 struct netinfo
*ntip
;
120 struct netinfo
*savefromnet
;
121 struct netent
*nentp
;
123 struct sockaddr_in server
;
133 while ((c
= getopt(argc
, argv
, "Mtdn:i:F:G:P:")) != -1) {
145 errx(1, "-i and -n make no sense together");
154 errx(1, "-i and -n make no sense together");
162 add_good_host(optarg
,1);
163 while (optind
< argc
&& argv
[optind
][0] != '-')
164 add_good_host(argv
[optind
++], 1);
172 errx(1, "only one net group");
183 /* If we care about which machine is the master, then we must
184 * be willing to be a master
186 if (0 != goodgroup
|| 0 != goodhosts
)
189 if (gethostname(hostname
, sizeof(hostname
) - 1) < 0)
190 err(1, "gethostname");
198 if (goodhosts
!= 0) /* trust ourself */
199 add_good_host(hostname
,1);
201 srvp
= getservbyname("timed", "udp");
203 errx(1, "unknown service 'timed/udp'");
205 bzero(&server
, sizeof(struct sockaddr_in
));
206 server
.sin_port
= srvp
->s_port
;
207 server
.sin_family
= AF_INET
;
208 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
211 if (setsockopt(sock
, SOL_SOCKET
, SO_BROADCAST
, (char *)&on
,
213 err(1, "setsockopt");
214 if (bind(sock
, (struct sockaddr
*)&server
, sizeof(server
))) {
215 if (errno
== EADDRINUSE
)
216 warnx("time daemon already running");
222 /* choose a unique seed for random number generation */
223 gettimeofday(&ntime
, 0);
224 srandom(ntime
.tv_sec
+ ntime
.tv_usec
);
226 sequence
= random(); /* initial seq number */
228 /* rounds kernel variable time to multiple of 5 ms. */
230 ntime
.tv_usec
= -((ntime
.tv_usec
/1000) % 5) * 1000;
231 adjtime(&ntime
, NULL
);
233 for (nt
= nets
; nt
; nt
= nt
->next
) {
234 nentp
= getnetbyname(nt
->name
);
236 nt
->net
= inet_network(nt
->name
);
237 if (nt
->net
!= (long)INADDR_NONE
)
238 nentp
= getnetbyaddr(nt
->net
, AF_INET
);
241 nt
->net
= nentp
->n_net
;
242 } else if (nt
->net
== (long)INADDR_NONE
) {
243 errx(1, "unknown net %s", nt
->name
);
244 } else if (nt
->net
== (long)INADDR_ANY
) {
245 errx(1, "bad net %s", nt
->name
);
247 warnx("warning: %s unknown in /etc/networks",
251 if (0 == (nt
->net
& 0xff000000))
253 if (0 == (nt
->net
& 0xff000000))
255 if (0 == (nt
->net
& 0xff000000))
258 ifc
.ifc_len
= sizeof(buf
);
260 if (ioctl(sock
, SIOCGIFCONF
, (char *)&ifc
) < 0)
261 err(1, "get interface configuration");
264 #define size(p) max((p).sa_len, sizeof(p))
265 cplim
= buf
+ ifc
.ifc_len
; /*skip over if's with big ifr_addr's */
266 for (cp
= buf
; cp
< cplim
;
267 cp
+= sizeof (ifr
->ifr_name
) + size(ifr
->ifr_addr
)) {
268 ifr
= (struct ifreq
*)cp
;
269 if (ifr
->ifr_addr
.sa_family
!= AF_INET
)
272 ntp
= (struct netinfo
*)malloc(sizeof(struct netinfo
));
273 bzero(ntp
,sizeof(*ntp
));
274 ntp
->my_addr
=((struct sockaddr_in
*)&ifr
->ifr_addr
)->sin_addr
;
275 ntp
->status
= NOMASTER
;
279 if (ioctl(sock
, SIOCGIFFLAGS
, (char *)&ifreqf
) < 0) {
280 warn("get interface flags");
283 if ((ifreqf
.ifr_flags
& IFF_UP
) == 0)
285 if ((ifreqf
.ifr_flags
& IFF_BROADCAST
) == 0 &&
286 (ifreqf
.ifr_flags
& IFF_POINTOPOINT
) == 0) {
291 if (ioctl(sock
, SIOCGIFNETMASK
, (char *)&ifreq
) < 0) {
295 ntp
->mask
= ((struct sockaddr_in
*)
296 &ifreq
.ifr_addr
)->sin_addr
.s_addr
;
298 if (ifreqf
.ifr_flags
& IFF_BROADCAST
) {
299 if (ioctl(sock
, SIOCGIFBRDADDR
, (char *)&ifreq
) < 0) {
300 warn("get broadaddr");
303 ntp
->dest_addr
= *(struct sockaddr_in
*)&ifreq
.ifr_broadaddr
;
304 /* What if the broadcast address is all ones?
305 * So we cannot just mask ntp->dest_addr. */
306 ntp
->net
= ntp
->my_addr
;
307 ntp
->net
.s_addr
&= ntp
->mask
;
309 if (ioctl(sock
, SIOCGIFDSTADDR
,
310 (char *)&ifreq
) < 0) {
311 warn("get destaddr");
314 ntp
->dest_addr
= *(struct sockaddr_in
*)&ifreq
.ifr_dstaddr
;
315 ntp
->net
= ntp
->dest_addr
.sin_addr
;
318 ntp
->dest_addr
.sin_port
= port
;
320 for (nt
= nets
; nt
; nt
= nt
->next
) {
321 if (ntp
->net
.s_addr
== htonl(nt
->net
))
324 if ((nflag
&& !nt
) || (iflag
&& nt
))
328 if (nettab
== NULL
) {
339 errx(1, "no network usable");
342 /* microseconds to delay before responding to a broadcast */
343 delay1
= casual(1, 100*1000);
345 /* election timer delay in secs. */
346 delay2
= casual(MINTOUT
, MAXTOUT
);
354 openlog("timed", LOG_CONS
|LOG_PID
, LOG_DAEMON
);
357 * keep returning here
359 ret
= setjmp(jmpenv
);
360 savefromnet
= fromnet
;
371 /* Just lost our master */
373 slavenet
->status
= election(slavenet
);
374 if (!slavenet
|| slavenet
->status
== MASTER
) {
378 makeslave(slavenet
); /* prune extras */
383 /* Just been told to quit */
385 pickslavenet(savefromnet
);
390 if (!(status
& MASTER
) && sock_raw
!= -1) {
391 /* sock_raw is not being used now */
396 if (status
== MASTER
)
402 if (sock_raw
!= -1) {
408 /* we just lost our master or were told to quit */
411 for (ntp
= nettab
; ntp
!= NULL
; ntp
= ntp
->next
) {
412 if (ntp
->status
== MASTER
)
414 ntp
->status
= NOMASTER
;
432 "usage: timed [-dtM] [-i net|-n net] [-F host1 host2 ...] [-G netgp]\n");
435 "usage: timed [-dtM] [-i net|-n net] [-F host1 host2 ...]\n");
441 * suppress an upstart, untrustworthy, self-appointed master
444 suppress(struct sockaddr_in
*addr
, char *name
, struct netinfo
*net
)
446 struct sockaddr_in tgt
;
447 char tname
[MAXHOSTNAMELEN
];
449 static struct timeval wait
;
452 fprintf(fd
, "suppress: %s\n", name
);
454 strlcpy(tname
, name
, sizeof(tname
));
456 while (0 != readmsg(TSP_ANY
, ANYADDR
, &wait
, net
)) {
458 fprintf(fd
, "suppress:\tdiscarded packet from %s\n",
462 syslog(LOG_NOTICE
, "suppressing false master %s", tname
);
463 msg
.tsp_type
= TSP_QUIT
;
464 strlcpy(msg
.tsp_name
, hostname
, sizeof(msg
.tsp_name
));
465 acksend(&msg
, &tgt
, tname
, TSP_ACK
, 0, 1);
469 lookformaster(struct netinfo
*ntp
)
471 struct tsp resp
, conflict
, *answer
;
472 struct timeval ntime
;
473 char mastername
[MAXHOSTNAMELEN
];
474 struct sockaddr_in masteraddr
;
479 /* look for master */
480 resp
.tsp_type
= TSP_MASTERREQ
;
481 strlcpy(resp
.tsp_name
, hostname
, sizeof(resp
.tsp_name
));
482 answer
= acksend(&resp
, &ntp
->dest_addr
, ANYADDR
,
483 TSP_MASTERACK
, ntp
, 0);
484 if (answer
!= 0 && !good_host_name(answer
->tsp_name
)) {
485 suppress(&from
, answer
->tsp_name
, ntp
);
486 ntp
->status
= NOMASTER
;
491 * Various conditions can cause conflict: races between
492 * two just started timedaemons when no master is
493 * present, or timedaemons started during an election.
494 * A conservative approach is taken. Give up and became a
495 * slave, postponing election of a master until first
498 ntime
.tv_sec
= ntime
.tv_usec
= 0;
499 answer
= readmsg(TSP_MASTERREQ
, ANYADDR
, &ntime
, ntp
);
501 if (!good_host_name(answer
->tsp_name
)) {
502 suppress(&from
, answer
->tsp_name
, ntp
);
503 ntp
->status
= NOMASTER
;
508 ntime
.tv_sec
= ntime
.tv_usec
= 0;
509 answer
= readmsg(TSP_MASTERUP
, ANYADDR
, &ntime
, ntp
);
511 if (!good_host_name(answer
->tsp_name
)) {
512 suppress(&from
, answer
->tsp_name
, ntp
);
513 ntp
->status
= NOMASTER
;
518 ntime
.tv_sec
= ntime
.tv_usec
= 0;
519 answer
= readmsg(TSP_ELECTION
, ANYADDR
, &ntime
, ntp
);
521 if (!good_host_name(answer
->tsp_name
)) {
522 suppress(&from
, answer
->tsp_name
, ntp
);
523 ntp
->status
= NOMASTER
;
529 ntp
->status
= MASTER
;
531 ntp
->status
= NOMASTER
;
536 strlcpy(mastername
, answer
->tsp_name
, sizeof(mastername
));
540 * If network has been partitioned, there might be other
541 * masters; tell the one we have just acknowledged that
542 * it has to gain control over the others.
545 ntime
.tv_usec
= 300000;
546 answer
= readmsg(TSP_MASTERACK
, ANYADDR
, &ntime
, ntp
);
548 * checking also not to send CONFLICT to ack'ed master
549 * due to duplicated MASTERACKs
551 if (answer
!= NULL
&&
552 strcmp(answer
->tsp_name
, mastername
) != 0) {
553 conflict
.tsp_type
= TSP_CONFLICT
;
554 strlcpy(conflict
.tsp_name
, hostname
, sizeof(conflict
.tsp_name
));
555 if (!acksend(&conflict
, &masteraddr
, mastername
,
558 "error on sending TSP_CONFLICT");
564 * based on the current network configuration, set the status, and count
573 nmasternets
= nslavenets
= nnets
= nignorednets
= 0;
575 fprintf(fd
, "Net status:\n");
576 for (ntp
= nettab
; ntp
!= NULL
; ntp
= ntp
->next
) {
577 switch ((int)ntp
->status
) {
590 fprintf(fd
, "\t%-16s", inet_ntoa(ntp
->net
));
591 switch ((int)ntp
->status
) {
593 fprintf(fd
, "NOMASTER\n");
596 fprintf(fd
, "MASTER\n");
599 fprintf(fd
, "SLAVE\n");
602 fprintf(fd
, "IGNORE\n");
605 fprintf(fd
, "invalid state %d\n",
611 status
|= ntp
->status
;
616 "\tnets=%d masters=%d slaves=%d ignored=%d delay2=%ld\n",
617 nnets
, nmasternets
, nslavenets
, nignorednets
, delay2
);
621 makeslave(struct netinfo
*net
)
625 for (ntp
= nettab
; ntp
!= NULL
; ntp
= ntp
->next
) {
626 if (ntp
->status
== SLAVE
&& ntp
!= net
)
627 ntp
->status
= IGNORE
;
633 * Try to become master over ignored nets..
636 checkignorednets(void)
640 for (ntp
= nettab
; ntp
!= NULL
; ntp
= ntp
->next
) {
641 if (!Mflag
&& ntp
->status
== SLAVE
)
644 if (ntp
->status
== IGNORE
|| ntp
->status
== NOMASTER
) {
646 if (!Mflag
&& ntp
->status
== SLAVE
)
653 * choose a good network on which to be a slave
654 * The ignored networks must have already been checked.
655 * Take a hint about for a good network.
658 pickslavenet(struct netinfo
*ntp
)
661 if (slavenet
!= 0 && slavenet
->status
== SLAVE
) {
662 makeslave(slavenet
); /* prune extras */
666 if (ntp
== 0 || ntp
->status
!= SLAVE
) {
667 for (ntp
= nettab
; ntp
!= 0; ntp
= ntp
->next
) {
668 if (ntp
->status
== SLAVE
)
676 * returns a random number in the range [inf, sup]
679 casual(long inf
, long sup
)
683 value
= ((double)(random() & 0x7fffffff)) / (0x7fffffff*1.0);
684 return(inf
+ (sup
- inf
)*value
);
693 gettimeofday(&tv
, NULL
);
695 return (ctime(&tv_sec
));
699 addnetname(char *name
)
701 struct nets
**netlist
= &nets
;
704 netlist
= &((*netlist
)->next
);
705 *netlist
= (struct nets
*)malloc(sizeof **netlist
);
707 errx(1, "malloc failed");
708 bzero((char *)*netlist
, sizeof(**netlist
));
709 (*netlist
)->name
= name
;
712 /* note a host as trustworthy */
714 add_good_host(char *name
,
715 int perm
) /* 1=not part of the netgroup */
717 struct goodhost
*ghp
;
718 struct hostent
*hentp
;
720 ghp
= (struct goodhost
*)malloc(sizeof(*ghp
));
722 syslog(LOG_ERR
, "malloc failed");
726 bzero((char*)ghp
, sizeof(*ghp
));
727 strlcpy(&ghp
->name
[0], name
, sizeof(ghp
->name
));
728 ghp
->next
= goodhosts
;
732 hentp
= gethostbyname(name
);
733 if (0 == hentp
&& perm
)
734 warnx("unknown host %s", name
);
738 /* update our image of the net-group of trustworthy hosts
741 get_goodgroup(int force
)
743 # define NG_DELAY (30*60*CLK_TCK) /* 30 minutes */
744 static unsigned long last_update
= -NG_DELAY
;
745 unsigned long new_update
;
746 struct goodhost
*ghp
, **ghpp
;
749 char *mach
, *usr
, *dom
;
754 /* if no netgroup, then we are finished */
755 if (goodgroup
== 0 || !Mflag
)
758 /* Do not chatter with the netgroup master too often.
760 new_update
= times(&tm
);
761 if (new_update
< last_update
+ NG_DELAY
764 last_update
= new_update
;
766 /* forget the old temporary entries */
768 while (0 != (ghp
= *ghpp
)) {
778 /* quit now if we are not one of the trusted masters
780 if (!innetgr(goodgroup
, &hostname
[0], 0,0)) {
782 fprintf(fd
, "get_goodgroup: %s not in %s\n",
783 &hostname
[0], goodgroup
);
787 fprintf(fd
, "get_goodgroup: %s in %s\n",
788 &hostname
[0], goodgroup
);
790 /* mark the entire netgroup as trusted */
791 setnetgrent(goodgroup
);
792 while (getnetgrent(&mach
,&usr
,&dom
)) {
794 add_good_host(mach
,0);
798 /* update list of slaves */
799 for (htp
= self
.l_fwd
; htp
!= &self
; htp
= htp
->l_fwd
) {
800 htp
->good
= good_host_name(&htp
->name
[0]);
806 /* see if a machine is trustworthy
808 int /* 1=trust hp to change our date */
809 good_host_name(char *name
)
811 struct goodhost
*ghp
= goodhosts
;
814 if (!ghp
|| !Mflag
) /* trust everyone if no one named */
819 if (c
== ghp
->name
[0]
820 && !strcasecmp(name
, ghp
->name
))
821 return 1; /* found him, so say so */
822 } while (0 != (ghp
= ghp
->next
));
824 if (!strcasecmp(name
,hostname
)) /* trust ourself */
827 return 0; /* did not find him */