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