cmds.c revision 30642
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 "$Id$"; 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 (void)gethostname(myname,sizeof(myname)); 189 190 /* get the address for the date ready */ 191 sp = getservbyname(DATE_PORT, DATE_PROTO); 192 if (!sp) { 193 warnx("%s/%s is an unknown service", DATE_PORT, DATE_PROTO); 194 dayaddr.sin_port = 0; 195 } else { 196 dayaddr.sin_port = sp->s_port; 197 } 198 199 while (argc > 1) { 200 argc--; argv++; 201 hp = gethostbyname(*argv); 202 if (hp == NULL) { 203 warnx("%s: %s", *argv, hstrerror(h_errno)); 204 continue; 205 } 206 207 server.sin_family = hp->h_addrtype; 208 bcopy(hp->h_addr, &server.sin_addr.s_addr, hp->h_length); 209 for (avg_cnt = 0, avg = 0; avg_cnt < 16; avg_cnt++) { 210 measure_status = measure(10000,100, *argv, &server, 1); 211 if (measure_status != GOOD) 212 break; 213 avg += measure_delta; 214 } 215 if (measure_status == GOOD) 216 measure_delta = avg/avg_cnt; 217 218 switch (measure_status) { 219 case HOSTDOWN: 220 printf("%s is down\n", hp->h_name); 221 continue; 222 case NONSTDTIME: 223 printf("%s transmitts a non-standard time format\n", 224 hp->h_name); 225 continue; 226 case UNREACHABLE: 227 printf("%s is unreachable\n", hp->h_name); 228 continue; 229 } 230 231 /* 232 * Try to get the date only after using ICMP timestamps to 233 * get the time. This is because the date protocol 234 * is optional. 235 */ 236 if (dayaddr.sin_port != 0) { 237 dayaddr.sin_family = hp->h_addrtype; 238 bcopy(hp->h_addr, &dayaddr.sin_addr.s_addr, 239 hp->h_length); 240 avg = daydiff(*argv); 241 if (avg > SECDAY) { 242 printf("time on %s is %ld days ahead %s\n", 243 hp->h_name, avg/SECDAY, myname); 244 continue; 245 } else if (avg < -SECDAY) { 246 printf("time on %s is %ld days behind %s\n", 247 hp->h_name, -avg/SECDAY, myname); 248 continue; 249 } 250 } 251 252 if (measure_delta > 0) { 253 printf("time on %s is %d ms. ahead of time on %s\n", 254 hp->h_name, measure_delta, myname); 255 } else if (measure_delta == 0) { 256 printf("%s and %s have the same time\n", 257 hp->h_name, myname); 258 } else { 259 printf("time on %s is %d ms. behind time on %s\n", 260 hp->h_name, -measure_delta, myname); 261 } 262 } 263 return; 264} 265 266 267/* 268 * finds location of master timedaemon 269 */ 270void 271msite(argc, argv) 272 int argc; 273 char *argv[]; 274{ 275 int cc; 276 fd_set ready; 277 struct sockaddr_in dest; 278 int i, length; 279 struct sockaddr 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("udp/timed: unknown service"); 293 return; 294 } 295 dest.sin_port = srvp->s_port; 296 dest.sin_family = AF_INET; 297 298 (void)gethostname(myname, sizeof(myname)); 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)strncpy(msg.tsp_name, myname, sizeof msg.tsp_name-1); 310 msg.tsp_name[sizeof msg.tsp_name-1] = '\0'; 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(struct sockaddr); 328 cc = recvfrom(sock, &msg, sizeof(struct tsp), 0, 329 &from, &length); 330 if (cc < 0) { 331 warn("recvfrom"); 332 continue; 333 } 334 bytehostorder(&msg); 335 if (msg.tsp_type == TSP_ACK) { 336 printf("master timedaemon at %s is %s\n", 337 tgtname, msg.tsp_name); 338 } else { 339 printf("received wrong ack: %s\n", 340 tsptype[msg.tsp_type]); 341 } 342 } else { 343 printf("communication error with %s\n", tgtname); 344 } 345 } while (++i < argc); 346} 347 348/* 349 * quits timedc 350 */ 351void 352quit() 353{ 354 exit(0); 355} 356 357 358/* 359 * Causes the election timer to expire on the selected hosts 360 * It sends just one udp message per machine, relying on 361 * reliability of communication channel. 362 */ 363void 364testing(argc, argv) 365 int argc; 366 char *argv[]; 367{ 368 struct servent *srvp; 369 struct sockaddr_in sin; 370 struct tsp msg; 371 372 if (argc < 2) { 373 printf("usage: timedc election host1 [host2 ...]\n"); 374 return; 375 } 376 377 srvp = getservbyname("timed", "udp"); 378 if (srvp == 0) { 379 warnx("udp/timed: unknown service"); 380 return; 381 } 382 383 while (argc > 1) { 384 argc--; argv++; 385 hp = gethostbyname(*argv); 386 if (hp == NULL) { 387 warnx("%s: %s", *argv, hstrerror(h_errno)); 388 argc--; argv++; 389 continue; 390 } 391 sin.sin_port = srvp->s_port; 392 sin.sin_family = hp->h_addrtype; 393 bcopy(hp->h_addr, &sin.sin_addr.s_addr, hp->h_length); 394 395 msg.tsp_type = TSP_TEST; 396 msg.tsp_vers = TSPVERSION; 397 (void)gethostname(myname, sizeof(myname)); 398 (void)strncpy(msg.tsp_name, myname, sizeof(msg.tsp_name)); 399 bytenetorder(&msg); 400 if (sendto(sock, &msg, sizeof(struct tsp), 0, 401 (struct sockaddr*)&sin, 402 sizeof(struct sockaddr)) < 0) { 403 warn("sendto"); 404 } 405 } 406} 407 408 409/* 410 * Enables or disables tracing on local timedaemon 411 */ 412void 413tracing(argc, argv) 414 int argc; 415 char *argv[]; 416{ 417 int onflag; 418 int length; 419 int cc; 420 fd_set ready; 421 struct sockaddr_in dest; 422 struct sockaddr from; 423 struct timeval tout; 424 struct tsp msg; 425 struct servent *srvp; 426 427 if (argc != 2) { 428 printf("usage: timedc trace { on | off }\n"); 429 return; 430 } 431 432 srvp = getservbyname("timed", "udp"); 433 if (srvp == 0) { 434 warnx("udp/timed: unknown service"); 435 return; 436 } 437 dest.sin_port = srvp->s_port; 438 dest.sin_family = AF_INET; 439 440 (void)gethostname(myname,sizeof(myname)); 441 hp = gethostbyname(myname); 442 bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length); 443 444 if (strcmp(argv[1], "on") == 0) { 445 msg.tsp_type = TSP_TRACEON; 446 onflag = ON; 447 } else { 448 msg.tsp_type = TSP_TRACEOFF; 449 onflag = OFF; 450 } 451 452 (void)strncpy(msg.tsp_name, myname, sizeof msg.tsp_name-1); 453 msg.tsp_name[sizeof msg.tsp_name-1] = '\0'; 454 msg.tsp_vers = TSPVERSION; 455 bytenetorder(&msg); 456 if (sendto(sock, &msg, sizeof(struct tsp), 0, 457 (struct sockaddr*)&dest, sizeof(struct sockaddr)) < 0) { 458 warn("sendto"); 459 return; 460 } 461 462 tout.tv_sec = 5; 463 tout.tv_usec = 0; 464 FD_ZERO(&ready); 465 FD_SET(sock, &ready); 466 if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) { 467 length = sizeof(struct sockaddr); 468 cc = recvfrom(sock, &msg, sizeof(struct tsp), 0, 469 &from, &length); 470 if (cc < 0) { 471 warn("recvfrom"); 472 return; 473 } 474 bytehostorder(&msg); 475 if (msg.tsp_type == TSP_ACK) 476 if (onflag) 477 printf("timed tracing enabled\n"); 478 else 479 printf("timed tracing disabled\n"); 480 else 481 printf("wrong ack received: %s\n", 482 tsptype[msg.tsp_type]); 483 } else 484 printf("communication error\n"); 485} 486 487int 488priv_resources() 489{ 490 int port; 491 struct sockaddr_in sin; 492 493 sock = socket(AF_INET, SOCK_DGRAM, 0); 494 if (sock < 0) { 495 warn("opening socket"); 496 return(-1); 497 } 498 499 sin.sin_family = AF_INET; 500 sin.sin_addr.s_addr = 0; 501 for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) { 502 sin.sin_port = htons((u_short)port); 503 if (bind(sock, (struct sockaddr*)&sin, sizeof (sin)) >= 0) 504 break; 505 if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) { 506 warn("bind"); 507 (void) close(sock); 508 return(-1); 509 } 510 } 511 if (port == IPPORT_RESERVED / 2) { 512 warnx("all reserved ports in use"); 513 (void) close(sock); 514 return(-1); 515 } 516 517 sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 518 if (sock_raw < 0) { 519 warn("opening raw socket"); 520 (void) close(sock); 521 return(-1); 522 } 523 return(1); 524} 525