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