Home | History | Annotate | Line # | Download | only in sntp
main.c revision 1.1
      1  1.1  kardel /*	$NetBSD: main.c,v 1.1 2009/12/13 16:57:10 kardel Exp $	*/
      2  1.1  kardel 
      3  1.1  kardel #include <l_stdlib.h>
      4  1.1  kardel #include <ntp_fp.h>
      5  1.1  kardel #include <ntp.h>
      6  1.1  kardel #include <ntp_stdlib.h>
      7  1.1  kardel #include <ntp_unixtime.h>
      8  1.1  kardel #include <isc/result.h>
      9  1.1  kardel #include <isc/net.h>
     10  1.1  kardel #include <stdio.h>
     11  1.1  kardel 
     12  1.1  kardel #include <sntp-opts.h>
     13  1.1  kardel 
     14  1.1  kardel #include "crypto.h"
     15  1.1  kardel #include "kod_management.h"
     16  1.1  kardel #include "networking.h"
     17  1.1  kardel #include "utilities.h"
     18  1.1  kardel #include "log.h"
     19  1.1  kardel 
     20  1.1  kardel char *progname = "sntp";	/* for msyslog */
     21  1.1  kardel 
     22  1.1  kardel int ai_fam_pref = AF_UNSPEC;
     23  1.1  kardel volatile int debug;
     24  1.1  kardel 
     25  1.1  kardel struct key *keys = NULL;
     26  1.1  kardel 
     27  1.1  kardel void set_li_vn_mode (struct pkt *spkt, char leap, char version, char mode);
     28  1.1  kardel int sntp_main (int argc, char **argv);
     29  1.1  kardel int on_wire (struct addrinfo *host);
     30  1.1  kardel int set_time (double offset);
     31  1.1  kardel 
     32  1.1  kardel 
     33  1.1  kardel int
     34  1.1  kardel main (
     35  1.1  kardel 		int argc,
     36  1.1  kardel 		char **argv
     37  1.1  kardel 		)
     38  1.1  kardel {
     39  1.1  kardel 	return sntp_main(argc, argv);
     40  1.1  kardel }
     41  1.1  kardel 
     42  1.1  kardel /*
     43  1.1  kardel  * The actual main function.
     44  1.1  kardel  */
     45  1.1  kardel int
     46  1.1  kardel sntp_main (
     47  1.1  kardel 		int argc,
     48  1.1  kardel 		char **argv
     49  1.1  kardel 		)
     50  1.1  kardel {
     51  1.1  kardel 	register int c;
     52  1.1  kardel 	struct kod_entry *reason = NULL;
     53  1.1  kardel 	int optct;
     54  1.1  kardel 	int sync_data_suc = 0;
     55  1.1  kardel 	struct addrinfo **resh = NULL;
     56  1.1  kardel 	struct addrinfo *ai;
     57  1.1  kardel 	int resc;
     58  1.1  kardel 	int kodc;
     59  1.1  kardel 	int ow_ret;
     60  1.1  kardel 	char *hostname;
     61  1.1  kardel 
     62  1.1  kardel 	/* IPv6 available? */
     63  1.1  kardel 	if (isc_net_probeipv6() != ISC_R_SUCCESS) {
     64  1.1  kardel 		ai_fam_pref = AF_INET;
     65  1.1  kardel #ifdef DEBUG
     66  1.1  kardel 		printf("No ipv6 support available, forcing ipv4\n");
     67  1.1  kardel #endif
     68  1.1  kardel 	}
     69  1.1  kardel 	else {
     70  1.1  kardel 		/* Check for options -4 and -6 */
     71  1.1  kardel 		if (HAVE_OPT(IPV4))
     72  1.1  kardel 			ai_fam_pref = AF_INET;
     73  1.1  kardel 		else if (HAVE_OPT(IPV6))
     74  1.1  kardel 			ai_fam_pref = AF_INET6;
     75  1.1  kardel 	}
     76  1.1  kardel 
     77  1.1  kardel 	log_msg("Started sntp", 0);
     78  1.1  kardel 
     79  1.1  kardel 	optct = optionProcess(&sntpOptions, argc, argv);
     80  1.1  kardel 	argc -= optct;
     81  1.1  kardel 	argv += optct;
     82  1.1  kardel 
     83  1.1  kardel 	/* Parse config file if declared TODO */
     84  1.1  kardel 
     85  1.1  kardel 	/* Initialize logging system */
     86  1.1  kardel 	if (HAVE_OPT(FILELOG))
     87  1.1  kardel 		init_log(OPT_ARG(FILELOG));
     88  1.1  kardel 
     89  1.1  kardel 	/*
     90  1.1  kardel 	 * If there's a specified KOD file init KOD system.  If not use
     91  1.1  kardel 	 * default file.  For embedded systems with no writable
     92  1.1  kardel 	 * filesystem, -K /dev/null can be used to disable KoD storage.
     93  1.1  kardel 	 */
     94  1.1  kardel 	if (HAVE_OPT(KOD))
     95  1.1  kardel 		kod_init_kod_db(OPT_ARG(KOD));
     96  1.1  kardel 	else
     97  1.1  kardel 		kod_init_kod_db("/var/db/ntp-kod");
     98  1.1  kardel 
     99  1.1  kardel 	if (HAVE_OPT(KEYFILE))
    100  1.1  kardel 		auth_init(OPT_ARG(KEYFILE), &keys);
    101  1.1  kardel 
    102  1.1  kardel #ifdef EXERCISE_KOD_DB
    103  1.1  kardel 	add_entry("192.168.169.170", "DENY");
    104  1.1  kardel 	add_entry("192.168.169.171", "DENY");
    105  1.1  kardel 	add_entry("192.168.169.172", "DENY");
    106  1.1  kardel 	add_entry("192.168.169.173", "DENY");
    107  1.1  kardel 	add_entry("192.168.169.174", "DENY");
    108  1.1  kardel 	delete_entry("192.168.169.174", "DENY");
    109  1.1  kardel 	delete_entry("192.168.169.172", "DENY");
    110  1.1  kardel 	delete_entry("192.168.169.170", "DENY");
    111  1.1  kardel 	if ((kodc = search_entry("192.168.169.173", &reason)) == 0)
    112  1.1  kardel 		printf("entry for 192.168.169.173 not found but should have been!\n");
    113  1.1  kardel 	else
    114  1.1  kardel 		free(reason);
    115  1.1  kardel #endif
    116  1.1  kardel 
    117  1.1  kardel 	/* Considering employing a variable that prevents functions of doing anything until
    118  1.1  kardel 	 * everything is initialized properly
    119  1.1  kardel 	 */
    120  1.1  kardel 	resc = resolve_hosts(argv, argc, &resh, ai_fam_pref);
    121  1.1  kardel 
    122  1.1  kardel 	if (resc < 1) {
    123  1.1  kardel 		printf("Unable to resolve hostname(s)\n");
    124  1.1  kardel 		return -1;
    125  1.1  kardel 	}
    126  1.1  kardel 
    127  1.1  kardel 	/* Select a certain ntp server according to simple criteria? For now
    128  1.1  kardel 	 * let's just pay attention to previous KoDs.
    129  1.1  kardel 	 */
    130  1.1  kardel 	for (c = 0; c < resc && !sync_data_suc; c++) {
    131  1.1  kardel 		ai = resh[c];
    132  1.1  kardel 		do {
    133  1.1  kardel 			hostname = addrinfo_to_str(ai);
    134  1.1  kardel 
    135  1.1  kardel 			if ((kodc = search_entry(hostname, &reason)) == 0) {
    136  1.1  kardel 				if (is_reachable(ai)) {
    137  1.1  kardel 					ow_ret = on_wire(ai);
    138  1.1  kardel 					if (ow_ret < 0)
    139  1.1  kardel 						printf("on_wire failed for server %s!\n", hostname);
    140  1.1  kardel 					else
    141  1.1  kardel 						sync_data_suc = 1;
    142  1.1  kardel 				}
    143  1.1  kardel 			} else {
    144  1.1  kardel 				printf("%d prior KoD%s for %s, skipping.\n",
    145  1.1  kardel 					kodc, (kodc > 1) ? "s" : "", hostname);
    146  1.1  kardel 				free(reason);
    147  1.1  kardel 			}
    148  1.1  kardel 			free(hostname);
    149  1.1  kardel 			ai = ai->ai_next;
    150  1.1  kardel 		} while (NULL != ai);
    151  1.1  kardel 		freeaddrinfo(resh[c]);
    152  1.1  kardel 	}
    153  1.1  kardel 	free(resh);
    154  1.1  kardel 
    155  1.1  kardel 	return 0;
    156  1.1  kardel }
    157  1.1  kardel 
    158  1.1  kardel /* The heart of (S)NTP, exchange NTP packets and compute values to correct the local clock */
    159  1.1  kardel int
    160  1.1  kardel on_wire (
    161  1.1  kardel 		struct addrinfo *host
    162  1.1  kardel 					)
    163  1.1  kardel {
    164  1.1  kardel 	char logmsg[32 + INET6_ADDRSTRLEN];
    165  1.1  kardel 	char addr_buf[INET6_ADDRSTRLEN];
    166  1.1  kardel 	register int try;
    167  1.1  kardel 	SOCKET sock;
    168  1.1  kardel 	struct pkt x_pkt;
    169  1.1  kardel 	struct pkt r_pkt;
    170  1.1  kardel 	char *ref;
    171  1.1  kardel 
    172  1.1  kardel 	for(try=0; try<5; try++) {
    173  1.1  kardel 		struct timeval tv_xmt, tv_dst;
    174  1.1  kardel 		double t21, t34, delta, offset, precision, root_dispersion;
    175  1.1  kardel 		int digits, error, rpktl, sw_case;
    176  1.1  kardel 		char *hostname = NULL, *ts_str = NULL;
    177  1.1  kardel 		char *log_str;
    178  1.1  kardel 		u_fp p_rdly, p_rdsp;
    179  1.1  kardel 		l_fp p_rec, p_xmt, p_ref, p_org, xmt, tmp, dst;
    180  1.1  kardel 
    181  1.1  kardel 		memset(&r_pkt, 0, sizeof(r_pkt));
    182  1.1  kardel 		memset(&x_pkt, 0, sizeof(x_pkt));
    183  1.1  kardel 
    184  1.1  kardel 		error = GETTIMEOFDAY(&tv_xmt, (struct timezone *)NULL);
    185  1.1  kardel 
    186  1.1  kardel 		tv_xmt.tv_sec += JAN_1970;
    187  1.1  kardel 
    188  1.1  kardel #ifdef DEBUG
    189  1.1  kardel 		printf("sntp on_wire: Current time sec: %i msec: %i\n", (unsigned int) tv_xmt.tv_sec,
    190  1.1  kardel 				(unsigned int) tv_xmt.tv_usec);
    191  1.1  kardel #endif
    192  1.1  kardel 
    193  1.1  kardel 		TVTOTS(&tv_xmt, &xmt);
    194  1.1  kardel 		HTONL_FP(&xmt, &(x_pkt.xmt));
    195  1.1  kardel 
    196  1.1  kardel 		x_pkt.stratum = STRATUM_TO_PKT(STRATUM_UNSPEC);
    197  1.1  kardel 		x_pkt.ppoll = 8;
    198  1.1  kardel 		/* FIXME! Modus broadcast + adr. check -> bdr. pkt */
    199  1.1  kardel 		set_li_vn_mode(&x_pkt, LEAP_NOTINSYNC, 4, 3);
    200  1.1  kardel 
    201  1.1  kardel 		create_socket(&sock, (sockaddr_u *)host->ai_addr);
    202  1.1  kardel 
    203  1.1  kardel 		sendpkt(sock, (sockaddr_u *)host->ai_addr, &x_pkt, LEN_PKT_NOMAC);
    204  1.1  kardel 		rpktl = recvpkt(sock, &r_pkt, &x_pkt);
    205  1.1  kardel 
    206  1.1  kardel 		closesocket(sock);
    207  1.1  kardel 
    208  1.1  kardel 		if(rpktl > 0)
    209  1.1  kardel 			sw_case = 1;
    210  1.1  kardel 		else
    211  1.1  kardel 			sw_case = rpktl;
    212  1.1  kardel 
    213  1.1  kardel 		switch(sw_case) {
    214  1.1  kardel 			case SERVER_UNUSEABLE:
    215  1.1  kardel 				return -1;
    216  1.1  kardel 				break;
    217  1.1  kardel 
    218  1.1  kardel 			case PACKET_UNUSEABLE:
    219  1.1  kardel 				break;
    220  1.1  kardel 
    221  1.1  kardel 			case SERVER_AUTH_FAIL:
    222  1.1  kardel 				break;
    223  1.1  kardel 
    224  1.1  kardel 			case KOD_DEMOBILIZE:
    225  1.1  kardel 				/* Received a DENY or RESTR KOD packet */
    226  1.1  kardel 				hostname = addrinfo_to_str(host);
    227  1.1  kardel 				ref = (char *)&r_pkt.refid;
    228  1.1  kardel 				add_entry(hostname, ref);
    229  1.1  kardel 
    230  1.1  kardel 				if (ENABLED_OPT(NORMALVERBOSE))
    231  1.1  kardel 					printf("sntp on_wire: Received KOD packet with code: %c%c%c%c from %s, demobilizing all connections\n",
    232  1.1  kardel 					       ref[0], ref[1], ref[2], ref[3],
    233  1.1  kardel 					       hostname);
    234  1.1  kardel 
    235  1.1  kardel 				log_str = emalloc(INET6_ADDRSTRLEN + 72);
    236  1.1  kardel 				snprintf(log_str, INET6_ADDRSTRLEN + 72,
    237  1.1  kardel 					 "Received a KOD packet with code %c%c%c%c from %s, demobilizing all connections",
    238  1.1  kardel 					 ref[0], ref[1], ref[2], ref[3],
    239  1.1  kardel 					 hostname);
    240  1.1  kardel 				log_msg(log_str, 2);
    241  1.1  kardel 				free(log_str);
    242  1.1  kardel 				break;
    243  1.1  kardel 
    244  1.1  kardel 			case KOD_RATE:
    245  1.1  kardel 				/* Hmm... probably we should sleep a bit here */
    246  1.1  kardel 				break;
    247  1.1  kardel 
    248  1.1  kardel 			case 1:
    249  1.1  kardel 
    250  1.1  kardel 			/* Convert timestamps from network to host byte order */
    251  1.1  kardel 			p_rdly = NTOHS_FP(r_pkt.rootdelay);
    252  1.1  kardel 			p_rdsp = NTOHS_FP(r_pkt.rootdisp);
    253  1.1  kardel 			NTOHL_FP(&r_pkt.reftime, &p_ref);
    254  1.1  kardel 			NTOHL_FP(&r_pkt.org, &p_org);
    255  1.1  kardel 			NTOHL_FP(&r_pkt.rec, &p_rec);
    256  1.1  kardel 			NTOHL_FP(&r_pkt.xmt, &p_xmt);
    257  1.1  kardel 
    258  1.1  kardel 			if (ENABLED_OPT(NORMALVERBOSE)) {
    259  1.1  kardel 				getnameinfo(host->ai_addr, host->ai_addrlen, addr_buf,
    260  1.1  kardel 						sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
    261  1.1  kardel 
    262  1.1  kardel 				printf("sntp on_wire: Received %i bytes from %s\n", rpktl, addr_buf);
    263  1.1  kardel 			}
    264  1.1  kardel 
    265  1.1  kardel 			precision = LOGTOD(r_pkt.precision);
    266  1.1  kardel #ifdef DEBUG
    267  1.1  kardel 			printf("sntp precision: %f\n", precision);
    268  1.1  kardel #endif /* DEBUG */
    269  1.1  kardel 			for (digits = 0; (precision *= 10.) < 1.; ++digits)
    270  1.1  kardel 				/* empty */ ;
    271  1.1  kardel 			if (digits > 6)
    272  1.1  kardel 				digits = 6;
    273  1.1  kardel 
    274  1.1  kardel 			root_dispersion = FPTOD(p_rdsp);
    275  1.1  kardel 
    276  1.1  kardel #ifdef DEBUG
    277  1.1  kardel 			printf("sntp rootdelay: %f\n", FPTOD(p_rdly));
    278  1.1  kardel 			printf("sntp rootdisp: %f\n", root_dispersion);
    279  1.1  kardel 
    280  1.1  kardel 			pkt_output(&r_pkt, rpktl, stdout);
    281  1.1  kardel 
    282  1.1  kardel 			printf("sntp on_wire: r_pkt.reftime:\n");
    283  1.1  kardel 			l_fp_output(&(r_pkt.reftime), stdout);
    284  1.1  kardel 			printf("sntp on_wire: r_pkt.org:\n");
    285  1.1  kardel 			l_fp_output(&(r_pkt.org), stdout);
    286  1.1  kardel 			printf("sntp on_wire: r_pkt.rec:\n");
    287  1.1  kardel 			l_fp_output(&(r_pkt.rec), stdout);
    288  1.1  kardel 			printf("sntp on_wire: r_pkt.rec:\n");
    289  1.1  kardel 			l_fp_output_bin(&(r_pkt.rec), stdout);
    290  1.1  kardel 			printf("sntp on_wire: r_pkt.rec:\n");
    291  1.1  kardel 			l_fp_output_dec(&(r_pkt.rec), stdout);
    292  1.1  kardel 			printf("sntp on_wire: r_pkt.xmt:\n");
    293  1.1  kardel 			l_fp_output(&(r_pkt.xmt), stdout);
    294  1.1  kardel #endif
    295  1.1  kardel 
    296  1.1  kardel 			/* Compute offset etc. */
    297  1.1  kardel 			GETTIMEOFDAY(&tv_dst, (struct timezone *)NULL);
    298  1.1  kardel 
    299  1.1  kardel 			tv_dst.tv_sec += JAN_1970;
    300  1.1  kardel 
    301  1.1  kardel 			tmp = p_rec;
    302  1.1  kardel 			L_SUB(&tmp, &p_org);
    303  1.1  kardel 
    304  1.1  kardel 			LFPTOD(&tmp, t21);
    305  1.1  kardel 
    306  1.1  kardel 			TVTOTS(&tv_dst, &dst);
    307  1.1  kardel 
    308  1.1  kardel 			tmp = dst;
    309  1.1  kardel 			L_SUB(&tmp, &p_xmt);
    310  1.1  kardel 
    311  1.1  kardel 			LFPTOD(&tmp, t34);
    312  1.1  kardel 
    313  1.1  kardel 			offset = (t21 + t34) / 2.;
    314  1.1  kardel 			delta = t21 - t34;
    315  1.1  kardel 
    316  1.1  kardel 			if(ENABLED_OPT(NORMALVERBOSE))
    317  1.1  kardel 				printf("sntp on_wire:\tt21: %.6f\t\t t34: %.6f\n\t\tdelta: %.6f\t offset: %.6f\n",
    318  1.1  kardel 					t21, t34, delta, offset);
    319  1.1  kardel 
    320  1.1  kardel 			ts_str = tv_to_str(&tv_dst);
    321  1.1  kardel 
    322  1.1  kardel 			printf("%s ", ts_str);
    323  1.1  kardel 
    324  1.1  kardel 			if(offset > 0)
    325  1.1  kardel 				printf("+");
    326  1.1  kardel 
    327  1.1  kardel 			printf("%.*f", digits, offset);
    328  1.1  kardel 
    329  1.1  kardel 			if (root_dispersion > 0.)
    330  1.1  kardel 				printf(" +/- %f secs", root_dispersion);
    331  1.1  kardel 
    332  1.1  kardel 			printf("\n");
    333  1.1  kardel 
    334  1.1  kardel 			free(ts_str);
    335  1.1  kardel 
    336  1.1  kardel 			if(ENABLED_OPT(SETTOD) || ENABLED_OPT(ADJTIME))
    337  1.1  kardel 				return set_time(offset);
    338  1.1  kardel 
    339  1.1  kardel 			return 0;
    340  1.1  kardel 		}
    341  1.1  kardel 	}
    342  1.1  kardel 
    343  1.1  kardel 	getnameinfo(host->ai_addr, host->ai_addrlen, addr_buf, sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
    344  1.1  kardel 
    345  1.1  kardel 	snprintf(logmsg, sizeof(logmsg), "Received no useable packet from %s!", addr_buf);
    346  1.1  kardel 	log_msg(logmsg, 1);
    347  1.1  kardel 
    348  1.1  kardel 	if (ENABLED_OPT(NORMALVERBOSE))
    349  1.1  kardel 		printf("sntp on_wire: Received no useable packet from %s!\n", addr_buf);
    350  1.1  kardel 
    351  1.1  kardel 	return -1;
    352  1.1  kardel }
    353  1.1  kardel 
    354  1.1  kardel /* Compute the 8 bits for li_vn_mode */
    355  1.1  kardel void
    356  1.1  kardel set_li_vn_mode (
    357  1.1  kardel 		struct pkt *spkt,
    358  1.1  kardel 		char leap,
    359  1.1  kardel 		char version,
    360  1.1  kardel 		char mode
    361  1.1  kardel 	       )
    362  1.1  kardel {
    363  1.1  kardel 
    364  1.1  kardel 	if(leap > 3) {
    365  1.1  kardel 		debug_msg("set_li_vn_mode: leap > 3 using max. 3");
    366  1.1  kardel 		leap = 3;
    367  1.1  kardel 	}
    368  1.1  kardel 
    369  1.1  kardel 	if(mode > 7) {
    370  1.1  kardel 		debug_msg("set_li_vn_mode: mode > 7, using client mode 3");
    371  1.1  kardel 		mode = 3;
    372  1.1  kardel 	}
    373  1.1  kardel 
    374  1.1  kardel 	spkt->li_vn_mode  = leap << 6;
    375  1.1  kardel 	spkt->li_vn_mode |= version << 3;
    376  1.1  kardel 	spkt->li_vn_mode |= mode;
    377  1.1  kardel }
    378  1.1  kardel 
    379  1.1  kardel /* set_time corrects the local clock by offset with either settimeofday() or by default
    380  1.1  kardel  * with adjtime()/adjusttimeofday().
    381  1.1  kardel  */
    382  1.1  kardel int
    383  1.1  kardel set_time (
    384  1.1  kardel 		double offset
    385  1.1  kardel 	 )
    386  1.1  kardel {
    387  1.1  kardel 	struct timeval tp;
    388  1.1  kardel 
    389  1.1  kardel 	if(ENABLED_OPT(SETTOD)) {
    390  1.1  kardel 		GETTIMEOFDAY(&tp, (struct timezone *)NULL);
    391  1.1  kardel 
    392  1.1  kardel 		tp.tv_sec += (int) offset;
    393  1.1  kardel 		tp.tv_usec += offset - (double)((int)offset);
    394  1.1  kardel 
    395  1.1  kardel 		if(SETTIMEOFDAY(&tp, (struct timezone *)NULL) < 0) {
    396  1.1  kardel 			printf("set_time: settimeofday(): Time not set: %s\n",
    397  1.1  kardel 				strerror(errno));
    398  1.1  kardel 			return -1;
    399  1.1  kardel 		}
    400  1.1  kardel 		else {
    401  1.1  kardel 			return 0;
    402  1.1  kardel 		}
    403  1.1  kardel 	}
    404  1.1  kardel 	else {
    405  1.1  kardel 		tp.tv_sec = (int) offset;
    406  1.1  kardel 		tp.tv_usec = offset - (double)((int)offset);
    407  1.1  kardel 
    408  1.1  kardel 		if(ADJTIMEOFDAY(&tp, NULL) < 0) {
    409  1.1  kardel 			printf("set_time: adjtime(): Time not set: %s\n",
    410  1.1  kardel 				strerror(errno));
    411  1.1  kardel 			return -1;
    412  1.1  kardel 		}
    413  1.1  kardel 		else {
    414  1.1  kardel 			return 0;
    415  1.1  kardel 		}
    416  1.1  kardel 	}
    417  1.1  kardel }
    418