xref: /freebsd/contrib/ntp/sntp/networking.c (revision e43d33d286a1aa41b6fc6a209f28a18e8cd7437a)
12b15cb3dSCy Schubert #include <config.h>
22b15cb3dSCy Schubert #include "networking.h"
32b15cb3dSCy Schubert #include "ntp_debug.h"
42b15cb3dSCy Schubert 
52b15cb3dSCy Schubert 
62b15cb3dSCy Schubert /* Send a packet */
72b15cb3dSCy Schubert int
sendpkt(SOCKET rsock,sockaddr_u * dest,struct pkt * pkt,int len)82b15cb3dSCy Schubert sendpkt (
92b15cb3dSCy Schubert 	SOCKET rsock,
102b15cb3dSCy Schubert 	sockaddr_u *dest,
112b15cb3dSCy Schubert 	struct pkt *pkt,
122b15cb3dSCy Schubert 	int len
132b15cb3dSCy Schubert 	)
142b15cb3dSCy Schubert {
152b15cb3dSCy Schubert 	int cc;
162b15cb3dSCy Schubert 
172b15cb3dSCy Schubert #ifdef DEBUG
182b15cb3dSCy Schubert 	if (debug > 2) {
192b15cb3dSCy Schubert 		printf("sntp sendpkt: Packet data:\n");
202b15cb3dSCy Schubert 		pkt_output(pkt, len, stdout);
212b15cb3dSCy Schubert 	}
222b15cb3dSCy Schubert #endif
232b15cb3dSCy Schubert 	TRACE(1, ("sntp sendpkt: Sending packet to %s ...\n",
242b15cb3dSCy Schubert 		  sptoa(dest)));
252b15cb3dSCy Schubert 
262b15cb3dSCy Schubert 	cc = sendto(rsock, (void *)pkt, len, 0, &dest->sa,
272b15cb3dSCy Schubert 		    SOCKLEN(dest));
282b15cb3dSCy Schubert 	if (cc == SOCKET_ERROR) {
29*2d4e511cSCy Schubert 		msyslog(LOG_ERR, "sendpkt: sendto(%s) failed: %m",
302b15cb3dSCy Schubert 			sptoa(dest));
312b15cb3dSCy Schubert 		return FALSE;
322b15cb3dSCy Schubert 	}
332b15cb3dSCy Schubert 	TRACE(1, ("Packet sent.\n"));
342b15cb3dSCy Schubert 
352b15cb3dSCy Schubert 	return TRUE;
362b15cb3dSCy Schubert }
372b15cb3dSCy Schubert 
382b15cb3dSCy Schubert 
392b15cb3dSCy Schubert /* Receive raw data */
402b15cb3dSCy Schubert int
recvdata(SOCKET rsock,sockaddr_u * sender,void * rdata,int rdata_length)412b15cb3dSCy Schubert recvdata(
422b15cb3dSCy Schubert 	SOCKET		rsock,
432b15cb3dSCy Schubert 	sockaddr_u *	sender,
442b15cb3dSCy Schubert 	void *		rdata,
452b15cb3dSCy Schubert 	int		rdata_length
462b15cb3dSCy Schubert 	)
472b15cb3dSCy Schubert {
482b15cb3dSCy Schubert 	GETSOCKNAME_SOCKLEN_TYPE slen;
492b15cb3dSCy Schubert 	int recvc;
502b15cb3dSCy Schubert 
512b15cb3dSCy Schubert 	slen = sizeof(*sender);
522b15cb3dSCy Schubert 	recvc = recvfrom(rsock, rdata, rdata_length, 0,
532b15cb3dSCy Schubert 			 &sender->sa, &slen);
542b15cb3dSCy Schubert 	if (recvc < 0)
552b15cb3dSCy Schubert 		return recvc;
562b15cb3dSCy Schubert #ifdef DEBUG
572b15cb3dSCy Schubert 	if (debug > 2) {
582b15cb3dSCy Schubert 		printf("Received %d bytes from %s:\n", recvc, sptoa(sender));
592b15cb3dSCy Schubert 		pkt_output((struct pkt *)rdata, recvc, stdout);
602b15cb3dSCy Schubert 	}
612b15cb3dSCy Schubert #endif
622b15cb3dSCy Schubert 	return recvc;
632b15cb3dSCy Schubert }
642b15cb3dSCy Schubert 
652b15cb3dSCy Schubert /* Parsing from a short 'struct pkt' directly is bound to create
662b15cb3dSCy Schubert  * coverity warnings. These are hard to avoid, as the formal declaration
672b15cb3dSCy Schubert  * does not reflect the true layout in the presence of autokey extension
682b15cb3dSCy Schubert  * fields. Parsing and skipping the extension fields of a received packet
692b15cb3dSCy Schubert  * until there's only the MAC left is better done in this separate
702b15cb3dSCy Schubert  * function.
712b15cb3dSCy Schubert  */
722b15cb3dSCy Schubert static void*
skip_efields(u_int32 * head,u_int32 * tail)732b15cb3dSCy Schubert skip_efields(
742b15cb3dSCy Schubert 	u_int32 *head,	/* head of extension chain 	*/
752b15cb3dSCy Schubert 	u_int32 *tail	/* tail/end of extension chain	*/
762b15cb3dSCy Schubert 	)
772b15cb3dSCy Schubert {
782b15cb3dSCy Schubert 
792b15cb3dSCy Schubert 	u_int nlen;	/* next extension length */
802b15cb3dSCy Schubert 	while ((tail - head) > 6) {
81052d159aSCy Schubert 		nlen = ntohl(*head) & 0xffff;
82052d159aSCy Schubert 		++head;
832b15cb3dSCy Schubert 		nlen = (nlen + 3) >> 2;
842b15cb3dSCy Schubert 		if (nlen > (u_int)(tail - head) || nlen < 4)
852b15cb3dSCy Schubert 			return NULL;	/* Blooper! Inconsistent! */
862b15cb3dSCy Schubert 		head += nlen;
872b15cb3dSCy Schubert 	}
882b15cb3dSCy Schubert 	return head;
892b15cb3dSCy Schubert }
902b15cb3dSCy Schubert 
912b15cb3dSCy Schubert /*
922b15cb3dSCy Schubert ** Check if it's data for us and whether it's useable or not.
932b15cb3dSCy Schubert **
942b15cb3dSCy Schubert ** If not, return a failure code so we can delete this server from our list
952b15cb3dSCy Schubert ** and continue with another one.
962b15cb3dSCy Schubert */
972b15cb3dSCy Schubert int
process_pkt(struct pkt * rpkt,sockaddr_u * sender,int pkt_len,int mode,struct pkt * spkt,const char * func_name)982b15cb3dSCy Schubert process_pkt (
992b15cb3dSCy Schubert 	struct pkt *rpkt,
1002b15cb3dSCy Schubert 	sockaddr_u *sender,
1012b15cb3dSCy Schubert 	int pkt_len,
1022b15cb3dSCy Schubert 	int mode,
1032b15cb3dSCy Schubert 	struct pkt *spkt,
1042b15cb3dSCy Schubert 	const char * func_name
1052b15cb3dSCy Schubert 	)
1062b15cb3dSCy Schubert {
1072b15cb3dSCy Schubert 	u_int		key_id;
1082b15cb3dSCy Schubert 	struct key *	pkt_key;
1092b15cb3dSCy Schubert 	int		is_authentic;
1102b15cb3dSCy Schubert 	int		mac_size;
1112b15cb3dSCy Schubert 	u_int		exten_len;
1122b15cb3dSCy Schubert 	u_int32 *       exten_end;
1132b15cb3dSCy Schubert 	u_int32 *       packet_end;
1142b15cb3dSCy Schubert 	l_fp		sent_xmt;
1152b15cb3dSCy Schubert 	l_fp		resp_org;
1162b15cb3dSCy Schubert 
1179034852cSGleb Smirnoff 	// key_id = 0;
1182b15cb3dSCy Schubert 	pkt_key = NULL;
1192b15cb3dSCy Schubert 	is_authentic = (HAVE_OPT(AUTHENTICATION)) ? 0 : -1;
1202b15cb3dSCy Schubert 
1212b15cb3dSCy Schubert 	/*
1222b15cb3dSCy Schubert 	 * Parse the extension field if present. We figure out whether
1232b15cb3dSCy Schubert 	 * an extension field is present by measuring the MAC size. If
1242b15cb3dSCy Schubert 	 * the number of words following the packet header is 0, no MAC
1252b15cb3dSCy Schubert 	 * is present and the packet is not authenticated. If 1, the
1262b15cb3dSCy Schubert 	 * packet is a crypto-NAK; if 3, the packet is authenticated
1272b15cb3dSCy Schubert 	 * with DES; if 5, the packet is authenticated with MD5; if 6,
1282b15cb3dSCy Schubert 	 * the packet is authenticated with SHA. If 2 or 4, the packet
1292b15cb3dSCy Schubert 	 * is a runt and discarded forthwith. If greater than 6, an
1302b15cb3dSCy Schubert 	 * extension field is present, so we subtract the length of the
1312b15cb3dSCy Schubert 	 * field and go around again.
1322b15cb3dSCy Schubert 	 */
1332b15cb3dSCy Schubert 	if (pkt_len < (int)LEN_PKT_NOMAC || (pkt_len & 3) != 0) {
1342b15cb3dSCy Schubert 		msyslog(LOG_ERR,
1352b15cb3dSCy Schubert 			"%s: Incredible packet length: %d.  Discarding.",
1362b15cb3dSCy Schubert 			func_name, pkt_len);
1372b15cb3dSCy Schubert 		return PACKET_UNUSEABLE;
1382b15cb3dSCy Schubert 	}
13909100258SXin LI 
14009100258SXin LI 	/* HMS: the following needs a bit of work */
1412b15cb3dSCy Schubert 	/* Note: pkt_len must be a multiple of 4 at this point! */
1423311ff84SXin LI 	packet_end = (void*)((char*)rpkt + pkt_len);
1432b15cb3dSCy Schubert 	exten_end = skip_efields(rpkt->exten, packet_end);
1442b15cb3dSCy Schubert 	if (NULL == exten_end) {
1452b15cb3dSCy Schubert 		msyslog(LOG_ERR,
1462b15cb3dSCy Schubert 			"%s: Missing extension field.  Discarding.",
1472b15cb3dSCy Schubert 			func_name);
1482b15cb3dSCy Schubert 		return PACKET_UNUSEABLE;
1492b15cb3dSCy Schubert 	}
15009100258SXin LI 
1512b15cb3dSCy Schubert 	/* get size of MAC in cells; can be zero */
1522b15cb3dSCy Schubert 	exten_len = (u_int)(packet_end - exten_end);
1532b15cb3dSCy Schubert 
1542b15cb3dSCy Schubert 	/* deduce action required from remaining length */
1552b15cb3dSCy Schubert 	switch (exten_len) {
1562b15cb3dSCy Schubert 
15709100258SXin LI 	case 0:	/* no Legacy MAC */
1582b15cb3dSCy Schubert 		break;
1592b15cb3dSCy Schubert 
1602b15cb3dSCy Schubert 	case 1:	/* crypto NAK */
16109100258SXin LI 		/* Only if the keyID is 0 and there were no EFs */
1622b15cb3dSCy Schubert 		key_id = ntohl(*exten_end);
16309100258SXin LI 		printf("Crypto NAK = 0x%08x from %s\n", key_id, stoa(sender));
1642b15cb3dSCy Schubert 		break;
1652b15cb3dSCy Schubert 
1662b15cb3dSCy Schubert 	case 3: /* key ID + 3DES MAC -- unsupported! */
1672b15cb3dSCy Schubert 		msyslog(LOG_ERR,
1682b15cb3dSCy Schubert 			"%s: Key ID + 3DES MAC is unsupported.  Discarding.",
1692b15cb3dSCy Schubert 			func_name);
1702b15cb3dSCy Schubert 		return PACKET_UNUSEABLE;
1712b15cb3dSCy Schubert 
1722b15cb3dSCy Schubert 	case 5:	/* key ID + MD5 MAC */
1732b15cb3dSCy Schubert 	case 6:	/* key ID + SHA MAC */
1742b15cb3dSCy Schubert 		/*
1752b15cb3dSCy Schubert 		** Look for the key used by the server in the specified
1762b15cb3dSCy Schubert 		** keyfile and if existent, fetch it or else leave the
1772b15cb3dSCy Schubert 		** pointer untouched
1782b15cb3dSCy Schubert 		*/
1792b15cb3dSCy Schubert 		key_id = ntohl(*exten_end);
1802b15cb3dSCy Schubert 		get_key(key_id, &pkt_key);
1812b15cb3dSCy Schubert 		if (!pkt_key) {
1822b15cb3dSCy Schubert 			printf("unrecognized key ID = 0x%08x\n", key_id);
1832b15cb3dSCy Schubert 			break;
1842b15cb3dSCy Schubert 		}
1852b15cb3dSCy Schubert 		/*
1862b15cb3dSCy Schubert 		** Seems like we've got a key with matching keyid.
1872b15cb3dSCy Schubert 		**
1882b15cb3dSCy Schubert 		** Generate a md5sum of the packet with the key from our
1892b15cb3dSCy Schubert 		** keyfile and compare those md5sums.
1902b15cb3dSCy Schubert 		*/
1912b15cb3dSCy Schubert 		mac_size = exten_len << 2;
19268ba7e87SXin LI 		if (!auth_md5(rpkt, pkt_len - mac_size,
1932b15cb3dSCy Schubert 			      mac_size - 4, pkt_key)) {
1942b15cb3dSCy Schubert 			is_authentic = FALSE;
1952b15cb3dSCy Schubert 			break;
1962b15cb3dSCy Schubert 		}
1972b15cb3dSCy Schubert 		/* Yay! Things worked out! */
1982b15cb3dSCy Schubert 		is_authentic = TRUE;
1992b15cb3dSCy Schubert 		TRACE(1, ("sntp %s: packet from %s authenticated using key id %d.\n",
2002b15cb3dSCy Schubert 			  func_name, stoa(sender), key_id));
2012b15cb3dSCy Schubert 		break;
2022b15cb3dSCy Schubert 
2032b15cb3dSCy Schubert 	default:
2042b15cb3dSCy Schubert 		msyslog(LOG_ERR,
2052b15cb3dSCy Schubert 			"%s: Unexpected extension length: %d.  Discarding.",
2062b15cb3dSCy Schubert 			func_name, exten_len);
2072b15cb3dSCy Schubert 		return PACKET_UNUSEABLE;
2082b15cb3dSCy Schubert 	}
2092b15cb3dSCy Schubert 
2102b15cb3dSCy Schubert 	switch (is_authentic) {
2112b15cb3dSCy Schubert 
2122b15cb3dSCy Schubert 	case -1:	/* unknown */
2132b15cb3dSCy Schubert 		break;
2142b15cb3dSCy Schubert 
2152b15cb3dSCy Schubert 	case 0:		/* not authentic */
2162b15cb3dSCy Schubert 		return SERVER_AUTH_FAIL;
2172b15cb3dSCy Schubert 		break;
2182b15cb3dSCy Schubert 
2192b15cb3dSCy Schubert 	case 1:		/* authentic */
2202b15cb3dSCy Schubert 		break;
2212b15cb3dSCy Schubert 
2222b15cb3dSCy Schubert 	default:	/* error */
2232b15cb3dSCy Schubert 		break;
2242b15cb3dSCy Schubert 	}
2252b15cb3dSCy Schubert 
2262b15cb3dSCy Schubert 	/* Check for server's ntp version */
2272b15cb3dSCy Schubert 	if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION ||
2282b15cb3dSCy Schubert 		PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) {
2292b15cb3dSCy Schubert 		msyslog(LOG_ERR,
2302b15cb3dSCy Schubert 			"%s: Packet shows wrong version (%d)",
2312b15cb3dSCy Schubert 			func_name, PKT_VERSION(rpkt->li_vn_mode));
2322b15cb3dSCy Schubert 		return SERVER_UNUSEABLE;
2332b15cb3dSCy Schubert 	}
2342b15cb3dSCy Schubert 	/* We want a server to sync with */
2352b15cb3dSCy Schubert 	if (PKT_MODE(rpkt->li_vn_mode) != mode &&
2362b15cb3dSCy Schubert 	    PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE) {
2372b15cb3dSCy Schubert 		msyslog(LOG_ERR,
2382b15cb3dSCy Schubert 			"%s: mode %d stratum %d", func_name,
2392b15cb3dSCy Schubert 			PKT_MODE(rpkt->li_vn_mode), rpkt->stratum);
2402b15cb3dSCy Schubert 		return SERVER_UNUSEABLE;
2412b15cb3dSCy Schubert 	}
2422b15cb3dSCy Schubert 	/* Stratum is unspecified (0) check what's going on */
2432b15cb3dSCy Schubert 	if (STRATUM_PKT_UNSPEC == rpkt->stratum) {
2442b15cb3dSCy Schubert 		char *ref_char;
2452b15cb3dSCy Schubert 
2462b15cb3dSCy Schubert 		TRACE(1, ("%s: Stratum unspecified, going to check for KOD (stratum: %d)\n",
2472b15cb3dSCy Schubert 			  func_name, rpkt->stratum));
2482b15cb3dSCy Schubert 		ref_char = (char *) &rpkt->refid;
2492b15cb3dSCy Schubert 		TRACE(1, ("%s: Packet refid: %c%c%c%c\n", func_name,
2502b15cb3dSCy Schubert 			  ref_char[0], ref_char[1], ref_char[2], ref_char[3]));
2512b15cb3dSCy Schubert 		/* If it's a KOD packet we'll just use the KOD information */
2522b15cb3dSCy Schubert 		if (ref_char[0] != 'X') {
2532b15cb3dSCy Schubert 			if (strncmp(ref_char, "DENY", 4) == 0)
2542b15cb3dSCy Schubert 				return KOD_DEMOBILIZE;
2552b15cb3dSCy Schubert 			if (strncmp(ref_char, "RSTR", 4) == 0)
2562b15cb3dSCy Schubert 				return KOD_DEMOBILIZE;
2572b15cb3dSCy Schubert 			if (strncmp(ref_char, "RATE", 4) == 0)
2582b15cb3dSCy Schubert 				return KOD_RATE;
2592b15cb3dSCy Schubert 			/*
2602b15cb3dSCy Schubert 			** There are other interesting kiss codes which
2612b15cb3dSCy Schubert 			** might be interesting for authentication.
2622b15cb3dSCy Schubert 			*/
2632b15cb3dSCy Schubert 		}
2642b15cb3dSCy Schubert 	}
2652b15cb3dSCy Schubert 	/* If the server is not synced it's not really useable for us */
2662b15cb3dSCy Schubert 	if (LEAP_NOTINSYNC == PKT_LEAP(rpkt->li_vn_mode)) {
2672b15cb3dSCy Schubert 		msyslog(LOG_ERR,
2682b15cb3dSCy Schubert 			"%s: %s not in sync, skipping this server",
2692b15cb3dSCy Schubert 			func_name, stoa(sender));
2702b15cb3dSCy Schubert 		return SERVER_UNUSEABLE;
2712b15cb3dSCy Schubert 	}
2722b15cb3dSCy Schubert 
2732b15cb3dSCy Schubert 	/*
2742b15cb3dSCy Schubert 	 * Decode the org timestamp and make sure we're getting a response
2752b15cb3dSCy Schubert 	 * to our last request, but only if we're not in broadcast mode.
2762b15cb3dSCy Schubert 	 */
2772b15cb3dSCy Schubert 	if (MODE_BROADCAST == mode)
2782b15cb3dSCy Schubert 		return pkt_len;
2792b15cb3dSCy Schubert 
2802b15cb3dSCy Schubert 	if (!L_ISEQU(&rpkt->org, &spkt->xmt)) {
2812b15cb3dSCy Schubert 		NTOHL_FP(&rpkt->org, &resp_org);
2822b15cb3dSCy Schubert 		NTOHL_FP(&spkt->xmt, &sent_xmt);
2832b15cb3dSCy Schubert 		msyslog(LOG_ERR,
2842b15cb3dSCy Schubert 			"%s response org expected to match sent xmt",
2852b15cb3dSCy Schubert 			stoa(sender));
2862b15cb3dSCy Schubert 		msyslog(LOG_ERR, "resp org: %s", prettydate(&resp_org));
2872b15cb3dSCy Schubert 		msyslog(LOG_ERR, "sent xmt: %s", prettydate(&sent_xmt));
2882b15cb3dSCy Schubert 		return PACKET_UNUSEABLE;
2892b15cb3dSCy Schubert 	}
2902b15cb3dSCy Schubert 
2912b15cb3dSCy Schubert 	return pkt_len;
2922b15cb3dSCy Schubert }
293