bind - Upgraded vendor branch to 9.5.2-P1
[dragonfly.git] / contrib / bind-9.2.4rc7 / lib / isc / unix / net.c
1 /*
2  * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2001  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /* $Id: net.c,v 1.22.2.3 2004/03/09 06:12:11 marka Exp $ */
19
20 #include <config.h>
21
22 #include <errno.h>
23 #include <unistd.h>
24
25 #include <isc/log.h>
26 #include <isc/msgs.h>
27 #include <isc/net.h>
28 #include <isc/once.h>
29 #include <isc/strerror.h>
30 #include <isc/string.h>
31 #include <isc/util.h>
32
33 #if defined(ISC_PLATFORM_HAVEIPV6) && defined(ISC_PLATFORM_NEEDIN6ADDRANY)
34 const struct in6_addr isc_net_in6addrany = IN6ADDR_ANY_INIT;
35 #endif
36
37 #if defined(ISC_PLATFORM_HAVEIPV6) && defined(ISC_PLATFORM_NEEDIN6ADDRLOOPBACK)
38 const struct in6_addr isc_net_in6addrloop = IN6ADDR_LOOPBACK_INIT;
39 #endif
40
41 static isc_once_t       once = ISC_ONCE_INIT;
42 static isc_result_t     ipv4_result = ISC_R_NOTFOUND;
43 static isc_result_t     ipv6_result = ISC_R_NOTFOUND;
44
45 static isc_result_t
46 try_proto(int domain) {
47         int s;
48         isc_result_t result = ISC_R_SUCCESS;
49         char strbuf[ISC_STRERRORSIZE];
50
51         s = socket(domain, SOCK_STREAM, 0);
52         if (s == -1) {
53                 switch (errno) {
54 #ifdef EAFNOSUPPORT
55                 case EAFNOSUPPORT:
56 #endif
57 #ifdef EPROTONOSUPPORT
58                 case EPROTONOSUPPORT:
59 #endif
60 #ifdef EINVAL
61                 case EINVAL:
62 #endif
63                         return (ISC_R_NOTFOUND);
64                 default:
65                         isc__strerror(errno, strbuf, sizeof(strbuf));
66                         UNEXPECTED_ERROR(__FILE__, __LINE__,
67                                          "socket() %s: %s",
68                                          isc_msgcat_get(isc_msgcat,
69                                                         ISC_MSGSET_GENERAL,
70                                                         ISC_MSG_FAILED,
71                                                         "failed"),
72                                          strbuf);
73                         return (ISC_R_UNEXPECTED);
74                 }
75         }
76
77 #ifdef ISC_PLATFORM_HAVEIPV6
78 #ifdef WANT_IPV6
79 #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
80         if (domain == PF_INET6) {
81                 struct sockaddr_in6 sin6;
82                 unsigned int len;
83
84                 /*
85                  * Check to see if IPv6 is broken, as is common on Linux.
86                  */
87                 len = sizeof(sin6);
88                 if (getsockname(s, (struct sockaddr *)&sin6, (void *)&len) < 0)
89                 {
90                         isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
91                                       ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
92                                       "retrieving the address of an IPv6 "
93                                       "socket from the kernel failed.");
94                         isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
95                                       ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
96                                       "IPv6 support is disabled.");
97                         result = ISC_R_NOTFOUND;
98                 } else {
99                         if (len == sizeof(struct sockaddr_in6))
100                                 result = ISC_R_SUCCESS;
101                         else {
102                                 isc_log_write(isc_lctx,
103                                               ISC_LOGCATEGORY_GENERAL,
104                                               ISC_LOGMODULE_SOCKET,
105                                               ISC_LOG_ERROR,
106                                               "IPv6 structures in kernel and "
107                                               "user space do not match.");
108                                 isc_log_write(isc_lctx,
109                                               ISC_LOGCATEGORY_GENERAL,
110                                               ISC_LOGMODULE_SOCKET,
111                                               ISC_LOG_ERROR,
112                                               "IPv6 support is disabled.");
113                                 result = ISC_R_NOTFOUND;
114                         }
115                 }
116         }
117 #endif
118 #endif
119 #endif
120
121         close(s);
122
123         return (result);
124 }
125
126 static void
127 initialize_action(void) {
128         ipv4_result = try_proto(PF_INET);
129 #ifdef ISC_PLATFORM_HAVEIPV6
130 #ifdef WANT_IPV6
131 #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
132         ipv6_result = try_proto(PF_INET6);
133 #endif
134 #endif
135 #endif
136 }
137
138 static void
139 initialize(void) {
140         RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
141 }
142
143 isc_result_t
144 isc_net_probeipv4(void) {
145         initialize();
146         return (ipv4_result);
147 }
148
149 isc_result_t
150 isc_net_probeipv6(void) {
151         initialize();
152         return (ipv6_result);
153 }