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