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