3 #include "networking.h"
5 char adr_buf
[INET6_ADDRSTRLEN
];
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?
18 struct addrinfo
***res
,
22 register unsigned int a
;
24 struct addrinfo
**tres
;
26 if (hostc
< 1 || NULL
== res
)
29 tres
= emalloc(sizeof(struct addrinfo
*) * hostc
);
31 for (a
= 0, resc
= 0; a
< hostc
; a
++) {
32 struct addrinfo hints
;
38 printf("sntp resolve_hosts: Starting host resolution for %s...\n", hosts
[a
]);
41 memset(&hints
, 0, sizeof(hints
));
43 if (AF_UNSPEC
== pref_family
)
44 hints
.ai_family
= PF_UNSPEC
;
46 hints
.ai_family
= pref_family
;
48 hints
.ai_socktype
= SOCK_DGRAM
;
50 error
= getaddrinfo(hosts
[a
], "123", &hints
, &tres
[resc
]);
53 size_t msg_length
= strlen(hosts
[a
]) + 21;
54 char *logmsg
= (char *) emalloc(sizeof(char) * msg_length
);
56 snprintf(logmsg
, msg_length
, "Error looking up %s", hosts
[a
]);
58 printf("%s\n", logmsg
);
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
);
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
);
80 *res
= realloc(tres
, sizeof(struct addrinfo
*) * resc
);
89 /* Creates a socket and returns. */
96 *rsock
= socket(AF(dest
), SOCK_DGRAM
, 0);
98 if (-1 == *rsock
&& ENABLED_OPT(NORMALVERBOSE
))
99 printf("Failed to create UDP socket with family %d\n", AF(dest
));
114 printf("sntp sendpkt: Packet data:\n");
115 pkt_output(pkt
, len
, stdout
);
118 if (ENABLED_OPT(NORMALVERBOSE
)) {
119 getnameinfo(&dest
->sa
, SOCKLEN(dest
), adr_buf
, sizeof(adr_buf
), NULL
, 0, NI_NUMERICHOST
);
121 printf("sntp sendpkt: Sending packet to %s... ", adr_buf
);
124 cc
= sendto(rsock
, (void *)pkt
, len
, 0, &dest
->sa
, SOCKLEN(dest
));
126 if (cc
== SOCKET_ERROR
) {
128 printf("\n sntp sendpkt: Socket error: %i. Couldn't send packet!\n", cc
);
131 if (errno
!= EWOULDBLOCK
&& errno
!= ENOBUFS
) {
134 } else if (ENABLED_OPT(NORMALVERBOSE
))
135 printf("Packet sent.\n");
138 /* Receive raw data */
147 GETSOCKNAME_SOCKLEN_TYPE slen
;
151 printf("sntp recvdata: Trying to receive data from...\n");
153 slen
= sizeof(sender
->sas
);
154 recvc
= recvfrom(rsock
, rdata
, rdata_length
, 0,
158 printf("Received %d bytes from %s:\n", recvc
, stoa(sender
));
160 pkt_output((struct pkt
*) rdata
, recvc
, stdout
);
164 printf("recvfrom error %d (%s)\n", errno
, strerror(errno
));
172 /* Receive data from broadcast. Couldn't finish that. Need to do some digging
173 * here, especially for protocol independence and IPv6 multicast */
183 struct timeval timeout_tv
;
190 setsockopt(rsock
, SOL_SOCKET
, SO_REUSEADDR
, &btrue
, sizeof(btrue
));
193 struct ip_mreq mdevadr
;
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");
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
;
206 mdevadr
.imr_multiaddr
.s_addr
= NSRCADR(sas
);
207 mdevadr
.imr_interface
.s_addr
= htonl(INADDR_ANY
);
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",
215 return BROADCAST_FAILED
;
218 if (setsockopt(rsock
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &mdevadr
, sizeof(mdevadr
)) < 0) {
219 if (ENABLED_OPT(NORMALVERBOSE
)) {
220 buf
= ss_to_str(sas
);
222 printf("sntp recv_bcst_data: Couldn't add IP membership for %s\n", buf
);
226 return BROADCAST_FAILED
;
230 #ifdef ISC_PLATFORM_HAVEIPV6
231 else if (IS_IPV6(sas
)) {
232 #ifndef INCLUDE_IPV6_MULTICAST_SUPPORT
233 return BROADCAST_FAILED
;
235 struct ipv6_mreq mdevadr
;
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");
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
;
247 memset(&mdevadr
, 0, sizeof(mdevadr
));
248 mdevadr
.ipv6mr_multiaddr
= SOCK_ADDR6(sas
);
250 if(!IN6_IS_ADDR_MULTICAST(&mdevadr
.ipv6mr_multiaddr
)) {
251 if(ENABLED_OPT(NORMALVERBOSE
)) {
252 buf
= ss_to_str(sas
);
254 printf("sntp recv_bcst_data: %s is not a broad-/multicast address, aborting...\n", buf
);
259 return BROADCAST_FAILED
;
262 if (setsockopt(rsock
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &mdevadr
, sizeof(mdevadr
)) < 0) {
263 if(ENABLED_OPT(NORMALVERBOSE
)) {
264 buf
= ss_to_str(sas
);
266 printf("sntp recv_bcst_data: Couldn't join group for %s\n", buf
);
270 return BROADCAST_FAILED
;
273 #endif /* INCLUDE_IPV6_MULTICAST_SUPPORT */
275 #endif /* ISC_PLATFORM_HAVEIPV6 */
278 FD_SET(rsock
, &bcst_fd
);
280 if(ENABLED_OPT(TIMEOUT
))
281 timeout_tv
.tv_sec
= (int) OPT_ARG(TIMEOUT
);
283 timeout_tv
.tv_sec
= 68; /* ntpd broadcasts every 64s */
285 switch(select(rsock
+ 1, &bcst_fd
, 0, 0, &timeout_tv
)) {
286 FD_CLR(rsock
, &bcst_fd
);
289 if(ENABLED_OPT(NORMALVERBOSE
))
290 printf("sntp recv_bcst_data: select() returned -1, an error occured, aborting.\n");
292 return BROADCAST_FAILED
;
296 if(ENABLED_OPT(NORMALVERBOSE
))
297 printf("sntp recv_bcst_data: select() reached timeout (%u sec), aborting.\n",
298 (unsigned)timeout_tv
.tv_sec
);
300 return BROADCAST_FAILED
;
305 GETSOCKNAME_SOCKLEN_TYPE ss_len
= sizeof(ras
->sas
);
307 recv_bytes
= recvfrom(rsock
, rdata
, rdata_len
, 0, &ras
->sa
, &ss_len
);
311 if (recv_bytes
== -1) {
312 if(ENABLED_OPT(NORMALVERBOSE
))
313 printf("sntp recv_bcst_data: Failed to receive from broad-/multicast\n");
315 return BROADCAST_FAILED
;
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
));
337 int is_authentic
, has_mac
= 0, orig_pkt_len
;
339 char *rdata
= emalloc(sizeof(char) * 256);
341 int pkt_len
= recv_bcst_data(rsock
, rdata
, 256, sas
, &sender
);
347 return BROADCAST_FAILED
;
350 /* No MAC, no authentication */
351 if (LEN_PKT_NOMAC
== pkt_len
)
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
;
358 if(ENABLED_OPT(NORMALVERBOSE
)) {
359 printf("sntp recv_bcst_pkt: Funny packet length: %i. Discarding package.\n", pkt_len
);
362 return PACKET_UNUSEABLE
;
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",
372 return PACKET_UNUSEABLE
;
375 orig_pkt_len
= pkt_len
;
376 pkt_len
= min(pkt_len
, sizeof(struct pkt
));
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
];
383 ((char *)rpkt
)[a
] = 0;
387 /* MAC could be useable for us */
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? */
394 if (MAX_MAC_LEN
== has_mac
) {
395 struct key
*pkt_key
= NULL
;
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
);
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",
415 return SERVER_AUTH_FAIL
;
418 /* We don't know if the user wanted authentication so let's
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",
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]);
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
));
455 return SERVER_UNUSEABLE
;
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
);
465 return SERVER_UNUSEABLE
;
468 if (STRATUM_PKT_UNSPEC
== rpkt
->stratum
) {
471 if (ENABLED_OPT(NORMALVERBOSE
))
472 printf("sntp recv_bcst_pkt: Stratum unspecified, going to check for KOD (stratum: %i)\n", rpkt
->stratum
);
474 ref_char
= (char *) &rpkt
->refid
;
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
;
481 if (strncmp(ref_char
, "RSTR", 4))
482 return KOD_DEMOBILIZE
;
484 if (strncmp(ref_char
, "RATE", 4))
487 /* There are other interesting kiss codes which might be interesting for authentication */
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");
496 return SERVER_UNUSEABLE
;
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.
515 char *rdata
/* , done */;
518 int has_mac
, is_authentic
, pkt_len
, orig_pkt_len
;
521 /* Much space, just to be sure */
522 rdata
= emalloc(sizeof(char) * 256);
524 pkt_len
= recvdata(rsock
, &sender
, rdata
, 256);
526 #if 0 /* done uninitialized */
528 /* Do something about it, first check for a maximum length of ntp packets,
529 * probably that's something we can avoid
534 /* Some checks to see if that packet is intended for us */
536 /* No MAC, no authentication */
537 if (LEN_PKT_NOMAC
== pkt_len
)
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
;
545 if (ENABLED_OPT(NORMALVERBOSE
))
546 printf("sntp recvpkt: Funny packet length: %i. Discarding package.\n", pkt_len
);
549 return PACKET_UNUSEABLE
;
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",
559 return PACKET_UNUSEABLE
;
562 orig_pkt_len
= pkt_len
;
563 pkt_len
= min(pkt_len
, sizeof(struct pkt
));
565 for (a
= 0; a
< pkt_len
; a
++)
567 if (a
< orig_pkt_len
)
568 ((char *) rpkt
)[a
] = rdata
[a
];
570 ((char *) rpkt
)[a
] = 0;
575 /* MAC could be useable for us */
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? */
582 if (MAX_MAC_LEN
== has_mac
) {
583 struct key
*pkt_key
= NULL
;
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
589 get_key(rpkt
->mac
[0], &pkt_key
);
591 /* Seems like we've got a key with matching keyid */
592 if (pkt_key
!= NULL
) {
594 * Generate a md5sum of the packet with the key from our keyfile
595 * and compare those md5sums
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",
607 return SERVER_AUTH_FAIL
;
611 * We don't know if the user wanted authentication so let's
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",
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]);
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
));
648 return SERVER_UNUSEABLE
;
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
);
658 return SERVER_UNUSEABLE
;
661 /* Stratum is unspecified (0) check what's going on */
662 if (STRATUM_PKT_UNSPEC
== rpkt
->stratum
) {
665 if (ENABLED_OPT(NORMALVERBOSE
))
666 printf("sntp recvpkt: Stratum unspecified, going to check for KOD (stratum: %i)\n", rpkt
->stratum
);
669 ref_char
= (char *) &rpkt
->refid
;
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]);
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
;
679 if (!strncmp(ref_char
, "RSTR", 4))
680 return KOD_DEMOBILIZE
;
682 if (!strncmp(ref_char
, "RATE", 4))
685 /* There are other interesting kiss codes which might be interesting for authentication */
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");
694 return SERVER_UNUSEABLE
;
698 * Decode the org timestamp and make sure we're getting a response
699 * to our last request.
703 printf("rpkt->org:\n");
704 l_fp_output(&rpkt
->org
, stdout
);
705 printf("spkt->xmt:\n");
706 l_fp_output(&spkt
->xmt
, stdout
);
709 if (!L_ISEQU(&rpkt
->org
, &spkt
->xmt
)) {
710 if (ENABLED_OPT(NORMALVERBOSE
))
711 printf("sntp recvpkt: pkt.org and peer.xmt differ\n");
713 return PACKET_UNUSEABLE
;
720 * is_reachable - check to see if we have a route to given destination
729 sockfd
= socket(dst
->ai_family
, SOCK_DGRAM
, 0);
733 printf("is_reachable: Couldn't create socket\n");
738 if (connect(sockfd
, dst
->ai_addr
, SOCKLEN((sockaddr_u
*)dst
->ai_addr
))) {