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