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