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