2 * Copyright Internet Systems Consortium, Inc. ("ISC")
3 * Copyright Internet Software Consortium.
4 * Copyright the NTPsec project contributors
5 * SPDX-License-Identifier: ISC
11 #include <sys/types.h>
13 /* hack to ignore GCC Unused Result */
14 #define IGNORE(r) do{if(r){}}while(0)
20 /* for struct sockaddr on *BSD */
21 #include <sys/socket.h> /* Contractual promise. */
22 #include <netinet/in.h> /* Contractual promise. */
24 #include "isc_netaddr.h"
25 #include "ntp_stdlib.h"
26 #include "isc_result.h"
28 static isc_result_t ipv4_result
= ISC_R_NOTFOUND
;
29 static isc_result_t ipv6_result
= ISC_R_NOTFOUND
;
30 static isc_result_t ipv6only_result
= ISC_R_NOTFOUND
;
33 try_proto(int domain
) {
35 isc_result_t result
= ISC_R_SUCCESS
;
38 s
= socket(domain
, SOCK_STREAM
, 0);
44 #ifdef EPROTONOSUPPORT
50 return (ISC_R_NOTFOUND
);
52 ntp_strerror_r(errno
, strbuf
, sizeof(strbuf
));
53 msyslog(LOG_ERR
, "socket() failed: %s", strbuf
);
54 return (ISC_R_UNEXPECTED
);
58 if (domain
== PF_INET6
) {
59 struct sockaddr_in6 sin6
;
63 * Check to see if IPv6 is broken, as is common on Linux.
66 if (getsockname(s
, (struct sockaddr
*)&sin6
, &len
) < 0)
68 /* isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
69 ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
70 "retrieving the address of an IPv6 "
71 "socket from the kernel failed.");
72 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
73 ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
74 "IPv6 is not supported.");
76 result
= ISC_R_NOTFOUND
;
78 if (len
== sizeof(struct sockaddr_in6
)) {
79 result
= ISC_R_SUCCESS
;
81 /* isc_log_write(isc_lctx,
82 ISC_LOGCATEGORY_GENERAL,
85 "IPv6 structures in kernel and "
86 "user space do not match.");
87 isc_log_write(isc_lctx,
88 ISC_LOGCATEGORY_GENERAL,
91 "IPv6 is not supported.");
93 result
= ISC_R_NOTFOUND
;
105 static bool once
= false;
109 ipv4_result
= try_proto(PF_INET
);
110 ipv6_result
= try_proto(PF_INET6
);
114 isc_net_probeipv4_bool(void) {
116 return (ISC_R_SUCCESS
== ipv4_result
);
120 isc_net_probeipv6_bool(void) {
121 return (ISC_R_SUCCESS
== isc_net_probeipv6());
125 isc_net_probeipv6(void) {
127 return (ipv6_result
);
131 initialize_ipv6only(void) {
132 static bool once_ipv6only
= false;
138 if (once_ipv6only
) return;
139 once_ipv6only
= true;
142 result
= isc_net_probeipv6();
143 if (result
!= ISC_R_SUCCESS
) {
144 ipv6only_result
= result
;
149 ipv6only_result
= ISC_R_NOTFOUND
;
152 /* check for TCP sockets */
153 s
= socket(PF_INET6
, SOCK_STREAM
, 0);
155 ntp_strerror_r(errno
, strbuf
, sizeof(strbuf
));
156 msyslog(LOG_ERR
, "socket() failed: %s", strbuf
);
157 ipv6only_result
= ISC_R_UNEXPECTED
;
162 if (setsockopt(s
, IPPROTO_IPV6
, IPV6_V6ONLY
, &on
, sizeof(on
)) < 0) {
163 ipv6only_result
= ISC_R_NOTFOUND
;
169 /* check for UDP sockets */
170 s
= socket(PF_INET6
, SOCK_DGRAM
, 0);
172 ntp_strerror_r(errno
, strbuf
, sizeof(strbuf
));
173 msyslog(LOG_ERR
, "socket() failed: %s", strbuf
);
174 ipv6only_result
= ISC_R_UNEXPECTED
;
179 if (setsockopt(s
, IPPROTO_IPV6
, IPV6_V6ONLY
, &on
, sizeof(on
)) < 0) {
180 ipv6only_result
= ISC_R_NOTFOUND
;
184 ipv6only_result
= ISC_R_SUCCESS
;
189 #endif /* IPV6_V6ONLY */
193 isc_net_probe_ipv6only_bool(void) {
194 initialize_ipv6only();
195 return (ISC_R_SUCCESS
== ipv6only_result
);