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: src/usr.sbin/timed/timedc/cmds.c,v 1.13 2004/02/04 21:59:29 johan Exp $"); 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 socklen_t 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 transmits 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; 278 socklen_t length; 279 struct sockaddr_in from; 280 struct timeval tout; 281 struct tsp msg; 282 struct servent *srvp; 283 char *tgtname; 284 285 if (argc < 1) { 286 printf("usage: timedc msite [host ...]\n"); 287 return; 288 } 289 290 srvp = getservbyname("timed", "udp"); 291 if (srvp == 0) { 292 warnx("timed/udp: unknown service"); 293 return; 294 } 295 dest.sin_port = srvp->s_port; 296 dest.sin_family = AF_INET; 297 298 if (gethostname(myname, sizeof(myname) - 1) < 0) 299 err(1, "gethostname"); 300 i = 1; 301 do { 302 tgtname = (i >= argc) ? myname : argv[i]; 303 hp = gethostbyname(tgtname); 304 if (hp == 0) { 305 warnx("%s: %s", tgtname, hstrerror(h_errno)); 306 continue; 307 } 308 bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length); 309 310 (void)strlcpy(msg.tsp_name, myname, sizeof(msg.tsp_name)); 311 msg.tsp_type = TSP_MSITE; 312 msg.tsp_vers = TSPVERSION; 313 bytenetorder(&msg); 314 if (sendto(sock, &msg, sizeof(struct tsp), 0, 315 (struct sockaddr*)&dest, 316 sizeof(struct sockaddr)) < 0) { 317 warn("sendto"); 318 continue; 319 } 320 321 tout.tv_sec = 15; 322 tout.tv_usec = 0; 323 FD_ZERO(&ready); 324 FD_SET(sock, &ready); 325 if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, 326 &tout)) { 327 length = sizeof(from); 328 cc = recvfrom(sock, &msg, sizeof(struct tsp), 0, 329 (struct sockaddr *)&from, &length); 330 if (cc < 0) { 331 warn("recvfrom"); 332 continue; 333 } 334 /* 335 * The 4.3BSD protocol spec had a 32-byte tsp_name field, and 336 * this is still OS-dependent. Demand that the packet is at 337 * least long enough to hold a 4.3BSD packet. 338 */ 339 if (cc < (sizeof(struct tsp) - MAXHOSTNAMELEN + 32)) { 340 fprintf(stderr, 341 "short packet (%u/%lu bytes) from %s\n", 342 cc, sizeof(struct tsp) - MAXHOSTNAMELEN + 32, 343 inet_ntoa(from.sin_addr)); 344 continue; 345 } 346 bytehostorder(&msg); 347 if (msg.tsp_type == TSP_ACK) { 348 printf("master timedaemon at %s is %s\n", 349 tgtname, msg.tsp_name); 350 } else { 351 if (msg.tsp_type >= TSPTYPENUMBER) 352 printf("unknown ack received: %u\n", 353 msg.tsp_type); 354 else 355 printf("wrong ack received: %s\n", 356 tsptype[msg.tsp_type]); 357 } 358 } else { 359 printf("communication error with %s\n", tgtname); 360 } 361 } while (++i < argc); 362} 363 364/* 365 * quits timedc 366 */ 367void 368quit() 369{ 370 exit(0); 371} 372 373 374/* 375 * Causes the election timer to expire on the selected hosts 376 * It sends just one udp message per machine, relying on 377 * reliability of communication channel. 378 */ 379void 380testing(argc, argv) 381 int argc; 382 char *argv[]; 383{ 384 struct servent *srvp; 385 struct sockaddr_in sin; 386 struct tsp msg; 387 388 if (argc < 2) { 389 printf("usage: timedc election host1 [host2 ...]\n"); 390 return; 391 } 392 393 srvp = getservbyname("timed", "udp"); 394 if (srvp == 0) { 395 warnx("timed/udp: unknown service"); 396 return; 397 } 398 399 while (argc > 1) { 400 argc--; argv++; 401 hp = gethostbyname(*argv); 402 if (hp == NULL) { 403 warnx("%s: %s", *argv, hstrerror(h_errno)); 404 argc--; argv++; 405 continue; 406 } 407 sin.sin_port = srvp->s_port; 408 sin.sin_family = hp->h_addrtype; 409 bcopy(hp->h_addr, &sin.sin_addr.s_addr, hp->h_length); 410 411 msg.tsp_type = TSP_TEST; 412 msg.tsp_vers = TSPVERSION; 413 if (gethostname(myname, sizeof(myname) - 1) < 0) 414 err(1, "gethostname"); 415 (void)strlcpy(msg.tsp_name, myname, sizeof(msg.tsp_name)); 416 bytenetorder(&msg); 417 if (sendto(sock, &msg, sizeof(struct tsp), 0, 418 (struct sockaddr*)&sin, 419 sizeof(struct sockaddr)) < 0) { 420 warn("sendto"); 421 } 422 } 423} 424 425 426/* 427 * Enables or disables tracing on local timedaemon 428 */ 429void 430tracing(argc, argv) 431 int argc; 432 char *argv[]; 433{ 434 int onflag; 435 socklen_t length; 436 int cc; 437 fd_set ready; 438 struct sockaddr_in dest; 439 struct sockaddr_in from; 440 struct timeval tout; 441 struct tsp msg; 442 struct servent *srvp; 443 444 if (argc != 2) { 445 printf("usage: timedc trace { on | off }\n"); 446 return; 447 } 448 449 srvp = getservbyname("timed", "udp"); 450 if (srvp == 0) { 451 warnx("timed/udp: unknown service"); 452 return; 453 } 454 dest.sin_port = srvp->s_port; 455 dest.sin_family = AF_INET; 456 457 if (gethostname(myname, sizeof(myname) - 1) < 0) 458 err(1, "gethostname"); 459 hp = gethostbyname(myname); 460 bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length); 461 462 if (strcmp(argv[1], "on") == 0) { 463 msg.tsp_type = TSP_TRACEON; 464 onflag = ON; 465 } else { 466 msg.tsp_type = TSP_TRACEOFF; 467 onflag = OFF; 468 } 469 470 (void)strcpy(msg.tsp_name, myname); 471 msg.tsp_vers = TSPVERSION; 472 bytenetorder(&msg); 473 if (sendto(sock, &msg, sizeof(struct tsp), 0, 474 (struct sockaddr*)&dest, sizeof(struct sockaddr)) < 0) { 475 warn("sendto"); 476 return; 477 } 478 479 tout.tv_sec = 5; 480 tout.tv_usec = 0; 481 FD_ZERO(&ready); 482 FD_SET(sock, &ready); 483 if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) { 484 length = sizeof(from); 485 cc = recvfrom(sock, &msg, sizeof(struct tsp), 0, 486 (struct sockaddr *)&from, &length); 487 if (cc < 0) { 488 warn("recvfrom"); 489 return; 490 } 491 /* 492 * The 4.3BSD protocol spec had a 32-byte tsp_name field, and 493 * this is still OS-dependent. Demand that the packet is at 494 * least long enough to hold a 4.3BSD packet. 495 */ 496 if (cc < (sizeof(struct tsp) - MAXHOSTNAMELEN + 32)) { 497 fprintf(stderr, "short packet (%u/%lu bytes) from %s\n", 498 cc, sizeof(struct tsp) - MAXHOSTNAMELEN + 32, 499 inet_ntoa(from.sin_addr)); 500 return; 501 } 502 bytehostorder(&msg); 503 if (msg.tsp_type == TSP_ACK) 504 if (onflag) 505 printf("timed tracing enabled\n"); 506 else 507 printf("timed tracing disabled\n"); 508 else { 509 if (msg.tsp_type >= TSPTYPENUMBER) 510 printf("unknown ack received: %u\n", 511 msg.tsp_type); 512 else 513 printf("wrong ack received: %s\n", 514 tsptype[msg.tsp_type]); 515 } 516 } else 517 printf("communication error\n"); 518} 519 520int 521priv_resources() 522{ 523 int port; 524 struct sockaddr_in sin; 525 526 sock = socket(AF_INET, SOCK_DGRAM, 0); 527 if (sock < 0) { 528 warn("opening socket"); 529 return(-1); 530 } 531 532 sin.sin_family = AF_INET; 533 sin.sin_addr.s_addr = 0; 534 for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) { 535 sin.sin_port = htons((u_short)port); 536 if (bind(sock, (struct sockaddr*)&sin, sizeof (sin)) >= 0) 537 break; 538 if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) { 539 warn("bind"); 540 (void) close(sock); 541 return(-1); 542 } 543 } 544 if (port == IPPORT_RESERVED / 2) { 545 warnx("all reserved ports in use"); 546 (void) close(sock); 547 return(-1); 548 } 549 550 sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 551 if (sock_raw < 0) { 552 warn("opening raw socket"); 553 (void) close(sock); 554 return(-1); 555 } 556 return(1); 557} 558