1*23785Sgusella /* 2*23785Sgusella * Copyright (c) 1983 Regents of the University of California. 3*23785Sgusella * All rights reserved. The Berkeley software License Agreement 4*23785Sgusella * specifies the terms and conditions for redistribution. 5*23785Sgusella */ 6*23785Sgusella 7*23785Sgusella #ifndef lint 8*23785Sgusella static char sccsid[] = "@(#)cmds.c 1.1 (Berkeley) 06/27/85"; 9*23785Sgusella #endif not lint 10*23785Sgusella 11*23785Sgusella #include "timedc.h" 12*23785Sgusella #include <netinet/in_systm.h> 13*23785Sgusella #include <netinet/ip.h> 14*23785Sgusella #include <netinet/ip_icmp.h> 15*23785Sgusella #define TSPTYPES 16*23785Sgusella #include <protocols/timed.h> 17*23785Sgusella #include <sys/file.h> 18*23785Sgusella 19*23785Sgusella #define OFF 0 20*23785Sgusella #define ON 1 21*23785Sgusella 22*23785Sgusella int id; 23*23785Sgusella int sock; 24*23785Sgusella int sock_raw; 25*23785Sgusella char hostname[32]; 26*23785Sgusella struct hostent *hp, *gethostbyname(); 27*23785Sgusella struct sockaddr_in server; 28*23785Sgusella extern int measure_delta; 29*23785Sgusella int bytenetorder(), bytehostorder(); 30*23785Sgusella char *strcpy(); 31*23785Sgusella 32*23785Sgusella /* 33*23785Sgusella * Clockdiff computes the difference between the time of the machine on 34*23785Sgusella * which it is called and the time of the machines given as argument. 35*23785Sgusella * The time differences measured by clockdiff are obtained using a sequence 36*23785Sgusella * of ICMP TSTAMP messages which are returned to the sender by the IP module 37*23785Sgusella * in the remote machine. 38*23785Sgusella * In order to compare clocks of machines in different time zones, the time 39*23785Sgusella * is transmitted (as a 32-bit value) in milliseconds since midnight UT. 40*23785Sgusella * If a hosts uses a different time format, it should set the high order 41*23785Sgusella * bit of the 32-bit quantity it transmits. 42*23785Sgusella * However, VMS apparently transmits the time in milliseconds since midnight 43*23785Sgusella * local time (rather than GMT) without setting the high order bit. 44*23785Sgusella * Furthermore, it does not understand daylight-saving time. This makes 45*23785Sgusella * clockdiff behaving inconsistently with hosts running VMS. 46*23785Sgusella * 47*23785Sgusella * In order to reduce the sensitivity to the variance of message transmission 48*23785Sgusella * time, clockdiff sends a sequence of messages. Yet, measures between 49*23785Sgusella * two `distant' hosts can be affected by a small error. The error can, however, 50*23785Sgusella * be reduced by increasing the number of messages sent in each measurement. 51*23785Sgusella */ 52*23785Sgusella 53*23785Sgusella clockdiff(argc, argv) 54*23785Sgusella int argc; 55*23785Sgusella char *argv[]; 56*23785Sgusella { 57*23785Sgusella int measure_status; 58*23785Sgusella struct timeval ack; 59*23785Sgusella int measure(); 60*23785Sgusella 61*23785Sgusella if(argc < 2) { 62*23785Sgusella printf("Usage: clockdiff host ... \n"); 63*23785Sgusella return; 64*23785Sgusella } 65*23785Sgusella 66*23785Sgusella id = getpid(); 67*23785Sgusella (void)gethostname(hostname,sizeof(hostname)); 68*23785Sgusella 69*23785Sgusella while (argc > 1) { 70*23785Sgusella argc--; argv++; 71*23785Sgusella hp = gethostbyname(*argv); 72*23785Sgusella if (hp == NULL) { 73*23785Sgusella printf("%s: unknown host\n", *argv); 74*23785Sgusella continue; 75*23785Sgusella } 76*23785Sgusella server.sin_family = hp->h_addrtype; 77*23785Sgusella bcopy(hp->h_addr, &(server.sin_addr.s_addr), hp->h_length); 78*23785Sgusella ack.tv_sec = 1; 79*23785Sgusella ack.tv_usec = 500000; 80*23785Sgusella if ((measure_status = measure(&ack, OFF)) < 0) { 81*23785Sgusella perror("measure"); 82*23785Sgusella return; 83*23785Sgusella } 84*23785Sgusella switch (measure_status) { 85*23785Sgusella 86*23785Sgusella case HOSTDOWN: 87*23785Sgusella printf("%s is down\n", hp->h_name); 88*23785Sgusella continue; 89*23785Sgusella break; 90*23785Sgusella case NONSTDTIME: 91*23785Sgusella printf("%s time transmitted in a non-standard format\n", hp->h_name); 92*23785Sgusella continue; 93*23785Sgusella break; 94*23785Sgusella case UNREACHABLE: 95*23785Sgusella printf("%s is unreachable\n", hp->h_name); 96*23785Sgusella continue; 97*23785Sgusella break; 98*23785Sgusella default: 99*23785Sgusella break; 100*23785Sgusella } 101*23785Sgusella 102*23785Sgusella if (measure_delta > 0) 103*23785Sgusella printf("time on %s is %d ms. ahead of time on %s\n", 104*23785Sgusella hp->h_name, measure_delta, 105*23785Sgusella hostname); 106*23785Sgusella else 107*23785Sgusella if (measure_delta == 0) 108*23785Sgusella printf("%s and %s have the same time\n", 109*23785Sgusella hp->h_name, hostname); 110*23785Sgusella else 111*23785Sgusella printf("time on %s is %d ms. behind time on %s\n", 112*23785Sgusella hp->h_name, -measure_delta, hostname); 113*23785Sgusella } 114*23785Sgusella return; 115*23785Sgusella } 116*23785Sgusella /* 117*23785Sgusella * finds location of master timedaemon 118*23785Sgusella */ 119*23785Sgusella 120*23785Sgusella msite(argc) 121*23785Sgusella int argc; 122*23785Sgusella { 123*23785Sgusella int length; 124*23785Sgusella int cc, ready, found; 125*23785Sgusella struct sockaddr_in dest; 126*23785Sgusella struct timeval tout; 127*23785Sgusella struct sockaddr_in from; 128*23785Sgusella struct tsp msg; 129*23785Sgusella struct servent *srvp; 130*23785Sgusella 131*23785Sgusella if (argc != 1) { 132*23785Sgusella printf("Usage: msite\n"); 133*23785Sgusella return; 134*23785Sgusella } 135*23785Sgusella 136*23785Sgusella (void) open("/etc/timed", O_WRONLY, 01700); 137*23785Sgusella if (errno != ETXTBSY) { 138*23785Sgusella printf("No timed on this machine\n"); 139*23785Sgusella return; 140*23785Sgusella } 141*23785Sgusella 142*23785Sgusella srvp = getservbyname("timed", "udp"); 143*23785Sgusella if (srvp == 0) { 144*23785Sgusella fprintf(stderr, "udp/timed: unknown service\n"); 145*23785Sgusella return; 146*23785Sgusella } 147*23785Sgusella dest.sin_port = srvp->s_port; 148*23785Sgusella dest.sin_family = AF_INET; 149*23785Sgusella 150*23785Sgusella (void)gethostname(hostname,sizeof(hostname)); 151*23785Sgusella hp = gethostbyname(hostname); 152*23785Sgusella if (hp == NULL) { 153*23785Sgusella perror("gethostbyname"); 154*23785Sgusella return; 155*23785Sgusella } 156*23785Sgusella bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length); 157*23785Sgusella 158*23785Sgusella (void)strcpy(msg.tsp_name, hostname); 159*23785Sgusella msg.tsp_type = TSP_MSITE; 160*23785Sgusella msg.tsp_vers = TSPVERSION; 161*23785Sgusella bytenetorder(&msg); 162*23785Sgusella length = sizeof(struct sockaddr_in); 163*23785Sgusella if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0, 164*23785Sgusella &dest, length) < 0) { 165*23785Sgusella perror("sendto"); 166*23785Sgusella return; 167*23785Sgusella } 168*23785Sgusella 169*23785Sgusella tout.tv_sec = 15; 170*23785Sgusella tout.tv_usec = 0; 171*23785Sgusella ready = 1<<sock; 172*23785Sgusella found = select(20, &ready, (int *)0, (int *)0, &tout); 173*23785Sgusella if (found) { 174*23785Sgusella length = sizeof(struct sockaddr_in); 175*23785Sgusella cc = recvfrom(sock, (char *)&msg, sizeof(struct tsp), 0, 176*23785Sgusella &from, &length); 177*23785Sgusella if (cc < 0) { 178*23785Sgusella perror("recvfrom"); 179*23785Sgusella return; 180*23785Sgusella } 181*23785Sgusella bytehostorder(&msg); 182*23785Sgusella if (msg.tsp_type == TSP_ACK) 183*23785Sgusella printf("master timedaemon runs on %s\n", msg.tsp_name); 184*23785Sgusella else 185*23785Sgusella printf("received wrong ack: %s\n", 186*23785Sgusella tsptype[msg.tsp_type]); 187*23785Sgusella } else 188*23785Sgusella printf("communication error\n"); 189*23785Sgusella } 190*23785Sgusella 191*23785Sgusella /* 192*23785Sgusella * quits timedc 193*23785Sgusella */ 194*23785Sgusella 195*23785Sgusella quit() 196*23785Sgusella { 197*23785Sgusella exit(0); 198*23785Sgusella } 199*23785Sgusella 200*23785Sgusella #define MAXH 4 /* max no. of hosts where election can occur */ 201*23785Sgusella 202*23785Sgusella /* 203*23785Sgusella * Causes the election timer to expire on the selected hosts 204*23785Sgusella * It sends just one udp message per machine, relying on 205*23785Sgusella * reliability of communication channel. 206*23785Sgusella */ 207*23785Sgusella 208*23785Sgusella testing(argc, argv) 209*23785Sgusella int argc; 210*23785Sgusella char *argv[]; 211*23785Sgusella { 212*23785Sgusella int length; 213*23785Sgusella int nhosts; 214*23785Sgusella struct servent *srvp; 215*23785Sgusella struct sockaddr_in sin[MAXH]; 216*23785Sgusella struct tsp msg; 217*23785Sgusella 218*23785Sgusella if(argc < 2) { 219*23785Sgusella printf("Usage: testing host ...\n"); 220*23785Sgusella return; 221*23785Sgusella } 222*23785Sgusella 223*23785Sgusella (void) open("/etc/timed", O_WRONLY, 01700); 224*23785Sgusella if (errno != ETXTBSY) { 225*23785Sgusella printf("No timed on this machine\n"); 226*23785Sgusella return; 227*23785Sgusella } 228*23785Sgusella 229*23785Sgusella srvp = getservbyname("timed", "udp"); 230*23785Sgusella if (srvp == 0) { 231*23785Sgusella fprintf(stderr, "udp/timed: unknown service\n"); 232*23785Sgusella return; 233*23785Sgusella } 234*23785Sgusella 235*23785Sgusella nhosts = 0; 236*23785Sgusella while (argc > 1) { 237*23785Sgusella argc--; argv++; 238*23785Sgusella hp = gethostbyname(*argv); 239*23785Sgusella if (hp == NULL) { 240*23785Sgusella printf("%s: unknown host %s\n", *argv); 241*23785Sgusella argc--; argv++; 242*23785Sgusella continue; 243*23785Sgusella } 244*23785Sgusella sin[nhosts].sin_port = srvp->s_port; 245*23785Sgusella sin[nhosts].sin_family = hp->h_addrtype; 246*23785Sgusella bcopy(hp->h_addr, &(sin[nhosts].sin_addr.s_addr), hp->h_length); 247*23785Sgusella if (++nhosts == MAXH) 248*23785Sgusella break; 249*23785Sgusella } 250*23785Sgusella 251*23785Sgusella msg.tsp_type = TSP_TEST; 252*23785Sgusella msg.tsp_vers = TSPVERSION; 253*23785Sgusella (void)gethostname(hostname, sizeof(hostname)); 254*23785Sgusella (void)strcpy(msg.tsp_name, hostname); 255*23785Sgusella bytenetorder(&msg); /* it is not really necessary here */ 256*23785Sgusella while (nhosts-- > 0) { 257*23785Sgusella length = sizeof(struct sockaddr_in); 258*23785Sgusella if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0, 259*23785Sgusella &sin[nhosts], length) < 0) { 260*23785Sgusella perror("sendto"); 261*23785Sgusella return; 262*23785Sgusella } 263*23785Sgusella } 264*23785Sgusella } 265*23785Sgusella 266*23785Sgusella /* 267*23785Sgusella * Enables or disables tracing on local timedaemon 268*23785Sgusella */ 269*23785Sgusella 270*23785Sgusella tracing(argc, argv) 271*23785Sgusella int argc; 272*23785Sgusella char *argv[]; 273*23785Sgusella { 274*23785Sgusella int onflag; 275*23785Sgusella int length; 276*23785Sgusella int cc, ready, found; 277*23785Sgusella struct sockaddr_in dest; 278*23785Sgusella struct timeval tout; 279*23785Sgusella struct sockaddr_in from; 280*23785Sgusella struct tsp msg; 281*23785Sgusella struct servent *srvp; 282*23785Sgusella 283*23785Sgusella if (argc != 2) { 284*23785Sgusella printf("Usage: tracing { on | off }\n"); 285*23785Sgusella return; 286*23785Sgusella } 287*23785Sgusella 288*23785Sgusella (void) open("/etc/timed", O_WRONLY, 01700); 289*23785Sgusella if (errno != ETXTBSY) { 290*23785Sgusella printf("No timed on this machine\n"); 291*23785Sgusella return; 292*23785Sgusella } 293*23785Sgusella 294*23785Sgusella srvp = getservbyname("timed", "udp"); 295*23785Sgusella if (srvp == 0) { 296*23785Sgusella fprintf(stderr, "udp/timed: unknown service\n"); 297*23785Sgusella return; 298*23785Sgusella } 299*23785Sgusella dest.sin_port = srvp->s_port; 300*23785Sgusella dest.sin_family = AF_INET; 301*23785Sgusella 302*23785Sgusella (void)gethostname(hostname,sizeof(hostname)); 303*23785Sgusella hp = gethostbyname(hostname); 304*23785Sgusella bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length); 305*23785Sgusella 306*23785Sgusella if (strcmp(argv[1], "on") == 0) { 307*23785Sgusella msg.tsp_type = TSP_TRACEON; 308*23785Sgusella onflag = ON; 309*23785Sgusella } else { 310*23785Sgusella msg.tsp_type = TSP_TRACEOFF; 311*23785Sgusella onflag = OFF; 312*23785Sgusella } 313*23785Sgusella 314*23785Sgusella (void)strcpy(msg.tsp_name, hostname); 315*23785Sgusella msg.tsp_vers = TSPVERSION; 316*23785Sgusella bytenetorder(&msg); 317*23785Sgusella length = sizeof(struct sockaddr_in); 318*23785Sgusella if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0, 319*23785Sgusella &dest, length) < 0) { 320*23785Sgusella perror("sendto"); 321*23785Sgusella return; 322*23785Sgusella } 323*23785Sgusella 324*23785Sgusella tout.tv_sec = 5; 325*23785Sgusella tout.tv_usec = 0; 326*23785Sgusella ready = 1<<sock; 327*23785Sgusella found = select(20, &ready, (int *)0, (int *)0, &tout); 328*23785Sgusella if (found) { 329*23785Sgusella length = sizeof(struct sockaddr_in); 330*23785Sgusella cc = recvfrom(sock, (char *)&msg, sizeof(struct tsp), 0, 331*23785Sgusella &from, &length); 332*23785Sgusella if (cc < 0) { 333*23785Sgusella perror("recvfrom"); 334*23785Sgusella return; 335*23785Sgusella } 336*23785Sgusella bytehostorder(&msg); 337*23785Sgusella if (msg.tsp_type == TSP_ACK) 338*23785Sgusella if (onflag) 339*23785Sgusella printf("timed tracing enabled\n"); 340*23785Sgusella else 341*23785Sgusella printf("timed tracing disabled\n"); 342*23785Sgusella else 343*23785Sgusella printf("wrong ack received: %s\n", 344*23785Sgusella tsptype[msg.tsp_type]); 345*23785Sgusella } else 346*23785Sgusella printf("communication error\n"); 347*23785Sgusella } 348*23785Sgusella 349*23785Sgusella priv_resources() 350*23785Sgusella { 351*23785Sgusella int port; 352*23785Sgusella struct sockaddr_in sin; 353*23785Sgusella 354*23785Sgusella sock = socket(AF_INET, SOCK_DGRAM, 0); 355*23785Sgusella if (sock < 0) { 356*23785Sgusella perror("opening socket"); 357*23785Sgusella return(-1); 358*23785Sgusella } 359*23785Sgusella 360*23785Sgusella sin.sin_family = AF_INET; 361*23785Sgusella sin.sin_addr.s_addr = 0; 362*23785Sgusella for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) { 363*23785Sgusella sin.sin_port = htons((u_short)port); 364*23785Sgusella if (bind(sock, (struct sockaddr *)&sin, sizeof (sin)) >= 0) 365*23785Sgusella break; 366*23785Sgusella if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) { 367*23785Sgusella perror("bind"); 368*23785Sgusella (void) close(sock); 369*23785Sgusella return(-1); 370*23785Sgusella } 371*23785Sgusella } 372*23785Sgusella if (port == IPPORT_RESERVED / 2) { 373*23785Sgusella fprintf(stderr, "all reserved ports in use\n"); 374*23785Sgusella (void) close(sock); 375*23785Sgusella return(-1); 376*23785Sgusella } 377*23785Sgusella 378*23785Sgusella sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 379*23785Sgusella if (sock_raw < 0) { 380*23785Sgusella perror("opening raw socket"); 381*23785Sgusella (void) close(sock_raw); 382*23785Sgusella return(-1); 383*23785Sgusella } 384*23785Sgusella return(1); 385*23785Sgusella } 386