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