xref: /original-bsd/usr.sbin/timed/timed/timed.c (revision ae291b9c)
1 /*
2  * Copyright (c) 1985 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1985 Regents of the University of California.\n\
11  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)timed.c	2.21 (Berkeley) 03/02/91";
16 #endif /* not lint */
17 
18 #include "globals.h"
19 #define TSPTYPES
20 #include <protocols/timed.h>
21 #include <net/if.h>
22 #include <arpa/inet.h>
23 #include <sys/file.h>
24 #include <sys/ioctl.h>
25 #include <setjmp.h>
26 #include "pathnames.h"
27 
28 int id;
29 int trace;
30 int sock, sock_raw = -1;
31 int status = 0;
32 int backoff;
33 int slvcount;				/* no. of slaves controlled by master */
34 int machup;
35 u_short sequence;			/* sequence number */
36 long delay1;
37 long delay2;
38 long random();
39 char hostname[MAXHOSTNAMELEN];
40 struct host hp[NHOSTS];
41 char tracefile[] = _PATH_TIMEDLOG;
42 FILE *fd;
43 jmp_buf jmpenv;
44 struct netinfo *nettab = NULL;
45 int nslavenets;		/* Number of networks were I could be a slave */
46 int nmasternets;	/* Number of networks were I could be a master */
47 int nignorednets;	/* Number of ignored networks */
48 int nnets;		/* Number of networks I am connected to */
49 struct netinfo *slavenet;
50 struct netinfo *firstslavenet();
51 int Mflag;
52 int justquit = 0;
53 
54 struct nets {
55 	char *name;
56 	long net;
57 	struct nets *next;
58 } *nets = (struct nets *)0;
59 
60 /*
61  * The timedaemons synchronize the clocks of hosts in a local area network.
62  * One daemon runs as master, all the others as slaves. The master
63  * performs the task of computing clock differences and sends correction
64  * values to the slaves.
65  * Slaves start an election to choose a new master when the latter disappears
66  * because of a machine crash, network partition, or when killed.
67  * A resolution protocol is used to kill all but one of the masters
68  * that happen to exist in segments of a partitioned network when the
69  * network partition is fixed.
70  *
71  * Authors: Riccardo Gusella & Stefano Zatti
72  */
73 
74 main(argc, argv)
75 int argc;
76 char **argv;
77 {
78 	int on;
79 	int ret;
80 	long seed;
81 	int nflag, iflag;
82 	struct timeval time;
83 	struct servent *srvp;
84 	long casual();
85 	char *date();
86 	int n;
87 	int flag;
88 	char buf[BUFSIZ], *cp, *cplim;
89 	struct ifconf ifc;
90 	struct ifreq ifreq, *ifr;
91 	register struct netinfo *ntp;
92 	struct netinfo *ntip;
93 	struct netinfo *savefromnet;
94 	struct sockaddr_in server;
95 	u_short port;
96 	uid_t getuid();
97 
98 #ifdef lint
99 	ntip = NULL;
100 #endif
101 
102 	Mflag = 0;
103 	on = 1;
104 	backoff = 1;
105 	trace = OFF;
106 	nflag = OFF;
107 	iflag = OFF;
108 	openlog("timed", LOG_CONS|LOG_PID, LOG_DAEMON);
109 
110 	if (getuid() != 0) {
111 		fprintf(stderr, "Timed: not superuser\n");
112 		exit(1);
113 	}
114 
115 	while (--argc > 0 && **++argv == '-') {
116 		(*argv)++;
117 		do {
118 			switch (**argv) {
119 
120 			case 'M':
121 				Mflag = 1;
122 				break;
123 			case 't':
124 				trace = ON;
125 				break;
126 			case 'n':
127 				argc--, argv++;
128 				if (iflag) {
129 					fprintf(stderr,
130 				    "timed: -i and -n make no sense together\n");
131 				} else {
132 					nflag = ON;
133 					addnetname(*argv);
134 				}
135 				while (*(++(*argv)+1)) ;
136 				break;
137 			case 'i':
138 				argc--, argv++;
139 				if (nflag) {
140 					fprintf(stderr,
141 				    "timed: -i and -n make no sense together\n");
142 				} else {
143 					iflag = ON;
144 					addnetname(*argv);
145 				}
146 				while (*(++(*argv)+1)) ;
147 				break;
148 			default:
149 				fprintf(stderr, "timed: -%c: unknown option\n",
150 							**argv);
151 				break;
152 			}
153 		} while (*++(*argv));
154 	}
155 
156 #ifndef DEBUG
157 	daemon(0, 0);
158 #endif
159 
160 	if (trace == ON) {
161 		fd = fopen(tracefile, "w");
162 		setlinebuf(fd);
163 		fprintf(fd, "Tracing started on: %s\n\n",
164 					date());
165 	}
166 
167 	srvp = getservbyname("timed", "udp");
168 	if (srvp == 0) {
169 		syslog(LOG_CRIT, "unknown service 'timed/udp'");
170 		exit(1);
171 	}
172 	port = srvp->s_port;
173 	server.sin_port = srvp->s_port;
174 	server.sin_family = AF_INET;
175 	sock = socket(AF_INET, SOCK_DGRAM, 0);
176 	if (sock < 0) {
177 		syslog(LOG_ERR, "socket: %m");
178 		exit(1);
179 	}
180 	if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&on,
181 							sizeof(on)) < 0) {
182 		syslog(LOG_ERR, "setsockopt: %m");
183 		exit(1);
184 	}
185 	if (bind(sock, (struct sockaddr *)&server, sizeof(server))) {
186 		if (errno == EADDRINUSE)
187 		        syslog(LOG_ERR, "server already running");
188 		else
189 		        syslog(LOG_ERR, "bind: %m");
190 		exit(1);
191 	}
192 
193 	/* choose a unique seed for random number generation */
194 	(void)gettimeofday(&time, (struct timezone *)0);
195 	seed = time.tv_sec + time.tv_usec;
196 	srandom(seed);
197 
198 	sequence = random();     /* initial seq number */
199 
200 	/* rounds kernel variable time to multiple of 5 ms. */
201 	time.tv_sec = 0;
202 	time.tv_usec = -((time.tv_usec/1000) % 5) * 1000;
203 	(void)adjtime(&time, (struct timeval *)0);
204 
205 	id = getpid();
206 
207 	if (gethostname(hostname, sizeof(hostname) - 1) < 0) {
208 		syslog(LOG_ERR, "gethostname: %m");
209 		exit(1);
210 	}
211 	hp[0].name = hostname;
212 
213 	if (nflag || iflag) {
214 		struct netent *getnetent();
215 		struct netent *n;
216 		struct nets *np;
217 		for ( np = nets ; np ; np = np->next) {
218 			n = getnetbyname(np->name);
219 			if (n == NULL) {
220 				syslog(LOG_ERR, "getnetbyname: unknown net %s",
221 					np->name);
222 				exit(1);
223 			}
224 			np->net = n->n_net;
225 		}
226 	}
227 	ifc.ifc_len = sizeof(buf);
228 	ifc.ifc_buf = buf;
229 	if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
230 		syslog(LOG_ERR, "get interface configuration: %m");
231 		exit(1);
232 	}
233 	ntp = NULL;
234 #define max(a, b) (a > b ? a : b)
235 #define size(p)	max((p).sa_len, sizeof(p))
236 	cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */
237 	for (cp = buf; cp < cplim;
238 			cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) {
239 		ifr = (struct ifreq *)cp;
240 		if (ifr->ifr_addr.sa_family != AF_INET)
241 			continue;
242 		ifreq = *ifr;
243 		if (ntp == NULL)
244 			ntp = (struct netinfo *)malloc(sizeof(struct netinfo));
245 		ntp->my_addr =
246 			((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
247 		if (ioctl(sock, SIOCGIFFLAGS,
248 					(char *)&ifreq) < 0) {
249 			syslog(LOG_ERR, "get interface flags: %m");
250 			continue;
251 		}
252 		if ((ifreq.ifr_flags & IFF_UP) == 0 ||
253 			((ifreq.ifr_flags & IFF_BROADCAST) == 0 &&
254 			(ifreq.ifr_flags & IFF_POINTOPOINT) == 0)) {
255 			continue;
256 		}
257 		if (ifreq.ifr_flags & IFF_BROADCAST)
258 			flag = 1;
259 		else
260 			flag = 0;
261 		if (ioctl(sock, SIOCGIFNETMASK,
262 					(char *)&ifreq) < 0) {
263 			syslog(LOG_ERR, "get netmask: %m");
264 			continue;
265 		}
266 		ntp->mask = ((struct sockaddr_in *)
267 			&ifreq.ifr_addr)->sin_addr.s_addr;
268 		if (flag) {
269 			if (ioctl(sock, SIOCGIFBRDADDR,
270 						(char *)&ifreq) < 0) {
271 				syslog(LOG_ERR, "get broadaddr: %m");
272 				continue;
273 			}
274 			ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_broadaddr;
275 		} else {
276 			if (ioctl(sock, SIOCGIFDSTADDR,
277 						(char *)&ifreq) < 0) {
278 				syslog(LOG_ERR, "get destaddr: %m");
279 				continue;
280 			}
281 			ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_dstaddr;
282 		}
283 		ntp->dest_addr.sin_port = port;
284 		if (nflag || iflag) {
285 			u_long addr, mask;
286 			struct nets *n;
287 
288 			addr = ntohl(ntp->dest_addr.sin_addr.s_addr);
289 			mask = ntohl(ntp->mask);
290 			while ((mask & 1) == 0) {
291 				addr >>= 1;
292 				mask >>= 1;
293 			}
294 			for (n = nets ; n ; n = n->next)
295 				if (addr == n->net)
296 					break;
297 			if (nflag && !n || iflag && n)
298 				continue;
299 		}
300 		ntp->net = ntp->mask & ntp->dest_addr.sin_addr.s_addr;
301 		ntp->next = NULL;
302 		if (nettab == NULL) {
303 			nettab = ntp;
304 		} else {
305 			ntip->next = ntp;
306 		}
307 		ntip = ntp;
308 		ntp = NULL;
309 	}
310 	if (ntp)
311 		(void) free((char *)ntp);
312 	if (nettab == NULL) {
313 		syslog(LOG_ERR, "No network usable");
314 		exit(1);
315 	}
316 
317 	for (ntp = nettab; ntp != NULL; ntp = ntp->next)
318 		lookformaster(ntp);
319 	setstatus();
320 	/*
321 	 * Take care of some basic initialization.
322 	 */
323 	/* us. delay to be used in response to broadcast */
324 	delay1 = casual((long)10000, 200000);
325 
326 	/* election timer delay in secs. */
327 	delay2 = casual((long)MINTOUT, (long)MAXTOUT);
328 
329 	if (Mflag) {
330 		/*
331 		 * number (increased by 1) of slaves controlled by master:
332 		 * used in master.c, candidate.c, networkdelta.c, and
333 		 * correct.c
334 		 */
335 		slvcount = 1;
336 		ret = setjmp(jmpenv);
337 
338 		switch (ret) {
339 
340 		case 0:
341 			makeslave(firstslavenet());
342 			setstatus();
343 			break;
344 		case 1:
345 			/* Just lost our master */
346 			setstatus();
347 			slavenet->status = election(slavenet);
348 			checkignorednets();
349 			setstatus();
350 			if (slavenet->status == MASTER)
351 				makeslave(firstslavenet());
352 			else
353 				makeslave(slavenet);
354 			setstatus();
355 			break;
356 		case 2:
357 			/* Just been told to quit */
358 			fromnet->status = SLAVE;
359 			setstatus();
360 			savefromnet = fromnet;
361 			rmnetmachs(fromnet);
362 			checkignorednets();
363 			if (slavenet)
364 				makeslave(slavenet);
365 			else
366 				makeslave(savefromnet);
367 			setstatus();
368 			justquit = 1;
369 			break;
370 
371 		default:
372 			/* this should not happen */
373 			syslog(LOG_ERR, "Attempt to enter invalid state");
374 			break;
375 		}
376 
377 		if (status & MASTER) {
378 			/* open raw socket used to measure time differences */
379 			if (sock_raw == -1) {
380 			    sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
381 			    if (sock_raw < 0)  {
382 				    syslog(LOG_ERR, "opening raw socket: %m");
383 				    exit (1);
384 			    }
385 			}
386 		} else {
387 			/* sock_raw is not being used now */
388 			if (sock_raw != -1) {
389 			    (void)close(sock_raw);
390 			    sock_raw = -1;
391 			}
392 		}
393 
394 		if (status == MASTER)
395 			master();
396 		else
397 			slave();
398 	} else {
399 		/* if Mflag is not set timedaemon is forced to act as a slave */
400 		status = SLAVE;
401 		if (setjmp(jmpenv)) {
402 			setstatus();
403 			checkignorednets();
404 		}
405 		makeslave(firstslavenet());
406 		for (ntp = nettab; ntp != NULL; ntp = ntp->next)
407 			if (ntp->status == MASTER)
408 				ntp->status = IGNORE;
409 		setstatus();
410 		slave();
411 	}
412 }
413 
414 /*
415  * Try to become master over ignored nets..
416  */
417 checkignorednets()
418 {
419 	register struct netinfo *ntp;
420 	for (ntp = nettab; ntp != NULL; ntp = ntp->next)
421 		if (ntp->status == IGNORE)
422 			lookformaster(ntp);
423 }
424 
425 lookformaster(ntp)
426 	register struct netinfo *ntp;
427 {
428 	struct tsp resp, conflict, *answer, *readmsg(), *acksend();
429 	struct timeval time;
430 	char mastername[MAXHOSTNAMELEN];
431 	struct sockaddr_in masteraddr;
432 
433 	ntp->status = SLAVE;
434 	/* look for master */
435 	resp.tsp_type = TSP_MASTERREQ;
436 	(void)strcpy(resp.tsp_name, hostname);
437 	answer = acksend(&resp, &ntp->dest_addr, (char *)ANYADDR,
438 	    TSP_MASTERACK, ntp);
439 	if (answer == NULL) {
440 		/*
441 		 * Various conditions can cause conflict: race between
442 		 * two just started timedaemons when no master is
443 		 * present, or timedaemon started during an election.
444 		 * Conservative approach is taken: give up and became a
445 		 * slave postponing election of a master until first
446 		 * timer expires.
447 		 */
448 		time.tv_sec = time.tv_usec = 0;
449 		answer = readmsg(TSP_MASTERREQ, (char *)ANYADDR,
450 		    &time, ntp);
451 		if (answer != NULL) {
452 			ntp->status = SLAVE;
453 			return;
454 		}
455 
456 		time.tv_sec = time.tv_usec = 0;
457 		answer = readmsg(TSP_MASTERUP, (char *)ANYADDR,
458 		    &time, ntp);
459 		if (answer != NULL) {
460 			ntp->status = SLAVE;
461 			return;
462 		}
463 
464 		time.tv_sec = time.tv_usec = 0;
465 		answer = readmsg(TSP_ELECTION, (char *)ANYADDR,
466 		    &time, ntp);
467 		if (answer != NULL) {
468 			ntp->status = SLAVE;
469 			return;
470 		}
471 		ntp->status = MASTER;
472 	} else {
473 		(void)strcpy(mastername, answer->tsp_name);
474 		masteraddr = from;
475 
476 		/*
477 		 * If network has been partitioned, there might be other
478 		 * masters; tell the one we have just acknowledged that
479 		 * it has to gain control over the others.
480 		 */
481 		time.tv_sec = 0;
482 		time.tv_usec = 300000;
483 		answer = readmsg(TSP_MASTERACK, (char *)ANYADDR, &time,
484 		    ntp);
485 		/*
486 		 * checking also not to send CONFLICT to ack'ed master
487 		 * due to duplicated MASTERACKs
488 		 */
489 		if (answer != NULL &&
490 		    strcmp(answer->tsp_name, mastername) != 0) {
491 			conflict.tsp_type = TSP_CONFLICT;
492 			(void)strcpy(conflict.tsp_name, hostname);
493 			if (acksend(&conflict, &masteraddr, mastername,
494 			    TSP_ACK, (struct netinfo *)NULL) == NULL) {
495 				syslog(LOG_ERR,
496 				    "error on sending TSP_CONFLICT");
497 				exit(1);
498 			}
499 		}
500 	}
501 }
502 /*
503  * based on the current network configuration, set the status, and count
504  * networks;
505  */
506 setstatus()
507 {
508 	register struct netinfo *ntp;
509 
510 	status = 0;
511 	nmasternets = nslavenets = nnets = nignorednets = 0;
512 	if (trace)
513 		fprintf(fd, "Net status:\n");
514 	for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
515 		switch ((int)ntp->status) {
516 		  case MASTER:
517 			nmasternets++;
518 			break;
519 		  case SLAVE:
520 			nslavenets++;
521 			break;
522 		  case IGNORE:
523 			nignorednets++;
524 			break;
525 		}
526 		if (trace) {
527 			fprintf(fd, "\t%-16s",
528 			    inet_ntoa(inet_makeaddr(ntp->net, 0)));
529 			switch ((int)ntp->status) {
530 			  case MASTER:
531 				fprintf(fd, "MASTER\n");
532 				break;
533 			  case SLAVE:
534 				fprintf(fd, "SLAVE\n");
535 				break;
536 			  case IGNORE:
537 				fprintf(fd, "IGNORE\n");
538 				break;
539 			  default:
540 				fprintf(fd, "invalid state %d\n",(int)ntp->status);
541 				break;
542 			}
543 		}
544 		nnets++;
545 		status |= ntp->status;
546 	}
547 	status &= ~IGNORE;
548 	if (trace)
549 		fprintf(fd,
550 		      "\tnets = %d, masters = %d, slaves = %d, ignored = %d\n",
551 		      nnets, nmasternets, nslavenets, nignorednets);
552 }
553 
554 makeslave(net)
555 	struct netinfo *net;
556 {
557 	register struct netinfo *ntp;
558 
559 	for (ntp = nettab; ntp != NULL; ntp = ntp->next)
560 		if (ntp->status == SLAVE && ntp != net)
561 			ntp->status = IGNORE;
562 	slavenet = net;
563 }
564 
565 struct netinfo *
566 firstslavenet()
567 {
568 	register struct netinfo *ntp;
569 
570 	for (ntp = nettab; ntp != NULL; ntp = ntp->next)
571 		if (ntp->status == SLAVE)
572 			return (ntp);
573 	return ((struct netinfo *)0);
574 }
575 
576 /*
577  * `casual' returns a random number in the range [inf, sup]
578  */
579 
580 long
581 casual(inf, sup)
582 long inf;
583 long sup;
584 {
585 	float value;
586 
587 	value = (float)(random() & 0x7fffffff) / 0x7fffffff;
588 	return(inf + (sup - inf) * value);
589 }
590 
591 char *
592 date()
593 {
594 	char    *ctime();
595 	struct	timeval tv;
596 
597 	(void)gettimeofday(&tv, (struct timezone *)0);
598 	return (ctime(&tv.tv_sec));
599 }
600 
601 addnetname(name)
602 	char *name;
603 {
604 	register struct nets **netlist = &nets;
605 
606 	while (*netlist)
607 		netlist = &((*netlist)->next);
608 	*netlist = (struct nets *)malloc(sizeof **netlist);
609 	if (*netlist == (struct nets *)0) {
610 		syslog(LOG_ERR, "malloc failed");
611 		exit(1);
612 	}
613 	bzero((char *)*netlist, sizeof(**netlist));
614 	(*netlist)->name = name;
615 }
616