networking.c revision 294569
1183550Szec#include <config.h>
2196019Srwatson#include "networking.h"
3196019Srwatson#include "ntp_debug.h"
4196019Srwatson
5196019Srwatson
6196019Srwatson/* Send a packet */
7196019Srwatsonint
8196019Srwatsonsendpkt (
9196019Srwatson	SOCKET rsock,
10195699Srwatson	sockaddr_u *dest,
11195699Srwatson	struct pkt *pkt,
12195705Srwatson	int len
13183550Szec	)
14183550Szec{
15183550Szec	int cc;
16183550Szec
17183550Szec#ifdef DEBUG
18183550Szec	if (debug > 2) {
19183550Szec		printf("sntp sendpkt: Packet data:\n");
20183550Szec		pkt_output(pkt, len, stdout);
21183550Szec	}
22195705Srwatson#endif
23183550Szec	TRACE(1, ("sntp sendpkt: Sending packet to %s ...\n",
24183550Szec		  sptoa(dest)));
25183550Szec
26183550Szec	cc = sendto(rsock, (void *)pkt, len, 0, &dest->sa,
27183550Szec		    SOCKLEN(dest));
28183550Szec	if (cc == SOCKET_ERROR) {
29183550Szec		msyslog(LOG_ERR, "Send to %s failed, %m",
30183550Szec			sptoa(dest));
31183550Szec		return FALSE;
32183550Szec	}
33183550Szec	TRACE(1, ("Packet sent.\n"));
34183550Szec
35183550Szec	return TRUE;
36183550Szec}
37183550Szec
38195972Srwatson
39195972Srwatson/* Receive raw data */
40195972Srwatsonint
41195972Srwatsonrecvdata(
42196019Srwatson	SOCKET		rsock,
43196019Srwatson	sockaddr_u *	sender,
44196019Srwatson	void *		rdata,
45195972Srwatson	int		rdata_length
46195972Srwatson	)
47195972Srwatson{
48195972Srwatson	GETSOCKNAME_SOCKLEN_TYPE slen;
49195972Srwatson	int recvc;
50195972Srwatson
51195972Srwatson	slen = sizeof(*sender);
52195972Srwatson	recvc = recvfrom(rsock, rdata, rdata_length, 0,
53195972Srwatson			 &sender->sa, &slen);
54195972Srwatson	if (recvc < 0)
55195699Srwatson		return recvc;
56195699Srwatson#ifdef DEBUG
57183550Szec	if (debug > 2) {
58192669Szec		printf("Received %d bytes from %s:\n", recvc, sptoa(sender));
59183550Szec		pkt_output((struct pkt *)rdata, recvc, stdout);
60195972Srwatson	}
61196019Srwatson#endif
62196019Srwatson	return recvc;
63196019Srwatson}
64195972Srwatson
65195778Srwatson/* Parsing from a short 'struct pkt' directly is bound to create
66196019Srwatson * coverity warnings. These are hard to avoid, as the formal declaration
67196019Srwatson * does not reflect the true layout in the presence of autokey extension
68196019Srwatson * fields. Parsing and skipping the extension fields of a received packet
69196019Srwatson * until there's only the MAC left is better done in this separate
70196019Srwatson * function.
71196019Srwatson */
72196019Srwatsonstatic void*
73196019Srwatsonskip_efields(
74196019Srwatson	u_int32 *head,	/* head of extension chain 	*/
75196019Srwatson	u_int32 *tail	/* tail/end of extension chain	*/
76196019Srwatson	)
77196019Srwatson{
78196019Srwatson
79196019Srwatson	u_int nlen;	/* next extension length */
80196019Srwatson	while ((tail - head) > 6) {
81196019Srwatson		nlen = ntohl(*head++) & 0xffff;
82195778Srwatson		nlen = (nlen + 3) >> 2;
83195778Srwatson		if (nlen > (u_int)(tail - head) || nlen < 4)
84195778Srwatson			return NULL;	/* Blooper! Inconsistent! */
85195778Srwatson		head += nlen;
86195699Srwatson	}
87196019Srwatson	return head;
88253082Sae}
89253082Sae
90253082Sae/*
91253082Sae** Check if it's data for us and whether it's useable or not.
92253082Sae**
93253082Sae** If not, return a failure code so we can delete this server from our list
94253082Sae** and continue with another one.
95253082Sae*/
96253082Saeint
97253082Saeprocess_pkt (
98253082Sae	struct pkt *rpkt,
99253082Sae	sockaddr_u *sender,
100253082Sae	int pkt_len,
101253082Sae	int mode,
102253082Sae	struct pkt *spkt,
103253082Sae	const char * func_name
104253082Sae	)
105253082Sae{
106253082Sae	u_int		key_id;
107253082Sae	struct key *	pkt_key;
108253082Sae	int		is_authentic;
109253082Sae	int		mac_size;
110253082Sae	u_int		exten_len;
111253082Sae	u_int32 *       exten_end;
112253082Sae	u_int32 *       packet_end;
113253082Sae	l_fp		sent_xmt;
114253082Sae	l_fp		resp_org;
115253082Sae
116253082Sae	// key_id = 0;
117253082Sae	pkt_key = NULL;
118253082Sae	is_authentic = (HAVE_OPT(AUTHENTICATION)) ? 0 : -1;
119253082Sae
120253082Sae	/*
121253082Sae	 * Parse the extension field if present. We figure out whether
122253082Sae	 * an extension field is present by measuring the MAC size. If
123253082Sae	 * the number of words following the packet header is 0, no MAC
124253082Sae	 * is present and the packet is not authenticated. If 1, the
125253082Sae	 * packet is a crypto-NAK; if 3, the packet is authenticated
126253082Sae	 * with DES; if 5, the packet is authenticated with MD5; if 6,
127253100Sae	 * the packet is authenticated with SHA. If 2 or 4, the packet
128253100Sae	 * is a runt and discarded forthwith. If greater than 6, an
129253082Sae	 * extension field is present, so we subtract the length of the
130253082Sae	 * field and go around again.
131253082Sae	 */
132253082Sae	if (pkt_len < (int)LEN_PKT_NOMAC || (pkt_len & 3) != 0) {
133253082Sae		msyslog(LOG_ERR,
134253082Sae			"%s: Incredible packet length: %d.  Discarding.",
135253082Sae			func_name, pkt_len);
136253082Sae		return PACKET_UNUSEABLE;
137253082Sae	}
138195699Srwatson	/* Note: pkt_len must be a multiple of 4 at this point! */
139196019Srwatson	packet_end = (void*)((char*)rpkt + pkt_len);
140196019Srwatson	exten_end = skip_efields(rpkt->exten, packet_end);
141196019Srwatson	if (NULL == exten_end) {
142196019Srwatson		msyslog(LOG_ERR,
143183550Szec			"%s: Missing extension field.  Discarding.",
144196019Srwatson			func_name);
145206639Sjulian		return PACKET_UNUSEABLE;
146206639Sjulian	}
147206639Sjulian	/* get size of MAC in cells; can be zero */
148215701Sdim	exten_len = (u_int)(packet_end - exten_end);
149206639Sjulian
150215701Sdim	/* deduce action required from remaining length */
151206639Sjulian	switch (exten_len) {
152206639Sjulian
153206639Sjulian	case 0:	/* no MAC at all */
154206639Sjulian		break;
155206639Sjulian
156196019Srwatson	case 1:	/* crypto NAK */
157196019Srwatson		key_id = ntohl(*exten_end);
158196019Srwatson		printf("Crypto NAK = 0x%08x\n", key_id);
159196019Srwatson		break;
160196019Srwatson
161196019Srwatson	case 3: /* key ID + 3DES MAC -- unsupported! */
162196019Srwatson		msyslog(LOG_ERR,
163196019Srwatson			"%s: Key ID + 3DES MAC is unsupported.  Discarding.",
164196019Srwatson			func_name);
165196019Srwatson		return PACKET_UNUSEABLE;
166196019Srwatson
167196019Srwatson	case 5:	/* key ID + MD5 MAC */
168196019Srwatson	case 6:	/* key ID + SHA MAC */
169196019Srwatson		/*
170196019Srwatson		** Look for the key used by the server in the specified
171218559Sbz		** keyfile and if existent, fetch it or else leave the
172218559Sbz		** pointer untouched
173218559Sbz		*/
174218559Sbz		key_id = ntohl(*exten_end);
175218559Sbz		get_key(key_id, &pkt_key);
176218559Sbz		if (!pkt_key) {
177218559Sbz			printf("unrecognized key ID = 0x%08x\n", key_id);
178218559Sbz			break;
179218559Sbz		}
180218559Sbz		/*
181196019Srwatson		** Seems like we've got a key with matching keyid.
182203483Szec		**
183203483Szec		** Generate a md5sum of the packet with the key from our
184196019Srwatson		** keyfile and compare those md5sums.
185218559Sbz		*/
186218559Sbz		mac_size = exten_len << 2;
187218559Sbz		if (!auth_md5(rpkt, pkt_len - mac_size,
188196019Srwatson			      mac_size - 4, pkt_key)) {
189196019Srwatson			is_authentic = FALSE;
190196019Srwatson			break;
191218555Sbz		}
192196019Srwatson		/* Yay! Things worked out! */
193196019Srwatson		is_authentic = TRUE;
194196019Srwatson		TRACE(1, ("sntp %s: packet from %s authenticated using key id %d.\n",
195196019Srwatson			  func_name, stoa(sender), key_id));
196203483Szec		break;
197196019Srwatson
198196019Srwatson	default:
199196019Srwatson		msyslog(LOG_ERR,
200196019Srwatson			"%s: Unexpected extension length: %d.  Discarding.",
201218559Sbz			func_name, exten_len);
202218559Sbz		return PACKET_UNUSEABLE;
203218559Sbz	}
204218559Sbz
205196019Srwatson	switch (is_authentic) {
206196019Srwatson
207196019Srwatson	case -1:	/* unknown */
208196019Srwatson		break;
209218567Sbz
210218567Sbz	case 0:		/* not authentic */
211218567Sbz		return SERVER_AUTH_FAIL;
212218567Sbz		break;
213196019Srwatson
214196019Srwatson	case 1:		/* authentic */
215196019Srwatson		break;
216218567Sbz
217218567Sbz	default:	/* error */
218218567Sbz		break;
219218567Sbz	}
220196019Srwatson
221196019Srwatson	/* Check for server's ntp version */
222218567Sbz	if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION ||
223218567Sbz		PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) {
224218567Sbz		msyslog(LOG_ERR,
225218567Sbz			"%s: Packet shows wrong version (%d)",
226196019Srwatson			func_name, PKT_VERSION(rpkt->li_vn_mode));
227196019Srwatson		return SERVER_UNUSEABLE;
228196019Srwatson	}
229196019Srwatson	/* We want a server to sync with */
230196019Srwatson	if (PKT_MODE(rpkt->li_vn_mode) != mode &&
231196019Srwatson	    PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE) {
232196019Srwatson		msyslog(LOG_ERR,
233196019Srwatson			"%s: mode %d stratum %d", func_name,
234196019Srwatson			PKT_MODE(rpkt->li_vn_mode), rpkt->stratum);
235196019Srwatson		return SERVER_UNUSEABLE;
236196019Srwatson	}
237196019Srwatson	/* Stratum is unspecified (0) check what's going on */
238196019Srwatson	if (STRATUM_PKT_UNSPEC == rpkt->stratum) {
239196019Srwatson		char *ref_char;
240196019Srwatson
241196019Srwatson		TRACE(1, ("%s: Stratum unspecified, going to check for KOD (stratum: %d)\n",
242196019Srwatson			  func_name, rpkt->stratum));
243196019Srwatson		ref_char = (char *) &rpkt->refid;
244196019Srwatson		TRACE(1, ("%s: Packet refid: %c%c%c%c\n", func_name,
245196019Srwatson			  ref_char[0], ref_char[1], ref_char[2], ref_char[3]));
246196019Srwatson		/* If it's a KOD packet we'll just use the KOD information */
247196019Srwatson		if (ref_char[0] != 'X') {
248196019Srwatson			if (strncmp(ref_char, "DENY", 4) == 0)
249196019Srwatson				return KOD_DEMOBILIZE;
250196019Srwatson			if (strncmp(ref_char, "RSTR", 4) == 0)
251196019Srwatson				return KOD_DEMOBILIZE;
252196019Srwatson			if (strncmp(ref_char, "RATE", 4) == 0)
253196019Srwatson				return KOD_RATE;
254196019Srwatson			/*
255196019Srwatson			** There are other interesting kiss codes which
256196019Srwatson			** might be interesting for authentication.
257196019Srwatson			*/
258196019Srwatson		}
259196019Srwatson	}
260196019Srwatson	/* If the server is not synced it's not really useable for us */
261195699Srwatson	if (LEAP_NOTINSYNC == PKT_LEAP(rpkt->li_vn_mode)) {
262195699Srwatson		msyslog(LOG_ERR,
263215701Sdim			"%s: %s not in sync, skipping this server",
264215701Sdim			func_name, stoa(sender));
265215701Sdim		return SERVER_UNUSEABLE;
266183550Szec	}
267195727Srwatson
268183550Szec	/*
269195699Srwatson	 * Decode the org timestamp and make sure we're getting a response
270195699Srwatson	 * to our last request, but only if we're not in broadcast mode.
271195699Srwatson	 */
272195699Srwatson	if (MODE_BROADCAST == mode)
273195727Srwatson		return pkt_len;
274183550Szec
275195699Srwatson	if (!L_ISEQU(&rpkt->org, &spkt->xmt)) {
276195727Srwatson		NTOHL_FP(&rpkt->org, &resp_org);
277183550Szec		NTOHL_FP(&spkt->xmt, &sent_xmt);
278195699Srwatson		msyslog(LOG_ERR,
279195972Srwatson			"%s response org expected to match sent xmt",
280195972Srwatson			stoa(sender));
281195972Srwatson		msyslog(LOG_ERR, "resp org: %s", prettydate(&resp_org));
282195972Srwatson		msyslog(LOG_ERR, "sent xmt: %s", prettydate(&sent_xmt));
283195972Srwatson		return PACKET_UNUSEABLE;
284195972Srwatson	}
285195972Srwatson
286195699Srwatson	return pkt_len;
287195699Srwatson}
288195699Srwatson