Exemplo n.º 1
0
int
process_pkt (
	struct pkt *rpkt,
	sockaddr_u *sas,
	int pkt_len,
	int mode,
	struct pkt *spkt,
	const char * func_name
	)
{
	unsigned int key_id = 0;
	struct key *pkt_key = NULL;
	int is_authentic = 0;
	unsigned int exten_words, exten_words_used = 0;
	int mac_size;
	/*
	 * Parse the extension field if present. We figure out whether
	 * an extension field is present by measuring the MAC size. If
	 * the number of words following the packet header is 0, no MAC
	 * is present and the packet is not authenticated. If 1, the
	 * packet is a crypto-NAK; if 3, the packet is authenticated
	 * with DES; if 5, the packet is authenticated with MD5; if 6,
	 * the packet is authenticated with SHA. If 2 or 4, the packet
	 * is a runt and discarded forthwith. If greater than 6, an
	 * extension field is present, so we subtract the length of the
	 * field and go around again.
	 */
	if (pkt_len < (int)LEN_PKT_NOMAC || (pkt_len & 3) != 0) {
unusable:
		if (ENABLED_OPT(NORMALVERBOSE))
			printf("sntp %s: Funny packet length: %i. Discarding package.\n", func_name, pkt_len);
		return PACKET_UNUSEABLE;
	}
	/* skip past the extensions, if any */
	exten_words = ((unsigned)pkt_len - LEN_PKT_NOMAC) >> 2;
	while (exten_words > 6) {
		unsigned int exten_len;
		exten_len = ntohl(rpkt->exten[exten_words_used]) & 0xffff;
		exten_len = (exten_len + 7) >> 2; /* convert to words, add 1 */
		if (exten_len > exten_words || exten_len < 5)
			goto unusable;
		exten_words -= exten_len;
		exten_words_used += exten_len;
	}

	switch (exten_words) {
	case 1:
		key_id = ntohl(rpkt->exten[exten_words_used]);
		printf("Crypto NAK = 0x%08x\n", key_id);
		break;
	case 5:
	case 6:
		/* Look for the key used by the server in the specified keyfile
		 * and if existent, fetch it or else leave the pointer untouched */
		key_id = ntohl(rpkt->exten[exten_words_used]);
		get_key(key_id, &pkt_key);
		if (!pkt_key) {
			printf("unrecognized key ID = 0x%08x\n", key_id);
			break;
		}
		/* Seems like we've got a key with matching keyid */
		/* Generate a md5sum of the packet with the key from our keyfile
		 * and compare those md5sums */
		mac_size = exten_words << 2;
		if (!auth_md5((char *)rpkt, pkt_len - mac_size, mac_size - 4, pkt_key)) {
			break;
		}
		/* Yay! Things worked out! */
		if (ENABLED_OPT(NORMALVERBOSE)) {
			char *hostname = ss_to_str(sas);
			printf("sntp %s: packet received from %s successfully authenticated using key id %i.\n",
				func_name, hostname, key_id);
			free(hostname);
		}
		is_authentic = 1;
		break;
	case 0:
		break;
	default:
		goto unusable;
		break;
	}
	if (!is_authentic) {
		if (ENABLED_OPT(AUTHENTICATION)) {
			/* We want a authenticated packet */
			if (ENABLED_OPT(NORMALVERBOSE)) {
				char *hostname = ss_to_str(sas);
				printf("sntp %s: packet received from %s is not authentic. Will discard it.\n",
					func_name, hostname);
				free(hostname);
			}
			return SERVER_AUTH_FAIL;
		}
		/* We don't know if the user wanted authentication so let's 
		 * use it anyways */
		if (ENABLED_OPT(NORMALVERBOSE)) {
			char *hostname = ss_to_str(sas);
			printf("sntp %s: packet received from %s is not authentic. Authentication not enforced.\n",
				func_name, hostname);
			free(hostname);
		}
	}
	/* Check for server's ntp version */
	if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION ||
		PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) {
		if (ENABLED_OPT(NORMALVERBOSE))
			printf("sntp %s: Packet shows wrong version (%i)\n",
				func_name, PKT_VERSION(rpkt->li_vn_mode));
		return SERVER_UNUSEABLE;
	} 
	/* We want a server to sync with */
	if (PKT_MODE(rpkt->li_vn_mode) != mode &&
	    PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE) {
		if (ENABLED_OPT(NORMALVERBOSE))
			printf("sntp %s: mode %d stratum %i\n", func_name, 
			       PKT_MODE(rpkt->li_vn_mode), rpkt->stratum);
		return SERVER_UNUSEABLE;
	}
	/* Stratum is unspecified (0) check what's going on */
	if (STRATUM_PKT_UNSPEC == rpkt->stratum) {
		char *ref_char;
		if (ENABLED_OPT(NORMALVERBOSE))
			printf("sntp %s: Stratum unspecified, going to check for KOD (stratum: %i)\n", 
				func_name, rpkt->stratum);
		ref_char = (char *) &rpkt->refid;
		if (ENABLED_OPT(NORMALVERBOSE))
			printf("sntp %s: Packet refid: %c%c%c%c\n", func_name,
			       ref_char[0], ref_char[1], ref_char[2], ref_char[3]);
		/* If it's a KOD packet we'll just use the KOD information */
		if (ref_char[0] != 'X') {
			if (strncmp(ref_char, "DENY", 4) == 0)
				return KOD_DEMOBILIZE;
			if (strncmp(ref_char, "RSTR", 4) == 0)
				return KOD_DEMOBILIZE;
			if (strncmp(ref_char, "RATE", 4) == 0)
				return KOD_RATE;
			/* There are other interesting kiss codes which might be interesting for authentication */
		}
	}
	/* If the server is not synced it's not really useable for us */
	if (LEAP_NOTINSYNC == PKT_LEAP(rpkt->li_vn_mode)) {
		if (ENABLED_OPT(NORMALVERBOSE)) 
			printf("sntp %s: Server not in sync, skipping this server\n", func_name);
		return SERVER_UNUSEABLE;
	}

	/*
	 * Decode the org timestamp and make sure we're getting a response
	 * to our last request, but only if we're not in broadcast mode.
	 */
