cmds.c revision 81946
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[] = "@(#)cmds.c 8.1 (Berkeley) 6/6/93"; 37#endif 38static const char rcsid[] = 39 "$FreeBSD: head/usr.sbin/timed/timedc/cmds.c 81946 2001-08-20 06:16:04Z kris $"; 40#endif /* not lint */ 41 42#include "timedc.h" 43#include <sys/file.h> 44 45#include <netinet/in_systm.h> 46#include <netinet/ip.h> 47#include <netinet/ip_icmp.h> 48 49#include <err.h> 50#include <stdlib.h> 51#include <strings.h> 52#include <unistd.h> 53 54#define TSPTYPES 55#include <protocols/timed.h> 56 57#ifdef sgi 58#include <bstring.h> 59#include <sys/clock.h> 60#else 61#define SECHR (60*60) 62#define SECDAY (24*SECHR) 63#endif /* sgi */ 64 65# define DATE_PROTO "udp" 66# define DATE_PORT "time" 67 68 69int sock; 70int sock_raw; 71char myname[MAXHOSTNAMELEN]; 72struct hostent *hp; 73struct sockaddr_in server; 74struct sockaddr_in dayaddr; 75extern int measure_delta; 76 77void bytenetorder(struct tsp *); 78void bytehostorder(struct tsp *); 79 80 81#define BU (2208988800UL) /* seconds before UNIX epoch */ 82 83 84/* compute the difference between our date and another machine 85 */ 86static int /* difference in days from our time */ 87daydiff(hostname) 88 char *hostname; 89{ 90 int i; 91 int trials; 92 struct timeval tout, now; 93 fd_set ready; 94 struct sockaddr from; 95 int fromlen; 96 unsigned long sec; 97 98 99 /* wait 2 seconds between 10 tries */ 100 tout.tv_sec = 2; 101 tout.tv_usec = 0; 102 for (trials = 0; trials < 10; trials++) { 103 /* ask for the time */ 104 sec = 0; 105 if (sendto(sock, &sec, sizeof(sec), 0, 106 (struct sockaddr*)&dayaddr, sizeof(dayaddr)) < 0) { 107 warn("sendto(sock)"); 108 return 0; 109 } 110 111 for (;;) { 112 FD_ZERO(&ready); 113 FD_SET(sock, &ready); 114 i = select(sock+1, &ready, (fd_set *)0, 115 (fd_set *)0, &tout); 116 if (i < 0) { 117 if (errno == EINTR) 118 continue; 119 warn("select(date read)"); 120 return 0; 121 } 122 if (0 == i) 123 break; 124 125 fromlen = sizeof(from); 126 if (recvfrom(sock,&sec,sizeof(sec),0, 127 &from,&fromlen) < 0) { 128 warn("recvfrom(date read)"); 129 return 0; 130 } 131 132 sec = ntohl(sec); 133 if (sec < BU) { 134 warnx("%s says it is before 1970: %lu", 135 hostname, sec); 136 return 0; 137 } 138 sec -= BU; 139 140 (void)gettimeofday(&now, (struct timezone*)0); 141 return (sec - now.tv_sec); 142 } 143 } 144 145 /* if we get here, we tried too many times */ 146 warnx("%s will not tell us the date", hostname); 147 return 0; 148} 149 150 151/* 152 * Clockdiff computes the difference between the time of the machine on 153 * which it is called and the time of the machines given as argument. 154 * The time differences measured by clockdiff are obtained using a sequence 155 * of ICMP TSTAMP messages which are returned to the sender by the IP module 156 * in the remote machine. 157 * In order to compare clocks of machines in different time zones, the time 158 * is transmitted (as a 32-bit value) in milliseconds since midnight UT. 159 * If a hosts uses a different time format, it should set the high order 160 * bit of the 32-bit quantity it transmits. 161 * However, VMS apparently transmits the time in milliseconds since midnight 162 * local time (rather than GMT) without setting the high order bit. 163 * Furthermore, it does not understand daylight-saving time. This makes 164 * clockdiff behaving inconsistently with hosts running VMS. 165 * 166 * In order to reduce the sensitivity to the variance of message transmission 167 * time, clockdiff sends a sequence of messages. Yet, measures between 168 * two `distant' hosts can be affected by a small error. The error can, 169 * however, be reduced by increasing the number of messages sent in each 170 * measurement. 171 */ 172void 173clockdiff(argc, argv) 174 int argc; 175 char *argv[]; 176{ 177 int measure_status; 178 extern int measure(u_long, u_long, char *, struct sockaddr_in*, int); 179 register int avg_cnt; 180 register long avg; 181 struct servent *sp; 182 183 if (argc < 2) { 184 printf("usage: timedc clockdiff host ...\n"); 185 return; 186 } 187 188 if (gethostname(myname, sizeof(myname) - 1) < 0) 189 err(1, "gethostname"); 190 191 /* get the address for the date ready */ 192 sp = getservbyname(DATE_PORT, DATE_PROTO); 193 if (!sp) { 194 warnx("%s/%s is an unknown service", DATE_PORT, DATE_PROTO); 195 dayaddr.sin_port = 0; 196 } else { 197 dayaddr.sin_port = sp->s_port; 198 } 199 200 while (argc > 1) { 201 argc--; argv++; 202 hp = gethostbyname(*argv); 203 if (hp == NULL) { 204 warnx("%s: %s", *argv, hstrerror(h_errno)); 205 continue; 206 } 207 208 server.sin_family = hp->h_addrtype; 209 bcopy(hp->h_addr, &server.sin_addr.s_addr, hp->h_length); 210 for (avg_cnt = 0, avg = 0; avg_cnt < 16; avg_cnt++) { 211 measure_status = measure(10000,100, *argv, &server, 1); 212 if (measure_status != GOOD) 213 break; 214 avg += measure_delta; 215 } 216 if (measure_status == GOOD) 217 measure_delta = avg/avg_cnt; 218 219 switch (measure_status) { 220 case HOSTDOWN: 221 printf("%s is down\n", hp->h_name); 222 continue; 223 case NONSTDTIME: 224 printf("%s transmitts a non-standard time format\n", 225 hp->h_name); 226 continue; 227 case UNREACHABLE: 228 printf("%s is unreachable\n", hp->h_name); 229 continue; 230 } 231 232 /* 233 * Try to get the date only after using ICMP timestamps to 234 * get the time. This is because the date protocol 235 * is optional. 236 */ 237 if (dayaddr.sin_port != 0) { 238 dayaddr.sin_family = hp->h_addrtype; 239 bcopy(hp->h_addr, &dayaddr.sin_addr.s_addr, 240 hp->h_length); 241 avg = daydiff(*argv); 242 if (avg > SECDAY) { 243 printf("time on %s is %ld days ahead %s\n", 244 hp->h_name, avg/SECDAY, myname); 245 continue; 246 } else if (avg < -SECDAY) { 247 printf("time on %s is %ld days behind %s\n", 248 hp->h_name, -avg/SECDAY, myname); 249 continue; 250 } 251 } 252 253 if (measure_delta > 0) { 254 printf("time on %s is %d ms. ahead of time on %s\n", 255 hp->h_name, measure_delta, myname); 256 } else if (measure_delta == 0) { 257 printf("%s and %s have the same time\n", 258 hp->h_name, myname); 259 } else { 260 printf("time on %s is %d ms. behind time on %s\n", 261 hp->h_name, -measure_delta, myname); 262 } 263 } 264 return; 265} 266 267 268/* 269 * finds location of master timedaemon 270 */ 271void 272msite(argc, argv) 273 int argc; 274 char *argv[]; 275{ 276 int cc; 277 fd_set ready; 278 struct sockaddr_in dest; 279 int i, length; 280 struct sockaddr_in from; 281 struct timeval tout; 282 struct tsp msg; 283 struct servent *srvp; 284 char *tgtname; 285 286 if (argc < 1) { 287 printf("usage: timedc msite [host ...]\n"); 288 return; 289 } 290 291 srvp = getservbyname("timed", "udp"); 292 if (srvp == 0) { 293 warnx("udp/timed: unknown service"); 294 return; 295 } 296 dest.sin_port = srvp->s_port; 297 dest.sin_family = AF_INET; 298 299 if (gethostname(myname, sizeof(myname) - 1) < 0) 300 err(1, "gethostname"); 301 i = 1; 302 do { 303 tgtname = (i >= argc) ? myname : argv[i]; 304 hp = gethostbyname(tgtname); 305 if (hp == 0) { 306 warnx("%s: %s", tgtname, hstrerror(h_errno)); 307 continue; 308 } 309 bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length); 310 311 (void)strlcpy(msg.tsp_name, myname, sizeof(msg.tsp_name)); 312 msg.tsp_type = TSP_MSITE; 313 msg.tsp_vers = TSPVERSION; 314 bytenetorder(&msg); 315 if (sendto(sock, &msg, sizeof(struct tsp), 0, 316 (struct sockaddr*)&dest, 317 sizeof(struct sockaddr)) < 0) { 318 warn("sendto"); 319 continue; 320 } 321 322 tout.tv_sec = 15; 323 tout.tv_usec = 0; 324 FD_ZERO(&ready); 325 FD_SET(sock, &ready); 326 if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, 327 &tout)) { 328 length = sizeof(from); 329 cc = recvfrom(sock, &msg, sizeof(struct tsp), 0, 330 (struct sockaddr *)&from, &length); 331 if (cc < 0) { 332 warn("recvfrom"); 333 continue; 334 } 335 /* 336 * The 4.3BSD protocol spec had a 32-byte tsp_name field, and 337 * this is still OS-dependent. Demand that the packet is at 338 * least long enough to hold a 4.3BSD packet. 339 */ 340 if (cc < (sizeof(struct tsp) - MAXHOSTNAMELEN + 32)) { 341 fprintf(stderr, 342 "short packet (%u/%u bytes) from %s\n", 343 cc, sizeof(struct tsp) - MAXHOSTNAMELEN + 32, 344 inet_ntoa(from.sin_addr)); 345 continue; 346 } 347 bytehostorder(&msg); 348 if (msg.tsp_type == TSP_ACK) { 349 printf("master timedaemon at %s is %s\n", 350 tgtname, msg.tsp_name); 351 } else { 352 if (msg.tsp_type >= TSPTYPENUMBER) 353 printf("unknown ack received: %u\n", 354 msg.tsp_type); 355 else 356 printf("wrong ack received: %s\n", 357 tsptype[msg.tsp_type]); 358 } 359 } else { 360 printf("communication error with %s\n", tgtname); 361 } 362 } while (++i < argc); 363} 364 365/* 366 * quits timedc 367 */ 368void 369quit() 370{ 371 exit(0); 372} 373 374 375/* 376 * Causes the election timer to expire on the selected hosts 377 * It sends just one udp message per machine, relying on 378 * reliability of communication channel. 379 */ 380void 381testing(argc, argv) 382 int argc; 383 char *argv[]; 384{ 385 struct servent *srvp; 386 struct sockaddr_in sin; 387 struct tsp msg; 388 389 if (argc < 2) { 390 printf("usage: timedc election host1 [host2 ...]\n"); 391 return; 392 } 393 394 srvp = getservbyname("timed", "udp"); 395 if (srvp == 0) { 396 warnx("udp/timed: unknown service"); 397 return; 398 } 399 400 while (argc > 1) { 401 argc--; argv++; 402 hp = gethostbyname(*argv); 403 if (hp == NULL) { 404 warnx("%s: %s", *argv, hstrerror(h_errno)); 405 argc--; argv++; 406 continue; 407 } 408 sin.sin_port = srvp->s_port; 409 sin.sin_family = hp->h_addrtype; 410 bcopy(hp->h_addr, &sin.sin_addr.s_addr, hp->h_length); 411 412 msg.tsp_type = TSP_TEST; 413 msg.tsp_vers = TSPVERSION; 414 if (gethostname(myname, sizeof(myname) - 1) < 0) 415 err(1, "gethostname"); 416 (void)strlcpy(msg.tsp_name, myname, sizeof(msg.tsp_name)); 417 bytenetorder(&msg); 418 if (sendto(sock, &msg, sizeof(struct tsp), 0, 419 (struct sockaddr*)&sin, 420 sizeof(struct sockaddr)) < 0) { 421 warn("sendto"); 422 } 423 } 424} 425 426 427/* 428 * Enables or disables tracing on local timedaemon 429 */ 430void 431tracing(argc, argv) 432 int argc; 433 char *argv[]; 434{ 435 int onflag; 436 int length; 437 int cc; 438 fd_set ready; 439 struct sockaddr_in dest; 440 struct sockaddr_in from; 441 struct timeval tout; 442 struct tsp msg; 443 struct servent *srvp; 444 445 if (argc != 2) { 446 printf("usage: timedc trace { on | off }\n"); 447 return; 448 } 449 450 srvp = getservbyname("timed", "udp"); 451 if (srvp == 0) { 452 warnx("udp/timed: unknown service"); 453 return; 454 } 455 dest.sin_port = srvp->s_port; 456 dest.sin_family = AF_INET; 457 458 if (gethostname(myname, sizeof(myname) - 1) < 0) 459 err(1, "gethostname"); 460 hp = gethostbyname(myname); 461 bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length); 462 463 if (strcmp(argv[1], "on") == 0) { 464 msg.tsp_type = TSP_TRACEON; 465 onflag = ON; 466 } else { 467 msg.tsp_type = TSP_TRACEOFF; 468 onflag = OFF; 469 } 470 471 (void)strcpy(msg.tsp_name, myname); 472 msg.tsp_vers = TSPVERSION; 473 bytenetorder(&msg); 474 if (sendto(sock, &msg, sizeof(struct tsp), 0, 475 (struct sockaddr*)&dest, sizeof(struct sockaddr)) < 0) { 476 warn("sendto"); 477 return; 478 } 479 480 tout.tv_sec = 5; 481 tout.tv_usec = 0; 482 FD_ZERO(&ready); 483 FD_SET(sock, &ready); 484 if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) { 485 length = sizeof(from); 486 cc = recvfrom(sock, &msg, sizeof(struct tsp), 0, 487 (struct sockaddr *)&from, &length); 488 if (cc < 0) { 489 warn("recvfrom"); 490 return; 491 } 492 /* 493 * The 4.3BSD protocol spec had a 32-byte tsp_name field, and 494 * this is still OS-dependent. Demand that the packet is at 495 * least long enough to hold a 4.3BSD packet. 496 */ 497 if (cc < (sizeof(struct tsp) - MAXHOSTNAMELEN + 32)) { 498 fprintf(stderr, "short packet (%u/%u bytes) from %s\n", 499 cc, sizeof(struct tsp) - MAXHOSTNAMELEN + 32, 500 inet_ntoa(from.sin_addr)); 501 return; 502 } 503 bytehostorder(&msg); 504 if (msg.tsp_type == TSP_ACK) 505 if (onflag) 506 printf("timed tracing enabled\n"); 507 else 508 printf("timed tracing disabled\n"); 509 else { 510 if (msg.tsp_type >= TSPTYPENUMBER) 511 printf("unknown ack received: %u\n", 512 msg.tsp_type); 513 else 514 printf("wrong ack received: %s\n", 515 tsptype[msg.tsp_type]); 516 } 517 } else 518 printf("communication error\n"); 519} 520 521int 522priv_resources() 523{ 524 int port; 525 struct sockaddr_in sin; 526 527 sock = socket(AF_INET, SOCK_DGRAM, 0); 528 if (sock < 0) { 529 warn("opening socket"); 530 return(-1); 531 } 532 533 sin.sin_family = AF_INET; 534 sin.sin_addr.s_addr = 0; 535 for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) { 536 sin.sin_port = htons((u_short)port); 537 if (bind(sock, (struct sockaddr*)&sin, sizeof (sin)) >= 0) 538 break; 539 if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) { 540 warn("bind"); 541 (void) close(sock); 542 return(-1); 543 } 544 } 545 if (port == IPPORT_RESERVED / 2) { 546 warnx("all reserved ports in use"); 547 (void) close(sock); 548 return(-1); 549 } 550 551 sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 552 if (sock_raw < 0) { 553 warn("opening raw socket"); 554 (void) close(sock); 555 return(-1); 556 } 557 return(1); 558} 559