xref: /netbsd-src/external/bsd/ntp/dist/sntp/networking.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /*	$NetBSD: networking.c,v 1.3 2010/08/28 20:54:24 kardel Exp $	*/
2 
3 #include "networking.h"
4 
5 char adr_buf[INET6_ADDRSTRLEN];
6 
7 
8 /* resolve_hosts consumes an array of hostnames/addresses and its length, stores a pointer
9  * to the array with the resolved hosts in res and returns the size of the array res.
10  * pref_family enforces IPv4 or IPv6 depending on commandline options and system
11  * capability. If pref_family is NULL or PF_UNSPEC any compatible family will be accepted.
12  * Check here: Probably getaddrinfo() can do without ISC's IPv6 availability check?
13  */
14 int
15 resolve_hosts (
16 		char **hosts,
17 		int hostc,
18 		struct addrinfo ***res,
19 		int pref_family
20 		)
21 {
22 	register unsigned int a;
23 	unsigned int resc;
24 	struct addrinfo **tres;
25 
26 	if (hostc < 1 || NULL == res)
27 		return 0;
28 
29 	tres = emalloc(sizeof(struct addrinfo *) * hostc);
30 
31 	for (a = 0, resc = 0; a < hostc; a++) {
32 		struct addrinfo hints;
33 		int error;
34 
35 		tres[resc] = NULL;
36 
37 #ifdef DEBUG
38 		printf("sntp resolve_hosts: Starting host resolution for %s...\n", hosts[a]);
39 #endif
40 
41 		memset(&hints, 0, sizeof(hints));
42 
43 		if (AF_UNSPEC == pref_family)
44 			hints.ai_family = PF_UNSPEC;
45 		else
46 			hints.ai_family = pref_family;
47 
48 		hints.ai_socktype = SOCK_DGRAM;
49 
50 		error = getaddrinfo(hosts[a], "123", &hints, &tres[resc]);
51 
52 		if (error) {
53 			size_t msg_length = strlen(hosts[a]) + 21;
54 			char *logmsg = (char *) emalloc(sizeof(char) * msg_length);
55 
56 			snprintf(logmsg, msg_length, "Error looking up %s", hosts[a]);
57 #ifdef DEBUG
58 			printf("%s\n", logmsg);
59 #endif
60 
61 			log_msg(logmsg, 1);
62 			free(logmsg);
63 		} else {
64 #ifdef DEBUG
65 			struct addrinfo *dres;
66 
67 			for (dres = tres[resc]; dres; dres = dres->ai_next) {
68 				getnameinfo(dres->ai_addr, dres->ai_addrlen, adr_buf, sizeof(adr_buf), NULL, 0, NI_NUMERICHOST);
69 				STDLINE
70 				printf("Resolv No.: %i Result of getaddrinfo for %s:\n", resc, hosts[a]);
71 				printf("socktype: %i ", dres->ai_socktype);
72 				printf("protocol: %i ", dres->ai_protocol);
73 				printf("Prefered socktype: %i IP: %s\n", dres->ai_socktype, adr_buf);
74 				STDLINE
75 			}
76 #endif
77 			resc++;
78 		}
79 	}
80 
81 	if (resc)
82 		*res = realloc(tres, sizeof(struct addrinfo *) * resc);
83 	else {
84 		free(tres);
85 		*res = NULL;
86 	}
87 
88 	return resc;
89 }
90 
91 /* Creates a socket and returns. */
92 void
93 create_socket (
94 		SOCKET *rsock,
95 		sockaddr_u *dest
96 		)
97 {
98 	*rsock = socket(AF(dest), SOCK_DGRAM, 0);
99 
100 	if (-1 == *rsock && ENABLED_OPT(NORMALVERBOSE))
101 		printf("Failed to create UDP socket with family %d\n", AF(dest));
102 }
103 
104 /* Send a packet */
105 void
106 sendpkt (
107 	SOCKET rsock,
108 	sockaddr_u *dest,
109 	struct pkt *pkt,
110 	int len
111 	)
112 {
113 	int cc;
114 
115 #ifdef DEBUG
116 	printf("sntp sendpkt: Packet data:\n");
117 	pkt_output(pkt, len, stdout);
118 #endif
119 
120 	if (ENABLED_OPT(NORMALVERBOSE)) {
121 		getnameinfo(&dest->sa, SOCKLEN(dest), adr_buf, sizeof(adr_buf), NULL, 0, NI_NUMERICHOST);
122 
123 		printf("sntp sendpkt: Sending packet to %s... ", adr_buf);
124 	}
125 
126 	cc = sendto(rsock, (void *)pkt, len, 0, &dest->sa, SOCKLEN(dest));
127 
128 	if (cc == SOCKET_ERROR) {
129 #ifdef DEBUG
130 		printf("\n sntp sendpkt: Socket error: %i. Couldn't send packet!\n", cc);
131 #endif
132 
133 		if (errno != EWOULDBLOCK && errno != ENOBUFS) {
134 
135 		}
136 	} else if (ENABLED_OPT(NORMALVERBOSE))
137 		printf("Packet sent.\n");
138 }
139 
140 /* Receive raw data */
141 int
142 recvdata (
143 		SOCKET rsock,
144 		sockaddr_u *sender,
145 		char *rdata,
146 		int rdata_length
147 	 )
148 {
149 	GETSOCKNAME_SOCKLEN_TYPE slen;
150 	int recvc;
151 
152 #ifdef DEBUG
153 	printf("sntp recvdata: Trying to receive data from...\n");
154 #endif
155 	slen = sizeof(sender->sas);
156 	recvc = recvfrom(rsock, rdata, rdata_length, 0,
157 			 &sender->sa, &slen);
158 #ifdef DEBUG
159 	if (recvc > 0) {
160 		printf("Received %d bytes from %s:\n", recvc, stoa(sender));
161 
162 		pkt_output((struct pkt *) rdata, recvc, stdout);
163 	}
164 	else {
165 		int saved_errno = errno;
166 		printf("recvfrom error %d (%s)\n", errno, strerror(errno));
167 		errno = saved_errno;
168 	}
169 #endif
170 
171 	return recvc;
172 }
173 
174 /* Receive data from broadcast. Couldn't finish that. Need to do some digging
175  * here, especially for protocol independence and IPv6 multicast */
176 int
177 recv_bcst_data (
178 		SOCKET rsock,
179 		char *rdata,
180 		int rdata_len,
181 		sockaddr_u *sas,
182 		sockaddr_u *ras
183 	 )
184 {
185 	struct timeval timeout_tv;
186 	fd_set bcst_fd;
187 	char *buf;
188 	int btrue = 1;
189 	int recv_bytes = 0;
190 
191 
192 	setsockopt(rsock, SOL_SOCKET, SO_REUSEADDR, &btrue, sizeof(btrue));
193 
194 	if (IS_IPV4(sas)) {
195 		struct ip_mreq mdevadr;
196 
197 		if (bind(rsock, &sas->sa, SOCKLEN(sas)) < 0) {
198 			if (ENABLED_OPT(NORMALVERBOSE))
199 				printf("sntp recv_bcst_data: Couldn't bind() address.\n");
200 		}
201 
202 
203 		if (setsockopt(rsock, IPPROTO_IP, IP_MULTICAST_LOOP, &btrue, sizeof(btrue)) < 0) {
204 			/* some error message regarding setting up multicast loop */
205 			return BROADCAST_FAILED;
206 		}
207 
208 		mdevadr.imr_multiaddr.s_addr = NSRCADR(sas);
209 		mdevadr.imr_interface.s_addr = htonl(INADDR_ANY);
210 
211 		if (mdevadr.imr_multiaddr.s_addr == -1) {
212 			if (ENABLED_OPT(NORMALVERBOSE)) {
213 				printf("sntp recv_bcst_data: %s is not a broad-/multicast address, aborting...\n",
214 				       stoa(sas));
215 			}
216 
217 			return BROADCAST_FAILED;
218 		}
219 
220 		if (setsockopt(rsock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mdevadr, sizeof(mdevadr)) < 0) {
221 			if (ENABLED_OPT(NORMALVERBOSE)) {
222 				buf = ss_to_str(sas);
223 
224 				printf("sntp recv_bcst_data: Couldn't add IP membership for %s\n", buf);
225 
226 				free(buf);
227 
228 				return BROADCAST_FAILED;
229 			}
230 		}
231 	}
232 #ifdef ISC_PLATFORM_HAVEIPV6
233 	else if (IS_IPV6(sas)) {
234 #ifndef INCLUDE_IPV6_MULTICAST_SUPPORT
235 		return BROADCAST_FAILED;
236 #else
237 		struct ipv6_mreq mdevadr;
238 
239 		if (bind(rsock, &sas->sa, SOCKLEN(sas)) < 0) {
240 			if (ENABLED_OPT(NORMALVERBOSE))
241 				printf("sntp recv_bcst_data: Couldn't bind() address.\n");
242 		}
243 
244 		if (setsockopt(rsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &btrue, sizeof (btrue)) < 0) {
245 			/* some error message regarding setting up multicast loop */
246 			return BROADCAST_FAILED;
247 		}
248 
249 		memset(&mdevadr, 0, sizeof(mdevadr));
250 		mdevadr.ipv6mr_multiaddr = SOCK_ADDR6(sas);
251 
252 		if(!IN6_IS_ADDR_MULTICAST(&mdevadr.ipv6mr_multiaddr)) {
253 			if(ENABLED_OPT(NORMALVERBOSE)) {
254 				buf = ss_to_str(sas);
255 
256 				printf("sntp recv_bcst_data: %s is not a broad-/multicast address, aborting...\n", buf);
257 
258 				free(buf);
259 			}
260 
261 			return BROADCAST_FAILED;
262 		}
263 
264 		if (setsockopt(rsock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mdevadr, sizeof(mdevadr)) < 0) {
265 			if(ENABLED_OPT(NORMALVERBOSE)) {
266 				buf = ss_to_str(sas);
267 
268 				printf("sntp recv_bcst_data: Couldn't join group for %s\n", buf);
269 
270 				free(buf);
271 
272 				return BROADCAST_FAILED;
273 			}
274 		}
275 #endif	/* INCLUDE_IPV6_MULTICAST_SUPPORT */
276 	}
277 #endif	/* ISC_PLATFORM_HAVEIPV6 */
278 
279 	FD_ZERO(&bcst_fd);
280 	FD_SET(rsock, &bcst_fd);
281 
282 	if(ENABLED_OPT(TIMEOUT))
283 		timeout_tv.tv_sec = atol(OPT_ARG(TIMEOUT));
284 	else
285 		timeout_tv.tv_sec = 68; /* ntpd broadcasts every 64s */
286 
287 	switch(select(rsock + 1, &bcst_fd, 0, 0, &timeout_tv)) {
288 		FD_CLR(rsock, &bcst_fd);
289 
290 		case -1:
291 			if(ENABLED_OPT(NORMALVERBOSE))
292 				printf("sntp recv_bcst_data: select() returned -1, an error occured, aborting.\n");
293 
294 			return BROADCAST_FAILED;
295 			break;
296 
297 		case 0:
298 			if(ENABLED_OPT(NORMALVERBOSE))
299 				printf("sntp recv_bcst_data: select() reached timeout (%u sec), aborting.\n",
300 				       (unsigned)timeout_tv.tv_sec);
301 
302 			return BROADCAST_FAILED;
303 			break;
304 
305 		default:
306 		{
307 			GETSOCKNAME_SOCKLEN_TYPE ss_len = sizeof(ras->sas);
308 
309 			recv_bytes = recvfrom(rsock, rdata, rdata_len, 0, &ras->sa, &ss_len);
310 		}
311 	}
312 
313 	if (recv_bytes == -1) {
314 		if(ENABLED_OPT(NORMALVERBOSE))
315 			printf("sntp recv_bcst_data: Failed to receive from broad-/multicast\n");
316 
317 		return BROADCAST_FAILED;
318 	}
319 
320 	if (IS_IPV4(sas))
321 		setsockopt(rsock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &btrue, sizeof(btrue));
322 #ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
323 	else if (IS_IPV6(sas))
324 		setsockopt(rsock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &btrue, sizeof(btrue));
325 #endif
326 
327 	return recv_bytes;
328 }
329 
330 int
331 recv_bcst_pkt (
332 		SOCKET rsock,
333 		struct pkt *rpkt,
334 		sockaddr_u *sas
335 		)
336 {
337 	sockaddr_u sender;
338 	register int a;
339 	int is_authentic, has_mac = 0, orig_pkt_len;
340 
341 	char *rdata = emalloc(sizeof(char) * 256);
342 
343 	int pkt_len = recv_bcst_data(rsock, rdata, 256, sas, &sender);
344 
345 
346 	if (pkt_len < 0) {
347 		free(rdata);
348 
349 		return BROADCAST_FAILED;
350 	}
351 
352 	/* No MAC, no authentication */
353 	if (LEN_PKT_NOMAC == pkt_len)
354 		has_mac = 0;
355 
356 	/* If there's more than just the NTP packet it should be a MAC */
357 	else if(pkt_len > LEN_PKT_NOMAC)
358 		has_mac = pkt_len - LEN_PKT_NOMAC;
359 	else
360 		if(ENABLED_OPT(NORMALVERBOSE)) {
361 			printf("sntp recv_bcst_pkt: Funny packet length: %i. Discarding package.\n", pkt_len);
362 			free(rdata);
363 
364 			return PACKET_UNUSEABLE;
365 		}
366 
367 	/* Packet too big */
368 	if(pkt_len > LEN_PKT_NOMAC + MAX_MAC_LEN) {
369 		if(ENABLED_OPT(NORMALVERBOSE))
370 			printf("sntp recv_bcst_pkt: Received packet is too big (%i bytes), trying again to get a useFable packet\n",
371 					pkt_len);
372 		free(rdata);
373 
374 		return PACKET_UNUSEABLE;
375 	}
376 
377 	orig_pkt_len = pkt_len;
378 	pkt_len = min(pkt_len, sizeof(struct pkt));
379 
380 	/* Let's copy the received data to the packet structure */
381 	for (a = 0; a < pkt_len; a++)
382 		if (a < orig_pkt_len)
383 			((char *)rpkt)[a] = rdata[a];
384 		else
385 			((char *)rpkt)[a] = 0;
386 
387 	free(rdata);
388 
389 	/* MAC could be useable for us */
390 	if (has_mac) {
391 		/* Two more things that the MAC must conform to */
392 		if (has_mac > MAX_MAC_LEN || has_mac % 4 != 0) {
393 			is_authentic = 0; /* Or should we discard this packet? */
394 		}
395 		else  {
396 			if (MAX_MAC_LEN == has_mac) {
397 				struct key *pkt_key = NULL;
398 
399 				/* Look for the key used by the server in the specified keyfile
400 				 * and if existent, fetch it or else leave the pointer untouched */
401 				get_key(rpkt->mac[0], &pkt_key);
402 
403 				/* Seems like we've got a key with matching keyid */
404 				if (pkt_key != NULL) {
405 					/* Generate a md5sum of the packet with the key from our keyfile
406 					 * and compare those md5sums */
407 					if (!auth_md5((char *) rpkt, has_mac, pkt_key)) {
408 						if (ENABLED_OPT(AUTHENTICATION)) {
409 							/* We want a authenticated packet */
410 							if (ENABLED_OPT(NORMALVERBOSE)) {
411 								char *hostname = ss_to_str(sas);
412 								printf("sntp recv_bcst_pkt: Broadcast packet received from %s is not authentic. Will discard this packet.\n",
413 										hostname);
414 
415 								free(hostname);
416 							}
417 							return SERVER_AUTH_FAIL;
418 						}
419 						else {
420 							/* We don't know if the user wanted authentication so let's
421 							 * use it anyways */
422 							if (ENABLED_OPT(NORMALVERBOSE)) {
423 								char *hostname = ss_to_str(sas);
424 								printf("sntp recv_bcst_pkt: Broadcast packet received from %s is not authentic. Authentication not enforced.\n",
425 										hostname);
426 
427 								free(hostname);
428 							}
429 
430 							is_authentic = 0;
431 						}
432 					}
433 					else {
434 						/* Yay! Things worked out! */
435 						if (ENABLED_OPT(NORMALVERBOSE)) {
436 							char *hostname = ss_to_str(sas);
437 							printf("sntp recv_bcst_pkt: Broadcast packet received from %s successfully authenticated using key id %i.\n",
438 									hostname, rpkt->mac[0]);
439 
440 							free(hostname);
441 						}
442 
443 						is_authentic = 1;
444 					}
445 				}
446 			}
447 		}
448 	}
449 
450 	/* Check for server's ntp version */
451 	if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION ||
452 		PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) {
453 		if (ENABLED_OPT(NORMALVERBOSE))
454 			printf("sntp recv_bcst_pkt: Packet shows wrong version (%i)\n",
455 					PKT_VERSION(rpkt->li_vn_mode));
456 
457 		return SERVER_UNUSEABLE;
458 	}
459 
460 	/* We want a server to sync with */
461 	if (PKT_MODE(rpkt->li_vn_mode) != MODE_BROADCAST
462 		 && PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE) {
463 		if (ENABLED_OPT(NORMALVERBOSE))
464 			printf("sntp recv_bcst_pkt: mode %d stratum %i\n",
465 			   PKT_MODE(rpkt->li_vn_mode), rpkt->stratum);
466 
467 		return SERVER_UNUSEABLE;
468 	}
469 
470 	if (STRATUM_PKT_UNSPEC == rpkt->stratum) {
471 		char *ref_char;
472 
473 		if (ENABLED_OPT(NORMALVERBOSE))
474 			printf("sntp recv_bcst_pkt: Stratum unspecified, going to check for KOD (stratum: %i)\n", rpkt->stratum);
475 
476 		ref_char = (char *) &rpkt->refid;
477 
478 		/* If it's a KOD packet we'll just use the KOD information */
479 		if (ref_char[0] != 'X') {
480 			if (strncmp(ref_char, "DENY", 4))
481 				return KOD_DEMOBILIZE;
482 
483 			if (strncmp(ref_char, "RSTR", 4))
484 				return KOD_DEMOBILIZE;
485 
486 			if (strncmp(ref_char, "RATE", 4))
487 				return KOD_RATE;
488 
489 			/* There are other interesting kiss codes which might be interesting for authentication */
490 		}
491 	}
492 
493 	/* If the server is not synced it's not really useable for us */
494 	if (LEAP_NOTINSYNC == PKT_LEAP(rpkt->li_vn_mode)) {
495 		if (ENABLED_OPT(NORMALVERBOSE))
496 			printf("recv_bcst_pkt: Server not in sync, skipping this server\n");
497 
498 		return SERVER_UNUSEABLE;
499 	}
500 
501 	return pkt_len;
502 }
503 
504 
505 
506 /* Fetch data, check if it's data for us and whether it's useable or not. If not, return
507  * a failure code so we can delete this server from our list and continue with another one.
508  */
509 int
510 recvpkt (
511 		SOCKET rsock,
512 		struct pkt *rpkt,
513 		struct pkt *spkt
514 	)
515 {
516 	sockaddr_u sender;
517 	char *rdata /* , done */;
518 
519 	register int a;
520 	int has_mac, is_authentic, pkt_len, orig_pkt_len;
521 
522 
523 	/* Much space, just to be sure */
524 	rdata = emalloc(sizeof(char) * 256);
525 
526 	pkt_len = recvdata(rsock, &sender, rdata, 256);
527 
528 #if 0	/* done uninitialized */
529 	if (!done) {
530 		/* Do something about it, first check for a maximum length of ntp packets,
531 		 * probably that's something we can avoid
532 		 */
533 	}
534 #endif
535 
536 	/* Some checks to see if that packet is intended for us */
537 
538 	/* No MAC, no authentication */
539 	if (LEN_PKT_NOMAC == pkt_len)
540 		has_mac = 0;
541 
542 	/* If there's more than just the NTP packet it should be a MAC */
543 	else if (pkt_len > LEN_PKT_NOMAC)
544 		has_mac = pkt_len - LEN_PKT_NOMAC;
545 
546 	else {
547 		if (ENABLED_OPT(NORMALVERBOSE))
548 			printf("sntp recvpkt: Funny packet length: %i. Discarding package.\n", pkt_len);
549 		free(rdata);
550 
551 		return PACKET_UNUSEABLE;
552 	}
553 
554 	/* Packet too big */
555 	if (pkt_len > LEN_PKT_MAC) {
556 		if (ENABLED_OPT(NORMALVERBOSE))
557 			printf("sntp recvpkt: Received packet is too big (%i bytes), trying again to get a useable packet\n",
558 					pkt_len);
559 		free(rdata);
560 
561 		return PACKET_UNUSEABLE;
562 	}
563 
564 	orig_pkt_len = pkt_len;
565 	pkt_len = min(pkt_len, sizeof(struct pkt));
566 
567 	for (a = 0; a < pkt_len; a++)
568 		/* FIXME! */
569 		if (a < orig_pkt_len)
570 			((char *) rpkt)[a] = rdata[a];
571 		else
572 			((char *) rpkt)[a] = 0;
573 
574 	free(rdata);
575 	rdata = NULL;
576 
577 	/* MAC could be useable for us */
578 	if (has_mac) {
579 		/* Two more things that the MAC must conform to */
580 		if(has_mac > MAX_MAC_LEN || has_mac % 4 != 0) {
581 			is_authentic = 0; /* Or should we discard this packet? */
582 		}
583 		else {
584 			if (MAX_MAC_LEN == has_mac) {
585 				struct key *pkt_key = NULL;
586 
587 				/*
588 				 * Look for the key used by the server in the specified keyfile
589 				 * and if existent, fetch it or else leave the pointer untouched
590 				 */
591 				get_key(rpkt->mac[0], &pkt_key);
592 
593 				/* Seems like we've got a key with matching keyid */
594 				if (pkt_key != NULL) {
595 					/*
596 					 * Generate a md5sum of the packet with the key from our keyfile
597 					 * and compare those md5sums
598 					 */
599 					if (!auth_md5((char *) rpkt, has_mac, pkt_key)) {
600 						if (ENABLED_OPT(AUTHENTICATION)) {
601 							/* We want a authenticated packet */
602 							if (ENABLED_OPT(NORMALVERBOSE)) {
603 								char *hostname = ss_to_str(&sender);
604 								printf("sntp recvpkt: Broadcast packet received from %s is not authentic. Will discard this packet.\n",
605 										hostname);
606 
607 								free(hostname);
608 							}
609 							return SERVER_AUTH_FAIL;
610 						}
611 						else {
612 							/*
613 							 * We don't know if the user wanted authentication so let's
614 							 * use it anyways
615 							 */
616 							if (ENABLED_OPT(NORMALVERBOSE)) {
617 								char *hostname = ss_to_str(&sender);
618 								printf("sntp recvpkt: Broadcast packet received from %s is not authentic. Authentication not enforced.\n",
619 										hostname);
620 
621 								free(hostname);
622 							}
623 
624 							is_authentic = 0;
625 						}
626 					}
627 					else {
628 						/* Yay! Things worked out! */
629 						if (ENABLED_OPT(NORMALVERBOSE)) {
630 							char *hostname = ss_to_str(&sender);
631 							printf("sntp recvpkt: Broadcast packet received from %s successfully authenticated using key id %i.\n",
632 									hostname, rpkt->mac[0]);
633 
634 							free(hostname);
635 						}
636 
637 						is_authentic = 1;
638 					}
639 				}
640 			}
641 		}
642 	}
643 
644 	/* Check for server's ntp version */
645 	if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION ||
646 	    PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) {
647 		if (ENABLED_OPT(NORMALVERBOSE))
648 			printf("sntp recvpkt: Packet got wrong version (%i)\n", PKT_VERSION(rpkt->li_vn_mode));
649 
650 		return SERVER_UNUSEABLE;
651 	}
652 
653 	/* We want a server to sync with */
654 	if (PKT_MODE(rpkt->li_vn_mode) != MODE_SERVER &&
655 	    PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE) {
656 		if (ENABLED_OPT(NORMALVERBOSE))
657 			printf("sntp recvpkt: mode %d stratum %i\n",
658 			   PKT_MODE(rpkt->li_vn_mode), rpkt->stratum);
659 
660 		return SERVER_UNUSEABLE;
661 	}
662 
663 	/* Stratum is unspecified (0) check what's going on */
664 	if (STRATUM_PKT_UNSPEC == rpkt->stratum) {
665 		char *ref_char;
666 
667 		if (ENABLED_OPT(NORMALVERBOSE))
668 			printf("sntp recvpkt: Stratum unspecified, going to check for KOD (stratum: %i)\n", rpkt->stratum);
669 
670 
671 		ref_char = (char *) &rpkt->refid;
672 
673 		if (ENABLED_OPT(NORMALVERBOSE))
674 			printf("sntp recvpkt: Packet refid: %c%c%c%c\n", ref_char[0], ref_char[1], ref_char[2], ref_char[3]);
675 
676 		/* If it's a KOD packet we'll just use the KOD information */
677 		if (ref_char[0] != 'X') {
678 			if (!strncmp(ref_char, "DENY", 4))
679 				return KOD_DEMOBILIZE;
680 
681 			if (!strncmp(ref_char, "RSTR", 4))
682 				return KOD_DEMOBILIZE;
683 
684 			if (!strncmp(ref_char, "RATE", 4))
685 				return KOD_RATE;
686 
687 			/* There are other interesting kiss codes which might be interesting for authentication */
688 		}
689 	}
690 
691 	/* If the server is not synced it's not really useable for us */
692 	if (LEAP_NOTINSYNC == PKT_LEAP(rpkt->li_vn_mode)) {
693 		if (ENABLED_OPT(NORMALVERBOSE))
694 			printf("sntp recvpkt: Server not in sync, skipping this server\n");
695 
696 		return SERVER_UNUSEABLE;
697 	}
698 
699 	/*
700 	 * Decode the org timestamp and make sure we're getting a response
701 	 * to our last request.
702 	 */
703 
704 #ifdef DEBUG
705 	printf("rpkt->org:\n");
706 	l_fp_output(&rpkt->org, stdout);
707 	printf("spkt->xmt:\n");
708 	l_fp_output(&spkt->xmt, stdout);
709 #endif
710 
711 	if (!L_ISEQU(&rpkt->org, &spkt->xmt)) {
712 		if (ENABLED_OPT(NORMALVERBOSE))
713 			printf("sntp recvpkt: pkt.org and peer.xmt differ\n");
714 
715 		return PACKET_UNUSEABLE;
716 	}
717 
718 	return pkt_len;
719 }
720 
721 /*
722  * is_reachable - check to see if we have a route to given destination
723  */
724 int
725 is_reachable (
726 		struct addrinfo *dst
727 		)
728 {
729 	SOCKET sockfd;
730 
731 	sockfd = socket(dst->ai_family, SOCK_DGRAM, 0);
732 
733 	if (-1 == sockfd) {
734 #ifdef DEBUG
735 		printf("is_reachable: Couldn't create socket\n");
736 #endif
737 		return 0;
738 	}
739 
740 	if (connect(sockfd, dst->ai_addr, SOCKLEN((sockaddr_u *)dst->ai_addr))) {
741 		closesocket(sockfd);
742 		return 0;
743 	}
744 
745 	closesocket(sockfd);
746 	return 1;
747 }
748