File: | src/lib/libc/asr/gethostnamadr_async.c |
Warning: | line 324, column 8 Although the value stored to 'r' is used in the enclosing expression, the value is never actually read from 'r' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: gethostnamadr_async.c,v 1.49 2023/11/22 13:19:31 florian Exp $ */ |
2 | /* |
3 | * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> |
4 | * |
5 | * Permission to use, copy, modify, and distribute this software for any |
6 | * purpose with or without fee is hereby granted, provided that the above |
7 | * copyright notice and this permission notice appear in all copies. |
8 | * |
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
16 | */ |
17 | |
18 | #include <sys/types.h> |
19 | #include <sys/socket.h> |
20 | #include <netinet/in.h> |
21 | #include <arpa/inet.h> |
22 | #include <arpa/nameser.h> |
23 | #include <netdb.h> |
24 | |
25 | #include <asr.h> |
26 | #include <ctype.h> |
27 | #include <errno(*__errno()).h> |
28 | #include <resolv.h> /* for res_hnok */ |
29 | #include <stdlib.h> |
30 | #include <string.h> |
31 | #include <unistd.h> |
32 | #include <limits.h> |
33 | |
34 | #include "asr_private.h" |
35 | |
36 | #define MAXALIASES35 35 |
37 | #define MAXADDRS35 35 |
38 | |
39 | struct hostent_ext { |
40 | struct hostent h; |
41 | char *aliases[MAXALIASES35 + 1]; |
42 | char *addrs[MAXADDRS35 + 1]; |
43 | char *end; |
44 | char *pos; |
45 | }; |
46 | |
47 | struct netent_ext { |
48 | struct netent n; |
49 | char *aliases[MAXALIASES35 + 1]; |
50 | char *end; |
51 | char *pos; |
52 | }; |
53 | |
54 | static int gethostnamadr_async_run(struct asr_query *, struct asr_result *); |
55 | static struct hostent_ext *hostent_alloc(int); |
56 | static int hostent_set_cname(struct hostent_ext *, const char *, int); |
57 | static int hostent_add_alias(struct hostent_ext *, const char *, int); |
58 | static int hostent_add_addr(struct hostent_ext *, const void *, size_t); |
59 | static struct hostent_ext *hostent_from_addr(int, const char *, const char *); |
60 | static struct hostent_ext *hostent_file_match(FILE *, int, int, const char *, |
61 | int); |
62 | static struct hostent_ext *hostent_from_packet(int, int, char *, size_t); |
63 | static void netent_from_hostent(struct asr_result *ar); |
64 | |
65 | struct asr_query * |
66 | gethostbyname_async(const char *name, void *asr) |
67 | { |
68 | return gethostbyname2_async(name, AF_INET2, asr); |
69 | } |
70 | DEF_WEAK(gethostbyname_async)__asm__(".weak " "gethostbyname_async" " ; " "gethostbyname_async" " = " "_libc_gethostbyname_async"); |
71 | |
72 | struct asr_query * |
73 | gethostbyname2_async(const char *name, int af, void *asr) |
74 | { |
75 | struct asr_ctx *ac; |
76 | struct asr_query *as; |
77 | |
78 | /* the original segfaults */ |
79 | if (name == NULL((void *)0)) { |
80 | errno(*__errno()) = EINVAL22; |
81 | return (NULL((void *)0)); |
82 | } |
83 | |
84 | ac = _asr_use_resolver(asr); |
85 | if ((as = _asr_async_new(ac, ASR_GETHOSTBYNAME)) == NULL((void *)0)) |
86 | goto abort; /* errno set */ |
87 | as->as_run = gethostnamadr_async_run; |
88 | |
89 | as->as.hostnamadr.family = af; |
90 | if (af == AF_INET2) |
91 | as->as.hostnamadr.addrlen = INADDRSZ4; |
92 | else if (af == AF_INET624) |
93 | as->as.hostnamadr.addrlen = IN6ADDRSZ16; |
94 | as->as.hostnamadr.name = strdup(name); |
95 | if (as->as.hostnamadr.name == NULL((void *)0)) |
96 | goto abort; /* errno set */ |
97 | |
98 | _asr_ctx_unref(ac); |
99 | return (as); |
100 | |
101 | abort: |
102 | if (as) |
103 | _asr_async_free(as); |
104 | _asr_ctx_unref(ac); |
105 | return (NULL((void *)0)); |
106 | } |
107 | DEF_WEAK(gethostbyname2_async)__asm__(".weak " "gethostbyname2_async" " ; " "gethostbyname2_async" " = " "_libc_gethostbyname2_async"); |
108 | |
109 | struct asr_query * |
110 | gethostbyaddr_async(const void *addr, socklen_t len, int af, void *asr) |
111 | { |
112 | struct asr_ctx *ac; |
113 | struct asr_query *as; |
114 | |
115 | ac = _asr_use_resolver(asr); |
116 | as = _gethostbyaddr_async_ctx(addr, len, af, ac); |
117 | _asr_ctx_unref(ac); |
118 | |
119 | return (as); |
120 | } |
121 | DEF_WEAK(gethostbyaddr_async)__asm__(".weak " "gethostbyaddr_async" " ; " "gethostbyaddr_async" " = " "_libc_gethostbyaddr_async"); |
122 | |
123 | struct asr_query * |
124 | _gethostbyaddr_async_ctx(const void *addr, socklen_t len, int af, |
125 | struct asr_ctx *ac) |
126 | { |
127 | struct asr_query *as; |
128 | |
129 | if ((as = _asr_async_new(ac, ASR_GETHOSTBYADDR)) == NULL((void *)0)) |
130 | goto abort; /* errno set */ |
131 | as->as_run = gethostnamadr_async_run; |
132 | |
133 | as->as.hostnamadr.family = af; |
134 | as->as.hostnamadr.addrlen = len; |
135 | if (len > 0) |
136 | memmove(as->as.hostnamadr.addr, addr, (len > 16) ? 16 : len); |
137 | |
138 | return (as); |
139 | |
140 | abort: |
141 | if (as) |
142 | _asr_async_free(as); |
143 | return (NULL((void *)0)); |
144 | } |
145 | |
146 | static int |
147 | gethostnamadr_async_run(struct asr_query *as, struct asr_result *ar) |
148 | { |
149 | struct hostent_ext *h; |
150 | int r, type, saved_errno; |
151 | FILE *f; |
152 | char name[MAXDNAME1025], *data, addr[16], *c; |
153 | |
154 | next: |
155 | switch (as->as_state) { |
156 | |
157 | case ASR_STATE_INIT: |
158 | |
159 | if (as->as.hostnamadr.family != AF_INET2 && |
160 | as->as.hostnamadr.family != AF_INET624) { |
161 | ar->ar_h_errno = NETDB_INTERNAL-1; |
162 | ar->ar_errno = EAFNOSUPPORT47; |
163 | async_set_state(as, ASR_STATE_HALT)do { ; (as)->as_state = (ASR_STATE_HALT); } while (0); |
164 | break; |
165 | } |
166 | |
167 | if ((as->as.hostnamadr.family == AF_INET2 && |
168 | as->as.hostnamadr.addrlen != INADDRSZ4) || |
169 | (as->as.hostnamadr.family == AF_INET624 && |
170 | as->as.hostnamadr.addrlen != IN6ADDRSZ16)) { |
171 | ar->ar_h_errno = NETDB_INTERNAL-1; |
172 | ar->ar_errno = EINVAL22; |
173 | async_set_state(as, ASR_STATE_HALT)do { ; (as)->as_state = (ASR_STATE_HALT); } while (0); |
174 | break; |
175 | } |
176 | |
177 | if (as->as_type == ASR_GETHOSTBYNAME) { |
178 | |
179 | if (as->as.hostnamadr.name[0] == '\0') { |
180 | ar->ar_h_errno = NO_DATA4; |
181 | async_set_state(as, ASR_STATE_HALT)do { ; (as)->as_state = (ASR_STATE_HALT); } while (0); |
182 | break; |
183 | } |
184 | |
185 | /* Name might be an IP address string */ |
186 | for (c = as->as.hostnamadr.name; *c; c++) |
187 | if (!isdigit((unsigned char)*c) && |
188 | *c != '.' && *c != ':') |
189 | break; |
190 | if (*c == 0 && |
191 | inet_pton(as->as.hostnamadr.family, |
192 | as->as.hostnamadr.name, addr) == 1) { |
193 | h = hostent_from_addr(as->as.hostnamadr.family, |
194 | as->as.hostnamadr.name, addr); |
195 | if (h == NULL((void *)0)) { |
196 | ar->ar_errno = errno(*__errno()); |
197 | ar->ar_h_errno = NETDB_INTERNAL-1; |
198 | } |
199 | else { |
200 | ar->ar_hostent = &h->h; |
201 | ar->ar_h_errno = NETDB_SUCCESS0; |
202 | } |
203 | async_set_state(as, ASR_STATE_HALT)do { ; (as)->as_state = (ASR_STATE_HALT); } while (0); |
204 | break; |
205 | } |
206 | |
207 | if (!hnok_lenient(as->as.hostnamadr.name)) { |
208 | ar->ar_h_errno = NETDB_INTERNAL-1; |
209 | ar->ar_errno = EINVAL22; |
210 | async_set_state(as, ASR_STATE_HALT)do { ; (as)->as_state = (ASR_STATE_HALT); } while (0); |
211 | break; |
212 | } |
213 | |
214 | /* |
215 | * If hostname is "localhost" or falls within the |
216 | * ".localhost." domain, use local address. |
217 | * RFC 6761, 6.3: |
218 | * 3. Name resolution APIs and libraries SHOULD |
219 | * recognize localhost names as special and SHOULD |
220 | * always return the IP loopback address for address |
221 | * queries and negative responses for all other query |
222 | * types. Name resolution APIs SHOULD NOT send queries |
223 | * for localhost names to their configured caching DNS |
224 | * server(s). |
225 | */ |
226 | |
227 | if (_asr_is_localhost(as->as.hostnamadr.name)) { |
228 | inet_pton(as->as.hostnamadr.family, |
229 | as->as.hostnamadr.family == AF_INET2 ? |
230 | "127.0.0.1" : "::1", addr); |
231 | h = hostent_from_addr(as->as.hostnamadr.family, |
232 | as->as.hostnamadr.name, addr); |
233 | if (h == NULL((void *)0)) { |
234 | ar->ar_errno = errno(*__errno()); |
235 | ar->ar_h_errno = NETDB_INTERNAL-1; |
236 | } |
237 | else { |
238 | ar->ar_hostent = &h->h; |
239 | ar->ar_h_errno = NETDB_SUCCESS0; |
240 | } |
241 | async_set_state(as, ASR_STATE_HALT)do { ; (as)->as_state = (ASR_STATE_HALT); } while (0); |
242 | break; |
243 | } |
244 | } |
245 | async_set_state(as, ASR_STATE_NEXT_DB)do { ; (as)->as_state = (ASR_STATE_NEXT_DB); } while (0); |
246 | break; |
247 | |
248 | case ASR_STATE_NEXT_DB: |
249 | |
250 | if (_asr_iter_db(as) == -1) { |
251 | async_set_state(as, ASR_STATE_NOT_FOUND)do { ; (as)->as_state = (ASR_STATE_NOT_FOUND); } while (0); |
252 | break; |
253 | } |
254 | |
255 | switch (AS_DB(as)((as)->as_ctx->ac_db[(as)->as_db_idx - 1])) { |
256 | |
257 | case ASR_DB_DNS'b': |
258 | |
259 | /* Create a subquery to do the DNS lookup */ |
260 | |
261 | if (as->as_type == ASR_GETHOSTBYNAME) { |
262 | type = (as->as.hostnamadr.family == AF_INET2) ? |
263 | T_A1 : T_AAAA28; |
264 | as->as_subq = _res_search_async_ctx( |
265 | as->as.hostnamadr.name, |
266 | C_IN1, type, as->as_ctx); |
267 | } else { |
268 | _asr_addr_as_fqdn(as->as.hostnamadr.addr, |
269 | as->as.hostnamadr.family, |
270 | name, sizeof(name)); |
271 | as->as_subq = _res_query_async_ctx( |
272 | name, C_IN1, T_PTR12, as->as_ctx); |
273 | } |
274 | |
275 | if (as->as_subq == NULL((void *)0)) { |
276 | ar->ar_errno = errno(*__errno()); |
277 | ar->ar_h_errno = NETDB_INTERNAL-1; |
278 | async_set_state(as, ASR_STATE_HALT)do { ; (as)->as_state = (ASR_STATE_HALT); } while (0); |
279 | break; |
280 | } |
281 | |
282 | async_set_state(as, ASR_STATE_SUBQUERY)do { ; (as)->as_state = (ASR_STATE_SUBQUERY); } while (0); |
283 | break; |
284 | |
285 | case ASR_DB_FILE'f': |
286 | |
287 | /* Try to find a match in the host file */ |
288 | |
289 | if ((f = fopen(_PATH_HOSTS"/etc/hosts", "re")) == NULL((void *)0)) |
290 | break; |
291 | |
292 | if (as->as_type == ASR_GETHOSTBYNAME) |
293 | data = as->as.hostnamadr.name; |
294 | else |
295 | data = as->as.hostnamadr.addr; |
296 | |
297 | h = hostent_file_match(f, as->as_type, |
298 | as->as.hostnamadr.family, data, |
299 | as->as.hostnamadr.addrlen); |
300 | saved_errno = errno(*__errno()); |
301 | fclose(f); |
302 | errno(*__errno()) = saved_errno; |
303 | |
304 | if (h == NULL((void *)0)) { |
305 | if (errno(*__errno())) { |
306 | ar->ar_errno = errno(*__errno()); |
307 | ar->ar_h_errno = NETDB_INTERNAL-1; |
308 | async_set_state(as, ASR_STATE_HALT)do { ; (as)->as_state = (ASR_STATE_HALT); } while (0); |
309 | } |
310 | /* otherwise not found */ |
311 | break; |
312 | } |
313 | ar->ar_hostent = &h->h; |
314 | ar->ar_h_errno = NETDB_SUCCESS0; |
315 | async_set_state(as, ASR_STATE_HALT)do { ; (as)->as_state = (ASR_STATE_HALT); } while (0); |
316 | break; |
317 | } |
318 | break; |
319 | |
320 | case ASR_STATE_SUBQUERY: |
321 | |
322 | /* Run the DNS subquery. */ |
323 | |
324 | if ((r = asr_run(as->as_subq, ar)) == ASYNC_COND0) |
Although the value stored to 'r' is used in the enclosing expression, the value is never actually read from 'r' | |
325 | return (ASYNC_COND0); |
326 | |
327 | /* Done. */ |
328 | as->as_subq = NULL((void *)0); |
329 | |
330 | /* |
331 | * We either got no packet or a packet without an answer. |
332 | * Saveguard the h_errno and use the next DB. |
333 | */ |
334 | if (ar->ar_count == 0) { |
335 | free(ar->ar_data); |
336 | as->as.hostnamadr.subq_h_errno = ar->ar_h_errno; |
337 | async_set_state(as, ASR_STATE_NEXT_DB)do { ; (as)->as_state = (ASR_STATE_NEXT_DB); } while (0); |
338 | break; |
339 | } |
340 | |
341 | /* Read the hostent from the packet. */ |
342 | |
343 | h = hostent_from_packet(as->as_type, |
344 | as->as.hostnamadr.family, ar->ar_data, ar->ar_datalen); |
345 | free(ar->ar_data); |
346 | if (h == NULL((void *)0)) { |
347 | ar->ar_errno = errno(*__errno()); |
348 | ar->ar_h_errno = NETDB_INTERNAL-1; |
349 | async_set_state(as, ASR_STATE_HALT)do { ; (as)->as_state = (ASR_STATE_HALT); } while (0); |
350 | break; |
351 | } |
352 | |
353 | if (as->as_type == ASR_GETHOSTBYADDR) { |
354 | if (hostent_add_addr(h, as->as.hostnamadr.addr, |
355 | as->as.hostnamadr.addrlen) == -1) { |
356 | free(h); |
357 | ar->ar_errno = errno(*__errno()); |
358 | ar->ar_h_errno = NETDB_INTERNAL-1; |
359 | async_set_state(as, ASR_STATE_HALT)do { ; (as)->as_state = (ASR_STATE_HALT); } while (0); |
360 | break; |
361 | } |
362 | } |
363 | |
364 | /* |
365 | * No valid hostname or address found in the dns packet. |
366 | * Ignore it. |
367 | */ |
368 | if ((as->as_type == ASR_GETHOSTBYNAME && |
369 | h->h.h_addr_list[0] == NULL((void *)0)) || |
370 | h->h.h_name == NULL((void *)0)) { |
371 | free(h); |
372 | async_set_state(as, ASR_STATE_NEXT_DB)do { ; (as)->as_state = (ASR_STATE_NEXT_DB); } while (0); |
373 | break; |
374 | } |
375 | |
376 | ar->ar_hostent = &h->h; |
377 | ar->ar_h_errno = NETDB_SUCCESS0; |
378 | async_set_state(as, ASR_STATE_HALT)do { ; (as)->as_state = (ASR_STATE_HALT); } while (0); |
379 | break; |
380 | |
381 | case ASR_STATE_NOT_FOUND: |
382 | ar->ar_errno = 0; |
383 | if (as->as.hostnamadr.subq_h_errno) |
384 | ar->ar_h_errno = as->as.hostnamadr.subq_h_errno; |
385 | else |
386 | ar->ar_h_errno = HOST_NOT_FOUND1; |
387 | async_set_state(as, ASR_STATE_HALT)do { ; (as)->as_state = (ASR_STATE_HALT); } while (0); |
388 | break; |
389 | |
390 | case ASR_STATE_HALT: |
391 | if (ar->ar_h_errno == NETDB_SUCCESS0 && |
392 | as->as_flags & ASYNC_GETNET0x00001000) |
393 | netent_from_hostent(ar); |
394 | if (ar->ar_h_errno) { |
395 | ar->ar_hostent = NULL((void *)0); |
396 | ar->ar_netent = NULL((void *)0); |
397 | } else |
398 | ar->ar_errno = 0; |
399 | return (ASYNC_DONE1); |
400 | |
401 | default: |
402 | ar->ar_errno = EOPNOTSUPP45; |
403 | ar->ar_h_errno = NETDB_INTERNAL-1; |
404 | ar->ar_gai_errno = EAI_SYSTEM-11; |
405 | async_set_state(as, ASR_STATE_HALT)do { ; (as)->as_state = (ASR_STATE_HALT); } while (0); |
406 | break; |
407 | } |
408 | goto next; |
409 | } |
410 | |
411 | /* |
412 | * Create a hostent from a numeric address string. |
413 | */ |
414 | static struct hostent_ext * |
415 | hostent_from_addr(int family, const char *name, const char *addr) |
416 | { |
417 | struct hostent_ext *h; |
418 | |
419 | if ((h = hostent_alloc(family)) == NULL((void *)0)) |
420 | return (NULL((void *)0)); |
421 | if (hostent_set_cname(h, name, 0) == -1) |
422 | goto fail; |
423 | if (hostent_add_addr(h, addr, h->h.h_length) == -1) |
424 | goto fail; |
425 | return (h); |
426 | fail: |
427 | free(h); |
428 | return (NULL((void *)0)); |
429 | } |
430 | |
431 | /* |
432 | * Lookup the first matching entry in the hostfile, either by address or by |
433 | * name depending on reqtype, and build a hostent from the line. |
434 | */ |
435 | static struct hostent_ext * |
436 | hostent_file_match(FILE *f, int reqtype, int family, const char *data, |
437 | int datalen) |
438 | { |
439 | char *tokens[MAXTOKEN10], addr[16], buf[BUFSIZ1024 + 1]; |
440 | struct hostent_ext *h; |
441 | int n, i; |
442 | |
443 | for (;;) { |
444 | n = _asr_parse_namedb_line(f, tokens, MAXTOKEN10, buf, sizeof(buf)); |
445 | if (n == -1) { |
446 | errno(*__errno()) = 0; /* ignore errors reading the file */ |
447 | return (NULL((void *)0)); |
448 | } |
449 | |
450 | /* there must be an address and at least one name */ |
451 | if (n < 2) |
452 | continue; |
453 | |
454 | if (reqtype == ASR_GETHOSTBYNAME) { |
455 | for (i = 1; i < n; i++) { |
456 | if (strcasecmp(data, tokens[i])) |
457 | continue; |
458 | if (inet_pton(family, tokens[0], addr) == 1) |
459 | goto found; |
460 | } |
461 | } else { |
462 | if (inet_pton(family, tokens[0], addr) == 1 && |
463 | memcmp(addr, data, datalen) == 0) |
464 | goto found; |
465 | } |
466 | } |
467 | |
468 | found: |
469 | if ((h = hostent_alloc(family)) == NULL((void *)0)) |
470 | return (NULL((void *)0)); |
471 | if (hostent_set_cname(h, tokens[1], 0) == -1) |
472 | goto fail; |
473 | for (i = 2; i < n; i ++) |
474 | if (hostent_add_alias(h, tokens[i], 0) == -1) |
475 | goto fail; |
476 | if (hostent_add_addr(h, addr, h->h.h_length) == -1) |
477 | goto fail; |
478 | return (h); |
479 | fail: |
480 | free(h); |
481 | return (NULL((void *)0)); |
482 | } |
483 | |
484 | /* |
485 | * Fill the hostent from the given DNS packet. |
486 | */ |
487 | static struct hostent_ext * |
488 | hostent_from_packet(int reqtype, int family, char *pkt, size_t pktlen) |
489 | { |
490 | struct hostent_ext *h; |
491 | struct asr_unpack p; |
492 | struct asr_dns_header hdr; |
493 | struct asr_dns_query q; |
494 | struct asr_dns_rr rr; |
495 | char dname[MAXDNAME1025]; |
496 | |
497 | if ((h = hostent_alloc(family)) == NULL((void *)0)) |
498 | return (NULL((void *)0)); |
499 | |
500 | _asr_unpack_init(&p, pkt, pktlen); |
501 | _asr_unpack_header(&p, &hdr); |
502 | for (; hdr.qdcount; hdr.qdcount--) |
503 | _asr_unpack_query(&p, &q); |
504 | strlcpy(dname, q.q_dname, sizeof(dname)); |
505 | |
506 | for (; hdr.ancount; hdr.ancount--) { |
507 | _asr_unpack_rr(&p, &rr); |
508 | if (rr.rr_class != C_IN1) |
509 | continue; |
510 | switch (rr.rr_type) { |
511 | |
512 | case T_CNAME5: |
513 | if (reqtype == ASR_GETHOSTBYNAME) { |
514 | if (hostent_add_alias(h, rr.rr_dname, 1) == -1) |
515 | goto fail; |
516 | } else { |
517 | if (strcasecmp(rr.rr_dname, dname) == 0) |
518 | strlcpy(dname, rr.rr.cname.cname, |
519 | sizeof(dname)); |
520 | } |
521 | break; |
522 | |
523 | case T_PTR12: |
524 | if (reqtype != ASR_GETHOSTBYADDR) |
525 | break; |
526 | if (strcasecmp(rr.rr_dname, dname) != 0) |
527 | continue; |
528 | if (hostent_set_cname(h, rr.rr.ptr.ptrname, 1) == -1) |
529 | hostent_add_alias(h, rr.rr.ptr.ptrname, 1); |
530 | break; |
531 | |
532 | case T_A1: |
533 | if (reqtype != ASR_GETHOSTBYNAME) |
534 | break; |
535 | if (family != AF_INET2) |
536 | break; |
537 | if (hostent_set_cname(h, rr.rr_dname, 1) == -1) |
538 | ; |
539 | if (hostent_add_addr(h, &rr.rr.in_a.addr, 4) == -1) |
540 | goto fail; |
541 | break; |
542 | |
543 | case T_AAAA28: |
544 | if (reqtype != ASR_GETHOSTBYNAME) |
545 | break; |
546 | if (family != AF_INET624) |
547 | break; |
548 | if (hostent_set_cname(h, rr.rr_dname, 1) == -1) |
549 | ; |
550 | if (hostent_add_addr(h, &rr.rr.in_aaaa.addr6, 16) == -1) |
551 | goto fail; |
552 | break; |
553 | } |
554 | } |
555 | |
556 | return (h); |
557 | fail: |
558 | free(h); |
559 | return (NULL((void *)0)); |
560 | } |
561 | |
562 | static struct hostent_ext * |
563 | hostent_alloc(int family) |
564 | { |
565 | struct hostent_ext *h; |
566 | size_t alloc; |
567 | |
568 | alloc = sizeof(*h) + 1024; |
569 | if ((h = calloc(1, alloc)) == NULL((void *)0)) |
570 | return (NULL((void *)0)); |
571 | |
572 | h->h.h_addrtype = family; |
573 | h->h.h_length = (family == AF_INET2) ? 4 : 16; |
574 | h->h.h_aliases = h->aliases; |
575 | h->h.h_addr_list = h->addrs; |
576 | h->pos = (char *)(h) + sizeof(*h); |
577 | h->end = h->pos + 1024; |
578 | |
579 | return (h); |
580 | } |
581 | |
582 | static int |
583 | hostent_set_cname(struct hostent_ext *h, const char *name, int isdname) |
584 | { |
585 | char buf[MAXDNAME1025]; |
586 | size_t n; |
587 | |
588 | if (h->h.h_name) |
589 | return (-1); |
590 | |
591 | if (isdname) { |
592 | _asr_strdname(name, buf, sizeof buf); |
593 | buf[strlen(buf) - 1] = '\0'; |
594 | if (!res_hnok__res_hnok(buf)) |
595 | return (-1); |
596 | name = buf; |
597 | } |
598 | |
599 | n = strlen(name) + 1; |
600 | if (h->pos + n >= h->end) |
601 | return (-1); |
602 | |
603 | h->h.h_name = h->pos; |
604 | memmove(h->pos, name, n); |
605 | h->pos += n; |
606 | return (0); |
607 | } |
608 | |
609 | static int |
610 | hostent_add_alias(struct hostent_ext *h, const char *name, int isdname) |
611 | { |
612 | char buf[MAXDNAME1025]; |
613 | size_t i, n; |
614 | |
615 | for (i = 0; i < MAXALIASES35; i++) |
616 | if (h->aliases[i] == NULL((void *)0)) |
617 | break; |
618 | if (i == MAXALIASES35) |
619 | return (0); |
620 | |
621 | if (isdname) { |
622 | _asr_strdname(name, buf, sizeof buf); |
623 | buf[strlen(buf)-1] = '\0'; |
624 | if (!res_hnok__res_hnok(buf)) |
625 | return (-1); |
626 | name = buf; |
627 | } |
628 | |
629 | n = strlen(name) + 1; |
630 | if (h->pos + n >= h->end) |
631 | return (0); |
632 | |
633 | h->aliases[i] = h->pos; |
634 | memmove(h->pos, name, n); |
635 | h->pos += n; |
636 | return (0); |
637 | } |
638 | |
639 | static int |
640 | hostent_add_addr(struct hostent_ext *h, const void *addr, size_t size) |
641 | { |
642 | int i; |
643 | |
644 | for (i = 0; i < MAXADDRS35; i++) |
645 | if (h->addrs[i] == NULL((void *)0)) |
646 | break; |
647 | if (i == MAXADDRS35) |
648 | return (0); |
649 | |
650 | if (h->pos + size >= h->end) |
651 | return (0); |
652 | |
653 | h->addrs[i] = h->pos; |
654 | memmove(h->pos, addr, size); |
655 | h->pos += size; |
656 | return (0); |
657 | } |
658 | |
659 | static void |
660 | netent_from_hostent(struct asr_result *ar) |
661 | { |
662 | struct in_addr *addr; |
663 | struct netent_ext *n; |
664 | struct hostent_ext *h; |
665 | char **na, **ha; |
666 | size_t sz; |
667 | |
668 | /* Allocate and initialize the output. */ |
669 | if ((n = calloc(1, sizeof(*n) + 1024)) == NULL((void *)0)) { |
670 | ar->ar_h_errno = NETDB_INTERNAL-1; |
671 | ar->ar_errno = errno(*__errno()); |
672 | goto out; |
673 | } |
674 | n->pos = (char *)(n) + sizeof(*n); |
675 | n->end = n->pos + 1024; |
676 | n->n.n_name = n->pos; |
677 | n->n.n_aliases = n->aliases; |
678 | |
679 | /* Copy the fixed-size data. */ |
680 | h = (struct hostent_ext *)ar->ar_hostent; |
681 | addr = (struct in_addr *)h->h.h_addrh_addr_list[0]; |
682 | n->n.n_net = ntohl(addr->s_addr)(__uint32_t)(__builtin_constant_p(addr->s_addr) ? (__uint32_t )(((__uint32_t)(addr->s_addr) & 0xff) << 24 | (( __uint32_t)(addr->s_addr) & 0xff00) << 8 | ((__uint32_t )(addr->s_addr) & 0xff0000) >> 8 | ((__uint32_t) (addr->s_addr) & 0xff000000) >> 24) : __swap32md (addr->s_addr)); |
683 | n->n.n_addrtype = h->h.h_addrtype; |
684 | |
685 | /* Copy the network name. */ |
686 | sz = strlen(h->h.h_name) + 1; |
687 | memcpy(n->pos, h->h.h_name, sz); |
688 | n->pos += sz; |
689 | |
690 | /* |
691 | * Copy the aliases. |
692 | * No overflow check is needed because we are merely copying |
693 | * a part of the data from a structure of the same size. |
694 | */ |
695 | na = n->aliases; |
696 | for (ha = h->aliases; *ha != NULL((void *)0); ha++) { |
697 | sz = strlen(*ha) + 1; |
698 | memcpy(n->pos, *ha, sz); |
699 | *na++ = n->pos; |
700 | n->pos += sz; |
701 | } |
702 | *na = NULL((void *)0); |
703 | |
704 | /* Handle the return values. */ |
705 | ar->ar_netent = &n->n; |
706 | out: |
707 | free(ar->ar_hostent); |
708 | ar->ar_hostent = NULL((void *)0); |
709 | } |