File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / sntp / main.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 2 months ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>