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