xref: /freebsd-11-stable/usr.sbin/timed/timed/readmsg.c (revision 4ab2e064d7950be84256d671a7ae93f87cc6aa36)
1 /*-
2  * Copyright (c) 1985, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
16  *
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
27  * SUCH DAMAGE.
28  */
29 
30 #ifndef lint
31 #if 0
32 static char sccsid[] = "@(#)readmsg.c	8.1 (Berkeley) 6/6/93";
33 #endif
34 static const char rcsid[] =
35   "$FreeBSD$";
36 #endif /* not lint */
37 
38 #define	TSPTYPES
39 #include "globals.h"
40 
41 /*
42  * LOOKAT checks if the message is of the requested type and comes from
43  * the right machine, returning 1 in case of affirmative answer
44  */
45 #define LOOKAT(msg, mtype, mfrom, netp, froms) \
46 	(((mtype) == TSP_ANY || (mtype) == (msg).tsp_type) &&		\
47 	 ((mfrom) == 0 || !strcmp((mfrom), (msg).tsp_name)) &&		\
48 	 ((netp) == 0 || 						\
49 	  ((netp)->mask & (froms).sin_addr.s_addr) == (netp)->net.s_addr))
50 
51 struct timeval rtime, rwait, rtout;
52 struct tsp msgin;
53 static struct tsplist {
54 	struct tsp info;
55 	struct timeval when;
56 	struct sockaddr_in addr;
57 	struct tsplist *p;
58 } msgslist;
59 struct sockaddr_in from;
60 struct netinfo *fromnet;
61 struct timeval from_when;
62 
63 /*
64  * `readmsg' returns message `type' sent by `machfrom' if it finds it
65  * either in the receive queue, or in a linked list of previously received
66  * messages that it maintains.
67  * Otherwise it waits to see if the appropriate message arrives within
68  * `intvl' seconds. If not, it returns NULL.
69  */
70 
71 struct tsp *
readmsg(int type,char * machfrom,struct timeval * intvl,struct netinfo * netfrom)72 readmsg(int type, char *machfrom, struct timeval *intvl, struct netinfo *netfrom)
73 {
74 	int length;
75 	fd_set ready;
76 	static struct tsplist *head = &msgslist;
77 	static struct tsplist *tail = &msgslist;
78 	static int msgcnt = 0;
79 	struct tsplist *prev;
80 	register struct netinfo *ntp;
81 	register struct tsplist *ptr;
82 	ssize_t n;
83 
84 	if (trace) {
85 		fprintf(fd, "readmsg: looking for %s from %s, %s\n",
86 			tsptype[type], machfrom == NULL ? "ANY" : machfrom,
87 			netfrom == NULL ? "ANYNET" : inet_ntoa(netfrom->net));
88 		if (head->p != NULL) {
89 			length = 1;
90 			for (ptr = head->p; ptr != NULL; ptr = ptr->p) {
91 				/* do not repeat the hundreds of messages */
92 				if (++length > 3) {
93 					if (ptr == tail) {
94 						fprintf(fd,"\t ...%d skipped\n",
95 							length);
96 					} else {
97 						continue;
98 					}
99 				}
100 				fprintf(fd, length > 1 ? "\t" : "queue:\t");
101 				print(&ptr->info, &ptr->addr);
102 			}
103 		}
104 	}
105 
106 	ptr = head->p;
107 	prev = head;
108 
109 	/*
110 	 * Look for the requested message scanning through the
111 	 * linked list. If found, return it and free the space
112 	 */
113 
114 	while (ptr != NULL) {
115 		if (LOOKAT(ptr->info, type, machfrom, netfrom, ptr->addr)) {
116 again:
117 			msgin = ptr->info;
118 			from = ptr->addr;
119 			from_when = ptr->when;
120 			prev->p = ptr->p;
121 			if (ptr == tail)
122 				tail = prev;
123 			free((char *)ptr);
124 			fromnet = NULL;
125 			if (netfrom == NULL)
126 			    for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
127 				    if ((ntp->mask & from.sin_addr.s_addr) ==
128 					ntp->net.s_addr) {
129 					    fromnet = ntp;
130 					    break;
131 				    }
132 			    }
133 			else
134 			    fromnet = netfrom;
135 			if (trace) {
136 				fprintf(fd, "readmsg: found ");
137 				print(&msgin, &from);
138 			}
139 
140 /* The protocol can get far behind.  When it does, it gets
141  *	hopelessly confused.  So delete duplicate messages.
142  */
143 			for (ptr = prev; (ptr = ptr->p) != NULL; prev = ptr) {
144 				if (ptr->addr.sin_addr.s_addr
145 					== from.sin_addr.s_addr
146 				    && ptr->info.tsp_type == msgin.tsp_type) {
147 					if (trace)
148 						fprintf(fd, "\tdup ");
149 					goto again;
150 				}
151 			}
152 			msgcnt--;
153 			return(&msgin);
154 		} else {
155 			prev = ptr;
156 			ptr = ptr->p;
157 		}
158 	}
159 
160 	/*
161 	 * If the message was not in the linked list, it may still be
162 	 * coming from the network. Set the timer and wait
163 	 * on a select to read the next incoming message: if it is the
164 	 * right one, return it, otherwise insert it in the linked list.
165 	 */
166 
167 	(void)gettimeofday(&rtout, NULL);
168 	timevaladd(&rtout, intvl);
169 	FD_ZERO(&ready);
170 	for (;;) {
171 		(void)gettimeofday(&rtime, NULL);
172 		timevalsub(&rwait, &rtout, &rtime);
173 		if (rwait.tv_sec < 0)
174 			rwait.tv_sec = rwait.tv_usec = 0;
175 		else if (rwait.tv_sec == 0
176 			 && rwait.tv_usec < 1000000/CLK_TCK)
177 			rwait.tv_usec = 1000000/CLK_TCK;
178 
179 		if (trace) {
180 			fprintf(fd, "readmsg: wait %jd.%6ld at %s\n",
181 				(intmax_t)rwait.tv_sec, rwait.tv_usec, date());
182 			/* Notice a full disk, as we flush trace info.
183 			 * It is better to flush periodically than at
184 			 * every line because the tracing consists of bursts
185 			 * of many lines.  Without care, tracing slows
186 			 * down the code enough to break the protocol.
187 			 */
188 			if (rwait.tv_sec != 0
189 			    && EOF == fflush(fd))
190 				traceoff("Tracing ended for cause at %s\n");
191 		}
192 
193 		FD_SET(sock, &ready);
194 		if (!select(sock+1, &ready, (fd_set *)0, (fd_set *)0,
195 			   &rwait)) {
196 			if (rwait.tv_sec == 0 && rwait.tv_usec == 0)
197 				return(0);
198 			continue;
199 		}
200 		length = sizeof(from);
201 		if ((n = recvfrom(sock, (char *)&msgin, sizeof(struct tsp), 0,
202 			     (struct sockaddr*)&from, &length)) < 0) {
203 			syslog(LOG_ERR, "recvfrom: %m");
204 			exit(1);
205 		}
206 		/*
207 		 * The 4.3BSD protocol spec had a 32-byte tsp_name field, and
208 		 * this is still OS-dependent.  Demand that the packet is at
209 		 * least long enough to hold a 4.3BSD packet.
210 		 */
211 		if (n < (ssize_t)(sizeof(struct tsp) - MAXHOSTNAMELEN + 32)) {
212 			syslog(LOG_NOTICE,
213 			    "short packet (%zd/%zu bytes) from %s",
214 			      n, sizeof(struct tsp) - MAXHOSTNAMELEN + 32,
215 			      inet_ntoa(from.sin_addr));
216 			continue;
217 		}
218 		(void)gettimeofday(&from_when, NULL);
219 		bytehostorder(&msgin);
220 
221 		if (msgin.tsp_vers > TSPVERSION) {
222 			if (trace) {
223 			    fprintf(fd,"readmsg: version mismatch\n");
224 			    /* should do a dump of the packet */
225 			}
226 			continue;
227 		}
228 
229 		if (memchr(msgin.tsp_name,
230 		    '\0', sizeof msgin.tsp_name) == NULL) {
231 			syslog(LOG_NOTICE, "hostname field not NUL terminated "
232 			    "in packet from %s", inet_ntoa(from.sin_addr));
233 			continue;
234 		}
235 
236 		fromnet = NULL;
237 		for (ntp = nettab; ntp != NULL; ntp = ntp->next)
238 			if ((ntp->mask & from.sin_addr.s_addr) ==
239 			    ntp->net.s_addr) {
240 				fromnet = ntp;
241 				break;
242 			}
243 
244 		/*
245 		 * drop packets from nets we are ignoring permanently
246 		 */
247 		if (fromnet == NULL) {
248 			/*
249 			 * The following messages may originate on
250 			 * this host with an ignored network address
251 			 */
252 			if (msgin.tsp_type != TSP_TRACEON &&
253 			    msgin.tsp_type != TSP_SETDATE &&
254 			    msgin.tsp_type != TSP_MSITE &&
255 			    msgin.tsp_type != TSP_TEST &&
256 			    msgin.tsp_type != TSP_TRACEOFF) {
257 				if (trace) {
258 				    fprintf(fd,"readmsg: discard null net ");
259 				    print(&msgin, &from);
260 				}
261 				continue;
262 			}
263 		}
264 
265 		/*
266 		 * Throw away messages coming from this machine,
267 		 * unless they are of some particular type.
268 		 * This gets rid of broadcast messages and reduces
269 		 * master processing time.
270 		 */
271 		if (!strcmp(msgin.tsp_name, hostname)
272 		    && msgin.tsp_type != TSP_SETDATE
273 		    && msgin.tsp_type != TSP_TEST
274 		    && msgin.tsp_type != TSP_MSITE
275 		    && msgin.tsp_type != TSP_TRACEON
276 		    && msgin.tsp_type != TSP_TRACEOFF
277 		    && msgin.tsp_type != TSP_LOOP) {
278 			if (trace) {
279 				fprintf(fd, "readmsg: discard own ");
280 				print(&msgin, &from);
281 			}
282 			continue;
283 		}
284 
285 		/*
286 		 * Send acknowledgements here; this is faster and
287 		 * avoids deadlocks that would occur if acks were
288 		 * sent from a higher level routine.  Different
289 		 * acknowledgements are necessary, depending on
290 		 * status.
291 		 */
292 		if (fromnet == NULL)	/* do not de-reference 0 */
293 			ignoreack();
294 		else if (fromnet->status == MASTER)
295 			masterack();
296 		else if (fromnet->status == SLAVE)
297 			slaveack();
298 		else
299 			ignoreack();
300 
301 		if (LOOKAT(msgin, type, machfrom, netfrom, from)) {
302 			if (trace) {
303 				fprintf(fd, "readmsg: ");
304 				print(&msgin, &from);
305 			}
306 			return(&msgin);
307 		} else if (++msgcnt > NHOSTS*3) {
308 
309 /* The protocol gets hopelessly confused if it gets too far
310 *	behind.  However, it seems able to recover from all cases of lost
311 *	packets.  Therefore, if we are swamped, throw everything away.
312 */
313 			if (trace)
314 				fprintf(fd,
315 					"readmsg: discarding %d msgs\n",
316 					msgcnt);
317 			msgcnt = 0;
318 			while ((ptr=head->p) != NULL) {
319 				head->p = ptr->p;
320 				free((char *)ptr);
321 			}
322 			tail = head;
323 		} else {
324 			tail->p = (struct tsplist *)
325 				    malloc(sizeof(struct tsplist));
326 			tail = tail->p;
327 			tail->p = NULL;
328 			tail->info = msgin;
329 			tail->addr = from;
330 			/* timestamp msgs so SETTIMEs are correct */
331 			tail->when = from_when;
332 		}
333 	}
334 }
335 
336 /*
337  * Send the necessary acknowledgements:
338  * only the type ACK is to be sent by a slave
339  */
340 void
slaveack(void)341 slaveack(void)
342 {
343 	switch(msgin.tsp_type) {
344 
345 	case TSP_ADJTIME:
346 	case TSP_SETTIME:
347 	case TSP_ACCEPT:
348 	case TSP_REFUSE:
349 	case TSP_TRACEON:
350 	case TSP_TRACEOFF:
351 	case TSP_QUIT:
352 		if (trace) {
353 			fprintf(fd, "Slaveack: ");
354 			print(&msgin, &from);
355 		}
356 		xmit(TSP_ACK,msgin.tsp_seq, &from);
357 		break;
358 
359 	default:
360 		if (trace) {
361 			fprintf(fd, "Slaveack: no ack: ");
362 			print(&msgin, &from);
363 		}
364 		break;
365 	}
366 }
367 
368 /*
369  * Certain packets may arrive from this machine on ignored networks.
370  * These packets should be acknowledged.
371  */
372 void
ignoreack(void)373 ignoreack(void)
374 {
375 	switch(msgin.tsp_type) {
376 
377 	case TSP_TRACEON:
378 	case TSP_TRACEOFF:
379 	case TSP_QUIT:
380 		if (trace) {
381 			fprintf(fd, "Ignoreack: ");
382 			print(&msgin, &from);
383 		}
384 		xmit(TSP_ACK,msgin.tsp_seq, &from);
385 		break;
386 
387 	default:
388 		if (trace) {
389 			fprintf(fd, "Ignoreack: no ack: ");
390 			print(&msgin, &from);
391 		}
392 		break;
393 	}
394 }
395 
396 /*
397  * `masterack' sends the necessary acknowledgments
398  * to the messages received by a master
399  */
400 void
masterack(void)401 masterack(void)
402 {
403 	struct tsp resp;
404 
405 	resp = msgin;
406 	resp.tsp_vers = TSPVERSION;
407 	(void)strcpy(resp.tsp_name, hostname);
408 
409 	switch(msgin.tsp_type) {
410 
411 	case TSP_QUIT:
412 	case TSP_TRACEON:
413 	case TSP_TRACEOFF:
414 	case TSP_MSITEREQ:
415 		if (trace) {
416 			fprintf(fd, "Masterack: ");
417 			print(&msgin, &from);
418 		}
419 		xmit(TSP_ACK,msgin.tsp_seq, &from);
420 		break;
421 
422 	case TSP_RESOLVE:
423 	case TSP_MASTERREQ:
424 		if (trace) {
425 			fprintf(fd, "Masterack: ");
426 			print(&msgin, &from);
427 		}
428 		xmit(TSP_MASTERACK,msgin.tsp_seq, &from);
429 		break;
430 
431 	default:
432 		if (trace) {
433 			fprintf(fd,"Masterack: no ack: ");
434 			print(&msgin, &from);
435 		}
436 		break;
437 	}
438 }
439 
440 /*
441  * Print a TSP message
442  */
443 void
print(struct tsp * msg,struct sockaddr_in * addr)444 print(struct tsp *msg, struct sockaddr_in *addr)
445 {
446 	char tm[26];
447 	time_t tsp_time_sec;
448 
449 	if (msg->tsp_type >= TSPTYPENUMBER) {
450 		fprintf(fd, "bad type (%u) on packet from %s\n",
451 		  msg->tsp_type, inet_ntoa(addr->sin_addr));
452 		return;
453 	}
454 
455 	switch (msg->tsp_type) {
456 
457 	case TSP_LOOP:
458 		fprintf(fd, "%s %d %-6u #%d %-15s %s\n",
459 			tsptype[msg->tsp_type],
460 			msg->tsp_vers,
461 			msg->tsp_seq,
462 			msg->tsp_hopcnt,
463 			inet_ntoa(addr->sin_addr),
464 			msg->tsp_name);
465 		break;
466 
467 	case TSP_SETTIME:
468 	case TSP_SETDATE:
469 	case TSP_SETDATEREQ:
470 		tsp_time_sec = msg->tsp_time.tv_sec;
471 		strncpy(tm, ctime(&tsp_time_sec)+3+1, sizeof(tm));
472 		tm[15] = '\0';		/* ugh */
473 		fprintf(fd, "%s %d %-6u %s %-15s %s\n",
474 			tsptype[msg->tsp_type],
475 			msg->tsp_vers,
476 			msg->tsp_seq,
477 			tm,
478 			inet_ntoa(addr->sin_addr),
479 			msg->tsp_name);
480 		break;
481 
482 	case TSP_ADJTIME:
483 		fprintf(fd, "%s %d %-6u (%d,%d) %-15s %s\n",
484 			tsptype[msg->tsp_type],
485 			msg->tsp_vers,
486 			msg->tsp_seq,
487 			msg->tsp_time.tv_sec,
488 			msg->tsp_time.tv_usec,
489 			inet_ntoa(addr->sin_addr),
490 			msg->tsp_name);
491 		break;
492 
493 	default:
494 		fprintf(fd, "%s %d %-6u %-15s %s\n",
495 			tsptype[msg->tsp_type],
496 			msg->tsp_vers,
497 			msg->tsp_seq,
498 			inet_ntoa(addr->sin_addr),
499 			msg->tsp_name);
500 		break;
501 	}
502 }
503