xref: /freebsd/contrib/ntp/sntp/networking.c (revision 2b15cb3d0922bd70ea592f0da9b4a5b167f4d53f)
1*2b15cb3dSCy Schubert #include <config.h>
2*2b15cb3dSCy Schubert #include "networking.h"
3*2b15cb3dSCy Schubert #include "ntp_debug.h"
4*2b15cb3dSCy Schubert 
5*2b15cb3dSCy Schubert 
6*2b15cb3dSCy Schubert /* Send a packet */
7*2b15cb3dSCy Schubert int
8*2b15cb3dSCy Schubert sendpkt (
9*2b15cb3dSCy Schubert 	SOCKET rsock,
10*2b15cb3dSCy Schubert 	sockaddr_u *dest,
11*2b15cb3dSCy Schubert 	struct pkt *pkt,
12*2b15cb3dSCy Schubert 	int len
13*2b15cb3dSCy Schubert 	)
14*2b15cb3dSCy Schubert {
15*2b15cb3dSCy Schubert 	int cc;
16*2b15cb3dSCy Schubert 
17*2b15cb3dSCy Schubert #ifdef DEBUG
18*2b15cb3dSCy Schubert 	if (debug > 2) {
19*2b15cb3dSCy Schubert 		printf("sntp sendpkt: Packet data:\n");
20*2b15cb3dSCy Schubert 		pkt_output(pkt, len, stdout);
21*2b15cb3dSCy Schubert 	}
22*2b15cb3dSCy Schubert #endif
23*2b15cb3dSCy Schubert 	TRACE(1, ("sntp sendpkt: Sending packet to %s ...\n",
24*2b15cb3dSCy Schubert 		  sptoa(dest)));
25*2b15cb3dSCy Schubert 
26*2b15cb3dSCy Schubert 	cc = sendto(rsock, (void *)pkt, len, 0, &dest->sa,
27*2b15cb3dSCy Schubert 		    SOCKLEN(dest));
28*2b15cb3dSCy Schubert 	if (cc == SOCKET_ERROR) {
29*2b15cb3dSCy Schubert 		msyslog(LOG_ERR, "Send to %s failed, %m",
30*2b15cb3dSCy Schubert 			sptoa(dest));
31*2b15cb3dSCy Schubert 		return FALSE;
32*2b15cb3dSCy Schubert 	}
33*2b15cb3dSCy Schubert 	TRACE(1, ("Packet sent.\n"));
34*2b15cb3dSCy Schubert 
35*2b15cb3dSCy Schubert 	return TRUE;
36*2b15cb3dSCy Schubert }
37*2b15cb3dSCy Schubert 
38*2b15cb3dSCy Schubert 
39*2b15cb3dSCy Schubert /* Receive raw data */
40*2b15cb3dSCy Schubert int
41*2b15cb3dSCy Schubert recvdata(
42*2b15cb3dSCy Schubert 	SOCKET		rsock,
43*2b15cb3dSCy Schubert 	sockaddr_u *	sender,
44*2b15cb3dSCy Schubert 	void *		rdata,
45*2b15cb3dSCy Schubert 	int		rdata_length
46*2b15cb3dSCy Schubert 	)
47*2b15cb3dSCy Schubert {
48*2b15cb3dSCy Schubert 	GETSOCKNAME_SOCKLEN_TYPE slen;
49*2b15cb3dSCy Schubert 	int recvc;
50*2b15cb3dSCy Schubert 
51*2b15cb3dSCy Schubert 	slen = sizeof(*sender);
52*2b15cb3dSCy Schubert 	recvc = recvfrom(rsock, rdata, rdata_length, 0,
53*2b15cb3dSCy Schubert 			 &sender->sa, &slen);
54*2b15cb3dSCy Schubert 	if (recvc < 0)
55*2b15cb3dSCy Schubert 		return recvc;
56*2b15cb3dSCy Schubert #ifdef DEBUG
57*2b15cb3dSCy Schubert 	if (debug > 2) {
58*2b15cb3dSCy Schubert 		printf("Received %d bytes from %s:\n", recvc, sptoa(sender));
59*2b15cb3dSCy Schubert 		pkt_output((struct pkt *)rdata, recvc, stdout);
60*2b15cb3dSCy Schubert 	}
61*2b15cb3dSCy Schubert #endif
62*2b15cb3dSCy Schubert 	return recvc;
63*2b15cb3dSCy Schubert }
64*2b15cb3dSCy Schubert 
65*2b15cb3dSCy Schubert /* Parsing from a short 'struct pkt' directly is bound to create
66*2b15cb3dSCy Schubert  * coverity warnings. These are hard to avoid, as the formal declaration
67*2b15cb3dSCy Schubert  * does not reflect the true layout in the presence of autokey extension
68*2b15cb3dSCy Schubert  * fields. Parsing and skipping the extension fields of a received packet
69*2b15cb3dSCy Schubert  * until there's only the MAC left is better done in this separate
70*2b15cb3dSCy Schubert  * function.
71*2b15cb3dSCy Schubert  */
72*2b15cb3dSCy Schubert static void*
73*2b15cb3dSCy Schubert skip_efields(
74*2b15cb3dSCy Schubert 	u_int32 *head,	/* head of extension chain 	*/
75*2b15cb3dSCy Schubert 	u_int32 *tail	/* tail/end of extension chain	*/
76*2b15cb3dSCy Schubert 	)
77*2b15cb3dSCy Schubert {
78*2b15cb3dSCy Schubert 
79*2b15cb3dSCy Schubert 	u_int nlen;	/* next extension length */
80*2b15cb3dSCy Schubert 	while ((tail - head) > 6) {
81*2b15cb3dSCy Schubert 		nlen = ntohl(*head++) & 0xffff;
82*2b15cb3dSCy Schubert 		nlen = (nlen + 3) >> 2;
83*2b15cb3dSCy Schubert 		if (nlen > (u_int)(tail - head) || nlen < 4)
84*2b15cb3dSCy Schubert 			return NULL;	/* Blooper! Inconsistent! */
85*2b15cb3dSCy Schubert 		head += nlen;
86*2b15cb3dSCy Schubert 	}
87*2b15cb3dSCy Schubert 	return head;
88*2b15cb3dSCy Schubert }
89*2b15cb3dSCy Schubert 
90*2b15cb3dSCy Schubert /*
91*2b15cb3dSCy Schubert ** Check if it's data for us and whether it's useable or not.
92*2b15cb3dSCy Schubert **
93*2b15cb3dSCy Schubert ** If not, return a failure code so we can delete this server from our list
94*2b15cb3dSCy Schubert ** and continue with another one.
95*2b15cb3dSCy Schubert */
96*2b15cb3dSCy Schubert int
97*2b15cb3dSCy Schubert process_pkt (
98*2b15cb3dSCy Schubert 	struct pkt *rpkt,
99*2b15cb3dSCy Schubert 	sockaddr_u *sender,
100*2b15cb3dSCy Schubert 	int pkt_len,
101*2b15cb3dSCy Schubert 	int mode,
102*2b15cb3dSCy Schubert 	struct pkt *spkt,
103*2b15cb3dSCy Schubert 	const char * func_name
104*2b15cb3dSCy Schubert 	)
105*2b15cb3dSCy Schubert {
106*2b15cb3dSCy Schubert 	u_int		key_id;
107*2b15cb3dSCy Schubert 	struct key *	pkt_key;
108*2b15cb3dSCy Schubert 	int		is_authentic;
109*2b15cb3dSCy Schubert 	int		mac_size;
110*2b15cb3dSCy Schubert 	u_int		exten_len;
111*2b15cb3dSCy Schubert 	u_int32 *       exten_end;
112*2b15cb3dSCy Schubert 	u_int32 *       packet_end;
113*2b15cb3dSCy Schubert 	l_fp		sent_xmt;
114*2b15cb3dSCy Schubert 	l_fp		resp_org;
115*2b15cb3dSCy Schubert 
116*2b15cb3dSCy Schubert 	key_id = 0;
117*2b15cb3dSCy Schubert 	pkt_key = NULL;
118*2b15cb3dSCy Schubert 	is_authentic = (HAVE_OPT(AUTHENTICATION)) ? 0 : -1;
119*2b15cb3dSCy Schubert 
120*2b15cb3dSCy Schubert 	/*
121*2b15cb3dSCy Schubert 	 * Parse the extension field if present. We figure out whether
122*2b15cb3dSCy Schubert 	 * an extension field is present by measuring the MAC size. If
123*2b15cb3dSCy Schubert 	 * the number of words following the packet header is 0, no MAC
124*2b15cb3dSCy Schubert 	 * is present and the packet is not authenticated. If 1, the
125*2b15cb3dSCy Schubert 	 * packet is a crypto-NAK; if 3, the packet is authenticated
126*2b15cb3dSCy Schubert 	 * with DES; if 5, the packet is authenticated with MD5; if 6,
127*2b15cb3dSCy Schubert 	 * the packet is authenticated with SHA. If 2 or 4, the packet
128*2b15cb3dSCy Schubert 	 * is a runt and discarded forthwith. If greater than 6, an
129*2b15cb3dSCy Schubert 	 * extension field is present, so we subtract the length of the
130*2b15cb3dSCy Schubert 	 * field and go around again.
131*2b15cb3dSCy Schubert 	 */
132*2b15cb3dSCy Schubert 	if (pkt_len < (int)LEN_PKT_NOMAC || (pkt_len & 3) != 0) {
133*2b15cb3dSCy Schubert 		msyslog(LOG_ERR,
134*2b15cb3dSCy Schubert 			"%s: Incredible packet length: %d.  Discarding.",
135*2b15cb3dSCy Schubert 			func_name, pkt_len);
136*2b15cb3dSCy Schubert 		return PACKET_UNUSEABLE;
137*2b15cb3dSCy Schubert 	}
138*2b15cb3dSCy Schubert 	/* Note: pkt_len must be a multiple of 4 at this point! */
139*2b15cb3dSCy Schubert 	packet_end = (u_int32*)((char*)rpkt + pkt_len);
140*2b15cb3dSCy Schubert 	exten_end = skip_efields(rpkt->exten, packet_end);
141*2b15cb3dSCy Schubert 	if (NULL == exten_end) {
142*2b15cb3dSCy Schubert 		msyslog(LOG_ERR,
143*2b15cb3dSCy Schubert 			"%s: Missing extension field.  Discarding.",
144*2b15cb3dSCy Schubert 			func_name);
145*2b15cb3dSCy Schubert 		return PACKET_UNUSEABLE;
146*2b15cb3dSCy Schubert 	}
147*2b15cb3dSCy Schubert 	/* get size of MAC in cells; can be zero */
148*2b15cb3dSCy Schubert 	exten_len = (u_int)(packet_end - exten_end);
149*2b15cb3dSCy Schubert 
150*2b15cb3dSCy Schubert 	/* deduce action required from remaining length */
151*2b15cb3dSCy Schubert 	switch (exten_len) {
152*2b15cb3dSCy Schubert 
153*2b15cb3dSCy Schubert 	case 0:	/* no MAC at all */
154*2b15cb3dSCy Schubert 		break;
155*2b15cb3dSCy Schubert 
156*2b15cb3dSCy Schubert 	case 1:	/* crypto NAK */
157*2b15cb3dSCy Schubert 		key_id = ntohl(*exten_end);
158*2b15cb3dSCy Schubert 		printf("Crypto NAK = 0x%08x\n", key_id);
159*2b15cb3dSCy Schubert 		break;
160*2b15cb3dSCy Schubert 
161*2b15cb3dSCy Schubert 	case 3: /* key ID + 3DES MAC -- unsupported! */
162*2b15cb3dSCy Schubert 		msyslog(LOG_ERR,
163*2b15cb3dSCy Schubert 			"%s: Key ID + 3DES MAC is unsupported.  Discarding.",
164*2b15cb3dSCy Schubert 			func_name);
165*2b15cb3dSCy Schubert 		return PACKET_UNUSEABLE;
166*2b15cb3dSCy Schubert 
167*2b15cb3dSCy Schubert 	case 5:	/* key ID + MD5 MAC */
168*2b15cb3dSCy Schubert 	case 6:	/* key ID + SHA MAC */
169*2b15cb3dSCy Schubert 		/*
170*2b15cb3dSCy Schubert 		** Look for the key used by the server in the specified
171*2b15cb3dSCy Schubert 		** keyfile and if existent, fetch it or else leave the
172*2b15cb3dSCy Schubert 		** pointer untouched
173*2b15cb3dSCy Schubert 		*/
174*2b15cb3dSCy Schubert 		key_id = ntohl(*exten_end);
175*2b15cb3dSCy Schubert 		get_key(key_id, &pkt_key);
176*2b15cb3dSCy Schubert 		if (!pkt_key) {
177*2b15cb3dSCy Schubert 			printf("unrecognized key ID = 0x%08x\n", key_id);
178*2b15cb3dSCy Schubert 			break;
179*2b15cb3dSCy Schubert 		}
180*2b15cb3dSCy Schubert 		/*
181*2b15cb3dSCy Schubert 		** Seems like we've got a key with matching keyid.
182*2b15cb3dSCy Schubert 		**
183*2b15cb3dSCy Schubert 		** Generate a md5sum of the packet with the key from our
184*2b15cb3dSCy Schubert 		** keyfile and compare those md5sums.
185*2b15cb3dSCy Schubert 		*/
186*2b15cb3dSCy Schubert 		mac_size = exten_len << 2;
187*2b15cb3dSCy Schubert 		if (!auth_md5((char *)rpkt, pkt_len - mac_size,
188*2b15cb3dSCy Schubert 			      mac_size - 4, pkt_key)) {
189*2b15cb3dSCy Schubert 			is_authentic = FALSE;
190*2b15cb3dSCy Schubert 			break;
191*2b15cb3dSCy Schubert 		}
192*2b15cb3dSCy Schubert 		/* Yay! Things worked out! */
193*2b15cb3dSCy Schubert 		is_authentic = TRUE;
194*2b15cb3dSCy Schubert 		TRACE(1, ("sntp %s: packet from %s authenticated using key id %d.\n",
195*2b15cb3dSCy Schubert 			  func_name, stoa(sender), key_id));
196*2b15cb3dSCy Schubert 		break;
197*2b15cb3dSCy Schubert 
198*2b15cb3dSCy Schubert 	default:
199*2b15cb3dSCy Schubert 		msyslog(LOG_ERR,
200*2b15cb3dSCy Schubert 			"%s: Unexpected extension length: %d.  Discarding.",
201*2b15cb3dSCy Schubert 			func_name, exten_len);
202*2b15cb3dSCy Schubert 		return PACKET_UNUSEABLE;
203*2b15cb3dSCy Schubert 	}
204*2b15cb3dSCy Schubert 
205*2b15cb3dSCy Schubert 	switch (is_authentic) {
206*2b15cb3dSCy Schubert 
207*2b15cb3dSCy Schubert 	case -1:	/* unknown */
208*2b15cb3dSCy Schubert 		break;
209*2b15cb3dSCy Schubert 
210*2b15cb3dSCy Schubert 	case 0:		/* not authentic */
211*2b15cb3dSCy Schubert 		return SERVER_AUTH_FAIL;
212*2b15cb3dSCy Schubert 		break;
213*2b15cb3dSCy Schubert 
214*2b15cb3dSCy Schubert 	case 1:		/* authentic */
215*2b15cb3dSCy Schubert 		break;
216*2b15cb3dSCy Schubert 
217*2b15cb3dSCy Schubert 	default:	/* error */
218*2b15cb3dSCy Schubert 		break;
219*2b15cb3dSCy Schubert 	}
220*2b15cb3dSCy Schubert 
221*2b15cb3dSCy Schubert 	/* Check for server's ntp version */
222*2b15cb3dSCy Schubert 	if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION ||
223*2b15cb3dSCy Schubert 		PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) {
224*2b15cb3dSCy Schubert 		msyslog(LOG_ERR,
225*2b15cb3dSCy Schubert 			"%s: Packet shows wrong version (%d)",
226*2b15cb3dSCy Schubert 			func_name, PKT_VERSION(rpkt->li_vn_mode));
227*2b15cb3dSCy Schubert 		return SERVER_UNUSEABLE;
228*2b15cb3dSCy Schubert 	}
229*2b15cb3dSCy Schubert 	/* We want a server to sync with */
230*2b15cb3dSCy Schubert 	if (PKT_MODE(rpkt->li_vn_mode) != mode &&
231*2b15cb3dSCy Schubert 	    PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE) {
232*2b15cb3dSCy Schubert 		msyslog(LOG_ERR,
233*2b15cb3dSCy Schubert 			"%s: mode %d stratum %d", func_name,
234*2b15cb3dSCy Schubert 			PKT_MODE(rpkt->li_vn_mode), rpkt->stratum);
235*2b15cb3dSCy Schubert 		return SERVER_UNUSEABLE;
236*2b15cb3dSCy Schubert 	}
237*2b15cb3dSCy Schubert 	/* Stratum is unspecified (0) check what's going on */
238*2b15cb3dSCy Schubert 	if (STRATUM_PKT_UNSPEC == rpkt->stratum) {
239*2b15cb3dSCy Schubert 		char *ref_char;
240*2b15cb3dSCy Schubert 
241*2b15cb3dSCy Schubert 		TRACE(1, ("%s: Stratum unspecified, going to check for KOD (stratum: %d)\n",
242*2b15cb3dSCy Schubert 			  func_name, rpkt->stratum));
243*2b15cb3dSCy Schubert 		ref_char = (char *) &rpkt->refid;
244*2b15cb3dSCy Schubert 		TRACE(1, ("%s: Packet refid: %c%c%c%c\n", func_name,
245*2b15cb3dSCy Schubert 			  ref_char[0], ref_char[1], ref_char[2], ref_char[3]));
246*2b15cb3dSCy Schubert 		/* If it's a KOD packet we'll just use the KOD information */
247*2b15cb3dSCy Schubert 		if (ref_char[0] != 'X') {
248*2b15cb3dSCy Schubert 			if (strncmp(ref_char, "DENY", 4) == 0)
249*2b15cb3dSCy Schubert 				return KOD_DEMOBILIZE;
250*2b15cb3dSCy Schubert 			if (strncmp(ref_char, "RSTR", 4) == 0)
251*2b15cb3dSCy Schubert 				return KOD_DEMOBILIZE;
252*2b15cb3dSCy Schubert 			if (strncmp(ref_char, "RATE", 4) == 0)
253*2b15cb3dSCy Schubert 				return KOD_RATE;
254*2b15cb3dSCy Schubert 			/*
255*2b15cb3dSCy Schubert 			** There are other interesting kiss codes which
256*2b15cb3dSCy Schubert 			** might be interesting for authentication.
257*2b15cb3dSCy Schubert 			*/
258*2b15cb3dSCy Schubert 		}
259*2b15cb3dSCy Schubert 	}
260*2b15cb3dSCy Schubert 	/* If the server is not synced it's not really useable for us */
261*2b15cb3dSCy Schubert 	if (LEAP_NOTINSYNC == PKT_LEAP(rpkt->li_vn_mode)) {
262*2b15cb3dSCy Schubert 		msyslog(LOG_ERR,
263*2b15cb3dSCy Schubert 			"%s: %s not in sync, skipping this server",
264*2b15cb3dSCy Schubert 			func_name, stoa(sender));
265*2b15cb3dSCy Schubert 		return SERVER_UNUSEABLE;
266*2b15cb3dSCy Schubert 	}
267*2b15cb3dSCy Schubert 
268*2b15cb3dSCy Schubert 	/*
269*2b15cb3dSCy Schubert 	 * Decode the org timestamp and make sure we're getting a response
270*2b15cb3dSCy Schubert 	 * to our last request, but only if we're not in broadcast mode.
271*2b15cb3dSCy Schubert 	 */
272*2b15cb3dSCy Schubert 	if (MODE_BROADCAST == mode)
273*2b15cb3dSCy Schubert 		return pkt_len;
274*2b15cb3dSCy Schubert 
275*2b15cb3dSCy Schubert 	if (!L_ISEQU(&rpkt->org, &spkt->xmt)) {
276*2b15cb3dSCy Schubert 		NTOHL_FP(&rpkt->org, &resp_org);
277*2b15cb3dSCy Schubert 		NTOHL_FP(&spkt->xmt, &sent_xmt);
278*2b15cb3dSCy Schubert 		msyslog(LOG_ERR,
279*2b15cb3dSCy Schubert 			"%s response org expected to match sent xmt",
280*2b15cb3dSCy Schubert 			stoa(sender));
281*2b15cb3dSCy Schubert 		msyslog(LOG_ERR, "resp org: %s", prettydate(&resp_org));
282*2b15cb3dSCy Schubert 		msyslog(LOG_ERR, "sent xmt: %s", prettydate(&sent_xmt));
283*2b15cb3dSCy Schubert 		return PACKET_UNUSEABLE;
284*2b15cb3dSCy Schubert 	}
285*2b15cb3dSCy Schubert 
286*2b15cb3dSCy Schubert 	return pkt_len;
287*2b15cb3dSCy Schubert }
288