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