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 32static char sccsid[] = "@(#)readmsg.c 8.1 (Berkeley) 6/6/93"; 33#endif 34static const char rcsid[] = 35 "$FreeBSD: releng/10.2/usr.sbin/timed/timed/readmsg.c 246209 2013-02-01 14:26:54Z charnier $"; 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 51struct timeval rtime, rwait, rtout; 52struct tsp msgin; 53static struct tsplist { 54 struct tsp info; 55 struct timeval when; 56 struct sockaddr_in addr; 57 struct tsplist *p; 58} msgslist; 59struct sockaddr_in from; 60struct netinfo *fromnet; 61struct 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 71struct tsp * 72readmsg(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 != 0) { 89 length = 1; 90 for (ptr = head->p; ptr != 0; 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)) { 116again: 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 */ 340void 341slaveack(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 */ 372void 373ignoreack(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 */ 400void 401masterack(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 */ 443void 444print(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