CI opt-test: Drop Python2 & Bash in Fedora latest.
[ntpsec.git] / libntp / isc_net.c
blob6593b8ac8f20010cc10dd9a89cdde5f59945eb41
1 /*
2 * Copyright Internet Systems Consortium, Inc. ("ISC")
3 * Copyright Internet Software Consortium.
4 * Copyright the NTPsec project contributors
5 * SPDX-License-Identifier: ISC
6 */
8 #include "config.h"
10 #include <stdio.h>
11 #include <sys/types.h>
13 /* hack to ignore GCC Unused Result */
14 #define IGNORE(r) do{if(r){}}while(0)
16 #include <errno.h>
17 #include <unistd.h>
18 #include <string.h>
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;
32 static isc_result_t
33 try_proto(int domain) {
34 int s;
35 isc_result_t result = ISC_R_SUCCESS;
36 char strbuf[BUFSIZ];
38 s = socket(domain, SOCK_STREAM, 0);
39 if (s == -1) {
40 switch (errno) {
41 #ifdef EAFNOSUPPORT
42 case EAFNOSUPPORT:
43 #endif
44 #ifdef EPROTONOSUPPORT
45 case EPROTONOSUPPORT:
46 #endif
47 #ifdef EINVAL
48 case EINVAL:
49 #endif
50 return (ISC_R_NOTFOUND);
51 default:
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;
60 socklen_t len;
63 * Check to see if IPv6 is broken, as is common on Linux.
65 len = sizeof(sin6);
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;
77 } else {
78 if (len == sizeof(struct sockaddr_in6)) {
79 result = ISC_R_SUCCESS;
80 } else {
81 /* isc_log_write(isc_lctx,
82 ISC_LOGCATEGORY_GENERAL,
83 ISC_LOGMODULE_SOCKET,
84 ISC_LOG_ERROR,
85 "IPv6 structures in kernel and "
86 "user space do not match.");
87 isc_log_write(isc_lctx,
88 ISC_LOGCATEGORY_GENERAL,
89 ISC_LOGMODULE_SOCKET,
90 ISC_LOG_ERROR,
91 "IPv6 is not supported.");
93 result = ISC_R_NOTFOUND;
98 (void)close(s);
100 return (result);
103 static void
104 initialize(void) {
105 static bool once = false;
107 if (once) return;
108 once = true;
109 ipv4_result = try_proto(PF_INET);
110 ipv6_result = try_proto(PF_INET6);
113 bool
114 isc_net_probeipv4_bool(void) {
115 initialize();
116 return (ISC_R_SUCCESS == ipv4_result);
119 bool
120 isc_net_probeipv6_bool(void) {
121 return (ISC_R_SUCCESS == isc_net_probeipv6());
124 isc_result_t
125 isc_net_probeipv6(void) {
126 initialize();
127 return (ipv6_result);
130 static void
131 initialize_ipv6only(void) {
132 static bool once_ipv6only = false;
133 #ifdef IPV6_V6ONLY
134 int s, on;
135 char strbuf[BUFSIZ];
136 #endif
138 if (once_ipv6only) return;
139 once_ipv6only = true;
140 isc_result_t result;
142 result = isc_net_probeipv6();
143 if (result != ISC_R_SUCCESS) {
144 ipv6only_result = result;
145 return;
148 #ifndef IPV6_V6ONLY
149 ipv6only_result = ISC_R_NOTFOUND;
150 return;
151 #else
152 /* check for TCP sockets */
153 s = socket(PF_INET6, SOCK_STREAM, 0);
154 if (s == -1) {
155 ntp_strerror_r(errno, strbuf, sizeof(strbuf));
156 msyslog(LOG_ERR, "socket() failed: %s", strbuf);
157 ipv6only_result = ISC_R_UNEXPECTED;
158 return;
161 on = 1;
162 if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
163 ipv6only_result = ISC_R_NOTFOUND;
164 goto close;
167 close(s);
169 /* check for UDP sockets */
170 s = socket(PF_INET6, SOCK_DGRAM, 0);
171 if (s == -1) {
172 ntp_strerror_r(errno, strbuf, sizeof(strbuf));
173 msyslog(LOG_ERR, "socket() failed: %s", strbuf);
174 ipv6only_result = ISC_R_UNEXPECTED;
175 return;
178 on = 1;
179 if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
180 ipv6only_result = ISC_R_NOTFOUND;
181 goto close;
184 ipv6only_result = ISC_R_SUCCESS;
186 close:
187 close(s);
188 return;
189 #endif /* IPV6_V6ONLY */
192 bool
193 isc_net_probe_ipv6only_bool(void) {
194 initialize_ipv6only();
195 return (ISC_R_SUCCESS == ipv6only_result);