1 /* $NetBSD: net.c,v 1.8 2015/07/08 17:29:00 christos Exp $ */
2
3 /*
4 * Copyright (C) 2004, 2005, 2007, 2008, 2012-2015 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2003 Internet Software Consortium.
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /* Id */
21
22 #include <config.h>
23
24 #include <sys/types.h>
25
26 #if defined(HAVE_SYS_SYSCTL_H)
27 #if defined(HAVE_SYS_PARAM_H)
28 #include <sys/param.h>
29 #endif
30 #include <sys/sysctl.h>
31 #endif
32 #include <sys/uio.h>
33
34 #include <errno.h>
35 #include <unistd.h>
36 #include <fcntl.h>
37
38 #include <isc/log.h>
39 #include <isc/msgs.h>
40 #include <isc/net.h>
41 #include <isc/netdb.h>
42 #include <isc/once.h>
43 #include <isc/strerror.h>
44 #include <isc/string.h>
45 #include <isc/util.h>
46
47 #ifndef ISC_SOCKADDR_LEN_T
48 #define ISC_SOCKADDR_LEN_T unsigned int
49 #endif
50
51 /*%
52 * Definitions about UDP port range specification. This is a total mess of
53 * portability variants: some use sysctl (but the sysctl names vary), some use
54 * system-specific interfaces, some have the same interface for IPv4 and IPv6,
55 * some separate them, etc...
56 */
57
58 /*%
59 * The last resort defaults: use all non well known port space
60 */
61 #ifndef ISC_NET_PORTRANGELOW
62 #define ISC_NET_PORTRANGELOW 1024
63 #endif /* ISC_NET_PORTRANGELOW */
64 #ifndef ISC_NET_PORTRANGEHIGH
65 #define ISC_NET_PORTRANGEHIGH 65535
66 #endif /* ISC_NET_PORTRANGEHIGH */
67
68 #ifdef HAVE_SYSCTLBYNAME
69
70 /*%
71 * sysctl variants
72 */
73 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
74 #define USE_SYSCTL_PORTRANGE
75 #define SYSCTL_V4PORTRANGE_LOW "net.inet.ip.portrange.hifirst"
76 #define SYSCTL_V4PORTRANGE_HIGH "net.inet.ip.portrange.hilast"
77 #define SYSCTL_V6PORTRANGE_LOW "net.inet.ip.portrange.hifirst"
78 #define SYSCTL_V6PORTRANGE_HIGH "net.inet.ip.portrange.hilast"
79 #endif
80
81 #ifdef __NetBSD__
82 #define USE_SYSCTL_PORTRANGE
83 #define SYSCTL_V4PORTRANGE_LOW "net.inet.ip.anonportmin"
84 #define SYSCTL_V4PORTRANGE_HIGH "net.inet.ip.anonportmax"
85 #define SYSCTL_V6PORTRANGE_LOW "net.inet6.ip6.anonportmin"
86 #define SYSCTL_V6PORTRANGE_HIGH "net.inet6.ip6.anonportmax"
87 #endif
88
89 #else /* !HAVE_SYSCTLBYNAME */
90
91 #ifdef __OpenBSD__
92 #define USE_SYSCTL_PORTRANGE
93 #define SYSCTL_V4PORTRANGE_LOW { CTL_NET, PF_INET, IPPROTO_IP, \
94 IPCTL_IPPORT_HIFIRSTAUTO }
95 #define SYSCTL_V4PORTRANGE_HIGH { CTL_NET, PF_INET, IPPROTO_IP, \
96 IPCTL_IPPORT_HILASTAUTO }
97 /* Same for IPv6 */
98 #define SYSCTL_V6PORTRANGE_LOW SYSCTL_V4PORTRANGE_LOW
99 #define SYSCTL_V6PORTRANGE_HIGH SYSCTL_V4PORTRANGE_HIGH
100 #endif
101
102 #endif /* HAVE_SYSCTLBYNAME */
103
104 #if defined(ISC_PLATFORM_HAVEIPV6)
105 # if defined(ISC_PLATFORM_NEEDIN6ADDRANY)
106 const struct in6_addr isc_net_in6addrany = IN6ADDR_ANY_INIT;
107 # endif
108
109 # if defined(ISC_PLATFORM_NEEDIN6ADDRLOOPBACK)
110 const struct in6_addr isc_net_in6addrloop = IN6ADDR_LOOPBACK_INIT;
111 # endif
112
113 # if defined(WANT_IPV6)
114 static isc_once_t once_ipv6only = ISC_ONCE_INIT;
115 # endif
116
117 # if defined(ISC_PLATFORM_HAVEIN6PKTINFO)
118 static isc_once_t once_ipv6pktinfo = ISC_ONCE_INIT;
119 # endif
120 #endif /* ISC_PLATFORM_HAVEIPV6 */
121
122 static isc_once_t once = ISC_ONCE_INIT;
123 static isc_once_t once_dscp = ISC_ONCE_INIT;
124
125 static isc_result_t ipv4_result = ISC_R_NOTFOUND;
126 static isc_result_t ipv6_result = ISC_R_NOTFOUND;
127 static isc_result_t unix_result = ISC_R_NOTFOUND;
128 static isc_result_t ipv6only_result = ISC_R_NOTFOUND;
129 static isc_result_t ipv6pktinfo_result = ISC_R_NOTFOUND;
130 static unsigned int dscp_result = 0;
131
132 static isc_result_t
try_proto(int domain)133 try_proto(int domain) {
134 int s;
135 isc_result_t result = ISC_R_SUCCESS;
136 char strbuf[ISC_STRERRORSIZE];
137
138 s = socket(domain, SOCK_STREAM, 0);
139 if (s == -1) {
140 switch (errno) {
141 #ifdef EAFNOSUPPORT
142 case EAFNOSUPPORT:
143 #endif
144 #ifdef EPROTONOSUPPORT
145 case EPROTONOSUPPORT:
146 #endif
147 #ifdef EINVAL
148 case EINVAL:
149 #endif
150 return (ISC_R_NOTFOUND);
151 default:
152 isc__strerror(errno, strbuf, sizeof(strbuf));
153 UNEXPECTED_ERROR(__FILE__, __LINE__,
154 "socket() %s: %s",
155 isc_msgcat_get(isc_msgcat,
156 ISC_MSGSET_GENERAL,
157 ISC_MSG_FAILED,
158 "failed"),
159 strbuf);
160 return (ISC_R_UNEXPECTED);
161 }
162 }
163
164 #ifdef ISC_PLATFORM_HAVEIPV6
165 #ifdef WANT_IPV6
166 #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
167 if (domain == PF_INET6) {
168 struct sockaddr_in6 sin6;
169 unsigned int len;
170
171 /*
172 * Check to see if IPv6 is broken, as is common on Linux.
173 */
174 len = sizeof(sin6);
175 if (getsockname(s, (struct sockaddr *)&sin6, (void *)&len) < 0)
176 {
177 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
178 ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
179 "retrieving the address of an IPv6 "
180 "socket from the kernel failed.");
181 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
182 ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
183 "IPv6 is not supported.");
184 result = ISC_R_NOTFOUND;
185 } else {
186 if (len == sizeof(struct sockaddr_in6))
187 result = ISC_R_SUCCESS;
188 else {
189 isc_log_write(isc_lctx,
190 ISC_LOGCATEGORY_GENERAL,
191 ISC_LOGMODULE_SOCKET,
192 ISC_LOG_ERROR,
193 "IPv6 structures in kernel and "
194 "user space do not match.");
195 isc_log_write(isc_lctx,
196 ISC_LOGCATEGORY_GENERAL,
197 ISC_LOGMODULE_SOCKET,
198 ISC_LOG_ERROR,
199 "IPv6 is not supported.");
200 result = ISC_R_NOTFOUND;
201 }
202 }
203 }
204 #endif
205 #endif
206 #endif
207
208 (void)close(s);
209
210 return (result);
211 }
212
213 static void
initialize_action(void)214 initialize_action(void) {
215 ipv4_result = try_proto(PF_INET);
216 #ifdef ISC_PLATFORM_HAVEIPV6
217 #ifdef WANT_IPV6
218 #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
219 ipv6_result = try_proto(PF_INET6);
220 #endif
221 #endif
222 #endif
223 #ifdef ISC_PLATFORM_HAVESYSUNH
224 unix_result = try_proto(PF_UNIX);
225 #endif
226 }
227
228 static void
initialize(void)229 initialize(void) {
230 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
231 }
232
233 isc_result_t
isc_net_probeipv4(void)234 isc_net_probeipv4(void) {
235 initialize();
236 return (ipv4_result);
237 }
238
239 isc_result_t
isc_net_probeipv6(void)240 isc_net_probeipv6(void) {
241 initialize();
242 return (ipv6_result);
243 }
244
245 isc_result_t
isc_net_probeunix(void)246 isc_net_probeunix(void) {
247 initialize();
248 return (unix_result);
249 }
250
251 #ifdef ISC_PLATFORM_HAVEIPV6
252 #ifdef WANT_IPV6
253 static void
try_ipv6only(void)254 try_ipv6only(void) {
255 #ifdef IPV6_V6ONLY
256 int s, on;
257 char strbuf[ISC_STRERRORSIZE];
258 #endif
259 isc_result_t result;
260
261 result = isc_net_probeipv6();
262 if (result != ISC_R_SUCCESS) {
263 ipv6only_result = result;
264 return;
265 }
266
267 #ifndef IPV6_V6ONLY
268 ipv6only_result = ISC_R_NOTFOUND;
269 return;
270 #else
271 /* check for TCP sockets */
272 s = socket(PF_INET6, SOCK_STREAM, 0);
273 if (s == -1) {
274 isc__strerror(errno, strbuf, sizeof(strbuf));
275 UNEXPECTED_ERROR(__FILE__, __LINE__,
276 "socket() %s: %s",
277 isc_msgcat_get(isc_msgcat,
278 ISC_MSGSET_GENERAL,
279 ISC_MSG_FAILED,
280 "failed"),
281 strbuf);
282 ipv6only_result = ISC_R_UNEXPECTED;
283 return;
284 }
285
286 on = 1;
287 if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
288 ipv6only_result = ISC_R_NOTFOUND;
289 goto close;
290 }
291
292 close(s);
293
294 /* check for UDP sockets */
295 s = socket(PF_INET6, SOCK_DGRAM, 0);
296 if (s == -1) {
297 isc__strerror(errno, strbuf, sizeof(strbuf));
298 UNEXPECTED_ERROR(__FILE__, __LINE__,
299 "socket() %s: %s",
300 isc_msgcat_get(isc_msgcat,
301 ISC_MSGSET_GENERAL,
302 ISC_MSG_FAILED,
303 "failed"),
304 strbuf);
305 ipv6only_result = ISC_R_UNEXPECTED;
306 return;
307 }
308
309 on = 1;
310 if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
311 ipv6only_result = ISC_R_NOTFOUND;
312 goto close;
313 }
314
315 ipv6only_result = ISC_R_SUCCESS;
316
317 close:
318 close(s);
319 return;
320 #endif /* IPV6_V6ONLY */
321 }
322
323 static void
initialize_ipv6only(void)324 initialize_ipv6only(void) {
325 RUNTIME_CHECK(isc_once_do(&once_ipv6only,
326 try_ipv6only) == ISC_R_SUCCESS);
327 }
328 #endif /* WANT_IPV6 */
329
330 #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
331 #ifdef WANT_IPV6
332 static void
try_ipv6pktinfo(void)333 try_ipv6pktinfo(void) {
334 int s, on;
335 char strbuf[ISC_STRERRORSIZE];
336 isc_result_t result;
337 int optname;
338
339 result = isc_net_probeipv6();
340 if (result != ISC_R_SUCCESS) {
341 ipv6pktinfo_result = result;
342 return;
343 }
344
345 /* we only use this for UDP sockets */
346 s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
347 if (s == -1) {
348 isc__strerror(errno, strbuf, sizeof(strbuf));
349 UNEXPECTED_ERROR(__FILE__, __LINE__,
350 "socket() %s: %s",
351 isc_msgcat_get(isc_msgcat,
352 ISC_MSGSET_GENERAL,
353 ISC_MSG_FAILED,
354 "failed"),
355 strbuf);
356 ipv6pktinfo_result = ISC_R_UNEXPECTED;
357 return;
358 }
359
360 #ifdef IPV6_RECVPKTINFO
361 optname = IPV6_RECVPKTINFO;
362 #else
363 optname = IPV6_PKTINFO;
364 #endif
365 on = 1;
366 if (setsockopt(s, IPPROTO_IPV6, optname, &on, sizeof(on)) < 0) {
367 ipv6pktinfo_result = ISC_R_NOTFOUND;
368 goto close;
369 }
370
371 ipv6pktinfo_result = ISC_R_SUCCESS;
372
373 close:
374 close(s);
375 return;
376 }
377
378 static void
initialize_ipv6pktinfo(void)379 initialize_ipv6pktinfo(void) {
380 RUNTIME_CHECK(isc_once_do(&once_ipv6pktinfo,
381 try_ipv6pktinfo) == ISC_R_SUCCESS);
382 }
383 #endif /* WANT_IPV6 */
384 #endif /* ISC_PLATFORM_HAVEIN6PKTINFO */
385 #endif /* ISC_PLATFORM_HAVEIPV6 */
386
387 isc_result_t
isc_net_probe_ipv6only(void)388 isc_net_probe_ipv6only(void) {
389 #ifdef ISC_PLATFORM_HAVEIPV6
390 #ifdef WANT_IPV6
391 initialize_ipv6only();
392 #else
393 ipv6only_result = ISC_R_NOTFOUND;
394 #endif
395 #endif
396 return (ipv6only_result);
397 }
398
399 isc_result_t
isc_net_probe_ipv6pktinfo(void)400 isc_net_probe_ipv6pktinfo(void) {
401 #ifdef ISC_PLATFORM_HAVEIPV6
402 #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
403 #ifdef WANT_IPV6
404 initialize_ipv6pktinfo();
405 #else
406 ipv6pktinfo_result = ISC_R_NOTFOUND;
407 #endif
408 #endif
409 #endif
410 return (ipv6pktinfo_result);
411 }
412
413 static inline ISC_SOCKADDR_LEN_T
cmsg_len(ISC_SOCKADDR_LEN_T len)414 cmsg_len(ISC_SOCKADDR_LEN_T len) {
415 #ifdef CMSG_LEN
416 return (CMSG_LEN(len));
417 #else
418 ISC_SOCKADDR_LEN_T hdrlen;
419
420 /*
421 * Cast NULL so that any pointer arithmetic performed by CMSG_DATA
422 * is correct.
423 */
424 hdrlen = (ISC_SOCKADDR_LEN_T)CMSG_DATA(((struct cmsghdr *)NULL));
425 return (hdrlen + len);
426 #endif
427 }
428
429 static inline ISC_SOCKADDR_LEN_T
cmsg_space(ISC_SOCKADDR_LEN_T len)430 cmsg_space(ISC_SOCKADDR_LEN_T len) {
431 #ifdef CMSG_SPACE
432 return (CMSG_SPACE(len));
433 #else
434 struct msghdr msg;
435 struct cmsghdr *cmsgp;
436 /*
437 * XXX: The buffer length is an ad-hoc value, but should be enough
438 * in a practical sense.
439 */
440 char dummybuf[sizeof(struct cmsghdr) + 1024];
441
442 memset(&msg, 0, sizeof(msg));
443 msg.msg_control = dummybuf;
444 msg.msg_controllen = sizeof(dummybuf);
445
446 cmsgp = (struct cmsghdr *)dummybuf;
447 cmsgp->cmsg_len = cmsg_len(len);
448
449 cmsgp = CMSG_NXTHDR(&msg, cmsgp);
450 if (cmsgp != NULL)
451 return ((char *)cmsgp - (char *)msg.msg_control);
452 else
453 return (0);
454 #endif
455 }
456
457 #ifdef ISC_NET_BSD44MSGHDR
458 /*
459 * Make a fd non-blocking.
460 */
461 static isc_result_t
make_nonblock(int fd)462 make_nonblock(int fd) {
463 int ret;
464 int flags;
465 char strbuf[ISC_STRERRORSIZE];
466 #ifdef USE_FIONBIO_IOCTL
467 int on = 1;
468
469 ret = ioctl(fd, FIONBIO, (char *)&on);
470 #else
471 flags = fcntl(fd, F_GETFL, 0);
472 flags |= PORT_NONBLOCK;
473 ret = fcntl(fd, F_SETFL, flags);
474 #endif
475
476 if (ret == -1) {
477 isc__strerror(errno, strbuf, sizeof(strbuf));
478 UNEXPECTED_ERROR(__FILE__, __LINE__,
479 #ifdef USE_FIONBIO_IOCTL
480 "ioctl(%d, FIONBIO, &on): %s", fd,
481 #else
482 "fcntl(%d, F_SETFL, %d): %s", fd, flags,
483 #endif
484 strbuf);
485
486 return (ISC_R_UNEXPECTED);
487 }
488
489 return (ISC_R_SUCCESS);
490 }
491
492 static isc_boolean_t
cmsgsend(int s,int level,int type,struct addrinfo * res)493 cmsgsend(int s, int level, int type, struct addrinfo *res) {
494 char strbuf[ISC_STRERRORSIZE];
495 struct sockaddr_storage ss;
496 ISC_SOCKADDR_LEN_T len = sizeof(ss);
497 struct msghdr msg;
498 union {
499 struct cmsghdr h;
500 unsigned char b[256];
501 } control;
502 struct cmsghdr *cmsgp;
503 int dscp = 46;
504 struct iovec iovec;
505 char buf[1] = { 0 };
506 isc_result_t result;
507
508 if (bind(s, res->ai_addr, res->ai_addrlen) < 0) {
509 isc__strerror(errno, strbuf, sizeof(strbuf));
510 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
511 ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10),
512 "bind: %s", strbuf);
513 return (ISC_FALSE);
514 }
515
516 if (getsockname(s, (struct sockaddr *)&ss, &len) < 0) {
517 isc__strerror(errno, strbuf, sizeof(strbuf));
518 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
519 ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10),
520 "getsockname: %s", strbuf);
521 return (ISC_FALSE);
522 }
523
524 memset(&control, 0, sizeof(control));
525
526 iovec.iov_base = buf;
527 iovec.iov_len = sizeof(buf);
528
529 memset(&msg, 0, sizeof(msg));
530 msg.msg_name = (struct sockaddr *)&ss;
531 msg.msg_namelen = len;
532 msg.msg_iov = &iovec;
533 msg.msg_iovlen = 1;
534 msg.msg_control = (void*)&control;
535 msg.msg_controllen = cmsg_space(sizeof(int));
536 msg.msg_flags = 0;
537
538 cmsgp = msg.msg_control;
539 cmsgp->cmsg_level = level;
540 cmsgp->cmsg_type = type;
541
542 switch (cmsgp->cmsg_type) {
543 #ifdef IP_TOS
544 case IP_TOS:
545 cmsgp->cmsg_len = cmsg_len(sizeof(char));
546 *(unsigned char*)CMSG_DATA(cmsgp) = dscp;
547 break;
548 #endif
549 #ifdef IPV6_TCLASS
550 case IPV6_TCLASS:
551 cmsgp->cmsg_len = cmsg_len(sizeof(dscp));
552 memmove(CMSG_DATA(cmsgp), &dscp, sizeof(dscp));
553 break;
554 #endif
555 default:
556 INSIST(0);
557 }
558
559 if (sendmsg(s, &msg, 0) < 0) {
560 int debug = ISC_LOG_DEBUG(10);
561 switch (errno) {
562 #ifdef ENOPROTOOPT
563 case ENOPROTOOPT:
564 #endif
565 #ifdef EOPNOTSUPP
566 case EOPNOTSUPP:
567 #endif
568 case EINVAL:
569 break;
570 default:
571 debug = ISC_LOG_NOTICE;
572 }
573 isc__strerror(errno, strbuf, sizeof(strbuf));
574 if (debug != ISC_LOG_NOTICE) {
575 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
576 ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10),
577 "sendmsg: %s", strbuf);
578 } else {
579 UNEXPECTED_ERROR(__FILE__, __LINE__,
580 "sendmsg() %s: %s",
581 isc_msgcat_get(isc_msgcat,
582 ISC_MSGSET_GENERAL,
583 ISC_MSG_FAILED,
584 "failed"),
585 strbuf);
586 }
587 return (ISC_FALSE);
588 }
589
590 /*
591 * Make sure the message actually got sent.
592 */
593 result = make_nonblock(s);
594 RUNTIME_CHECK(result == ISC_R_SUCCESS);
595
596 iovec.iov_base = buf;
597 iovec.iov_len = sizeof(buf);
598
599 memset(&msg, 0, sizeof(msg));
600 msg.msg_name = (struct sockaddr *)&ss;
601 msg.msg_namelen = sizeof(ss);
602 msg.msg_iov = &iovec;
603 msg.msg_iovlen = 1;
604 msg.msg_control = NULL;
605 msg.msg_controllen = 0;
606 msg.msg_flags = 0;
607
608 if (recvmsg(s, &msg, 0) < 0)
609 return (ISC_FALSE);
610
611 return (ISC_TRUE);
612 }
613 #endif
614
615 static void
try_dscp_v4(void)616 try_dscp_v4(void) {
617 #ifdef IP_TOS
618 char strbuf[ISC_STRERRORSIZE];
619 struct addrinfo hints, *res0;
620 int s, dscp = 0, n;
621 #ifdef IP_RECVTOS
622 int on = 1;
623 #endif /* IP_RECVTOS */
624
625 memset(&hints, 0, sizeof(hints));
626 hints.ai_family = AF_INET;
627 hints.ai_socktype = SOCK_DGRAM;
628 hints.ai_protocol = IPPROTO_UDP;
629 #ifdef AI_NUMERICHOST
630 hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
631 #else
632 hints.ai_flags = AI_PASSIVE;
633 #endif
634
635 n = getaddrinfo("127.0.0.1", NULL, &hints, &res0);
636 if (n != 0 || res0 == NULL) {
637 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
638 ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10),
639 "getaddrinfo(127.0.0.1): %s", gai_strerror(n));
640 return;
641 }
642
643 s = socket(res0->ai_family, res0->ai_socktype, res0->ai_protocol);
644
645 if (s == -1) {
646 isc__strerror(errno, strbuf, sizeof(strbuf));
647 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
648 ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10),
649 "socket: %s", strbuf);
650 freeaddrinfo(res0);
651 return;
652 }
653
654 if (setsockopt(s, IPPROTO_IP, IP_TOS, &dscp, sizeof(dscp)) == 0)
655 dscp_result |= ISC_NET_DSCPSETV4;
656
657 #ifdef IP_RECVTOS
658 on = 1;
659 if (setsockopt(s, IPPROTO_IP, IP_RECVTOS, &on, sizeof(on)) == 0)
660 dscp_result |= ISC_NET_DSCPRECVV4;
661 #endif /* IP_RECVTOS */
662
663 #ifdef ISC_NET_BSD44MSGHDR
664
665 #ifndef ISC_CMSG_IP_TOS
666 #ifdef __APPLE__
667 #define ISC_CMSG_IP_TOS 0 /* As of 10.8.2. */
668 #else /* ! __APPLE__ */
669 #define ISC_CMSG_IP_TOS 1
670 #endif /* ! __APPLE__ */
671 #endif /* ! ISC_CMSG_IP_TOS */
672
673 #if ISC_CMSG_IP_TOS
674 if (cmsgsend(s, IPPROTO_IP, IP_TOS, res0))
675 dscp_result |= ISC_NET_DSCPPKTV4;
676 #endif /* ISC_CMSG_IP_TOS */
677
678 #endif /* ISC_NET_BSD44MSGHDR */
679
680 freeaddrinfo(res0);
681 close(s);
682
683 #endif /* IP_TOS */
684 }
685
686 static void
try_dscp_v6(void)687 try_dscp_v6(void) {
688 #ifdef ISC_PLATFORM_HAVEIPV6
689 #ifdef WANT_IPV6
690 #ifdef IPV6_TCLASS
691 char strbuf[ISC_STRERRORSIZE];
692 struct addrinfo hints, *res0;
693 int s, dscp = 0, n;
694 #if defined(IPV6_RECVTCLASS)
695 int on = 1;
696 #endif /* IPV6_RECVTCLASS */
697
698 memset(&hints, 0, sizeof(hints));
699 hints.ai_family = AF_INET6;
700 hints.ai_socktype = SOCK_DGRAM;
701 hints.ai_protocol = IPPROTO_UDP;
702 #ifdef AI_NUMERICHOST
703 hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
704 #else
705 hints.ai_flags = AI_PASSIVE;
706 #endif
707
708 n = getaddrinfo("::1", NULL, &hints, &res0);
709 if (n != 0 || res0 == NULL) {
710 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
711 ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10),
712 "getaddrinfo(::1): %s", gai_strerror(n));
713 return;
714 }
715
716 s = socket(res0->ai_family, res0->ai_socktype, res0->ai_protocol);
717 if (s == -1) {
718 isc__strerror(errno, strbuf, sizeof(strbuf));
719 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
720 ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10),
721 "socket: %s", strbuf);
722 freeaddrinfo(res0);
723 return;
724 }
725 if (setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS, &dscp, sizeof(dscp)) == 0)
726 dscp_result |= ISC_NET_DSCPSETV6;
727
728 #ifdef IPV6_RECVTCLASS
729 on = 1;
730 if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVTCLASS, &on, sizeof(on)) == 0)
731 dscp_result |= ISC_NET_DSCPRECVV6;
732 #endif /* IPV6_RECVTCLASS */
733
734 #ifdef ISC_NET_BSD44MSGHDR
735 if (cmsgsend(s, IPPROTO_IPV6, IPV6_TCLASS, res0))
736 dscp_result |= ISC_NET_DSCPPKTV6;
737 #endif /* ISC_NET_BSD44MSGHDR */
738
739 freeaddrinfo(res0);
740 close(s);
741
742 #endif /* IPV6_TCLASS */
743 #endif /* WANT_IPV6 */
744 #endif /* ISC_PLATFORM_HAVEIPV6 */
745 }
746
747 static void
try_dscp(void)748 try_dscp(void) {
749 try_dscp_v4();
750 try_dscp_v6();
751 }
752
753 static void
initialize_dscp(void)754 initialize_dscp(void) {
755 RUNTIME_CHECK(isc_once_do(&once_dscp, try_dscp) == ISC_R_SUCCESS);
756 }
757
758 unsigned int
isc_net_probedscp(void)759 isc_net_probedscp(void) {
760 initialize_dscp();
761 return (dscp_result);
762 }
763
764 #if defined(USE_SYSCTL_PORTRANGE)
765 #if defined(HAVE_SYSCTLBYNAME)
766 static isc_result_t
getudpportrange_sysctl(int af,in_port_t * low,in_port_t * high)767 getudpportrange_sysctl(int af, in_port_t *low, in_port_t *high) {
768 int port_low, port_high;
769 size_t portlen;
770 const char *sysctlname_lowport, *sysctlname_hiport;
771
772 if (af == AF_INET) {
773 sysctlname_lowport = SYSCTL_V4PORTRANGE_LOW;
774 sysctlname_hiport = SYSCTL_V4PORTRANGE_HIGH;
775 } else {
776 sysctlname_lowport = SYSCTL_V6PORTRANGE_LOW;
777 sysctlname_hiport = SYSCTL_V6PORTRANGE_HIGH;
778 }
779 portlen = sizeof(portlen);
780 if (sysctlbyname(sysctlname_lowport, &port_low, &portlen,
781 NULL, 0) < 0) {
782 return (ISC_R_FAILURE);
783 }
784 portlen = sizeof(portlen);
785 if (sysctlbyname(sysctlname_hiport, &port_high, &portlen,
786 NULL, 0) < 0) {
787 return (ISC_R_FAILURE);
788 }
789 if ((port_low & ~0xffff) != 0 || (port_high & ~0xffff) != 0)
790 return (ISC_R_RANGE);
791
792 *low = (in_port_t)port_low;
793 *high = (in_port_t)port_high;
794
795 return (ISC_R_SUCCESS);
796 }
797 #else /* !HAVE_SYSCTLBYNAME */
798 static isc_result_t
getudpportrange_sysctl(int af,in_port_t * low,in_port_t * high)799 getudpportrange_sysctl(int af, in_port_t *low, in_port_t *high) {
800 int mib_lo4[4] = SYSCTL_V4PORTRANGE_LOW;
801 int mib_hi4[4] = SYSCTL_V4PORTRANGE_HIGH;
802 int mib_lo6[4] = SYSCTL_V6PORTRANGE_LOW;
803 int mib_hi6[4] = SYSCTL_V6PORTRANGE_HIGH;
804 int *mib_lo, *mib_hi, miblen;
805 int port_low, port_high;
806 size_t portlen;
807
808 if (af == AF_INET) {
809 mib_lo = mib_lo4;
810 mib_hi = mib_hi4;
811 miblen = sizeof(mib_lo4) / sizeof(mib_lo4[0]);
812 } else {
813 mib_lo = mib_lo6;
814 mib_hi = mib_hi6;
815 miblen = sizeof(mib_lo6) / sizeof(mib_lo6[0]);
816 }
817
818 portlen = sizeof(portlen);
819 if (sysctl(mib_lo, miblen, &port_low, &portlen, NULL, 0) < 0) {
820 return (ISC_R_FAILURE);
821 }
822
823 portlen = sizeof(portlen);
824 if (sysctl(mib_hi, miblen, &port_high, &portlen, NULL, 0) < 0) {
825 return (ISC_R_FAILURE);
826 }
827
828 if ((port_low & ~0xffff) != 0 || (port_high & ~0xffff) != 0)
829 return (ISC_R_RANGE);
830
831 *low = (in_port_t) port_low;
832 *high = (in_port_t) port_high;
833
834 return (ISC_R_SUCCESS);
835 }
836 #endif /* HAVE_SYSCTLBYNAME */
837 #endif /* USE_SYSCTL_PORTRANGE */
838
839 isc_result_t
isc_net_getudpportrange(int af,in_port_t * low,in_port_t * high)840 isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high) {
841 int result = ISC_R_FAILURE;
842
843 REQUIRE(low != NULL && high != NULL);
844
845 #if defined(USE_SYSCTL_PORTRANGE)
846 result = getudpportrange_sysctl(af, low, high);
847 #else
848 UNUSED(af);
849 #endif
850
851 if (result != ISC_R_SUCCESS) {
852 *low = ISC_NET_PORTRANGELOW;
853 *high = ISC_NET_PORTRANGEHIGH;
854 }
855
856 return (ISC_R_SUCCESS); /* we currently never fail in this function */
857 }
858
859 void
isc_net_disableipv4(void)860 isc_net_disableipv4(void) {
861 initialize();
862 if (ipv4_result == ISC_R_SUCCESS)
863 ipv4_result = ISC_R_DISABLED;
864 }
865
866 void
isc_net_disableipv6(void)867 isc_net_disableipv6(void) {
868 initialize();
869 if (ipv6_result == ISC_R_SUCCESS)
870 ipv6_result = ISC_R_DISABLED;
871 }
872
873 void
isc_net_enableipv4(void)874 isc_net_enableipv4(void) {
875 initialize();
876 if (ipv4_result == ISC_R_DISABLED)
877 ipv4_result = ISC_R_SUCCESS;
878 }
879
880 void
isc_net_enableipv6(void)881 isc_net_enableipv6(void) {
882 initialize();
883 if (ipv6_result == ISC_R_DISABLED)
884 ipv6_result = ISC_R_SUCCESS;
885 }
886