Blame clockdiff.c

Packit Service 6f2e62
/*-
Packit Service 6f2e62
 * Copyright (c) 1985, 1993
Packit Service 6f2e62
 *	The Regents of the University of California.  All rights reserved.
Packit Service 6f2e62
 *
Packit Service 6f2e62
 * Redistribution and use in source and binary forms, with or without
Packit Service 6f2e62
 * modification, are permitted provided that the following conditions
Packit Service 6f2e62
 * are met:
Packit Service 6f2e62
 * 1. Redistributions of source code must retain the above copyright
Packit Service 6f2e62
 *    notice, this list of conditions and the following disclaimer.
Packit Service 6f2e62
 * 2. Redistributions in binary form must reproduce the above copyright
Packit Service 6f2e62
 *    notice, this list of conditions and the following disclaimer in the
Packit Service 6f2e62
 *    documentation and/or other materials provided with the distribution.
Packit Service 6f2e62
 * 3. Neither the name of the University nor the names of its contributors
Packit Service 6f2e62
 *    may be used to endorse or promote products derived from this software
Packit Service 6f2e62
 *    without specific prior written permission.
Packit Service 6f2e62
 *
Packit Service 6f2e62
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
Packit Service 6f2e62
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
Packit Service 6f2e62
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit Service 6f2e62
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
Packit Service 6f2e62
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
Packit Service 6f2e62
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
Packit Service 6f2e62
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
Packit Service 6f2e62
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
Packit Service 6f2e62
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
Packit Service 6f2e62
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
Packit Service 6f2e62
 * SUCH DAMAGE.
Packit Service 6f2e62
 */
Packit Service 6f2e62
Packit Service 6f2e62
#include <time.h>
Packit Service 6f2e62
#include <sys/types.h>
Packit Service 6f2e62
#include <sys/param.h>
Packit Service 6f2e62
#include <stdio.h>
Packit Service 6f2e62
#include <unistd.h>
Packit Service 6f2e62
#include <stdlib.h>
Packit Service 6f2e62
#include <math.h>
Packit Service 6f2e62
#include <string.h>
Packit Service 6f2e62
#include <sys/time.h>
Packit Service 6f2e62
#include <sys/timex.h>
Packit Service 6f2e62
#include <errno.h>
Packit Service 6f2e62
#include <sys/socket.h>
Packit Service 6f2e62
#include <netinet/in.h>
Packit Service 6f2e62
#include <netinet/ip.h>
Packit Service 6f2e62
#include <netinet/ip_icmp.h>
Packit Service 6f2e62
#define TSPTYPES
Packit Service 6f2e62
#include <fcntl.h>
Packit Service 6f2e62
#include <netdb.h>
Packit Service 6f2e62
#include <arpa/inet.h>
Packit Service 6f2e62
#include <errno.h>
Packit Service 6f2e62
#include <linux/types.h>
Packit Service 6f2e62
#ifdef CAPABILITIES
Packit Service 6f2e62
#include <sys/capability.h>
Packit Service 6f2e62
#endif
Packit Service 6f2e62
Packit Service 6f2e62
void usage(void) __attribute__((noreturn));
Packit Service 6f2e62
Packit Service 6f2e62
#define MAX_HOSTNAMELEN	NI_MAXHOST
Packit Service 6f2e62
Packit Service 6f2e62
/*
Packit Service 6f2e62
 * Checksum routine for Internet Protocol family headers.
Packit Service 6f2e62
 *
Packit Service 6f2e62
 * This routine is very heavily used in the network
Packit Service 6f2e62
 * code and should be modified for each CPU to be as fast as possible.
Packit Service 6f2e62
 *
Packit Service 6f2e62
 * This implementation is TAHOE version.
Packit Service 6f2e62
 */
