fix grammar: a -> andiff -r1.47 -r1.48 src/lib/libc/net/getaddrinfo.3
(cegger)
--- src/lib/libc/net/getaddrinfo.3 2009/10/02 02:45:29 1.47
+++ src/lib/libc/net/getaddrinfo.3 2009/10/02 06:49:23 1.48
@@ -1,468 +1,468 @@ | @@ -1,468 +1,468 @@ | |||
1 | .\" $NetBSD: getaddrinfo.3,v 1.47 2009/10/02 02:45:29 tsarna Exp $ | 1 | .\" $NetBSD: getaddrinfo.3,v 1.48 2009/10/02 06:49:23 cegger Exp $ | |
2 | .\" $KAME: getaddrinfo.3,v 1.36 2005/01/05 03:23:05 itojun Exp $ | 2 | .\" $KAME: getaddrinfo.3,v 1.36 2005/01/05 03:23:05 itojun Exp $ | |
3 | .\" $OpenBSD: getaddrinfo.3,v 1.35 2004/12/21 03:40:31 jaredy Exp $ | 3 | .\" $OpenBSD: getaddrinfo.3,v 1.35 2004/12/21 03:40:31 jaredy Exp $ | |
4 | .\" | 4 | .\" | |
5 | .\" Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") | 5 | .\" Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") | |
6 | .\" Copyright (C) 2000, 2001 Internet Software Consortium. | 6 | .\" Copyright (C) 2000, 2001 Internet Software Consortium. | |
7 | .\" | 7 | .\" | |
8 | .\" Permission to use, copy, modify, and distribute this software for any | 8 | .\" Permission to use, copy, modify, and distribute this software for any | |
9 | .\" purpose with or without fee is hereby granted, provided that the above | 9 | .\" purpose with or without fee is hereby granted, provided that the above | |
10 | .\" copyright notice and this permission notice appear in all copies. | 10 | .\" copyright notice and this permission notice appear in all copies. | |
11 | .\" | 11 | .\" | |
12 | .\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH | 12 | .\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH | |
13 | .\" REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | 13 | .\" REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | |
14 | .\" AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, | 14 | .\" AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, | |
15 | .\" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM | 15 | .\" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM | |
16 | .\" LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE | 16 | .\" LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE | |
17 | .\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | 17 | .\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | |
18 | .\" PERFORMANCE OF THIS SOFTWARE. | 18 | .\" PERFORMANCE OF THIS SOFTWARE. | |
19 | .\" | 19 | .\" | |
20 | .Dd November 24, 2006 | 20 | .Dd November 24, 2006 | |
21 | .Dt GETADDRINFO 3 | 21 | .Dt GETADDRINFO 3 | |
22 | .Os | 22 | .Os | |
23 | .Sh NAME | 23 | .Sh NAME | |
24 | .Nm getaddrinfo , | 24 | .Nm getaddrinfo , | |
25 | .Nm freeaddrinfo , | 25 | .Nm freeaddrinfo , | |
26 | .Nm allocaddrinfo | 26 | .Nm allocaddrinfo | |
27 | .Nd host and service name to socket address structure | 27 | .Nd host and service name to socket address structure | |
28 | .Sh SYNOPSIS | 28 | .Sh SYNOPSIS | |
29 | .In netdb.h | 29 | .In netdb.h | |
30 | .Ft int | 30 | .Ft int | |
31 | .Fn getaddrinfo "const char * restrict hostname" \ | 31 | .Fn getaddrinfo "const char * restrict hostname" \ | |
32 | "const char * restrict servname" \ | 32 | "const char * restrict servname" \ | |
33 | "const struct addrinfo * restrict hints" "struct addrinfo ** restrict res" | 33 | "const struct addrinfo * restrict hints" "struct addrinfo ** restrict res" | |
34 | .Ft void | 34 | .Ft void | |
35 | .Fn freeaddrinfo "struct addrinfo *ai" | 35 | .Fn freeaddrinfo "struct addrinfo *ai" | |
36 | .Ft struct addrinfo * | 36 | .Ft struct addrinfo * | |
37 | .Fn allocaddrinfo "socklen_t len" | 37 | .Fn allocaddrinfo "socklen_t len" | |
38 | .Sh DESCRIPTION | 38 | .Sh DESCRIPTION | |
39 | The | 39 | The | |
40 | .Fn getaddrinfo | 40 | .Fn getaddrinfo | |
41 | function is used to get a list of | 41 | function is used to get a list of | |
42 | .Tn IP | 42 | .Tn IP | |
43 | addresses and port numbers for host | 43 | addresses and port numbers for host | |
44 | .Fa hostname | 44 | .Fa hostname | |
45 | and service | 45 | and service | |
46 | .Fa servname . | 46 | .Fa servname . | |
47 | It is a replacement for and provides more flexibility than the | 47 | It is a replacement for and provides more flexibility than the | |
48 | .Xr gethostbyname 3 | 48 | .Xr gethostbyname 3 | |
49 | and | 49 | and | |
50 | .Xr getservbyname 3 | 50 | .Xr getservbyname 3 | |
51 | functions. | 51 | functions. | |
52 | .Pp | 52 | .Pp | |
53 | The | 53 | The | |
54 | .Fa hostname | 54 | .Fa hostname | |
55 | and | 55 | and | |
56 | .Fa servname | 56 | .Fa servname | |
57 | arguments are either pointers to NUL-terminated strings or the null pointer. | 57 | arguments are either pointers to NUL-terminated strings or the null pointer. | |
58 | An acceptable value for | 58 | An acceptable value for | |
59 | .Fa hostname | 59 | .Fa hostname | |
60 | is either a valid host name or a numeric host address string consisting | 60 | is either a valid host name or a numeric host address string consisting | |
61 | of a dotted decimal IPv4 address or an IPv6 address. | 61 | of a dotted decimal IPv4 address or an IPv6 address. | |
62 | The | 62 | The | |
63 | .Fa servname | 63 | .Fa servname | |
64 | is either a decimal port number or a service name listed in | 64 | is either a decimal port number or a service name listed in | |
65 | .Xr services 5 . | 65 | .Xr services 5 . | |
66 | At least one of | 66 | At least one of | |
67 | .Fa hostname | 67 | .Fa hostname | |
68 | and | 68 | and | |
69 | .Fa servname | 69 | .Fa servname | |
70 | must be non-null. | 70 | must be non-null. | |
71 | .Pp | 71 | .Pp | |
72 | .Fa hints | 72 | .Fa hints | |
73 | is an optional pointer to a | 73 | is an optional pointer to a | |
74 | .Li struct addrinfo , | 74 | .Li struct addrinfo , | |
75 | as defined by | 75 | as defined by | |
76 | .Aq Pa netdb.h : | 76 | .Aq Pa netdb.h : | |
77 | .Bd -literal | 77 | .Bd -literal | |
78 | struct addrinfo { | 78 | struct addrinfo { | |
79 | int ai_flags; /* input flags */ | 79 | int ai_flags; /* input flags */ | |
80 | int ai_family; /* protocol family for socket */ | 80 | int ai_family; /* protocol family for socket */ | |
81 | int ai_socktype; /* socket type */ | 81 | int ai_socktype; /* socket type */ | |
82 | int ai_protocol; /* protocol for socket */ | 82 | int ai_protocol; /* protocol for socket */ | |
83 | socklen_t ai_addrlen; /* length of socket-address */ | 83 | socklen_t ai_addrlen; /* length of socket-address */ | |
84 | struct sockaddr *ai_addr; /* socket-address for socket */ | 84 | struct sockaddr *ai_addr; /* socket-address for socket */ | |
85 | char *ai_canonname; /* canonical name for service location */ | 85 | char *ai_canonname; /* canonical name for service location */ | |
86 | struct addrinfo *ai_next; /* pointer to next in list */ | 86 | struct addrinfo *ai_next; /* pointer to next in list */ | |
87 | }; | 87 | }; | |
88 | .Ed | 88 | .Ed | |
89 | .Pp | 89 | .Pp | |
90 | This structure can be used to provide hints concerning the type of socket | 90 | This structure can be used to provide hints concerning the type of socket | |
91 | that the caller supports or wishes to use. | 91 | that the caller supports or wishes to use. | |
92 | The caller can supply the following structure elements in | 92 | The caller can supply the following structure elements in | |
93 | .Fa hints : | 93 | .Fa hints : | |
94 | .Bl -tag -width "ai_socktypeXX" | 94 | .Bl -tag -width "ai_socktypeXX" | |
95 | .It Fa ai_family | 95 | .It Fa ai_family | |
96 | The protocol family that should be used. | 96 | The protocol family that should be used. | |
97 | When | 97 | When | |
98 | .Fa ai_family | 98 | .Fa ai_family | |
99 | is set to | 99 | is set to | |
100 | .Dv PF_UNSPEC , | 100 | .Dv PF_UNSPEC , | |
101 | it means the caller will accept any protocol family supported by the | 101 | it means the caller will accept any protocol family supported by the | |
102 | operating system. | 102 | operating system. | |
103 | .It Fa ai_socktype | 103 | .It Fa ai_socktype | |
104 | Denotes the type of socket that is wanted: | 104 | Denotes the type of socket that is wanted: | |
105 | .Dv SOCK_STREAM , | 105 | .Dv SOCK_STREAM , | |
106 | .Dv SOCK_DGRAM , | 106 | .Dv SOCK_DGRAM , | |
107 | or | 107 | or | |
108 | .Dv SOCK_RAW . | 108 | .Dv SOCK_RAW . | |
109 | When | 109 | When | |
110 | .Fa ai_socktype | 110 | .Fa ai_socktype | |
111 | is zero the caller will accept any socket type. | 111 | is zero the caller will accept any socket type. | |
112 | .It Fa ai_protocol | 112 | .It Fa ai_protocol | |
113 | Indicates which transport protocol is desired, | 113 | Indicates which transport protocol is desired, | |
114 | .Dv IPPROTO_UDP | 114 | .Dv IPPROTO_UDP | |
115 | or | 115 | or | |
116 | .Dv IPPROTO_TCP . | 116 | .Dv IPPROTO_TCP . | |
117 | If | 117 | If | |
118 | .Fa ai_protocol | 118 | .Fa ai_protocol | |
119 | is zero the caller will accept any protocol. | 119 | is zero the caller will accept any protocol. | |
120 | .It Fa ai_flags | 120 | .It Fa ai_flags | |
121 | .Fa ai_flags | 121 | .Fa ai_flags | |
122 | is formed by | 122 | is formed by | |
123 | .Tn OR Ns 'ing | 123 | .Tn OR Ns 'ing | |
124 | the following values: | 124 | the following values: | |
125 | .Bl -tag -width "AI_CANONNAMEXX" | 125 | .Bl -tag -width "AI_CANONNAMEXX" | |
126 | .It Dv AI_CANONNAME | 126 | .It Dv AI_CANONNAME | |
127 | If the | 127 | If the | |
128 | .Dv AI_CANONNAME | 128 | .Dv AI_CANONNAME | |
129 | bit is set, a successful call to | 129 | bit is set, a successful call to | |
130 | .Fn getaddrinfo | 130 | .Fn getaddrinfo | |
131 | will return a NUL-terminated string containing the canonical name | 131 | will return a NUL-terminated string containing the canonical name | |
132 | of the specified hostname in the | 132 | of the specified hostname in the | |
133 | .Fa ai_canonname | 133 | .Fa ai_canonname | |
134 | element of the first | 134 | element of the first | |
135 | .Li addrinfo | 135 | .Li addrinfo | |
136 | structure returned. | 136 | structure returned. | |
137 | .It Dv AI_NUMERICHOST | 137 | .It Dv AI_NUMERICHOST | |
138 | If the | 138 | If the | |
139 | .Dv AI_NUMERICHOST | 139 | .Dv AI_NUMERICHOST | |
140 | bit is set, it indicates that | 140 | bit is set, it indicates that | |
141 | .Fa hostname | 141 | .Fa hostname | |
142 | should be treated as a numeric string defining an IPv4 or IPv6 address | 142 | should be treated as a numeric string defining an IPv4 or IPv6 address | |
143 | and no name resolution should be attempted. | 143 | and no name resolution should be attempted. | |
144 | .It Dv AI_NUMERICSERV | 144 | .It Dv AI_NUMERICSERV | |
145 | If the | 145 | If the | |
146 | .Dv AI_NUMERICSERV | 146 | .Dv AI_NUMERICSERV | |
147 | bit is set, it indicates that the | 147 | bit is set, it indicates that the | |
148 | .Fa servname | 148 | .Fa servname | |
149 | string contains a numeric port number. | 149 | string contains a numeric port number. | |
150 | This is used to prevent service name resolution. | 150 | This is used to prevent service name resolution. | |
151 | .It Dv AI_PASSIVE | 151 | .It Dv AI_PASSIVE | |
152 | If the | 152 | If the | |
153 | .Dv AI_PASSIVE | 153 | .Dv AI_PASSIVE | |
154 | bit is set it indicates that the returned socket address structure | 154 | bit is set it indicates that the returned socket address structure | |
155 | is intended for use in a call to | 155 | is intended for use in a call to | |
156 | .Xr bind 2 . | 156 | .Xr bind 2 . | |
157 | In this case, if the | 157 | In this case, if the | |
158 | .Fa hostname | 158 | .Fa hostname | |
159 | argument is the null pointer, then the IP address portion of the | 159 | argument is the null pointer, then the IP address portion of the | |
160 | socket address structure will be set to | 160 | socket address structure will be set to | |
161 | .Dv INADDR_ANY | 161 | .Dv INADDR_ANY | |
162 | for an IPv4 address or | 162 | for an IPv4 address or | |
163 | .Dv IN6ADDR_ANY_INIT | 163 | .Dv IN6ADDR_ANY_INIT | |
164 | for an IPv6 address. | 164 | for an IPv6 address. | |
165 | .Pp | 165 | .Pp | |
166 | If the | 166 | If the | |
167 | .Dv AI_PASSIVE | 167 | .Dv AI_PASSIVE | |
168 | bit is not set, the returned socket address structure will be ready | 168 | bit is not set, the returned socket address structure will be ready | |
169 | for use in a call to | 169 | for use in a call to | |
170 | .Xr connect 2 | 170 | .Xr connect 2 | |
171 | for a connection-oriented protocol or | 171 | for a connection-oriented protocol or | |
172 | .Xr connect 2 , | 172 | .Xr connect 2 , | |
173 | .Xr sendto 2 , | 173 | .Xr sendto 2 , | |
174 | or | 174 | or | |
175 | .Xr sendmsg 2 | 175 | .Xr sendmsg 2 | |
176 | if a connectionless protocol was chosen. | 176 | if a connectionless protocol was chosen. | |
177 | The | 177 | The | |
178 | .Tn IP | 178 | .Tn IP | |
179 | address portion of the socket address structure will be set to the | 179 | address portion of the socket address structure will be set to the | |
180 | loopback address if | 180 | loopback address if | |
181 | .Fa hostname | 181 | .Fa hostname | |
182 | is the null pointer and | 182 | is the null pointer and | |
183 | .Dv AI_PASSIVE | 183 | .Dv AI_PASSIVE | |
184 | is not set. | 184 | is not set. | |
185 | .El | 185 | .El | |
186 | .El | 186 | .El | |
187 | .Pp | 187 | .Pp | |
188 | All other elements of the | 188 | All other elements of the | |
189 | .Li addrinfo | 189 | .Li addrinfo | |
190 | structure passed via | 190 | structure passed via | |
191 | .Fa hints | 191 | .Fa hints | |
192 | must be zero or the null pointer. | 192 | must be zero or the null pointer. | |
193 | .Pp | 193 | .Pp | |
194 | If | 194 | If | |
195 | .Fa hints | 195 | .Fa hints | |
196 | is the null pointer, | 196 | is the null pointer, | |
197 | .Fn getaddrinfo | 197 | .Fn getaddrinfo | |
198 | behaves as if the caller provided a | 198 | behaves as if the caller provided a | |
199 | .Li struct addrinfo | 199 | .Li struct addrinfo | |
200 | with | 200 | with | |
201 | .Fa ai_family | 201 | .Fa ai_family | |
202 | set to | 202 | set to | |
203 | .Dv PF_UNSPEC | 203 | .Dv PF_UNSPEC | |
204 | and all other elements set to zero or | 204 | and all other elements set to zero or | |
205 | .Dv NULL . | 205 | .Dv NULL . | |
206 | .Pp | 206 | .Pp | |
207 | After a successful call to | 207 | After a successful call to | |
208 | .Fn getaddrinfo , | 208 | .Fn getaddrinfo , | |
209 | .Fa *res | 209 | .Fa *res | |
210 | is a pointer to a linked list of one or more | 210 | is a pointer to a linked list of one or more | |
211 | .Li addrinfo | 211 | .Li addrinfo | |
212 | structures. | 212 | structures. | |
213 | The list can be traversed by following the | 213 | The list can be traversed by following the | |
214 | .Fa ai_next | 214 | .Fa ai_next | |
215 | pointer in each | 215 | pointer in each | |
216 | .Li addrinfo | 216 | .Li addrinfo | |
217 | structure until a null pointer is encountered. | 217 | structure until a null pointer is encountered. | |
218 | The three members | 218 | The three members | |
219 | .Fa ai_family , | 219 | .Fa ai_family , | |
220 | .Fa ai_socktype , | 220 | .Fa ai_socktype , | |
221 | and | 221 | and | |
222 | .Fa ai_protocol | 222 | .Fa ai_protocol | |
223 | in each returned | 223 | in each returned | |
224 | .Li addrinfo | 224 | .Li addrinfo | |
225 | structure are suitable for a call to | 225 | structure are suitable for a call to | |
226 | .Xr socket 2 . | 226 | .Xr socket 2 . | |
227 | For each | 227 | For each | |
228 | .Li addrinfo | 228 | .Li addrinfo | |
229 | structure in the list, the | 229 | structure in the list, the | |
230 | .Fa ai_addr | 230 | .Fa ai_addr | |
231 | member points to a filled-in socket address structure of length | 231 | member points to a filled-in socket address structure of length | |
232 | .Fa ai_addrlen . | 232 | .Fa ai_addrlen . | |
233 | .Pp | 233 | .Pp | |
234 | This implementation of | 234 | This implementation of | |
235 | .Fn getaddrinfo | 235 | .Fn getaddrinfo | |
236 | allows numeric IPv6 address notation with scope identifier, | 236 | allows numeric IPv6 address notation with scope identifier, | |
237 | as documented in chapter 11 of draft-ietf-ipv6-scoping-arch-02.txt. | 237 | as documented in chapter 11 of draft-ietf-ipv6-scoping-arch-02.txt. | |
238 | By appending the percent character and scope identifier to addresses, | 238 | By appending the percent character and scope identifier to addresses, | |
239 | one can fill the | 239 | one can fill the | |
240 | .Li sin6_scope_id | 240 | .Li sin6_scope_id | |
241 | field for addresses. | 241 | field for addresses. | |
242 | This would make management of scoped addresses easier | 242 | This would make management of scoped addresses easier | |
243 | and allows cut-and-paste input of scoped addresses. | 243 | and allows cut-and-paste input of scoped addresses. | |
244 | .Pp | 244 | .Pp | |
245 | At this moment the code supports only link-local addresses with the format. | 245 | At this moment the code supports only link-local addresses with the format. | |
246 | The scope identifier is hardcoded to the name of the hardware interface | 246 | The scope identifier is hardcoded to the name of the hardware interface | |
247 | associated | 247 | associated | |
248 | with the link | 248 | with the link | |
249 | .Po | 249 | .Po | |
250 | such as | 250 | such as | |
251 | .Li ne0 | 251 | .Li ne0 | |
252 | .Pc . | 252 | .Pc . | |
253 | An example is | 253 | An example is | |
254 | .Dq Li fe80::1%ne0 , | 254 | .Dq Li fe80::1%ne0 , | |
255 | which means | 255 | which means | |
256 | .Do | 256 | .Do | |
257 | .Li fe80::1 | 257 | .Li fe80::1 | |
258 | on the link associated with the | 258 | on the link associated with the | |
259 | .Li ne0 | 259 | .Li ne0 | |
260 | interface | 260 | interface | |
261 | .Dc . | 261 | .Dc . | |
262 | .Pp | 262 | .Pp | |
263 | The current implementation assumes a one-to-one relationship between | 263 | The current implementation assumes an one-to-one relationship between | |
264 | the interface and link, which is not necessarily true from the specification. | 264 | the interface and link, which is not necessarily true from the specification. | |
265 | .Pp | 265 | .Pp | |
266 | All of the information returned by | 266 | All of the information returned by | |
267 | .Fn getaddrinfo | 267 | .Fn getaddrinfo | |
268 | is dynamically allocated: the | 268 | is dynamically allocated: the | |
269 | .Li addrinfo | 269 | .Li addrinfo | |
270 | structures themselves as well as the socket address structures and | 270 | structures themselves as well as the socket address structures and | |
271 | the canonical host name strings included in the | 271 | the canonical host name strings included in the | |
272 | .Li addrinfo | 272 | .Li addrinfo | |
273 | structures. | 273 | structures. | |
274 | .Pp | 274 | .Pp | |
275 | Memory allocated for the dynamically allocated structures created by | 275 | Memory allocated for the dynamically allocated structures created by | |
276 | a successful call to | 276 | a successful call to | |
277 | .Fn getaddrinfo | 277 | .Fn getaddrinfo | |
278 | is released by the | 278 | is released by the | |
279 | .Fn freeaddrinfo | 279 | .Fn freeaddrinfo | |
280 | function. | 280 | function. | |
281 | The | 281 | The | |
282 | .Fa ai | 282 | .Fa ai | |
283 | pointer should be a | 283 | pointer should be an | |
284 | .Li addrinfo | 284 | .Li addrinfo | |
285 | structure created by a call to | 285 | structure created by a call to | |
286 | .Fn getaddrinfo | 286 | .Fn getaddrinfo | |
287 | or | 287 | or | |
288 | .Fn allocaddrinfo . | 288 | .Fn allocaddrinfo . | |
289 | The | 289 | The | |
290 | .Fn allocaddrinfo | 290 | .Fn allocaddrinfo | |
291 | function is intended primarily for authors of | 291 | function is intended primarily for authors of | |
292 | .Xr nsdispatch 3 | 292 | .Xr nsdispatch 3 | |
293 | plugins implementing | 293 | plugins implementing | |
294 | .Fn getaddrinfo | 294 | .Fn getaddrinfo | |
295 | backends. | 295 | backends. | |
296 | .Fn allocaddrinfo | 296 | .Fn allocaddrinfo | |
297 | allocates a | 297 | allocates a | |
298 | .Li struct addrinfo | 298 | .Li struct addrinfo | |
299 | in a way that is compatible with being returned from | 299 | in a way that is compatible with being returned from | |
300 | .Fn getaddrinfo | 300 | .Fn getaddrinfo | |
301 | and being ultimately freed by | 301 | and being ultimately freed by | |
302 | .Fn freeaddrinfo . | 302 | .Fn freeaddrinfo . | |
303 | The returned structure is zeroed, except for the | 303 | The returned structure is zeroed, except for the | |
304 | .Fa ai_addr | 304 | .Fa ai_addr | |
305 | field, which | 305 | field, which | |
306 | will point to | 306 | will point to | |
307 | .Fa len | 307 | .Fa len | |
308 | bytes of memory for storage of a socket address. | 308 | bytes of memory for storage of a socket address. | |
309 | It is safe to allocate memory separately for | 309 | It is safe to allocate memory separately for | |
310 | .Fa ai_canonname | 310 | .Fa ai_canonname | |
311 | with | 311 | with | |
312 | .Xr malloc 3 , | 312 | .Xr malloc 3 , | |
313 | or in any other way that is compatible with deallocation by | 313 | or in any other way that is compatible with deallocation by | |
314 | .Xr free 3 . | 314 | .Xr free 3 . | |
315 | .Sh RETURN VALUES | 315 | .Sh RETURN VALUES | |
316 | .Fn getaddrinfo | 316 | .Fn getaddrinfo | |
317 | returns zero on success or one of the error codes listed in | 317 | returns zero on success or one of the error codes listed in | |
318 | .Xr gai_strerror 3 | 318 | .Xr gai_strerror 3 | |
319 | if an error occurs. | 319 | if an error occurs. | |
320 | .Sh EXAMPLES | 320 | .Sh EXAMPLES | |
321 | The following code tries to connect to | 321 | The following code tries to connect to | |
322 | .Dq Li www.kame.net | 322 | .Dq Li www.kame.net | |
323 | service | 323 | service | |
324 | .Dq Li http | 324 | .Dq Li http | |
325 | via a stream socket. | 325 | via a stream socket. | |
326 | It loops through all the addresses available, regardless of address family. | 326 | It loops through all the addresses available, regardless of address family. | |
327 | If the destination resolves to an IPv4 address, it will use an | 327 | If the destination resolves to an IPv4 address, it will use an | |
328 | .Dv AF_INET | 328 | .Dv AF_INET | |
329 | socket. | 329 | socket. | |
330 | Similarly, if it resolves to IPv6, an | 330 | Similarly, if it resolves to IPv6, an | |
331 | .Dv AF_INET6 | 331 | .Dv AF_INET6 | |
332 | socket is used. | 332 | socket is used. | |
333 | Observe that there is no hardcoded reference to a particular address family. | 333 | Observe that there is no hardcoded reference to a particular address family. | |
334 | The code works even if | 334 | The code works even if | |
335 | .Fn getaddrinfo | 335 | .Fn getaddrinfo | |
336 | returns addresses that are not IPv4/v6. | 336 | returns addresses that are not IPv4/v6. | |
337 | .Bd -literal -offset indent | 337 | .Bd -literal -offset indent | |
338 | struct addrinfo hints, *res, *res0; | 338 | struct addrinfo hints, *res, *res0; | |
339 | int error; | 339 | int error; | |
340 | int s; | 340 | int s; | |
341 | const char *cause = NULL; | 341 | const char *cause = NULL; | |
342 | 342 | |||
343 | memset(\*[Am]hints, 0, sizeof(hints)); | 343 | memset(\*[Am]hints, 0, sizeof(hints)); | |
344 | hints.ai_family = PF_UNSPEC; | 344 | hints.ai_family = PF_UNSPEC; | |
345 | hints.ai_socktype = SOCK_STREAM; | 345 | hints.ai_socktype = SOCK_STREAM; | |
346 | error = getaddrinfo("www.kame.net", "http", \*[Am]hints, \*[Am]res0); | 346 | error = getaddrinfo("www.kame.net", "http", \*[Am]hints, \*[Am]res0); | |
347 | if (error) { | 347 | if (error) { | |
348 | errx(1, "%s", gai_strerror(error)); | 348 | errx(1, "%s", gai_strerror(error)); | |
349 | /*NOTREACHED*/ | 349 | /*NOTREACHED*/ | |
350 | } | 350 | } | |
351 | s = -1; | 351 | s = -1; | |
352 | for (res = res0; res; res = res-\*[Gt]ai_next) { | 352 | for (res = res0; res; res = res-\*[Gt]ai_next) { | |
353 | s = socket(res-\*[Gt]ai_family, res-\*[Gt]ai_socktype, | 353 | s = socket(res-\*[Gt]ai_family, res-\*[Gt]ai_socktype, | |
354 | res-\*[Gt]ai_protocol); | 354 | res-\*[Gt]ai_protocol); | |
355 | if (s \*[Lt] 0) { | 355 | if (s \*[Lt] 0) { | |
356 | cause = "socket"; | 356 | cause = "socket"; | |
357 | continue; | 357 | continue; | |
358 | } | 358 | } | |
359 | 359 | |||
360 | if (connect(s, res-\*[Gt]ai_addr, res-\*[Gt]ai_addrlen) \*[Lt] 0) { | 360 | if (connect(s, res-\*[Gt]ai_addr, res-\*[Gt]ai_addrlen) \*[Lt] 0) { | |
361 | cause = "connect"; | 361 | cause = "connect"; | |
362 | close(s); | 362 | close(s); | |
363 | s = -1; | 363 | s = -1; | |
364 | continue; | 364 | continue; | |
365 | } | 365 | } | |
366 | 366 | |||
367 | break; /* okay we got one */ | 367 | break; /* okay we got one */ | |
368 | } | 368 | } | |
369 | if (s \*[Lt] 0) { | 369 | if (s \*[Lt] 0) { | |
370 | err(1, "%s", cause); | 370 | err(1, "%s", cause); | |
371 | /*NOTREACHED*/ | 371 | /*NOTREACHED*/ | |
372 | } | 372 | } | |
373 | freeaddrinfo(res0); | 373 | freeaddrinfo(res0); | |
374 | .Ed | 374 | .Ed | |
375 | .Pp | 375 | .Pp | |
376 | The following example tries to open a wildcard listening socket onto service | 376 | The following example tries to open a wildcard listening socket onto service | |
377 | .Dq Li http , | 377 | .Dq Li http , | |
378 | for all the address families available. | 378 | for all the address families available. | |
379 | .Bd -literal -offset indent | 379 | .Bd -literal -offset indent | |
380 | struct addrinfo hints, *res, *res0; | 380 | struct addrinfo hints, *res, *res0; | |
381 | int error; | 381 | int error; | |
382 | int s[MAXSOCK]; | 382 | int s[MAXSOCK]; | |
383 | int nsock; | 383 | int nsock; | |
384 | const char *cause = NULL; | 384 | const char *cause = NULL; | |
385 | 385 | |||
386 | memset(\*[Am]hints, 0, sizeof(hints)); | 386 | memset(\*[Am]hints, 0, sizeof(hints)); | |
387 | hints.ai_family = PF_UNSPEC; | 387 | hints.ai_family = PF_UNSPEC; | |
388 | hints.ai_socktype = SOCK_STREAM; | 388 | hints.ai_socktype = SOCK_STREAM; | |
389 | hints.ai_flags = AI_PASSIVE; | 389 | hints.ai_flags = AI_PASSIVE; | |
390 | error = getaddrinfo(NULL, "http", \*[Am]hints, \*[Am]res0); | 390 | error = getaddrinfo(NULL, "http", \*[Am]hints, \*[Am]res0); | |
391 | if (error) { | 391 | if (error) { | |
392 | errx(1, "%s", gai_strerror(error)); | 392 | errx(1, "%s", gai_strerror(error)); | |
393 | /*NOTREACHED*/ | 393 | /*NOTREACHED*/ | |
394 | } | 394 | } | |
395 | nsock = 0; | 395 | nsock = 0; | |
396 | for (res = res0; res \*[Am]\*[Am] nsock \*[Lt] MAXSOCK; res = res-\*[Gt]ai_next) { | 396 | for (res = res0; res \*[Am]\*[Am] nsock \*[Lt] MAXSOCK; res = res-\*[Gt]ai_next) { | |
397 | s[nsock] = socket(res-\*[Gt]ai_family, res-\*[Gt]ai_socktype, | 397 | s[nsock] = socket(res-\*[Gt]ai_family, res-\*[Gt]ai_socktype, | |
398 | res-\*[Gt]ai_protocol); | 398 | res-\*[Gt]ai_protocol); | |
399 | if (s[nsock] \*[Lt] 0) { | 399 | if (s[nsock] \*[Lt] 0) { | |
400 | cause = "socket"; | 400 | cause = "socket"; | |
401 | continue; | 401 | continue; | |
402 | } | 402 | } | |
403 | 403 | |||
404 | if (bind(s[nsock], res-\*[Gt]ai_addr, res-\*[Gt]ai_addrlen) \*[Lt] 0) { | 404 | if (bind(s[nsock], res-\*[Gt]ai_addr, res-\*[Gt]ai_addrlen) \*[Lt] 0) { | |
405 | cause = "bind"; | 405 | cause = "bind"; | |
406 | close(s[nsock]); | 406 | close(s[nsock]); | |
407 | continue; | 407 | continue; | |
408 | } | 408 | } | |
409 | (void) listen(s[nsock], 5); | 409 | (void) listen(s[nsock], 5); | |
410 | 410 | |||
411 | nsock++; | 411 | nsock++; | |
412 | } | 412 | } | |
413 | if (nsock == 0) { | 413 | if (nsock == 0) { | |
414 | err(1, "%s", cause); | 414 | err(1, "%s", cause); | |
415 | /*NOTREACHED*/ | 415 | /*NOTREACHED*/ | |
416 | } | 416 | } | |
417 | freeaddrinfo(res0); | 417 | freeaddrinfo(res0); | |
418 | .Ed | 418 | .Ed | |
419 | .Sh SEE ALSO | 419 | .Sh SEE ALSO | |
420 | .Xr bind 2 , | 420 | .Xr bind 2 , | |
421 | .Xr connect 2 , | 421 | .Xr connect 2 , | |
422 | .Xr send 2 , | 422 | .Xr send 2 , | |
423 | .Xr socket 2 , | 423 | .Xr socket 2 , | |
424 | .Xr gai_strerror 3 , | 424 | .Xr gai_strerror 3 , | |
425 | .Xr gethostbyname 3 , | 425 | .Xr gethostbyname 3 , | |
426 | .Xr getnameinfo 3 , | 426 | .Xr getnameinfo 3 , | |
427 | .Xr getservbyname 3 , | 427 | .Xr getservbyname 3 , | |
428 | .Xr resolver 3 , | 428 | .Xr resolver 3 , | |
429 | .Xr hosts 5 , | 429 | .Xr hosts 5 , | |
430 | .Xr resolv.conf 5 , | 430 | .Xr resolv.conf 5 , | |
431 | .Xr services 5 , | 431 | .Xr services 5 , | |
432 | .Xr hostname 7 , | 432 | .Xr hostname 7 , | |
433 | .Xr named 8 | 433 | .Xr named 8 | |
434 | .Rs | 434 | .Rs | |
435 | .%A R. Gilligan | 435 | .%A R. Gilligan | |
436 | .%A S. Thomson | 436 | .%A S. Thomson | |
437 | .%A J. Bound | 437 | .%A J. Bound | |
438 | .%A J. McCann | 438 | .%A J. McCann | |
439 | .%A W. Stevens | 439 | .%A W. Stevens | |
440 | .%T Basic Socket Interface Extensions for IPv6 | 440 | .%T Basic Socket Interface Extensions for IPv6 | |
441 | .%R RFC 3493 | 441 | .%R RFC 3493 | |
442 | .%D February 2003 | 442 | .%D February 2003 | |
443 | .Re | 443 | .Re | |
444 | .Rs | 444 | .Rs | |
445 | .%A S. Deering | 445 | .%A S. Deering | |
446 | .%A B. Haberman | 446 | .%A B. Haberman | |
447 | .%A T. Jinmei | 447 | .%A T. Jinmei | |
448 | .%A E. Nordmark | 448 | .%A E. Nordmark | |
449 | .%A B. Zill | 449 | .%A B. Zill | |
450 | .%T "IPv6 Scoped Address Architecture" | 450 | .%T "IPv6 Scoped Address Architecture" | |
451 | .%R internet draft | 451 | .%R internet draft | |
452 | .%N draft-ietf-ipv6-scoping-arch-02.txt | 452 | .%N draft-ietf-ipv6-scoping-arch-02.txt | |
453 | .%O work in progress material | 453 | .%O work in progress material | |
454 | .Re | 454 | .Re | |
455 | .Rs | 455 | .Rs | |
456 | .%A Craig Metz | 456 | .%A Craig Metz | |
457 | .%T Protocol Independence Using the Sockets API | 457 | .%T Protocol Independence Using the Sockets API | |
458 | .%B "Proceedings of the FREENIX track: 2000 USENIX annual technical conference" | 458 | .%B "Proceedings of the FREENIX track: 2000 USENIX annual technical conference" | |
459 | .%D June 2000 | 459 | .%D June 2000 | |
460 | .Re | 460 | .Re | |
461 | .Sh STANDARDS | 461 | .Sh STANDARDS | |
462 | The | 462 | The | |
463 | .Fn getaddrinfo | 463 | .Fn getaddrinfo | |
464 | function is defined by the | 464 | function is defined by the | |
465 | .St -p1003.1g-2000 | 465 | .St -p1003.1g-2000 | |
466 | draft specification and documented in | 466 | draft specification and documented in | |
467 | .Dv "RFC 3493" , | 467 | .Dv "RFC 3493" , | |
468 | .Dq Basic Socket Interface Extensions for IPv6 . | 468 | .Dq Basic Socket Interface Extensions for IPv6 . |
--- src/lib/libc/net/getaddrinfo.c 2009/10/02 02:45:29 1.93
+++ src/lib/libc/net/getaddrinfo.c 2009/10/02 06:49:23 1.94
@@ -1,1958 +1,1958 @@ | @@ -1,1958 +1,1958 @@ | |||
1 | /* $NetBSD: getaddrinfo.c,v 1.93 2009/10/02 02:45:29 tsarna Exp $ */ | 1 | /* $NetBSD: getaddrinfo.c,v 1.94 2009/10/02 06:49:23 cegger Exp $ */ | |
2 | /* $KAME: getaddrinfo.c,v 1.29 2000/08/31 17:26:57 itojun Exp $ */ | 2 | /* $KAME: getaddrinfo.c,v 1.29 2000/08/31 17:26:57 itojun Exp $ */ | |
3 | 3 | |||
4 | /* | 4 | /* | |
5 | * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. | 5 | * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. | |
6 | * All rights reserved. | 6 | * All rights reserved. | |
7 | * | 7 | * | |
8 | * Redistribution and use in source and binary forms, with or without | 8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions | 9 | * modification, are permitted provided that the following conditions | |
10 | * are met: | 10 | * are met: | |
11 | * 1. Redistributions of source code must retain the above copyright | 11 | * 1. Redistributions of source code must retain the above copyright | |
12 | * notice, this list of conditions and the following disclaimer. | 12 | * notice, this list of conditions and the following disclaimer. | |
13 | * 2. Redistributions in binary form must reproduce the above copyright | 13 | * 2. Redistributions in binary form must reproduce the above copyright | |
14 | * notice, this list of conditions and the following disclaimer in the | 14 | * notice, this list of conditions and the following disclaimer in the | |
15 | * documentation and/or other materials provided with the distribution. | 15 | * documentation and/or other materials provided with the distribution. | |
16 | * 3. Neither the name of the project nor the names of its contributors | 16 | * 3. Neither the name of the project nor the names of its contributors | |
17 | * may be used to endorse or promote products derived from this software | 17 | * may be used to endorse or promote products derived from this software | |
18 | * without specific prior written permission. | 18 | * without specific prior written permission. | |
19 | * | 19 | * | |
20 | * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND | 20 | * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND | |
21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE | 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE | |
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
30 | * SUCH DAMAGE. | 30 | * SUCH DAMAGE. | |
31 | */ | 31 | */ | |
32 | 32 | |||
33 | /* | 33 | /* | |
34 | * Issues to be discussed: | 34 | * Issues to be discussed: | |
35 | * - Return values. There are nonstandard return values defined and used | 35 | * - Return values. There are nonstandard return values defined and used | |
36 | * in the source code. This is because RFC2553 is silent about which error | 36 | * in the source code. This is because RFC2553 is silent about which error | |
37 | * code must be returned for which situation. | 37 | * code must be returned for which situation. | |
38 | * - IPv4 classful (shortened) form. RFC2553 is silent about it. XNET 5.2 | 38 | * - IPv4 classful (shortened) form. RFC2553 is silent about it. XNET 5.2 | |
39 | * says to use inet_aton() to convert IPv4 numeric to binary (alows | 39 | * says to use inet_aton() to convert IPv4 numeric to binary (alows | |
40 | * classful form as a result). | 40 | * classful form as a result). | |
41 | * current code - disallow classful form for IPv4 (due to use of inet_pton). | 41 | * current code - disallow classful form for IPv4 (due to use of inet_pton). | |
42 | * - freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is | 42 | * - freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is | |
43 | * invalid. | 43 | * invalid. | |
44 | * current code - SEGV on freeaddrinfo(NULL) | 44 | * current code - SEGV on freeaddrinfo(NULL) | |
45 | * Note: | 45 | * Note: | |
46 | * - The code filters out AFs that are not supported by the kernel, | 46 | * - The code filters out AFs that are not supported by the kernel, | |
47 | * when globbing NULL hostname (to loopback, or wildcard). Is it the right | 47 | * when globbing NULL hostname (to loopback, or wildcard). Is it the right | |
48 | * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG | 48 | * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG | |
49 | * in ai_flags? | 49 | * in ai_flags? | |
50 | * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague. | 50 | * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague. | |
51 | * (1) what should we do against numeric hostname (2) what should we do | 51 | * (1) what should we do against numeric hostname (2) what should we do | |
52 | * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready? | 52 | * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready? | |
53 | * non-loopback address configured? global address configured? | 53 | * non-loopback address configured? global address configured? | |
54 | */ | 54 | */ | |
55 | 55 | |||
56 | #include <sys/cdefs.h> | 56 | #include <sys/cdefs.h> | |
57 | #if defined(LIBC_SCCS) && !defined(lint) | 57 | #if defined(LIBC_SCCS) && !defined(lint) | |
58 | __RCSID("$NetBSD: getaddrinfo.c,v 1.93 2009/10/02 02:45:29 tsarna Exp $"); | 58 | __RCSID("$NetBSD: getaddrinfo.c,v 1.94 2009/10/02 06:49:23 cegger Exp $"); | |
59 | #endif /* LIBC_SCCS and not lint */ | 59 | #endif /* LIBC_SCCS and not lint */ | |
60 | 60 | |||
61 | #include "namespace.h" | 61 | #include "namespace.h" | |
62 | #include <sys/types.h> | 62 | #include <sys/types.h> | |
63 | #include <sys/param.h> | 63 | #include <sys/param.h> | |
64 | #include <sys/socket.h> | 64 | #include <sys/socket.h> | |
65 | #include <net/if.h> | 65 | #include <net/if.h> | |
66 | #include <netinet/in.h> | 66 | #include <netinet/in.h> | |
67 | #include <arpa/inet.h> | 67 | #include <arpa/inet.h> | |
68 | #include <arpa/nameser.h> | 68 | #include <arpa/nameser.h> | |
69 | #include <assert.h> | 69 | #include <assert.h> | |
70 | #include <ctype.h> | 70 | #include <ctype.h> | |
71 | #include <errno.h> | 71 | #include <errno.h> | |
72 | #include <netdb.h> | 72 | #include <netdb.h> | |
73 | #include <resolv.h> | 73 | #include <resolv.h> | |
74 | #include <stddef.h> | 74 | #include <stddef.h> | |
75 | #include <stdio.h> | 75 | #include <stdio.h> | |
76 | #include <stdlib.h> | 76 | #include <stdlib.h> | |
77 | #include <string.h> | 77 | #include <string.h> | |
78 | #include <unistd.h> | 78 | #include <unistd.h> | |
79 | 79 | |||
80 | #include <syslog.h> | 80 | #include <syslog.h> | |
81 | #include <stdarg.h> | 81 | #include <stdarg.h> | |
82 | #include <nsswitch.h> | 82 | #include <nsswitch.h> | |
83 | 83 | |||
84 | #ifdef YP | 84 | #ifdef YP | |
85 | #include <rpc/rpc.h> | 85 | #include <rpc/rpc.h> | |
86 | #include <rpcsvc/yp_prot.h> | 86 | #include <rpcsvc/yp_prot.h> | |
87 | #include <rpcsvc/ypclnt.h> | 87 | #include <rpcsvc/ypclnt.h> | |
88 | #endif | 88 | #endif | |
89 | 89 | |||
90 | #include "servent.h" | 90 | #include "servent.h" | |
91 | 91 | |||
92 | #ifdef __weak_alias | 92 | #ifdef __weak_alias | |
93 | __weak_alias(getaddrinfo,_getaddrinfo) | 93 | __weak_alias(getaddrinfo,_getaddrinfo) | |
94 | __weak_alias(freeaddrinfo,_freeaddrinfo) | 94 | __weak_alias(freeaddrinfo,_freeaddrinfo) | |
95 | __weak_alias(gai_strerror,_gai_strerror) | 95 | __weak_alias(gai_strerror,_gai_strerror) | |
96 | #endif | 96 | #endif | |
97 | 97 | |||
98 | #define SUCCESS 0 | 98 | #define SUCCESS 0 | |
99 | #define ANY 0 | 99 | #define ANY 0 | |
100 | #define YES 1 | 100 | #define YES 1 | |
101 | #define NO 0 | 101 | #define NO 0 | |
102 | 102 | |||
103 | static const char in_addrany[] = { 0, 0, 0, 0 }; | 103 | static const char in_addrany[] = { 0, 0, 0, 0 }; | |
104 | static const char in_loopback[] = { 127, 0, 0, 1 }; | 104 | static const char in_loopback[] = { 127, 0, 0, 1 }; | |
105 | #ifdef INET6 | 105 | #ifdef INET6 | |
106 | static const char in6_addrany[] = { | 106 | static const char in6_addrany[] = { | |
107 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | 107 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | |
108 | }; | 108 | }; | |
109 | static const char in6_loopback[] = { | 109 | static const char in6_loopback[] = { | |
110 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 | 110 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 | |
111 | }; | 111 | }; | |
112 | #endif | 112 | #endif | |
113 | 113 | |||
114 | static const struct afd { | 114 | static const struct afd { | |
115 | int a_af; | 115 | int a_af; | |
116 | int a_addrlen; | 116 | int a_addrlen; | |
117 | int a_socklen; | 117 | int a_socklen; | |
118 | int a_off; | 118 | int a_off; | |
119 | const char *a_addrany; | 119 | const char *a_addrany; | |
120 | const char *a_loopback; | 120 | const char *a_loopback; | |
121 | int a_scoped; | 121 | int a_scoped; | |
122 | } afdl [] = { | 122 | } afdl [] = { | |
123 | #ifdef INET6 | 123 | #ifdef INET6 | |
124 | {PF_INET6, sizeof(struct in6_addr), | 124 | {PF_INET6, sizeof(struct in6_addr), | |
125 | sizeof(struct sockaddr_in6), | 125 | sizeof(struct sockaddr_in6), | |
126 | offsetof(struct sockaddr_in6, sin6_addr), | 126 | offsetof(struct sockaddr_in6, sin6_addr), | |
127 | in6_addrany, in6_loopback, 1}, | 127 | in6_addrany, in6_loopback, 1}, | |
128 | #endif | 128 | #endif | |
129 | {PF_INET, sizeof(struct in_addr), | 129 | {PF_INET, sizeof(struct in_addr), | |
130 | sizeof(struct sockaddr_in), | 130 | sizeof(struct sockaddr_in), | |
131 | offsetof(struct sockaddr_in, sin_addr), | 131 | offsetof(struct sockaddr_in, sin_addr), | |
132 | in_addrany, in_loopback, 0}, | 132 | in_addrany, in_loopback, 0}, | |
133 | {0, 0, 0, 0, NULL, NULL, 0}, | 133 | {0, 0, 0, 0, NULL, NULL, 0}, | |
134 | }; | 134 | }; | |
135 | 135 | |||
136 | struct explore { | 136 | struct explore { | |
137 | int e_af; | 137 | int e_af; | |
138 | int e_socktype; | 138 | int e_socktype; | |
139 | int e_protocol; | 139 | int e_protocol; | |
140 | const char *e_protostr; | 140 | const char *e_protostr; | |
141 | int e_wild; | 141 | int e_wild; | |
142 | #define WILD_AF(ex) ((ex)->e_wild & 0x01) | 142 | #define WILD_AF(ex) ((ex)->e_wild & 0x01) | |
143 | #define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02) | 143 | #define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02) | |
144 | #define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04) | 144 | #define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04) | |
145 | }; | 145 | }; | |
146 | 146 | |||
147 | static const struct explore explore[] = { | 147 | static const struct explore explore[] = { | |
148 | #if 0 | 148 | #if 0 | |
149 | { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 }, | 149 | { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 }, | |
150 | #endif | 150 | #endif | |
151 | #ifdef INET6 | 151 | #ifdef INET6 | |
152 | { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, | 152 | { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, | |
153 | { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, | 153 | { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, | |
154 | { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 }, | 154 | { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 }, | |
155 | #endif | 155 | #endif | |
156 | { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, | 156 | { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, | |
157 | { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, | 157 | { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, | |
158 | { PF_INET, SOCK_RAW, ANY, NULL, 0x05 }, | 158 | { PF_INET, SOCK_RAW, ANY, NULL, 0x05 }, | |
159 | { PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, | 159 | { PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, | |
160 | { PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, | 160 | { PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, | |
161 | { PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 }, | 161 | { PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 }, | |
162 | { -1, 0, 0, NULL, 0 }, | 162 | { -1, 0, 0, NULL, 0 }, | |
163 | }; | 163 | }; | |
164 | 164 | |||
165 | #ifdef INET6 | 165 | #ifdef INET6 | |
166 | #define PTON_MAX 16 | 166 | #define PTON_MAX 16 | |
167 | #else | 167 | #else | |
168 | #define PTON_MAX 4 | 168 | #define PTON_MAX 4 | |
169 | #endif | 169 | #endif | |
170 | 170 | |||
171 | static const ns_src default_dns_files[] = { | 171 | static const ns_src default_dns_files[] = { | |
172 | { NSSRC_FILES, NS_SUCCESS }, | 172 | { NSSRC_FILES, NS_SUCCESS }, | |
173 | { NSSRC_DNS, NS_SUCCESS }, | 173 | { NSSRC_DNS, NS_SUCCESS }, | |
174 | { 0, 0 } | 174 | { 0, 0 } | |
175 | }; | 175 | }; | |
176 | 176 | |||
177 | #define MAXPACKET (64*1024) | 177 | #define MAXPACKET (64*1024) | |
178 | 178 | |||
179 | typedef union { | 179 | typedef union { | |
180 | HEADER hdr; | 180 | HEADER hdr; | |
181 | u_char buf[MAXPACKET]; | 181 | u_char buf[MAXPACKET]; | |
182 | } querybuf; | 182 | } querybuf; | |
183 | 183 | |||
184 | struct res_target { | 184 | struct res_target { | |
185 | struct res_target *next; | 185 | struct res_target *next; | |
186 | const char *name; /* domain name */ | 186 | const char *name; /* domain name */ | |
187 | int qclass, qtype; /* class and type of query */ | 187 | int qclass, qtype; /* class and type of query */ | |
188 | u_char *answer; /* buffer to put answer */ | 188 | u_char *answer; /* buffer to put answer */ | |
189 | int anslen; /* size of answer buffer */ | 189 | int anslen; /* size of answer buffer */ | |
190 | int n; /* result length */ | 190 | int n; /* result length */ | |
191 | }; | 191 | }; | |
192 | 192 | |||
193 | static int str2number(const char *); | 193 | static int str2number(const char *); | |
194 | static int explore_fqdn(const struct addrinfo *, const char *, | 194 | static int explore_fqdn(const struct addrinfo *, const char *, | |
195 | const char *, struct addrinfo **, struct servent_data *); | 195 | const char *, struct addrinfo **, struct servent_data *); | |
196 | static int explore_null(const struct addrinfo *, | 196 | static int explore_null(const struct addrinfo *, | |
197 | const char *, struct addrinfo **, struct servent_data *); | 197 | const char *, struct addrinfo **, struct servent_data *); | |
198 | static int explore_numeric(const struct addrinfo *, const char *, | 198 | static int explore_numeric(const struct addrinfo *, const char *, | |
199 | const char *, struct addrinfo **, const char *, struct servent_data *); | 199 | const char *, struct addrinfo **, const char *, struct servent_data *); | |
200 | static int explore_numeric_scope(const struct addrinfo *, const char *, | 200 | static int explore_numeric_scope(const struct addrinfo *, const char *, | |
201 | const char *, struct addrinfo **, struct servent_data *); | 201 | const char *, struct addrinfo **, struct servent_data *); | |
202 | static int get_canonname(const struct addrinfo *, | 202 | static int get_canonname(const struct addrinfo *, | |
203 | struct addrinfo *, const char *); | 203 | struct addrinfo *, const char *); | |
204 | static struct addrinfo *get_ai(const struct addrinfo *, | 204 | static struct addrinfo *get_ai(const struct addrinfo *, | |
205 | const struct afd *, const char *); | 205 | const struct afd *, const char *); | |
206 | static int get_portmatch(const struct addrinfo *, const char *, | 206 | static int get_portmatch(const struct addrinfo *, const char *, | |
207 | struct servent_data *); | 207 | struct servent_data *); | |
208 | static int get_port(const struct addrinfo *, const char *, int, | 208 | static int get_port(const struct addrinfo *, const char *, int, | |
209 | struct servent_data *); | 209 | struct servent_data *); | |
210 | static const struct afd *find_afd(int); | 210 | static const struct afd *find_afd(int); | |
211 | #ifdef INET6 | 211 | #ifdef INET6 | |
212 | static int ip6_str2scopeid(char *, struct sockaddr_in6 *, u_int32_t *); | 212 | static int ip6_str2scopeid(char *, struct sockaddr_in6 *, u_int32_t *); | |
213 | #endif | 213 | #endif | |
214 | 214 | |||
215 | static struct addrinfo *getanswer(const querybuf *, int, const char *, int, | 215 | static struct addrinfo *getanswer(const querybuf *, int, const char *, int, | |
216 | const struct addrinfo *); | 216 | const struct addrinfo *); | |
217 | static void aisort(struct addrinfo *s, res_state res); | 217 | static void aisort(struct addrinfo *s, res_state res); | |
218 | static int _dns_getaddrinfo(void *, void *, va_list); | 218 | static int _dns_getaddrinfo(void *, void *, va_list); | |
219 | static void _sethtent(FILE **); | 219 | static void _sethtent(FILE **); | |
220 | static void _endhtent(FILE **); | 220 | static void _endhtent(FILE **); | |
221 | static struct addrinfo *_gethtent(FILE **, const char *, | 221 | static struct addrinfo *_gethtent(FILE **, const char *, | |
222 | const struct addrinfo *); | 222 | const struct addrinfo *); | |
223 | static int _files_getaddrinfo(void *, void *, va_list); | 223 | static int _files_getaddrinfo(void *, void *, va_list); | |
224 | #ifdef YP | 224 | #ifdef YP | |
225 | static struct addrinfo *_yphostent(char *, const struct addrinfo *); | 225 | static struct addrinfo *_yphostent(char *, const struct addrinfo *); | |
226 | static int _yp_getaddrinfo(void *, void *, va_list); | 226 | static int _yp_getaddrinfo(void *, void *, va_list); | |
227 | #endif | 227 | #endif | |
228 | 228 | |||
229 | static int res_queryN(const char *, struct res_target *, res_state); | 229 | static int res_queryN(const char *, struct res_target *, res_state); | |
230 | static int res_searchN(const char *, struct res_target *, res_state); | 230 | static int res_searchN(const char *, struct res_target *, res_state); | |
231 | static int res_querydomainN(const char *, const char *, | 231 | static int res_querydomainN(const char *, const char *, | |
232 | struct res_target *, res_state); | 232 | struct res_target *, res_state); | |
233 | 233 | |||
234 | static const char * const ai_errlist[] = { | 234 | static const char * const ai_errlist[] = { | |
235 | "Success", | 235 | "Success", | |
236 | "Address family for hostname not supported", /* EAI_ADDRFAMILY */ | 236 | "Address family for hostname not supported", /* EAI_ADDRFAMILY */ | |
237 | "Temporary failure in name resolution", /* EAI_AGAIN */ | 237 | "Temporary failure in name resolution", /* EAI_AGAIN */ | |
238 | "Invalid value for ai_flags", /* EAI_BADFLAGS */ | 238 | "Invalid value for ai_flags", /* EAI_BADFLAGS */ | |
239 | "Non-recoverable failure in name resolution", /* EAI_FAIL */ | 239 | "Non-recoverable failure in name resolution", /* EAI_FAIL */ | |
240 | "ai_family not supported", /* EAI_FAMILY */ | 240 | "ai_family not supported", /* EAI_FAMILY */ | |
241 | "Memory allocation failure", /* EAI_MEMORY */ | 241 | "Memory allocation failure", /* EAI_MEMORY */ | |
242 | "No address associated with hostname", /* EAI_NODATA */ | 242 | "No address associated with hostname", /* EAI_NODATA */ | |
243 | "hostname nor servname provided, or not known", /* EAI_NONAME */ | 243 | "hostname nor servname provided, or not known", /* EAI_NONAME */ | |
244 | "servname not supported for ai_socktype", /* EAI_SERVICE */ | 244 | "servname not supported for ai_socktype", /* EAI_SERVICE */ | |
245 | "ai_socktype not supported", /* EAI_SOCKTYPE */ | 245 | "ai_socktype not supported", /* EAI_SOCKTYPE */ | |
246 | "System error returned in errno", /* EAI_SYSTEM */ | 246 | "System error returned in errno", /* EAI_SYSTEM */ | |
247 | "Invalid value for hints", /* EAI_BADHINTS */ | 247 | "Invalid value for hints", /* EAI_BADHINTS */ | |
248 | "Resolved protocol is unknown", /* EAI_PROTOCOL */ | 248 | "Resolved protocol is unknown", /* EAI_PROTOCOL */ | |
249 | "Argument buffer overflow", /* EAI_OVERFLOW */ | 249 | "Argument buffer overflow", /* EAI_OVERFLOW */ | |
250 | "Unknown error", /* EAI_MAX */ | 250 | "Unknown error", /* EAI_MAX */ | |
251 | }; | 251 | }; | |
252 | 252 | |||
253 | /* XXX macros that make external reference is BAD. */ | 253 | /* XXX macros that make external reference is BAD. */ | |
254 | 254 | |||
255 | #define GET_AI(ai, afd, addr) \ | 255 | #define GET_AI(ai, afd, addr) \ | |
256 | do { \ | 256 | do { \ | |
257 | /* external reference: pai, error, and label free */ \ | 257 | /* external reference: pai, error, and label free */ \ | |
258 | (ai) = get_ai(pai, (afd), (addr)); \ | 258 | (ai) = get_ai(pai, (afd), (addr)); \ | |
259 | if ((ai) == NULL) { \ | 259 | if ((ai) == NULL) { \ | |
260 | error = EAI_MEMORY; \ | 260 | error = EAI_MEMORY; \ | |
261 | goto free; \ | 261 | goto free; \ | |
262 | } \ | 262 | } \ | |
263 | } while (/*CONSTCOND*/0) | 263 | } while (/*CONSTCOND*/0) | |
264 | 264 | |||
265 | #define GET_PORT(ai, serv, svd) \ | 265 | #define GET_PORT(ai, serv, svd) \ | |
266 | do { \ | 266 | do { \ | |
267 | /* external reference: error and label free */ \ | 267 | /* external reference: error and label free */ \ | |
268 | error = get_port((ai), (serv), 0, (svd)); \ | 268 | error = get_port((ai), (serv), 0, (svd)); \ | |
269 | if (error != 0) \ | 269 | if (error != 0) \ | |
270 | goto free; \ | 270 | goto free; \ | |
271 | } while (/*CONSTCOND*/0) | 271 | } while (/*CONSTCOND*/0) | |
272 | 272 | |||
273 | #define GET_CANONNAME(ai, str) \ | 273 | #define GET_CANONNAME(ai, str) \ | |
274 | do { \ | 274 | do { \ | |
275 | /* external reference: pai, error and label free */ \ | 275 | /* external reference: pai, error and label free */ \ | |
276 | error = get_canonname(pai, (ai), (str)); \ | 276 | error = get_canonname(pai, (ai), (str)); \ | |
277 | if (error != 0) \ | 277 | if (error != 0) \ | |
278 | goto free; \ | 278 | goto free; \ | |
279 | } while (/*CONSTCOND*/0) | 279 | } while (/*CONSTCOND*/0) | |
280 | 280 | |||
281 | #define ERR(err) \ | 281 | #define ERR(err) \ | |
282 | do { \ | 282 | do { \ | |
283 | /* external reference: error, and label bad */ \ | 283 | /* external reference: error, and label bad */ \ | |
284 | error = (err); \ | 284 | error = (err); \ | |
285 | goto bad; \ | 285 | goto bad; \ | |
286 | /*NOTREACHED*/ \ | 286 | /*NOTREACHED*/ \ | |
287 | } while (/*CONSTCOND*/0) | 287 | } while (/*CONSTCOND*/0) | |
288 | 288 | |||
289 | #define MATCH_FAMILY(x, y, w) \ | 289 | #define MATCH_FAMILY(x, y, w) \ | |
290 | ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || \ | 290 | ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || \ | |
291 | (y) == PF_UNSPEC))) | 291 | (y) == PF_UNSPEC))) | |
292 | #define MATCH(x, y, w) \ | 292 | #define MATCH(x, y, w) \ | |
293 | ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY))) | 293 | ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY))) | |
294 | 294 | |||
295 | const char * | 295 | const char * | |
296 | gai_strerror(int ecode) | 296 | gai_strerror(int ecode) | |
297 | { | 297 | { | |
298 | if (ecode < 0 || ecode > EAI_MAX) | 298 | if (ecode < 0 || ecode > EAI_MAX) | |
299 | ecode = EAI_MAX; | 299 | ecode = EAI_MAX; | |
300 | return ai_errlist[ecode]; | 300 | return ai_errlist[ecode]; | |
301 | } | 301 | } | |
302 | 302 | |||
303 | void | 303 | void | |
304 | freeaddrinfo(struct addrinfo *ai) | 304 | freeaddrinfo(struct addrinfo *ai) | |
305 | { | 305 | { | |
306 | struct addrinfo *next; | 306 | struct addrinfo *next; | |
307 | 307 | |||
308 | _DIAGASSERT(ai != NULL); | 308 | _DIAGASSERT(ai != NULL); | |
309 | 309 | |||
310 | do { | 310 | do { | |
311 | next = ai->ai_next; | 311 | next = ai->ai_next; | |
312 | if (ai->ai_canonname) | 312 | if (ai->ai_canonname) | |
313 | free(ai->ai_canonname); | 313 | free(ai->ai_canonname); | |
314 | /* no need to free(ai->ai_addr) */ | 314 | /* no need to free(ai->ai_addr) */ | |
315 | free(ai); | 315 | free(ai); | |
316 | ai = next; | 316 | ai = next; | |
317 | } while (ai); | 317 | } while (ai); | |
318 | } | 318 | } | |
319 | 319 | |||
320 | static int | 320 | static int | |
321 | str2number(const char *p) | 321 | str2number(const char *p) | |
322 | { | 322 | { | |
323 | char *ep; | 323 | char *ep; | |
324 | unsigned long v; | 324 | unsigned long v; | |
325 | 325 | |||
326 | _DIAGASSERT(p != NULL); | 326 | _DIAGASSERT(p != NULL); | |
327 | 327 | |||
328 | if (*p == '\0') | 328 | if (*p == '\0') | |
329 | return -1; | 329 | return -1; | |
330 | ep = NULL; | 330 | ep = NULL; | |
331 | errno = 0; | 331 | errno = 0; | |
332 | v = strtoul(p, &ep, 10); | 332 | v = strtoul(p, &ep, 10); | |
333 | if (errno == 0 && ep && *ep == '\0' && v <= UINT_MAX) | 333 | if (errno == 0 && ep && *ep == '\0' && v <= UINT_MAX) | |
334 | return v; | 334 | return v; | |
335 | else | 335 | else | |
336 | return -1; | 336 | return -1; | |
337 | } | 337 | } | |
338 | 338 | |||
339 | int | 339 | int | |
340 | getaddrinfo(const char *hostname, const char *servname, | 340 | getaddrinfo(const char *hostname, const char *servname, | |
341 | const struct addrinfo *hints, struct addrinfo **res) | 341 | const struct addrinfo *hints, struct addrinfo **res) | |
342 | { | 342 | { | |
343 | struct addrinfo sentinel; | 343 | struct addrinfo sentinel; | |
344 | struct addrinfo *cur; | 344 | struct addrinfo *cur; | |
345 | int error = 0; | 345 | int error = 0; | |
346 | struct addrinfo ai; | 346 | struct addrinfo ai; | |
347 | struct addrinfo ai0; | 347 | struct addrinfo ai0; | |
348 | struct addrinfo *pai; | 348 | struct addrinfo *pai; | |
349 | const struct explore *ex; | 349 | const struct explore *ex; | |
350 | struct servent_data svd; | 350 | struct servent_data svd; | |
351 | 351 | |||
352 | /* hostname is allowed to be NULL */ | 352 | /* hostname is allowed to be NULL */ | |
353 | /* servname is allowed to be NULL */ | 353 | /* servname is allowed to be NULL */ | |
354 | /* hints is allowed to be NULL */ | 354 | /* hints is allowed to be NULL */ | |
355 | _DIAGASSERT(res != NULL); | 355 | _DIAGASSERT(res != NULL); | |
356 | 356 | |||
357 | (void)memset(&svd, 0, sizeof(svd)); | 357 | (void)memset(&svd, 0, sizeof(svd)); | |
358 | memset(&sentinel, 0, sizeof(sentinel)); | 358 | memset(&sentinel, 0, sizeof(sentinel)); | |
359 | cur = &sentinel; | 359 | cur = &sentinel; | |
360 | memset(&ai, 0, sizeof(ai)); | 360 | memset(&ai, 0, sizeof(ai)); | |
361 | pai = &ai; | 361 | pai = &ai; | |
362 | pai->ai_flags = 0; | 362 | pai->ai_flags = 0; | |
363 | pai->ai_family = PF_UNSPEC; | 363 | pai->ai_family = PF_UNSPEC; | |
364 | pai->ai_socktype = ANY; | 364 | pai->ai_socktype = ANY; | |
365 | pai->ai_protocol = ANY; | 365 | pai->ai_protocol = ANY; | |
366 | pai->ai_addrlen = 0; | 366 | pai->ai_addrlen = 0; | |
367 | pai->ai_canonname = NULL; | 367 | pai->ai_canonname = NULL; | |
368 | pai->ai_addr = NULL; | 368 | pai->ai_addr = NULL; | |
369 | pai->ai_next = NULL; | 369 | pai->ai_next = NULL; | |
370 | 370 | |||
371 | if (hostname == NULL && servname == NULL) | 371 | if (hostname == NULL && servname == NULL) | |
372 | return EAI_NONAME; | 372 | return EAI_NONAME; | |
373 | if (hints) { | 373 | if (hints) { | |
374 | /* error check for hints */ | 374 | /* error check for hints */ | |
375 | if (hints->ai_addrlen || hints->ai_canonname || | 375 | if (hints->ai_addrlen || hints->ai_canonname || | |
376 | hints->ai_addr || hints->ai_next) | 376 | hints->ai_addr || hints->ai_next) | |
377 | ERR(EAI_BADHINTS); /* xxx */ | 377 | ERR(EAI_BADHINTS); /* xxx */ | |
378 | if (hints->ai_flags & ~AI_MASK) | 378 | if (hints->ai_flags & ~AI_MASK) | |
379 | ERR(EAI_BADFLAGS); | 379 | ERR(EAI_BADFLAGS); | |
380 | switch (hints->ai_family) { | 380 | switch (hints->ai_family) { | |
381 | case PF_UNSPEC: | 381 | case PF_UNSPEC: | |
382 | case PF_INET: | 382 | case PF_INET: | |
383 | #ifdef INET6 | 383 | #ifdef INET6 | |
384 | case PF_INET6: | 384 | case PF_INET6: | |
385 | #endif | 385 | #endif | |
386 | break; | 386 | break; | |
387 | default: | 387 | default: | |
388 | ERR(EAI_FAMILY); | 388 | ERR(EAI_FAMILY); | |
389 | } | 389 | } | |
390 | memcpy(pai, hints, sizeof(*pai)); | 390 | memcpy(pai, hints, sizeof(*pai)); | |
391 | 391 | |||
392 | /* | 392 | /* | |
393 | * if both socktype/protocol are specified, check if they | 393 | * if both socktype/protocol are specified, check if they | |
394 | * are meaningful combination. | 394 | * are meaningful combination. | |
395 | */ | 395 | */ | |
396 | if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) { | 396 | if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) { | |
397 | for (ex = explore; ex->e_af >= 0; ex++) { | 397 | for (ex = explore; ex->e_af >= 0; ex++) { | |
398 | if (pai->ai_family != ex->e_af) | 398 | if (pai->ai_family != ex->e_af) | |
399 | continue; | 399 | continue; | |
400 | if (ex->e_socktype == ANY) | 400 | if (ex->e_socktype == ANY) | |
401 | continue; | 401 | continue; | |
402 | if (ex->e_protocol == ANY) | 402 | if (ex->e_protocol == ANY) | |
403 | continue; | 403 | continue; | |
404 | if (pai->ai_socktype == ex->e_socktype | 404 | if (pai->ai_socktype == ex->e_socktype | |
405 | && pai->ai_protocol != ex->e_protocol) { | 405 | && pai->ai_protocol != ex->e_protocol) { | |
406 | ERR(EAI_BADHINTS); | 406 | ERR(EAI_BADHINTS); | |
407 | } | 407 | } | |
408 | } | 408 | } | |
409 | } | 409 | } | |
410 | } | 410 | } | |
411 | 411 | |||
412 | /* | 412 | /* | |
413 | * check for special cases. (1) numeric servname is disallowed if | 413 | * check for special cases. (1) numeric servname is disallowed if | |
414 | * socktype/protocol are left unspecified. (2) servname is disallowed | 414 | * socktype/protocol are left unspecified. (2) servname is disallowed | |
415 | * for raw and other inet{,6} sockets. | 415 | * for raw and other inet{,6} sockets. | |
416 | */ | 416 | */ | |
417 | if (MATCH_FAMILY(pai->ai_family, PF_INET, 1) | 417 | if (MATCH_FAMILY(pai->ai_family, PF_INET, 1) | |
418 | #ifdef PF_INET6 | 418 | #ifdef PF_INET6 | |
419 | || MATCH_FAMILY(pai->ai_family, PF_INET6, 1) | 419 | || MATCH_FAMILY(pai->ai_family, PF_INET6, 1) | |
420 | #endif | 420 | #endif | |
421 | ) { | 421 | ) { | |
422 | ai0 = *pai; /* backup *pai */ | 422 | ai0 = *pai; /* backup *pai */ | |
423 | 423 | |||
424 | if (pai->ai_family == PF_UNSPEC) { | 424 | if (pai->ai_family == PF_UNSPEC) { | |
425 | #ifdef PF_INET6 | 425 | #ifdef PF_INET6 | |
426 | pai->ai_family = PF_INET6; | 426 | pai->ai_family = PF_INET6; | |
427 | #else | 427 | #else | |
428 | pai->ai_family = PF_INET; | 428 | pai->ai_family = PF_INET; | |
429 | #endif | 429 | #endif | |
430 | } | 430 | } | |
431 | error = get_portmatch(pai, servname, &svd); | 431 | error = get_portmatch(pai, servname, &svd); | |
432 | if (error) | 432 | if (error) | |
433 | ERR(error); | 433 | ERR(error); | |
434 | 434 | |||
435 | *pai = ai0; | 435 | *pai = ai0; | |
436 | } | 436 | } | |
437 | 437 | |||
438 | ai0 = *pai; | 438 | ai0 = *pai; | |
439 | 439 | |||
440 | /* NULL hostname, or numeric hostname */ | 440 | /* NULL hostname, or numeric hostname */ | |
441 | for (ex = explore; ex->e_af >= 0; ex++) { | 441 | for (ex = explore; ex->e_af >= 0; ex++) { | |
442 | *pai = ai0; | 442 | *pai = ai0; | |
443 | 443 | |||
444 | /* PF_UNSPEC entries are prepared for DNS queries only */ | 444 | /* PF_UNSPEC entries are prepared for DNS queries only */ | |
445 | if (ex->e_af == PF_UNSPEC) | 445 | if (ex->e_af == PF_UNSPEC) | |
446 | continue; | 446 | continue; | |
447 | 447 | |||
448 | if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) | 448 | if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) | |
449 | continue; | 449 | continue; | |
450 | if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) | 450 | if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) | |
451 | continue; | 451 | continue; | |
452 | if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex))) | 452 | if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex))) | |
453 | continue; | 453 | continue; | |
454 | 454 | |||
455 | if (pai->ai_family == PF_UNSPEC) | 455 | if (pai->ai_family == PF_UNSPEC) | |
456 | pai->ai_family = ex->e_af; | 456 | pai->ai_family = ex->e_af; | |
457 | if (pai->ai_socktype == ANY && ex->e_socktype != ANY) | 457 | if (pai->ai_socktype == ANY && ex->e_socktype != ANY) | |
458 | pai->ai_socktype = ex->e_socktype; | 458 | pai->ai_socktype = ex->e_socktype; | |
459 | if (pai->ai_protocol == ANY && ex->e_protocol != ANY) | 459 | if (pai->ai_protocol == ANY && ex->e_protocol != ANY) | |
460 | pai->ai_protocol = ex->e_protocol; | 460 | pai->ai_protocol = ex->e_protocol; | |
461 | 461 | |||
462 | if (hostname == NULL) | 462 | if (hostname == NULL) | |
463 | error = explore_null(pai, servname, &cur->ai_next, | 463 | error = explore_null(pai, servname, &cur->ai_next, | |
464 | &svd); | 464 | &svd); | |
465 | else | 465 | else | |
466 | error = explore_numeric_scope(pai, hostname, servname, | 466 | error = explore_numeric_scope(pai, hostname, servname, | |
467 | &cur->ai_next, &svd); | 467 | &cur->ai_next, &svd); | |
468 | 468 | |||
469 | if (error) | 469 | if (error) | |
470 | goto free; | 470 | goto free; | |
471 | 471 | |||
472 | while (cur->ai_next) | 472 | while (cur->ai_next) | |
473 | cur = cur->ai_next; | 473 | cur = cur->ai_next; | |
474 | } | 474 | } | |
475 | 475 | |||
476 | /* | 476 | /* | |
477 | * XXX | 477 | * XXX | |
478 | * If numeric representation of AF1 can be interpreted as FQDN | 478 | * If numeric representation of AF1 can be interpreted as FQDN | |
479 | * representation of AF2, we need to think again about the code below. | 479 | * representation of AF2, we need to think again about the code below. | |
480 | */ | 480 | */ | |
481 | if (sentinel.ai_next) | 481 | if (sentinel.ai_next) | |
482 | goto good; | 482 | goto good; | |
483 | 483 | |||
484 | if (hostname == NULL) | 484 | if (hostname == NULL) | |
485 | ERR(EAI_NODATA); | 485 | ERR(EAI_NODATA); | |
486 | if (pai->ai_flags & AI_NUMERICHOST) | 486 | if (pai->ai_flags & AI_NUMERICHOST) | |
487 | ERR(EAI_NONAME); | 487 | ERR(EAI_NONAME); | |
488 | 488 | |||
489 | /* | 489 | /* | |
490 | * hostname as alphabetical name. | 490 | * hostname as alphabetical name. | |
491 | * we would like to prefer AF_INET6 than AF_INET, so we'll make a | 491 | * we would like to prefer AF_INET6 than AF_INET, so we'll make a | |
492 | * outer loop by AFs. | 492 | * outer loop by AFs. | |
493 | */ | 493 | */ | |
494 | for (ex = explore; ex->e_af >= 0; ex++) { | 494 | for (ex = explore; ex->e_af >= 0; ex++) { | |
495 | *pai = ai0; | 495 | *pai = ai0; | |
496 | 496 | |||
497 | /* require exact match for family field */ | 497 | /* require exact match for family field */ | |
498 | if (pai->ai_family != ex->e_af) | 498 | if (pai->ai_family != ex->e_af) | |
499 | continue; | 499 | continue; | |
500 | 500 | |||
501 | if (!MATCH(pai->ai_socktype, ex->e_socktype, | 501 | if (!MATCH(pai->ai_socktype, ex->e_socktype, | |
502 | WILD_SOCKTYPE(ex))) { | 502 | WILD_SOCKTYPE(ex))) { | |
503 | continue; | 503 | continue; | |
504 | } | 504 | } | |
505 | if (!MATCH(pai->ai_protocol, ex->e_protocol, | 505 | if (!MATCH(pai->ai_protocol, ex->e_protocol, | |
506 | WILD_PROTOCOL(ex))) { | 506 | WILD_PROTOCOL(ex))) { | |
507 | continue; | 507 | continue; | |
508 | } | 508 | } | |
509 | 509 | |||
510 | if (pai->ai_socktype == ANY && ex->e_socktype != ANY) | 510 | if (pai->ai_socktype == ANY && ex->e_socktype != ANY) | |
511 | pai->ai_socktype = ex->e_socktype; | 511 | pai->ai_socktype = ex->e_socktype; | |
512 | if (pai->ai_protocol == ANY && ex->e_protocol != ANY) | 512 | if (pai->ai_protocol == ANY && ex->e_protocol != ANY) | |
513 | pai->ai_protocol = ex->e_protocol; | 513 | pai->ai_protocol = ex->e_protocol; | |
514 | 514 | |||
515 | error = explore_fqdn(pai, hostname, servname, &cur->ai_next, | 515 | error = explore_fqdn(pai, hostname, servname, &cur->ai_next, | |
516 | &svd); | 516 | &svd); | |
517 | 517 | |||
518 | while (cur && cur->ai_next) | 518 | while (cur && cur->ai_next) | |
519 | cur = cur->ai_next; | 519 | cur = cur->ai_next; | |
520 | } | 520 | } | |
521 | 521 | |||
522 | /* XXX */ | 522 | /* XXX */ | |
523 | if (sentinel.ai_next) | 523 | if (sentinel.ai_next) | |
524 | error = 0; | 524 | error = 0; | |
525 | 525 | |||
526 | if (error) | 526 | if (error) | |
527 | goto free; | 527 | goto free; | |
528 | 528 | |||
529 | if (sentinel.ai_next) { | 529 | if (sentinel.ai_next) { | |
530 | good: | 530 | good: | |
531 | endservent_r(&svd); | 531 | endservent_r(&svd); | |
532 | *res = sentinel.ai_next; | 532 | *res = sentinel.ai_next; | |
533 | return SUCCESS; | 533 | return SUCCESS; | |
534 | } else | 534 | } else | |
535 | error = EAI_FAIL; | 535 | error = EAI_FAIL; | |
536 | free: | 536 | free: | |
537 | bad: | 537 | bad: | |
538 | endservent_r(&svd); | 538 | endservent_r(&svd); | |
539 | if (sentinel.ai_next) | 539 | if (sentinel.ai_next) | |
540 | freeaddrinfo(sentinel.ai_next); | 540 | freeaddrinfo(sentinel.ai_next); | |
541 | *res = NULL; | 541 | *res = NULL; | |
542 | return error; | 542 | return error; | |
543 | } | 543 | } | |
544 | 544 | |||
545 | /* | 545 | /* | |
546 | * FQDN hostname, DNS lookup | 546 | * FQDN hostname, DNS lookup | |
547 | */ | 547 | */ | |
548 | static int | 548 | static int | |
549 | explore_fqdn(const struct addrinfo *pai, const char *hostname, | 549 | explore_fqdn(const struct addrinfo *pai, const char *hostname, | |
550 | const char *servname, struct addrinfo **res, struct servent_data *svd) | 550 | const char *servname, struct addrinfo **res, struct servent_data *svd) | |
551 | { | 551 | { | |
552 | struct addrinfo *result; | 552 | struct addrinfo *result; | |
553 | struct addrinfo *cur; | 553 | struct addrinfo *cur; | |
554 | int error = 0; | 554 | int error = 0; | |
555 | static const ns_dtab dtab[] = { | 555 | static const ns_dtab dtab[] = { | |
556 | NS_FILES_CB(_files_getaddrinfo, NULL) | 556 | NS_FILES_CB(_files_getaddrinfo, NULL) | |
557 | { NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */ | 557 | { NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */ | |
558 | NS_NIS_CB(_yp_getaddrinfo, NULL) | 558 | NS_NIS_CB(_yp_getaddrinfo, NULL) | |
559 | NS_NULL_CB | 559 | NS_NULL_CB | |
560 | }; | 560 | }; | |
561 | 561 | |||
562 | _DIAGASSERT(pai != NULL); | 562 | _DIAGASSERT(pai != NULL); | |
563 | /* hostname may be NULL */ | 563 | /* hostname may be NULL */ | |
564 | /* servname may be NULL */ | 564 | /* servname may be NULL */ | |
565 | _DIAGASSERT(res != NULL); | 565 | _DIAGASSERT(res != NULL); | |
566 | 566 | |||
567 | result = NULL; | 567 | result = NULL; | |
568 | 568 | |||
569 | /* | 569 | /* | |
570 | * if the servname does not match socktype/protocol, ignore it. | 570 | * if the servname does not match socktype/protocol, ignore it. | |
571 | */ | 571 | */ | |
572 | if (get_portmatch(pai, servname, svd) != 0) | 572 | if (get_portmatch(pai, servname, svd) != 0) | |
573 | return 0; | 573 | return 0; | |
574 | 574 | |||
575 | switch (nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo", | 575 | switch (nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo", | |
576 | default_dns_files, hostname, pai)) { | 576 | default_dns_files, hostname, pai)) { | |
577 | case NS_TRYAGAIN: | 577 | case NS_TRYAGAIN: | |
578 | error = EAI_AGAIN; | 578 | error = EAI_AGAIN; | |
579 | goto free; | 579 | goto free; | |
580 | case NS_UNAVAIL: | 580 | case NS_UNAVAIL: | |
581 | error = EAI_FAIL; | 581 | error = EAI_FAIL; | |
582 | goto free; | 582 | goto free; | |
583 | case NS_NOTFOUND: | 583 | case NS_NOTFOUND: | |
584 | error = EAI_NODATA; | 584 | error = EAI_NODATA; | |
585 | goto free; | 585 | goto free; | |
586 | case NS_SUCCESS: | 586 | case NS_SUCCESS: | |
587 | error = 0; | 587 | error = 0; | |
588 | for (cur = result; cur; cur = cur->ai_next) { | 588 | for (cur = result; cur; cur = cur->ai_next) { | |
589 | GET_PORT(cur, servname, svd); | 589 | GET_PORT(cur, servname, svd); | |
590 | /* canonname should be filled already */ | 590 | /* canonname should be filled already */ | |
591 | } | 591 | } | |
592 | break; | 592 | break; | |
593 | } | 593 | } | |
594 | 594 | |||
595 | *res = result; | 595 | *res = result; | |
596 | 596 | |||
597 | return 0; | 597 | return 0; | |
598 | 598 | |||
599 | free: | 599 | free: | |
600 | if (result) | 600 | if (result) | |
601 | freeaddrinfo(result); | 601 | freeaddrinfo(result); | |
602 | return error; | 602 | return error; | |
603 | } | 603 | } | |
604 | 604 | |||
605 | /* | 605 | /* | |
606 | * hostname == NULL. | 606 | * hostname == NULL. | |
607 | * passive socket -> anyaddr (0.0.0.0 or ::) | 607 | * passive socket -> anyaddr (0.0.0.0 or ::) | |
608 | * non-passive socket -> localhost (127.0.0.1 or ::1) | 608 | * non-passive socket -> localhost (127.0.0.1 or ::1) | |
609 | */ | 609 | */ | |
610 | static int | 610 | static int | |
611 | explore_null(const struct addrinfo *pai, const char *servname, | 611 | explore_null(const struct addrinfo *pai, const char *servname, | |
612 | struct addrinfo **res, struct servent_data *svd) | 612 | struct addrinfo **res, struct servent_data *svd) | |
613 | { | 613 | { | |
614 | int s; | 614 | int s; | |
615 | const struct afd *afd; | 615 | const struct afd *afd; | |
616 | struct addrinfo *cur; | 616 | struct addrinfo *cur; | |
617 | struct addrinfo sentinel; | 617 | struct addrinfo sentinel; | |
618 | int error; | 618 | int error; | |
619 | 619 | |||
620 | _DIAGASSERT(pai != NULL); | 620 | _DIAGASSERT(pai != NULL); | |
621 | /* servname may be NULL */ | 621 | /* servname may be NULL */ | |
622 | _DIAGASSERT(res != NULL); | 622 | _DIAGASSERT(res != NULL); | |
623 | 623 | |||
624 | *res = NULL; | 624 | *res = NULL; | |
625 | sentinel.ai_next = NULL; | 625 | sentinel.ai_next = NULL; | |
626 | cur = &sentinel; | 626 | cur = &sentinel; | |
627 | 627 | |||
628 | /* | 628 | /* | |
629 | * filter out AFs that are not supported by the kernel | 629 | * filter out AFs that are not supported by the kernel | |
630 | * XXX errno? | 630 | * XXX errno? | |
631 | */ | 631 | */ | |
632 | s = socket(pai->ai_family, SOCK_DGRAM, 0); | 632 | s = socket(pai->ai_family, SOCK_DGRAM, 0); | |
633 | if (s < 0) { | 633 | if (s < 0) { | |
634 | if (errno != EMFILE) | 634 | if (errno != EMFILE) | |
635 | return 0; | 635 | return 0; | |
636 | } else | 636 | } else | |
637 | close(s); | 637 | close(s); | |
638 | 638 | |||
639 | /* | 639 | /* | |
640 | * if the servname does not match socktype/protocol, ignore it. | 640 | * if the servname does not match socktype/protocol, ignore it. | |
641 | */ | 641 | */ | |
642 | if (get_portmatch(pai, servname, svd) != 0) | 642 | if (get_portmatch(pai, servname, svd) != 0) | |
643 | return 0; | 643 | return 0; | |
644 | 644 | |||
645 | afd = find_afd(pai->ai_family); | 645 | afd = find_afd(pai->ai_family); | |
646 | if (afd == NULL) | 646 | if (afd == NULL) | |
647 | return 0; | 647 | return 0; | |
648 | 648 | |||
649 | if (pai->ai_flags & AI_PASSIVE) { | 649 | if (pai->ai_flags & AI_PASSIVE) { | |
650 | GET_AI(cur->ai_next, afd, afd->a_addrany); | 650 | GET_AI(cur->ai_next, afd, afd->a_addrany); | |
651 | /* xxx meaningless? | 651 | /* xxx meaningless? | |
652 | * GET_CANONNAME(cur->ai_next, "anyaddr"); | 652 | * GET_CANONNAME(cur->ai_next, "anyaddr"); | |
653 | */ | 653 | */ | |
654 | GET_PORT(cur->ai_next, servname, svd); | 654 | GET_PORT(cur->ai_next, servname, svd); | |
655 | } else { | 655 | } else { | |
656 | GET_AI(cur->ai_next, afd, afd->a_loopback); | 656 | GET_AI(cur->ai_next, afd, afd->a_loopback); | |
657 | /* xxx meaningless? | 657 | /* xxx meaningless? | |
658 | * GET_CANONNAME(cur->ai_next, "localhost"); | 658 | * GET_CANONNAME(cur->ai_next, "localhost"); | |
659 | */ | 659 | */ | |
660 | GET_PORT(cur->ai_next, servname, svd); | 660 | GET_PORT(cur->ai_next, servname, svd); | |
661 | } | 661 | } | |
662 | cur = cur->ai_next; | 662 | cur = cur->ai_next; | |
663 | 663 | |||
664 | *res = sentinel.ai_next; | 664 | *res = sentinel.ai_next; | |
665 | return 0; | 665 | return 0; | |
666 | 666 | |||
667 | free: | 667 | free: | |
668 | if (sentinel.ai_next) | 668 | if (sentinel.ai_next) | |
669 | freeaddrinfo(sentinel.ai_next); | 669 | freeaddrinfo(sentinel.ai_next); | |
670 | return error; | 670 | return error; | |
671 | } | 671 | } | |
672 | 672 | |||
673 | /* | 673 | /* | |
674 | * numeric hostname | 674 | * numeric hostname | |
675 | */ | 675 | */ | |
676 | static int | 676 | static int | |
677 | explore_numeric(const struct addrinfo *pai, const char *hostname, | 677 | explore_numeric(const struct addrinfo *pai, const char *hostname, | |
678 | const char *servname, struct addrinfo **res, const char *canonname, | 678 | const char *servname, struct addrinfo **res, const char *canonname, | |
679 | struct servent_data *svd) | 679 | struct servent_data *svd) | |
680 | { | 680 | { | |
681 | const struct afd *afd; | 681 | const struct afd *afd; | |
682 | struct addrinfo *cur; | 682 | struct addrinfo *cur; | |
683 | struct addrinfo sentinel; | 683 | struct addrinfo sentinel; | |
684 | int error; | 684 | int error; | |
685 | char pton[PTON_MAX]; | 685 | char pton[PTON_MAX]; | |
686 | 686 | |||
687 | _DIAGASSERT(pai != NULL); | 687 | _DIAGASSERT(pai != NULL); | |
688 | /* hostname may be NULL */ | 688 | /* hostname may be NULL */ | |
689 | /* servname may be NULL */ | 689 | /* servname may be NULL */ | |
690 | _DIAGASSERT(res != NULL); | 690 | _DIAGASSERT(res != NULL); | |
691 | 691 | |||
692 | *res = NULL; | 692 | *res = NULL; | |
693 | sentinel.ai_next = NULL; | 693 | sentinel.ai_next = NULL; | |
694 | cur = &sentinel; | 694 | cur = &sentinel; | |
695 | 695 | |||
696 | /* | 696 | /* | |
697 | * if the servname does not match socktype/protocol, ignore it. | 697 | * if the servname does not match socktype/protocol, ignore it. | |
698 | */ | 698 | */ | |
699 | if (get_portmatch(pai, servname, svd) != 0) | 699 | if (get_portmatch(pai, servname, svd) != 0) | |
700 | return 0; | 700 | return 0; | |
701 | 701 | |||
702 | afd = find_afd(pai->ai_family); | 702 | afd = find_afd(pai->ai_family); | |
703 | if (afd == NULL) | 703 | if (afd == NULL) | |
704 | return 0; | 704 | return 0; | |
705 | 705 | |||
706 | switch (afd->a_af) { | 706 | switch (afd->a_af) { | |
707 | #if 0 /*X/Open spec*/ | 707 | #if 0 /*X/Open spec*/ | |
708 | case AF_INET: | 708 | case AF_INET: | |
709 | if (inet_aton(hostname, (struct in_addr *)pton) == 1) { | 709 | if (inet_aton(hostname, (struct in_addr *)pton) == 1) { | |
710 | if (pai->ai_family == afd->a_af || | 710 | if (pai->ai_family == afd->a_af || | |
711 | pai->ai_family == PF_UNSPEC /*?*/) { | 711 | pai->ai_family == PF_UNSPEC /*?*/) { | |
712 | GET_AI(cur->ai_next, afd, pton); | 712 | GET_AI(cur->ai_next, afd, pton); | |
713 | GET_PORT(cur->ai_next, servname, svd); | 713 | GET_PORT(cur->ai_next, servname, svd); | |
714 | if ((pai->ai_flags & AI_CANONNAME)) { | 714 | if ((pai->ai_flags & AI_CANONNAME)) { | |
715 | /* | 715 | /* | |
716 | * Set the numeric address itself as | 716 | * Set the numeric address itself as | |
717 | * the canonical name, based on a | 717 | * the canonical name, based on a | |
718 | * clarification in rfc2553bis-03. | 718 | * clarification in rfc2553bis-03. | |
719 | */ | 719 | */ | |
720 | GET_CANONNAME(cur->ai_next, canonname); | 720 | GET_CANONNAME(cur->ai_next, canonname); | |
721 | } | 721 | } | |
722 | while (cur && cur->ai_next) | 722 | while (cur && cur->ai_next) | |
723 | cur = cur->ai_next; | 723 | cur = cur->ai_next; | |
724 | } else | 724 | } else | |
725 | ERR(EAI_FAMILY); /*xxx*/ | 725 | ERR(EAI_FAMILY); /*xxx*/ | |
726 | } | 726 | } | |
727 | break; | 727 | break; | |
728 | #endif | 728 | #endif | |
729 | default: | 729 | default: | |
730 | if (inet_pton(afd->a_af, hostname, pton) == 1) { | 730 | if (inet_pton(afd->a_af, hostname, pton) == 1) { | |
731 | if (pai->ai_family == afd->a_af || | 731 | if (pai->ai_family == afd->a_af || | |
732 | pai->ai_family == PF_UNSPEC /*?*/) { | 732 | pai->ai_family == PF_UNSPEC /*?*/) { | |
733 | GET_AI(cur->ai_next, afd, pton); | 733 | GET_AI(cur->ai_next, afd, pton); | |
734 | GET_PORT(cur->ai_next, servname, svd); | 734 | GET_PORT(cur->ai_next, servname, svd); | |
735 | if ((pai->ai_flags & AI_CANONNAME)) { | 735 | if ((pai->ai_flags & AI_CANONNAME)) { | |
736 | /* | 736 | /* | |
737 | * Set the numeric address itself as | 737 | * Set the numeric address itself as | |
738 | * the canonical name, based on a | 738 | * the canonical name, based on a | |
739 | * clarification in rfc2553bis-03. | 739 | * clarification in rfc2553bis-03. | |
740 | */ | 740 | */ | |
741 | GET_CANONNAME(cur->ai_next, canonname); | 741 | GET_CANONNAME(cur->ai_next, canonname); | |
742 | } | 742 | } | |
743 | while (cur->ai_next) | 743 | while (cur->ai_next) | |
744 | cur = cur->ai_next; | 744 | cur = cur->ai_next; | |
745 | } else | 745 | } else | |
746 | ERR(EAI_FAMILY); /*xxx*/ | 746 | ERR(EAI_FAMILY); /*xxx*/ | |
747 | } | 747 | } | |
748 | break; | 748 | break; | |
749 | } | 749 | } | |
750 | 750 | |||
751 | *res = sentinel.ai_next; | 751 | *res = sentinel.ai_next; | |
752 | return 0; | 752 | return 0; | |
753 | 753 | |||
754 | free: | 754 | free: | |
755 | bad: | 755 | bad: | |
756 | if (sentinel.ai_next) | 756 | if (sentinel.ai_next) | |
757 | freeaddrinfo(sentinel.ai_next); | 757 | freeaddrinfo(sentinel.ai_next); | |
758 | return error; | 758 | return error; | |
759 | } | 759 | } | |
760 | 760 | |||
761 | /* | 761 | /* | |
762 | * numeric hostname with scope | 762 | * numeric hostname with scope | |
763 | */ | 763 | */ | |
764 | static int | 764 | static int | |
765 | explore_numeric_scope(const struct addrinfo *pai, const char *hostname, | 765 | explore_numeric_scope(const struct addrinfo *pai, const char *hostname, | |
766 | const char *servname, struct addrinfo **res, struct servent_data *svd) | 766 | const char *servname, struct addrinfo **res, struct servent_data *svd) | |
767 | { | 767 | { | |
768 | #if !defined(SCOPE_DELIMITER) || !defined(INET6) | 768 | #if !defined(SCOPE_DELIMITER) || !defined(INET6) | |
769 | return explore_numeric(pai, hostname, servname, res, hostname, svd); | 769 | return explore_numeric(pai, hostname, servname, res, hostname, svd); | |
770 | #else | 770 | #else | |
771 | const struct afd *afd; | 771 | const struct afd *afd; | |
772 | struct addrinfo *cur; | 772 | struct addrinfo *cur; | |
773 | int error; | 773 | int error; | |
774 | char *cp, *hostname2 = NULL, *scope, *addr; | 774 | char *cp, *hostname2 = NULL, *scope, *addr; | |
775 | struct sockaddr_in6 *sin6; | 775 | struct sockaddr_in6 *sin6; | |
776 | 776 | |||
777 | _DIAGASSERT(pai != NULL); | 777 | _DIAGASSERT(pai != NULL); | |
778 | /* hostname may be NULL */ | 778 | /* hostname may be NULL */ | |
779 | /* servname may be NULL */ | 779 | /* servname may be NULL */ | |
780 | _DIAGASSERT(res != NULL); | 780 | _DIAGASSERT(res != NULL); | |
781 | 781 | |||
782 | /* | 782 | /* | |
783 | * if the servname does not match socktype/protocol, ignore it. | 783 | * if the servname does not match socktype/protocol, ignore it. | |
784 | */ | 784 | */ | |
785 | if (get_portmatch(pai, servname, svd) != 0) | 785 | if (get_portmatch(pai, servname, svd) != 0) | |
786 | return 0; | 786 | return 0; | |
787 | 787 | |||
788 | afd = find_afd(pai->ai_family); | 788 | afd = find_afd(pai->ai_family); | |
789 | if (afd == NULL) | 789 | if (afd == NULL) | |
790 | return 0; | 790 | return 0; | |
791 | 791 | |||
792 | if (!afd->a_scoped) | 792 | if (!afd->a_scoped) | |
793 | return explore_numeric(pai, hostname, servname, res, hostname, | 793 | return explore_numeric(pai, hostname, servname, res, hostname, | |
794 | svd); | 794 | svd); | |
795 | 795 | |||
796 | cp = strchr(hostname, SCOPE_DELIMITER); | 796 | cp = strchr(hostname, SCOPE_DELIMITER); | |
797 | if (cp == NULL) | 797 | if (cp == NULL) | |
798 | return explore_numeric(pai, hostname, servname, res, hostname, | 798 | return explore_numeric(pai, hostname, servname, res, hostname, | |
799 | svd); | 799 | svd); | |
800 | 800 | |||
801 | /* | 801 | /* | |
802 | * Handle special case of <scoped_address><delimiter><scope id> | 802 | * Handle special case of <scoped_address><delimiter><scope id> | |
803 | */ | 803 | */ | |
804 | hostname2 = strdup(hostname); | 804 | hostname2 = strdup(hostname); | |
805 | if (hostname2 == NULL) | 805 | if (hostname2 == NULL) | |
806 | return EAI_MEMORY; | 806 | return EAI_MEMORY; | |
807 | /* terminate at the delimiter */ | 807 | /* terminate at the delimiter */ | |
808 | hostname2[cp - hostname] = '\0'; | 808 | hostname2[cp - hostname] = '\0'; | |
809 | addr = hostname2; | 809 | addr = hostname2; | |
810 | scope = cp + 1; | 810 | scope = cp + 1; | |
811 | 811 | |||
812 | error = explore_numeric(pai, addr, servname, res, hostname, svd); | 812 | error = explore_numeric(pai, addr, servname, res, hostname, svd); | |
813 | if (error == 0) { | 813 | if (error == 0) { | |
814 | u_int32_t scopeid; | 814 | u_int32_t scopeid; | |
815 | 815 | |||
816 | for (cur = *res; cur; cur = cur->ai_next) { | 816 | for (cur = *res; cur; cur = cur->ai_next) { | |
817 | if (cur->ai_family != AF_INET6) | 817 | if (cur->ai_family != AF_INET6) | |
818 | continue; | 818 | continue; | |
819 | sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr; | 819 | sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr; | |
820 | if (ip6_str2scopeid(scope, sin6, &scopeid) == -1) { | 820 | if (ip6_str2scopeid(scope, sin6, &scopeid) == -1) { | |
821 | free(hostname2); | 821 | free(hostname2); | |
822 | return(EAI_NODATA); /* XXX: is return OK? */ | 822 | return(EAI_NODATA); /* XXX: is return OK? */ | |
823 | } | 823 | } | |
824 | sin6->sin6_scope_id = scopeid; | 824 | sin6->sin6_scope_id = scopeid; | |
825 | } | 825 | } | |
826 | } | 826 | } | |
827 | 827 | |||
828 | free(hostname2); | 828 | free(hostname2); | |
829 | 829 | |||
830 | return error; | 830 | return error; | |
831 | #endif | 831 | #endif | |
832 | } | 832 | } | |
833 | 833 | |||
834 | static int | 834 | static int | |
835 | get_canonname(const struct addrinfo *pai, struct addrinfo *ai, const char *str) | 835 | get_canonname(const struct addrinfo *pai, struct addrinfo *ai, const char *str) | |
836 | { | 836 | { | |
837 | 837 | |||
838 | _DIAGASSERT(pai != NULL); | 838 | _DIAGASSERT(pai != NULL); | |
839 | _DIAGASSERT(ai != NULL); | 839 | _DIAGASSERT(ai != NULL); | |
840 | _DIAGASSERT(str != NULL); | 840 | _DIAGASSERT(str != NULL); | |
841 | 841 | |||
842 | if ((pai->ai_flags & AI_CANONNAME) != 0) { | 842 | if ((pai->ai_flags & AI_CANONNAME) != 0) { | |
843 | ai->ai_canonname = strdup(str); | 843 | ai->ai_canonname = strdup(str); | |
844 | if (ai->ai_canonname == NULL) | 844 | if (ai->ai_canonname == NULL) | |
845 | return EAI_MEMORY; | 845 | return EAI_MEMORY; | |
846 | } | 846 | } | |
847 | return 0; | 847 | return 0; | |
848 | } | 848 | } | |
849 | 849 | |||
850 | struct addrinfo * | 850 | struct addrinfo * | |
851 | allocaddrinfo(socklen_t addrlen) | 851 | allocaddrinfo(socklen_t addrlen) | |
852 | { | 852 | { | |
853 | struct addrinfo *ai; | 853 | struct addrinfo *ai; | |
854 | 854 | |||
855 | ai = calloc(sizeof(struct addrinfo) + addrlen, 1); | 855 | ai = calloc(sizeof(struct addrinfo) + addrlen, 1); | |
856 | if (ai) { | 856 | if (ai) { | |
857 | ai->ai_addr = (void *)(ai+1); | 857 | ai->ai_addr = (void *)(ai+1); | |
858 | ai->ai_addrlen = ai->ai_addr->sa_len = addrlen; | 858 | ai->ai_addrlen = ai->ai_addr->sa_len = addrlen; | |
859 | } | 859 | } | |
860 | 860 | |||
861 | return ai; | 861 | return ai; | |
862 | } | 862 | } | |
863 | 863 | |||
864 | static struct addrinfo * | 864 | static struct addrinfo * | |
865 | get_ai(const struct addrinfo *pai, const struct afd *afd, const char *addr) | 865 | get_ai(const struct addrinfo *pai, const struct afd *afd, const char *addr) | |
866 | { | 866 | { | |
867 | char *p; | 867 | char *p; | |
868 | struct addrinfo *ai; | 868 | struct addrinfo *ai; | |
869 | struct sockaddr *save; | 869 | struct sockaddr *save; | |
870 | 870 | |||
871 | _DIAGASSERT(pai != NULL); | 871 | _DIAGASSERT(pai != NULL); | |
872 | _DIAGASSERT(afd != NULL); | 872 | _DIAGASSERT(afd != NULL); | |
873 | _DIAGASSERT(addr != NULL); | 873 | _DIAGASSERT(addr != NULL); | |
874 | 874 | |||
875 | ai = allocaddrinfo((socklen_t)afd->a_socklen); | 875 | ai = allocaddrinfo((socklen_t)afd->a_socklen); | |
876 | if (ai == NULL) | 876 | if (ai == NULL) | |
877 | return NULL; | 877 | return NULL; | |
878 | 878 | |||
879 | save = ai->ai_addr; | 879 | save = ai->ai_addr; | |
880 | memcpy(ai, pai, sizeof(struct addrinfo)); | 880 | memcpy(ai, pai, sizeof(struct addrinfo)); | |
881 | 881 | |||
882 | /* since we just overwrote all of ai, we have | 882 | /* since we just overwrote all of ai, we have | |
883 | to restore ai_addr and ai_addrlen */ | 883 | to restore ai_addr and ai_addrlen */ | |
884 | ai->ai_addr = save; | 884 | ai->ai_addr = save; | |
885 | ai->ai_addrlen = (socklen_t)afd->a_socklen; | 885 | ai->ai_addrlen = (socklen_t)afd->a_socklen; | |
886 | 886 | |||
887 | ai->ai_addr->sa_family = ai->ai_family = afd->a_af; | 887 | ai->ai_addr->sa_family = ai->ai_family = afd->a_af; | |
888 | p = (char *)(void *)(ai->ai_addr); | 888 | p = (char *)(void *)(ai->ai_addr); | |
889 | memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen); | 889 | memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen); | |
890 | return ai; | 890 | return ai; | |
891 | } | 891 | } | |
892 | 892 | |||
893 | static int | 893 | static int | |
894 | get_portmatch(const struct addrinfo *ai, const char *servname, | 894 | get_portmatch(const struct addrinfo *ai, const char *servname, | |
895 | struct servent_data *svd) | 895 | struct servent_data *svd) | |
896 | { | 896 | { | |
897 | 897 | |||
898 | _DIAGASSERT(ai != NULL); | 898 | _DIAGASSERT(ai != NULL); | |
899 | /* servname may be NULL */ | 899 | /* servname may be NULL */ | |
900 | 900 | |||
901 | return get_port(ai, servname, 1, svd); | 901 | return get_port(ai, servname, 1, svd); | |
902 | } | 902 | } | |
903 | 903 | |||
904 | static int | 904 | static int | |
905 | get_port(const struct addrinfo *ai, const char *servname, int matchonly, | 905 | get_port(const struct addrinfo *ai, const char *servname, int matchonly, | |
906 | struct servent_data *svd) | 906 | struct servent_data *svd) | |
907 | { | 907 | { | |
908 | const char *proto; | 908 | const char *proto; | |
909 | struct servent *sp; | 909 | struct servent *sp; | |
910 | int port; | 910 | int port; | |
911 | int allownumeric; | 911 | int allownumeric; | |
912 | 912 | |||
913 | _DIAGASSERT(ai != NULL); | 913 | _DIAGASSERT(ai != NULL); | |
914 | /* servname may be NULL */ | 914 | /* servname may be NULL */ | |
915 | 915 | |||
916 | if (servname == NULL) | 916 | if (servname == NULL) | |
917 | return 0; | 917 | return 0; | |
918 | switch (ai->ai_family) { | 918 | switch (ai->ai_family) { | |
919 | case AF_INET: | 919 | case AF_INET: | |
920 | #ifdef AF_INET6 | 920 | #ifdef AF_INET6 | |
921 | case AF_INET6: | 921 | case AF_INET6: | |
922 | #endif | 922 | #endif | |
923 | break; | 923 | break; | |
924 | default: | 924 | default: | |
925 | return 0; | 925 | return 0; | |
926 | } | 926 | } | |
927 | 927 | |||
928 | switch (ai->ai_socktype) { | 928 | switch (ai->ai_socktype) { | |
929 | case SOCK_RAW: | 929 | case SOCK_RAW: | |
930 | return EAI_SERVICE; | 930 | return EAI_SERVICE; | |
931 | case SOCK_DGRAM: | 931 | case SOCK_DGRAM: | |
932 | case SOCK_STREAM: | 932 | case SOCK_STREAM: | |
933 | allownumeric = 1; | 933 | allownumeric = 1; | |
934 | break; | 934 | break; | |
935 | case ANY: | 935 | case ANY: | |
936 | /* | 936 | /* | |
937 | * This was 0. It is now 1 so that queries specifying | 937 | * This was 0. It is now 1 so that queries specifying | |
938 | * a NULL hint, or hint without socktype (but, hopefully, | 938 | * a NULL hint, or hint without socktype (but, hopefully, | |
939 | * with protocol) and numeric address actually work. | 939 | * with protocol) and numeric address actually work. | |
940 | */ | 940 | */ | |
941 | allownumeric = 1; | 941 | allownumeric = 1; | |
942 | break; | 942 | break; | |
943 | default: | 943 | default: | |
944 | return EAI_SOCKTYPE; | 944 | return EAI_SOCKTYPE; | |
945 | } | 945 | } | |
946 | 946 | |||
947 | port = str2number(servname); | 947 | port = str2number(servname); | |
948 | if (port >= 0) { | 948 | if (port >= 0) { | |
949 | if (!allownumeric) | 949 | if (!allownumeric) | |
950 | return EAI_SERVICE; | 950 | return EAI_SERVICE; | |
951 | if (port < 0 || port > 65535) | 951 | if (port < 0 || port > 65535) | |
952 | return EAI_SERVICE; | 952 | return EAI_SERVICE; | |
953 | port = htons(port); | 953 | port = htons(port); | |
954 | } else { | 954 | } else { | |
955 | struct servent sv; | 955 | struct servent sv; | |
956 | if (ai->ai_flags & AI_NUMERICSERV) | 956 | if (ai->ai_flags & AI_NUMERICSERV) | |
957 | return EAI_NONAME; | 957 | return EAI_NONAME; | |
958 | 958 | |||
959 | switch (ai->ai_socktype) { | 959 | switch (ai->ai_socktype) { | |
960 | case SOCK_DGRAM: | 960 | case SOCK_DGRAM: | |
961 | proto = "udp"; | 961 | proto = "udp"; | |
962 | break; | 962 | break; | |
963 | case SOCK_STREAM: | 963 | case SOCK_STREAM: | |
964 | proto = "tcp"; | 964 | proto = "tcp"; | |
965 | break; | 965 | break; | |
966 | default: | 966 | default: | |
967 | proto = NULL; | 967 | proto = NULL; | |
968 | break; | 968 | break; | |
969 | } | 969 | } | |
970 | 970 | |||
971 | sp = getservbyname_r(servname, proto, &sv, svd); | 971 | sp = getservbyname_r(servname, proto, &sv, svd); | |
972 | if (sp == NULL) | 972 | if (sp == NULL) | |
973 | return EAI_SERVICE; | 973 | return EAI_SERVICE; | |
974 | port = sp->s_port; | 974 | port = sp->s_port; | |
975 | } | 975 | } | |
976 | 976 | |||
977 | if (!matchonly) { | 977 | if (!matchonly) { | |
978 | switch (ai->ai_family) { | 978 | switch (ai->ai_family) { | |
979 | case AF_INET: | 979 | case AF_INET: | |
980 | ((struct sockaddr_in *)(void *) | 980 | ((struct sockaddr_in *)(void *) | |
981 | ai->ai_addr)->sin_port = port; | 981 | ai->ai_addr)->sin_port = port; | |
982 | break; | 982 | break; | |
983 | #ifdef INET6 | 983 | #ifdef INET6 | |
984 | case AF_INET6: | 984 | case AF_INET6: | |
985 | ((struct sockaddr_in6 *)(void *) | 985 | ((struct sockaddr_in6 *)(void *) | |
986 | ai->ai_addr)->sin6_port = port; | 986 | ai->ai_addr)->sin6_port = port; | |
987 | break; | 987 | break; | |
988 | #endif | 988 | #endif | |
989 | } | 989 | } | |
990 | } | 990 | } | |
991 | 991 | |||
992 | return 0; | 992 | return 0; | |
993 | } | 993 | } | |
994 | 994 | |||
995 | static const struct afd * | 995 | static const struct afd * | |
996 | find_afd(int af) | 996 | find_afd(int af) | |
997 | { | 997 | { | |
998 | const struct afd *afd; | 998 | const struct afd *afd; | |
999 | 999 | |||
1000 | if (af == PF_UNSPEC) | 1000 | if (af == PF_UNSPEC) | |
1001 | return NULL; | 1001 | return NULL; | |
1002 | for (afd = afdl; afd->a_af; afd++) { | 1002 | for (afd = afdl; afd->a_af; afd++) { | |
1003 | if (afd->a_af == af) | 1003 | if (afd->a_af == af) | |
1004 | return afd; | 1004 | return afd; | |
1005 | } | 1005 | } | |
1006 | return NULL; | 1006 | return NULL; | |
1007 | } | 1007 | } | |
1008 | 1008 | |||
1009 | #ifdef INET6 | 1009 | #ifdef INET6 | |
1010 | /* convert a string to a scope identifier. XXX: IPv6 specific */ | 1010 | /* convert a string to a scope identifier. XXX: IPv6 specific */ | |
1011 | static int | 1011 | static int | |
1012 | ip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6, u_int32_t *scopeid) | 1012 | ip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6, u_int32_t *scopeid) | |
1013 | { | 1013 | { | |
1014 | u_long lscopeid; | 1014 | u_long lscopeid; | |
1015 | struct in6_addr *a6; | 1015 | struct in6_addr *a6; | |
1016 | char *ep; | 1016 | char *ep; | |
1017 | 1017 | |||
1018 | _DIAGASSERT(scope != NULL); | 1018 | _DIAGASSERT(scope != NULL); | |
1019 | _DIAGASSERT(sin6 != NULL); | 1019 | _DIAGASSERT(sin6 != NULL); | |
1020 | _DIAGASSERT(scopeid != NULL); | 1020 | _DIAGASSERT(scopeid != NULL); | |
1021 | 1021 | |||
1022 | a6 = &sin6->sin6_addr; | 1022 | a6 = &sin6->sin6_addr; | |
1023 | 1023 | |||
1024 | /* empty scopeid portion is invalid */ | 1024 | /* empty scopeid portion is invalid */ | |
1025 | if (*scope == '\0') | 1025 | if (*scope == '\0') | |
1026 | return -1; | 1026 | return -1; | |
1027 | 1027 | |||
1028 | if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) { | 1028 | if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) { | |
1029 | /* | 1029 | /* | |
1030 | * We currently assume a one-to-one mapping between links | 1030 | * We currently assume an one-to-one mapping between links | |
1031 | * and interfaces, so we simply use interface indices for | 1031 | * and interfaces, so we simply use interface indices for | |
1032 | * like-local scopes. | 1032 | * like-local scopes. | |
1033 | */ | 1033 | */ | |
1034 | *scopeid = if_nametoindex(scope); | 1034 | *scopeid = if_nametoindex(scope); | |
1035 | if (*scopeid == 0) | 1035 | if (*scopeid == 0) | |
1036 | goto trynumeric; | 1036 | goto trynumeric; | |
1037 | return 0; | 1037 | return 0; | |
1038 | } | 1038 | } | |
1039 | 1039 | |||
1040 | /* still unclear about literal, allow numeric only - placeholder */ | 1040 | /* still unclear about literal, allow numeric only - placeholder */ | |
1041 | if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6)) | 1041 | if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6)) | |
1042 | goto trynumeric; | 1042 | goto trynumeric; | |
1043 | if (IN6_IS_ADDR_MC_ORGLOCAL(a6)) | 1043 | if (IN6_IS_ADDR_MC_ORGLOCAL(a6)) | |
1044 | goto trynumeric; | 1044 | goto trynumeric; | |
1045 | else | 1045 | else | |
1046 | goto trynumeric; /* global */ | 1046 | goto trynumeric; /* global */ | |
1047 | 1047 | |||
1048 | /* try to convert to a numeric id as a last resort */ | 1048 | /* try to convert to a numeric id as a last resort */ | |
1049 | trynumeric: | 1049 | trynumeric: | |
1050 | errno = 0; | 1050 | errno = 0; | |
1051 | lscopeid = strtoul(scope, &ep, 10); | 1051 | lscopeid = strtoul(scope, &ep, 10); | |
1052 | *scopeid = (u_int32_t)(lscopeid & 0xffffffffUL); | 1052 | *scopeid = (u_int32_t)(lscopeid & 0xffffffffUL); | |
1053 | if (errno == 0 && ep && *ep == '\0' && *scopeid == lscopeid) | 1053 | if (errno == 0 && ep && *ep == '\0' && *scopeid == lscopeid) | |
1054 | return 0; | 1054 | return 0; | |
1055 | else | 1055 | else | |
1056 | return -1; | 1056 | return -1; | |
1057 | } | 1057 | } | |
1058 | #endif | 1058 | #endif | |
1059 | 1059 | |||
1060 | /* code duplicate with gethnamaddr.c */ | 1060 | /* code duplicate with gethnamaddr.c */ | |
1061 | 1061 | |||
1062 | static const char AskedForGot[] = | 1062 | static const char AskedForGot[] = | |
1063 | "gethostby*.getanswer: asked for \"%s\", got \"%s\""; | 1063 | "gethostby*.getanswer: asked for \"%s\", got \"%s\""; | |
1064 | 1064 | |||
1065 | static struct addrinfo * | 1065 | static struct addrinfo * | |
1066 | getanswer(const querybuf *answer, int anslen, const char *qname, int qtype, | 1066 | getanswer(const querybuf *answer, int anslen, const char *qname, int qtype, | |
1067 | const struct addrinfo *pai) | 1067 | const struct addrinfo *pai) | |
1068 | { | 1068 | { | |
1069 | struct addrinfo sentinel, *cur; | 1069 | struct addrinfo sentinel, *cur; | |
1070 | struct addrinfo ai; | 1070 | struct addrinfo ai; | |
1071 | const struct afd *afd; | 1071 | const struct afd *afd; | |
1072 | char *canonname; | 1072 | char *canonname; | |
1073 | const HEADER *hp; | 1073 | const HEADER *hp; | |
1074 | const u_char *cp; | 1074 | const u_char *cp; | |
1075 | int n; | 1075 | int n; | |
1076 | const u_char *eom; | 1076 | const u_char *eom; | |
1077 | char *bp, *ep; | 1077 | char *bp, *ep; | |
1078 | int type, class, ancount, qdcount; | 1078 | int type, class, ancount, qdcount; | |
1079 | int haveanswer, had_error; | 1079 | int haveanswer, had_error; | |
1080 | char tbuf[MAXDNAME]; | 1080 | char tbuf[MAXDNAME]; | |
1081 | int (*name_ok) (const char *); | 1081 | int (*name_ok) (const char *); | |
1082 | char hostbuf[8*1024]; | 1082 | char hostbuf[8*1024]; | |
1083 | 1083 | |||
1084 | _DIAGASSERT(answer != NULL); | 1084 | _DIAGASSERT(answer != NULL); | |
1085 | _DIAGASSERT(qname != NULL); | 1085 | _DIAGASSERT(qname != NULL); | |
1086 | _DIAGASSERT(pai != NULL); | 1086 | _DIAGASSERT(pai != NULL); | |
1087 | 1087 | |||
1088 | memset(&sentinel, 0, sizeof(sentinel)); | 1088 | memset(&sentinel, 0, sizeof(sentinel)); | |
1089 | cur = &sentinel; | 1089 | cur = &sentinel; | |
1090 | 1090 | |||
1091 | canonname = NULL; | 1091 | canonname = NULL; | |
1092 | eom = answer->buf + anslen; | 1092 | eom = answer->buf + anslen; | |
1093 | switch (qtype) { | 1093 | switch (qtype) { | |
1094 | case T_A: | 1094 | case T_A: | |
1095 | case T_AAAA: | 1095 | case T_AAAA: | |
1096 | case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/ | 1096 | case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/ | |
1097 | name_ok = res_hnok; | 1097 | name_ok = res_hnok; | |
1098 | break; | 1098 | break; | |
1099 | default: | 1099 | default: | |
1100 | return NULL; /* XXX should be abort(); */ | 1100 | return NULL; /* XXX should be abort(); */ | |
1101 | } | 1101 | } | |
1102 | /* | 1102 | /* | |
1103 | * find first satisfactory answer | 1103 | * find first satisfactory answer | |
1104 | */ | 1104 | */ | |
1105 | hp = &answer->hdr; | 1105 | hp = &answer->hdr; | |
1106 | ancount = ntohs(hp->ancount); | 1106 | ancount = ntohs(hp->ancount); | |
1107 | qdcount = ntohs(hp->qdcount); | 1107 | qdcount = ntohs(hp->qdcount); | |
1108 | bp = hostbuf; | 1108 | bp = hostbuf; | |
1109 | ep = hostbuf + sizeof hostbuf; | 1109 | ep = hostbuf + sizeof hostbuf; | |
1110 | cp = answer->buf + HFIXEDSZ; | 1110 | cp = answer->buf + HFIXEDSZ; | |
1111 | if (qdcount != 1) { | 1111 | if (qdcount != 1) { | |
1112 | h_errno = NO_RECOVERY; | 1112 | h_errno = NO_RECOVERY; | |
1113 | return (NULL); | 1113 | return (NULL); | |
1114 | } | 1114 | } | |
1115 | n = dn_expand(answer->buf, eom, cp, bp, ep - bp); | 1115 | n = dn_expand(answer->buf, eom, cp, bp, ep - bp); | |
1116 | if ((n < 0) || !(*name_ok)(bp)) { | 1116 | if ((n < 0) || !(*name_ok)(bp)) { | |
1117 | h_errno = NO_RECOVERY; | 1117 | h_errno = NO_RECOVERY; | |
1118 | return (NULL); | 1118 | return (NULL); | |
1119 | } | 1119 | } | |
1120 | cp += n + QFIXEDSZ; | 1120 | cp += n + QFIXEDSZ; | |
1121 | if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) { | 1121 | if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) { | |
1122 | /* res_send() has already verified that the query name is the | 1122 | /* res_send() has already verified that the query name is the | |
1123 | * same as the one we sent; this just gets the expanded name | 1123 | * same as the one we sent; this just gets the expanded name | |
1124 | * (i.e., with the succeeding search-domain tacked on). | 1124 | * (i.e., with the succeeding search-domain tacked on). | |
1125 | */ | 1125 | */ | |
1126 | n = strlen(bp) + 1; /* for the \0 */ | 1126 | n = strlen(bp) + 1; /* for the \0 */ | |
1127 | if (n >= MAXHOSTNAMELEN) { | 1127 | if (n >= MAXHOSTNAMELEN) { | |
1128 | h_errno = NO_RECOVERY; | 1128 | h_errno = NO_RECOVERY; | |
1129 | return (NULL); | 1129 | return (NULL); | |
1130 | } | 1130 | } | |
1131 | canonname = bp; | 1131 | canonname = bp; | |
1132 | bp += n; | 1132 | bp += n; | |
1133 | /* The qname can be abbreviated, but h_name is now absolute. */ | 1133 | /* The qname can be abbreviated, but h_name is now absolute. */ | |
1134 | qname = canonname; | 1134 | qname = canonname; | |
1135 | } | 1135 | } | |
1136 | haveanswer = 0; | 1136 | haveanswer = 0; | |
1137 | had_error = 0; | 1137 | had_error = 0; | |
1138 | while (ancount-- > 0 && cp < eom && !had_error) { | 1138 | while (ancount-- > 0 && cp < eom && !had_error) { | |
1139 | n = dn_expand(answer->buf, eom, cp, bp, ep - bp); | 1139 | n = dn_expand(answer->buf, eom, cp, bp, ep - bp); | |
1140 | if ((n < 0) || !(*name_ok)(bp)) { | 1140 | if ((n < 0) || !(*name_ok)(bp)) { | |
1141 | had_error++; | 1141 | had_error++; | |
1142 | continue; | 1142 | continue; | |
1143 | } | 1143 | } | |
1144 | cp += n; /* name */ | 1144 | cp += n; /* name */ | |
1145 | type = _getshort(cp); | 1145 | type = _getshort(cp); | |
1146 | cp += INT16SZ; /* type */ | 1146 | cp += INT16SZ; /* type */ | |
1147 | class = _getshort(cp); | 1147 | class = _getshort(cp); | |
1148 | cp += INT16SZ + INT32SZ; /* class, TTL */ | 1148 | cp += INT16SZ + INT32SZ; /* class, TTL */ | |
1149 | n = _getshort(cp); | 1149 | n = _getshort(cp); | |
1150 | cp += INT16SZ; /* len */ | 1150 | cp += INT16SZ; /* len */ | |
1151 | if (class != C_IN) { | 1151 | if (class != C_IN) { | |
1152 | /* XXX - debug? syslog? */ | 1152 | /* XXX - debug? syslog? */ | |
1153 | cp += n; | 1153 | cp += n; | |
1154 | continue; /* XXX - had_error++ ? */ | 1154 | continue; /* XXX - had_error++ ? */ | |
1155 | } | 1155 | } | |
1156 | if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) && | 1156 | if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) && | |
1157 | type == T_CNAME) { | 1157 | type == T_CNAME) { | |
1158 | n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); | 1158 | n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); | |
1159 | if ((n < 0) || !(*name_ok)(tbuf)) { | 1159 | if ((n < 0) || !(*name_ok)(tbuf)) { | |
1160 | had_error++; | 1160 | had_error++; | |
1161 | continue; | 1161 | continue; | |
1162 | } | 1162 | } | |
1163 | cp += n; | 1163 | cp += n; | |
1164 | /* Get canonical name. */ | 1164 | /* Get canonical name. */ | |
1165 | n = strlen(tbuf) + 1; /* for the \0 */ | 1165 | n = strlen(tbuf) + 1; /* for the \0 */ | |
1166 | if (n > ep - bp || n >= MAXHOSTNAMELEN) { | 1166 | if (n > ep - bp || n >= MAXHOSTNAMELEN) { | |
1167 | had_error++; | 1167 | had_error++; | |
1168 | continue; | 1168 | continue; | |
1169 | } | 1169 | } | |
1170 | strlcpy(bp, tbuf, (size_t)(ep - bp)); | 1170 | strlcpy(bp, tbuf, (size_t)(ep - bp)); | |
1171 | canonname = bp; | 1171 | canonname = bp; | |
1172 | bp += n; | 1172 | bp += n; | |
1173 | continue; | 1173 | continue; | |
1174 | } | 1174 | } | |
1175 | if (qtype == T_ANY) { | 1175 | if (qtype == T_ANY) { | |
1176 | if (!(type == T_A || type == T_AAAA)) { | 1176 | if (!(type == T_A || type == T_AAAA)) { | |
1177 | cp += n; | 1177 | cp += n; | |
1178 | continue; | 1178 | continue; | |
1179 | } | 1179 | } | |
1180 | } else if (type != qtype) { | 1180 | } else if (type != qtype) { | |
1181 | if (type != T_KEY && type != T_SIG) { | 1181 | if (type != T_KEY && type != T_SIG) { | |
1182 | struct syslog_data sd = SYSLOG_DATA_INIT; | 1182 | struct syslog_data sd = SYSLOG_DATA_INIT; | |
1183 | syslog_r(LOG_NOTICE|LOG_AUTH, &sd, | 1183 | syslog_r(LOG_NOTICE|LOG_AUTH, &sd, | |
1184 | "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"", | 1184 | "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"", | |
1185 | qname, p_class(C_IN), p_type(qtype), | 1185 | qname, p_class(C_IN), p_type(qtype), | |
1186 | p_type(type)); | 1186 | p_type(type)); | |
1187 | } | 1187 | } | |
1188 | cp += n; | 1188 | cp += n; | |
1189 | continue; /* XXX - had_error++ ? */ | 1189 | continue; /* XXX - had_error++ ? */ | |
1190 | } | 1190 | } | |
1191 | switch (type) { | 1191 | switch (type) { | |
1192 | case T_A: | 1192 | case T_A: | |
1193 | case T_AAAA: | 1193 | case T_AAAA: | |
1194 | if (strcasecmp(canonname, bp) != 0) { | 1194 | if (strcasecmp(canonname, bp) != 0) { | |
1195 | struct syslog_data sd = SYSLOG_DATA_INIT; | 1195 | struct syslog_data sd = SYSLOG_DATA_INIT; | |
1196 | syslog_r(LOG_NOTICE|LOG_AUTH, &sd, | 1196 | syslog_r(LOG_NOTICE|LOG_AUTH, &sd, | |
1197 | AskedForGot, canonname, bp); | 1197 | AskedForGot, canonname, bp); | |
1198 | cp += n; | 1198 | cp += n; | |
1199 | continue; /* XXX - had_error++ ? */ | 1199 | continue; /* XXX - had_error++ ? */ | |
1200 | } | 1200 | } | |
1201 | if (type == T_A && n != INADDRSZ) { | 1201 | if (type == T_A && n != INADDRSZ) { | |
1202 | cp += n; | 1202 | cp += n; | |
1203 | continue; | 1203 | continue; | |
1204 | } | 1204 | } | |
1205 | if (type == T_AAAA && n != IN6ADDRSZ) { | 1205 | if (type == T_AAAA && n != IN6ADDRSZ) { | |
1206 | cp += n; | 1206 | cp += n; | |
1207 | continue; | 1207 | continue; | |
1208 | } | 1208 | } | |
1209 | if (type == T_AAAA) { | 1209 | if (type == T_AAAA) { | |
1210 | struct in6_addr in6; | 1210 | struct in6_addr in6; | |
1211 | memcpy(&in6, cp, IN6ADDRSZ); | 1211 | memcpy(&in6, cp, IN6ADDRSZ); | |
1212 | if (IN6_IS_ADDR_V4MAPPED(&in6)) { | 1212 | if (IN6_IS_ADDR_V4MAPPED(&in6)) { | |
1213 | cp += n; | 1213 | cp += n; | |
1214 | continue; | 1214 | continue; | |
1215 | } | 1215 | } | |
1216 | } | 1216 | } | |
1217 | if (!haveanswer) { | 1217 | if (!haveanswer) { | |
1218 | int nn; | 1218 | int nn; | |
1219 | 1219 | |||
1220 | canonname = bp; | 1220 | canonname = bp; | |
1221 | nn = strlen(bp) + 1; /* for the \0 */ | 1221 | nn = strlen(bp) + 1; /* for the \0 */ | |
1222 | bp += nn; | 1222 | bp += nn; | |
1223 | } | 1223 | } | |
1224 | 1224 | |||
1225 | /* don't overwrite pai */ | 1225 | /* don't overwrite pai */ | |
1226 | ai = *pai; | 1226 | ai = *pai; | |
1227 | ai.ai_family = (type == T_A) ? AF_INET : AF_INET6; | 1227 | ai.ai_family = (type == T_A) ? AF_INET : AF_INET6; | |
1228 | afd = find_afd(ai.ai_family); | 1228 | afd = find_afd(ai.ai_family); | |
1229 | if (afd == NULL) { | 1229 | if (afd == NULL) { | |
1230 | cp += n; | 1230 | cp += n; | |
1231 | continue; | 1231 | continue; | |
1232 | } | 1232 | } | |
1233 | cur->ai_next = get_ai(&ai, afd, (const char *)cp); | 1233 | cur->ai_next = get_ai(&ai, afd, (const char *)cp); | |
1234 | if (cur->ai_next == NULL) | 1234 | if (cur->ai_next == NULL) | |
1235 | had_error++; | 1235 | had_error++; | |
1236 | while (cur && cur->ai_next) | 1236 | while (cur && cur->ai_next) | |
1237 | cur = cur->ai_next; | 1237 | cur = cur->ai_next; | |
1238 | cp += n; | 1238 | cp += n; | |
1239 | break; | 1239 | break; | |
1240 | default: | 1240 | default: | |
1241 | abort(); | 1241 | abort(); | |
1242 | } | 1242 | } | |
1243 | if (!had_error) | 1243 | if (!had_error) | |
1244 | haveanswer++; | 1244 | haveanswer++; | |
1245 | } | 1245 | } | |
1246 | if (haveanswer) { | 1246 | if (haveanswer) { | |
1247 | if (!canonname) | 1247 | if (!canonname) | |
1248 | (void)get_canonname(pai, sentinel.ai_next, qname); | 1248 | (void)get_canonname(pai, sentinel.ai_next, qname); | |
1249 | else | 1249 | else | |
1250 | (void)get_canonname(pai, sentinel.ai_next, canonname); | 1250 | (void)get_canonname(pai, sentinel.ai_next, canonname); | |
1251 | h_errno = NETDB_SUCCESS; | 1251 | h_errno = NETDB_SUCCESS; | |
1252 | return sentinel.ai_next; | 1252 | return sentinel.ai_next; | |
1253 | } | 1253 | } | |
1254 | 1254 | |||
1255 | h_errno = NO_RECOVERY; | 1255 | h_errno = NO_RECOVERY; | |
1256 | return NULL; | 1256 | return NULL; | |
1257 | } | 1257 | } | |
1258 | 1258 | |||
1259 | #define SORTEDADDR(p) (((struct sockaddr_in *)(void *)(p->ai_next->ai_addr))->sin_addr.s_addr) | 1259 | #define SORTEDADDR(p) (((struct sockaddr_in *)(void *)(p->ai_next->ai_addr))->sin_addr.s_addr) | |
1260 | #define SORTMATCH(p, s) ((SORTEDADDR(p) & (s).mask) == (s).addr.s_addr) | 1260 | #define SORTMATCH(p, s) ((SORTEDADDR(p) & (s).mask) == (s).addr.s_addr) | |
1261 | 1261 | |||
1262 | static void | 1262 | static void | |
1263 | aisort(struct addrinfo *s, res_state res) | 1263 | aisort(struct addrinfo *s, res_state res) | |
1264 | { | 1264 | { | |
1265 | struct addrinfo head, *t, *p; | 1265 | struct addrinfo head, *t, *p; | |
1266 | int i; | 1266 | int i; | |
1267 | 1267 | |||
1268 | head.ai_next = NULL; | 1268 | head.ai_next = NULL; | |
1269 | t = &head; | 1269 | t = &head; | |
1270 | 1270 | |||
1271 | for (i = 0; i < res->nsort; i++) { | 1271 | for (i = 0; i < res->nsort; i++) { | |
1272 | p = s; | 1272 | p = s; | |
1273 | while (p->ai_next) { | 1273 | while (p->ai_next) { | |
1274 | if ((p->ai_next->ai_family != AF_INET) | 1274 | if ((p->ai_next->ai_family != AF_INET) | |
1275 | || SORTMATCH(p, res->sort_list[i])) { | 1275 | || SORTMATCH(p, res->sort_list[i])) { | |
1276 | t->ai_next = p->ai_next; | 1276 | t->ai_next = p->ai_next; | |
1277 | t = t->ai_next; | 1277 | t = t->ai_next; | |
1278 | p->ai_next = p->ai_next->ai_next; | 1278 | p->ai_next = p->ai_next->ai_next; | |
1279 | } else { | 1279 | } else { | |
1280 | p = p->ai_next; | 1280 | p = p->ai_next; | |
1281 | } | 1281 | } | |
1282 | } | 1282 | } | |
1283 | } | 1283 | } | |
1284 | 1284 | |||
1285 | /* add rest of list and reset s to the new list*/ | 1285 | /* add rest of list and reset s to the new list*/ | |
1286 | t->ai_next = s->ai_next; | 1286 | t->ai_next = s->ai_next; | |
1287 | s->ai_next = head.ai_next; | 1287 | s->ai_next = head.ai_next; | |
1288 | } | 1288 | } | |
1289 | 1289 | |||
1290 | /*ARGSUSED*/ | 1290 | /*ARGSUSED*/ | |
1291 | static int | 1291 | static int | |
1292 | _dns_getaddrinfo(void *rv, void *cb_data, va_list ap) | 1292 | _dns_getaddrinfo(void *rv, void *cb_data, va_list ap) | |
1293 | { | 1293 | { | |
1294 | struct addrinfo *ai; | 1294 | struct addrinfo *ai; | |
1295 | querybuf *buf, *buf2; | 1295 | querybuf *buf, *buf2; | |
1296 | const char *name; | 1296 | const char *name; | |
1297 | const struct addrinfo *pai; | 1297 | const struct addrinfo *pai; | |
1298 | struct addrinfo sentinel, *cur; | 1298 | struct addrinfo sentinel, *cur; | |
1299 | struct res_target q, q2; | 1299 | struct res_target q, q2; | |
1300 | res_state res; | 1300 | res_state res; | |
1301 | 1301 | |||
1302 | name = va_arg(ap, char *); | 1302 | name = va_arg(ap, char *); | |
1303 | pai = va_arg(ap, const struct addrinfo *); | 1303 | pai = va_arg(ap, const struct addrinfo *); | |
1304 | 1304 | |||
1305 | memset(&q, 0, sizeof(q)); | 1305 | memset(&q, 0, sizeof(q)); | |
1306 | memset(&q2, 0, sizeof(q2)); | 1306 | memset(&q2, 0, sizeof(q2)); | |
1307 | memset(&sentinel, 0, sizeof(sentinel)); | 1307 | memset(&sentinel, 0, sizeof(sentinel)); | |
1308 | cur = &sentinel; | 1308 | cur = &sentinel; | |
1309 | 1309 | |||
1310 | buf = malloc(sizeof(*buf)); | 1310 | buf = malloc(sizeof(*buf)); | |
1311 | if (buf == NULL) { | 1311 | if (buf == NULL) { | |
1312 | h_errno = NETDB_INTERNAL; | 1312 | h_errno = NETDB_INTERNAL; | |
1313 | return NS_NOTFOUND; | 1313 | return NS_NOTFOUND; | |
1314 | } | 1314 | } | |
1315 | buf2 = malloc(sizeof(*buf2)); | 1315 | buf2 = malloc(sizeof(*buf2)); | |
1316 | if (buf2 == NULL) { | 1316 | if (buf2 == NULL) { | |
1317 | free(buf); | 1317 | free(buf); | |
1318 | h_errno = NETDB_INTERNAL; | 1318 | h_errno = NETDB_INTERNAL; | |
1319 | return NS_NOTFOUND; | 1319 | return NS_NOTFOUND; | |
1320 | } | 1320 | } | |
1321 | 1321 | |||
1322 | switch (pai->ai_family) { | 1322 | switch (pai->ai_family) { | |
1323 | case AF_UNSPEC: | 1323 | case AF_UNSPEC: | |
1324 | /* prefer IPv6 */ | 1324 | /* prefer IPv6 */ | |
1325 | q.name = name; | 1325 | q.name = name; | |
1326 | q.qclass = C_IN; | 1326 | q.qclass = C_IN; | |
1327 | q.qtype = T_AAAA; | 1327 | q.qtype = T_AAAA; | |
1328 | q.answer = buf->buf; | 1328 | q.answer = buf->buf; | |
1329 | q.anslen = sizeof(buf->buf); | 1329 | q.anslen = sizeof(buf->buf); | |
1330 | q.next = &q2; | 1330 | q.next = &q2; | |
1331 | q2.name = name; | 1331 | q2.name = name; | |
1332 | q2.qclass = C_IN; | 1332 | q2.qclass = C_IN; | |
1333 | q2.qtype = T_A; | 1333 | q2.qtype = T_A; | |
1334 | q2.answer = buf2->buf; | 1334 | q2.answer = buf2->buf; | |
1335 | q2.anslen = sizeof(buf2->buf); | 1335 | q2.anslen = sizeof(buf2->buf); | |
1336 | break; | 1336 | break; | |
1337 | case AF_INET: | 1337 | case AF_INET: | |
1338 | q.name = name; | 1338 | q.name = name; | |
1339 | q.qclass = C_IN; | 1339 | q.qclass = C_IN; | |
1340 | q.qtype = T_A; | 1340 | q.qtype = T_A; | |
1341 | q.answer = buf->buf; | 1341 | q.answer = buf->buf; | |
1342 | q.anslen = sizeof(buf->buf); | 1342 | q.anslen = sizeof(buf->buf); | |
1343 | break; | 1343 | break; | |
1344 | case AF_INET6: | 1344 | case AF_INET6: | |
1345 | q.name = name; | 1345 | q.name = name; | |
1346 | q.qclass = C_IN; | 1346 | q.qclass = C_IN; | |
1347 | q.qtype = T_AAAA; | 1347 | q.qtype = T_AAAA; | |
1348 | q.answer = buf->buf; | 1348 | q.answer = buf->buf; | |
1349 | q.anslen = sizeof(buf->buf); | 1349 | q.anslen = sizeof(buf->buf); | |
1350 | break; | 1350 | break; | |
1351 | default: | 1351 | default: | |
1352 | free(buf); | 1352 | free(buf); | |
1353 | free(buf2); | 1353 | free(buf2); | |
1354 | return NS_UNAVAIL; | 1354 | return NS_UNAVAIL; | |
1355 | } | 1355 | } | |
1356 | 1356 | |||
1357 | res = __res_get_state(); | 1357 | res = __res_get_state(); | |
1358 | if (res == NULL) { | 1358 | if (res == NULL) { | |
1359 | free(buf); | 1359 | free(buf); | |
1360 | free(buf2); | 1360 | free(buf2); | |
1361 | return NS_NOTFOUND; | 1361 | return NS_NOTFOUND; | |
1362 | } | 1362 | } | |
1363 | 1363 | |||
1364 | if (res_searchN(name, &q, res) < 0) { | 1364 | if (res_searchN(name, &q, res) < 0) { | |
1365 | __res_put_state(res); | 1365 | __res_put_state(res); | |
1366 | free(buf); | 1366 | free(buf); | |
1367 | free(buf2); | 1367 | free(buf2); | |
1368 | return NS_NOTFOUND; | 1368 | return NS_NOTFOUND; | |
1369 | } | 1369 | } | |
1370 | ai = getanswer(buf, q.n, q.name, q.qtype, pai); | 1370 | ai = getanswer(buf, q.n, q.name, q.qtype, pai); | |
1371 | if (ai) { | 1371 | if (ai) { | |
1372 | cur->ai_next = ai; | 1372 | cur->ai_next = ai; | |
1373 | while (cur && cur->ai_next) | 1373 | while (cur && cur->ai_next) | |
1374 | cur = cur->ai_next; | 1374 | cur = cur->ai_next; | |
1375 | } | 1375 | } | |
1376 | if (q.next) { | 1376 | if (q.next) { | |
1377 | ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai); | 1377 | ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai); | |
1378 | if (ai) | 1378 | if (ai) | |
1379 | cur->ai_next = ai; | 1379 | cur->ai_next = ai; | |
1380 | } | 1380 | } | |
1381 | free(buf); | 1381 | free(buf); | |
1382 | free(buf2); | 1382 | free(buf2); | |
1383 | if (sentinel.ai_next == NULL) { | 1383 | if (sentinel.ai_next == NULL) { | |
1384 | __res_put_state(res); | 1384 | __res_put_state(res); | |
1385 | switch (h_errno) { | 1385 | switch (h_errno) { | |
1386 | case HOST_NOT_FOUND: | 1386 | case HOST_NOT_FOUND: | |
1387 | return NS_NOTFOUND; | 1387 | return NS_NOTFOUND; | |
1388 | case TRY_AGAIN: | 1388 | case TRY_AGAIN: | |
1389 | return NS_TRYAGAIN; | 1389 | return NS_TRYAGAIN; | |
1390 | default: | 1390 | default: | |
1391 | return NS_UNAVAIL; | 1391 | return NS_UNAVAIL; | |
1392 | } | 1392 | } | |
1393 | } | 1393 | } | |
1394 | 1394 | |||
1395 | if (res->nsort) | 1395 | if (res->nsort) | |
1396 | aisort(&sentinel, res); | 1396 | aisort(&sentinel, res); | |
1397 | 1397 | |||
1398 | __res_put_state(res); | 1398 | __res_put_state(res); | |
1399 | 1399 | |||
1400 | *((struct addrinfo **)rv) = sentinel.ai_next; | 1400 | *((struct addrinfo **)rv) = sentinel.ai_next; | |
1401 | return NS_SUCCESS; | 1401 | return NS_SUCCESS; | |
1402 | } | 1402 | } | |
1403 | 1403 | |||
1404 | static void | 1404 | static void | |
1405 | _sethtent(FILE **hostf) | 1405 | _sethtent(FILE **hostf) | |
1406 | { | 1406 | { | |
1407 | 1407 | |||
1408 | if (!*hostf) | 1408 | if (!*hostf) | |
1409 | *hostf = fopen(_PATH_HOSTS, "r" ); | 1409 | *hostf = fopen(_PATH_HOSTS, "r" ); | |
1410 | else | 1410 | else | |
1411 | rewind(*hostf); | 1411 | rewind(*hostf); | |
1412 | } | 1412 | } | |
1413 | 1413 | |||
1414 | static void | 1414 | static void | |
1415 | _endhtent(FILE **hostf) | 1415 | _endhtent(FILE **hostf) | |
1416 | { | 1416 | { | |
1417 | 1417 | |||
1418 | if (*hostf) { | 1418 | if (*hostf) { | |
1419 | (void) fclose(*hostf); | 1419 | (void) fclose(*hostf); | |
1420 | *hostf = NULL; | 1420 | *hostf = NULL; | |
1421 | } | 1421 | } | |
1422 | } | 1422 | } | |
1423 | 1423 | |||
1424 | static struct addrinfo * | 1424 | static struct addrinfo * | |
1425 | _gethtent(FILE **hostf, const char *name, const struct addrinfo *pai) | 1425 | _gethtent(FILE **hostf, const char *name, const struct addrinfo *pai) | |
1426 | { | 1426 | { | |
1427 | char *p; | 1427 | char *p; | |
1428 | char *cp, *tname, *cname; | 1428 | char *cp, *tname, *cname; | |
1429 | struct addrinfo hints, *res0, *res; | 1429 | struct addrinfo hints, *res0, *res; | |
1430 | int error; | 1430 | int error; | |
1431 | const char *addr; | 1431 | const char *addr; | |
1432 | char hostbuf[8*1024]; | 1432 | char hostbuf[8*1024]; | |
1433 | 1433 | |||
1434 | _DIAGASSERT(name != NULL); | 1434 | _DIAGASSERT(name != NULL); | |
1435 | _DIAGASSERT(pai != NULL); | 1435 | _DIAGASSERT(pai != NULL); | |
1436 | 1436 | |||
1437 | if (!*hostf && !(*hostf = fopen(_PATH_HOSTS, "r" ))) | 1437 | if (!*hostf && !(*hostf = fopen(_PATH_HOSTS, "r" ))) | |
1438 | return (NULL); | 1438 | return (NULL); | |
1439 | again: | 1439 | again: | |
1440 | if (!(p = fgets(hostbuf, sizeof hostbuf, *hostf))) | 1440 | if (!(p = fgets(hostbuf, sizeof hostbuf, *hostf))) | |
1441 | return (NULL); | 1441 | return (NULL); | |
1442 | if (*p == '#') | 1442 | if (*p == '#') | |
1443 | goto again; | 1443 | goto again; | |
1444 | if (!(cp = strpbrk(p, "#\n"))) | 1444 | if (!(cp = strpbrk(p, "#\n"))) | |
1445 | goto again; | 1445 | goto again; | |
1446 | *cp = '\0'; | 1446 | *cp = '\0'; | |
1447 | if (!(cp = strpbrk(p, " \t"))) | 1447 | if (!(cp = strpbrk(p, " \t"))) | |
1448 | goto again; | 1448 | goto again; | |
1449 | *cp++ = '\0'; | 1449 | *cp++ = '\0'; | |
1450 | addr = p; | 1450 | addr = p; | |
1451 | /* if this is not something we're looking for, skip it. */ | 1451 | /* if this is not something we're looking for, skip it. */ | |
1452 | cname = NULL; | 1452 | cname = NULL; | |
1453 | while (cp && *cp) { | 1453 | while (cp && *cp) { | |
1454 | if (*cp == ' ' || *cp == '\t') { | 1454 | if (*cp == ' ' || *cp == '\t') { | |
1455 | cp++; | 1455 | cp++; | |
1456 | continue; | 1456 | continue; | |
1457 | } | 1457 | } | |
1458 | if (!cname) | 1458 | if (!cname) | |
1459 | cname = cp; | 1459 | cname = cp; | |
1460 | tname = cp; | 1460 | tname = cp; | |
1461 | if ((cp = strpbrk(cp, " \t")) != NULL) | 1461 | if ((cp = strpbrk(cp, " \t")) != NULL) | |
1462 | *cp++ = '\0'; | 1462 | *cp++ = '\0'; | |
1463 | if (strcasecmp(name, tname) == 0) | 1463 | if (strcasecmp(name, tname) == 0) | |
1464 | goto found; | 1464 | goto found; | |
1465 | } | 1465 | } | |
1466 | goto again; | 1466 | goto again; | |
1467 | 1467 | |||
1468 | found: | 1468 | found: | |
1469 | hints = *pai; | 1469 | hints = *pai; | |
1470 | hints.ai_flags = AI_NUMERICHOST; | 1470 | hints.ai_flags = AI_NUMERICHOST; | |
1471 | error = getaddrinfo(addr, NULL, &hints, &res0); | 1471 | error = getaddrinfo(addr, NULL, &hints, &res0); | |
1472 | if (error) | 1472 | if (error) | |
1473 | goto again; | 1473 | goto again; | |
1474 | for (res = res0; res; res = res->ai_next) { | 1474 | for (res = res0; res; res = res->ai_next) { | |
1475 | /* cover it up */ | 1475 | /* cover it up */ | |
1476 | res->ai_flags = pai->ai_flags; | 1476 | res->ai_flags = pai->ai_flags; | |
1477 | 1477 | |||
1478 | if (pai->ai_flags & AI_CANONNAME) { | 1478 | if (pai->ai_flags & AI_CANONNAME) { | |
1479 | if (get_canonname(pai, res, cname) != 0) { | 1479 | if (get_canonname(pai, res, cname) != 0) { | |
1480 | freeaddrinfo(res0); | 1480 | freeaddrinfo(res0); | |
1481 | goto again; | 1481 | goto again; | |
1482 | } | 1482 | } | |
1483 | } | 1483 | } | |
1484 | } | 1484 | } | |
1485 | return res0; | 1485 | return res0; | |
1486 | } | 1486 | } | |
1487 | 1487 | |||
1488 | /*ARGSUSED*/ | 1488 | /*ARGSUSED*/ | |
1489 | static int | 1489 | static int | |
1490 | _files_getaddrinfo(void *rv, void *cb_data, va_list ap) | 1490 | _files_getaddrinfo(void *rv, void *cb_data, va_list ap) | |
1491 | { | 1491 | { | |
1492 | const char *name; | 1492 | const char *name; | |
1493 | const struct addrinfo *pai; | 1493 | const struct addrinfo *pai; | |
1494 | struct addrinfo sentinel, *cur; | 1494 | struct addrinfo sentinel, *cur; | |
1495 | struct addrinfo *p; | 1495 | struct addrinfo *p; | |
1496 | #ifndef _REENTRANT | 1496 | #ifndef _REENTRANT | |
1497 | static | 1497 | static | |
1498 | #endif | 1498 | #endif | |
1499 | FILE *hostf = NULL; | 1499 | FILE *hostf = NULL; | |
1500 | 1500 | |||
1501 | name = va_arg(ap, char *); | 1501 | name = va_arg(ap, char *); | |
1502 | pai = va_arg(ap, const struct addrinfo *); | 1502 | pai = va_arg(ap, const struct addrinfo *); | |
1503 | 1503 | |||
1504 | memset(&sentinel, 0, sizeof(sentinel)); | 1504 | memset(&sentinel, 0, sizeof(sentinel)); | |
1505 | cur = &sentinel; | 1505 | cur = &sentinel; | |
1506 | 1506 | |||
1507 | _sethtent(&hostf); | 1507 | _sethtent(&hostf); | |
1508 | while ((p = _gethtent(&hostf, name, pai)) != NULL) { | 1508 | while ((p = _gethtent(&hostf, name, pai)) != NULL) { | |
1509 | cur->ai_next = p; | 1509 | cur->ai_next = p; | |
1510 | while (cur && cur->ai_next) | 1510 | while (cur && cur->ai_next) | |
1511 | cur = cur->ai_next; | 1511 | cur = cur->ai_next; | |
1512 | } | 1512 | } | |
1513 | _endhtent(&hostf); | 1513 | _endhtent(&hostf); | |
1514 | 1514 | |||
1515 | *((struct addrinfo **)rv) = sentinel.ai_next; | 1515 | *((struct addrinfo **)rv) = sentinel.ai_next; | |
1516 | if (sentinel.ai_next == NULL) | 1516 | if (sentinel.ai_next == NULL) | |
1517 | return NS_NOTFOUND; | 1517 | return NS_NOTFOUND; | |
1518 | return NS_SUCCESS; | 1518 | return NS_SUCCESS; | |
1519 | } | 1519 | } | |
1520 | 1520 | |||
1521 | #ifdef YP | 1521 | #ifdef YP | |
1522 | /*ARGSUSED*/ | 1522 | /*ARGSUSED*/ | |
1523 | static struct addrinfo * | 1523 | static struct addrinfo * | |
1524 | _yphostent(char *line, const struct addrinfo *pai) | 1524 | _yphostent(char *line, const struct addrinfo *pai) | |
1525 | { | 1525 | { | |
1526 | struct addrinfo sentinel, *cur; | 1526 | struct addrinfo sentinel, *cur; | |
1527 | struct addrinfo hints, *res, *res0; | 1527 | struct addrinfo hints, *res, *res0; | |
1528 | int error; | 1528 | int error; | |
1529 | char *p; | 1529 | char *p; | |
1530 | const char *addr, *canonname; | 1530 | const char *addr, *canonname; | |
1531 | char *nextline; | 1531 | char *nextline; | |
1532 | char *cp; | 1532 | char *cp; | |
1533 | 1533 | |||
1534 | _DIAGASSERT(line != NULL); | 1534 | _DIAGASSERT(line != NULL); | |
1535 | _DIAGASSERT(pai != NULL); | 1535 | _DIAGASSERT(pai != NULL); | |
1536 | 1536 | |||
1537 | p = line; | 1537 | p = line; | |
1538 | addr = canonname = NULL; | 1538 | addr = canonname = NULL; | |
1539 | 1539 | |||
1540 | memset(&sentinel, 0, sizeof(sentinel)); | 1540 | memset(&sentinel, 0, sizeof(sentinel)); | |
1541 | cur = &sentinel; | 1541 | cur = &sentinel; | |
1542 | 1542 | |||
1543 | nextline: | 1543 | nextline: | |
1544 | /* terminate line */ | 1544 | /* terminate line */ | |
1545 | cp = strchr(p, '\n'); | 1545 | cp = strchr(p, '\n'); | |
1546 | if (cp) { | 1546 | if (cp) { | |
1547 | *cp++ = '\0'; | 1547 | *cp++ = '\0'; | |
1548 | nextline = cp; | 1548 | nextline = cp; | |
1549 | } else | 1549 | } else | |
1550 | nextline = NULL; | 1550 | nextline = NULL; | |
1551 | 1551 | |||
1552 | cp = strpbrk(p, " \t"); | 1552 | cp = strpbrk(p, " \t"); | |
1553 | if (cp == NULL) { | 1553 | if (cp == NULL) { | |
1554 | if (canonname == NULL) | 1554 | if (canonname == NULL) | |
1555 | return (NULL); | 1555 | return (NULL); | |
1556 | else | 1556 | else | |
1557 | goto done; | 1557 | goto done; | |
1558 | } | 1558 | } | |
1559 | *cp++ = '\0'; | 1559 | *cp++ = '\0'; | |
1560 | 1560 | |||
1561 | addr = p; | 1561 | addr = p; | |
1562 | 1562 | |||
1563 | while (cp && *cp) { | 1563 | while (cp && *cp) { | |
1564 | if (*cp == ' ' || *cp == '\t') { | 1564 | if (*cp == ' ' || *cp == '\t') { | |
1565 | cp++; | 1565 | cp++; | |
1566 | continue; | 1566 | continue; | |
1567 | } | 1567 | } | |
1568 | if (!canonname) | 1568 | if (!canonname) | |
1569 | canonname = cp; | 1569 | canonname = cp; | |
1570 | if ((cp = strpbrk(cp, " \t")) != NULL) | 1570 | if ((cp = strpbrk(cp, " \t")) != NULL) | |
1571 | *cp++ = '\0'; | 1571 | *cp++ = '\0'; | |
1572 | } | 1572 | } | |
1573 | 1573 | |||
1574 | hints = *pai; | 1574 | hints = *pai; | |
1575 | hints.ai_flags = AI_NUMERICHOST; | 1575 | hints.ai_flags = AI_NUMERICHOST; | |
1576 | error = getaddrinfo(addr, NULL, &hints, &res0); | 1576 | error = getaddrinfo(addr, NULL, &hints, &res0); | |
1577 | if (error == 0) { | 1577 | if (error == 0) { | |
1578 | for (res = res0; res; res = res->ai_next) { | 1578 | for (res = res0; res; res = res->ai_next) { | |
1579 | /* cover it up */ | 1579 | /* cover it up */ | |
1580 | res->ai_flags = pai->ai_flags; | 1580 | res->ai_flags = pai->ai_flags; | |
1581 | 1581 | |||
1582 | if (pai->ai_flags & AI_CANONNAME) | 1582 | if (pai->ai_flags & AI_CANONNAME) | |
1583 | (void)get_canonname(pai, res, canonname); | 1583 | (void)get_canonname(pai, res, canonname); | |
1584 | } | 1584 | } | |
1585 | } else | 1585 | } else | |
1586 | res0 = NULL; | 1586 | res0 = NULL; | |
1587 | if (res0) { | 1587 | if (res0) { | |
1588 | cur->ai_next = res0; | 1588 | cur->ai_next = res0; | |
1589 | while (cur->ai_next) | 1589 | while (cur->ai_next) | |
1590 | cur = cur->ai_next; | 1590 | cur = cur->ai_next; | |
1591 | } | 1591 | } | |
1592 | 1592 | |||
1593 | if (nextline) { | 1593 | if (nextline) { | |
1594 | p = nextline; | 1594 | p = nextline; | |
1595 | goto nextline; | 1595 | goto nextline; | |
1596 | } | 1596 | } | |
1597 | 1597 | |||
1598 | done: | 1598 | done: | |
1599 | return sentinel.ai_next; | 1599 | return sentinel.ai_next; | |
1600 | } | 1600 | } | |
1601 | 1601 | |||
1602 | /*ARGSUSED*/ | 1602 | /*ARGSUSED*/ | |
1603 | static int | 1603 | static int | |
1604 | _yp_getaddrinfo(void *rv, void *cb_data, va_list ap) | 1604 | _yp_getaddrinfo(void *rv, void *cb_data, va_list ap) | |
1605 | { | 1605 | { | |
1606 | struct addrinfo sentinel, *cur; | 1606 | struct addrinfo sentinel, *cur; | |
1607 | struct addrinfo *ai = NULL; | 1607 | struct addrinfo *ai = NULL; | |
1608 | char *ypbuf; | 1608 | char *ypbuf; | |
1609 | int ypbuflen, r; | 1609 | int ypbuflen, r; | |
1610 | const char *name; | 1610 | const char *name; | |
1611 | const struct addrinfo *pai; | 1611 | const struct addrinfo *pai; | |
1612 | char *ypdomain; | 1612 | char *ypdomain; | |
1613 | 1613 | |||
1614 | if (_yp_check(&ypdomain) == 0) | 1614 | if (_yp_check(&ypdomain) == 0) | |
1615 | return NS_UNAVAIL; | 1615 | return NS_UNAVAIL; | |
1616 | 1616 | |||
1617 | name = va_arg(ap, char *); | 1617 | name = va_arg(ap, char *); | |
1618 | pai = va_arg(ap, const struct addrinfo *); | 1618 | pai = va_arg(ap, const struct addrinfo *); | |
1619 | 1619 | |||
1620 | memset(&sentinel, 0, sizeof(sentinel)); | 1620 | memset(&sentinel, 0, sizeof(sentinel)); | |
1621 | cur = &sentinel; | 1621 | cur = &sentinel; | |
1622 | 1622 | |||
1623 | /* hosts.byname is only for IPv4 (Solaris8) */ | 1623 | /* hosts.byname is only for IPv4 (Solaris8) */ | |
1624 | if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) { | 1624 | if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) { | |
1625 | r = yp_match(ypdomain, "hosts.byname", name, | 1625 | r = yp_match(ypdomain, "hosts.byname", name, | |
1626 | (int)strlen(name), &ypbuf, &ypbuflen); | 1626 | (int)strlen(name), &ypbuf, &ypbuflen); | |
1627 | if (r == 0) { | 1627 | if (r == 0) { | |
1628 | struct addrinfo ai4; | 1628 | struct addrinfo ai4; | |
1629 | 1629 | |||
1630 | ai4 = *pai; | 1630 | ai4 = *pai; | |
1631 | ai4.ai_family = AF_INET; | 1631 | ai4.ai_family = AF_INET; | |
1632 | ai = _yphostent(ypbuf, &ai4); | 1632 | ai = _yphostent(ypbuf, &ai4); | |
1633 | if (ai) { | 1633 | if (ai) { | |
1634 | cur->ai_next = ai; | 1634 | cur->ai_next = ai; | |
1635 | while (cur && cur->ai_next) | 1635 | while (cur && cur->ai_next) | |
1636 | cur = cur->ai_next; | 1636 | cur = cur->ai_next; | |
1637 | } | 1637 | } | |
1638 | } | 1638 | } | |
1639 | free(ypbuf); | 1639 | free(ypbuf); | |
1640 | } | 1640 | } | |
1641 | 1641 | |||
1642 | /* ipnodes.byname can hold both IPv4/v6 */ | 1642 | /* ipnodes.byname can hold both IPv4/v6 */ | |
1643 | r = yp_match(ypdomain, "ipnodes.byname", name, | 1643 | r = yp_match(ypdomain, "ipnodes.byname", name, | |
1644 | (int)strlen(name), &ypbuf, &ypbuflen); | 1644 | (int)strlen(name), &ypbuf, &ypbuflen); | |
1645 | if (r == 0) { | 1645 | if (r == 0) { | |
1646 | ai = _yphostent(ypbuf, pai); | 1646 | ai = _yphostent(ypbuf, pai); | |
1647 | if (ai) | 1647 | if (ai) | |
1648 | cur->ai_next = ai; | 1648 | cur->ai_next = ai; | |
1649 | free(ypbuf); | 1649 | free(ypbuf); | |
1650 | } | 1650 | } | |
1651 | 1651 | |||
1652 | if (sentinel.ai_next == NULL) { | 1652 | if (sentinel.ai_next == NULL) { | |
1653 | h_errno = HOST_NOT_FOUND; | 1653 | h_errno = HOST_NOT_FOUND; | |
1654 | return NS_NOTFOUND; | 1654 | return NS_NOTFOUND; | |
1655 | } | 1655 | } | |
1656 | *((struct addrinfo **)rv) = sentinel.ai_next; | 1656 | *((struct addrinfo **)rv) = sentinel.ai_next; | |
1657 | return NS_SUCCESS; | 1657 | return NS_SUCCESS; | |
1658 | } | 1658 | } | |
1659 | #endif | 1659 | #endif | |
1660 | 1660 | |||
1661 | /* resolver logic */ | 1661 | /* resolver logic */ | |
1662 | 1662 | |||
1663 | /* | 1663 | /* | |
1664 | * Formulate a normal query, send, and await answer. | 1664 | * Formulate a normal query, send, and await answer. | |
1665 | * Returned answer is placed in supplied buffer "answer". | 1665 | * Returned answer is placed in supplied buffer "answer". | |
1666 | * Perform preliminary check of answer, returning success only | 1666 | * Perform preliminary check of answer, returning success only | |
1667 | * if no error is indicated and the answer count is nonzero. | 1667 | * if no error is indicated and the answer count is nonzero. | |
1668 | * Return the size of the response on success, -1 on error. | 1668 | * Return the size of the response on success, -1 on error. | |
1669 | * Error number is left in h_errno. | 1669 | * Error number is left in h_errno. | |
1670 | * | 1670 | * | |
1671 | * Caller must parse answer and determine whether it answers the question. | 1671 | * Caller must parse answer and determine whether it answers the question. | |
1672 | */ | 1672 | */ | |
1673 | static int | 1673 | static int | |
1674 | res_queryN(const char *name, /* domain name */ struct res_target *target, | 1674 | res_queryN(const char *name, /* domain name */ struct res_target *target, | |
1675 | res_state res) | 1675 | res_state res) | |
1676 | { | 1676 | { | |
1677 | u_char buf[MAXPACKET]; | 1677 | u_char buf[MAXPACKET]; | |
1678 | HEADER *hp; | 1678 | HEADER *hp; | |
1679 | int n; | 1679 | int n; | |
1680 | struct res_target *t; | 1680 | struct res_target *t; | |
1681 | int rcode; | 1681 | int rcode; | |
1682 | int ancount; | 1682 | int ancount; | |
1683 | 1683 | |||
1684 | _DIAGASSERT(name != NULL); | 1684 | _DIAGASSERT(name != NULL); | |
1685 | /* XXX: target may be NULL??? */ | 1685 | /* XXX: target may be NULL??? */ | |
1686 | 1686 | |||
1687 | rcode = NOERROR; | 1687 | rcode = NOERROR; | |
1688 | ancount = 0; | 1688 | ancount = 0; | |
1689 | 1689 | |||
1690 | for (t = target; t; t = t->next) { | 1690 | for (t = target; t; t = t->next) { | |
1691 | int class, type; | 1691 | int class, type; | |
1692 | u_char *answer; | 1692 | u_char *answer; | |
1693 | int anslen; | 1693 | int anslen; | |
1694 | 1694 | |||
1695 | hp = (HEADER *)(void *)t->answer; | 1695 | hp = (HEADER *)(void *)t->answer; | |
1696 | hp->rcode = NOERROR; /* default */ | 1696 | hp->rcode = NOERROR; /* default */ | |
1697 | 1697 | |||
1698 | /* make it easier... */ | 1698 | /* make it easier... */ | |
1699 | class = t->qclass; | 1699 | class = t->qclass; | |
1700 | type = t->qtype; | 1700 | type = t->qtype; | |
1701 | answer = t->answer; | 1701 | answer = t->answer; | |
1702 | anslen = t->anslen; | 1702 | anslen = t->anslen; | |
1703 | #ifdef DEBUG | 1703 | #ifdef DEBUG | |
1704 | if (res->options & RES_DEBUG) | 1704 | if (res->options & RES_DEBUG) | |
1705 | printf(";; res_nquery(%s, %d, %d)\n", name, class, type); | 1705 | printf(";; res_nquery(%s, %d, %d)\n", name, class, type); | |
1706 | #endif | 1706 | #endif | |
1707 | 1707 | |||
1708 | n = res_nmkquery(res, QUERY, name, class, type, NULL, 0, NULL, | 1708 | n = res_nmkquery(res, QUERY, name, class, type, NULL, 0, NULL, | |
1709 | buf, sizeof(buf)); | 1709 | buf, sizeof(buf)); | |
1710 | #ifdef RES_USE_EDNS0 | 1710 | #ifdef RES_USE_EDNS0 | |
1711 | if (n > 0 && (res->options & RES_USE_EDNS0) != 0) | 1711 | if (n > 0 && (res->options & RES_USE_EDNS0) != 0) | |
1712 | n = res_nopt(res, n, buf, sizeof(buf), anslen); | 1712 | n = res_nopt(res, n, buf, sizeof(buf), anslen); | |
1713 | #endif | 1713 | #endif | |
1714 | if (n <= 0) { | 1714 | if (n <= 0) { | |
1715 | #ifdef DEBUG | 1715 | #ifdef DEBUG | |
1716 | if (res->options & RES_DEBUG) | 1716 | if (res->options & RES_DEBUG) | |
1717 | printf(";; res_nquery: mkquery failed\n"); | 1717 | printf(";; res_nquery: mkquery failed\n"); | |
1718 | #endif | 1718 | #endif | |
1719 | h_errno = NO_RECOVERY; | 1719 | h_errno = NO_RECOVERY; | |
1720 | return n; | 1720 | return n; | |
1721 | } | 1721 | } | |
1722 | n = res_nsend(res, buf, n, answer, anslen); | 1722 | n = res_nsend(res, buf, n, answer, anslen); | |
1723 | #if 0 | 1723 | #if 0 | |
1724 | if (n < 0) { | 1724 | if (n < 0) { | |
1725 | #ifdef DEBUG | 1725 | #ifdef DEBUG | |
1726 | if (res->options & RES_DEBUG) | 1726 | if (res->options & RES_DEBUG) | |
1727 | printf(";; res_query: send error\n"); | 1727 | printf(";; res_query: send error\n"); | |
1728 | #endif | 1728 | #endif | |
1729 | h_errno = TRY_AGAIN; | 1729 | h_errno = TRY_AGAIN; | |
1730 | return n; | 1730 | return n; | |
1731 | } | 1731 | } | |
1732 | #endif | 1732 | #endif | |
1733 | 1733 | |||
1734 | if (n < 0 || hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { | 1734 | if (n < 0 || hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { | |
1735 | rcode = hp->rcode; /* record most recent error */ | 1735 | rcode = hp->rcode; /* record most recent error */ | |
1736 | #ifdef DEBUG | 1736 | #ifdef DEBUG | |
1737 | if (res->options & RES_DEBUG) | 1737 | if (res->options & RES_DEBUG) | |
1738 | printf(";; rcode = %u, ancount=%u\n", hp->rcode, | 1738 | printf(";; rcode = %u, ancount=%u\n", hp->rcode, | |
1739 | ntohs(hp->ancount)); | 1739 | ntohs(hp->ancount)); | |
1740 | #endif | 1740 | #endif | |
1741 | continue; | 1741 | continue; | |
1742 | } | 1742 | } | |
1743 | 1743 | |||
1744 | ancount += ntohs(hp->ancount); | 1744 | ancount += ntohs(hp->ancount); | |
1745 | 1745 | |||
1746 | t->n = n; | 1746 | t->n = n; | |
1747 | } | 1747 | } | |
1748 | 1748 | |||
1749 | if (ancount == 0) { | 1749 | if (ancount == 0) { | |
1750 | switch (rcode) { | 1750 | switch (rcode) { | |
1751 | case NXDOMAIN: | 1751 | case NXDOMAIN: | |
1752 | h_errno = HOST_NOT_FOUND; | 1752 | h_errno = HOST_NOT_FOUND; | |
1753 | break; | 1753 | break; | |
1754 | case SERVFAIL: | 1754 | case SERVFAIL: | |
1755 | h_errno = TRY_AGAIN; | 1755 | h_errno = TRY_AGAIN; | |
1756 | break; | 1756 | break; | |
1757 | case NOERROR: | 1757 | case NOERROR: | |
1758 | h_errno = NO_DATA; | 1758 | h_errno = NO_DATA; | |
1759 | break; | 1759 | break; | |
1760 | case FORMERR: | 1760 | case FORMERR: | |
1761 | case NOTIMP: | 1761 | case NOTIMP: | |
1762 | case REFUSED: | 1762 | case REFUSED: | |
1763 | default: | 1763 | default: | |
1764 | h_errno = NO_RECOVERY; | 1764 | h_errno = NO_RECOVERY; | |
1765 | break; | 1765 | break; | |
1766 | } | 1766 | } | |
1767 | return -1; | 1767 | return -1; | |
1768 | } | 1768 | } | |
1769 | return ancount; | 1769 | return ancount; | |
1770 | } | 1770 | } | |
1771 | 1771 | |||
1772 | /* | 1772 | /* | |
1773 | * Formulate a normal query, send, and retrieve answer in supplied buffer. | 1773 | * Formulate a normal query, send, and retrieve answer in supplied buffer. | |
1774 | * Return the size of the response on success, -1 on error. | 1774 | * Return the size of the response on success, -1 on error. | |
1775 | * If enabled, implement search rules until answer or unrecoverable failure | 1775 | * If enabled, implement search rules until answer or unrecoverable failure | |
1776 | * is detected. Error code, if any, is left in h_errno. | 1776 | * is detected. Error code, if any, is left in h_errno. | |
1777 | */ | 1777 | */ | |
1778 | static int | 1778 | static int | |
1779 | res_searchN(const char *name, struct res_target *target, res_state res) | 1779 | res_searchN(const char *name, struct res_target *target, res_state res) | |
1780 | { | 1780 | { | |
1781 | const char *cp, * const *domain; | 1781 | const char *cp, * const *domain; | |
1782 | HEADER *hp; | 1782 | HEADER *hp; | |
1783 | u_int dots; | 1783 | u_int dots; | |
1784 | int trailing_dot, ret, saved_herrno; | 1784 | int trailing_dot, ret, saved_herrno; | |
1785 | int got_nodata = 0, got_servfail = 0, tried_as_is = 0; | 1785 | int got_nodata = 0, got_servfail = 0, tried_as_is = 0; | |
1786 | 1786 | |||
1787 | _DIAGASSERT(name != NULL); | 1787 | _DIAGASSERT(name != NULL); | |
1788 | _DIAGASSERT(target != NULL); | 1788 | _DIAGASSERT(target != NULL); | |
1789 | 1789 | |||
1790 | hp = (HEADER *)(void *)target->answer; /*XXX*/ | 1790 | hp = (HEADER *)(void *)target->answer; /*XXX*/ | |
1791 | 1791 | |||
1792 | errno = 0; | 1792 | errno = 0; | |
1793 | h_errno = HOST_NOT_FOUND; /* default, if we never query */ | 1793 | h_errno = HOST_NOT_FOUND; /* default, if we never query */ | |
1794 | dots = 0; | 1794 | dots = 0; | |
1795 | for (cp = name; *cp; cp++) | 1795 | for (cp = name; *cp; cp++) | |
1796 | dots += (*cp == '.'); | 1796 | dots += (*cp == '.'); | |
1797 | trailing_dot = 0; | 1797 | trailing_dot = 0; | |
1798 | if (cp > name && *--cp == '.') | 1798 | if (cp > name && *--cp == '.') | |
1799 | trailing_dot++; | 1799 | trailing_dot++; | |
1800 | 1800 | |||
1801 | /* | 1801 | /* | |
1802 | * if there aren't any dots, it could be a user-level alias | 1802 | * if there aren't any dots, it could be an user-level alias | |
1803 | */ | 1803 | */ | |
1804 | if (!dots && (cp = __hostalias(name)) != NULL) { | 1804 | if (!dots && (cp = __hostalias(name)) != NULL) { | |
1805 | ret = res_queryN(cp, target, res); | 1805 | ret = res_queryN(cp, target, res); | |
1806 | return ret; | 1806 | return ret; | |
1807 | } | 1807 | } | |
1808 | 1808 | |||
1809 | /* | 1809 | /* | |
1810 | * If there are dots in the name already, let's just give it a try | 1810 | * If there are dots in the name already, let's just give it a try | |
1811 | * 'as is'. The threshold can be set with the "ndots" option. | 1811 | * 'as is'. The threshold can be set with the "ndots" option. | |
1812 | */ | 1812 | */ | |
1813 | saved_herrno = -1; | 1813 | saved_herrno = -1; | |
1814 | if (dots >= res->ndots) { | 1814 | if (dots >= res->ndots) { | |
1815 | ret = res_querydomainN(name, NULL, target, res); | 1815 | ret = res_querydomainN(name, NULL, target, res); | |
1816 | if (ret > 0) | 1816 | if (ret > 0) | |
1817 | return (ret); | 1817 | return (ret); | |
1818 | saved_herrno = h_errno; | 1818 | saved_herrno = h_errno; | |
1819 | tried_as_is++; | 1819 | tried_as_is++; | |
1820 | } | 1820 | } | |
1821 | 1821 | |||
1822 | /* | 1822 | /* | |
1823 | * We do at least one level of search if | 1823 | * We do at least one level of search if | |
1824 | * - there is no dot and RES_DEFNAME is set, or | 1824 | * - there is no dot and RES_DEFNAME is set, or | |
1825 | * - there is at least one dot, there is no trailing dot, | 1825 | * - there is at least one dot, there is no trailing dot, | |
1826 | * and RES_DNSRCH is set. | 1826 | * and RES_DNSRCH is set. | |
1827 | */ | 1827 | */ | |
1828 | if ((!dots && (res->options & RES_DEFNAMES)) || | 1828 | if ((!dots && (res->options & RES_DEFNAMES)) || | |
1829 | (dots && !trailing_dot && (res->options & RES_DNSRCH))) { | 1829 | (dots && !trailing_dot && (res->options & RES_DNSRCH))) { | |
1830 | int done = 0; | 1830 | int done = 0; | |
1831 | 1831 | |||
1832 | for (domain = (const char * const *)res->dnsrch; | 1832 | for (domain = (const char * const *)res->dnsrch; | |
1833 | *domain && !done; | 1833 | *domain && !done; | |
1834 | domain++) { | 1834 | domain++) { | |
1835 | 1835 | |||
1836 | ret = res_querydomainN(name, *domain, target, res); | 1836 | ret = res_querydomainN(name, *domain, target, res); | |
1837 | if (ret > 0) | 1837 | if (ret > 0) | |
1838 | return ret; | 1838 | return ret; | |
1839 | 1839 | |||
1840 | /* | 1840 | /* | |
1841 | * If no server present, give up. | 1841 | * If no server present, give up. | |
1842 | * If name isn't found in this domain, | 1842 | * If name isn't found in this domain, | |
1843 | * keep trying higher domains in the search list | 1843 | * keep trying higher domains in the search list | |
1844 | * (if that's enabled). | 1844 | * (if that's enabled). | |
1845 | * On a NO_DATA error, keep trying, otherwise | 1845 | * On a NO_DATA error, keep trying, otherwise | |
1846 | * a wildcard entry of another type could keep us | 1846 | * a wildcard entry of another type could keep us | |
1847 | * from finding this entry higher in the domain. | 1847 | * from finding this entry higher in the domain. | |
1848 | * If we get some other error (negative answer or | 1848 | * If we get some other error (negative answer or | |
1849 | * server failure), then stop searching up, | 1849 | * server failure), then stop searching up, | |
1850 | * but try the input name below in case it's | 1850 | * but try the input name below in case it's | |
1851 | * fully-qualified. | 1851 | * fully-qualified. | |
1852 | */ | 1852 | */ | |
1853 | if (errno == ECONNREFUSED) { | 1853 | if (errno == ECONNREFUSED) { | |
1854 | h_errno = TRY_AGAIN; | 1854 | h_errno = TRY_AGAIN; | |
1855 | return -1; | 1855 | return -1; | |
1856 | } | 1856 | } | |
1857 | 1857 | |||
1858 | switch (h_errno) { | 1858 | switch (h_errno) { | |
1859 | case NO_DATA: | 1859 | case NO_DATA: | |
1860 | got_nodata++; | 1860 | got_nodata++; | |
1861 | /* FALLTHROUGH */ | 1861 | /* FALLTHROUGH */ | |
1862 | case HOST_NOT_FOUND: | 1862 | case HOST_NOT_FOUND: | |
1863 | /* keep trying */ | 1863 | /* keep trying */ | |
1864 | break; | 1864 | break; | |
1865 | case TRY_AGAIN: | 1865 | case TRY_AGAIN: | |
1866 | if (hp->rcode == SERVFAIL) { | 1866 | if (hp->rcode == SERVFAIL) { | |
1867 | /* try next search element, if any */ | 1867 | /* try next search element, if any */ | |
1868 | got_servfail++; | 1868 | got_servfail++; | |
1869 | break; | 1869 | break; | |
1870 | } | 1870 | } | |
1871 | /* FALLTHROUGH */ | 1871 | /* FALLTHROUGH */ | |
1872 | default: | 1872 | default: | |
1873 | /* anything else implies that we're done */ | 1873 | /* anything else implies that we're done */ | |
1874 | done++; | 1874 | done++; | |
1875 | } | 1875 | } | |
1876 | /* | 1876 | /* | |
1877 | * if we got here for some reason other than DNSRCH, | 1877 | * if we got here for some reason other than DNSRCH, | |
1878 | * we only wanted one iteration of the loop, so stop. | 1878 | * we only wanted one iteration of the loop, so stop. | |
1879 | */ | 1879 | */ | |
1880 | if (!(res->options & RES_DNSRCH)) | 1880 | if (!(res->options & RES_DNSRCH)) | |
1881 | done++; | 1881 | done++; | |
1882 | } | 1882 | } | |
1883 | } | 1883 | } | |
1884 | 1884 | |||
1885 | /* | 1885 | /* | |
1886 | * if we have not already tried the name "as is", do that now. | 1886 | * if we have not already tried the name "as is", do that now. | |
1887 | * note that we do this regardless of how many dots were in the | 1887 | * note that we do this regardless of how many dots were in the | |
1888 | * name or whether it ends with a dot. | 1888 | * name or whether it ends with a dot. | |
1889 | */ | 1889 | */ | |
1890 | if (!tried_as_is) { | 1890 | if (!tried_as_is) { | |
1891 | ret = res_querydomainN(name, NULL, target, res); | 1891 | ret = res_querydomainN(name, NULL, target, res); | |
1892 | if (ret > 0) | 1892 | if (ret > 0) | |
1893 | return ret; | 1893 | return ret; | |
1894 | } | 1894 | } | |
1895 | 1895 | |||
1896 | /* | 1896 | /* | |
1897 | * if we got here, we didn't satisfy the search. | 1897 | * if we got here, we didn't satisfy the search. | |
1898 | * if we did an initial full query, return that query's h_errno | 1898 | * if we did an initial full query, return that query's h_errno | |
1899 | * (note that we wouldn't be here if that query had succeeded). | 1899 | * (note that we wouldn't be here if that query had succeeded). | |
1900 | * else if we ever got a nodata, send that back as the reason. | 1900 | * else if we ever got a nodata, send that back as the reason. | |
1901 | * else send back meaningless h_errno, that being the one from | 1901 | * else send back meaningless h_errno, that being the one from | |
1902 | * the last DNSRCH we did. | 1902 | * the last DNSRCH we did. | |
1903 | */ | 1903 | */ | |
1904 | if (saved_herrno != -1) | 1904 | if (saved_herrno != -1) | |
1905 | h_errno = saved_herrno; | 1905 | h_errno = saved_herrno; | |
1906 | else if (got_nodata) | 1906 | else if (got_nodata) | |
1907 | h_errno = NO_DATA; | 1907 | h_errno = NO_DATA; | |
1908 | else if (got_servfail) | 1908 | else if (got_servfail) | |
1909 | h_errno = TRY_AGAIN; | 1909 | h_errno = TRY_AGAIN; | |
1910 | return -1; | 1910 | return -1; | |
1911 | } | 1911 | } | |
1912 | 1912 | |||
1913 | /* | 1913 | /* | |
1914 | * Perform a call on res_query on the concatenation of name and domain, | 1914 | * Perform a call on res_query on the concatenation of name and domain, | |
1915 | * removing a trailing dot from name if domain is NULL. | 1915 | * removing a trailing dot from name if domain is NULL. | |
1916 | */ | 1916 | */ | |
1917 | static int | 1917 | static int | |
1918 | res_querydomainN(const char *name, const char *domain, | 1918 | res_querydomainN(const char *name, const char *domain, | |
1919 | struct res_target *target, res_state res) | 1919 | struct res_target *target, res_state res) | |
1920 | { | 1920 | { | |
1921 | char nbuf[MAXDNAME]; | 1921 | char nbuf[MAXDNAME]; | |
1922 | const char *longname = nbuf; | 1922 | const char *longname = nbuf; | |
1923 | size_t n, d; | 1923 | size_t n, d; | |
1924 | 1924 | |||
1925 | _DIAGASSERT(name != NULL); | 1925 | _DIAGASSERT(name != NULL); | |
1926 | /* XXX: target may be NULL??? */ | 1926 | /* XXX: target may be NULL??? */ | |
1927 | 1927 | |||
1928 | #ifdef DEBUG | 1928 | #ifdef DEBUG | |
1929 | if (res->options & RES_DEBUG) | 1929 | if (res->options & RES_DEBUG) | |
1930 | printf(";; res_querydomain(%s, %s)\n", | 1930 | printf(";; res_querydomain(%s, %s)\n", | |
1931 | name, domain?domain:"<Nil>"); | 1931 | name, domain?domain:"<Nil>"); | |
1932 | #endif | 1932 | #endif | |
1933 | if (domain == NULL) { | 1933 | if (domain == NULL) { | |
1934 | /* | 1934 | /* | |
1935 | * Check for trailing '.'; | 1935 | * Check for trailing '.'; | |
1936 | * copy without '.' if present. | 1936 | * copy without '.' if present. | |
1937 | */ | 1937 | */ | |
1938 | n = strlen(name); | 1938 | n = strlen(name); | |
1939 | if (n + 1 > sizeof(nbuf)) { | 1939 | if (n + 1 > sizeof(nbuf)) { | |
1940 | h_errno = NO_RECOVERY; | 1940 | h_errno = NO_RECOVERY; | |
1941 | return -1; | 1941 | return -1; | |
1942 | } | 1942 | } | |
1943 | if (n > 0 && name[--n] == '.') { | 1943 | if (n > 0 && name[--n] == '.') { | |
1944 | strncpy(nbuf, name, n); | 1944 | strncpy(nbuf, name, n); | |
1945 | nbuf[n] = '\0'; | 1945 | nbuf[n] = '\0'; | |
1946 | } else | 1946 | } else | |
1947 | longname = name; | 1947 | longname = name; | |
1948 | } else { | 1948 | } else { | |
1949 | n = strlen(name); | 1949 | n = strlen(name); | |
1950 | d = strlen(domain); | 1950 | d = strlen(domain); | |
1951 | if (n + 1 + d + 1 > sizeof(nbuf)) { | 1951 | if (n + 1 + d + 1 > sizeof(nbuf)) { | |
1952 | h_errno = NO_RECOVERY; | 1952 | h_errno = NO_RECOVERY; | |
1953 | return -1; | 1953 | return -1; | |
1954 | } | 1954 | } | |
1955 | snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain); | 1955 | snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain); | |
1956 | } | 1956 | } | |
1957 | return res_queryN(longname, target, res); | 1957 | return res_queryN(longname, target, res); | |
1958 | } | 1958 | } |
--- src/lib/libc/net/gethnamaddr.c 2007/01/27 22:27:35 1.73
+++ src/lib/libc/net/gethnamaddr.c 2009/10/02 06:49:23 1.74
@@ -1,1441 +1,1441 @@ | @@ -1,1441 +1,1441 @@ | |||
1 | /* $NetBSD: gethnamaddr.c,v 1.73 2007/01/27 22:27:35 christos Exp $ */ | 1 | /* $NetBSD: gethnamaddr.c,v 1.74 2009/10/02 06:49:23 cegger Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * ++Copyright++ 1985, 1988, 1993 | 4 | * ++Copyright++ 1985, 1988, 1993 | |
5 | * - | 5 | * - | |
6 | * Copyright (c) 1985, 1988, 1993 | 6 | * Copyright (c) 1985, 1988, 1993 | |
7 | * The Regents of the University of California. All rights reserved. | 7 | * The Regents of the University of California. All rights reserved. | |
8 | * | 8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | 9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | 10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | 11 | * are met: | |
12 | * 1. Redistributions of source code must retain the above copyright | 12 | * 1. Redistributions of source code must retain the above copyright | |
13 | * notice, this list of conditions and the following disclaimer. | 13 | * notice, this list of conditions and the following disclaimer. | |
14 | * 2. Redistributions in binary form must reproduce the above copyright | 14 | * 2. Redistributions in binary form must reproduce the above copyright | |
15 | * notice, this list of conditions and the following disclaimer in the | 15 | * notice, this list of conditions and the following disclaimer in the | |
16 | * documentation and/or other materials provided with the distribution. | 16 | * documentation and/or other materials provided with the distribution. | |
17 | * 3. Neither the name of the University nor the names of its contributors | 17 | * 3. Neither the name of the University nor the names of its contributors | |
18 | * may be used to endorse or promote products derived from this software | 18 | * may be used to endorse or promote products derived from this software | |
19 | * without specific prior written permission. | 19 | * without specific prior written permission. | |
20 | * | 20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
31 | * SUCH DAMAGE. | 31 | * SUCH DAMAGE. | |
32 | * - | 32 | * - | |
33 | * Portions Copyright (c) 1993 by Digital Equipment Corporation. | 33 | * Portions Copyright (c) 1993 by Digital Equipment Corporation. | |
34 | * | 34 | * | |
35 | * Permission to use, copy, modify, and distribute this software for any | 35 | * Permission to use, copy, modify, and distribute this software for any | |
36 | * purpose with or without fee is hereby granted, provided that the above | 36 | * purpose with or without fee is hereby granted, provided that the above | |
37 | * copyright notice and this permission notice appear in all copies, and that | 37 | * copyright notice and this permission notice appear in all copies, and that | |
38 | * the name of Digital Equipment Corporation not be used in advertising or | 38 | * the name of Digital Equipment Corporation not be used in advertising or | |
39 | * publicity pertaining to distribution of the document or software without | 39 | * publicity pertaining to distribution of the document or software without | |
40 | * specific, written prior permission. | 40 | * specific, written prior permission. | |
41 | * | 41 | * | |
42 | * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL | 42 | * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL | |
43 | * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES | 43 | * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES | |
44 | * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT | 44 | * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT | |
45 | * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | 45 | * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |
46 | * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR | 46 | * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR | |
47 | * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS | 47 | * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS | |
48 | * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | 48 | * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |
49 | * SOFTWARE. | 49 | * SOFTWARE. | |
50 | * - | 50 | * - | |
51 | * --Copyright-- | 51 | * --Copyright-- | |
52 | */ | 52 | */ | |
53 | 53 | |||
54 | #include <sys/cdefs.h> | 54 | #include <sys/cdefs.h> | |
55 | #if defined(LIBC_SCCS) && !defined(lint) | 55 | #if defined(LIBC_SCCS) && !defined(lint) | |
56 | #if 0 | 56 | #if 0 | |
57 | static char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93"; | 57 | static char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93"; | |
58 | static char rcsid[] = "Id: gethnamaddr.c,v 8.21 1997/06/01 20:34:37 vixie Exp "; | 58 | static char rcsid[] = "Id: gethnamaddr.c,v 8.21 1997/06/01 20:34:37 vixie Exp "; | |
59 | #else | 59 | #else | |
60 | __RCSID("$NetBSD: gethnamaddr.c,v 1.73 2007/01/27 22:27:35 christos Exp $"); | 60 | __RCSID("$NetBSD: gethnamaddr.c,v 1.74 2009/10/02 06:49:23 cegger Exp $"); | |
61 | #endif | 61 | #endif | |
62 | #endif /* LIBC_SCCS and not lint */ | 62 | #endif /* LIBC_SCCS and not lint */ | |
63 | 63 | |||
64 | #if defined(_LIBC) | 64 | #if defined(_LIBC) | |
65 | #include "namespace.h" | 65 | #include "namespace.h" | |
66 | #endif | 66 | #endif | |
67 | #include <sys/param.h> | 67 | #include <sys/param.h> | |
68 | #include <sys/socket.h> | 68 | #include <sys/socket.h> | |
69 | #include <netinet/in.h> | 69 | #include <netinet/in.h> | |
70 | #include <arpa/inet.h> | 70 | #include <arpa/inet.h> | |
71 | #include <arpa/nameser.h> | 71 | #include <arpa/nameser.h> | |
72 | 72 | |||
73 | #include <assert.h> | 73 | #include <assert.h> | |
74 | #include <ctype.h> | 74 | #include <ctype.h> | |
75 | #include <errno.h> | 75 | #include <errno.h> | |
76 | #include <netdb.h> | 76 | #include <netdb.h> | |
77 | #include <resolv.h> | 77 | #include <resolv.h> | |
78 | #include <stdarg.h> | 78 | #include <stdarg.h> | |
79 | #include <stdio.h> | 79 | #include <stdio.h> | |
80 | #include <syslog.h> | 80 | #include <syslog.h> | |
81 | 81 | |||
82 | #ifndef LOG_AUTH | 82 | #ifndef LOG_AUTH | |
83 | # define LOG_AUTH 0 | 83 | # define LOG_AUTH 0 | |
84 | #endif | 84 | #endif | |
85 | 85 | |||
86 | #define MULTI_PTRS_ARE_ALIASES 1 /* XXX - experimental */ | 86 | #define MULTI_PTRS_ARE_ALIASES 1 /* XXX - experimental */ | |
87 | 87 | |||
88 | #include <nsswitch.h> | 88 | #include <nsswitch.h> | |
89 | #include <stdlib.h> | 89 | #include <stdlib.h> | |
90 | #include <string.h> | 90 | #include <string.h> | |
91 | 91 | |||
92 | #ifdef YP | 92 | #ifdef YP | |
93 | #include <rpc/rpc.h> | 93 | #include <rpc/rpc.h> | |
94 | #include <rpcsvc/yp_prot.h> | 94 | #include <rpcsvc/yp_prot.h> | |
95 | #include <rpcsvc/ypclnt.h> | 95 | #include <rpcsvc/ypclnt.h> | |
96 | #endif | 96 | #endif | |
97 | 97 | |||
98 | #if defined(_LIBC) && defined(__weak_alias) | 98 | #if defined(_LIBC) && defined(__weak_alias) | |
99 | __weak_alias(gethostbyaddr,_gethostbyaddr) | 99 | __weak_alias(gethostbyaddr,_gethostbyaddr) | |
100 | __weak_alias(gethostbyname,_gethostbyname) | 100 | __weak_alias(gethostbyname,_gethostbyname) | |
101 | __weak_alias(gethostent,_gethostent) | 101 | __weak_alias(gethostent,_gethostent) | |
102 | #endif | 102 | #endif | |
103 | 103 | |||
104 | #define MAXALIASES 35 | 104 | #define MAXALIASES 35 | |
105 | #define MAXADDRS 35 | 105 | #define MAXADDRS 35 | |
106 | 106 | |||
107 | static const char AskedForGot[] = | 107 | static const char AskedForGot[] = | |
108 | "gethostby*.getanswer: asked for \"%s\", got \"%s\""; | 108 | "gethostby*.getanswer: asked for \"%s\", got \"%s\""; | |
109 | 109 | |||
110 | static char *h_addr_ptrs[MAXADDRS + 1]; | 110 | static char *h_addr_ptrs[MAXADDRS + 1]; | |
111 | 111 | |||
112 | #ifdef YP | 112 | #ifdef YP | |
113 | static char *__ypdomain; | 113 | static char *__ypdomain; | |
114 | #endif | 114 | #endif | |
115 | 115 | |||
116 | static struct hostent host; | 116 | static struct hostent host; | |
117 | static char *host_aliases[MAXALIASES]; | 117 | static char *host_aliases[MAXALIASES]; | |
118 | static char hostbuf[8*1024]; | 118 | static char hostbuf[8*1024]; | |
119 | static u_int32_t host_addr[16 / sizeof(u_int32_t)]; /* IPv4 or IPv6 */ | 119 | static u_int32_t host_addr[16 / sizeof(u_int32_t)]; /* IPv4 or IPv6 */ | |
120 | static FILE *hostf = NULL; | 120 | static FILE *hostf = NULL; | |
121 | static int stayopen = 0; | 121 | static int stayopen = 0; | |
122 | 122 | |||
123 | #define MAXPACKET (64*1024) | 123 | #define MAXPACKET (64*1024) | |
124 | 124 | |||
125 | typedef union { | 125 | typedef union { | |
126 | HEADER hdr; | 126 | HEADER hdr; | |
127 | u_char buf[MAXPACKET]; | 127 | u_char buf[MAXPACKET]; | |
128 | } querybuf; | 128 | } querybuf; | |
129 | 129 | |||
130 | typedef union { | 130 | typedef union { | |
131 | int32_t al; | 131 | int32_t al; | |
132 | char ac; | 132 | char ac; | |
133 | } align; | 133 | } align; | |
134 | 134 | |||
135 | #ifdef DEBUG | 135 | #ifdef DEBUG | |
136 | static void dprintf(const char *, res_state, ...) | 136 | static void dprintf(const char *, res_state, ...) | |
137 | __attribute__((__format__(__printf__, 1, 3))); | 137 | __attribute__((__format__(__printf__, 1, 3))); | |
138 | #endif | 138 | #endif | |
139 | static struct hostent *getanswer(const querybuf *, int, const char *, int, | 139 | static struct hostent *getanswer(const querybuf *, int, const char *, int, | |
140 | res_state); | 140 | res_state); | |
141 | static void map_v4v6_address(const char *, char *); | 141 | static void map_v4v6_address(const char *, char *); | |
142 | static void map_v4v6_hostent(struct hostent *, char **, char *); | 142 | static void map_v4v6_hostent(struct hostent *, char **, char *); | |
143 | static void addrsort(char **, int, res_state); | 143 | static void addrsort(char **, int, res_state); | |
144 | 144 | |||
145 | void _sethtent(int); | 145 | void _sethtent(int); | |
146 | void _endhtent(void); | 146 | void _endhtent(void); | |
147 | struct hostent *_gethtent(void); | 147 | struct hostent *_gethtent(void); | |
148 | void ht_sethostent(int); | 148 | void ht_sethostent(int); | |
149 | void ht_endhostent(void); | 149 | void ht_endhostent(void); | |
150 | struct hostent *ht_gethostbyname(char *); | 150 | struct hostent *ht_gethostbyname(char *); | |
151 | struct hostent *ht_gethostbyaddr(const char *, int, int); | 151 | struct hostent *ht_gethostbyaddr(const char *, int, int); | |
152 | void dns_service(void); | 152 | void dns_service(void); | |
153 | #undef dn_skipname | 153 | #undef dn_skipname | |
154 | int dn_skipname(const u_char *, const u_char *); | 154 | int dn_skipname(const u_char *, const u_char *); | |
155 | int _gethtbyaddr(void *, void *, va_list); | 155 | int _gethtbyaddr(void *, void *, va_list); | |
156 | int _gethtbyname(void *, void *, va_list); | 156 | int _gethtbyname(void *, void *, va_list); | |
157 | struct hostent *_gethtbyname2(const char *, int); | 157 | struct hostent *_gethtbyname2(const char *, int); | |
158 | int _dns_gethtbyaddr(void *, void *, va_list); | 158 | int _dns_gethtbyaddr(void *, void *, va_list); | |
159 | int _dns_gethtbyname(void *, void *, va_list); | 159 | int _dns_gethtbyname(void *, void *, va_list); | |
160 | #ifdef YP | 160 | #ifdef YP | |
161 | struct hostent *_yphostent(char *, int); | 161 | struct hostent *_yphostent(char *, int); | |
162 | int _yp_gethtbyaddr(void *, void *, va_list); | 162 | int _yp_gethtbyaddr(void *, void *, va_list); | |
163 | int _yp_gethtbyname(void *, void *, va_list); | 163 | int _yp_gethtbyname(void *, void *, va_list); | |
164 | #endif | 164 | #endif | |
165 | 165 | |||
166 | static struct hostent *gethostbyname_internal(const char *, int, res_state); | 166 | static struct hostent *gethostbyname_internal(const char *, int, res_state); | |
167 | 167 | |||
168 | static const ns_src default_dns_files[] = { | 168 | static const ns_src default_dns_files[] = { | |
169 | { NSSRC_FILES, NS_SUCCESS }, | 169 | { NSSRC_FILES, NS_SUCCESS }, | |
170 | { NSSRC_DNS, NS_SUCCESS }, | 170 | { NSSRC_DNS, NS_SUCCESS }, | |
171 | { 0, 0 } | 171 | { 0, 0 } | |
172 | }; | 172 | }; | |
173 | 173 | |||
174 | 174 | |||
175 | #ifdef DEBUG | 175 | #ifdef DEBUG | |
176 | static void | 176 | static void | |
177 | dprintf(const char *msg, res_state res, ...) | 177 | dprintf(const char *msg, res_state res, ...) | |
178 | { | 178 | { | |
179 | _DIAGASSERT(msg != NULL); | 179 | _DIAGASSERT(msg != NULL); | |
180 | 180 | |||
181 | if (res->options & RES_DEBUG) { | 181 | if (res->options & RES_DEBUG) { | |
182 | int save = errno; | 182 | int save = errno; | |
183 | va_list ap; | 183 | va_list ap; | |
184 | 184 | |||
185 | va_start (ap, res); | 185 | va_start (ap, res); | |
186 | vprintf(msg, ap); | 186 | vprintf(msg, ap); | |
187 | va_end (ap); | 187 | va_end (ap); | |
188 | 188 | |||
189 | errno = save; | 189 | errno = save; | |
190 | } | 190 | } | |
191 | } | 191 | } | |
192 | #else | 192 | #else | |
193 | # define dprintf(msg, res, num) /*nada*/ | 193 | # define dprintf(msg, res, num) /*nada*/ | |
194 | #endif | 194 | #endif | |
195 | 195 | |||
196 | #define BOUNDED_INCR(x) \ | 196 | #define BOUNDED_INCR(x) \ | |
197 | do { \ | 197 | do { \ | |
198 | cp += (x); \ | 198 | cp += (x); \ | |
199 | if (cp > eom) { \ | 199 | if (cp > eom) { \ | |
200 | h_errno = NO_RECOVERY; \ | 200 | h_errno = NO_RECOVERY; \ | |
201 | return NULL; \ | 201 | return NULL; \ | |
202 | } \ | 202 | } \ | |
203 | } while (/*CONSTCOND*/0) | 203 | } while (/*CONSTCOND*/0) | |
204 | 204 | |||
205 | #define BOUNDS_CHECK(ptr, count) \ | 205 | #define BOUNDS_CHECK(ptr, count) \ | |
206 | do { \ | 206 | do { \ | |
207 | if ((ptr) + (count) > eom) { \ | 207 | if ((ptr) + (count) > eom) { \ | |
208 | h_errno = NO_RECOVERY; \ | 208 | h_errno = NO_RECOVERY; \ | |
209 | return NULL; \ | 209 | return NULL; \ | |
210 | } \ | 210 | } \ | |
211 | } while (/*CONSTCOND*/0) | 211 | } while (/*CONSTCOND*/0) | |
212 | 212 | |||
213 | static struct hostent * | 213 | static struct hostent * | |
214 | getanswer(const querybuf *answer, int anslen, const char *qname, int qtype, | 214 | getanswer(const querybuf *answer, int anslen, const char *qname, int qtype, | |
215 | res_state res) | 215 | res_state res) | |
216 | { | 216 | { | |
217 | const HEADER *hp; | 217 | const HEADER *hp; | |
218 | const u_char *cp; | 218 | const u_char *cp; | |
219 | int n; | 219 | int n; | |
220 | const u_char *eom, *erdata; | 220 | const u_char *eom, *erdata; | |
221 | char *bp, **ap, **hap, *ep; | 221 | char *bp, **ap, **hap, *ep; | |
222 | int type, class, ancount, qdcount; | 222 | int type, class, ancount, qdcount; | |
223 | int haveanswer, had_error; | 223 | int haveanswer, had_error; | |
224 | int toobig = 0; | 224 | int toobig = 0; | |
225 | char tbuf[MAXDNAME]; | 225 | char tbuf[MAXDNAME]; | |
226 | const char *tname; | 226 | const char *tname; | |
227 | int (*name_ok)(const char *); | 227 | int (*name_ok)(const char *); | |
228 | 228 | |||
229 | _DIAGASSERT(answer != NULL); | 229 | _DIAGASSERT(answer != NULL); | |
230 | _DIAGASSERT(qname != NULL); | 230 | _DIAGASSERT(qname != NULL); | |
231 | 231 | |||
232 | tname = qname; | 232 | tname = qname; | |
233 | host.h_name = NULL; | 233 | host.h_name = NULL; | |
234 | eom = answer->buf + anslen; | 234 | eom = answer->buf + anslen; | |
235 | switch (qtype) { | 235 | switch (qtype) { | |
236 | case T_A: | 236 | case T_A: | |
237 | case T_AAAA: | 237 | case T_AAAA: | |
238 | name_ok = res_hnok; | 238 | name_ok = res_hnok; | |
239 | break; | 239 | break; | |
240 | case T_PTR: | 240 | case T_PTR: | |
241 | name_ok = res_dnok; | 241 | name_ok = res_dnok; | |
242 | break; | 242 | break; | |
243 | default: | 243 | default: | |
244 | return NULL; /* XXX should be abort(); */ | 244 | return NULL; /* XXX should be abort(); */ | |
245 | } | 245 | } | |
246 | /* | 246 | /* | |
247 | * find first satisfactory answer | 247 | * find first satisfactory answer | |
248 | */ | 248 | */ | |
249 | hp = &answer->hdr; | 249 | hp = &answer->hdr; | |
250 | ancount = ntohs(hp->ancount); | 250 | ancount = ntohs(hp->ancount); | |
251 | qdcount = ntohs(hp->qdcount); | 251 | qdcount = ntohs(hp->qdcount); | |
252 | bp = hostbuf; | 252 | bp = hostbuf; | |
253 | ep = hostbuf + sizeof hostbuf; | 253 | ep = hostbuf + sizeof hostbuf; | |
254 | cp = answer->buf; | 254 | cp = answer->buf; | |
255 | BOUNDED_INCR(HFIXEDSZ); | 255 | BOUNDED_INCR(HFIXEDSZ); | |
256 | if (qdcount != 1) { | 256 | if (qdcount != 1) { | |
257 | h_errno = NO_RECOVERY; | 257 | h_errno = NO_RECOVERY; | |
258 | return NULL; | 258 | return NULL; | |
259 | } | 259 | } | |
260 | n = dn_expand(answer->buf, eom, cp, bp, ep - bp); | 260 | n = dn_expand(answer->buf, eom, cp, bp, ep - bp); | |
261 | if ((n < 0) || !(*name_ok)(bp)) { | 261 | if ((n < 0) || !(*name_ok)(bp)) { | |
262 | h_errno = NO_RECOVERY; | 262 | h_errno = NO_RECOVERY; | |
263 | return NULL; | 263 | return NULL; | |
264 | } | 264 | } | |
265 | BOUNDED_INCR(n + QFIXEDSZ); | 265 | BOUNDED_INCR(n + QFIXEDSZ); | |
266 | if (qtype == T_A || qtype == T_AAAA) { | 266 | if (qtype == T_A || qtype == T_AAAA) { | |
267 | /* res_send() has already verified that the query name is the | 267 | /* res_send() has already verified that the query name is the | |
268 | * same as the one we sent; this just gets the expanded name | 268 | * same as the one we sent; this just gets the expanded name | |
269 | * (i.e., with the succeeding search-domain tacked on). | 269 | * (i.e., with the succeeding search-domain tacked on). | |
270 | */ | 270 | */ | |
271 | n = strlen(bp) + 1; /* for the \0 */ | 271 | n = strlen(bp) + 1; /* for the \0 */ | |
272 | if (n >= MAXHOSTNAMELEN) { | 272 | if (n >= MAXHOSTNAMELEN) { | |
273 | h_errno = NO_RECOVERY; | 273 | h_errno = NO_RECOVERY; | |
274 | return NULL; | 274 | return NULL; | |
275 | } | 275 | } | |
276 | host.h_name = bp; | 276 | host.h_name = bp; | |
277 | bp += n; | 277 | bp += n; | |
278 | /* The qname can be abbreviated, but h_name is now absolute. */ | 278 | /* The qname can be abbreviated, but h_name is now absolute. */ | |
279 | qname = host.h_name; | 279 | qname = host.h_name; | |
280 | } | 280 | } | |
281 | ap = host_aliases; | 281 | ap = host_aliases; | |
282 | *ap = NULL; | 282 | *ap = NULL; | |
283 | host.h_aliases = host_aliases; | 283 | host.h_aliases = host_aliases; | |
284 | hap = h_addr_ptrs; | 284 | hap = h_addr_ptrs; | |
285 | *hap = NULL; | 285 | *hap = NULL; | |
286 | host.h_addr_list = h_addr_ptrs; | 286 | host.h_addr_list = h_addr_ptrs; | |
287 | haveanswer = 0; | 287 | haveanswer = 0; | |
288 | had_error = 0; | 288 | had_error = 0; | |
289 | while (ancount-- > 0 && cp < eom && !had_error) { | 289 | while (ancount-- > 0 && cp < eom && !had_error) { | |
290 | n = dn_expand(answer->buf, eom, cp, bp, ep - bp); | 290 | n = dn_expand(answer->buf, eom, cp, bp, ep - bp); | |
291 | if ((n < 0) || !(*name_ok)(bp)) { | 291 | if ((n < 0) || !(*name_ok)(bp)) { | |
292 | had_error++; | 292 | had_error++; | |
293 | continue; | 293 | continue; | |
294 | } | 294 | } | |
295 | cp += n; /* name */ | 295 | cp += n; /* name */ | |
296 | BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ); | 296 | BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ); | |
297 | type = _getshort(cp); | 297 | type = _getshort(cp); | |
298 | cp += INT16SZ; /* type */ | 298 | cp += INT16SZ; /* type */ | |
299 | class = _getshort(cp); | 299 | class = _getshort(cp); | |
300 | cp += INT16SZ + INT32SZ; /* class, TTL */ | 300 | cp += INT16SZ + INT32SZ; /* class, TTL */ | |
301 | n = _getshort(cp); | 301 | n = _getshort(cp); | |
302 | cp += INT16SZ; /* len */ | 302 | cp += INT16SZ; /* len */ | |
303 | BOUNDS_CHECK(cp, n); | 303 | BOUNDS_CHECK(cp, n); | |
304 | erdata = cp + n; | 304 | erdata = cp + n; | |
305 | if (class != C_IN) { | 305 | if (class != C_IN) { | |
306 | /* XXX - debug? syslog? */ | 306 | /* XXX - debug? syslog? */ | |
307 | cp += n; | 307 | cp += n; | |
308 | continue; /* XXX - had_error++ ? */ | 308 | continue; /* XXX - had_error++ ? */ | |
309 | } | 309 | } | |
310 | if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) { | 310 | if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) { | |
311 | if (ap >= &host_aliases[MAXALIASES-1]) | 311 | if (ap >= &host_aliases[MAXALIASES-1]) | |
312 | continue; | 312 | continue; | |
313 | n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); | 313 | n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); | |
314 | if ((n < 0) || !(*name_ok)(tbuf)) { | 314 | if ((n < 0) || !(*name_ok)(tbuf)) { | |
315 | had_error++; | 315 | had_error++; | |
316 | continue; | 316 | continue; | |
317 | } | 317 | } | |
318 | cp += n; | 318 | cp += n; | |
319 | if (cp != erdata) { | 319 | if (cp != erdata) { | |
320 | h_errno = NO_RECOVERY; | 320 | h_errno = NO_RECOVERY; | |
321 | return NULL; | 321 | return NULL; | |
322 | } | 322 | } | |
323 | /* Store alias. */ | 323 | /* Store alias. */ | |
324 | *ap++ = bp; | 324 | *ap++ = bp; | |
325 | n = strlen(bp) + 1; /* for the \0 */ | 325 | n = strlen(bp) + 1; /* for the \0 */ | |
326 | if (n >= MAXHOSTNAMELEN) { | 326 | if (n >= MAXHOSTNAMELEN) { | |
327 | had_error++; | 327 | had_error++; | |
328 | continue; | 328 | continue; | |
329 | } | 329 | } | |
330 | bp += n; | 330 | bp += n; | |
331 | /* Get canonical name. */ | 331 | /* Get canonical name. */ | |
332 | n = strlen(tbuf) + 1; /* for the \0 */ | 332 | n = strlen(tbuf) + 1; /* for the \0 */ | |
333 | if (n > ep - bp || n >= MAXHOSTNAMELEN) { | 333 | if (n > ep - bp || n >= MAXHOSTNAMELEN) { | |
334 | had_error++; | 334 | had_error++; | |
335 | continue; | 335 | continue; | |
336 | } | 336 | } | |
337 | strlcpy(bp, tbuf, (size_t)(ep - bp)); | 337 | strlcpy(bp, tbuf, (size_t)(ep - bp)); | |
338 | host.h_name = bp; | 338 | host.h_name = bp; | |
339 | bp += n; | 339 | bp += n; | |
340 | continue; | 340 | continue; | |
341 | } | 341 | } | |
342 | if (qtype == T_PTR && type == T_CNAME) { | 342 | if (qtype == T_PTR && type == T_CNAME) { | |
343 | n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); | 343 | n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); | |
344 | if (n < 0 || !res_dnok(tbuf)) { | 344 | if (n < 0 || !res_dnok(tbuf)) { | |
345 | had_error++; | 345 | had_error++; | |
346 | continue; | 346 | continue; | |
347 | } | 347 | } | |
348 | cp += n; | 348 | cp += n; | |
349 | if (cp != erdata) { | 349 | if (cp != erdata) { | |
350 | h_errno = NO_RECOVERY; | 350 | h_errno = NO_RECOVERY; | |
351 | return NULL; | 351 | return NULL; | |
352 | } | 352 | } | |
353 | /* Get canonical name. */ | 353 | /* Get canonical name. */ | |
354 | n = strlen(tbuf) + 1; /* for the \0 */ | 354 | n = strlen(tbuf) + 1; /* for the \0 */ | |
355 | if (n > ep - bp || n >= MAXHOSTNAMELEN) { | 355 | if (n > ep - bp || n >= MAXHOSTNAMELEN) { | |
356 | had_error++; | 356 | had_error++; | |
357 | continue; | 357 | continue; | |
358 | } | 358 | } | |
359 | strlcpy(bp, tbuf, (size_t)(ep - bp)); | 359 | strlcpy(bp, tbuf, (size_t)(ep - bp)); | |
360 | tname = bp; | 360 | tname = bp; | |
361 | bp += n; | 361 | bp += n; | |
362 | continue; | 362 | continue; | |
363 | } | 363 | } | |
364 | if (type != qtype) { | 364 | if (type != qtype) { | |
365 | if (type != T_KEY && type != T_SIG) | 365 | if (type != T_KEY && type != T_SIG) | |
366 | syslog(LOG_NOTICE|LOG_AUTH, | 366 | syslog(LOG_NOTICE|LOG_AUTH, | |
367 | "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"", | 367 | "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"", | |
368 | qname, p_class(C_IN), p_type(qtype), | 368 | qname, p_class(C_IN), p_type(qtype), | |
369 | p_type(type)); | 369 | p_type(type)); | |
370 | cp += n; | 370 | cp += n; | |
371 | continue; /* XXX - had_error++ ? */ | 371 | continue; /* XXX - had_error++ ? */ | |
372 | } | 372 | } | |
373 | switch (type) { | 373 | switch (type) { | |
374 | case T_PTR: | 374 | case T_PTR: | |
375 | if (strcasecmp(tname, bp) != 0) { | 375 | if (strcasecmp(tname, bp) != 0) { | |
376 | syslog(LOG_NOTICE|LOG_AUTH, | 376 | syslog(LOG_NOTICE|LOG_AUTH, | |
377 | AskedForGot, qname, bp); | 377 | AskedForGot, qname, bp); | |
378 | cp += n; | 378 | cp += n; | |
379 | continue; /* XXX - had_error++ ? */ | 379 | continue; /* XXX - had_error++ ? */ | |
380 | } | 380 | } | |
381 | n = dn_expand(answer->buf, eom, cp, bp, ep - bp); | 381 | n = dn_expand(answer->buf, eom, cp, bp, ep - bp); | |
382 | if ((n < 0) || !res_hnok(bp)) { | 382 | if ((n < 0) || !res_hnok(bp)) { | |
383 | had_error++; | 383 | had_error++; | |
384 | break; | 384 | break; | |
385 | } | 385 | } | |
386 | #if MULTI_PTRS_ARE_ALIASES | 386 | #if MULTI_PTRS_ARE_ALIASES | |
387 | cp += n; | 387 | cp += n; | |
388 | if (cp != erdata) { | 388 | if (cp != erdata) { | |
389 | h_errno = NO_RECOVERY; | 389 | h_errno = NO_RECOVERY; | |
390 | return NULL; | 390 | return NULL; | |
391 | } | 391 | } | |
392 | if (!haveanswer) | 392 | if (!haveanswer) | |
393 | host.h_name = bp; | 393 | host.h_name = bp; | |
394 | else if (ap < &host_aliases[MAXALIASES-1]) | 394 | else if (ap < &host_aliases[MAXALIASES-1]) | |
395 | *ap++ = bp; | 395 | *ap++ = bp; | |
396 | else | 396 | else | |
397 | n = -1; | 397 | n = -1; | |
398 | if (n != -1) { | 398 | if (n != -1) { | |
399 | n = strlen(bp) + 1; /* for the \0 */ | 399 | n = strlen(bp) + 1; /* for the \0 */ | |
400 | if (n >= MAXHOSTNAMELEN) { | 400 | if (n >= MAXHOSTNAMELEN) { | |
401 | had_error++; | 401 | had_error++; | |
402 | break; | 402 | break; | |
403 | } | 403 | } | |
404 | bp += n; | 404 | bp += n; | |
405 | } | 405 | } | |
406 | break; | 406 | break; | |
407 | #else | 407 | #else | |
408 | host.h_name = bp; | 408 | host.h_name = bp; | |
409 | if (res->options & RES_USE_INET6) { | 409 | if (res->options & RES_USE_INET6) { | |
410 | n = strlen(bp) + 1; /* for the \0 */ | 410 | n = strlen(bp) + 1; /* for the \0 */ | |
411 | if (n >= MAXHOSTNAMELEN) { | 411 | if (n >= MAXHOSTNAMELEN) { | |
412 | had_error++; | 412 | had_error++; | |
413 | break; | 413 | break; | |
414 | } | 414 | } | |
415 | bp += n; | 415 | bp += n; | |
416 | map_v4v6_hostent(&host, &bp, ep); | 416 | map_v4v6_hostent(&host, &bp, ep); | |
417 | } | 417 | } | |
418 | h_errno = NETDB_SUCCESS; | 418 | h_errno = NETDB_SUCCESS; | |
419 | return &host; | 419 | return &host; | |
420 | #endif | 420 | #endif | |
421 | case T_A: | 421 | case T_A: | |
422 | case T_AAAA: | 422 | case T_AAAA: | |
423 | if (strcasecmp(host.h_name, bp) != 0) { | 423 | if (strcasecmp(host.h_name, bp) != 0) { | |
424 | syslog(LOG_NOTICE|LOG_AUTH, | 424 | syslog(LOG_NOTICE|LOG_AUTH, | |
425 | AskedForGot, host.h_name, bp); | 425 | AskedForGot, host.h_name, bp); | |
426 | cp += n; | 426 | cp += n; | |
427 | continue; /* XXX - had_error++ ? */ | 427 | continue; /* XXX - had_error++ ? */ | |
428 | } | 428 | } | |
429 | if (n != host.h_length) { | 429 | if (n != host.h_length) { | |
430 | cp += n; | 430 | cp += n; | |
431 | continue; | 431 | continue; | |
432 | } | 432 | } | |
433 | if (type == T_AAAA) { | 433 | if (type == T_AAAA) { | |
434 | struct in6_addr in6; | 434 | struct in6_addr in6; | |
435 | memcpy(&in6, cp, IN6ADDRSZ); | 435 | memcpy(&in6, cp, IN6ADDRSZ); | |
436 | if (IN6_IS_ADDR_V4MAPPED(&in6)) { | 436 | if (IN6_IS_ADDR_V4MAPPED(&in6)) { | |
437 | cp += n; | 437 | cp += n; | |
438 | continue; | 438 | continue; | |
439 | } | 439 | } | |
440 | } | 440 | } | |
441 | if (!haveanswer) { | 441 | if (!haveanswer) { | |
442 | int nn; | 442 | int nn; | |
443 | 443 | |||
444 | host.h_name = bp; | 444 | host.h_name = bp; | |
445 | nn = strlen(bp) + 1; /* for the \0 */ | 445 | nn = strlen(bp) + 1; /* for the \0 */ | |
446 | bp += nn; | 446 | bp += nn; | |
447 | } | 447 | } | |
448 | 448 | |||
449 | bp += sizeof(align) - | 449 | bp += sizeof(align) - | |
450 | (size_t)((u_long)bp % sizeof(align)); | 450 | (size_t)((u_long)bp % sizeof(align)); | |
451 | 451 | |||
452 | if (bp + n >= &hostbuf[sizeof hostbuf]) { | 452 | if (bp + n >= &hostbuf[sizeof hostbuf]) { | |
453 | dprintf("size (%d) too big\n", res, n); | 453 | dprintf("size (%d) too big\n", res, n); | |
454 | had_error++; | 454 | had_error++; | |
455 | continue; | 455 | continue; | |
456 | } | 456 | } | |
457 | if (hap >= &h_addr_ptrs[MAXADDRS-1]) { | 457 | if (hap >= &h_addr_ptrs[MAXADDRS-1]) { | |
458 | if (!toobig++) { | 458 | if (!toobig++) { | |
459 | dprintf("Too many addresses (%d)\n", | 459 | dprintf("Too many addresses (%d)\n", | |
460 | res, MAXADDRS); | 460 | res, MAXADDRS); | |
461 | } | 461 | } | |
462 | cp += n; | 462 | cp += n; | |
463 | continue; | 463 | continue; | |
464 | } | 464 | } | |
465 | (void)memcpy(*hap++ = bp, cp, (size_t)n); | 465 | (void)memcpy(*hap++ = bp, cp, (size_t)n); | |
466 | bp += n; | 466 | bp += n; | |
467 | cp += n; | 467 | cp += n; | |
468 | if (cp != erdata) { | 468 | if (cp != erdata) { | |
469 | h_errno = NO_RECOVERY; | 469 | h_errno = NO_RECOVERY; | |
470 | return NULL; | 470 | return NULL; | |
471 | } | 471 | } | |
472 | break; | 472 | break; | |
473 | default: | 473 | default: | |
474 | abort(); | 474 | abort(); | |
475 | } | 475 | } | |
476 | if (!had_error) | 476 | if (!had_error) | |
477 | haveanswer++; | 477 | haveanswer++; | |
478 | } | 478 | } | |
479 | if (haveanswer) { | 479 | if (haveanswer) { | |
480 | *ap = NULL; | 480 | *ap = NULL; | |
481 | *hap = NULL; | 481 | *hap = NULL; | |
482 | /* | 482 | /* | |
483 | * Note: we sort even if host can take only one address | 483 | * Note: we sort even if host can take only one address | |
484 | * in its return structures - should give it the "best" | 484 | * in its return structures - should give it the "best" | |
485 | * address in that case, not some random one | 485 | * address in that case, not some random one | |
486 | */ | 486 | */ | |
487 | if (res->nsort && haveanswer > 1 && qtype == T_A) | 487 | if (res->nsort && haveanswer > 1 && qtype == T_A) | |
488 | addrsort(h_addr_ptrs, haveanswer, res); | 488 | addrsort(h_addr_ptrs, haveanswer, res); | |
489 | if (!host.h_name) { | 489 | if (!host.h_name) { | |
490 | n = strlen(qname) + 1; /* for the \0 */ | 490 | n = strlen(qname) + 1; /* for the \0 */ | |
491 | if (n > ep - bp || n >= MAXHOSTNAMELEN) | 491 | if (n > ep - bp || n >= MAXHOSTNAMELEN) | |
492 | goto no_recovery; | 492 | goto no_recovery; | |
493 | strlcpy(bp, qname, (size_t)(ep - bp)); | 493 | strlcpy(bp, qname, (size_t)(ep - bp)); | |
494 | host.h_name = bp; | 494 | host.h_name = bp; | |
495 | bp += n; | 495 | bp += n; | |
496 | } | 496 | } | |
497 | if (res->options & RES_USE_INET6) | 497 | if (res->options & RES_USE_INET6) | |
498 | map_v4v6_hostent(&host, &bp, ep); | 498 | map_v4v6_hostent(&host, &bp, ep); | |
499 | h_errno = NETDB_SUCCESS; | 499 | h_errno = NETDB_SUCCESS; | |
500 | return &host; | 500 | return &host; | |
501 | } | 501 | } | |
502 | no_recovery: | 502 | no_recovery: | |
503 | h_errno = NO_RECOVERY; | 503 | h_errno = NO_RECOVERY; | |
504 | return NULL; | 504 | return NULL; | |
505 | } | 505 | } | |
506 | 506 | |||
507 | struct hostent * | 507 | struct hostent * | |
508 | gethostbyname(const char *name) | 508 | gethostbyname(const char *name) | |
509 | { | 509 | { | |
510 | struct hostent *hp; | 510 | struct hostent *hp; | |
511 | res_state res = __res_get_state(); | 511 | res_state res = __res_get_state(); | |
512 | 512 | |||
513 | if (res == NULL) | 513 | if (res == NULL) | |
514 | return NULL; | 514 | return NULL; | |
515 | 515 | |||
516 | _DIAGASSERT(name != NULL); | 516 | _DIAGASSERT(name != NULL); | |
517 | 517 | |||
518 | if (res->options & RES_USE_INET6) { | 518 | if (res->options & RES_USE_INET6) { | |
519 | hp = gethostbyname_internal(name, AF_INET6, res); | 519 | hp = gethostbyname_internal(name, AF_INET6, res); | |
520 | if (hp) { | 520 | if (hp) { | |
521 | __res_put_state(res); | 521 | __res_put_state(res); | |
522 | return hp; | 522 | return hp; | |
523 | } | 523 | } | |
524 | } | 524 | } | |
525 | hp = gethostbyname_internal(name, AF_INET, res); | 525 | hp = gethostbyname_internal(name, AF_INET, res); | |
526 | __res_put_state(res); | 526 | __res_put_state(res); | |
527 | return hp; | 527 | return hp; | |
528 | } | 528 | } | |
529 | 529 | |||
530 | struct hostent * | 530 | struct hostent * | |
531 | gethostbyname2(const char *name, int af) | 531 | gethostbyname2(const char *name, int af) | |
532 | { | 532 | { | |
533 | struct hostent *hp; | 533 | struct hostent *hp; | |
534 | res_state res = __res_get_state(); | 534 | res_state res = __res_get_state(); | |
535 | 535 | |||
536 | if (res == NULL) | 536 | if (res == NULL) | |
537 | return NULL; | 537 | return NULL; | |
538 | hp = gethostbyname_internal(name, af, res); | 538 | hp = gethostbyname_internal(name, af, res); | |
539 | __res_put_state(res); | 539 | __res_put_state(res); | |
540 | return hp; | 540 | return hp; | |
541 | } | 541 | } | |
542 | 542 | |||
543 | static struct hostent * | 543 | static struct hostent * | |
544 | gethostbyname_internal(const char *name, int af, res_state res) | 544 | gethostbyname_internal(const char *name, int af, res_state res) | |
545 | { | 545 | { | |
546 | const char *cp; | 546 | const char *cp; | |
547 | char *bp, *ep; | 547 | char *bp, *ep; | |
548 | int size; | 548 | int size; | |
549 | struct hostent *hp; | 549 | struct hostent *hp; | |
550 | static const ns_dtab dtab[] = { | 550 | static const ns_dtab dtab[] = { | |
551 | NS_FILES_CB(_gethtbyname, NULL) | 551 | NS_FILES_CB(_gethtbyname, NULL) | |
552 | { NSSRC_DNS, _dns_gethtbyname, NULL }, /* force -DHESIOD */ | 552 | { NSSRC_DNS, _dns_gethtbyname, NULL }, /* force -DHESIOD */ | |
553 | NS_NIS_CB(_yp_gethtbyname, NULL) | 553 | NS_NIS_CB(_yp_gethtbyname, NULL) | |
554 | NS_NULL_CB | 554 | NS_NULL_CB | |
555 | }; | 555 | }; | |
556 | 556 | |||
557 | _DIAGASSERT(name != NULL); | 557 | _DIAGASSERT(name != NULL); | |
558 | 558 | |||
559 | switch (af) { | 559 | switch (af) { | |
560 | case AF_INET: | 560 | case AF_INET: | |
561 | size = INADDRSZ; | 561 | size = INADDRSZ; | |
562 | break; | 562 | break; | |
563 | case AF_INET6: | 563 | case AF_INET6: | |
564 | size = IN6ADDRSZ; | 564 | size = IN6ADDRSZ; | |
565 | break; | 565 | break; | |
566 | default: | 566 | default: | |
567 | h_errno = NETDB_INTERNAL; | 567 | h_errno = NETDB_INTERNAL; | |
568 | errno = EAFNOSUPPORT; | 568 | errno = EAFNOSUPPORT; | |
569 | return NULL; | 569 | return NULL; | |
570 | } | 570 | } | |
571 | 571 | |||
572 | host.h_addrtype = af; | 572 | host.h_addrtype = af; | |
573 | host.h_length = size; | 573 | host.h_length = size; | |
574 | 574 | |||
575 | /* | 575 | /* | |
576 | * if there aren't any dots, it could be a user-level alias. | 576 | * if there aren't any dots, it could be an user-level alias. | |
577 | * this is also done in res_nquery() since we are not the only | 577 | * this is also done in res_nquery() since we are not the only | |
578 | * function that looks up host names. | 578 | * function that looks up host names. | |
579 | */ | 579 | */ | |
580 | if (!strchr(name, '.') && (cp = __hostalias(name))) | 580 | if (!strchr(name, '.') && (cp = __hostalias(name))) | |
581 | name = cp; | 581 | name = cp; | |
582 | 582 | |||
583 | /* | 583 | /* | |
584 | * disallow names consisting only of digits/dots, unless | 584 | * disallow names consisting only of digits/dots, unless | |
585 | * they end in a dot. | 585 | * they end in a dot. | |
586 | */ | 586 | */ | |
587 | if (isdigit((u_char) name[0])) | 587 | if (isdigit((u_char) name[0])) | |
588 | for (cp = name;; ++cp) { | 588 | for (cp = name;; ++cp) { | |
589 | if (!*cp) { | 589 | if (!*cp) { | |
590 | if (*--cp == '.') | 590 | if (*--cp == '.') | |
591 | break; | 591 | break; | |
592 | /* | 592 | /* | |
593 | * All-numeric, no dot at the end. | 593 | * All-numeric, no dot at the end. | |
594 | * Fake up a hostent as if we'd actually | 594 | * Fake up a hostent as if we'd actually | |
595 | * done a lookup. | 595 | * done a lookup. | |
596 | */ | 596 | */ | |
597 | if (inet_pton(af, name, | 597 | if (inet_pton(af, name, | |
598 | (char *)(void *)host_addr) <= 0) { | 598 | (char *)(void *)host_addr) <= 0) { | |
599 | h_errno = HOST_NOT_FOUND; | 599 | h_errno = HOST_NOT_FOUND; | |
600 | return NULL; | 600 | return NULL; | |
601 | } | 601 | } | |
602 | strncpy(hostbuf, name, MAXDNAME); | 602 | strncpy(hostbuf, name, MAXDNAME); | |
603 | hostbuf[MAXDNAME] = '\0'; | 603 | hostbuf[MAXDNAME] = '\0'; | |
604 | bp = hostbuf + MAXDNAME; | 604 | bp = hostbuf + MAXDNAME; | |
605 | ep = hostbuf + sizeof hostbuf; | 605 | ep = hostbuf + sizeof hostbuf; | |
606 | host.h_name = hostbuf; | 606 | host.h_name = hostbuf; | |
607 | host.h_aliases = host_aliases; | 607 | host.h_aliases = host_aliases; | |
608 | host_aliases[0] = NULL; | 608 | host_aliases[0] = NULL; | |
609 | h_addr_ptrs[0] = (char *)(void *)host_addr; | 609 | h_addr_ptrs[0] = (char *)(void *)host_addr; | |
610 | h_addr_ptrs[1] = NULL; | 610 | h_addr_ptrs[1] = NULL; | |
611 | host.h_addr_list = h_addr_ptrs; | 611 | host.h_addr_list = h_addr_ptrs; | |
612 | if (res->options & RES_USE_INET6) | 612 | if (res->options & RES_USE_INET6) | |
613 | map_v4v6_hostent(&host, &bp, ep); | 613 | map_v4v6_hostent(&host, &bp, ep); | |
614 | h_errno = NETDB_SUCCESS; | 614 | h_errno = NETDB_SUCCESS; | |
615 | return &host; | 615 | return &host; | |
616 | } | 616 | } | |
617 | if (!isdigit((u_char) *cp) && *cp != '.') | 617 | if (!isdigit((u_char) *cp) && *cp != '.') | |
618 | break; | 618 | break; | |
619 | } | 619 | } | |
620 | if ((isxdigit((u_char) name[0]) && strchr(name, ':') != NULL) || | 620 | if ((isxdigit((u_char) name[0]) && strchr(name, ':') != NULL) || | |
621 | name[0] == ':') | 621 | name[0] == ':') | |
622 | for (cp = name;; ++cp) { | 622 | for (cp = name;; ++cp) { | |
623 | if (!*cp) { | 623 | if (!*cp) { | |
624 | if (*--cp == '.') | 624 | if (*--cp == '.') | |
625 | break; | 625 | break; | |
626 | /* | 626 | /* | |
627 | * All-IPv6-legal, no dot at the end. | 627 | * All-IPv6-legal, no dot at the end. | |
628 | * Fake up a hostent as if we'd actually | 628 | * Fake up a hostent as if we'd actually | |
629 | * done a lookup. | 629 | * done a lookup. | |
630 | */ | 630 | */ | |
631 | if (inet_pton(af, name, | 631 | if (inet_pton(af, name, | |
632 | (char *)(void *)host_addr) <= 0) { | 632 | (char *)(void *)host_addr) <= 0) { | |
633 | h_errno = HOST_NOT_FOUND; | 633 | h_errno = HOST_NOT_FOUND; | |
634 | return NULL; | 634 | return NULL; | |
635 | } | 635 | } | |
636 | strncpy(hostbuf, name, MAXDNAME); | 636 | strncpy(hostbuf, name, MAXDNAME); | |
637 | hostbuf[MAXDNAME] = '\0'; | 637 | hostbuf[MAXDNAME] = '\0'; | |
638 | bp = hostbuf + MAXDNAME; | 638 | bp = hostbuf + MAXDNAME; | |
639 | ep = hostbuf + sizeof hostbuf; | 639 | ep = hostbuf + sizeof hostbuf; | |
640 | host.h_name = hostbuf; | 640 | host.h_name = hostbuf; | |
641 | host.h_aliases = host_aliases; | 641 | host.h_aliases = host_aliases; | |
642 | host_aliases[0] = NULL; | 642 | host_aliases[0] = NULL; | |
643 | h_addr_ptrs[0] = (char *)(void *)host_addr; | 643 | h_addr_ptrs[0] = (char *)(void *)host_addr; | |
644 | h_addr_ptrs[1] = NULL; | 644 | h_addr_ptrs[1] = NULL; | |
645 | host.h_addr_list = h_addr_ptrs; | 645 | host.h_addr_list = h_addr_ptrs; | |
646 | h_errno = NETDB_SUCCESS; | 646 | h_errno = NETDB_SUCCESS; | |
647 | return &host; | 647 | return &host; | |
648 | } | 648 | } | |
649 | if (!isxdigit((u_char) *cp) && *cp != ':' && *cp != '.') | 649 | if (!isxdigit((u_char) *cp) && *cp != ':' && *cp != '.') | |
650 | break; | 650 | break; | |
651 | } | 651 | } | |
652 | 652 | |||
653 | hp = NULL; | 653 | hp = NULL; | |
654 | h_errno = NETDB_INTERNAL; | 654 | h_errno = NETDB_INTERNAL; | |
655 | if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyname", | 655 | if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyname", | |
656 | default_dns_files, name, strlen(name), af) != NS_SUCCESS) | 656 | default_dns_files, name, strlen(name), af) != NS_SUCCESS) | |
657 | return NULL; | 657 | return NULL; | |
658 | h_errno = NETDB_SUCCESS; | 658 | h_errno = NETDB_SUCCESS; | |
659 | return hp; | 659 | return hp; | |
660 | } | 660 | } | |
661 | 661 | |||
662 | struct hostent * | 662 | struct hostent * | |
663 | gethostbyaddr(const char *addr, /* XXX should have been def'd as u_char! */ | 663 | gethostbyaddr(const char *addr, /* XXX should have been def'd as u_char! */ | |
664 | socklen_t len, int af) | 664 | socklen_t len, int af) | |
665 | { | 665 | { | |
666 | const u_char *uaddr = (const u_char *)addr; | 666 | const u_char *uaddr = (const u_char *)addr; | |
667 | socklen_t size; | 667 | socklen_t size; | |
668 | struct hostent *hp; | 668 | struct hostent *hp; | |
669 | static const ns_dtab dtab[] = { | 669 | static const ns_dtab dtab[] = { | |
670 | NS_FILES_CB(_gethtbyaddr, NULL) | 670 | NS_FILES_CB(_gethtbyaddr, NULL) | |
671 | { NSSRC_DNS, _dns_gethtbyaddr, NULL }, /* force -DHESIOD */ | 671 | { NSSRC_DNS, _dns_gethtbyaddr, NULL }, /* force -DHESIOD */ | |
672 | NS_NIS_CB(_yp_gethtbyaddr, NULL) | 672 | NS_NIS_CB(_yp_gethtbyaddr, NULL) | |
673 | NS_NULL_CB | 673 | NS_NULL_CB | |
674 | }; | 674 | }; | |
675 | 675 | |||
676 | _DIAGASSERT(addr != NULL); | 676 | _DIAGASSERT(addr != NULL); | |
677 | 677 | |||
678 | if (af == AF_INET6 && len == IN6ADDRSZ && | 678 | if (af == AF_INET6 && len == IN6ADDRSZ && | |
679 | (IN6_IS_ADDR_LINKLOCAL((const struct in6_addr *)(const void *)uaddr) || | 679 | (IN6_IS_ADDR_LINKLOCAL((const struct in6_addr *)(const void *)uaddr) || | |
680 | IN6_IS_ADDR_SITELOCAL((const struct in6_addr *)(const void *)uaddr))) { | 680 | IN6_IS_ADDR_SITELOCAL((const struct in6_addr *)(const void *)uaddr))) { | |
681 | h_errno = HOST_NOT_FOUND; | 681 | h_errno = HOST_NOT_FOUND; | |
682 | return NULL; | 682 | return NULL; | |
683 | } | 683 | } | |
684 | if (af == AF_INET6 && len == IN6ADDRSZ && | 684 | if (af == AF_INET6 && len == IN6ADDRSZ && | |
685 | (IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)(const void *)uaddr) || | 685 | (IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)(const void *)uaddr) || | |
686 | IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)(const void *)uaddr))) { | 686 | IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)(const void *)uaddr))) { | |
687 | /* Unmap. */ | 687 | /* Unmap. */ | |
688 | addr += IN6ADDRSZ - INADDRSZ; | 688 | addr += IN6ADDRSZ - INADDRSZ; | |
689 | uaddr += IN6ADDRSZ - INADDRSZ; | 689 | uaddr += IN6ADDRSZ - INADDRSZ; | |
690 | af = AF_INET; | 690 | af = AF_INET; | |
691 | len = INADDRSZ; | 691 | len = INADDRSZ; | |
692 | } | 692 | } | |
693 | switch (af) { | 693 | switch (af) { | |
694 | case AF_INET: | 694 | case AF_INET: | |
695 | size = INADDRSZ; | 695 | size = INADDRSZ; | |
696 | break; | 696 | break; | |
697 | case AF_INET6: | 697 | case AF_INET6: | |
698 | size = IN6ADDRSZ; | 698 | size = IN6ADDRSZ; | |
699 | break; | 699 | break; | |
700 | default: | 700 | default: | |
701 | errno = EAFNOSUPPORT; | 701 | errno = EAFNOSUPPORT; | |
702 | h_errno = NETDB_INTERNAL; | 702 | h_errno = NETDB_INTERNAL; | |
703 | return NULL; | 703 | return NULL; | |
704 | } | 704 | } | |
705 | if (size != len) { | 705 | if (size != len) { | |
706 | errno = EINVAL; | 706 | errno = EINVAL; | |
707 | h_errno = NETDB_INTERNAL; | 707 | h_errno = NETDB_INTERNAL; | |
708 | return NULL; | 708 | return NULL; | |
709 | } | 709 | } | |
710 | hp = NULL; | 710 | hp = NULL; | |
711 | h_errno = NETDB_INTERNAL; | 711 | h_errno = NETDB_INTERNAL; | |
712 | if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyaddr", | 712 | if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyaddr", | |
713 | default_dns_files, uaddr, len, af) != NS_SUCCESS) | 713 | default_dns_files, uaddr, len, af) != NS_SUCCESS) | |
714 | return NULL; | 714 | return NULL; | |
715 | h_errno = NETDB_SUCCESS; | 715 | h_errno = NETDB_SUCCESS; | |
716 | return hp; | 716 | return hp; | |
717 | } | 717 | } | |
718 | 718 | |||
719 | void | 719 | void | |
720 | _sethtent(int f) | 720 | _sethtent(int f) | |
721 | { | 721 | { | |
722 | if (!hostf) | 722 | if (!hostf) | |
723 | hostf = fopen(_PATH_HOSTS, "r" ); | 723 | hostf = fopen(_PATH_HOSTS, "r" ); | |
724 | else | 724 | else | |
725 | rewind(hostf); | 725 | rewind(hostf); | |
726 | stayopen = f; | 726 | stayopen = f; | |
727 | } | 727 | } | |
728 | 728 | |||
729 | void | 729 | void | |
730 | _endhtent(void) | 730 | _endhtent(void) | |
731 | { | 731 | { | |
732 | if (hostf && !stayopen) { | 732 | if (hostf && !stayopen) { | |
733 | (void) fclose(hostf); | 733 | (void) fclose(hostf); | |
734 | hostf = NULL; | 734 | hostf = NULL; | |
735 | } | 735 | } | |
736 | } | 736 | } | |
737 | 737 | |||
738 | struct hostent * | 738 | struct hostent * | |
739 | _gethtent(void) | 739 | _gethtent(void) | |
740 | { | 740 | { | |
741 | char *p; | 741 | char *p; | |
742 | char *cp, **q; | 742 | char *cp, **q; | |
743 | int af, len; | 743 | int af, len; | |
744 | 744 | |||
745 | if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) { | 745 | if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) { | |
746 | h_errno = NETDB_INTERNAL; | 746 | h_errno = NETDB_INTERNAL; | |
747 | return NULL; | 747 | return NULL; | |
748 | } | 748 | } | |
749 | again: | 749 | again: | |
750 | if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) { | 750 | if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) { | |
751 | h_errno = HOST_NOT_FOUND; | 751 | h_errno = HOST_NOT_FOUND; | |
752 | return NULL; | 752 | return NULL; | |
753 | } | 753 | } | |
754 | if (*p == '#') | 754 | if (*p == '#') | |
755 | goto again; | 755 | goto again; | |
756 | if (!(cp = strpbrk(p, "#\n"))) | 756 | if (!(cp = strpbrk(p, "#\n"))) | |
757 | goto again; | 757 | goto again; | |
758 | *cp = '\0'; | 758 | *cp = '\0'; | |
759 | if (!(cp = strpbrk(p, " \t"))) | 759 | if (!(cp = strpbrk(p, " \t"))) | |
760 | goto again; | 760 | goto again; | |
761 | *cp++ = '\0'; | 761 | *cp++ = '\0'; | |
762 | if (inet_pton(AF_INET6, p, (char *)(void *)host_addr) > 0) { | 762 | if (inet_pton(AF_INET6, p, (char *)(void *)host_addr) > 0) { | |
763 | af = AF_INET6; | 763 | af = AF_INET6; | |
764 | len = IN6ADDRSZ; | 764 | len = IN6ADDRSZ; | |
765 | } else if (inet_pton(AF_INET, p, (char *)(void *)host_addr) > 0) { | 765 | } else if (inet_pton(AF_INET, p, (char *)(void *)host_addr) > 0) { | |
766 | res_state res = __res_get_state(); | 766 | res_state res = __res_get_state(); | |
767 | if (res == NULL) | 767 | if (res == NULL) | |
768 | return NULL; | 768 | return NULL; | |
769 | if (res->options & RES_USE_INET6) { | 769 | if (res->options & RES_USE_INET6) { | |
770 | map_v4v6_address((char *)(void *)host_addr, | 770 | map_v4v6_address((char *)(void *)host_addr, | |
771 | (char *)(void *)host_addr); | 771 | (char *)(void *)host_addr); | |
772 | af = AF_INET6; | 772 | af = AF_INET6; | |
773 | len = IN6ADDRSZ; | 773 | len = IN6ADDRSZ; | |
774 | } else { | 774 | } else { | |
775 | af = AF_INET; | 775 | af = AF_INET; | |
776 | len = INADDRSZ; | 776 | len = INADDRSZ; | |
777 | } | 777 | } | |
778 | __res_put_state(res); | 778 | __res_put_state(res); | |
779 | } else { | 779 | } else { | |
780 | goto again; | 780 | goto again; | |
781 | } | 781 | } | |
782 | /* if this is not something we're looking for, skip it. */ | 782 | /* if this is not something we're looking for, skip it. */ | |
783 | if (host.h_addrtype != 0 && host.h_addrtype != af) | 783 | if (host.h_addrtype != 0 && host.h_addrtype != af) | |
784 | goto again; | 784 | goto again; | |
785 | if (host.h_length != 0 && host.h_length != len) | 785 | if (host.h_length != 0 && host.h_length != len) | |
786 | goto again; | 786 | goto again; | |
787 | h_addr_ptrs[0] = (char *)(void *)host_addr; | 787 | h_addr_ptrs[0] = (char *)(void *)host_addr; | |
788 | h_addr_ptrs[1] = NULL; | 788 | h_addr_ptrs[1] = NULL; | |
789 | host.h_addr_list = h_addr_ptrs; | 789 | host.h_addr_list = h_addr_ptrs; | |
790 | host.h_length = len; | 790 | host.h_length = len; | |
791 | host.h_addrtype = af; | 791 | host.h_addrtype = af; | |
792 | while (*cp == ' ' || *cp == '\t') | 792 | while (*cp == ' ' || *cp == '\t') | |
793 | cp++; | 793 | cp++; | |
794 | host.h_name = cp; | 794 | host.h_name = cp; | |
795 | q = host.h_aliases = host_aliases; | 795 | q = host.h_aliases = host_aliases; | |
796 | if ((cp = strpbrk(cp, " \t")) != NULL) | 796 | if ((cp = strpbrk(cp, " \t")) != NULL) | |
797 | *cp++ = '\0'; | 797 | *cp++ = '\0'; | |
798 | while (cp && *cp) { | 798 | while (cp && *cp) { | |
799 | if (*cp == ' ' || *cp == '\t') { | 799 | if (*cp == ' ' || *cp == '\t') { | |
800 | cp++; | 800 | cp++; | |
801 | continue; | 801 | continue; | |
802 | } | 802 | } | |
803 | if (q < &host_aliases[MAXALIASES - 1]) | 803 | if (q < &host_aliases[MAXALIASES - 1]) | |
804 | *q++ = cp; | 804 | *q++ = cp; | |
805 | if ((cp = strpbrk(cp, " \t")) != NULL) | 805 | if ((cp = strpbrk(cp, " \t")) != NULL) | |
806 | *cp++ = '\0'; | 806 | *cp++ = '\0'; | |
807 | } | 807 | } | |
808 | *q = NULL; | 808 | *q = NULL; | |
809 | h_errno = NETDB_SUCCESS; | 809 | h_errno = NETDB_SUCCESS; | |
810 | return &host; | 810 | return &host; | |
811 | } | 811 | } | |
812 | 812 | |||
813 | /*ARGSUSED*/ | 813 | /*ARGSUSED*/ | |
814 | int | 814 | int | |
815 | _gethtbyname(void *rv, void *cb_data, va_list ap) | 815 | _gethtbyname(void *rv, void *cb_data, va_list ap) | |
816 | { | 816 | { | |
817 | struct hostent *hp; | 817 | struct hostent *hp; | |
818 | const char *name; | 818 | const char *name; | |
819 | int af; | 819 | int af; | |
820 | 820 | |||
821 | _DIAGASSERT(rv != NULL); | 821 | _DIAGASSERT(rv != NULL); | |
822 | 822 | |||
823 | name = va_arg(ap, char *); | 823 | name = va_arg(ap, char *); | |
824 | /* NOSTRICT skip len */(void)va_arg(ap, int); | 824 | /* NOSTRICT skip len */(void)va_arg(ap, int); | |
825 | af = va_arg(ap, int); | 825 | af = va_arg(ap, int); | |
826 | 826 | |||
827 | hp = NULL; | 827 | hp = NULL; | |
828 | #if 0 | 828 | #if 0 | |
829 | { | 829 | { | |
830 | res_state res = __res_get_state(); | 830 | res_state res = __res_get_state(); | |
831 | if (res == NULL) | 831 | if (res == NULL) | |
832 | return NS_NOTFOUND; | 832 | return NS_NOTFOUND; | |
833 | if (res->options & RES_USE_INET6) | 833 | if (res->options & RES_USE_INET6) | |
834 | hp = _gethtbyname2(name, AF_INET6); | 834 | hp = _gethtbyname2(name, AF_INET6); | |
835 | if (hp==NULL) | 835 | if (hp==NULL) | |
836 | hp = _gethtbyname2(name, AF_INET); | 836 | hp = _gethtbyname2(name, AF_INET); | |
837 | __res_put_state(res); | 837 | __res_put_state(res); | |
838 | } | 838 | } | |
839 | #else | 839 | #else | |
840 | hp = _gethtbyname2(name, af); | 840 | hp = _gethtbyname2(name, af); | |
841 | #endif | 841 | #endif | |
842 | *((struct hostent **)rv) = hp; | 842 | *((struct hostent **)rv) = hp; | |
843 | if (hp == NULL) { | 843 | if (hp == NULL) { | |
844 | h_errno = HOST_NOT_FOUND; | 844 | h_errno = HOST_NOT_FOUND; | |
845 | return NS_NOTFOUND; | 845 | return NS_NOTFOUND; | |
846 | } | 846 | } | |
847 | return NS_SUCCESS; | 847 | return NS_SUCCESS; | |
848 | } | 848 | } | |
849 | 849 | |||
850 | struct hostent * | 850 | struct hostent * | |
851 | _gethtbyname2(const char *name, int af) | 851 | _gethtbyname2(const char *name, int af) | |
852 | { | 852 | { | |
853 | struct hostent *p; | 853 | struct hostent *p; | |
854 | char *tmpbuf, *ptr, **cp; | 854 | char *tmpbuf, *ptr, **cp; | |
855 | int num; | 855 | int num; | |
856 | size_t len; | 856 | size_t len; | |
857 | 857 | |||
858 | _DIAGASSERT(name != NULL); | 858 | _DIAGASSERT(name != NULL); | |
859 | 859 | |||
860 | _sethtent(stayopen); | 860 | _sethtent(stayopen); | |
861 | ptr = tmpbuf = NULL; | 861 | ptr = tmpbuf = NULL; | |
862 | num = 0; | 862 | num = 0; | |
863 | while ((p = _gethtent()) != NULL && num < MAXADDRS) { | 863 | while ((p = _gethtent()) != NULL && num < MAXADDRS) { | |
864 | if (p->h_addrtype != af) | 864 | if (p->h_addrtype != af) | |
865 | continue; | 865 | continue; | |
866 | if (strcasecmp(p->h_name, name) != 0) { | 866 | if (strcasecmp(p->h_name, name) != 0) { | |
867 | for (cp = p->h_aliases; *cp != NULL; cp++) | 867 | for (cp = p->h_aliases; *cp != NULL; cp++) | |
868 | if (strcasecmp(*cp, name) == 0) | 868 | if (strcasecmp(*cp, name) == 0) | |
869 | break; | 869 | break; | |
870 | if (*cp == NULL) continue; | 870 | if (*cp == NULL) continue; | |
871 | } | 871 | } | |
872 | 872 | |||
873 | if (num == 0) { | 873 | if (num == 0) { | |
874 | size_t bufsize; | 874 | size_t bufsize; | |
875 | char *src; | 875 | char *src; | |
876 | 876 | |||
877 | bufsize = strlen(p->h_name) + 2 + | 877 | bufsize = strlen(p->h_name) + 2 + | |
878 | MAXADDRS * p->h_length + | 878 | MAXADDRS * p->h_length + | |
879 | ALIGNBYTES; | 879 | ALIGNBYTES; | |
880 | for (cp = p->h_aliases; *cp != NULL; cp++) | 880 | for (cp = p->h_aliases; *cp != NULL; cp++) | |
881 | bufsize += strlen(*cp) + 1; | 881 | bufsize += strlen(*cp) + 1; | |
882 | 882 | |||
883 | if ((tmpbuf = malloc(bufsize)) == NULL) { | 883 | if ((tmpbuf = malloc(bufsize)) == NULL) { | |
884 | h_errno = NETDB_INTERNAL; | 884 | h_errno = NETDB_INTERNAL; | |
885 | return NULL; | 885 | return NULL; | |
886 | } | 886 | } | |
887 | 887 | |||
888 | ptr = tmpbuf; | 888 | ptr = tmpbuf; | |
889 | src = p->h_name; | 889 | src = p->h_name; | |
890 | while ((*ptr++ = *src++) != '\0'); | 890 | while ((*ptr++ = *src++) != '\0'); | |
891 | for (cp = p->h_aliases; *cp != NULL; cp++) { | 891 | for (cp = p->h_aliases; *cp != NULL; cp++) { | |
892 | src = *cp; | 892 | src = *cp; | |
893 | while ((*ptr++ = *src++) != '\0'); | 893 | while ((*ptr++ = *src++) != '\0'); | |
894 | } | 894 | } | |
895 | *ptr++ = '\0'; | 895 | *ptr++ = '\0'; | |
896 | 896 | |||
897 | ptr = (char *)(void *)ALIGN(ptr); | 897 | ptr = (char *)(void *)ALIGN(ptr); | |
898 | } | 898 | } | |
899 | 899 | |||
900 | (void)memcpy(ptr, p->h_addr_list[0], (size_t)p->h_length); | 900 | (void)memcpy(ptr, p->h_addr_list[0], (size_t)p->h_length); | |
901 | ptr += p->h_length; | 901 | ptr += p->h_length; | |
902 | num++; | 902 | num++; | |
903 | } | 903 | } | |
904 | _endhtent(); | 904 | _endhtent(); | |
905 | if (num == 0) return NULL; | 905 | if (num == 0) return NULL; | |
906 | 906 | |||
907 | len = ptr - tmpbuf; | 907 | len = ptr - tmpbuf; | |
908 | if (len > (sizeof(hostbuf) - ALIGNBYTES)) { | 908 | if (len > (sizeof(hostbuf) - ALIGNBYTES)) { | |
909 | free(tmpbuf); | 909 | free(tmpbuf); | |
910 | errno = ENOSPC; | 910 | errno = ENOSPC; | |
911 | h_errno = NETDB_INTERNAL; | 911 | h_errno = NETDB_INTERNAL; | |
912 | return NULL; | 912 | return NULL; | |
913 | } | 913 | } | |
914 | ptr = memcpy((void *)ALIGN(hostbuf), tmpbuf, len); | 914 | ptr = memcpy((void *)ALIGN(hostbuf), tmpbuf, len); | |
915 | free(tmpbuf); | 915 | free(tmpbuf); | |
916 | 916 | |||
917 | host.h_name = ptr; | 917 | host.h_name = ptr; | |
918 | while (*ptr++); | 918 | while (*ptr++); | |
919 | 919 | |||
920 | cp = host_aliases; | 920 | cp = host_aliases; | |
921 | while (*ptr) { | 921 | while (*ptr) { | |
922 | *cp++ = ptr; | 922 | *cp++ = ptr; | |
923 | while (*ptr++); | 923 | while (*ptr++); | |
924 | } | 924 | } | |
925 | ptr++; | 925 | ptr++; | |
926 | *cp = NULL; | 926 | *cp = NULL; | |
927 | 927 | |||
928 | ptr = (char *)(void *)ALIGN(ptr); | 928 | ptr = (char *)(void *)ALIGN(ptr); | |
929 | cp = h_addr_ptrs; | 929 | cp = h_addr_ptrs; | |
930 | while (num--) { | 930 | while (num--) { | |
931 | *cp++ = ptr; | 931 | *cp++ = ptr; | |
932 | ptr += host.h_length; | 932 | ptr += host.h_length; | |
933 | } | 933 | } | |
934 | *cp = NULL; | 934 | *cp = NULL; | |
935 | 935 | |||
936 | return &host; | 936 | return &host; | |
937 | } | 937 | } | |
938 | 938 | |||
939 | /*ARGSUSED*/ | 939 | /*ARGSUSED*/ | |
940 | int | 940 | int | |
941 | _gethtbyaddr(void *rv, void *cb_data, va_list ap) | 941 | _gethtbyaddr(void *rv, void *cb_data, va_list ap) | |
942 | { | 942 | { | |
943 | struct hostent *p; | 943 | struct hostent *p; | |
944 | const unsigned char *addr; | 944 | const unsigned char *addr; | |
945 | int len, af; | 945 | int len, af; | |
946 | 946 | |||
947 | _DIAGASSERT(rv != NULL); | 947 | _DIAGASSERT(rv != NULL); | |
948 | 948 | |||
949 | addr = va_arg(ap, unsigned char *); | 949 | addr = va_arg(ap, unsigned char *); | |
950 | len = va_arg(ap, int); | 950 | len = va_arg(ap, int); | |
951 | af = va_arg(ap, int); | 951 | af = va_arg(ap, int); | |
952 | 952 | |||
953 | host.h_length = len; | 953 | host.h_length = len; | |
954 | host.h_addrtype = af; | 954 | host.h_addrtype = af; | |
955 | 955 | |||
956 | _sethtent(stayopen); | 956 | _sethtent(stayopen); | |
957 | while ((p = _gethtent()) != NULL) | 957 | while ((p = _gethtent()) != NULL) | |
958 | if (p->h_addrtype == af && !memcmp(p->h_addr, addr, | 958 | if (p->h_addrtype == af && !memcmp(p->h_addr, addr, | |
959 | (size_t)len)) | 959 | (size_t)len)) | |
960 | break; | 960 | break; | |
961 | _endhtent(); | 961 | _endhtent(); | |
962 | *((struct hostent **)rv) = p; | 962 | *((struct hostent **)rv) = p; | |
963 | if (p==NULL) { | 963 | if (p==NULL) { | |
964 | h_errno = HOST_NOT_FOUND; | 964 | h_errno = HOST_NOT_FOUND; | |
965 | return NS_NOTFOUND; | 965 | return NS_NOTFOUND; | |
966 | } | 966 | } | |
967 | return NS_SUCCESS; | 967 | return NS_SUCCESS; | |
968 | } | 968 | } | |
969 | 969 | |||
970 | static void | 970 | static void | |
971 | map_v4v6_address(const char *src, char *dst) | 971 | map_v4v6_address(const char *src, char *dst) | |
972 | { | 972 | { | |
973 | u_char *p = (u_char *)dst; | 973 | u_char *p = (u_char *)dst; | |
974 | char tmp[INADDRSZ]; | 974 | char tmp[INADDRSZ]; | |
975 | int i; | 975 | int i; | |
976 | 976 | |||
977 | _DIAGASSERT(src != NULL); | 977 | _DIAGASSERT(src != NULL); | |
978 | _DIAGASSERT(dst != NULL); | 978 | _DIAGASSERT(dst != NULL); | |
979 | 979 | |||
980 | /* Stash a temporary copy so our caller can update in place. */ | 980 | /* Stash a temporary copy so our caller can update in place. */ | |
981 | (void)memcpy(tmp, src, INADDRSZ); | 981 | (void)memcpy(tmp, src, INADDRSZ); | |
982 | /* Mark this ipv6 addr as a mapped ipv4. */ | 982 | /* Mark this ipv6 addr as a mapped ipv4. */ | |
983 | for (i = 0; i < 10; i++) | 983 | for (i = 0; i < 10; i++) | |
984 | *p++ = 0x00; | 984 | *p++ = 0x00; | |
985 | *p++ = 0xff; | 985 | *p++ = 0xff; | |
986 | *p++ = 0xff; | 986 | *p++ = 0xff; | |
987 | /* Retrieve the saved copy and we're done. */ | 987 | /* Retrieve the saved copy and we're done. */ | |
988 | (void)memcpy((void *)p, tmp, INADDRSZ); | 988 | (void)memcpy((void *)p, tmp, INADDRSZ); | |
989 | } | 989 | } | |
990 | 990 | |||
991 | static void | 991 | static void | |
992 | map_v4v6_hostent(struct hostent *hp, char **bpp, char *ep) | 992 | map_v4v6_hostent(struct hostent *hp, char **bpp, char *ep) | |
993 | { | 993 | { | |
994 | char **ap; | 994 | char **ap; | |
995 | 995 | |||
996 | _DIAGASSERT(hp != NULL); | 996 | _DIAGASSERT(hp != NULL); | |
997 | _DIAGASSERT(bpp != NULL); | 997 | _DIAGASSERT(bpp != NULL); | |
998 | _DIAGASSERT(ep != NULL); | 998 | _DIAGASSERT(ep != NULL); | |
999 | 999 | |||
1000 | if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ) | 1000 | if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ) | |
1001 | return; | 1001 | return; | |
1002 | hp->h_addrtype = AF_INET6; | 1002 | hp->h_addrtype = AF_INET6; | |
1003 | hp->h_length = IN6ADDRSZ; | 1003 | hp->h_length = IN6ADDRSZ; | |
1004 | for (ap = hp->h_addr_list; *ap; ap++) { | 1004 | for (ap = hp->h_addr_list; *ap; ap++) { | |
1005 | int i = sizeof(align) - (size_t)((u_long)*bpp % sizeof(align)); | 1005 | int i = sizeof(align) - (size_t)((u_long)*bpp % sizeof(align)); | |
1006 | 1006 | |||
1007 | if (ep - *bpp < (i + IN6ADDRSZ)) { | 1007 | if (ep - *bpp < (i + IN6ADDRSZ)) { | |
1008 | /* Out of memory. Truncate address list here. XXX */ | 1008 | /* Out of memory. Truncate address list here. XXX */ | |
1009 | *ap = NULL; | 1009 | *ap = NULL; | |
1010 | return; | 1010 | return; | |
1011 | } | 1011 | } | |
1012 | *bpp += i; | 1012 | *bpp += i; | |
1013 | map_v4v6_address(*ap, *bpp); | 1013 | map_v4v6_address(*ap, *bpp); | |
1014 | *ap = *bpp; | 1014 | *ap = *bpp; | |
1015 | *bpp += IN6ADDRSZ; | 1015 | *bpp += IN6ADDRSZ; | |
1016 | } | 1016 | } | |
1017 | } | 1017 | } | |
1018 | 1018 | |||
1019 | static void | 1019 | static void | |
1020 | addrsort(char **ap, int num, res_state res) | 1020 | addrsort(char **ap, int num, res_state res) | |
1021 | { | 1021 | { | |
1022 | int i, j; | 1022 | int i, j; | |
1023 | char **p; | 1023 | char **p; | |
1024 | short aval[MAXADDRS]; | 1024 | short aval[MAXADDRS]; | |
1025 | int needsort = 0; | 1025 | int needsort = 0; | |
1026 | 1026 | |||
1027 | _DIAGASSERT(ap != NULL); | 1027 | _DIAGASSERT(ap != NULL); | |
1028 | 1028 | |||
1029 | p = ap; | 1029 | p = ap; | |
1030 | for (i = 0; i < num; i++, p++) { | 1030 | for (i = 0; i < num; i++, p++) { | |
1031 | for (j = 0 ; (unsigned)j < res->nsort; j++) | 1031 | for (j = 0 ; (unsigned)j < res->nsort; j++) | |
1032 | if (res->sort_list[j].addr.s_addr == | 1032 | if (res->sort_list[j].addr.s_addr == | |
1033 | (((struct in_addr *)(void *)(*p))->s_addr & | 1033 | (((struct in_addr *)(void *)(*p))->s_addr & | |
1034 | res->sort_list[j].mask)) | 1034 | res->sort_list[j].mask)) | |
1035 | break; | 1035 | break; | |
1036 | aval[i] = j; | 1036 | aval[i] = j; | |
1037 | if (needsort == 0 && i > 0 && j < aval[i-1]) | 1037 | if (needsort == 0 && i > 0 && j < aval[i-1]) | |
1038 | needsort = i; | 1038 | needsort = i; | |
1039 | } | 1039 | } | |
1040 | if (!needsort) | 1040 | if (!needsort) | |
1041 | return; | 1041 | return; | |
1042 | 1042 | |||
1043 | while (needsort < num) { | 1043 | while (needsort < num) { | |
1044 | for (j = needsort - 1; j >= 0; j--) { | 1044 | for (j = needsort - 1; j >= 0; j--) { | |
1045 | if (aval[j] > aval[j+1]) { | 1045 | if (aval[j] > aval[j+1]) { | |
1046 | char *hp; | 1046 | char *hp; | |
1047 | 1047 | |||
1048 | i = aval[j]; | 1048 | i = aval[j]; | |
1049 | aval[j] = aval[j+1]; | 1049 | aval[j] = aval[j+1]; | |
1050 | aval[j+1] = i; | 1050 | aval[j+1] = i; | |
1051 | 1051 | |||
1052 | hp = ap[j]; | 1052 | hp = ap[j]; | |
1053 | ap[j] = ap[j+1]; | 1053 | ap[j] = ap[j+1]; | |
1054 | ap[j+1] = hp; | 1054 | ap[j+1] = hp; | |
1055 | } else | 1055 | } else | |
1056 | break; | 1056 | break; | |
1057 | } | 1057 | } | |
1058 | needsort++; | 1058 | needsort++; | |
1059 | } | 1059 | } | |
1060 | } | 1060 | } | |
1061 | 1061 | |||
1062 | struct hostent * | 1062 | struct hostent * | |
1063 | gethostent(void) | 1063 | gethostent(void) | |
1064 | { | 1064 | { | |
1065 | host.h_addrtype = 0; | 1065 | host.h_addrtype = 0; | |
1066 | host.h_length = 0; | 1066 | host.h_length = 0; | |
1067 | return _gethtent(); | 1067 | return _gethtent(); | |
1068 | } | 1068 | } | |
1069 | 1069 | |||
1070 | /*ARGSUSED*/ | 1070 | /*ARGSUSED*/ | |
1071 | int | 1071 | int | |
1072 | _dns_gethtbyname(void *rv, void *cb_data, va_list ap) | 1072 | _dns_gethtbyname(void *rv, void *cb_data, va_list ap) | |
1073 | { | 1073 | { | |
1074 | querybuf *buf; | 1074 | querybuf *buf; | |
1075 | int n, type; | 1075 | int n, type; | |
1076 | struct hostent *hp; | 1076 | struct hostent *hp; | |
1077 | const char *name; | 1077 | const char *name; | |
1078 | int af; | 1078 | int af; | |
1079 | res_state res; | 1079 | res_state res; | |
1080 | 1080 | |||
1081 | _DIAGASSERT(rv != NULL); | 1081 | _DIAGASSERT(rv != NULL); | |
1082 | 1082 | |||
1083 | name = va_arg(ap, char *); | 1083 | name = va_arg(ap, char *); | |
1084 | /* NOSTRICT skip len */(void)va_arg(ap, int); | 1084 | /* NOSTRICT skip len */(void)va_arg(ap, int); | |
1085 | af = va_arg(ap, int); | 1085 | af = va_arg(ap, int); | |
1086 | 1086 | |||
1087 | switch (af) { | 1087 | switch (af) { | |
1088 | case AF_INET: | 1088 | case AF_INET: | |
1089 | type = T_A; | 1089 | type = T_A; | |
1090 | break; | 1090 | break; | |
1091 | case AF_INET6: | 1091 | case AF_INET6: | |
1092 | type = T_AAAA; | 1092 | type = T_AAAA; | |
1093 | break; | 1093 | break; | |
1094 | default: | 1094 | default: | |
1095 | return NS_UNAVAIL; | 1095 | return NS_UNAVAIL; | |
1096 | } | 1096 | } | |
1097 | buf = malloc(sizeof(*buf)); | 1097 | buf = malloc(sizeof(*buf)); | |
1098 | if (buf == NULL) { | 1098 | if (buf == NULL) { | |
1099 | h_errno = NETDB_INTERNAL; | 1099 | h_errno = NETDB_INTERNAL; | |
1100 | return NS_NOTFOUND; | 1100 | return NS_NOTFOUND; | |
1101 | } | 1101 | } | |
1102 | res = __res_get_state(); | 1102 | res = __res_get_state(); | |
1103 | if (res == NULL) { | 1103 | if (res == NULL) { | |
1104 | free(buf); | 1104 | free(buf); | |
1105 | return NS_NOTFOUND; | 1105 | return NS_NOTFOUND; | |
1106 | } | 1106 | } | |
1107 | n = res_nsearch(res, name, C_IN, type, buf->buf, sizeof(buf->buf)); | 1107 | n = res_nsearch(res, name, C_IN, type, buf->buf, sizeof(buf->buf)); | |
1108 | if (n < 0) { | 1108 | if (n < 0) { | |
1109 | free(buf); | 1109 | free(buf); | |
1110 | dprintf("res_nsearch failed (%d)\n", res, n); | 1110 | dprintf("res_nsearch failed (%d)\n", res, n); | |
1111 | __res_put_state(res); | 1111 | __res_put_state(res); | |
1112 | return NS_NOTFOUND; | 1112 | return NS_NOTFOUND; | |
1113 | } | 1113 | } | |
1114 | hp = getanswer(buf, n, name, type, res); | 1114 | hp = getanswer(buf, n, name, type, res); | |
1115 | free(buf); | 1115 | free(buf); | |
1116 | __res_put_state(res); | 1116 | __res_put_state(res); | |
1117 | if (hp == NULL) | 1117 | if (hp == NULL) | |
1118 | switch (h_errno) { | 1118 | switch (h_errno) { | |
1119 | case HOST_NOT_FOUND: | 1119 | case HOST_NOT_FOUND: | |
1120 | return NS_NOTFOUND; | 1120 | return NS_NOTFOUND; | |
1121 | case TRY_AGAIN: | 1121 | case TRY_AGAIN: | |
1122 | return NS_TRYAGAIN; | 1122 | return NS_TRYAGAIN; | |
1123 | default: | 1123 | default: | |
1124 | return NS_UNAVAIL; | 1124 | return NS_UNAVAIL; | |
1125 | } | 1125 | } | |
1126 | *((struct hostent **)rv) = hp; | 1126 | *((struct hostent **)rv) = hp; | |
1127 | return NS_SUCCESS; | 1127 | return NS_SUCCESS; | |
1128 | } | 1128 | } | |
1129 | 1129 | |||
1130 | /*ARGSUSED*/ | 1130 | /*ARGSUSED*/ | |
1131 | int | 1131 | int | |
1132 | _dns_gethtbyaddr(void *rv, void *cb_data, va_list ap) | 1132 | _dns_gethtbyaddr(void *rv, void *cb_data, va_list ap) | |
1133 | { | 1133 | { | |
1134 | char qbuf[MAXDNAME + 1], *qp, *ep; | 1134 | char qbuf[MAXDNAME + 1], *qp, *ep; | |
1135 | int n; | 1135 | int n; | |
1136 | querybuf *buf; | 1136 | querybuf *buf; | |
1137 | struct hostent *hp; | 1137 | struct hostent *hp; | |
1138 | const unsigned char *uaddr; | 1138 | const unsigned char *uaddr; | |
1139 | int len, af, advance; | 1139 | int len, af, advance; | |
1140 | res_state res; | 1140 | res_state res; | |
1141 | 1141 | |||
1142 | _DIAGASSERT(rv != NULL); | 1142 | _DIAGASSERT(rv != NULL); | |
1143 | 1143 | |||
1144 | uaddr = va_arg(ap, unsigned char *); | 1144 | uaddr = va_arg(ap, unsigned char *); | |
1145 | len = va_arg(ap, int); | 1145 | len = va_arg(ap, int); | |
1146 | af = va_arg(ap, int); | 1146 | af = va_arg(ap, int); | |
1147 | 1147 | |||
1148 | switch (af) { | 1148 | switch (af) { | |
1149 | case AF_INET: | 1149 | case AF_INET: | |
1150 | (void)snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u.in-addr.arpa", | 1150 | (void)snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u.in-addr.arpa", | |
1151 | (uaddr[3] & 0xff), (uaddr[2] & 0xff), | 1151 | (uaddr[3] & 0xff), (uaddr[2] & 0xff), | |
1152 | (uaddr[1] & 0xff), (uaddr[0] & 0xff)); | 1152 | (uaddr[1] & 0xff), (uaddr[0] & 0xff)); | |
1153 | break; | 1153 | break; | |
1154 | 1154 | |||
1155 | case AF_INET6: | 1155 | case AF_INET6: | |
1156 | qp = qbuf; | 1156 | qp = qbuf; | |
1157 | ep = qbuf + sizeof(qbuf) - 1; | 1157 | ep = qbuf + sizeof(qbuf) - 1; | |
1158 | for (n = IN6ADDRSZ - 1; n >= 0; n--) { | 1158 | for (n = IN6ADDRSZ - 1; n >= 0; n--) { | |
1159 | advance = snprintf(qp, (size_t)(ep - qp), "%x.%x.", | 1159 | advance = snprintf(qp, (size_t)(ep - qp), "%x.%x.", | |
1160 | uaddr[n] & 0xf, | 1160 | uaddr[n] & 0xf, | |
1161 | ((unsigned int)uaddr[n] >> 4) & 0xf); | 1161 | ((unsigned int)uaddr[n] >> 4) & 0xf); | |
1162 | if (advance > 0 && qp + advance < ep) | 1162 | if (advance > 0 && qp + advance < ep) | |
1163 | qp += advance; | 1163 | qp += advance; | |
1164 | else { | 1164 | else { | |
1165 | h_errno = NETDB_INTERNAL; | 1165 | h_errno = NETDB_INTERNAL; | |
1166 | return NS_NOTFOUND; | 1166 | return NS_NOTFOUND; | |
1167 | } | 1167 | } | |
1168 | } | 1168 | } | |
1169 | if (strlcat(qbuf, "ip6.arpa", sizeof(qbuf)) >= sizeof(qbuf)) { | 1169 | if (strlcat(qbuf, "ip6.arpa", sizeof(qbuf)) >= sizeof(qbuf)) { | |
1170 | h_errno = NETDB_INTERNAL; | 1170 | h_errno = NETDB_INTERNAL; | |
1171 | return NS_NOTFOUND; | 1171 | return NS_NOTFOUND; | |
1172 | } | 1172 | } | |
1173 | break; | 1173 | break; | |
1174 | default: | 1174 | default: | |
1175 | abort(); | 1175 | abort(); | |
1176 | } | 1176 | } | |
1177 | 1177 | |||
1178 | buf = malloc(sizeof(*buf)); | 1178 | buf = malloc(sizeof(*buf)); | |
1179 | if (buf == NULL) { | 1179 | if (buf == NULL) { | |
1180 | h_errno = NETDB_INTERNAL; | 1180 | h_errno = NETDB_INTERNAL; | |
1181 | return NS_NOTFOUND; | 1181 | return NS_NOTFOUND; | |
1182 | } | 1182 | } | |
1183 | res = __res_get_state(); | 1183 | res = __res_get_state(); | |
1184 | if (res == NULL) { | 1184 | if (res == NULL) { | |
1185 | free(buf); | 1185 | free(buf); | |
1186 | return NS_NOTFOUND; | 1186 | return NS_NOTFOUND; | |
1187 | } | 1187 | } | |
1188 | n = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, sizeof(buf->buf)); | 1188 | n = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, sizeof(buf->buf)); | |
1189 | if (n < 0) { | 1189 | if (n < 0) { | |
1190 | free(buf); | 1190 | free(buf); | |
1191 | dprintf("res_nquery failed (%d)\n", res, n); | 1191 | dprintf("res_nquery failed (%d)\n", res, n); | |
1192 | __res_put_state(res); | 1192 | __res_put_state(res); | |
1193 | return NS_NOTFOUND; | 1193 | return NS_NOTFOUND; | |
1194 | } | 1194 | } | |
1195 | hp = getanswer(buf, n, qbuf, T_PTR, res); | 1195 | hp = getanswer(buf, n, qbuf, T_PTR, res); | |
1196 | free(buf); | 1196 | free(buf); | |
1197 | if (hp == NULL) { | 1197 | if (hp == NULL) { | |
1198 | __res_put_state(res); | 1198 | __res_put_state(res); | |
1199 | switch (h_errno) { | 1199 | switch (h_errno) { | |
1200 | case HOST_NOT_FOUND: | 1200 | case HOST_NOT_FOUND: | |
1201 | return NS_NOTFOUND; | 1201 | return NS_NOTFOUND; | |
1202 | case TRY_AGAIN: | 1202 | case TRY_AGAIN: | |
1203 | return NS_TRYAGAIN; | 1203 | return NS_TRYAGAIN; | |
1204 | default: | 1204 | default: | |
1205 | return NS_UNAVAIL; | 1205 | return NS_UNAVAIL; | |
1206 | } | 1206 | } | |
1207 | } | 1207 | } | |
1208 | hp->h_addrtype = af; | 1208 | hp->h_addrtype = af; | |
1209 | hp->h_length = len; | 1209 | hp->h_length = len; | |
1210 | (void)memcpy(host_addr, uaddr, (size_t)len); | 1210 | (void)memcpy(host_addr, uaddr, (size_t)len); | |
1211 | h_addr_ptrs[0] = (char *)(void *)host_addr; | 1211 | h_addr_ptrs[0] = (char *)(void *)host_addr; | |
1212 | h_addr_ptrs[1] = NULL; | 1212 | h_addr_ptrs[1] = NULL; | |
1213 | if (af == AF_INET && (res->options & RES_USE_INET6)) { | 1213 | if (af == AF_INET && (res->options & RES_USE_INET6)) { | |
1214 | map_v4v6_address((char *)(void *)host_addr, | 1214 | map_v4v6_address((char *)(void *)host_addr, | |
1215 | (char *)(void *)host_addr); | 1215 | (char *)(void *)host_addr); | |
1216 | hp->h_addrtype = AF_INET6; | 1216 | hp->h_addrtype = AF_INET6; | |
1217 | hp->h_length = IN6ADDRSZ; | 1217 | hp->h_length = IN6ADDRSZ; | |
1218 | } | 1218 | } | |
1219 | 1219 | |||
1220 | __res_put_state(res); | 1220 | __res_put_state(res); | |
1221 | *((struct hostent **)rv) = hp; | 1221 | *((struct hostent **)rv) = hp; | |
1222 | h_errno = NETDB_SUCCESS; | 1222 | h_errno = NETDB_SUCCESS; | |
1223 | return NS_SUCCESS; | 1223 | return NS_SUCCESS; | |
1224 | } | 1224 | } | |
1225 | 1225 | |||
1226 | #ifdef YP | 1226 | #ifdef YP | |
1227 | /*ARGSUSED*/ | 1227 | /*ARGSUSED*/ | |
1228 | struct hostent * | 1228 | struct hostent * | |
1229 | _yphostent(char *line, int af) | 1229 | _yphostent(char *line, int af) | |
1230 | { | 1230 | { | |
1231 | static struct in_addr host_addrs[MAXADDRS]; | 1231 | static struct in_addr host_addrs[MAXADDRS]; | |
1232 | static struct in6_addr host6_addrs[MAXADDRS]; | 1232 | static struct in6_addr host6_addrs[MAXADDRS]; | |
1233 | char *p = line; | 1233 | char *p = line; | |
1234 | char *cp, **q; | 1234 | char *cp, **q; | |
1235 | char **hap; | 1235 | char **hap; | |
1236 | int addrok; | 1236 | int addrok; | |
1237 | int more; | 1237 | int more; | |
1238 | size_t naddrs; | 1238 | size_t naddrs; | |
1239 | 1239 | |||
1240 | _DIAGASSERT(line != NULL); | 1240 | _DIAGASSERT(line != NULL); | |
1241 | 1241 | |||
1242 | host.h_name = NULL; | 1242 | host.h_name = NULL; | |
1243 | host.h_addr_list = h_addr_ptrs; | 1243 | host.h_addr_list = h_addr_ptrs; | |
1244 | host.h_addrtype = af; | 1244 | host.h_addrtype = af; | |
1245 | switch (af) { | 1245 | switch (af) { | |
1246 | case AF_INET: | 1246 | case AF_INET: | |
1247 | host.h_length = INADDRSZ; | 1247 | host.h_length = INADDRSZ; | |
1248 | break; | 1248 | break; | |
1249 | case AF_INET6: | 1249 | case AF_INET6: | |
1250 | host.h_length = IN6ADDRSZ; | 1250 | host.h_length = IN6ADDRSZ; | |
1251 | break; | 1251 | break; | |
1252 | default: | 1252 | default: | |
1253 | return NULL; | 1253 | return NULL; | |
1254 | } | 1254 | } | |
1255 | hap = h_addr_ptrs; | 1255 | hap = h_addr_ptrs; | |
1256 | q = host.h_aliases = host_aliases; | 1256 | q = host.h_aliases = host_aliases; | |
1257 | naddrs = 0; | 1257 | naddrs = 0; | |
1258 | 1258 | |||
1259 | nextline: | 1259 | nextline: | |
1260 | /* check for host_addrs overflow */ | 1260 | /* check for host_addrs overflow */ | |
1261 | if (naddrs >= sizeof(host_addrs) / sizeof(host_addrs[0])) | 1261 | if (naddrs >= sizeof(host_addrs) / sizeof(host_addrs[0])) | |
1262 | goto done; | 1262 | goto done; | |
1263 | if (naddrs >= sizeof(host6_addrs) / sizeof(host6_addrs[0])) | 1263 | if (naddrs >= sizeof(host6_addrs) / sizeof(host6_addrs[0])) | |
1264 | goto done; | 1264 | goto done; | |
1265 | 1265 | |||
1266 | more = 0; | 1266 | more = 0; | |
1267 | cp = strpbrk(p, " \t"); | 1267 | cp = strpbrk(p, " \t"); | |
1268 | if (cp == NULL) | 1268 | if (cp == NULL) | |
1269 | goto done; | 1269 | goto done; | |
1270 | *cp++ = '\0'; | 1270 | *cp++ = '\0'; | |
1271 | 1271 | |||
1272 | /* p has should have an address */ | 1272 | /* p has should have an address */ | |
1273 | addrok = 0; | 1273 | addrok = 0; | |
1274 | switch (af) { | 1274 | switch (af) { | |
1275 | case AF_INET: | 1275 | case AF_INET: | |
1276 | addrok = inet_aton(p, &host_addrs[naddrs]); | 1276 | addrok = inet_aton(p, &host_addrs[naddrs]); | |
1277 | break; | 1277 | break; | |
1278 | case AF_INET6: | 1278 | case AF_INET6: | |
1279 | addrok = inet_pton(af, p, &host6_addrs[naddrs]); | 1279 | addrok = inet_pton(af, p, &host6_addrs[naddrs]); | |
1280 | break; | 1280 | break; | |
1281 | } | 1281 | } | |
1282 | if (addrok != 1) { | 1282 | if (addrok != 1) { | |
1283 | /* skip to the next line */ | 1283 | /* skip to the next line */ | |
1284 | while (cp && *cp) { | 1284 | while (cp && *cp) { | |
1285 | if (*cp == '\n') { | 1285 | if (*cp == '\n') { | |
1286 | cp++; | 1286 | cp++; | |
1287 | goto nextline; | 1287 | goto nextline; | |
1288 | } | 1288 | } | |
1289 | cp++; | 1289 | cp++; | |
1290 | } | 1290 | } | |
1291 | 1291 | |||
1292 | goto done; | 1292 | goto done; | |
1293 | } | 1293 | } | |
1294 | 1294 | |||
1295 | switch (af) { | 1295 | switch (af) { | |
1296 | case AF_INET: | 1296 | case AF_INET: | |
1297 | *hap++ = (char *)(void *)&host_addrs[naddrs++]; | 1297 | *hap++ = (char *)(void *)&host_addrs[naddrs++]; | |
1298 | break; | 1298 | break; | |
1299 | case AF_INET6: | 1299 | case AF_INET6: | |
1300 | *hap++ = (char *)(void *)&host6_addrs[naddrs++]; | 1300 | *hap++ = (char *)(void *)&host6_addrs[naddrs++]; | |
1301 | break; | 1301 | break; | |
1302 | } | 1302 | } | |
1303 | 1303 | |||
1304 | while (*cp == ' ' || *cp == '\t') | 1304 | while (*cp == ' ' || *cp == '\t') | |
1305 | cp++; | 1305 | cp++; | |
1306 | p = cp; | 1306 | p = cp; | |
1307 | cp = strpbrk(p, " \t\n"); | 1307 | cp = strpbrk(p, " \t\n"); | |
1308 | if (cp != NULL) { | 1308 | if (cp != NULL) { | |
1309 | if (*cp == '\n') | 1309 | if (*cp == '\n') | |
1310 | more = 1; | 1310 | more = 1; | |
1311 | *cp++ = '\0'; | 1311 | *cp++ = '\0'; | |
1312 | } | 1312 | } | |
1313 | if (!host.h_name) | 1313 | if (!host.h_name) | |
1314 | host.h_name = p; | 1314 | host.h_name = p; | |
1315 | else if (strcmp(host.h_name, p)==0) | 1315 | else if (strcmp(host.h_name, p)==0) | |
1316 | ; | 1316 | ; | |
1317 | else if (q < &host_aliases[MAXALIASES - 1]) | 1317 | else if (q < &host_aliases[MAXALIASES - 1]) | |
1318 | *q++ = p; | 1318 | *q++ = p; | |
1319 | p = cp; | 1319 | p = cp; | |
1320 | if (more) | 1320 | if (more) | |
1321 | goto nextline; | 1321 | goto nextline; | |
1322 | 1322 | |||
1323 | while (cp && *cp) { | 1323 | while (cp && *cp) { | |
1324 | if (*cp == ' ' || *cp == '\t') { | 1324 | if (*cp == ' ' || *cp == '\t') { | |
1325 | cp++; | 1325 | cp++; | |
1326 | continue; | 1326 | continue; | |
1327 | } | 1327 | } | |
1328 | if (*cp == '\n') { | 1328 | if (*cp == '\n') { | |
1329 | cp++; | 1329 | cp++; | |
1330 | goto nextline; | 1330 | goto nextline; | |
1331 | } | 1331 | } | |
1332 | if (q < &host_aliases[MAXALIASES - 1]) | 1332 | if (q < &host_aliases[MAXALIASES - 1]) | |
1333 | *q++ = cp; | 1333 | *q++ = cp; | |
1334 | cp = strpbrk(cp, " \t"); | 1334 | cp = strpbrk(cp, " \t"); | |
1335 | if (cp != NULL) | 1335 | if (cp != NULL) | |
1336 | *cp++ = '\0'; | 1336 | *cp++ = '\0'; | |
1337 | } | 1337 | } | |
1338 | 1338 | |||
1339 | done: | 1339 | done: | |
1340 | if (host.h_name == NULL) | 1340 | if (host.h_name == NULL) | |
1341 | return NULL; | 1341 | return NULL; | |
1342 | *q = NULL; | 1342 | *q = NULL; | |
1343 | *hap = NULL; | 1343 | *hap = NULL; | |
1344 | return &host; | 1344 | return &host; | |
1345 | } | 1345 | } | |
1346 | 1346 | |||
1347 | /*ARGSUSED*/ | 1347 | /*ARGSUSED*/ | |
1348 | int | 1348 | int | |
1349 | _yp_gethtbyaddr(void *rv, void *cb_data, va_list ap) | 1349 | _yp_gethtbyaddr(void *rv, void *cb_data, va_list ap) | |
1350 | { | 1350 | { | |
1351 | struct hostent *hp = NULL; | 1351 | struct hostent *hp = NULL; | |
1352 | static char *__ypcurrent; | 1352 | static char *__ypcurrent; | |
1353 | int __ypcurrentlen, r; | 1353 | int __ypcurrentlen, r; | |
1354 | char name[INET6_ADDRSTRLEN]; /* XXX enough? */ | 1354 | char name[INET6_ADDRSTRLEN]; /* XXX enough? */ | |
1355 | const unsigned char *uaddr; | 1355 | const unsigned char *uaddr; | |
1356 | int af; | 1356 | int af; | |
1357 | const char *map; | 1357 | const char *map; | |
1358 | 1358 | |||
1359 | _DIAGASSERT(rv != NULL); | 1359 | _DIAGASSERT(rv != NULL); | |
1360 | 1360 | |||
1361 | uaddr = va_arg(ap, unsigned char *); | 1361 | uaddr = va_arg(ap, unsigned char *); | |
1362 | /* NOSTRICT skip len */(void)va_arg(ap, int); | 1362 | /* NOSTRICT skip len */(void)va_arg(ap, int); | |
1363 | af = va_arg(ap, int); | 1363 | af = va_arg(ap, int); | |
1364 | 1364 | |||
1365 | if (!__ypdomain) { | 1365 | if (!__ypdomain) { | |
1366 | if (_yp_check(&__ypdomain) == 0) | 1366 | if (_yp_check(&__ypdomain) == 0) | |
1367 | return NS_UNAVAIL; | 1367 | return NS_UNAVAIL; | |
1368 | } | 1368 | } | |
1369 | /* | 1369 | /* | |
1370 | * XXX unfortunately, we cannot support IPv6 extended scoped address | 1370 | * XXX unfortunately, we cannot support IPv6 extended scoped address | |
1371 | * notation here. gethostbyaddr() is not scope-aware. too bad. | 1371 | * notation here. gethostbyaddr() is not scope-aware. too bad. | |
1372 | */ | 1372 | */ | |
1373 | if (inet_ntop(af, uaddr, name, sizeof(name)) == NULL) | 1373 | if (inet_ntop(af, uaddr, name, sizeof(name)) == NULL) | |
1374 | return NS_UNAVAIL; | 1374 | return NS_UNAVAIL; | |
1375 | if (__ypcurrent) | 1375 | if (__ypcurrent) | |
1376 | free(__ypcurrent); | 1376 | free(__ypcurrent); | |
1377 | __ypcurrent = NULL; | 1377 | __ypcurrent = NULL; | |
1378 | switch (af) { | 1378 | switch (af) { | |
1379 | case AF_INET: | 1379 | case AF_INET: | |
1380 | map = "hosts.byaddr"; | 1380 | map = "hosts.byaddr"; | |
1381 | break; | 1381 | break; | |
1382 | default: | 1382 | default: | |
1383 | map = "ipnodes.byaddr"; | 1383 | map = "ipnodes.byaddr"; | |
1384 | break; | 1384 | break; | |
1385 | } | 1385 | } | |
1386 | r = yp_match(__ypdomain, map, name, | 1386 | r = yp_match(__ypdomain, map, name, | |
1387 | (int)strlen(name), &__ypcurrent, &__ypcurrentlen); | 1387 | (int)strlen(name), &__ypcurrent, &__ypcurrentlen); | |
1388 | if (r == 0) | 1388 | if (r == 0) | |
1389 | hp = _yphostent(__ypcurrent, af); | 1389 | hp = _yphostent(__ypcurrent, af); | |
1390 | if (hp == NULL) { | 1390 | if (hp == NULL) { | |
1391 | h_errno = HOST_NOT_FOUND; | 1391 | h_errno = HOST_NOT_FOUND; | |
1392 | return NS_NOTFOUND; | 1392 | return NS_NOTFOUND; | |
1393 | } | 1393 | } | |
1394 | *((struct hostent **)rv) = hp; | 1394 | *((struct hostent **)rv) = hp; | |
1395 | return NS_SUCCESS; | 1395 | return NS_SUCCESS; | |
1396 | } | 1396 | } | |
1397 | 1397 | |||
1398 | /*ARGSUSED*/ | 1398 | /*ARGSUSED*/ | |
1399 | int | 1399 | int | |
1400 | _yp_gethtbyname(void *rv, void *cb_data, va_list ap) | 1400 | _yp_gethtbyname(void *rv, void *cb_data, va_list ap) | |
1401 | { | 1401 | { | |
1402 | struct hostent *hp = NULL; | 1402 | struct hostent *hp = NULL; | |
1403 | static char *__ypcurrent; | 1403 | static char *__ypcurrent; | |
1404 | int __ypcurrentlen, r; | 1404 | int __ypcurrentlen, r; | |
1405 | const char *name; | 1405 | const char *name; | |
1406 | int af; | 1406 | int af; | |
1407 | const char *map; | 1407 | const char *map; | |
1408 | 1408 | |||
1409 | _DIAGASSERT(rv != NULL); | 1409 | _DIAGASSERT(rv != NULL); | |
1410 | 1410 | |||
1411 | name = va_arg(ap, char *); | 1411 | name = va_arg(ap, char *); | |
1412 | /* NOSTRICT skip len */(void)va_arg(ap, int); | 1412 | /* NOSTRICT skip len */(void)va_arg(ap, int); | |
1413 | af = va_arg(ap, int); | 1413 | af = va_arg(ap, int); | |
1414 | 1414 | |||
1415 | if (!__ypdomain) { | 1415 | if (!__ypdomain) { | |
1416 | if (_yp_check(&__ypdomain) == 0) | 1416 | if (_yp_check(&__ypdomain) == 0) | |
1417 | return NS_UNAVAIL; | 1417 | return NS_UNAVAIL; | |
1418 | } | 1418 | } | |
1419 | if (__ypcurrent) | 1419 | if (__ypcurrent) | |
1420 | free(__ypcurrent); | 1420 | free(__ypcurrent); | |
1421 | __ypcurrent = NULL; | 1421 | __ypcurrent = NULL; | |
1422 | switch (af) { | 1422 | switch (af) { | |
1423 | case AF_INET: | 1423 | case AF_INET: | |
1424 | map = "hosts.byname"; | 1424 | map = "hosts.byname"; | |
1425 | break; | 1425 | break; | |
1426 | default: | 1426 | default: | |
1427 | map = "ipnodes.byname"; | 1427 | map = "ipnodes.byname"; | |
1428 | break; | 1428 | break; | |
1429 | } | 1429 | } | |
1430 | r = yp_match(__ypdomain, map, name, | 1430 | r = yp_match(__ypdomain, map, name, | |
1431 | (int)strlen(name), &__ypcurrent, &__ypcurrentlen); | 1431 | (int)strlen(name), &__ypcurrent, &__ypcurrentlen); | |
1432 | if (r == 0) | 1432 | if (r == 0) | |
1433 | hp = _yphostent(__ypcurrent, af); | 1433 | hp = _yphostent(__ypcurrent, af); | |
1434 | if (hp == NULL) { | 1434 | if (hp == NULL) { | |
1435 | h_errno = HOST_NOT_FOUND; | 1435 | h_errno = HOST_NOT_FOUND; | |
1436 | return NS_NOTFOUND; | 1436 | return NS_NOTFOUND; | |
1437 | } | 1437 | } | |
1438 | *((struct hostent **)rv) = hp; | 1438 | *((struct hostent **)rv) = hp; | |
1439 | return NS_SUCCESS; | 1439 | return NS_SUCCESS; | |
1440 | } | 1440 | } | |
1441 | #endif | 1441 | #endif |
--- src/lib/libc/net/resolver.3 2009/06/08 16:55:30 1.22
+++ src/lib/libc/net/resolver.3 2009/10/02 06:49:23 1.23
@@ -1,717 +1,717 @@ | @@ -1,717 +1,717 @@ | |||
1 | .\" $NetBSD: resolver.3,v 1.22 2009/06/08 16:55:30 christos Exp $ | 1 | .\" $NetBSD: resolver.3,v 1.23 2009/10/02 06:49:23 cegger Exp $ | |
2 | .\" Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") | 2 | .\" Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") | |
3 | .\" | 3 | .\" | |
4 | .\" Permission to use, copy, modify, and distribute this software for any | 4 | .\" Permission to use, copy, modify, and distribute this software for any | |
5 | .\" purpose with or without fee is hereby granted, provided that the above | 5 | .\" purpose with or without fee is hereby granted, provided that the above | |
6 | .\" copyright notice and this permission notice appear in all copies. | 6 | .\" copyright notice and this permission notice appear in all copies. | |
7 | .\" | 7 | .\" | |
8 | .\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES | 8 | .\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES | |
9 | .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 9 | .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
10 | .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR | 10 | .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR | |
11 | .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 11 | .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
12 | .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 12 | .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
13 | .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | 13 | .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | |
14 | .\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 14 | .\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
15 | .\" | 15 | .\" | |
16 | .\" Copyright (c) 1985, 1995 The Regents of the University of California. | 16 | .\" Copyright (c) 1985, 1995 The Regents of the University of California. | |
17 | .\" All rights reserved. | 17 | .\" All rights reserved. | |
18 | .\" | 18 | .\" | |
19 | .\" Redistribution and use in source and binary forms are permitted provided | 19 | .\" Redistribution and use in source and binary forms are permitted provided | |
20 | .\" that: (1) source distributions retain this entire copyright notice and | 20 | .\" that: (1) source distributions retain this entire copyright notice and | |
21 | .\" comment, and (2) distributions including binaries display the following | 21 | .\" comment, and (2) distributions including binaries display the following | |
22 | .\" acknowledgement: ``This product includes software developed by the | 22 | .\" acknowledgement: ``This product includes software developed by the | |
23 | .\" University of California, Berkeley and its contributors'' in the | 23 | .\" University of California, Berkeley and its contributors'' in the | |
24 | .\" documentation or other materials provided with the distribution and in | 24 | .\" documentation or other materials provided with the distribution and in | |
25 | .\" all advertising materials mentioning features or use of this software. | 25 | .\" all advertising materials mentioning features or use of this software. | |
26 | .\" Neither the name of the University nor the names of its contributors may | 26 | .\" Neither the name of the University nor the names of its contributors may | |
27 | .\" be used to endorse or promote products derived from this software without | 27 | .\" be used to endorse or promote products derived from this software without | |
28 | .\" specific prior written permission. | 28 | .\" specific prior written permission. | |
29 | .\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED | 29 | .\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED | |
30 | .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF | 30 | .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF | |
31 | .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | 31 | .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
32 | .\" | 32 | .\" | |
33 | .\" @(#)resolver.3 6.5 (Berkeley) 6/23/90 | 33 | .\" @(#)resolver.3 6.5 (Berkeley) 6/23/90 | |
34 | .\" Id: resolver.man3,v 1.2 2009/01/21 00:12:34 each Exp | 34 | .\" Id: resolver.man3,v 1.2 2009/01/21 00:12:34 each Exp | |
35 | .\" | 35 | .\" | |
36 | .Dd July 4, 2000 | 36 | .Dd July 4, 2000 | |
37 | .Dt RESOLVER 3 | 37 | .Dt RESOLVER 3 | |
38 | .Os | 38 | .Os | |
39 | .Sh NAME | 39 | .Sh NAME | |
40 | .Nm res_ninit , | 40 | .Nm res_ninit , | |
41 | .Nm res_ourserver_p , | 41 | .Nm res_ourserver_p , | |
42 | .Nm fp_resstat , | 42 | .Nm fp_resstat , | |
43 | .Nm res_hostalias , | 43 | .Nm res_hostalias , | |
44 | .Nm res_pquery , | 44 | .Nm res_pquery , | |
45 | .Nm res_nquery , | 45 | .Nm res_nquery , | |
46 | .Nm res_nsearch , | 46 | .Nm res_nsearch , | |
47 | .Nm res_nquerydomain , | 47 | .Nm res_nquerydomain , | |
48 | .Nm res_nmkquery , | 48 | .Nm res_nmkquery , | |
49 | .Nm res_nsend , | 49 | .Nm res_nsend , | |
50 | .Nm res_nupdate , | 50 | .Nm res_nupdate , | |
51 | .Nm res_nmkupdate , | 51 | .Nm res_nmkupdate , | |
52 | .Nm res_nclose , | 52 | .Nm res_nclose , | |
53 | .Nm res_nsendsigned , | 53 | .Nm res_nsendsigned , | |
54 | .Nm res_findzonecut , | 54 | .Nm res_findzonecut , | |
55 | .Nm res_getservers , | 55 | .Nm res_getservers , | |
56 | .Nm res_setservers , | 56 | .Nm res_setservers , | |
57 | .Nm res_ndestroy , | 57 | .Nm res_ndestroy , | |
58 | .Nm dn_comp , | 58 | .Nm dn_comp , | |
59 | .Nm dn_expand , | 59 | .Nm dn_expand , | |
60 | .\" .Nm hstrerror , | 60 | .\" .Nm hstrerror , | |
61 | .Nm res_init , | 61 | .Nm res_init , | |
62 | .Nm res_isourserver , | 62 | .Nm res_isourserver , | |
63 | .Nm fp_nquery , | 63 | .Nm fp_nquery , | |
64 | .Nm p_query , | 64 | .Nm p_query , | |
65 | .Nm hostalias , | 65 | .Nm hostalias , | |
66 | .Nm res_query , | 66 | .Nm res_query , | |
67 | .Nm res_search , | 67 | .Nm res_search , | |
68 | .Nm res_querydomain , | 68 | .Nm res_querydomain , | |
69 | .Nm res_mkquery , | 69 | .Nm res_mkquery , | |
70 | .Nm res_send , | 70 | .Nm res_send , | |
71 | .Nm res_update , | 71 | .Nm res_update , | |
72 | .Nm res_close , | 72 | .Nm res_close , | |
73 | .\" .Nm herror | 73 | .\" .Nm herror | |
74 | .Nd resolver routines | 74 | .Nd resolver routines | |
75 | .Sh LIBRARY | 75 | .Sh LIBRARY | |
76 | .Lb libc | 76 | .Lb libc | |
77 | .Sh SYNOPSIS | 77 | .Sh SYNOPSIS | |
78 | .In sys/types.h | 78 | .In sys/types.h | |
79 | .In netinet/in.h | 79 | .In netinet/in.h | |
80 | .In arpa/nameser.h | 80 | .In arpa/nameser.h | |
81 | .In resolv.h | 81 | .In resolv.h | |
82 | .In res_update.h | 82 | .In res_update.h | |
83 | .Vt typedef struct __res_state *res_state ; | 83 | .Vt typedef struct __res_state *res_state ; | |
84 | .Pp | 84 | .Pp | |
85 | .Ft int | 85 | .Ft int | |
86 | .Fn res_ninit "res_state statp" | 86 | .Fn res_ninit "res_state statp" | |
87 | .Ft int | 87 | .Ft int | |
88 | .Fn res_ourserver_p "const res_state statp" "const struct sockaddr_in *addr" | 88 | .Fn res_ourserver_p "const res_state statp" "const struct sockaddr_in *addr" | |
89 | .Ft void | 89 | .Ft void | |
90 | .Fn fp_resstat "const res_state statp" "FILE *fp" | 90 | .Fn fp_resstat "const res_state statp" "FILE *fp" | |
91 | .Ft "const char *" | 91 | .Ft "const char *" | |
92 | .Fn res_hostalias "const res_state statp" "const char *name" "char *buf" "size_t buflen" | 92 | .Fn res_hostalias "const res_state statp" "const char *name" "char *buf" "size_t buflen" | |
93 | .Ft int | 93 | .Ft int | |
94 | .Fn res_pquery "const res_state statp" "const u_char *msg" "int msglen" "FILE *fp" | 94 | .Fn res_pquery "const res_state statp" "const u_char *msg" "int msglen" "FILE *fp" | |
95 | .Ft int | 95 | .Ft int | |
96 | .Fn res_nquery "res_state statp" "const char *dname" "int class" "int type" "u_char *answer" "int anslen" | 96 | .Fn res_nquery "res_state statp" "const char *dname" "int class" "int type" "u_char *answer" "int anslen" | |
97 | .Ft int | 97 | .Ft int | |
98 | .Fn res_nsearch "res_state statp" "const char *dname" "int class" "int type" "u_char * answer" "int anslen" | 98 | .Fn res_nsearch "res_state statp" "const char *dname" "int class" "int type" "u_char * answer" "int anslen" | |
99 | .Ft int | 99 | .Ft int | |
100 | .Fn res_nquerydomain "res_state statp" "const char *name" "const char *domain" "int class" "int type" "u_char *answer" "int anslen" | 100 | .Fn res_nquerydomain "res_state statp" "const char *name" "const char *domain" "int class" "int type" "u_char *answer" "int anslen" | |
101 | .Ft int | 101 | .Ft int | |
102 | .Fo res_nmkquery | 102 | .Fo res_nmkquery | |
103 | .Fa "res_state statp" | 103 | .Fa "res_state statp" | |
104 | .Fa "int op" | 104 | .Fa "int op" | |
105 | .Fa "const char *dname" | 105 | .Fa "const char *dname" | |
106 | .Fa "int class" | 106 | .Fa "int class" | |
107 | .Fa "int type" | 107 | .Fa "int type" | |
108 | .Fa "const u_char *data" | 108 | .Fa "const u_char *data" | |
109 | .Fa "int datalen" | 109 | .Fa "int datalen" | |
110 | .Fa "const u_char *newrr" | 110 | .Fa "const u_char *newrr" | |
111 | .Fa "u_char *buf" | 111 | .Fa "u_char *buf" | |
112 | .Fa "int buflen" | 112 | .Fa "int buflen" | |
113 | .Fc | 113 | .Fc | |
114 | .Ft int | 114 | .Ft int | |
115 | .Fn res_nsend "res_state statp" "const u_char *msg" "int msglen" "u_char *answer" "int anslen" | 115 | .Fn res_nsend "res_state statp" "const u_char *msg" "int msglen" "u_char *answer" "int anslen" | |
116 | .Ft int | 116 | .Ft int | |
117 | .Fn res_nupdate "res_state statp" "ns_updrec *rrecp_in" | 117 | .Fn res_nupdate "res_state statp" "ns_updrec *rrecp_in" | |
118 | .Ft int | 118 | .Ft int | |
119 | .Fn res_nmkupdate "res_state statp" "ns_updrec *rrecp_in" "u_char *buf" "int buflen" | 119 | .Fn res_nmkupdate "res_state statp" "ns_updrec *rrecp_in" "u_char *buf" "int buflen" | |
120 | .Ft void | 120 | .Ft void | |
121 | .Fn res_nclose "res_state statp" | 121 | .Fn res_nclose "res_state statp" | |
122 | .Ft int | 122 | .Ft int | |
123 | .Fn res_nsendsigned "res_state statp" "const u_char *msg" "int msglen" "ns_tsig_key *key" "u_char *answer" "int anslen" | 123 | .Fn res_nsendsigned "res_state statp" "const u_char *msg" "int msglen" "ns_tsig_key *key" "u_char *answer" "int anslen" | |
124 | .Ft int | 124 | .Ft int | |
125 | .Fn res_findzonecut "res_state statp" "const char *dname" "ns_class class" "int options" "char *zname" "size_t zsize" "struct in_addr *addrs" "int naddrs" | 125 | .Fn res_findzonecut "res_state statp" "const char *dname" "ns_class class" "int options" "char *zname" "size_t zsize" "struct in_addr *addrs" "int naddrs" | |
126 | .Ft int | 126 | .Ft int | |
127 | .Fn res_getservers "res_state statp" "union res_sockaddr_union *set" "int cnt" | 127 | .Fn res_getservers "res_state statp" "union res_sockaddr_union *set" "int cnt" | |
128 | .Ft void | 128 | .Ft void | |
129 | .Fn res_setservers "res_state statp" "const union res_sockaddr_union *set" "int cnt" | 129 | .Fn res_setservers "res_state statp" "const union res_sockaddr_union *set" "int cnt" | |
130 | .Ft void | 130 | .Ft void | |
131 | .Fn res_ndestroy "res_state statp" | 131 | .Fn res_ndestroy "res_state statp" | |
132 | .Ft int | 132 | .Ft int | |
133 | .Fn dn_comp "const char *exp_dn" "u_char *comp_dn" "int length" "u_char **dnptrs" "u_char **lastdnptr" | 133 | .Fn dn_comp "const char *exp_dn" "u_char *comp_dn" "int length" "u_char **dnptrs" "u_char **lastdnptr" | |
134 | .Ft int | 134 | .Ft int | |
135 | .Fn dn_expand "const u_char *msg" "const u_char *eomorig" "const u_char *comp_dn" "char *exp_dn" "int length" | 135 | .Fn dn_expand "const u_char *msg" "const u_char *eomorig" "const u_char *comp_dn" "char *exp_dn" "int length" | |
136 | .\" .Ft "const char *" | 136 | .\" .Ft "const char *" | |
137 | .\" .Fn hstrerror "int err" | 137 | .\" .Fn hstrerror "int err" | |
138 | .Ss DEPRECATED | 138 | .Ss DEPRECATED | |
139 | .In sys/types.h | 139 | .In sys/types.h | |
140 | .In netinet/in.h | 140 | .In netinet/in.h | |
141 | .In arpa/nameser.h | 141 | .In arpa/nameser.h | |
142 | .In resolv.h | 142 | .In resolv.h | |
143 | .In res_update.h | 143 | .In res_update.h | |
144 | .Ft int | 144 | .Ft int | |
145 | .Fn res_init "void" | 145 | .Fn res_init "void" | |
146 | .Ft int | 146 | .Ft int | |
147 | .Fn res_isourserver "const struct sockaddr_in *addr" | 147 | .Fn res_isourserver "const struct sockaddr_in *addr" | |
148 | .Ft int | 148 | .Ft int | |
149 | .Fn fp_nquery "const u_char *msg" "int msglen" "FILE *fp" | 149 | .Fn fp_nquery "const u_char *msg" "int msglen" "FILE *fp" | |
150 | .Ft void | 150 | .Ft void | |
151 | .Fn p_query "const u_char *msg" "FILE *fp" | 151 | .Fn p_query "const u_char *msg" "FILE *fp" | |
152 | .Ft "const char *" | 152 | .Ft "const char *" | |
153 | .Fn hostalias "const char *name" | 153 | .Fn hostalias "const char *name" | |
154 | .Ft int | 154 | .Ft int | |
155 | .Fn res_query "const char *dname" "int class" "int type" "u_char *answer" "int anslen" | 155 | .Fn res_query "const char *dname" "int class" "int type" "u_char *answer" "int anslen" | |
156 | .Ft int | 156 | .Ft int | |
157 | .Fn res_search "const char *dname" "int class" "int type" "u_char *answer" "int anslen" | 157 | .Fn res_search "const char *dname" "int class" "int type" "u_char *answer" "int anslen" | |
158 | .Ft int | 158 | .Ft int | |
159 | .Fn res_querydomain "const char *name" "const char *domain" "int class" "int type" "u_char *answer" "int anslen" | 159 | .Fn res_querydomain "const char *name" "const char *domain" "int class" "int type" "u_char *answer" "int anslen" | |
160 | .Ft int | 160 | .Ft int | |
161 | .Fo res_mkquery | 161 | .Fo res_mkquery | |
162 | .Fa "int op" | 162 | .Fa "int op" | |
163 | .Fa "const char *dname" | 163 | .Fa "const char *dname" | |
164 | .Fa "int class" | 164 | .Fa "int class" | |
165 | .Fa "int type" | 165 | .Fa "int type" | |
166 | .Fa "const char *data" | 166 | .Fa "const char *data" | |
167 | .Fa "int datalen" | 167 | .Fa "int datalen" | |
168 | .Fa "struct rrec *newrr" | 168 | .Fa "struct rrec *newrr" | |
169 | .Fa "u_char *buf" | 169 | .Fa "u_char *buf" | |
170 | .Fa "int buflen" | 170 | .Fa "int buflen" | |
171 | .Fc | 171 | .Fc | |
172 | .Ft int | 172 | .Ft int | |
173 | .Fn res_send "const u_char *msg" "int msglen" "u_char *answer" "int anslen" | 173 | .Fn res_send "const u_char *msg" "int msglen" "u_char *answer" "int anslen" | |
174 | .Ft int | 174 | .Ft int | |
175 | .Fn res_update "ns_updrec *rrecp_in" | 175 | .Fn res_update "ns_updrec *rrecp_in" | |
176 | .Ft void | 176 | .Ft void | |
177 | .Fn res_close "void" | 177 | .Fn res_close "void" | |
178 | .\" .Ft void | 178 | .\" .Ft void | |
179 | .\" .Fn herror "const char *s" | 179 | .\" .Fn herror "const char *s" | |
180 | .Sh DESCRIPTION | 180 | .Sh DESCRIPTION | |
181 | These routines are used for making, sending and interpreting | 181 | These routines are used for making, sending and interpreting | |
182 | query and reply messages with Internet domain name servers. | 182 | query and reply messages with Internet domain name servers. | |
183 | .Pp | 183 | .Pp | |
184 | State information is kept in | 184 | State information is kept in | |
185 | .Fa statp | 185 | .Fa statp | |
186 | and is used to control the behavior of these functions. | 186 | and is used to control the behavior of these functions. | |
187 | .Fa statp | 187 | .Fa statp | |
188 | should be set to all zeros prior to the first call to any of these functions. | 188 | should be set to all zeros prior to the first call to any of these functions. | |
189 | .Pp | 189 | .Pp | |
190 | The functions | 190 | The functions | |
191 | .Fn res_init , | 191 | .Fn res_init , | |
192 | .Fn res_isourserver , | 192 | .Fn res_isourserver , | |
193 | .Fn fp_nquery , | 193 | .Fn fp_nquery , | |
194 | .Fn p_query , | 194 | .Fn p_query , | |
195 | .Fn hostalias , | 195 | .Fn hostalias , | |
196 | .Fn res_query , | 196 | .Fn res_query , | |
197 | .Fn res_search , | 197 | .Fn res_search , | |
198 | .Fn res_querydomain , | 198 | .Fn res_querydomain , | |
199 | .Fn res_mkquery , | 199 | .Fn res_mkquery , | |
200 | .Fn res_send , | 200 | .Fn res_send , | |
201 | .Fn res_update , | 201 | .Fn res_update , | |
202 | .Fn res_close | 202 | .Fn res_close | |
203 | .\" and | 203 | .\" and | |
204 | .\" .Fn herror | 204 | .\" .Fn herror | |
205 | are deprecated and are supplied for compatability with old source | 205 | are deprecated and are supplied for compatability with old source | |
206 | code. | 206 | code. | |
207 | They use global configuration and state information that is | 207 | They use global configuration and state information that is | |
208 | kept in the structure | 208 | kept in the structure | |
209 | .Ft _res | 209 | .Ft _res | |
210 | rather than that referenced through | 210 | rather than that referenced through | |
211 | .Ft statp . | 211 | .Ft statp . | |
212 | .Pp | 212 | .Pp | |
213 | Most of the values in | 213 | Most of the values in | |
214 | .Ft statp | 214 | .Ft statp | |
215 | and | 215 | and | |
216 | .Ft _res | 216 | .Ft _res | |
217 | are initialized on the first call to | 217 | are initialized on the first call to | |
218 | .Fn res_ninit | 218 | .Fn res_ninit | |
219 | / | 219 | / | |
220 | .Fn res_init | 220 | .Fn res_init | |
221 | to reasonable defaults and can be ignored. | 221 | to reasonable defaults and can be ignored. | |
222 | Options | 222 | Options | |
223 | stored in | 223 | stored in | |
224 | .Ft statp->options | 224 | .Ft statp->options | |
225 | / | 225 | / | |
226 | .Ft _res.options | 226 | .Ft _res.options | |
227 | are defined in | 227 | are defined in | |
228 | .Pa resolv.h | 228 | .Pa resolv.h | |
229 | and are as follows. | 229 | and are as follows. | |
230 | Options are stored as a simple bit mask containing the bitwise | 230 | Options are stored as a simple bit mask containing the bitwise | |
231 | .Dq OR | 231 | .Dq OR | |
232 | of the options enabled. | 232 | of the options enabled. | |
233 | .Bl -tag -width "RES_USE_INET6" | 233 | .Bl -tag -width "RES_USE_INET6" | |
234 | .It Dv RES_INIT | 234 | .It Dv RES_INIT | |
235 | True if the initial name server address and default domain name are | 235 | True if the initial name server address and default domain name are | |
236 | initialized (i.e., | 236 | initialized (i.e., | |
237 | .Fn res_ninit | 237 | .Fn res_ninit | |
238 | / | 238 | / | |
239 | .Fn res_init | 239 | .Fn res_init | |
240 | has been called). | 240 | has been called). | |
241 | .It Dv RES_DEBUG | 241 | .It Dv RES_DEBUG | |
242 | Print debugging messages. | 242 | Print debugging messages. | |
243 | .It Dv RES_AAONLY | 243 | .It Dv RES_AAONLY | |
244 | Accept authoritative answers only. | 244 | Accept authoritative answers only. | |
245 | Should continue until it finds an authoritative answer or finds an error. | 245 | Should continue until it finds an authoritative answer or finds an error. | |
246 | Currently this is not implemented. | 246 | Currently this is not implemented. | |
247 | .It Dv RES_USEVC | 247 | .It Dv RES_USEVC | |
248 | Use TCP connections for queries instead of UDP datagrams. | 248 | Use TCP connections for queries instead of UDP datagrams. | |
249 | .It Dv RES_STAYOPEN | 249 | .It Dv RES_STAYOPEN | |
250 | Used with | 250 | Used with | |
251 | .Dv RES_USEVC | 251 | .Dv RES_USEVC | |
252 | to keep the TCP connection open between queries. | 252 | to keep the TCP connection open between queries. | |
253 | This is useful only in programs that regularly do many queries. | 253 | This is useful only in programs that regularly do many queries. | |
254 | UDP should be the normal mode used. | 254 | UDP should be the normal mode used. | |
255 | .It Dv RES_IGNTC | 255 | .It Dv RES_IGNTC | |
256 | Ignore truncation errors, i.e., don't retry with TCP. | 256 | Ignore truncation errors, i.e., don't retry with TCP. | |
257 | .It Dv RES_RECURSE | 257 | .It Dv RES_RECURSE | |
258 | Set the recursion-desired bit in queries. | 258 | Set the recursion-desired bit in queries. | |
259 | This is the default. | 259 | This is the default. | |
260 | (\c | 260 | (\c | |
261 | .Fn res_nsend | 261 | .Fn res_nsend | |
262 | / | 262 | / | |
263 | .Fn res_send | 263 | .Fn res_send | |
264 | does not do iterative queries and expects the name server | 264 | does not do iterative queries and expects the name server | |
265 | to handle recursion.) | 265 | to handle recursion.) | |
266 | .It Dv RES_DEFNAMES | 266 | .It Dv RES_DEFNAMES | |
267 | If set, | 267 | If set, | |
268 | .Fn res_nsearch | 268 | .Fn res_nsearch | |
269 | / | 269 | / | |
270 | .Fn res_search | 270 | .Fn res_search | |
271 | will append the default domain name to single-component names | 271 | will append the default domain name to single-component names | |
272 | (those that do not contain a dot). | 272 | (those that do not contain a dot). | |
273 | This option is enabled by default. | 273 | This option is enabled by default. | |
274 | .It Dv RES_DNSRCH | 274 | .It Dv RES_DNSRCH | |
275 | If this option is set, | 275 | If this option is set, | |
276 | .Fn res_nsearch | 276 | .Fn res_nsearch | |
277 | / | 277 | / | |
278 | .Fn res_search | 278 | .Fn res_search | |
279 | will search for host names in the current domain and in parent domains; see | 279 | will search for host names in the current domain and in parent domains; see | |
280 | .Xr hostname 7 . | 280 | .Xr hostname 7 . | |
281 | This is used by the standard host lookup routine | 281 | This is used by the standard host lookup routine | |
282 | .Xr gethostbyname 3 . | 282 | .Xr gethostbyname 3 . | |
283 | This option is enabled by default. | 283 | This option is enabled by default. | |
284 | .It Dv RES_USE_INET6 | 284 | .It Dv RES_USE_INET6 | |
285 | Enables support for IPv6-only applications. | 285 | Enables support for IPv6-only applications. | |
286 | This causes IPv4 addresses to be returned as an IPv4 mapped address. | 286 | This causes IPv4 addresses to be returned as an IPv4 mapped address. | |
287 | For example, 10.1.1.1 will be returned as ::ffff:10.1.1.1. | 287 | For example, 10.1.1.1 will be returned as ::ffff:10.1.1.1. | |
288 | The option is meaningful with certain kernel configuration only. | 288 | The option is meaningful with certain kernel configuration only. | |
289 | .It Dv RES_USE_EDNS0 | 289 | .It Dv RES_USE_EDNS0 | |
290 | Enables support for OPT pseudo-RR for EDNS0 extension. | 290 | Enables support for OPT pseudo-RR for EDNS0 extension. | |
291 | With the option, resolver code will attach OPT pseudo-RR into DNS queries, | 291 | With the option, resolver code will attach OPT pseudo-RR into DNS queries, | |
292 | to inform of our receive buffer size. | 292 | to inform of our receive buffer size. | |
293 | The option will allow DNS servers to take advantage of non-default receive | 293 | The option will allow DNS servers to take advantage of non-default receive | |
294 | buffer size, and to send larger replies. | 294 | buffer size, and to send larger replies. | |
295 | DNS query packets with EDNS0 extension is not compatible with | 295 | DNS query packets with EDNS0 extension is not compatible with | |
296 | non-EDNS0 DNS servers. | 296 | non-EDNS0 DNS servers. | |
297 | .It Dv RES_NOALIASES | 297 | .It Dv RES_NOALIASES | |
298 | This option turns off the user level aliasing feature controlled by | 298 | This option turns off the user level aliasing feature controlled by | |
299 | the | 299 | the | |
300 | .Ev HOSTALIASES | 300 | .Ev HOSTALIASES | |
301 | environment variable. | 301 | environment variable. | |
302 | Network daemons should set this option. | 302 | Network daemons should set this option. | |
303 | .It Dv RES_ROTATE | 303 | .It Dv RES_ROTATE | |
304 | This options causes the | 304 | This options causes the | |
305 | .Fn res_nsend | 305 | .Fn res_nsend | |
306 | / | 306 | / | |
307 | .Fn res_send | 307 | .Fn res_send | |
308 | to rotate the list of nameservers in | 308 | to rotate the list of nameservers in | |
309 | .Fa statp->nsaddr_list | 309 | .Fa statp->nsaddr_list | |
310 | / | 310 | / | |
311 | .Fa _res.nsaddr_list . | 311 | .Fa _res.nsaddr_list . | |
312 | .It Dv RES_KEEPTSIG | 312 | .It Dv RES_KEEPTSIG | |
313 | This option causes | 313 | This option causes | |
314 | .Fn res_nsendsigned | 314 | .Fn res_nsendsigned | |
315 | to leave the message unchanged after TSIG verification; otherwise the TSIG | 315 | to leave the message unchanged after TSIG verification; otherwise the TSIG | |
316 | record would be removed and the header updated. | 316 | record would be removed and the header updated. | |
317 | .It Dv RES_NOTLDQUERY | 317 | .It Dv RES_NOTLDQUERY | |
318 | This option causes | 318 | This option causes | |
319 | .Fn res_nsearch | 319 | .Fn res_nsearch | |
320 | to not attempt to resolve a unqualified name as if it were a top level | 320 | to not attempt to resolve an unqualified name as if it were a top level | |
321 | domain (TLD). | 321 | domain (TLD). | |
322 | This option can cause problems if the site has "localhost" as a TLD rather | 322 | This option can cause problems if the site has "localhost" as a TLD rather | |
323 | than having localhost on one or more elements of the search list. | 323 | than having localhost on one or more elements of the search list. | |
324 | This option has no effect if neither | 324 | This option has no effect if neither | |
325 | .Dv RES_DEFNAMES | 325 | .Dv RES_DEFNAMES | |
326 | or | 326 | or | |
327 | .Dv RES_DNSRCH | 327 | .Dv RES_DNSRCH | |
328 | is set. | 328 | is set. | |
329 | .El | 329 | .El | |
330 | .Pp | 330 | .Pp | |
331 | The | 331 | The | |
332 | .Fn res_ninit | 332 | .Fn res_ninit | |
333 | / | 333 | / | |
334 | .Fn res_init | 334 | .Fn res_init | |
335 | routine | 335 | routine | |
336 | reads the configuration file (if any; see | 336 | reads the configuration file (if any; see | |
337 | .Xr resolv.conf 5 ) | 337 | .Xr resolv.conf 5 ) | |
338 | to get the default domain name, search list and | 338 | to get the default domain name, search list and | |
339 | the Internet address of the local name server(s). | 339 | the Internet address of the local name server(s). | |
340 | If no server is configured, the host running the resolver is tried. | 340 | If no server is configured, the host running the resolver is tried. | |
341 | The current domain name is defined by the hostname | 341 | The current domain name is defined by the hostname | |
342 | if not specified in the configuration file; | 342 | if not specified in the configuration file; | |
343 | it can be overridden by the environment variable | 343 | it can be overridden by the environment variable | |
344 | .Ev LOCALDOMAIN . | 344 | .Ev LOCALDOMAIN . | |
345 | This environment variable may contain several blank-separated | 345 | This environment variable may contain several blank-separated | |
346 | tokens if you wish to override the | 346 | tokens if you wish to override the | |
347 | .Fa search list | 347 | .Fa search list | |
348 | on a per-process basis. This is similar to the | 348 | on a per-process basis. This is similar to the | |
349 | .Fa search | 349 | .Fa search | |
350 | command in the configuration file. | 350 | command in the configuration file. | |
351 | Another environment variable | 351 | Another environment variable | |
352 | .Ev RES_OPTIONS | 352 | .Ev RES_OPTIONS | |
353 | can be set to override certain internal resolver options which are otherwise | 353 | can be set to override certain internal resolver options which are otherwise | |
354 | set by changing fields in the | 354 | set by changing fields in the | |
355 | .Ft statp | 355 | .Ft statp | |
356 | / | 356 | / | |
357 | .Ft _res | 357 | .Ft _res | |
358 | structure or are inherited from the configuration file's | 358 | structure or are inherited from the configuration file's | |
359 | .Fa options | 359 | .Fa options | |
360 | command. | 360 | command. | |
361 | The syntax of the | 361 | The syntax of the | |
362 | .Ev RES_OPTIONS | 362 | .Ev RES_OPTIONS | |
363 | environment variable is explained in | 363 | environment variable is explained in | |
364 | .Xr resolv.conf 5 . | 364 | .Xr resolv.conf 5 . | |
365 | Initialization normally occurs on the first call | 365 | Initialization normally occurs on the first call | |
366 | to one of the other resolver routines. | 366 | to one of the other resolver routines. | |
367 | .Pp | 367 | .Pp | |
368 | The memory referred to by | 368 | The memory referred to by | |
369 | .Ft statp | 369 | .Ft statp | |
370 | must be set to all zeros prior to the first call to | 370 | must be set to all zeros prior to the first call to | |
371 | .Fn res_ninit . | 371 | .Fn res_ninit . | |
372 | .Fn res_ndestroy | 372 | .Fn res_ndestroy | |
373 | should be call to free memory allocated by | 373 | should be call to free memory allocated by | |
374 | .Fn res_ninit | 374 | .Fn res_ninit | |
375 | after last use. | 375 | after last use. | |
376 | .Pp | 376 | .Pp | |
377 | The | 377 | The | |
378 | .Fn res_nquery | 378 | .Fn res_nquery | |
379 | / | 379 | / | |
380 | .Fn res_query | 380 | .Fn res_query | |
381 | functions provides interfaces to the server query mechanism. | 381 | functions provides interfaces to the server query mechanism. | |
382 | They constructs a query, sends it to the local server, | 382 | They constructs a query, sends it to the local server, | |
383 | awaits a response, and makes preliminary checks on the reply. | 383 | awaits a response, and makes preliminary checks on the reply. | |
384 | The query requests information of the specified | 384 | The query requests information of the specified | |
385 | .Fa type | 385 | .Fa type | |
386 | and | 386 | and | |
387 | .Fa class | 387 | .Fa class | |
388 | for the specified fully-qualified domain name | 388 | for the specified fully-qualified domain name | |
389 | .Fa dname . | 389 | .Fa dname . | |
390 | The reply message is left in the | 390 | The reply message is left in the | |
391 | .Fa answer | 391 | .Fa answer | |
392 | buffer with length | 392 | buffer with length | |
393 | .Fa anslen | 393 | .Fa anslen | |
394 | supplied by the caller. | 394 | supplied by the caller. | |
395 | .Fn res_nquery | 395 | .Fn res_nquery | |
396 | / | 396 | / | |
397 | .Fn res_query | 397 | .Fn res_query | |
398 | return -1 on error or the length of the answer. | 398 | return -1 on error or the length of the answer. | |
399 | .Pp | 399 | .Pp | |
400 | The | 400 | The | |
401 | .Fn res_nsearch | 401 | .Fn res_nsearch | |
402 | / | 402 | / | |
403 | .Fn res_search | 403 | .Fn res_search | |
404 | routines make a query and awaits a response like | 404 | routines make a query and awaits a response like | |
405 | .Fn res_nquery | 405 | .Fn res_nquery | |
406 | / | 406 | / | |
407 | .Fn res_query , | 407 | .Fn res_query , | |
408 | but in addition, it implements the default and search rules | 408 | but in addition, it implements the default and search rules | |
409 | controlled by the | 409 | controlled by the | |
410 | .Dv RES_DEFNAMES | 410 | .Dv RES_DEFNAMES | |
411 | and | 411 | and | |
412 | .Dv RES_DNSRCH | 412 | .Dv RES_DNSRCH | |
413 | options. | 413 | options. | |
414 | It returns the length of the first successful reply which is stored in | 414 | It returns the length of the first successful reply which is stored in | |
415 | .Ft answer | 415 | .Ft answer | |
416 | or -1 on error. | 416 | or -1 on error. | |
417 | .Pp | 417 | .Pp | |
418 | The remaining routines are lower-level routines used by | 418 | The remaining routines are lower-level routines used by | |
419 | .Fn res_nquery | 419 | .Fn res_nquery | |
420 | / | 420 | / | |
421 | .Fn res_query . | 421 | .Fn res_query . | |
422 | The | 422 | The | |
423 | .Fn res_nmkquery | 423 | .Fn res_nmkquery | |
424 | / | 424 | / | |
425 | .Fn res_mkquery | 425 | .Fn res_mkquery | |
426 | functions | 426 | functions | |
427 | constructs a standard query message and places it in | 427 | constructs a standard query message and places it in | |
428 | .Fa buf . | 428 | .Fa buf . | |
429 | It returns the size of the query, or \-1 if the query is | 429 | It returns the size of the query, or \-1 if the query is | |
430 | larger than | 430 | larger than | |
431 | .Fa buflen . | 431 | .Fa buflen . | |
432 | The query type | 432 | The query type | |
433 | .Fa op | 433 | .Fa op | |
434 | is usually | 434 | is usually | |
435 | .Dv QUERY , | 435 | .Dv QUERY , | |
436 | but can be any of the query types defined in | 436 | but can be any of the query types defined in | |
437 | .Pa <arpa/nameser.h> . | 437 | .Pa <arpa/nameser.h> . | |
438 | The domain name for the query is given by | 438 | The domain name for the query is given by | |
439 | .Fa dname . | 439 | .Fa dname . | |
440 | .Fa newrr | 440 | .Fa newrr | |
441 | is currently unused but is intended for making update messages. | 441 | is currently unused but is intended for making update messages. | |
442 | .Pp | 442 | .Pp | |
443 | The | 443 | The | |
444 | .Fn res_nsend | 444 | .Fn res_nsend | |
445 | / | 445 | / | |
446 | .Fn res_send | 446 | .Fn res_send | |
447 | / | 447 | / | |
448 | .Fn res_nsendsigned | 448 | .Fn res_nsendsigned | |
449 | routines | 449 | routines | |
450 | sends a pre-formatted query and returns an answer. | 450 | sends a pre-formatted query and returns an answer. | |
451 | It will call | 451 | It will call | |
452 | .Fn res_ninit | 452 | .Fn res_ninit | |
453 | / | 453 | / | |
454 | .Fn res_init | 454 | .Fn res_init | |
455 | if | 455 | if | |
456 | .Dv RES_INIT | 456 | .Dv RES_INIT | |
457 | is not set, send the query to the local name server, and | 457 | is not set, send the query to the local name server, and | |
458 | handle timeouts and retries. Additionally, | 458 | handle timeouts and retries. Additionally, | |
459 | .Fn res_nsendsigned | 459 | .Fn res_nsendsigned | |
460 | will use TSIG signatures to add authentication to the query and verify the | 460 | will use TSIG signatures to add authentication to the query and verify the | |
461 | response. In this case, only one nameserver will be contacted. | 461 | response. In this case, only one nameserver will be contacted. | |
462 | The length of the reply message is returned, or \-1 if there were errors. | 462 | The length of the reply message is returned, or \-1 if there were errors. | |
463 | .Pp | 463 | .Pp | |
464 | .Fn res_nquery | 464 | .Fn res_nquery | |
465 | / | 465 | / | |
466 | .Fn res_query , | 466 | .Fn res_query , | |
467 | .Fn res_nsearch | 467 | .Fn res_nsearch | |
468 | / | 468 | / | |
469 | .Fn res_search | 469 | .Fn res_search | |
470 | and | 470 | and | |
471 | .Fn res_nsend | 471 | .Fn res_nsend | |
472 | / | 472 | / | |
473 | .Fn res_send | 473 | .Fn res_send | |
474 | return a length that may be bigger than | 474 | return a length that may be bigger than | |
475 | .Fa anslen . | 475 | .Fa anslen . | |
476 | In that case the query should be retried with a bigger buffer. | 476 | In that case the query should be retried with a bigger buffer. | |
477 | NOTE the answer to the second query may be larger still so supplying | 477 | NOTE the answer to the second query may be larger still so supplying | |
478 | a buffer that bigger that the answer returned by the previous | 478 | a buffer that bigger that the answer returned by the previous | |
479 | query is recommended. | 479 | query is recommended. | |
480 | .Pp | 480 | .Pp | |
481 | .Fa answer | 481 | .Fa answer | |
482 | MUST be big enough to receive a maximum UDP response from the server or | 482 | MUST be big enough to receive a maximum UDP response from the server or | |
483 | parts of the answer will be silently discarded. | 483 | parts of the answer will be silently discarded. | |
484 | The default maximum UDP response size is 512 bytes. | 484 | The default maximum UDP response size is 512 bytes. | |
485 | .Pp | 485 | .Pp | |
486 | The function | 486 | The function | |
487 | .Fn res_ourserver_p | 487 | .Fn res_ourserver_p | |
488 | returns true when | 488 | returns true when | |
489 | .Fa inp | 489 | .Fa inp | |
490 | is one of the servers in | 490 | is one of the servers in | |
491 | .Fa statp->nsaddr_list | 491 | .Fa statp->nsaddr_list | |
492 | / | 492 | / | |
493 | .Fa _res.nsaddr_list . | 493 | .Fa _res.nsaddr_list . | |
494 | .Pp | 494 | .Pp | |
495 | The functions | 495 | The functions | |
496 | .Fn fp_nquery | 496 | .Fn fp_nquery | |
497 | / | 497 | / | |
498 | .Fn p_query | 498 | .Fn p_query | |
499 | print out the query and any answer in | 499 | print out the query and any answer in | |
500 | .Fa msg | 500 | .Fa msg | |
501 | on | 501 | on | |
502 | .Fa fp . | 502 | .Fa fp . | |
503 | .Fn p_query | 503 | .Fn p_query | |
504 | is equivalent to | 504 | is equivalent to | |
505 | .Fn fp_nquery | 505 | .Fn fp_nquery | |
506 | with | 506 | with | |
507 | .Fa msglen | 507 | .Fa msglen | |
508 | set to 512. | 508 | set to 512. | |
509 | .Pp | 509 | .Pp | |
510 | The function | 510 | The function | |
511 | .Fn fp_resstat | 511 | .Fn fp_resstat | |
512 | prints out the active flag bits in | 512 | prints out the active flag bits in | |
513 | .Fa statp->options | 513 | .Fa statp->options | |
514 | preceeded by the text ";; res options:" on | 514 | preceeded by the text ";; res options:" on | |
515 | .Fa file . | 515 | .Fa file . | |
516 | .Pp | 516 | .Pp | |
517 | The functions | 517 | The functions | |
518 | .Fn res_hostalias | 518 | .Fn res_hostalias | |
519 | / | 519 | / | |
520 | .Fn hostalias | 520 | .Fn hostalias | |
521 | lookup up name in the file referred to by the | 521 | lookup up name in the file referred to by the | |
522 | .Ev HOSTALIASES | 522 | .Ev HOSTALIASES | |
523 | files return a fully qualified hostname if found or NULL if | 523 | files return a fully qualified hostname if found or NULL if | |
524 | not found or an error occurred. | 524 | not found or an error occurred. | |
525 | .Fn res_hostalias | 525 | .Fn res_hostalias | |
526 | uses | 526 | uses | |
527 | .Fa buf | 527 | .Fa buf | |
528 | to store the result in, | 528 | to store the result in, | |
529 | .Fn hostalias | 529 | .Fn hostalias | |
530 | uses a static buffer. | 530 | uses a static buffer. | |
531 | .Pp | 531 | .Pp | |
532 | The functions | 532 | The functions | |
533 | .Fn res_getservers | 533 | .Fn res_getservers | |
534 | and | 534 | and | |
535 | .Fn res_setservers | 535 | .Fn res_setservers | |
536 | are used to get and set the list of server to be queried. | 536 | are used to get and set the list of server to be queried. | |
537 | .Pp | 537 | .Pp | |
538 | The functions | 538 | The functions | |
539 | .Fn res_nupdate | 539 | .Fn res_nupdate | |
540 | / | 540 | / | |
541 | .Fn res_update | 541 | .Fn res_update | |
542 | take a list of ns_updrec | 542 | take a list of ns_updrec | |
543 | .Fa rrecp_in . | 543 | .Fa rrecp_in . | |
544 | Identifies the containing zone for each record and groups the records | 544 | Identifies the containing zone for each record and groups the records | |
545 | according to containing zone maintaining in zone order then sends and update | 545 | according to containing zone maintaining in zone order then sends and update | |
546 | request to the servers for these zones. The number of zones updated is | 546 | request to the servers for these zones. The number of zones updated is | |
547 | returned or -1 on error. Note that | 547 | returned or -1 on error. Note that | |
548 | .Fn res_nupdate | 548 | .Fn res_nupdate | |
549 | will perform TSIG authenticated dynamic update operations if the key is not | 549 | will perform TSIG authenticated dynamic update operations if the key is not | |
550 | NULL. | 550 | NULL. | |
551 | .Pp | 551 | .Pp | |
552 | The function | 552 | The function | |
553 | .Fn res_findzonecut | 553 | .Fn res_findzonecut | |
554 | discovers the closest enclosing zone cut for a specified domain name, | 554 | discovers the closest enclosing zone cut for a specified domain name, | |
555 | and finds the IP addresses of the zone's master servers. | 555 | and finds the IP addresses of the zone's master servers. | |
556 | .Pp | 556 | .Pp | |
557 | The functions | 557 | The functions | |
558 | .Fn res_nmkupdate | 558 | .Fn res_nmkupdate | |
559 | / | 559 | / | |
560 | .Fn res_mkupdate | 560 | .Fn res_mkupdate | |
561 | take a linked list of ns_updrec | 561 | take a linked list of ns_updrec | |
562 | .Fa rrecp_in | 562 | .Fa rrecp_in | |
563 | and construct a UPDATE message in | 563 | and construct a UPDATE message in | |
564 | .Fa buf . | 564 | .Fa buf . | |
565 | .Fn res_nmkupdate | 565 | .Fn res_nmkupdate | |
566 | / | 566 | / | |
567 | .Fn res_mkupdate | 567 | .Fn res_mkupdate | |
568 | return the length of the constructed message on no error or one of the | 568 | return the length of the constructed message on no error or one of the | |
569 | following error values. | 569 | following error values. | |
570 | .Bl -inset -width "-5" | 570 | .Bl -inset -width "-5" | |
571 | .It -1 | 571 | .It -1 | |
572 | An error occurred parsing | 572 | An error occurred parsing | |
573 | .Fa rrecp_in . | 573 | .Fa rrecp_in . | |
574 | .It -2 | 574 | .It -2 | |
575 | The buffer | 575 | The buffer | |
576 | .Fa buf | 576 | .Fa buf | |
577 | was too small. | 577 | was too small. | |
578 | .It -3 | 578 | .It -3 | |
579 | The first record was not a zone section or there was a section order problem. | 579 | The first record was not a zone section or there was a section order problem. | |
580 | The section order is S_ZONE, S_PREREQ and S_UPDATE. | 580 | The section order is S_ZONE, S_PREREQ and S_UPDATE. | |
581 | .It -4 | 581 | .It -4 | |
582 | A number overflow occurred. | 582 | A number overflow occurred. | |
583 | .It -5 | 583 | .It -5 | |
584 | Unknown operation or no records. | 584 | Unknown operation or no records. | |
585 | .El | 585 | .El | |
586 | .Pp | 586 | .Pp | |
587 | The functions | 587 | The functions | |
588 | .Fn res_nclose | 588 | .Fn res_nclose | |
589 | / | 589 | / | |
590 | .Fn res_close | 590 | .Fn res_close | |
591 | close any open files referenced through | 591 | close any open files referenced through | |
592 | .Fa statp | 592 | .Fa statp | |
593 | / | 593 | / | |
594 | .Fa _res . | 594 | .Fa _res . | |
595 | .Pp | 595 | .Pp | |
596 | The function | 596 | The function | |
597 | .Fn res_ndestroy | 597 | .Fn res_ndestroy | |
598 | calls | 598 | calls | |
599 | .Fn res_nclose | 599 | .Fn res_nclose | |
600 | then frees any memory allocated by | 600 | then frees any memory allocated by | |
601 | .Fn res_ninit . | 601 | .Fn res_ninit . | |
602 | .Pp | 602 | .Pp | |
603 | The | 603 | The | |
604 | .Fn dn_comp | 604 | .Fn dn_comp | |
605 | function | 605 | function | |
606 | compresses the domain name | 606 | compresses the domain name | |
607 | .Fa exp_dn | 607 | .Fa exp_dn | |
608 | and stores it in | 608 | and stores it in | |
609 | .Fa comp_dn . | 609 | .Fa comp_dn . | |
610 | The size of the compressed name is returned or \-1 if there were errors. | 610 | The size of the compressed name is returned or \-1 if there were errors. | |
611 | The size of the array pointed to by | 611 | The size of the array pointed to by | |
612 | .Fa comp_dn | 612 | .Fa comp_dn | |
613 | is given by | 613 | is given by | |
614 | .Fa length . | 614 | .Fa length . | |
615 | The compression uses | 615 | The compression uses | |
616 | an array of pointers | 616 | an array of pointers | |
617 | .Fa dnptrs | 617 | .Fa dnptrs | |
618 | to previously-compressed names in the current message. | 618 | to previously-compressed names in the current message. | |
619 | The first pointer points to | 619 | The first pointer points to | |
620 | the beginning of the message and the list ends with | 620 | the beginning of the message and the list ends with | |
621 | .Dv NULL . | 621 | .Dv NULL . | |
622 | The limit to the array is specified by | 622 | The limit to the array is specified by | |
623 | .Fa lastdnptr . | 623 | .Fa lastdnptr . | |
624 | A side effect of | 624 | A side effect of | |
625 | .Fn dn_comp | 625 | .Fn dn_comp | |
626 | is to update the list of pointers for labels inserted into the message | 626 | is to update the list of pointers for labels inserted into the message | |
627 | as the name is compressed. If | 627 | as the name is compressed. If | |
628 | .Fa dnptr | 628 | .Fa dnptr | |
629 | is | 629 | is | |
630 | .Dv NULL , | 630 | .Dv NULL , | |
631 | names are not compressed. If | 631 | names are not compressed. If | |
632 | .Fa lastdnptr | 632 | .Fa lastdnptr | |
633 | is | 633 | is | |
634 | .Dv NULL , | 634 | .Dv NULL , | |
635 | the list of labels is not updated. | 635 | the list of labels is not updated. | |
636 | .Pp | 636 | .Pp | |
637 | The | 637 | The | |
638 | .Fn dn_expand | 638 | .Fn dn_expand | |
639 | entry expands the compressed domain name | 639 | entry expands the compressed domain name | |
640 | .Fa comp_dn | 640 | .Fa comp_dn | |
641 | to a full domain name. | 641 | to a full domain name. | |
642 | The compressed name is contained in a query or reply message; | 642 | The compressed name is contained in a query or reply message; | |
643 | .Fa msg | 643 | .Fa msg | |
644 | is a pointer to the beginning of the message. | 644 | is a pointer to the beginning of the message. | |
645 | .Fa eomorig | 645 | .Fa eomorig | |
646 | is a pointer to the first location after the message. | 646 | is a pointer to the first location after the message. | |
647 | The uncompressed name is placed in the buffer indicated by | 647 | The uncompressed name is placed in the buffer indicated by | |
648 | .Fa exp_dn | 648 | .Fa exp_dn | |
649 | which is of size | 649 | which is of size | |
650 | .Fa length . | 650 | .Fa length . | |
651 | The size of compressed name is returned or \-1 if there was an error. | 651 | The size of compressed name is returned or \-1 if there was an error. | |
652 | .Pp | 652 | .Pp | |
653 | The variables | 653 | The variables | |
654 | .Ft statp->res_h_errno | 654 | .Ft statp->res_h_errno | |
655 | / | 655 | / | |
656 | .Ft _res.res_h_errno | 656 | .Ft _res.res_h_errno | |
657 | and external variable | 657 | and external variable | |
658 | .Ft h_errno | 658 | .Ft h_errno | |
659 | is set whenever an error occurs during resolver operation. The following | 659 | is set whenever an error occurs during resolver operation. The following | |
660 | definitions are given in | 660 | definitions are given in | |
661 | .Pa <netdb.h> : | 661 | .Pa <netdb.h> : | |
662 | .Bd -literal | 662 | .Bd -literal | |
663 | #define NETDB_INTERNAL -1 | 663 | #define NETDB_INTERNAL -1 | |
664 | /* see errno */ | 664 | /* see errno */ | |
665 | #define NETDB_SUCCESS 0 | 665 | #define NETDB_SUCCESS 0 | |
666 | /* no problem */ | 666 | /* no problem */ | |
667 | #define HOST_NOT_FOUND 1 | 667 | #define HOST_NOT_FOUND 1 | |
668 | /* Authoritative Answer Host not found */ | 668 | /* Authoritative Answer Host not found */ | |
669 | #define TRY_AGAIN 2 | 669 | #define TRY_AGAIN 2 | |
670 | /* Non-Authoritative not found, or SERVFAIL */ | 670 | /* Non-Authoritative not found, or SERVFAIL */ | |
671 | #define NO_RECOVERY 3 | 671 | #define NO_RECOVERY 3 | |
672 | /* Non-Recoverable: FORMERR, REFUSED, NOTIMP */ | 672 | /* Non-Recoverable: FORMERR, REFUSED, NOTIMP */ | |
673 | #define NO_DATA 4 | 673 | #define NO_DATA 4 | |
674 | /* Valid name, no data for requested type */ | 674 | /* Valid name, no data for requested type */ | |
675 | .Ed | 675 | .Ed | |
676 | .\" .Pp | 676 | .\" .Pp | |
677 | .\" The | 677 | .\" The | |
678 | .\" .Fn herror | 678 | .\" .Fn herror | |
679 | .\" function writes a message to the diagnostic output consisting of the string | 679 | .\" function writes a message to the diagnostic output consisting of the string | |
680 | .\" parameter | 680 | .\" parameter | |
681 | .\" .Fa s , | 681 | .\" .Fa s , | |
682 | .\" the constant string ": ", and a message corresponding to the value of | 682 | .\" the constant string ": ", and a message corresponding to the value of | |
683 | .\" .Ft h_errno . | 683 | .\" .Ft h_errno . | |
684 | .\" .Pp | 684 | .\" .Pp | |
685 | .\" The | 685 | .\" The | |
686 | .\" .Fn hstrerror | 686 | .\" .Fn hstrerror | |
687 | .\" function returns a string which is the message text corresponding to the | 687 | .\" function returns a string which is the message text corresponding to the | |
688 | .\" value of the | 688 | .\" value of the | |
689 | .\" .Fa err | 689 | .\" .Fa err | |
690 | .\" parameter. | 690 | .\" parameter. | |
691 | .Sh FILES | 691 | .Sh FILES | |
692 | .Bl -tag -width "/etc/resolv.conf " | 692 | .Bl -tag -width "/etc/resolv.conf " | |
693 | .It Pa | 693 | .It Pa | |
694 | /etc/resolv.conf | 694 | /etc/resolv.conf | |
695 | The configuration file, see | 695 | The configuration file, see | |
696 | .Xr resolv.conf 5 . | 696 | .Xr resolv.conf 5 . | |
697 | .El | 697 | .El | |
698 | .Sh SEE ALSO | 698 | .Sh SEE ALSO | |
699 | .Xr gethostbyname 3 , | 699 | .Xr gethostbyname 3 , | |
700 | .Xr hostname 7 , | 700 | .Xr hostname 7 , | |
701 | .Xr resolv.conf 5 , | 701 | .Xr resolv.conf 5 , | |
702 | .Xr named 8 | 702 | .Xr named 8 | |
703 | .Pp | 703 | .Pp | |
704 | .%T RFC 974 , | 704 | .%T RFC 974 , | |
705 | .%T RFC 1032 , | 705 | .%T RFC 1032 , | |
706 | .%T RFC 1033 , | 706 | .%T RFC 1033 , | |
707 | .%T RFC 1034 , | 707 | .%T RFC 1034 , | |
708 | .%T RFC 1035 , | 708 | .%T RFC 1035 , | |
709 | .%T RFC 1535 | 709 | .%T RFC 1535 | |
710 | .Rs | 710 | .Rs | |
711 | .%T "Name Server Operations Guide for BIND" | 711 | .%T "Name Server Operations Guide for BIND" | |
712 | .Re | 712 | .Re | |
713 | .Sh HISTORY | 713 | .Sh HISTORY | |
714 | The | 714 | The | |
715 | .Nm | 715 | .Nm | |
716 | function appeared in | 716 | function appeared in | |
717 | .Bx 4.3 . | 717 | .Bx 4.3 . |