slave.c revision 331090
1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1985, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 4. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#ifndef lint
33#if 0
34static char sccsid[] = "@(#)slave.c	8.1 (Berkeley) 6/6/93";
35#endif
36static const char rcsid[] =
37  "$FreeBSD: stable/11/usr.sbin/timed/timed/slave.c 331090 2018-03-17 06:31:24Z eadler $";
38#endif /* not lint */
39
40#include "globals.h"
41#include <setjmp.h>
42#include <utmpx.h>
43#include "pathnames.h"
44
45extern jmp_buf jmpenv;
46extern int Mflag;
47extern int justquit;
48
49extern u_short sequence;
50
51static char master_name[MAXHOSTNAMELEN];
52static struct netinfo *old_slavenet;
53static int old_status;
54
55static void schgdate(struct tsp *, char *);
56static void setmaster(struct tsp *);
57static void answerdelay(void);
58
59void
60slave(void)
61{
62	int tries;
63	long electiontime, refusetime, looktime, looptime, adjtime;
64	u_short seq;
65	long fastelection;
66#define FASTTOUT 3
67	struct in_addr cadr;
68	struct timeval otime;
69	struct sockaddr_in taddr;
70	char tname[MAXHOSTNAMELEN];
71	struct tsp *msg, to;
72	struct timeval ntime, wait, tmptv;
73	time_t tsp_time_sec;
74	struct tsp *answer;
75	int timeout();
76	char olddate[32];
77	char newdate[32];
78	struct netinfo *ntp;
79	struct hosttbl *htp;
80	struct utmpx utx;
81
82
83	old_slavenet = NULL;
84	seq = 0;
85	refusetime = 0;
86	adjtime = 0;
87
88	(void)gettimeofday(&ntime, NULL);
89	electiontime = ntime.tv_sec + delay2;
90	fastelection = ntime.tv_sec + FASTTOUT;
91	if (justquit)
92		looktime = electiontime;
93	else
94		looktime = fastelection;
95	looptime = fastelection;
96
97	if (slavenet)
98		xmit(TSP_SLAVEUP, 0, &slavenet->dest_addr);
99	if (status & MASTER) {
100		for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
101			if (ntp->status == MASTER)
102				masterup(ntp);
103		}
104	}
105
106loop:
107	get_goodgroup(0);
108	(void)gettimeofday(&ntime, NULL);
109	if (ntime.tv_sec > electiontime) {
110		if (trace)
111			fprintf(fd, "election timer expired\n");
112		longjmp(jmpenv, 1);
113	}
114
115	if (ntime.tv_sec >= looktime) {
116		if (trace)
117			fprintf(fd, "Looking for nets to master\n");
118
119		if (Mflag && nignorednets > 0) {
120			for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
121				if (ntp->status == IGNORE
122				    || ntp->status == NOMASTER) {
123					lookformaster(ntp);
124					if (ntp->status == MASTER) {
125						masterup(ntp);
126					} else if (ntp->status == MASTER) {
127						ntp->status = NOMASTER;
128					}
129				}
130				if (ntp->status == MASTER
131				    && --ntp->quit_count < 0)
132					ntp->quit_count = 0;
133			}
134			makeslave(slavenet);	/* prune extras */
135			setstatus();
136		}
137		(void)gettimeofday(&ntime, NULL);
138		looktime = ntime.tv_sec + delay2;
139	}
140	if (ntime.tv_sec >= looptime) {
141		if (trace)
142			fprintf(fd, "Looking for loops\n");
143		for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
144		    if (ntp->status == MASTER) {
145			to.tsp_type = TSP_LOOP;
146			to.tsp_vers = TSPVERSION;
147			to.tsp_seq = sequence++;
148			to.tsp_hopcnt = MAX_HOPCNT;
149			(void)strcpy(to.tsp_name, hostname);
150			bytenetorder(&to);
151			if (sendto(sock, (char *)&to, sizeof(struct tsp), 0,
152				   (struct sockaddr*)&ntp->dest_addr,
153				   sizeof(ntp->dest_addr)) < 0) {
154				trace_sendto_err(ntp->dest_addr.sin_addr);
155			}
156		    }
157		}
158		(void)gettimeofday(&ntime, NULL);
159		looptime = ntime.tv_sec + delay2;
160	}
161
162	wait.tv_sec = min(electiontime,min(looktime,looptime)) - ntime.tv_sec;
163	if (wait.tv_sec < 0)
164		wait.tv_sec = 0;
165	wait.tv_sec += FASTTOUT;
166	wait.tv_usec = 0;
167	msg = readmsg(TSP_ANY, ANYADDR, &wait, 0);
168
169	if (msg != NULL) {
170		/*
171		 * filter stuff not for us
172		 */
173		switch (msg->tsp_type) {
174		case TSP_SETDATE:
175		case TSP_TRACEOFF:
176		case TSP_TRACEON:
177			/*
178			 * XXX check to see they are from ourself
179			 */
180			break;
181
182		case TSP_TEST:
183		case TSP_MSITE:
184			break;
185
186		case TSP_MASTERUP:
187			if (!fromnet) {
188				if (trace) {
189					fprintf(fd, "slave ignored: ");
190					print(msg, &from);
191				}
192				goto loop;
193			}
194			break;
195
196		default:
197			if (!fromnet
198			    || fromnet->status == IGNORE
199			    || fromnet->status == NOMASTER) {
200				if (trace) {
201					fprintf(fd, "slave ignored: ");
202					print(msg, &from);
203				}
204				goto loop;
205			}
206			break;
207		}
208
209
210		/*
211		 * now process the message
212		 */
213		switch (msg->tsp_type) {
214
215		case TSP_ADJTIME:
216			if (fromnet != slavenet)
217				break;
218			if (!good_host_name(msg->tsp_name)) {
219				syslog(LOG_NOTICE,
220				   "attempted time adjustment by %s",
221				       msg->tsp_name);
222				suppress(&from, msg->tsp_name, fromnet);
223				break;
224			}
225			/*
226			 * Speed up loop detection in case we have a loop.
227			 * Otherwise the clocks can race until the loop
228			 * is found.
229			 */
230			(void)gettimeofday(&otime, NULL);
231			if (adjtime < otime.tv_sec)
232				looptime -= (looptime-otime.tv_sec)/2 + 1;
233
234			setmaster(msg);
235			if (seq != msg->tsp_seq) {
236				seq = msg->tsp_seq;
237				synch(tvtomsround(msg->tsp_time));
238			}
239			(void)gettimeofday(&ntime, NULL);
240			electiontime = ntime.tv_sec + delay2;
241			fastelection = ntime.tv_sec + FASTTOUT;
242			adjtime = ntime.tv_sec + SAMPLEINTVL*2;
243			break;
244
245		case TSP_SETTIME:
246			if (fromnet != slavenet)
247				break;
248			if (seq == msg->tsp_seq)
249				break;
250			seq = msg->tsp_seq;
251
252			/* adjust time for residence on the queue */
253			(void)gettimeofday(&otime, NULL);
254			adj_msg_time(msg,&otime);
255			/*
256			 * the following line is necessary due to syslog
257			 * calling ctime() which clobbers the static buffer
258			 */
259			(void)strlcpy(olddate, date(), sizeof(olddate));
260			tsp_time_sec = msg->tsp_time.tv_sec;
261			(void)strlcpy(newdate, ctime(&tsp_time_sec),
262			    sizeof(newdate));
263
264			if (!good_host_name(msg->tsp_name)) {
265				syslog(LOG_NOTICE,
266			    "attempted time setting by untrusted %s to %s",
267				       msg->tsp_name, newdate);
268				suppress(&from, msg->tsp_name, fromnet);
269				break;
270			}
271
272			setmaster(msg);
273 			tmptv.tv_sec = msg->tsp_time.tv_sec;
274 			tmptv.tv_usec = msg->tsp_time.tv_usec;
275			timevalsub(&ntime, &tmptv, &otime);
276			if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) {
277				/*
278				 * do not change the clock if we can adjust it
279				 */
280				synch(tvtomsround(ntime));
281			} else {
282				utx.ut_type = OLD_TIME;
283				gettimeofday(&utx.ut_tv, NULL);
284				pututxline(&utx);
285				(void)settimeofday(&tmptv, 0);
286				utx.ut_type = NEW_TIME;
287				gettimeofday(&utx.ut_tv, NULL);
288				pututxline(&utx);
289				syslog(LOG_NOTICE,
290				       "date changed by %s from %s",
291					msg->tsp_name, olddate);
292				if (status & MASTER)
293					spreadtime();
294			}
295			(void)gettimeofday(&ntime, NULL);
296			electiontime = ntime.tv_sec + delay2;
297			fastelection = ntime.tv_sec + FASTTOUT;
298
299/* This patches a bad protocol bug.  Imagine a system with several networks,
300 * where there are a pair of redundant gateways between a pair of networks,
301 * each running timed.  Assume that we start with a third machine mastering
302 * one of the networks, and one of the gateways mastering the other.
303 * Imagine that the third machine goes away and the non-master gateway
304 * decides to replace it.  If things are timed just 'right,' we will have
305 * each gateway mastering one network for a little while.  If a SETTIME
306 * message gets into the network at that time, perhaps from the newly
307 * masterful gateway as it was taking control, the SETTIME will loop
308 * forever.  Each time a gateway receives it on its slave side, it will
309 * call spreadtime to forward it on its mastered network.  We are now in
310 * a permanent loop, since the SETTIME msgs will keep any clock
311 * in the network from advancing.  Normally, the 'LOOP' stuff will detect
312 * and correct the situation.  However, with the clocks stopped, the
313 * 'looptime' timer cannot expire.  While they are in this state, the
314 * masters will try to saturate the network with SETTIME packets.
315 */
316			looptime = ntime.tv_sec + (looptime-otime.tv_sec)/2-1;
317			break;
318
319		case TSP_MASTERUP:
320			if (slavenet && fromnet != slavenet)
321				break;
322			if (!good_host_name(msg->tsp_name)) {
323				suppress(&from, msg->tsp_name, fromnet);
324				if (electiontime > fastelection)
325					electiontime = fastelection;
326				break;
327			}
328			makeslave(fromnet);
329			setmaster(msg);
330			setstatus();
331			answerdelay();
332			xmit(TSP_SLAVEUP, 0, &from);
333			(void)gettimeofday(&ntime, NULL);
334			electiontime = ntime.tv_sec + delay2;
335			fastelection = ntime.tv_sec + FASTTOUT;
336			refusetime = 0;
337			break;
338
339		case TSP_MASTERREQ:
340			if (fromnet->status != SLAVE)
341				break;
342			(void)gettimeofday(&ntime, NULL);
343			electiontime = ntime.tv_sec + delay2;
344			break;
345
346		case TSP_SETDATE:
347			tsp_time_sec = msg->tsp_time.tv_sec;
348			(void)strlcpy(newdate, ctime(&tsp_time_sec),
349			    sizeof(newdate));
350			schgdate(msg, newdate);
351			break;
352
353		case TSP_SETDATEREQ:
354			if (fromnet->status != MASTER)
355				break;
356			tsp_time_sec = msg->tsp_time.tv_sec;
357			(void)strlcpy(newdate, ctime(&tsp_time_sec),
358			    sizeof(newdate));
359			htp = findhost(msg->tsp_name);
360			if (htp == NULL) {
361				syslog(LOG_WARNING,
362				       "DATEREQ from uncontrolled machine");
363				break;
364			}
365			if (!htp->good) {
366				syslog(LOG_WARNING,
367				"attempted date change by untrusted %s to %s",
368				       htp->name, newdate);
369				spreadtime();
370				break;
371			}
372			schgdate(msg, newdate);
373			break;
374
375		case TSP_TRACEON:
376			traceon();
377			break;
378
379		case TSP_TRACEOFF:
380			traceoff("Tracing ended at %s\n");
381			break;
382
383		case TSP_SLAVEUP:
384			newslave(msg);
385			break;
386
387		case TSP_ELECTION:
388			if (fromnet->status == SLAVE) {
389				(void)gettimeofday(&ntime, NULL);
390				electiontime = ntime.tv_sec + delay2;
391				fastelection = ntime.tv_sec + FASTTOUT;
392				seq = 0;
393				if (!good_host_name(msg->tsp_name)) {
394					syslog(LOG_NOTICE,
395					       "suppress election of %s",
396					       msg->tsp_name);
397					to.tsp_type = TSP_QUIT;
398					electiontime = fastelection;
399				} else if (cadr.s_addr != from.sin_addr.s_addr
400					   && ntime.tv_sec < refusetime) {
401/* if the candidate has to repeat itself, the old code would refuse it
402 * the second time.  That would prevent elections.
403 */
404					to.tsp_type = TSP_REFUSE;
405				} else {
406					cadr.s_addr = from.sin_addr.s_addr;
407					to.tsp_type = TSP_ACCEPT;
408					refusetime = ntime.tv_sec + 30;
409				}
410				taddr = from;
411				(void)strcpy(tname, msg->tsp_name);
412				(void)strcpy(to.tsp_name, hostname);
413				answerdelay();
414				if (!acksend(&to, &taddr, tname,
415					     TSP_ACK, 0, 0))
416					syslog(LOG_WARNING,
417					     "no answer from candidate %s\n",
418					       tname);
419
420			} else {	/* fromnet->status == MASTER */
421				htp = addmach(msg->tsp_name, &from,fromnet);
422				to.tsp_type = TSP_QUIT;
423				(void)strcpy(to.tsp_name, hostname);
424				if (!acksend(&to, &htp->addr, htp->name,
425					     TSP_ACK, 0, htp->noanswer)) {
426					syslog(LOG_ERR,
427					  "no reply from %s to ELECTION-QUIT",
428					       htp->name);
429					(void)remmach(htp);
430				}
431			}
432			break;
433
434		case TSP_CONFLICT:
435			if (fromnet->status != MASTER)
436				break;
437			/*
438			 * After a network partition, there can be
439			 * more than one master: the first slave to
440			 * come up will notify here the situation.
441			 */
442			(void)strcpy(to.tsp_name, hostname);
443
444			/* The other master often gets into the same state,
445			 * with boring results.
446			 */
447			ntp = fromnet;	/* (acksend() can leave fromnet=0 */
448			for (tries = 0; tries < 3; tries++) {
449				to.tsp_type = TSP_RESOLVE;
450				answer = acksend(&to, &ntp->dest_addr,
451						 ANYADDR, TSP_MASTERACK,
452						 ntp, 0);
453				if (answer == NULL)
454					break;
455				htp = addmach(answer->tsp_name,&from,ntp);
456				to.tsp_type = TSP_QUIT;
457				answer = acksend(&to, &htp->addr, htp->name,
458						 TSP_ACK, 0, htp->noanswer);
459				if (!answer) {
460					syslog(LOG_WARNING,
461				  "conflict error: no reply from %s to QUIT",
462						htp->name);
463					(void)remmach(htp);
464				}
465			}
466			masterup(ntp);
467			break;
468
469		case TSP_MSITE:
470			if (!slavenet)
471				break;
472			taddr = from;
473			to.tsp_type = TSP_MSITEREQ;
474			to.tsp_vers = TSPVERSION;
475			to.tsp_seq = 0;
476			(void)strcpy(to.tsp_name, hostname);
477			answer = acksend(&to, &slavenet->dest_addr,
478					 ANYADDR, TSP_ACK,
479					 slavenet, 0);
480			if (answer != NULL
481			    && good_host_name(answer->tsp_name)) {
482				setmaster(answer);
483				to.tsp_type = TSP_ACK;
484				(void)strcpy(to.tsp_name, answer->tsp_name);
485				bytenetorder(&to);
486				if (sendto(sock, (char *)&to,
487					   sizeof(struct tsp), 0,
488					   (struct sockaddr*)&taddr,
489					   sizeof(taddr)) < 0) {
490					trace_sendto_err(taddr.sin_addr);
491				}
492			}
493			break;
494
495		case TSP_MSITEREQ:
496			break;
497
498		case TSP_ACCEPT:
499		case TSP_REFUSE:
500		case TSP_RESOLVE:
501			break;
502
503		case TSP_QUIT:
504			doquit(msg);		/* become a slave */
505			break;
506
507		case TSP_TEST:
508			electiontime = 0;
509			break;
510
511		case TSP_LOOP:
512			/* looking for loops of masters */
513			if (!(status & MASTER))
514				break;
515			if (fromnet->status == SLAVE) {
516			    if (!strcmp(msg->tsp_name, hostname)) {
517				/*
518				 * Someone forwarded our message back to
519				 * us.  There must be a loop.  Tell the
520				 * master of this network to quit.
521				 *
522				 * The other master often gets into
523				 * the same state, with boring results.
524				 */
525				ntp = fromnet;
526				for (tries = 0; tries < 3; tries++) {
527				    to.tsp_type = TSP_RESOLVE;
528				    answer = acksend(&to, &ntp->dest_addr,
529						     ANYADDR, TSP_MASTERACK,
530						     ntp,0);
531				    if (answer == NULL)
532					break;
533				    taddr = from;
534				    (void)strcpy(tname, answer->tsp_name);
535				    to.tsp_type = TSP_QUIT;
536				    (void)strcpy(to.tsp_name, hostname);
537				    if (!acksend(&to, &taddr, tname,
538						 TSP_ACK, 0, 1)) {
539					syslog(LOG_ERR,
540					"no reply from %s to slave LOOP-QUIT",
541						 tname);
542				    } else {
543					electiontime = 0;
544				    }
545				}
546				(void)gettimeofday(&ntime, NULL);
547				looptime = ntime.tv_sec + FASTTOUT;
548			    } else {
549				if (msg->tsp_hopcnt-- < 1)
550				    break;
551				bytenetorder(msg);
552				for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
553				    if (ntp->status == MASTER
554					&& 0 > sendto(sock, (char *)msg,
555						      sizeof(struct tsp), 0,
556					      (struct sockaddr*)&ntp->dest_addr,
557						      sizeof(ntp->dest_addr)))
558				    trace_sendto_err(ntp->dest_addr.sin_addr);
559				}
560			    }
561			} else {	/* fromnet->status == MASTER */
562			    /*
563			     * We should not have received this from a net
564			     * we are master on.  There must be two masters,
565			     * unless the packet was really from us.
566			     */
567			    if (from.sin_addr.s_addr
568				== fromnet->my_addr.s_addr) {
569				if (trace)
570				    fprintf(fd,"discarding forwarded LOOP\n");
571				break;
572			    }
573
574			    /*
575			     * The other master often gets into the same
576			     * state, with boring results.
577			     */
578			    ntp = fromnet;
579			    for (tries = 0; tries < 3; tries++) {
580				to.tsp_type = TSP_RESOLVE;
581				answer = acksend(&to, &ntp->dest_addr,
582						 ANYADDR, TSP_MASTERACK,
583						ntp,0);
584				if (!answer)
585					break;
586				htp = addmach(answer->tsp_name,
587					      &from,ntp);
588				to.tsp_type = TSP_QUIT;
589				(void)strcpy(to.tsp_name, hostname);
590				if (!acksend(&to,&htp->addr,htp->name,
591					     TSP_ACK, 0, htp->noanswer)) {
592					syslog(LOG_ERR,
593				    "no reply from %s to master LOOP-QUIT",
594					       htp->name);
595					(void)remmach(htp);
596				}
597			    }
598			    (void)gettimeofday(&ntime, NULL);
599			    looptime = ntime.tv_sec + FASTTOUT;
600			}
601			break;
602		default:
603			if (trace) {
604				fprintf(fd, "garbage message: ");
605				print(msg, &from);
606			}
607			break;
608		}
609	}
610	goto loop;
611}
612
613
614/*
615 * tell the world who our master is
616 */
617static void
618setmaster(struct tsp *msg)
619{
620	if (slavenet
621	    && (slavenet != old_slavenet
622		|| strcmp(msg->tsp_name, master_name)
623		|| old_status != status)) {
624		(void)strcpy(master_name, msg->tsp_name);
625		old_slavenet = slavenet;
626		old_status = status;
627
628		if (status & MASTER) {
629			syslog(LOG_NOTICE, "submaster to %s", master_name);
630			if (trace)
631				fprintf(fd, "submaster to %s\n", master_name);
632
633		} else {
634			syslog(LOG_NOTICE, "slave to %s", master_name);
635			if (trace)
636				fprintf(fd, "slave to %s\n", master_name);
637		}
638	}
639}
640
641
642
643/*
644 * handle date change request on a slave
645 */
646static void
647schgdate(struct tsp *msg, char *newdate)
648{
649	struct tsp to;
650	u_short seq;
651	struct sockaddr_in taddr;
652	struct timeval otime;
653
654	if (!slavenet)
655		return;			/* no where to forward */
656
657	taddr = from;
658	seq = msg->tsp_seq;
659
660	syslog(LOG_INFO,
661	       "forwarding date change by %s to %s",
662	       msg->tsp_name, newdate);
663
664	/* adjust time for residence on the queue */
665	(void)gettimeofday(&otime, NULL);
666	adj_msg_time(msg, &otime);
667
668	to.tsp_type = TSP_SETDATEREQ;
669	to.tsp_time = msg->tsp_time;
670	(void)strcpy(to.tsp_name, hostname);
671	if (!acksend(&to, &slavenet->dest_addr,
672		     ANYADDR, TSP_DATEACK,
673		     slavenet, 0))
674		return;			/* no answer */
675
676	xmit(TSP_DATEACK, seq, &taddr);
677}
678
679
680/*
681 * Used before answering a broadcast message to avoid network
682 * contention and likely collisions.
683 */
684static void
685answerdelay(void)
686{
687	struct timeval timeout;
688
689	timeout.tv_sec = 0;
690	timeout.tv_usec = delay1;
691
692	(void)select(0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL,
693	    &timeout);
694	return;
695}
696