#ifdef DEBUG
	printf("rpkt->org:\n");
	l_fp_output(&rpkt->org, stdout);
	printf("spkt->xmt:\n");
	l_fp_output(&spkt->xmt, stdout);
#endif
	if (mode != MODE_BROADCAST && !L_ISEQU(&rpkt->org, &spkt->xmt)) {
		if (ENABLED_OPT(NORMALVERBOSE))
			printf("sntp process_pkt: pkt.org and peer.xmt differ\n");
		return PACKET_UNUSEABLE;
	}

	return pkt_len;
}
Exemplo n.º 2
0
void
offset_calculation(
	struct pkt *rpkt,
	int rpktl,
	struct timeval *tv_dst,
	double *offset,
	double *precision,
	double *synch_distance
	)
{
	l_fp p_rec, p_xmt, p_ref, p_org, tmp, dst;
	u_fp p_rdly, p_rdsp;
	double t21, t34, delta;

	/* Convert timestamps from network to host byte order */
	p_rdly = NTOHS_FP(rpkt->rootdelay);
	p_rdsp = NTOHS_FP(rpkt->rootdisp);
	NTOHL_FP(&rpkt->reftime, &p_ref);
	NTOHL_FP(&rpkt->org, &p_org);
	NTOHL_FP(&rpkt->rec, &p_rec);
	NTOHL_FP(&rpkt->xmt, &p_xmt);

	*precision = LOGTOD(rpkt->precision);

	TRACE(3, ("offset_calculation: LOGTOD(rpkt->precision): %f\n", *precision));

	/* Compute offset etc. */
	tmp = p_rec;
	L_SUB(&tmp, &p_org);
	LFPTOD(&tmp, t21);
	TVTOTS(tv_dst, &dst);
	dst.l_ui += JAN_1970;
	tmp = p_xmt;
	L_SUB(&tmp, &dst);
	LFPTOD(&tmp, t34);
	*offset = (t21 + t34) / 2.;
	delta = t21 - t34;

	// synch_distance is:
	// (peer->delay + peer->rootdelay) / 2 + peer->disp
	// + peer->rootdisp + clock_phi * (current_time - peer->update)
	// + peer->jitter;
	//
	// and peer->delay = fabs(peer->offset - p_offset) * 2;
	// and peer->offset needs history, so we're left with
	// p_offset = (t21 + t34) / 2.;
	// peer->disp = 0; (we have no history to augment this)
	// clock_phi = 15e-6; 
	// peer->jitter = LOGTOD(sys_precision); (we have no history to augment this)
	// and ntp_proto.c:set_sys_tick_precision() should get us sys_precision.
	//
	// so our answer seems to be:
	//
	// (fabs(t21 + t34) + peer->rootdelay) / 3.
	// + 0 (peer->disp)
	// + peer->rootdisp
	// + 15e-6 (clock_phi)
	// + LOGTOD(sys_precision)

	INSIST( FPTOD(p_rdly) >= 0. );
#if 1
	*synch_distance = (fabs(t21 + t34) + FPTOD(p_rdly)) / 3.
		+ 0.
		+ FPTOD(p_rdsp)
		+ 15e-6
		+ 0.	/* LOGTOD(sys_precision) when we can get it */
		;
	INSIST( *synch_distance >= 0. );
#else
	*synch_distance = (FPTOD(p_rdly) + FPTOD(p_rdsp))/2.0;
#endif

#ifdef DEBUG
	if (debug > 3) {
		printf("sntp rootdelay: %f\n", FPTOD(p_rdly));
		printf("sntp rootdisp: %f\n", FPTOD(p_rdsp));
		printf("sntp syncdist: %f\n", *synch_distance);

		pkt_output(rpkt, rpktl, stdout);

		printf("sntp offset_calculation: rpkt->reftime:\n");
		l_fp_output(&p_ref, stdout);
		printf("sntp offset_calculation: rpkt->org:\n");
		l_fp_output(&p_org, stdout);
		printf("sntp offset_calculation: rpkt->rec:\n");
		l_fp_output(&p_rec, stdout);
		printf("sntp offset_calculation: rpkt->xmt:\n");
		l_fp_output(&p_xmt, stdout);
	}
#endif

	TRACE(3, ("sntp offset_calculation:\trec - org t21: %.6f\n"
		  "\txmt - dst t34: %.6f\tdelta: %.6f\toffset: %.6f\n",
		  t21, t34, delta, *offset));

	return;
}
Exemplo n.º 3
0
void
offset_calculation (
	struct pkt *rpkt,
	int rpktl,
	struct timeval *tv_dst,
	double *offset,
	double *precision,
	double *root_dispersion
	)
{
	l_fp p_rec, p_xmt, p_ref, p_org, tmp, dst;
	u_fp p_rdly, p_rdsp;
	double t21, t34, delta;

	/* Convert timestamps from network to host byte order */
	p_rdly = NTOHS_FP(rpkt->rootdelay);
	p_rdsp = NTOHS_FP(rpkt->rootdisp);
	NTOHL_FP(&rpkt->reftime, &p_ref);
	NTOHL_FP(&rpkt->org, &p_org);
	NTOHL_FP(&rpkt->rec, &p_rec);
	NTOHL_FP(&rpkt->xmt, &p_xmt);

	*precision = LOGTOD(rpkt->precision);
#ifdef DEBUG
	printf("sntp precision: %f\n", *precision);
#endif /* DEBUG */

	*root_dispersion = FPTOD(p_rdsp);

#ifdef DEBUG
	printf("sntp rootdelay: %f\n", FPTOD(p_rdly));
	printf("sntp rootdisp: %f\n", *root_dispersion);

	pkt_output(rpkt, rpktl, stdout);

	printf("sntp offset_calculation: rpkt->reftime:\n");
	l_fp_output(&(rpkt->reftime), stdout);
	printf("sntp offset_calculation: rpkt->org:\n");
	l_fp_output(&(rpkt->org), stdout);
	printf("sntp offset_calculation: rpkt->rec:\n");
	l_fp_output(&(rpkt->rec), stdout);
	printf("sntp offset_calculation: rpkt->rec:\n");
	l_fp_output_bin(&(rpkt->rec), stdout);
	printf("sntp offset_calculation: rpkt->rec:\n");
	l_fp_output_dec(&(rpkt->rec), stdout);
	printf("sntp offset_calculation: rpkt->xmt:\n");
	l_fp_output(&(rpkt->xmt), stdout);
#endif

	/* Compute offset etc. */
	tmp = p_rec;
	L_SUB(&tmp, &p_org);
	LFPTOD(&tmp, t21);
	TVTOTS(tv_dst, &dst);
	dst.l_ui += JAN_1970;
	tmp = p_xmt;
	L_SUB(&tmp, &dst);
	LFPTOD(&tmp, t34);
	*offset = (t21 + t34) / 2.;
	delta = t21 - t34;

	if (ENABLED_OPT(NORMALVERBOSE))
		printf("sntp offset_calculation:\tt21: %.6f\t\t t34: %.6f\n\t\tdelta: %.6f\t offset: %.6f\n", 
			   t21, t34, delta, *offset);
}
Exemplo n.º 4
0
/* Fetch data, check if it's data for us and whether it's useable or not. If not, return 
 * a failure code so we can delete this server from our list and continue with another one. 
 */
