xref: /netbsd-src/external/bsd/ntp/dist/sntp/networking.c (revision 4391d5e9d4f291db41e3b3ba26a01b5e51364aae)
1 /*	$NetBSD: networking.c,v 1.6 2012/02/01 20:48:01 kardel Exp $	*/
2 
3 #include <config.h>
4 #include "networking.h"
5 
6 char adr_buf[INET6_ADDRSTRLEN];
7 
8 
9 /* resolve_hosts consumes an array of hostnames/addresses and its length, stores a pointer
10  * to the array with the resolved hosts in res and returns the size of the array res.
11  * pref_family enforces IPv4 or IPv6 depending on commandline options and system
12  * capability. If pref_family is NULL or PF_UNSPEC any compatible family will be accepted.
13  * Check here: Probably getaddrinfo() can do without ISC's IPv6 availability check?
14  */
15 int
16 resolve_hosts (
17 		const char **hosts,
18 		int hostc,
19 		struct addrinfo ***res,
20 		int pref_family
21 		)
22 {
23 	register int a;
24 	unsigned int resc;
25 	struct addrinfo **tres;
26 
27 	if (hostc < 1 || NULL == res)
28 		return 0;
29 
30 	tres = emalloc(sizeof(struct addrinfo *) * hostc);
31 	for (a = 0, resc = 0; a < hostc; a++) {
32 		struct addrinfo hints;
33 		int error;
34 
35 		tres[resc] = NULL;
36 #ifdef DEBUG
37 		printf("sntp resolve_hosts: Starting host resolution for %s...\n", hosts[a]);
38 #endif
39 		memset(&hints, 0, sizeof(hints));
40 		if (AF_UNSPEC == pref_family)
41 			hints.ai_family = PF_UNSPEC;
42 		else
43 			hints.ai_family = pref_family;
44 		hints.ai_socktype = SOCK_DGRAM;
45 		error = getaddrinfo(hosts[a], "123", &hints, &tres[resc]);
46 		if (error) {
47 			msyslog(LOG_DEBUG, "Error looking up %s%s: %s",
48 				(AF_UNSPEC == hints.ai_family)
49 				    ? ""
50 				    : (AF_INET == hints.ai_family)
51 					  ? "(A) "
52 					  : "(AAAA) ",
53 				hosts[a], gai_strerror(error));
54 		} else {
55 #ifdef DEBUG
56 			struct addrinfo *dres;
57 
58 			for (dres = tres[resc]; dres; dres = dres->ai_next) {
59 				getnameinfo(dres->ai_addr, dres->ai_addrlen, adr_buf, sizeof(adr_buf), NULL, 0, NI_NUMERICHOST);
60 				STDLINE
61 				printf("Resolv No.: %i Result of getaddrinfo for %s:\n", resc, hosts[a]);
62 				printf("socktype: %i ", dres->ai_socktype);
63 				printf("protocol: %i ", dres->ai_protocol);
64 				printf("Prefered socktype: %i IP: %s\n", dres->ai_socktype, adr_buf);
65 				STDLINE
66 			}
67 #endif
68 			resc++;
69 		}
70 	}
71 
72 	if (resc)
73 		*res = realloc(tres, sizeof(struct addrinfo *) * resc);
74 	else {
75 		free(tres);
76 		*res = NULL;
77 	}
78 	return resc;
79 }
80 
81 /* Creates a socket and returns. */
82 void
83 create_socket (
84 		SOCKET *rsock,
85 		sockaddr_u *dest
86 		)
87 {
88 	*rsock = socket(AF(dest), SOCK_DGRAM, 0);
89 
90 	if (-1 == *rsock && ENABLED_OPT(NORMALVERBOSE))
91 		printf("Failed to create UDP socket with family %d\n", AF(dest));
92 }
93 
94 /* Send a packet */
95 void
96 sendpkt (
97 	SOCKET rsock,
98 	sockaddr_u *dest,
99 	struct pkt *pkt,
100 	int len
101 	)
102 {
103 	int cc;
104 
105 #ifdef DEBUG
106 	printf("sntp sendpkt: Packet data:\n");
107 	pkt_output(pkt, len, stdout);
108 #endif
109 
110 	if (ENABLED_OPT(NORMALVERBOSE)) {
111 		getnameinfo(&dest->sa, SOCKLEN(dest), adr_buf, sizeof(adr_buf), NULL, 0, NI_NUMERICHOST);
112 		printf("sntp sendpkt: Sending packet to %s... ", adr_buf);
113 	}
114 
115 	cc = sendto(rsock, (void *)pkt, len, 0, &dest->sa, SOCKLEN(dest));
116 	if (cc == SOCKET_ERROR) {
117 #ifdef DEBUG
118 		printf("\n sntp sendpkt: Socket error: %i. Couldn't send packet!\n", cc);
119 #endif
120 		if (errno != EWOULDBLOCK && errno != ENOBUFS) {
121 			/* oh well */
122 		}
123 	} else if (ENABLED_OPT(NORMALVERBOSE)) {
124 		printf("Packet sent.\n");
125 	}
126 }
127 
128 /* Receive raw data */
129 int
130 recvdata(
131 	SOCKET rsock,
132 	sockaddr_u *sender,
133 	char *rdata,
134 	int rdata_length
135 	)
136 {
137 	GETSOCKNAME_SOCKLEN_TYPE slen;
138 	int recvc;
139 
140 #ifdef DEBUG
141 	printf("sntp recvdata: Trying to receive data from...\n");
142 #endif
143 	slen = sizeof(*sender);
144 	recvc = recvfrom(rsock, rdata, rdata_length, 0,
145 			 &sender->sa, &slen);
146 #ifdef DEBUG
147 	if (recvc > 0) {
148 		printf("Received %d bytes from %s:\n", recvc, stoa(sender));
149 		pkt_output((struct pkt *) rdata, recvc, stdout);
150 	} else {
151 		int saved_errno = errno;
152 		printf("recvfrom error %d (%s)\n", errno, strerror(errno));
153 		errno = saved_errno;
154 	}
155 #endif
156 	return recvc;
157 }
158 
159 /* Receive data from broadcast. Couldn't finish that. Need to do some digging
160  * here, especially for protocol independence and IPv6 multicast */
161 int
162 recv_bcst_data (
163 	SOCKET rsock,
164 	char *rdata,
165 	int rdata_len,
166 	sockaddr_u *sas,
167 	sockaddr_u *ras
168 	)
169 {
170 	char *buf;
171 	int btrue = 1;
172 	int recv_bytes = 0;
173 	int rdy_socks;
174 	GETSOCKNAME_SOCKLEN_TYPE ss_len;
175 	struct timeval timeout_tv;
176 	fd_set bcst_fd;
177 #ifdef MCAST
178 	struct ip_mreq mdevadr;
179 	TYPEOF_IP_MULTICAST_LOOP mtrue = 1;
180 #endif
181 #ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
182 	struct ipv6_mreq mdevadr6;
183 #endif
184 
185 	setsockopt(rsock, SOL_SOCKET, SO_REUSEADDR, &btrue, sizeof(btrue));
186 	if (IS_IPV4(sas)) {
187 		if (bind(rsock, &sas->sa, SOCKLEN(sas)) < 0) {
188 			if (ENABLED_OPT(NORMALVERBOSE))
189 				printf("sntp recv_bcst_data: Couldn't bind() address %s:%d.\n",
190 				       stoa(sas), SRCPORT(sas));
191 		}
192 
193 #ifdef MCAST
194 		if (setsockopt(rsock, IPPROTO_IP, IP_MULTICAST_LOOP, &mtrue, sizeof(mtrue)) < 0) {
195 			/* some error message regarding setting up multicast loop */
196 			return BROADCAST_FAILED;
197 		}
198 		mdevadr.imr_multiaddr.s_addr = NSRCADR(sas);
199 		mdevadr.imr_interface.s_addr = htonl(INADDR_ANY);
200 		if (mdevadr.imr_multiaddr.s_addr == ~(unsigned)0) {
201 			if (ENABLED_OPT(NORMALVERBOSE)) {
202 				printf("sntp recv_bcst_data: %s:%d is not a broad-/multicast address, aborting...\n",
203 				       stoa(sas), SRCPORT(sas));
204 			}
205 			return BROADCAST_FAILED;
206 		}
207 		if (setsockopt(rsock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mdevadr, sizeof(mdevadr)) < 0) {
208 			if (ENABLED_OPT(NORMALVERBOSE)) {
209 				buf = ss_to_str(sas);
210 				printf("sntp recv_bcst_data: Couldn't add IP membership for %s\n", buf);
211 				free(buf);
212 			}
213 		}
214 #endif	/* MCAST */
215 	}
216 #ifdef ISC_PLATFORM_HAVEIPV6
217 	else if (IS_IPV6(sas)) {
218 		if (bind(rsock, &sas->sa, SOCKLEN(sas)) < 0) {
219 			if (ENABLED_OPT(NORMALVERBOSE))
220 				printf("sntp recv_bcst_data: Couldn't bind() address.\n");
221 		}
222 #ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
223 		if (setsockopt(rsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &btrue, sizeof (btrue)) < 0) {
224 			/* some error message regarding setting up multicast loop */
225 			return BROADCAST_FAILED;
226 		}
227 		memset(&mdevadr6, 0, sizeof(mdevadr6));
228 		mdevadr6.ipv6mr_multiaddr = SOCK_ADDR6(sas);
229 		if (!IN6_IS_ADDR_MULTICAST(&mdevadr6.ipv6mr_multiaddr)) {
230 			if (ENABLED_OPT(NORMALVERBOSE)) {
231 				buf = ss_to_str(sas);
232 				printf("sntp recv_bcst_data: %s is not a broad-/multicast address, aborting...\n", buf);
233 				free(buf);
234 			}
235 			return BROADCAST_FAILED;
236 		}
237 		if (setsockopt(rsock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
238 			       &mdevadr6, sizeof(mdevadr6)) < 0) {
239 			if (ENABLED_OPT(NORMALVERBOSE)) {
240 				buf = ss_to_str(sas);
241 				printf("sntp recv_bcst_data: Couldn't join group for %s\n", buf);
242 				free(buf);
243 			}
244 		}
245 #endif	/* INCLUDE_IPV6_MULTICAST_SUPPORT */
246 	}
247 #endif	/* ISC_PLATFORM_HAVEIPV6 */
248 	FD_ZERO(&bcst_fd);
249 	FD_SET(rsock, &bcst_fd);
250 	if (ENABLED_OPT(TIMEOUT))
251 		timeout_tv.tv_sec = (int) atol(OPT_ARG(TIMEOUT));
252 	else
253 		timeout_tv.tv_sec = 68; /* ntpd broadcasts every 64s */
254 	timeout_tv.tv_usec = 0;
255 	rdy_socks = select(rsock + 1, &bcst_fd, 0, 0, &timeout_tv);
256 	switch (rdy_socks) {
257 	case -1:
258 		if (ENABLED_OPT(NORMALVERBOSE))
259 			perror("sntp recv_bcst_data: select()");
260 		return BROADCAST_FAILED;
261 		break;
262 	case 0:
263 		if (ENABLED_OPT(NORMALVERBOSE))
264 			printf("sntp recv_bcst_data: select() reached timeout (%u sec), aborting.\n",
265 			       (unsigned)timeout_tv.tv_sec);
266 		return BROADCAST_FAILED;
267 		break;
268 	default:
269 		ss_len = sizeof(*ras);
270 		recv_bytes = recvfrom(rsock, rdata, rdata_len, 0, &ras->sa, &ss_len);
271 		break;
272 	}
273 	if (recv_bytes == -1) {
274 		if (ENABLED_OPT(NORMALVERBOSE))
275 			perror("sntp recv_bcst_data: recvfrom:");
276 		recv_bytes = BROADCAST_FAILED;
277 	}
278 #ifdef MCAST
279 	if (IS_IPV4(sas))
280 		setsockopt(rsock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &btrue, sizeof(btrue));
281 #endif
282 #ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
283 	if (IS_IPV6(sas))
284 		setsockopt(rsock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &btrue, sizeof(btrue));
285 #endif
286 	return recv_bytes;
287 }
288 
289 int
290 process_pkt (
291 	struct pkt *rpkt,
292 	sockaddr_u *sas,
293 	int pkt_len,
294 	int mode,
295 	struct pkt *spkt,
296 	const char * func_name
297 	)
298 {
299 	unsigned int key_id = 0;
300 	struct key *pkt_key = NULL;
301 	int is_authentic = 0;
302 	unsigned int exten_words, exten_words_used = 0;
303 	int mac_size;
304 	/*
305 	 * Parse the extension field if present. We figure out whether
306 	 * an extension field is present by measuring the MAC size. If
307 	 * the number of words following the packet header is 0, no MAC
308 	 * is present and the packet is not authenticated. If 1, the
309 	 * packet is a crypto-NAK; if 3, the packet is authenticated
310 	 * with DES; if 5, the packet is authenticated with MD5; if 6,
311 	 * the packet is authenticated with SHA. If 2 or 4, the packet
312 	 * is a runt and discarded forthwith. If greater than 6, an
313 	 * extension field is present, so we subtract the length of the
314 	 * field and go around again.
315 	 */
316 	if (pkt_len < (int)LEN_PKT_NOMAC || (pkt_len & 3) != 0) {
317 unusable:
318 		if (ENABLED_OPT(NORMALVERBOSE))
319 			printf("sntp %s: Funny packet length: %i. Discarding package.\n", func_name, pkt_len);
320 		return PACKET_UNUSEABLE;
321 	}
322 	/* skip past the extensions, if any */
323 	exten_words = ((unsigned)pkt_len - LEN_PKT_NOMAC) >> 2;
324 	while (exten_words > 6) {
325 		unsigned int exten_len;
326 		exten_len = ntohl(rpkt->exten[exten_words_used]) & 0xffff;
327 		exten_len = (exten_len + 7) >> 2; /* convert to words, add 1 */
328 		if (exten_len > exten_words || exten_len < 5)
329 			goto unusable;
330 		exten_words -= exten_len;
331 		exten_words_used += exten_len;
332 	}
333 
334 	switch (exten_words) {
335 	case 1:
336 		key_id = ntohl(rpkt->exten[exten_words_used]);
337 		printf("Crypto NAK = 0x%08x\n", key_id);
338 		break;
339 	case 5:
340 	case 6:
341 		/* Look for the key used by the server in the specified keyfile
342 		 * and if existent, fetch it or else leave the pointer untouched */
343 		key_id = ntohl(rpkt->exten[exten_words_used]);
344 		get_key(key_id, &pkt_key);
345 		if (!pkt_key) {
346 			printf("unrecognized key ID = 0x%08x\n", key_id);
347 			break;
348 		}
349 		/* Seems like we've got a key with matching keyid */
350 		/* Generate a md5sum of the packet with the key from our keyfile
351 		 * and compare those md5sums */
352 		mac_size = exten_words << 2;
353 		if (!auth_md5((char *)rpkt, pkt_len - mac_size, mac_size - 4, pkt_key)) {
354 			break;
355 		}
356 		/* Yay! Things worked out! */
357 		if (ENABLED_OPT(NORMALVERBOSE)) {
358 			char *hostname = ss_to_str(sas);
359 			printf("sntp %s: packet received from %s successfully authenticated using key id %i.\n",
360 				func_name, hostname, key_id);
361 			free(hostname);
362 		}
363 		is_authentic = 1;
364 		break;
365 	case 0:
366 		break;
367 	default:
368 		goto unusable;
369 		break;
370 	}
371 	if (!is_authentic) {
372 		if (ENABLED_OPT(AUTHENTICATION)) {
373 			/* We want a authenticated packet */
374 			if (ENABLED_OPT(NORMALVERBOSE)) {
375 				char *hostname = ss_to_str(sas);
376 				printf("sntp %s: packet received from %s is not authentic. Will discard it.\n",
377 					func_name, hostname);
378 				free(hostname);
379 			}
380 			return SERVER_AUTH_FAIL;
381 		}
382 		/* We don't know if the user wanted authentication so let's
383 		 * use it anyways */
384 		if (ENABLED_OPT(NORMALVERBOSE)) {
385 			char *hostname = ss_to_str(sas);
386 			printf("sntp %s: packet received from %s is not authentic. Authentication not enforced.\n",
387 				func_name, hostname);
388 			free(hostname);
389 		}
390 	}
391 	/* Check for server's ntp version */
392 	if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION ||
393 		PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) {
394 		if (ENABLED_OPT(NORMALVERBOSE))
395 			printf("sntp %s: Packet shows wrong version (%i)\n",
396 				func_name, PKT_VERSION(rpkt->li_vn_mode));
397 		return SERVER_UNUSEABLE;
398 	}
399 	/* We want a server to sync with */
400 	if (PKT_MODE(rpkt->li_vn_mode) != mode &&
401 	    PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE) {
402 		if (ENABLED_OPT(NORMALVERBOSE))
403 			printf("sntp %s: mode %d stratum %i\n", func_name,
404 			       PKT_MODE(rpkt->li_vn_mode), rpkt->stratum);
405 		return SERVER_UNUSEABLE;
406 	}
407 	/* Stratum is unspecified (0) check what's going on */
408 	if (STRATUM_PKT_UNSPEC == rpkt->stratum) {
409 		char *ref_char;
410 		if (ENABLED_OPT(NORMALVERBOSE))
411 			printf("sntp %s: Stratum unspecified, going to check for KOD (stratum: %i)\n",
412 				func_name, rpkt->stratum);
413 		ref_char = (char *) &rpkt->refid;
414 		if (ENABLED_OPT(NORMALVERBOSE))
415 			printf("sntp %s: Packet refid: %c%c%c%c\n", func_name,
416 			       ref_char[0], ref_char[1], ref_char[2], ref_char[3]);
417 		/* If it's a KOD packet we'll just use the KOD information */
418 		if (ref_char[0] != 'X') {
419 			if (strncmp(ref_char, "DENY", 4) == 0)
420 				return KOD_DEMOBILIZE;
421 			if (strncmp(ref_char, "RSTR", 4) == 0)
422 				return KOD_DEMOBILIZE;
423 			if (strncmp(ref_char, "RATE", 4) == 0)
424 				return KOD_RATE;
425 			/* There are other interesting kiss codes which might be interesting for authentication */
426 		}
427 	}
428 	/* If the server is not synced it's not really useable for us */
429 	if (LEAP_NOTINSYNC == PKT_LEAP(rpkt->li_vn_mode)) {
430 		if (ENABLED_OPT(NORMALVERBOSE))
431 			printf("sntp %s: Server not in sync, skipping this server\n", func_name);
432 		return SERVER_UNUSEABLE;
433 	}
434 
435 	/*
436 	 * Decode the org timestamp and make sure we're getting a response
437 	 * to our last request, but only if we're not in broadcast mode.
438 	 */
439 #ifdef DEBUG
440 	printf("rpkt->org:\n");
441 	l_fp_output(&rpkt->org, stdout);
442 	printf("spkt->xmt:\n");
443 	l_fp_output(&spkt->xmt, stdout);
444 #endif
445 	if (mode != MODE_BROADCAST && !L_ISEQU(&rpkt->org, &spkt->xmt)) {
446 		if (ENABLED_OPT(NORMALVERBOSE))
447 			printf("sntp process_pkt: pkt.org and peer.xmt differ\n");
448 		return PACKET_UNUSEABLE;
449 	}
450 
451 	return pkt_len;
452 }
453 
454 int
455 recv_bcst_pkt (
456 	SOCKET rsock,
457 	struct pkt *rpkt,
458 	unsigned int rsize,
459 	sockaddr_u *sas
460 	)
461 {
462 	sockaddr_u sender;
463 	int pkt_len = recv_bcst_data(rsock, (char *)rpkt, rsize, sas, &sender);
464 	if (pkt_len < 0) {
465 		return BROADCAST_FAILED;
466 	}
467 	pkt_len = process_pkt(rpkt, sas, pkt_len, MODE_BROADCAST, NULL, "recv_bcst_pkt");
468 	return pkt_len;
469 }
470 
471 /* Fetch data, check if it's data for us and whether it's useable or not. If not, return
472  * a failure code so we can delete this server from our list and continue with another one.
473  */
474 int
475 recvpkt (
476 	SOCKET rsock,
477 	struct pkt *rpkt,    /* received packet (response) */
478 	unsigned int rsize,  /* size of rpkt buffer */
479 	struct pkt *spkt     /* sent     packet (request) */
480 	)
481 {
482 	int rdy_socks;
483 	int pkt_len;
484 	sockaddr_u sender;
485 	struct timeval timeout_tv;
486 	fd_set recv_fd;
487 
488 	FD_ZERO(&recv_fd);
489 	FD_SET(rsock, &recv_fd);
490 	if (ENABLED_OPT(TIMEOUT))
491 		timeout_tv.tv_sec = (int) atol(OPT_ARG(TIMEOUT));
492 	else
493 		timeout_tv.tv_sec = 68; /* ntpd broadcasts every 64s */
494 	timeout_tv.tv_usec = 0;
495 	rdy_socks = select(rsock + 1, &recv_fd, 0, 0, &timeout_tv);
496 	switch (rdy_socks) {
497 	case -1:
498 		if (ENABLED_OPT(NORMALVERBOSE))
499 			perror("sntp recvpkt: select()");
500 		return PACKET_UNUSEABLE;
501 		break;
502 	case 0:
503 		if (ENABLED_OPT(NORMALVERBOSE))
504 			printf("sntp recvpkt: select() reached timeout (%u sec), aborting.\n",
505 			       (unsigned)timeout_tv.tv_sec);
506 		return PACKET_UNUSEABLE;
507 		break;
508 	default:
509 		break;
510 	}
511 	pkt_len = recvdata(rsock, &sender, (char *)rpkt, rsize);
512 	if (pkt_len > 0)
513 		pkt_len = process_pkt(rpkt, &sender, pkt_len, MODE_SERVER, spkt, "recvpkt");
514 
515 	return pkt_len;
516 }
517 
518 /*
519  * is_reachable - check to see if we have a route to given destination
520  */
521 int
522 is_reachable (
523 	struct addrinfo *dst
524 	)
525 {
526 	SOCKET sockfd = socket(dst->ai_family, SOCK_DGRAM, 0);
527 
528 	if (-1 == sockfd) {
529 #ifdef DEBUG
530 		printf("is_reachable: Couldn't create socket\n");
531 #endif
532 		return 0;
533 	}
534 	if (connect(sockfd, dst->ai_addr, SOCKLEN((sockaddr_u *)dst->ai_addr))) {
535 		closesocket(sockfd);
536 		return 0;
537 	}
538 	closesocket(sockfd);
539 	return 1;
540 }
541