Packit Service 6f2e62
Packit Service 6f2e62
#undef	ADDCARRY
Packit Service 6f2e62
#define ADDCARRY(sum) { \
Packit Service 6f2e62
	if (sum & 0xffff0000) {	\
Packit Service 6f2e62
		sum &= 0xffff; \
Packit Service 6f2e62
		sum++; \
Packit Service 6f2e62
	} \
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
int in_cksum(unsigned short *addr, int len)
Packit Service 6f2e62
{
Packit Service 6f2e62
	union word {
Packit Service 6f2e62
		char	c[2];
Packit Service 6f2e62
		unsigned short	s;
Packit Service 6f2e62
	} u;
Packit Service 6f2e62
	int sum = 0;
Packit Service 6f2e62
Packit Service 6f2e62
	while (len > 0) {
Packit Service 6f2e62
		/*
Packit Service 6f2e62
		 * add by words.
Packit Service 6f2e62
		 */
Packit Service 6f2e62
		while ((len -= 2) >= 0) {
Packit Service 6f2e62
			if ((unsigned long)addr & 0x1) {
Packit Service 6f2e62
				/* word is not aligned */
Packit Service 6f2e62
				u.c[0] = *(char *)addr;
Packit Service 6f2e62
				u.c[1] = *((char *)addr+1);
Packit Service 6f2e62
				sum += u.s;
Packit Service 6f2e62
				addr++;
Packit Service 6f2e62
			} else
Packit Service 6f2e62
				sum += *addr++;
Packit Service 6f2e62
			ADDCARRY(sum);
Packit Service 6f2e62
		}
Packit Service 6f2e62
		if (len == -1)
Packit Service 6f2e62
			/*
Packit Service 6f2e62
			 * Odd number of bytes.
Packit Service 6f2e62
			 */
Packit Service 6f2e62
			u.c[0] = *(unsigned char *)addr;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	if (len == -1) {
Packit Service 6f2e62
		/* The last mbuf has odd # of bytes. Follow the
Packit Service 6f2e62
		   standard (the odd byte is shifted left by 8 bits) */
Packit Service 6f2e62
		u.c[1] = 0;
Packit Service 6f2e62
		sum += u.s;
Packit Service 6f2e62
		ADDCARRY(sum);
Packit Service 6f2e62
	}
Packit Service 6f2e62
	return (~sum & 0xffff);
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
#define ON		1
Packit Service 6f2e62
#define OFF		0
Packit Service 6f2e62
Packit Service 6f2e62
#define RANGE		1		/* best expected round-trip time, ms */
Packit Service 6f2e62
#define MSGS 		50
Packit Service 6f2e62
#define TRIALS		10
Packit Service 6f2e62
Packit Service 6f2e62
#define GOOD		0
Packit Service 6f2e62
#define UNREACHABLE	2
Packit Service 6f2e62
#define NONSTDTIME	3
Packit Service 6f2e62
#define HOSTDOWN 	0x7fffffff
Packit Service 6f2e62
Packit Service 6f2e62
Packit Service 6f2e62
int interactive = 0;
Packit Service 6f2e62
uint16_t id;
Packit Service 6f2e62
int sock;
Packit Service 6f2e62
int sock_raw;
Packit Service 6f2e62
struct sockaddr_in server;
Packit Service 6f2e62
int ip_opt_len = 0;
Packit Service 6f2e62
Packit Service 6f2e62
#define BIASP	 	43199999
Packit Service 6f2e62
#define BIASN		-43200000
Packit Service 6f2e62
#define MODULO	 	86400000
Packit Service 6f2e62
#define PROCESSING_TIME	0 	/* ms. to reduce error in measurement */
Packit Service 6f2e62
Packit Service 6f2e62
#define PACKET_IN	1024
Packit Service 6f2e62
Packit Service 6f2e62
int measure_delta;
Packit Service 6f2e62
int measure_delta1;
Packit Service 6f2e62
static unsigned short seqno, seqno0, acked;
Packit Service 6f2e62
long rtt = 1000;
Packit Service 6f2e62
long min_rtt;
Packit Service 6f2e62
long rtt_sigma = 0;
Packit Service 6f2e62
Packit Service 6f2e62
/*
Packit Service 6f2e62
 * Measures the differences between machines' clocks using
Packit Service 6f2e62
 * ICMP timestamp messages.
Packit Service 6f2e62
 */
Packit Service 6f2e62
int
Packit Service 6f2e62
measure(struct sockaddr_in * addr)
Packit Service 6f2e62
{
Packit Service 6f2e62
	socklen_t length;
Packit Service 6f2e62
	int msgcount;
Packit Service 6f2e62
	int cc, count;
Packit Service 6f2e62
	fd_set ready;
Packit Service 6f2e62
	long sendtime, recvtime, histime;
Packit Service 6f2e62
	long min1, min2, diff;
Packit Service 6f2e62
	long delta1, delta2;
Packit Service 6f2e62
	struct timeval tv1, tout;
Packit Service 6f2e62
	unsigned char packet[PACKET_IN], opacket[64];
Packit Service 6f2e62
	struct icmphdr *icp;
Packit Service 6f2e62
	struct icmphdr *oicp = (struct icmphdr *) opacket;
Packit Service 6f2e62
	struct iphdr *ip = (struct iphdr *) packet;
Packit Service 6f2e62
Packit Service 6f2e62
	min1 = min2 = 0x7fffffff;
Packit Service 6f2e62
	min_rtt = 0x7fffffff;
Packit Service 6f2e62
	measure_delta = HOSTDOWN;
Packit Service 6f2e62
	measure_delta1 = HOSTDOWN;
Packit Service 6f2e62
Packit Service 6f2e62
/* empties the icmp input queue */
Packit Service 6f2e62
	FD_ZERO(&ready);
Packit Service 6f2e62
Packit Service 6f2e62
empty:
Packit Service 6f2e62
	tout.tv_sec = tout.tv_usec = 0;
Packit Service 6f2e62
	FD_SET(sock_raw, &ready);
Packit Service 6f2e62
	if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) {
Packit Service 6f2e62
		length = sizeof(struct sockaddr_in);
Packit Service 6f2e62
		cc = recvfrom(sock_raw, (char *)packet, PACKET_IN, 0,
Packit Service 6f2e62
		    (struct sockaddr *)NULL, &length);
Packit Service 6f2e62
		if (cc < 0)
Packit Service 6f2e62
			return -1;
Packit Service 6f2e62
		goto empty;
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	/*
Packit Service 6f2e62
	 * To measure the difference, select MSGS messages whose round-trip
Packit Service 6f2e62
	 * time is smaller than RANGE if ckrange is 1, otherwise simply
Packit Service 6f2e62
	 * select MSGS messages regardless of round-trip transmission time.
Packit Service 6f2e62
	 * Choose the smallest transmission time in each of the two directions.
Packit Service 6f2e62
	 * Use these two latter quantities to compute the delta between
Packit Service 6f2e62
	 * the two clocks.
Packit Service 6f2e62
	 */
Packit Service 6f2e62
Packit Service 6f2e62
	length = sizeof(struct sockaddr_in);
Packit Service 6f2e62
	oicp->type = ICMP_TIMESTAMP;
Packit Service 6f2e62
	oicp->code = 0;
Packit Service 6f2e62
	oicp->checksum = 0;
Packit Service 6f2e62
	oicp->un.echo.id = id;
Packit Service 6f2e62
	((__u32*)(oicp+1))[0] = 0;
Packit Service 6f2e62
	((__u32*)(oicp+1))[1] = 0;
Packit Service 6f2e62
	((__u32*)(oicp+1))[2] = 0;
Packit Service 6f2e62
	FD_ZERO(&ready);
Packit Service 6f2e62
Packit Service 6f2e62
	acked = seqno = seqno0 = 0;
Packit Service 6f2e62
Packit Service 6f2e62
	for (msgcount = 0; msgcount < MSGS; ) {
Packit Service 6f2e62
Packit Service 6f2e62
	/*
Packit Service 6f2e62
	 * If no answer is received for TRIALS consecutive times,
Packit Service 6f2e62
	 * the machine is assumed to be down
Packit Service 6f2e62
	 */
Packit Service 6f2e62
		if (seqno - acked > TRIALS)
Packit Service 6f2e62
			return HOSTDOWN;
Packit Service 6f2e62
Packit Service 6f2e62
		oicp->un.echo.sequence = ++seqno;
Packit Service 6f2e62
		oicp->checksum = 0;
Packit Service 6f2e62
Packit Service 6f2e62
		(void)gettimeofday (&tv1, (struct timezone *)0);
Packit Service 6f2e62
		*(__u32*)(oicp+1) = htonl((tv1.tv_sec % (24*60*60)) * 1000
Packit Service 6f2e62
					  + tv1.tv_usec / 1000);
Packit Service 6f2e62
		oicp->checksum = in_cksum((unsigned short *)oicp, sizeof(*oicp) + 12);
Packit Service 6f2e62
Packit Service 6f2e62
		count = sendto(sock_raw, (char *)opacket, sizeof(*oicp)+12, 0,
Packit Service 6f2e62
			       (struct sockaddr *)addr, sizeof(struct sockaddr_in));
Packit Service 6f2e62
Packit Service 6f2e62
		if (count < 0)
Packit Service 6f2e62
			return UNREACHABLE;
Packit Service 6f2e62
Packit Service 6f2e62
		for (;;) {
Packit Service 6f2e62
			FD_ZERO(&ready);
Packit Service 6f2e62
			FD_SET(sock_raw, &ready);
Packit Service 6f2e62
			{
Packit Service 6f2e62
			  long tmo = rtt + rtt_sigma;
Packit Service 6f2e62
			  tout.tv_sec =  tmo/1000;
Packit Service 6f2e62
			  tout.tv_usec = (tmo - (tmo/1000)*1000)*1000;
Packit Service 6f2e62
			}
Packit Service 6f2e62
Packit Service 6f2e62
			if ((count = select(FD_SETSIZE, &ready, (fd_set *)0,
Packit Service 6f2e62
			    (fd_set *)0, &tout)) <= 0)
Packit Service 6f2e62
				break;
Packit Service 6f2e62
Packit Service 6f2e62
			(void)gettimeofday(&tv1, (struct timezone *)0);
Packit Service 6f2e62
			cc = recvfrom(sock_raw, (char *)packet, PACKET_IN, 0,
Packit Service 6f2e62
			    (struct sockaddr *)NULL, &length);
Packit Service 6f2e62
Packit Service 6f2e62
			if (cc < 0)
Packit Service 6f2e62
				return(-1);
Packit Service 6f2e62
Packit Service 6f2e62
			icp = (struct icmphdr *)(packet + (ip->ihl << 2));
Packit Service 6f2e62
			if( icp->type == ICMP_TIMESTAMPREPLY &&
Packit Service 6f2e62
			    icp->un.echo.id == id && icp->un.echo.sequence >= seqno0 &&
Packit Service 6f2e62
						  icp->un.echo.sequence <= seqno) {
Packit Service 6f2e62
			  if (acked < icp->un.echo.sequence)
Packit Service 6f2e62
			    acked = icp->un.echo.sequence;
Packit Service 6f2e62
Packit Service 6f2e62
			  recvtime = (tv1.tv_sec % (24*60*60)) * 1000 +
Packit Service 6f2e62
				     tv1.tv_usec / 1000;
Packit Service 6f2e62
			  sendtime = ntohl(*(__u32*)(icp+1));
Packit Service 6f2e62
			  diff = recvtime - sendtime;
Packit Service 6f2e62
		/*
Packit Service 6f2e62
		 * diff can be less than 0 aroud midnight
Packit Service 6f2e62
		 */
Packit Service 6f2e62
			  if (diff < 0)
Packit Service 6f2e62
			    continue;
Packit Service 6f2e62
			  rtt = (rtt * 3 + diff)/4;
Packit Service 6f2e62
			  rtt_sigma = (rtt_sigma *3 + abs(diff-rtt))/4;
Packit Service 6f2e62
			  msgcount++;
Packit Service 6f2e62
			  histime = ntohl(((__u32*)(icp+1))[1]);
Packit Service 6f2e62
		/*
Packit Service 6f2e62
		 * a hosts using a time format different from
Packit Service 6f2e62
		 * ms. since midnight UT (as per RFC792) should
Packit Service 6f2e62
		 * set the high order bit of the 32-bit time
Packit Service 6f2e62
		 * value it transmits.
Packit Service 6f2e62
		 */
Packit Service 6f2e62
			if ((histime & 0x80000000) != 0)
Packit Service 6f2e62
			  return NONSTDTIME;
Packit Service 6f2e62
Packit Service 6f2e62
			if (interactive) {
Packit Service 6f2e62
			  printf(".");
Packit Service 6f2e62
			  fflush(stdout);
Packit Service 6f2e62
			}
Packit Service 6f2e62
Packit Service 6f2e62
			delta1 = histime - sendtime;
Packit Service 6f2e62
		/*
Packit Service 6f2e62
		 * Handles wrap-around to avoid that around
Packit Service 6f2e62
		 * midnight small time differences appear
Packit Service 6f2e62
		 * enormous. However, the two machine's clocks
Packit Service 6f2e62
		 * must be within 12 hours from each other.
Packit Service 6f2e62
		 */
Packit Service 6f2e62
			if (delta1 < BIASN)
Packit Service 6f2e62
				delta1 += MODULO;
Packit Service 6f2e62
			else if (delta1 > BIASP)
Packit Service 6f2e62
				delta1 -= MODULO;
Packit Service 6f2e62
Packit Service 6f2e62
			delta2 = recvtime - histime;
Packit Service 6f2e62
			if (delta2 < BIASN)
Packit Service 6f2e62
				delta2 += MODULO;
Packit Service 6f2e62
			else if (delta2 > BIASP)
Packit Service 6f2e62
				delta2 -= MODULO;
Packit Service 6f2e62
Packit Service 6f2e62
			if (delta1 < min1)
Packit Service 6f2e62
				min1 = delta1;
Packit Service 6f2e62
			if (delta2 < min2)
Packit Service 6f2e62
				min2 = delta2;
Packit Service 6f2e62
			if (delta1 + delta2 < min_rtt) {
Packit Service 6f2e62
			  min_rtt  = delta1 + delta2;
Packit Service 6f2e62
			  measure_delta1 = (delta1 - delta2)/2 + PROCESSING_TIME;
Packit Service 6f2e62
			}
Packit Service 6f2e62
			if (diff < RANGE) {
Packit Service 6f2e62
				min1 = delta1;
Packit Service 6f2e62
				min2 = delta2;
Packit Service 6f2e62
				goto good_exit;
Packit Service 6f2e62
			}
Packit Service 6f2e62
		      }
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
good_exit:
Packit Service 6f2e62
	measure_delta = (min1 - min2)/2 + PROCESSING_TIME;
Packit Service 6f2e62
	return GOOD;
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
char *myname, *hisname;
Packit Service 6f2e62
Packit Service 6f2e62
int
Packit Service 6f2e62
measure_opt(struct sockaddr_in * addr)
Packit Service 6f2e62
{
Packit Service 6f2e62
	socklen_t length;
Packit Service 6f2e62
	int msgcount;
Packit Service 6f2e62
	int cc, count;
Packit Service 6f2e62
	fd_set ready;
Packit Service 6f2e62
	long sendtime, recvtime, histime, histime1;
Packit Service 6f2e62
	long min1, min2, diff;
Packit Service 6f2e62
	long delta1, delta2;
Packit Service 6f2e62
	struct timeval tv1, tout;
Packit Service 6f2e62
	unsigned char packet[PACKET_IN], opacket[64];
Packit Service 6f2e62
	struct icmphdr *icp;
Packit Service 6f2e62
	struct icmphdr *oicp = (struct icmphdr *) opacket;
Packit Service 6f2e62
	struct iphdr *ip = (struct iphdr *) packet;
Packit Service 6f2e62
Packit Service 6f2e62
	min1 = min2 = 0x7fffffff;
Packit Service 6f2e62
	min_rtt = 0x7fffffff;
Packit Service 6f2e62
	measure_delta = HOSTDOWN;
Packit Service 6f2e62
	measure_delta1 = HOSTDOWN;
Packit Service 6f2e62
Packit Service 6f2e62
/* empties the icmp input queue */
Packit Service 6f2e62
	FD_ZERO(&ready);
Packit Service 6f2e62
empty:
Packit Service 6f2e62
	tout.tv_sec = tout.tv_usec = 0;
Packit Service 6f2e62
	FD_SET(sock_raw, &ready);
Packit Service 6f2e62
	if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) {
Packit Service 6f2e62
		length = sizeof(struct sockaddr_in);
Packit Service 6f2e62
		cc = recvfrom(sock_raw, (char *)packet, PACKET_IN, 0,
Packit Service 6f2e62
		    (struct sockaddr *)NULL, &length);
Packit Service 6f2e62
		if (cc < 0)
Packit Service 6f2e62
			return -1;
Packit Service 6f2e62
		goto empty;
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	/*
Packit Service 6f2e62
	 * To measure the difference, select MSGS messages whose round-trip
Packit Service 6f2e62
	 * time is smaller than RANGE if ckrange is 1, otherwise simply
Packit Service 6f2e62
	 * select MSGS messages regardless of round-trip transmission time.
Packit Service 6f2e62
	 * Choose the smallest transmission time in each of the two directions.
Packit Service 6f2e62
	 * Use these two latter quantities to compute the delta between
Packit Service 6f2e62
	 * the two clocks.
Packit Service 6f2e62
	 */
Packit Service 6f2e62
Packit Service 6f2e62
	length = sizeof(struct sockaddr_in);
Packit Service 6f2e62
	oicp->type = ICMP_ECHO;
Packit Service 6f2e62
	oicp->code = 0;
Packit Service 6f2e62
	oicp->checksum = 0;
Packit Service 6f2e62
	oicp->un.echo.id = id;
Packit Service 6f2e62
	((__u32*)(oicp+1))[0] = 0;
Packit Service 6f2e62
	((__u32*)(oicp+1))[1] = 0;
Packit Service 6f2e62
	((__u32*)(oicp+1))[2] = 0;
Packit Service 6f2e62
Packit Service 6f2e62
	FD_ZERO(&ready);
Packit Service 6f2e62
Packit Service 6f2e62
	acked = seqno = seqno0 = 0;
Packit Service 6f2e62
Packit Service 6f2e62
	for (msgcount = 0; msgcount < MSGS; ) {
Packit Service 6f2e62
Packit Service 6f2e62
	/*
Packit Service 6f2e62
	 * If no answer is received for TRIALS consecutive times,
Packit Service 6f2e62
	 * the machine is assumed to be down
Packit Service 6f2e62
	 */
Packit Service 6f2e62
		if ( seqno - acked > TRIALS) {
Packit Service 6f2e62
			errno = EHOSTDOWN;
Packit Service 6f2e62
			return HOSTDOWN;
Packit Service 6f2e62
		}
Packit Service 6f2e62
		oicp->un.echo.sequence = ++seqno;
Packit Service 6f2e62
		oicp->checksum = 0;
Packit Service 6f2e62
Packit Service 6f2e62
		gettimeofday (&tv1, NULL);
Packit Service 6f2e62
		((__u32*)(oicp+1))[0] = htonl((tv1.tv_sec % (24*60*60)) * 1000
Packit Service 6f2e62
					      + tv1.tv_usec / 1000);
Packit Service 6f2e62
		oicp->checksum = in_cksum((unsigned short *)oicp, sizeof(*oicp)+12);
Packit Service 6f2e62
Packit Service 6f2e62
		count = sendto(sock_raw, (char *)opacket, sizeof(*oicp)+12, 0,
Packit Service 6f2e62
			       (struct sockaddr *)addr, sizeof(struct sockaddr_in));
Packit Service 6f2e62
Packit Service 6f2e62
		if (count < 0) {
Packit Service 6f2e62
			errno = EHOSTUNREACH;
Packit Service 6f2e62
			return UNREACHABLE;
Packit Service 6f2e62
		}
Packit Service 6f2e62
Packit Service 6f2e62
		for (;;) {
Packit Service 6f2e62
			FD_ZERO(&ready);
Packit Service 6f2e62
			FD_SET(sock_raw, &ready);
Packit Service 6f2e62
			{
Packit Service 6f2e62
				long tmo = rtt + rtt_sigma;
Packit Service 6f2e62
				tout.tv_sec =  tmo/1000;
Packit Service 6f2e62
				tout.tv_usec = (tmo - (tmo/1000)*1000)*1000;
Packit Service 6f2e62
			}
Packit Service 6f2e62
Packit Service 6f2e62
			if ((count = select(FD_SETSIZE, &ready, (fd_set *)0,
Packit Service 6f2e62
			    (fd_set *)0, &tout)) <= 0)
Packit Service 6f2e62
				break;
Packit Service 6f2e62
Packit Service 6f2e62
			(void)gettimeofday(&tv1, (struct timezone *)0);
Packit Service 6f2e62
			cc = recvfrom(sock_raw, (char *)packet, PACKET_IN, 0,
Packit Service 6f2e62
				      (struct sockaddr *)NULL, &length);
Packit Service 6f2e62
Packit Service 6f2e62
			if (cc < 0)
Packit Service 6f2e62
				return(-1);
Packit Service 6f2e62
Packit Service 6f2e62
			icp = (struct icmphdr *)(packet + (ip->ihl << 2));
Packit Service 6f2e62
			if (icp->type == ICMP_ECHOREPLY &&
Packit Service 6f2e62
			    packet[20] == IPOPT_TIMESTAMP &&
Packit Service 6f2e62
			    icp->un.echo.id == id &&
Packit Service 6f2e62
			    icp->un.echo.sequence >= seqno0 &&
Packit Service 6f2e62
			    icp->un.echo.sequence <= seqno) {
Packit Service 6f2e62
				int i;
Packit Service 6f2e62
				__u8 *opt = packet+20;
Packit Service 6f2e62
Packit Service 6f2e62
				if (acked < icp->un.echo.sequence)
Packit Service 6f2e62
					acked = icp->un.echo.sequence;
Packit Service 6f2e62
				if ((opt[3]&0xF) != IPOPT_TS_PRESPEC) {
Packit Service 6f2e62
					fprintf(stderr, "Wrong timestamp %d\n", opt[3]&0xF);
Packit Service 6f2e62
					return NONSTDTIME;
Packit Service 6f2e62
				}
Packit Service 6f2e62
				if (opt[3]>>4) {
Packit Service 6f2e62
					if ((opt[3]>>4) != 1 || ip_opt_len != 4+3*8)
Packit Service 6f2e62
						fprintf(stderr, "Overflow %d hops\n", opt[3]>>4);
Packit Service 6f2e62
				}
Packit Service 6f2e62
				sendtime = recvtime = histime = histime1 = 0;
Packit Service 6f2e62
				for (i=0; i < (opt[2]-5)/8; i++) {
Packit Service 6f2e62
					__u32 *timep = (__u32*)(opt+4+i*8+4);
Packit Service 6f2e62
					__u32 t = ntohl(*timep);
Packit Service 6f2e62
Packit Service 6f2e62
					if (t & 0x80000000)
Packit Service 6f2e62
						return NONSTDTIME;
Packit Service 6f2e62
Packit Service 6f2e62
					if (i == 0)
Packit Service 6f2e62
						sendtime = t;
Packit Service 6f2e62
					if (i == 1)
Packit Service 6f2e62
						histime = histime1 = t;
Packit Service 6f2e62
					if (i == 2) {
Packit Service 6f2e62
						if (ip_opt_len == 4+4*8)
Packit Service 6f2e62
							histime1 = t;
Packit Service 6f2e62
						else
Packit Service 6f2e62
							recvtime = t;
Packit Service 6f2e62
					}
Packit Service 6f2e62
					if (i == 3)
Packit Service 6f2e62
						recvtime = t;
Packit Service 6f2e62
				}
Packit Service 6f2e62
Packit Service 6f2e62
				if (!(sendtime&histime&histime1&recvtime)) {
Packit Service 6f2e62
					fprintf(stderr, "wrong timestamps\n");
Packit Service 6f2e62
					return -1;
Packit Service 6f2e62
				}
Packit Service 6f2e62
Packit Service 6f2e62
				diff = recvtime - sendtime;
Packit Service 6f2e62
				/*
Packit Service 6f2e62
				 * diff can be less than 0 aroud midnight
Packit Service 6f2e62
				 */
Packit Service 6f2e62
				if (diff < 0)
Packit Service 6f2e62
					continue;
Packit Service 6f2e62
				rtt = (rtt * 3 + diff)/4;
Packit Service 6f2e62
				rtt_sigma = (rtt_sigma *3 + abs(diff-rtt))/4;
Packit Service 6f2e62
				msgcount++;
Packit Service 6f2e62
Packit Service 6f2e62
				if (interactive) {
Packit Service 6f2e62
					printf(".");
Packit Service 6f2e62
					fflush(stdout);
Packit Service 6f2e62
				}
Packit Service 6f2e62
Packit Service 6f2e62
				delta1 = histime - sendtime;
Packit Service 6f2e62
				/*
Packit Service 6f2e62
				 * Handles wrap-around to avoid that around
Packit Service 6f2e62
				 * midnight small time differences appear
Packit Service 6f2e62
				 * enormous. However, the two machine's clocks
Packit Service 6f2e62
				 * must be within 12 hours from each other.
Packit Service 6f2e62
				 */
Packit Service 6f2e62
				if (delta1 < BIASN)
Packit Service 6f2e62
					delta1 += MODULO;
Packit Service 6f2e62
				else if (delta1 > BIASP)
Packit Service 6f2e62
					delta1 -= MODULO;
Packit Service 6f2e62
Packit Service 6f2e62
				delta2 = recvtime - histime1;
Packit Service 6f2e62
				if (delta2 < BIASN)
Packit Service 6f2e62
					delta2 += MODULO;
Packit Service 6f2e62
				else if (delta2 > BIASP)
Packit Service 6f2e62
					delta2 -= MODULO;
Packit Service 6f2e62
Packit Service 6f2e62
				if (delta1 < min1)
Packit Service 6f2e62
					min1 = delta1;
Packit Service 6f2e62
				if (delta2 < min2)
Packit Service 6f2e62
					min2 = delta2;
Packit Service 6f2e62
				if (delta1 + delta2 < min_rtt) {
Packit Service 6f2e62
					min_rtt  = delta1 + delta2;
Packit Service 6f2e62
					measure_delta1 = (delta1 - delta2)/2 + PROCESSING_TIME;
Packit Service 6f2e62
				}
Packit Service 6f2e62
				if (diff < RANGE) {
Packit Service 6f2e62
					min1 = delta1;
Packit Service 6f2e62
					min2 = delta2;
Packit Service 6f2e62
					goto good_exit;
Packit Service 6f2e62
				}
Packit Service 6f2e62
			}
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
good_exit:
Packit Service 6f2e62
	measure_delta = (min1 - min2)/2 + PROCESSING_TIME;
Packit Service 6f2e62
	return GOOD;
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
Packit Service 6f2e62
/*
Packit Service 6f2e62
 * Clockdiff computes the difference between the time of the machine on
Packit Service 6f2e62
 * which it is called and the time of the machines given as argument.
Packit Service 6f2e62
 * The time differences measured by clockdiff are obtained using a sequence
Packit Service 6f2e62
 * of ICMP TSTAMP messages which are returned to the sender by the IP module
Packit Service 6f2e62
 * in the remote machine.
Packit Service 6f2e62
 * In order to compare clocks of machines in different time zones, the time
Packit Service 6f2e62
 * is transmitted (as a 32-bit value) in milliseconds since midnight UT.
Packit Service 6f2e62
 * If a hosts uses a different time format, it should set the high order
Packit Service 6f2e62
 * bit of the 32-bit quantity it transmits.
Packit Service 6f2e62
 * However, VMS apparently transmits the time in milliseconds since midnight
Packit Service 6f2e62
 * local time (rather than GMT) without setting the high order bit.
Packit Service 6f2e62
 * Furthermore, it does not understand daylight-saving time.  This makes
Packit Service 6f2e62
 * clockdiff behaving inconsistently with hosts running VMS.
Packit Service 6f2e62
 *
Packit Service 6f2e62
 * In order to reduce the sensitivity to the variance of message transmission
Packit Service 6f2e62
 * time, clockdiff sends a sequence of messages.  Yet, measures between
Packit Service 6f2e62
 * two `distant' hosts can be affected by a small error. The error can, however,
Packit Service 6f2e62
 * be reduced by increasing the number of messages sent in each measurement.
Packit Service 6f2e62
 */
Packit Service 6f2e62
Packit Service 6f2e62
void
Packit Service 6f2e62
usage() {
Packit Service 6f2e62
  fprintf(stderr, "Usage: clockdiff [-o] <host>\n");
Packit Service 6f2e62
  exit(1);
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
void drop_rights(void) {
Packit Service 6f2e62
#ifdef CAPABILITIES
Packit Service 6f2e62
	cap_t caps = cap_init();
Packit Service 6f2e62
	if (cap_set_proc(caps)) {
Packit Service 6f2e62
		perror("clockdiff: cap_set_proc");
Packit Service 6f2e62
		exit(-1);
Packit Service 6f2e62
	}
Packit Service 6f2e62
	cap_free(caps);
Packit Service 6f2e62
#endif
Packit Service 6f2e62
	if (setuid(getuid())) {
Packit Service 6f2e62
		perror("clockdiff: setuid");
Packit Service 6f2e62
		exit(-1);
Packit Service 6f2e62
	}
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
int
Packit Service 6f2e62
main(int argc, char *argv[])
Packit Service 6f2e62
{
Packit Service 6f2e62
	int measure_status;
Packit Service 6f2e62
	struct addrinfo hints = { .ai_family = AF_INET, .ai_socktype = SOCK_RAW, .ai_flags = AI_CANONNAME };
Packit Service 6f2e62
	struct addrinfo *result;
Packit Service 6f2e62
	int status;
Packit Service 6f2e62
	char hostname[MAX_HOSTNAMELEN];
Packit Service 6f2e62
	int s_errno = 0;
Packit Service 6f2e62
	int n_errno = 0;
Packit Service 6f2e62
Packit Service 6f2e62
	if (argc < 2) {
Packit Service 6f2e62
		drop_rights();
Packit Service 6f2e62
		usage();
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
Packit Service 6f2e62
	s_errno = errno;
Packit Service 6f2e62
Packit Service 6f2e62
	errno = 0;
Packit Service 6f2e62
	if (nice(-16) == -1)
Packit Service 6f2e62
		n_errno = errno;
Packit Service 6f2e62
	drop_rights();
Packit Service 6f2e62
Packit Service 6f2e62
	if (argc == 3) {
Packit Service 6f2e62
		if (strcmp(argv[1], "-o") == 0) {
Packit Service 6f2e62
			ip_opt_len = 4 + 4*8;
Packit Service 6f2e62
			argv++;
Packit Service 6f2e62
		} else if (strcmp(argv[1], "-o1") == 0) {
Packit Service 6f2e62
			ip_opt_len = 4 + 3*8;
Packit Service 6f2e62
			argv++;
Packit Service 6f2e62
		} else
Packit Service 6f2e62
			usage();
Packit Service 6f2e62
	} else if (argc != 2)
Packit Service 6f2e62
		usage();
Packit Service 6f2e62
Packit Service 6f2e62
	if (sock_raw < 0)  {
Packit Service 6f2e62
		errno = s_errno;
Packit Service 6f2e62
		perror("clockdiff: socket");
Packit Service 6f2e62
		exit(1);
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	if (n_errno < 0) {
Packit Service 6f2e62
		errno = n_errno;
Packit Service 6f2e62
		perror("clockdiff: nice");
Packit Service 6f2e62
		exit(1);
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	if (isatty(fileno(stdin)) && isatty(fileno(stdout)))
Packit Service 6f2e62
		interactive = 1;
Packit Service 6f2e62
Packit Service 6f2e62
	id = getpid();
Packit Service 6f2e62
Packit Service 6f2e62
	(void)gethostname(hostname,sizeof(hostname));
Packit Service 6f2e62
	status = getaddrinfo(hostname, NULL, &hints, &result);
Packit Service 6f2e62
	if (status) {
Packit Service 6f2e62
		fprintf(stderr, "clockdiff: %s: %s\n", hostname, gai_strerror(status));
Packit Service 6f2e62
		exit(2);
Packit Service 6f2e62
	}
Packit Service 6f2e62
	myname = strdup(result->ai_canonname);
Packit Service 6f2e62
	freeaddrinfo(result);
Packit Service 6f2e62
Packit Service 6f2e62
	status = getaddrinfo(argv[1], NULL, &hints, &result);
Packit Service 6f2e62
	if (status) {
Packit Service 6f2e62
		fprintf(stderr, "clockdiff: %s: %s\n", argv[1], gai_strerror(status));
Packit Service 6f2e62
		exit(1);
Packit Service 6f2e62
	}
Packit Service 6f2e62
	hisname = strdup(result->ai_canonname);
Packit Service 6f2e62
Packit Service 6f2e62
	memcpy(&server, result->ai_addr, sizeof server);
Packit Service 6f2e62
	freeaddrinfo(result);
Packit Service 6f2e62
Packit Service 6f2e62
	if (connect(sock_raw, (struct sockaddr*)&server, sizeof(server)) == -1) {
Packit Service 6f2e62
		perror("connect");
Packit Service 6f2e62
		exit(1);
Packit Service 6f2e62
	}
Packit Service 6f2e62
	if (ip_opt_len) {
Packit Service 6f2e62
		struct sockaddr_in myaddr;
Packit Service 6f2e62
		socklen_t addrlen = sizeof(myaddr);
Packit Service 6f2e62
		unsigned char rspace[ip_opt_len];
Packit Service 6f2e62
Packit Service 6f2e62
		memset(rspace, 0, sizeof(rspace));
Packit Service 6f2e62
		rspace[0] = IPOPT_TIMESTAMP;
Packit Service 6f2e62
		rspace[1] = ip_opt_len;
Packit Service 6f2e62
		rspace[2] = 5;
Packit Service 6f2e62
		rspace[3] = IPOPT_TS_PRESPEC;
Packit Service 6f2e62
		if (getsockname(sock_raw, (struct sockaddr*)&myaddr, &addrlen) == -1) {
Packit Service 6f2e62
			perror("getsockname");
Packit Service 6f2e62
			exit(1);
Packit Service 6f2e62
		}
Packit Service 6f2e62
		((__u32*)(rspace+4))[0*2] = myaddr.sin_addr.s_addr;
Packit Service 6f2e62
		((__u32*)(rspace+4))[1*2] = server.sin_addr.s_addr;
Packit Service 6f2e62
		((__u32*)(rspace+4))[2*2] = myaddr.sin_addr.s_addr;
Packit Service 6f2e62
		if (ip_opt_len == 4+4*8) {
Packit Service 6f2e62
			((__u32*)(rspace+4))[2*2] = server.sin_addr.s_addr;
Packit Service 6f2e62
			((__u32*)(rspace+4))[3*2] = myaddr.sin_addr.s_addr;
Packit Service 6f2e62
		}
Packit Service 6f2e62
Packit Service 6f2e62
		if (setsockopt(sock_raw, IPPROTO_IP, IP_OPTIONS, rspace, ip_opt_len) < 0) {
Packit Service 6f2e62
			perror("ping: IP_OPTIONS (fallback to icmp tstamps)");
Packit Service 6f2e62
			ip_opt_len = 0;
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	if ((measure_status = (ip_opt_len ? measure_opt : measure)(&server)) < 0) {
Packit Service 6f2e62
		if (errno)
Packit Service 6f2e62
			perror("measure");
Packit Service 6f2e62
		else
Packit Service 6f2e62
			fprintf(stderr, "measure: unknown failure\n");
Packit Service 6f2e62
		exit(1);
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	switch (measure_status) {
Packit Service 6f2e62
	case HOSTDOWN:
Packit Service 6f2e62
		fprintf(stderr, "%s is down\n", hisname);
Packit Service 6f2e62
		exit(1);
Packit Service 6f2e62
	case NONSTDTIME:
Packit Service 6f2e62
		fprintf(stderr, "%s time transmitted in a non-standard format\n", hisname);
Packit Service 6f2e62
		exit(1);
Packit Service 6f2e62
	case UNREACHABLE:
Packit Service 6f2e62
		fprintf(stderr, "%s is unreachable\n", hisname);
Packit Service 6f2e62
		exit(1);
Packit Service 6f2e62
	default:
Packit Service 6f2e62
		break;
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
Packit Service 6f2e62
	{
Packit Service 6f2e62
		time_t now = time(NULL);
Packit Service 6f2e62
Packit Service 6f2e62
		if (interactive)
Packit Service 6f2e62
			printf("\nhost=%s rtt=%ld(%ld)ms/%ldms delta=%dms/%dms %s", hisname,
Packit Service 6f2e62
			       rtt, rtt_sigma, min_rtt,
Packit Service 6f2e62
			       measure_delta, measure_delta1,
Packit Service 6f2e62
			       ctime(&now));
Packit Service 6f2e62
		else
Packit Service 6f2e62
			printf("%ld %d %d\n", now, measure_delta, measure_delta1);
Packit Service 6f2e62
	}
Packit Service 6f2e62
	exit(0);
Packit Service 6f2e62
}