int 
recvpkt (
		SOCKET rsock,
		struct pkt *rpkt,
		struct pkt *spkt
	)
{
	sockaddr_u sender;
	char *rdata /* , done */;

	register int a;
	int has_mac, is_authentic, pkt_len, orig_pkt_len;


	/* Much space, just to be sure */
	rdata = emalloc(sizeof(char) * 256);

	pkt_len = recvdata(rsock, &sender, rdata, 256);

#if 0	/* done uninitialized */
	if (!done) {
		/* Do something about it, first check for a maximum length of ntp packets,
		 * probably that's something we can avoid 
		 */
	}
#endif
	
	if (pkt_len < 0) {
		if (ENABLED_OPT(NORMALVERBOSE)) {
			printf("sntp recvpkt failed: %d.\n", pkt_len);
		}
		free(rdata);
		return pkt_len;
	}
	
	/* Some checks to see if that packet is intended for us */

	/* No MAC, no authentication */
	if (LEN_PKT_NOMAC == pkt_len)
		has_mac = 0;

	/* If there's more than just the NTP packet it should be a MAC */	
	else if (pkt_len > LEN_PKT_NOMAC) 
		has_mac = pkt_len - LEN_PKT_NOMAC;
	
	else {
		if (ENABLED_OPT(NORMALVERBOSE))
			printf("sntp recvpkt: Funny packet length: %i. Discarding package.\n", pkt_len);
		free(rdata);

		return PACKET_UNUSEABLE;
	}

	/* Packet too big */
	if (pkt_len > LEN_PKT_MAC) {
		if (ENABLED_OPT(NORMALVERBOSE))
			printf("sntp recvpkt: Received packet is too big (%i bytes), trying again to get a useable packet\n", 
					pkt_len);
		free(rdata);

		return PACKET_UNUSEABLE;
	}

	orig_pkt_len = pkt_len;
	pkt_len = min(pkt_len, sizeof(struct pkt));
	
	for (a = 0; a < pkt_len; a++) 
		/* FIXME! */
		if (a < orig_pkt_len)
			((char *) rpkt)[a] = rdata[a];
		else
			((char *) rpkt)[a] = 0;

	free(rdata);
	rdata = NULL;

	/* MAC could be useable for us */
	if (has_mac) {
		/* Two more things that the MAC must conform to */
		if(has_mac > MAX_MAC_LEN || has_mac % 4 != 0) {
			is_authentic = 0; /* Or should we discard this packet? */
		}
		else {
			if (MAX_MAC_LEN == has_mac) {
				struct key *pkt_key = NULL;
				
				/*
				 * Look for the key used by the server in the specified keyfile
				 * and if existent, fetch it or else leave the pointer untouched 
				 */
				get_key(rpkt->mac[0], &pkt_key);

				/* Seems like we've got a key with matching keyid */
				if (pkt_key != NULL) {
					/*
					 * Generate a md5sum of the packet with the key from our keyfile
					 * and compare those md5sums 
					 */
					if (!auth_md5((char *) rpkt, has_mac, pkt_key)) {
						if (ENABLED_OPT(AUTHENTICATION)) {
							/* We want a authenticated packet */
							if (ENABLED_OPT(NORMALVERBOSE)) {
								char *hostname = ss_to_str(&sender);
								printf("sntp recvpkt: Broadcast packet received from %s is not authentic. Will discard this packet.\n", 
										hostname);

								free(hostname);
							}
							return SERVER_AUTH_FAIL;
						}
						else {
							/* 
							 * We don't know if the user wanted authentication so let's 
							 * use it anyways 
							 */
							if (ENABLED_OPT(NORMALVERBOSE)) {
								char *hostname = ss_to_str(&sender);
								printf("sntp recvpkt: Broadcast packet received from %s is not authentic. Authentication not enforced.\n", 
										hostname);

								free(hostname);
							}

							is_authentic = 0;
						}
					}
					else {
						/* Yay! Things worked out! */
						if (ENABLED_OPT(NORMALVERBOSE)) {
							char *hostname = ss_to_str(&sender);
							printf("sntp recvpkt: Broadcast packet received from %s successfully authenticated using key id %i.\n", 
									hostname, rpkt->mac[0]);

							free(hostname);
						}

						is_authentic = 1;
					}
				}
			}
		}
	}

	/* Check for server's ntp version */
	if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION ||
	    PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) {
		if (ENABLED_OPT(NORMALVERBOSE))
			printf("sntp recvpkt: Packet got wrong version (%i)\n", PKT_VERSION(rpkt->li_vn_mode));

		return SERVER_UNUSEABLE;
	} 

	/* We want a server to sync with */
	if (PKT_MODE(rpkt->li_vn_mode) != MODE_SERVER &&
	    PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE) {
		if (ENABLED_OPT(NORMALVERBOSE))
			printf("sntp recvpkt: mode %d stratum %i\n",
			   PKT_MODE(rpkt->li_vn_mode), rpkt->stratum);

		return SERVER_UNUSEABLE;
	}

	/* Stratum is unspecified (0) check what's going on */
	if (STRATUM_PKT_UNSPEC == rpkt->stratum) {
		char *ref_char;

		if (ENABLED_OPT(NORMALVERBOSE))
			printf("sntp recvpkt: Stratum unspecified, going to check for KOD (stratum: %i)\n", rpkt->stratum);


		ref_char = (char *) &rpkt->refid;

		if (ENABLED_OPT(NORMALVERBOSE)) 
			printf("sntp recvpkt: Packet refid: %c%c%c%c\n", ref_char[0], ref_char[1], ref_char[2], ref_char[3]);
		
		/* If it's a KOD packet we'll just use the KOD information */
		if (ref_char[0] != 'X') {
			if (!strncmp(ref_char, "DENY", 4))
				return KOD_DEMOBILIZE;

			if (!strncmp(ref_char, "RSTR", 4))
				return KOD_DEMOBILIZE;

			if (!strncmp(ref_char, "RATE", 4))
				return KOD_RATE;

			/* There are other interesting kiss codes which might be interesting for authentication */
		}
	}

	/* If the server is not synced it's not really useable for us */
	if (LEAP_NOTINSYNC == PKT_LEAP(rpkt->li_vn_mode)) {
		if (ENABLED_OPT(NORMALVERBOSE)) 
			printf("sntp recvpkt: Server not in sync, skipping this server\n");

		return SERVER_UNUSEABLE;
	}

	/*
	 * Decode the org timestamp and make sure we're getting a response
	 * to our last request. 
	 */

#ifdef DEBUG
	printf("rpkt->org:\n");
	l_fp_output(&rpkt->org, stdout);
	printf("spkt->xmt:\n");
	l_fp_output(&spkt->xmt, stdout);
#endif
	
	if (!L_ISEQU(&rpkt->org, &spkt->xmt)) {
		if (ENABLED_OPT(NORMALVERBOSE))
			printf("sntp recvpkt: pkt.org and peer.xmt differ\n");
		
		return PACKET_UNUSEABLE;
	}

	return pkt_len;
}