]>
Commit | Line | Data |
---|---|---|
9d957ce2 | 1 | /* Copyright (C) 1993, 1995-2001, 2002 Free Software Foundation, Inc. |
41bdb6e2 | 2 | This file is part of the GNU C Library. |
fa0bc87c RM |
3 | Contributed by David Mosberger (davidm@azstarnet.com). |
4 | ||
c84142e8 | 5 | The GNU C Library is free software; you can redistribute it and/or |
41bdb6e2 AJ |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either | |
8 | version 2.1 of the License, or (at your option) any later version. | |
fa0bc87c | 9 | |
c84142e8 UD |
10 | The GNU C Library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
41bdb6e2 | 13 | Lesser General Public License for more details. |
fa0bc87c | 14 | |
41bdb6e2 AJ |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, write to the Free | |
17 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
18 | 02111-1307 USA. */ | |
fa0bc87c RM |
19 | |
20 | /* This file provides a Linux /etc/host.conf compatible front end to | |
f720d3d2 UD |
21 | the various name resolvers (/etc/hosts, named, NIS server, etc.). |
22 | Though mostly compatibly, the following differences exist compared | |
23 | to the original implementation: | |
fa0bc87c RM |
24 | |
25 | - new command "spoof" takes an arguments like RESOLV_SPOOF_CHECK | |
26 | environment variable (i.e., `off', `nowarn', or `warn'). | |
27 | ||
28 | - line comments can appear anywhere (not just at the beginning of | |
29 | a line) | |
30 | */ | |
f720d3d2 UD |
31 | |
32 | #include <errno.h> | |
fa0bc87c | 33 | #include <ctype.h> |
51028f34 | 34 | #include <libintl.h> |
fa0bc87c RM |
35 | #include <memory.h> |
36 | #include <stdio.h> | |
2706ee38 | 37 | #include <stdio_ext.h> |
fa0bc87c RM |
38 | #include <stdlib.h> |
39 | #include <string.h> | |
5edb9387 | 40 | #include <net/if.h> |
f720d3d2 UD |
41 | #include <sys/ioctl.h> |
42 | #include <unistd.h> | |
43 | #include <netinet/in.h> | |
44 | #include <bits/libc-lock.h> | |
45 | #include "ifreq.h" | |
fa0bc87c | 46 | #include "res_hconf.h" |
51028f34 UD |
47 | #ifdef USE_IN_LIBIO |
48 | # include <wchar.h> | |
49 | #endif | |
fa0bc87c RM |
50 | |
51 | #define _PATH_HOSTCONF "/etc/host.conf" | |
52 | ||
53 | /* Environment vars that all user to override default behavior: */ | |
54 | #define ENV_HOSTCONF "RESOLV_HOST_CONF" | |
55 | #define ENV_SERVORDER "RESOLV_SERV_ORDER" | |
56 | #define ENV_SPOOF "RESOLV_SPOOF_CHECK" | |
57 | #define ENV_TRIM_OVERR "RESOLV_OVERRIDE_TRIM_DOMAINS" | |
58 | #define ENV_TRIM_ADD "RESOLV_ADD_TRIM_DOMAINS" | |
59 | #define ENV_MULTI "RESOLV_MULTI" | |
60 | #define ENV_REORDER "RESOLV_REORDER" | |
61 | ||
5edb9387 UD |
62 | static const char *arg_service_list (const char *, int, const char *, |
63 | unsigned int); | |
64 | static const char *arg_trimdomain_list (const char *, int, const char *, | |
65 | unsigned int); | |
66 | static const char *arg_spoof (const char *, int, const char *, unsigned int); | |
67 | static const char *arg_bool (const char *, int, const char *, unsigned int); | |
68 | ||
69 | static struct cmd | |
70 | { | |
71 | const char *name; | |
72 | const char *(*parse_args) (const char * filename, int line_num, | |
73 | const char * args, unsigned int arg); | |
74 | unsigned int arg; | |
75 | } cmd[] = | |
76 | { | |
fa0bc87c RM |
77 | {"order", arg_service_list, 0}, |
78 | {"trim", arg_trimdomain_list, 0}, | |
79 | {"spoof", arg_spoof, 0}, | |
80 | {"multi", arg_bool, HCONF_FLAG_MULTI}, | |
81 | {"nospoof", arg_bool, HCONF_FLAG_SPOOF}, | |
82 | {"spoofalert", arg_bool, HCONF_FLAG_SPOOFALERT}, | |
83 | {"reorder", arg_bool, HCONF_FLAG_REORDER} | |
84 | }; | |
85 | ||
5edb9387 UD |
86 | /* Structure containing the state. */ |
87 | struct hconf _res_hconf; | |
fa0bc87c | 88 | |
fa0bc87c RM |
89 | /* Skip white space. */ |
90 | static const char * | |
5edb9387 | 91 | skip_ws (const char *str) |
fa0bc87c RM |
92 | { |
93 | while (isspace (*str)) ++str; | |
94 | return str; | |
95 | } | |
96 | ||
97 | ||
98 | /* Skip until whitespace, comma, end of line, or comment character. */ | |
99 | static const char * | |
5edb9387 | 100 | skip_string (const char *str) |
fa0bc87c | 101 | { |
5edb9387 UD |
102 | while (*str && !isspace (*str) && *str != '#' && *str != ',') |
103 | ++str; | |
fa0bc87c RM |
104 | return str; |
105 | } | |
106 | ||
107 | ||
108 | static const char * | |
5edb9387 UD |
109 | arg_service_list (const char *fname, int line_num, const char *args, |
110 | unsigned int arg) | |
fa0bc87c RM |
111 | { |
112 | enum Name_Service service; | |
5edb9387 | 113 | const char *start; |
fa0bc87c | 114 | size_t len; |
57b36a0a | 115 | size_t i; |
5edb9387 UD |
116 | static struct |
117 | { | |
118 | const char * name; | |
119 | enum Name_Service service; | |
120 | } svcs[] = | |
121 | { | |
122 | {"bind", SERVICE_BIND}, | |
123 | {"hosts", SERVICE_HOSTS}, | |
124 | {"nis", SERVICE_NIS}, | |
125 | }; | |
fa0bc87c RM |
126 | |
127 | do | |
128 | { | |
129 | start = args; | |
130 | args = skip_string (args); | |
131 | len = args - start; | |
132 | ||
133 | service = SERVICE_NONE; | |
134 | for (i = 0; i < sizeof (svcs) / sizeof (svcs[0]); ++i) | |
135 | { | |
5edb9387 | 136 | if (__strncasecmp (start, svcs[i].name, len) == 0 |
fa0bc87c RM |
137 | && len == strlen (svcs[i].name)) |
138 | { | |
139 | service = svcs[i].service; | |
140 | break; | |
141 | } | |
142 | } | |
143 | if (service == SERVICE_NONE) | |
144 | { | |
51028f34 UD |
145 | char *buf; |
146 | ||
147 | __asprintf (&buf, _("%s: line %d: expected service, found `%s'\n"), | |
148 | fname, line_num, start); | |
149 | ||
150 | #ifdef USE_IN_LIBIO | |
151 | if (_IO_fwide (stderr, 0) > 0) | |
6293b803 | 152 | __fwprintf (stderr, L"%s", buf); |
51028f34 UD |
153 | else |
154 | #endif | |
155 | fputs (buf, stderr); | |
156 | ||
157 | free (buf); | |
fa0bc87c RM |
158 | return 0; |
159 | } | |
160 | if (_res_hconf.num_services >= SERVICE_MAX) | |
161 | { | |
51028f34 UD |
162 | char *buf; |
163 | ||
164 | __asprintf (&buf, | |
165 | _("%s: line %d: cannot specify more than %d services"), | |
166 | fname, line_num, SERVICE_MAX); | |
167 | ||
168 | #ifdef USE_IN_LIBIO | |
169 | if (_IO_fwide (stderr, 0) > 0) | |
6293b803 | 170 | __fwprintf (stderr, L"%s", buf); |
51028f34 UD |
171 | else |
172 | #endif | |
173 | fputs (buf, stderr); | |
174 | ||
175 | free (buf); | |
fa0bc87c RM |
176 | return 0; |
177 | } | |
178 | _res_hconf.service[_res_hconf.num_services++] = service; | |
179 | ||
180 | args = skip_ws (args); | |
181 | switch (*args) | |
182 | { | |
5edb9387 UD |
183 | case ',': |
184 | case ';': | |
185 | case ':': | |
fa0bc87c RM |
186 | args = skip_ws (++args); |
187 | if (!*args || *args == '#') | |
188 | { | |
51028f34 UD |
189 | char *buf; |
190 | ||
191 | __asprintf (&buf, _("\ | |
192 | %s: line %d: list delimiter not followed by keyword"), | |
193 | fname, line_num); | |
194 | ||
195 | #ifdef USE_IN_LIBIO | |
196 | if (_IO_fwide (stderr, 0) > 0) | |
6293b803 | 197 | __fwprintf (stderr, L"%s", buf); |
51028f34 UD |
198 | else |
199 | #endif | |
200 | fputs (buf, stderr); | |
201 | ||
202 | free (buf); | |
fa0bc87c RM |
203 | return 0; |
204 | } | |
205 | default: | |
206 | break; | |
207 | } | |
208 | } | |
209 | while (*args && *args != '#'); | |
210 | return args; | |
211 | } | |
212 | ||
213 | ||
214 | static const char * | |
5edb9387 UD |
215 | arg_trimdomain_list (const char *fname, int line_num, const char *args, |
216 | unsigned int flag) | |
fa0bc87c RM |
217 | { |
218 | const char * start; | |
219 | size_t len; | |
220 | ||
221 | do | |
222 | { | |
223 | start = args; | |
224 | args = skip_string (args); | |
225 | len = args - start; | |
226 | ||
227 | if (_res_hconf.num_trimdomains >= TRIMDOMAINS_MAX) | |
228 | { | |
51028f34 UD |
229 | char *buf; |
230 | ||
231 | __asprintf (&buf, _("\ | |
232 | %s: line %d: cannot specify more than %d trim domains"), | |
233 | fname, line_num, TRIMDOMAINS_MAX); | |
234 | ||
235 | #ifdef USE_IN_LIBIO | |
236 | if (_IO_fwide (stderr, 0) > 0) | |
6293b803 | 237 | __fwprintf (stderr, L"%s", buf); |
51028f34 UD |
238 | else |
239 | #endif | |
240 | fputs (buf, stderr); | |
241 | ||
242 | free (buf); | |
fa0bc87c RM |
243 | return 0; |
244 | } | |
245 | _res_hconf.trimdomain[_res_hconf.num_trimdomains++] = | |
5edb9387 | 246 | __strndup (start, len); |
fa0bc87c RM |
247 | args = skip_ws (args); |
248 | switch (*args) | |
249 | { | |
250 | case ',': case ';': case ':': | |
251 | args = skip_ws (++args); | |
252 | if (!*args || *args == '#') | |
253 | { | |
51028f34 UD |
254 | char *buf; |
255 | ||
256 | __asprintf (&buf, _("\ | |
257 | %s: line %d: list delimiter not followed by domain"), | |
258 | fname, line_num); | |
259 | ||
260 | #ifdef USE_IN_LIBIO | |
261 | if (_IO_fwide (stderr, 0) > 0) | |
6293b803 | 262 | __fwprintf (stderr, L"%s", buf); |
51028f34 UD |
263 | else |
264 | #endif | |
265 | fputs (buf, stderr); | |
266 | ||
267 | free (buf); | |
fa0bc87c RM |
268 | return 0; |
269 | } | |
270 | default: | |
271 | break; | |
272 | } | |
273 | } | |
274 | while (*args && *args != '#'); | |
275 | return args; | |
276 | } | |
277 | ||
278 | ||
279 | static const char * | |
5edb9387 | 280 | arg_spoof (const char *fname, int line_num, const char *args, unsigned flag) |
fa0bc87c | 281 | { |
5edb9387 | 282 | const char *start = args; |
fa0bc87c RM |
283 | size_t len; |
284 | ||
285 | args = skip_string (args); | |
286 | len = args - start; | |
287 | ||
5edb9387 | 288 | if (len == 3 && __strncasecmp (start, "off", len) == 0) |
fa0bc87c RM |
289 | _res_hconf.flags &= ~(HCONF_FLAG_SPOOF | HCONF_FLAG_SPOOFALERT); |
290 | else | |
291 | { | |
292 | _res_hconf.flags |= (HCONF_FLAG_SPOOF | HCONF_FLAG_SPOOFALERT); | |
5edb9387 UD |
293 | if ((len == 6 && __strncasecmp (start, "nowarn", len) == 0) |
294 | || !(len == 4 && __strncasecmp (start, "warn", len) == 0)) | |
fa0bc87c RM |
295 | _res_hconf.flags &= ~HCONF_FLAG_SPOOFALERT; |
296 | } | |
297 | return args; | |
298 | } | |
299 | ||
300 | ||
301 | static const char * | |
5edb9387 | 302 | arg_bool (const char *fname, int line_num, const char *args, unsigned flag) |
fa0bc87c | 303 | { |
5edb9387 | 304 | if (__strncasecmp (args, "on", 2) == 0) |
fa0bc87c RM |
305 | { |
306 | args += 2; | |
307 | _res_hconf.flags |= flag; | |
308 | } | |
5edb9387 | 309 | else if (__strncasecmp (args, "off", 3) == 0) |
fa0bc87c RM |
310 | { |
311 | args += 3; | |
312 | _res_hconf.flags &= ~flag; | |
313 | } | |
314 | else | |
315 | { | |
51028f34 UD |
316 | char *buf; |
317 | ||
318 | __asprintf (&buf, | |
319 | _("%s: line %d: expected `on' or `off', found `%s'\n"), | |
320 | fname, line_num, args); | |
321 | ||
322 | #ifdef USE_IN_LIBIO | |
323 | if (_IO_fwide (stderr, 0) > 0) | |
6293b803 | 324 | __fwprintf (stderr, L"%s", buf); |
51028f34 UD |
325 | else |
326 | #endif | |
327 | fputs (buf, stderr); | |
328 | ||
329 | free (buf); | |
fa0bc87c RM |
330 | return 0; |
331 | } | |
332 | return args; | |
333 | } | |
334 | ||
335 | ||
336 | static void | |
5edb9387 | 337 | parse_line (const char *fname, int line_num, const char *str) |
fa0bc87c | 338 | { |
5edb9387 UD |
339 | const char *start; |
340 | struct cmd *c = 0; | |
fa0bc87c | 341 | size_t len; |
57b36a0a | 342 | size_t i; |
fa0bc87c RM |
343 | |
344 | str = skip_ws (str); | |
345 | ||
6dc25b55 UD |
346 | /* skip line comment and empty lines: */ |
347 | if (*str == '\0' || *str == '#') return; | |
fa0bc87c RM |
348 | |
349 | start = str; | |
350 | str = skip_string (str); | |
351 | len = str - start; | |
352 | ||
353 | for (i = 0; i < sizeof (cmd) / sizeof (cmd[0]); ++i) | |
354 | { | |
4aebaa6b | 355 | if (__strncasecmp (start, cmd[i].name, len) == 0 |
fa0bc87c RM |
356 | && strlen (cmd[i].name) == len) |
357 | { | |
358 | c = &cmd[i]; | |
359 | break; | |
360 | } | |
361 | } | |
5edb9387 | 362 | if (c == NULL) |
fa0bc87c | 363 | { |
51028f34 UD |
364 | char *buf; |
365 | ||
366 | __asprintf (&buf, _("%s: line %d: bad command `%s'\n"), | |
367 | fname, line_num, start); | |
368 | ||
369 | #ifdef USE_IN_LIBIO | |
370 | if (_IO_fwide (stderr, 0) > 0) | |
6293b803 | 371 | __fwprintf (stderr, L"%s", buf); |
51028f34 UD |
372 | else |
373 | #endif | |
374 | fputs (buf, stderr); | |
375 | ||
376 | free (buf); | |
fa0bc87c RM |
377 | return; |
378 | } | |
379 | ||
380 | /* process args: */ | |
381 | str = skip_ws (str); | |
382 | str = (*c->parse_args) (fname, line_num, str, c->arg); | |
383 | if (!str) | |
384 | return; | |
385 | ||
386 | /* rest of line must contain white space or comment only: */ | |
387 | while (*str) | |
388 | { | |
389 | if (!isspace (*str)) { | |
390 | if (*str != '#') | |
51028f34 UD |
391 | { |
392 | char *buf; | |
393 | ||
394 | __asprintf (&buf, | |
395 | _("%s: line %d: ignoring trailing garbage `%s'\n"), | |
6293b803 | 396 | fname, line_num, str); |
51028f34 UD |
397 | |
398 | #ifdef USE_IN_LIBIO | |
399 | if (_IO_fwide (stderr, 0) > 0) | |
400 | __fwprintf (stderr, L"%s", buf); | |
401 | else | |
402 | #endif | |
403 | fputs (buf, stderr); | |
404 | ||
405 | free (buf); | |
406 | } | |
fa0bc87c RM |
407 | break; |
408 | } | |
409 | ++str; | |
410 | } | |
411 | } | |
412 | ||
413 | ||
9d957ce2 UD |
414 | static void |
415 | do_init (void) | |
fa0bc87c | 416 | { |
5edb9387 | 417 | const char *hconf_name; |
fa0bc87c | 418 | int line_num = 0; |
2c68584c | 419 | char buf[256], *envval; |
5edb9387 | 420 | FILE *fp; |
fa0bc87c | 421 | |
5edb9387 | 422 | memset (&_res_hconf, '\0', sizeof (_res_hconf)); |
fa0bc87c | 423 | |
74955460 | 424 | hconf_name = getenv (ENV_HOSTCONF); |
5edb9387 | 425 | if (hconf_name == NULL) |
fa0bc87c RM |
426 | hconf_name = _PATH_HOSTCONF; |
427 | ||
428 | fp = fopen (hconf_name, "r"); | |
429 | if (!fp) | |
430 | /* make up something reasonable: */ | |
431 | _res_hconf.service[_res_hconf.num_services++] = SERVICE_BIND; | |
432 | else | |
433 | { | |
2706ee38 UD |
434 | /* No threads using this stream. */ |
435 | __fsetlocking (fp, FSETLOCKING_BYCALLER); | |
436 | ||
5edb9387 | 437 | while (fgets_unlocked (buf, sizeof (buf), fp)) |
fa0bc87c RM |
438 | { |
439 | ++line_num; | |
c4563d2d | 440 | *__strchrnul (buf, '\n') = '\0'; |
fa0bc87c RM |
441 | parse_line (hconf_name, line_num, buf); |
442 | } | |
443 | fclose (fp); | |
444 | } | |
445 | ||
446 | envval = getenv (ENV_SERVORDER); | |
447 | if (envval) | |
448 | { | |
449 | _res_hconf.num_services = 0; | |
450 | arg_service_list (ENV_SERVORDER, 1, envval, 0); | |
451 | } | |
452 | ||
453 | envval = getenv (ENV_SPOOF); | |
454 | if (envval) | |
455 | arg_spoof (ENV_SPOOF, 1, envval, 0); | |
456 | ||
457 | envval = getenv (ENV_MULTI); | |
458 | if (envval) | |
459 | arg_bool (ENV_MULTI, 1, envval, HCONF_FLAG_MULTI); | |
460 | ||
461 | envval = getenv (ENV_REORDER); | |
462 | if (envval) | |
463 | arg_bool (ENV_REORDER, 1, envval, HCONF_FLAG_REORDER); | |
464 | ||
465 | envval = getenv (ENV_TRIM_ADD); | |
466 | if (envval) | |
467 | arg_trimdomain_list (ENV_TRIM_ADD, 1, envval, 0); | |
468 | ||
469 | envval = getenv (ENV_TRIM_OVERR); | |
470 | if (envval) | |
471 | { | |
472 | _res_hconf.num_trimdomains = 0; | |
473 | arg_trimdomain_list (ENV_TRIM_OVERR, 1, envval, 0); | |
474 | } | |
5edb9387 UD |
475 | |
476 | _res_hconf.initialized = 1; | |
fa0bc87c RM |
477 | } |
478 | ||
479 | ||
9d957ce2 UD |
480 | /* Initialize hconf datastructure by reading host.conf file and |
481 | environment variables. */ | |
482 | void | |
483 | _res_hconf_init (void) | |
484 | { | |
485 | __libc_once_define (static, once); | |
486 | ||
487 | __libc_once (once, do_init); | |
488 | } | |
489 | ||
490 | ||
f720d3d2 UD |
491 | /* List of known interfaces. */ |
492 | static struct netaddr | |
493 | { | |
494 | int addrtype; | |
495 | union | |
496 | { | |
497 | struct | |
498 | { | |
499 | u_int32_t addr; | |
500 | u_int32_t mask; | |
501 | } ipv4; | |
502 | } u; | |
503 | } *ifaddrs; | |
504 | ||
505 | /* We need to protect the dynamic buffer handling. */ | |
506 | __libc_lock_define_initialized (static, lock); | |
507 | ||
fa0bc87c RM |
508 | /* Reorder addresses returned in a hostent such that the first address |
509 | is an address on the local subnet, if there is such an address. | |
f720d3d2 UD |
510 | Otherwise, nothing is changed. |
511 | ||
512 | Note that this function currently only handles IPv4 addresses. */ | |
fa0bc87c RM |
513 | |
514 | void | |
5edb9387 | 515 | _res_hconf_reorder_addrs (struct hostent *hp) |
fa0bc87c | 516 | { |
5edb9387 | 517 | #if defined SIOCGIFCONF && defined SIOCGIFNETMASK |
f720d3d2 UD |
518 | int i, j; |
519 | /* Number of interfaces. */ | |
520 | static int num_ifs = -1; | |
fa0bc87c | 521 | |
f720d3d2 UD |
522 | /* Only reorder if we're supposed to. */ |
523 | if ((_res_hconf.flags & HCONF_FLAG_REORDER) == 0) | |
524 | return; | |
4aebaa6b | 525 | |
f720d3d2 | 526 | /* Can't deal with anything but IPv4 for now... */ |
fa0bc87c | 527 | if (hp->h_addrtype != AF_INET) |
f720d3d2 | 528 | return; |
fa0bc87c RM |
529 | |
530 | if (num_ifs <= 0) | |
531 | { | |
f720d3d2 UD |
532 | struct ifreq *ifr, *cur_ifr; |
533 | int sd, num, i; | |
534 | /* Save errno. */ | |
535 | int save = errno; | |
4aebaa6b | 536 | |
f720d3d2 | 537 | /* Initialize interface table. */ |
fa0bc87c RM |
538 | |
539 | num_ifs = 0; | |
540 | ||
7f1deee6 RM |
541 | /* The SIOCGIFNETMASK ioctl will only work on an AF_INET socket. */ |
542 | sd = __socket (AF_INET, SOCK_DGRAM, 0); | |
fa0bc87c RM |
543 | if (sd < 0) |
544 | return; | |
545 | ||
f720d3d2 UD |
546 | /* Get lock. */ |
547 | __libc_lock_lock (lock); | |
fa0bc87c | 548 | |
f720d3d2 | 549 | /* Get a list of interfaces. */ |
7f1deee6 | 550 | __ifreq (&ifr, &num, sd); |
f720d3d2 UD |
551 | if (!ifr) |
552 | goto cleanup; | |
fa0bc87c RM |
553 | |
554 | ifaddrs = malloc (num * sizeof (ifaddrs[0])); | |
555 | if (!ifaddrs) | |
f720d3d2 | 556 | goto cleanup1; |
4aebaa6b | 557 | |
f720d3d2 | 558 | /* Copy usable interfaces in ifaddrs structure. */ |
9db6ee8d | 559 | for (cur_ifr = ifr, i = 0; i < num; cur_ifr = __if_nextreq (cur_ifr), ++i) |
5edb9387 | 560 | { |
f720d3d2 | 561 | if (cur_ifr->ifr_addr.sa_family != AF_INET) |
5edb9387 | 562 | continue; |
4aebaa6b | 563 | |
5edb9387 | 564 | ifaddrs[num_ifs].addrtype = AF_INET; |
f720d3d2 UD |
565 | ifaddrs[num_ifs].u.ipv4.addr = |
566 | ((struct sockaddr_in *) &cur_ifr->ifr_addr)->sin_addr.s_addr; | |
fa0bc87c | 567 | |
f720d3d2 | 568 | if (__ioctl (sd, SIOCGIFNETMASK, cur_ifr) < 0) |
5edb9387 | 569 | continue; |
fa0bc87c | 570 | |
f720d3d2 UD |
571 | ifaddrs[num_ifs].u.ipv4.mask = |
572 | ((struct sockaddr_in *) &cur_ifr->ifr_netmask)->sin_addr.s_addr; | |
573 | ||
574 | /* Now we're committed to this entry. */ | |
575 | ++num_ifs; | |
5edb9387 | 576 | } |
f720d3d2 | 577 | /* Just keep enough memory to hold all the interfaces we want. */ |
fa0bc87c RM |
578 | ifaddrs = realloc (ifaddrs, num_ifs * sizeof (ifaddrs[0])); |
579 | ||
f720d3d2 | 580 | cleanup1: |
7f1deee6 | 581 | __if_freereq (ifr, num); |
f720d3d2 | 582 | |
fa0bc87c | 583 | cleanup: |
f720d3d2 UD |
584 | /* Release lock, preserve error value, and close socket. */ |
585 | save = errno; | |
586 | __libc_lock_unlock (lock); | |
4aebaa6b | 587 | __close (sd); |
fa0bc87c RM |
588 | } |
589 | ||
590 | if (num_ifs == 0) | |
591 | return; | |
592 | ||
f720d3d2 | 593 | /* Find an address for which we have a direct connection. */ |
fa0bc87c RM |
594 | for (i = 0; hp->h_addr_list[i]; ++i) |
595 | { | |
f720d3d2 | 596 | struct in_addr *haddr = (struct in_addr *) hp->h_addr_list[i]; |
fa0bc87c RM |
597 | |
598 | for (j = 0; j < num_ifs; ++j) | |
599 | { | |
f720d3d2 UD |
600 | u_int32_t if_addr = ifaddrs[j].u.ipv4.addr; |
601 | u_int32_t if_netmask = ifaddrs[j].u.ipv4.mask; | |
fa0bc87c | 602 | |
f720d3d2 | 603 | if (((haddr->s_addr ^ if_addr) & if_netmask) == 0) |
fa0bc87c | 604 | { |
5edb9387 | 605 | void *tmp; |
fa0bc87c | 606 | |
5edb9387 | 607 | tmp = hp->h_addr_list[i]; |
fa0bc87c RM |
608 | hp->h_addr_list[i] = hp->h_addr_list[0]; |
609 | hp->h_addr_list[0] = tmp; | |
610 | return; | |
611 | } | |
612 | } | |
613 | } | |
614 | #endif /* defined(SIOCGIFCONF) && ... */ | |
615 | } | |
616 | ||
617 | ||
618 | /* If HOSTNAME has a postfix matching any of the trimdomains, trim away | |
619 | that postfix. Notice that HOSTNAME is modified inplace. Also, the | |
620 | original code applied all trimdomains in order, meaning that the | |
621 | same domainname could be trimmed multiple times. I believe this | |
622 | was unintentional. */ | |
623 | void | |
5edb9387 | 624 | _res_hconf_trim_domain (char *hostname) |
fa0bc87c RM |
625 | { |
626 | size_t hostname_len, trim_len; | |
627 | int i; | |
628 | ||
5edb9387 | 629 | hostname_len = strlen (hostname); |
fa0bc87c RM |
630 | |
631 | for (i = 0; i < _res_hconf.num_trimdomains; ++i) | |
632 | { | |
5edb9387 | 633 | const char *trim = _res_hconf.trimdomain[i]; |
fa0bc87c | 634 | |
5edb9387 | 635 | trim_len = strlen (trim); |
fa0bc87c | 636 | if (hostname_len > trim_len |
5edb9387 | 637 | && __strcasecmp (&hostname[hostname_len - trim_len], trim) == 0) |
fa0bc87c RM |
638 | { |
639 | hostname[hostname_len - trim_len] = '\0'; | |
640 | break; | |
641 | } | |
642 | } | |
643 | } | |
644 | ||
645 | ||
646 | /* Trim all hostnames/aliases in HP according to the trimdomain list. | |
647 | Notice that HP is modified inplace! */ | |
648 | void | |
5edb9387 | 649 | _res_hconf_trim_domains (struct hostent *hp) |
fa0bc87c RM |
650 | { |
651 | int i; | |
652 | ||
653 | if (_res_hconf.num_trimdomains == 0) | |
654 | return; | |
655 | ||
656 | _res_hconf_trim_domain (hp->h_name); | |
657 | for (i = 0; hp->h_aliases[i]; ++i) | |
658 | _res_hconf_trim_domain (hp->h_aliases[i]); | |
659 | } | |
f720d3d2 UD |
660 | |
661 | ||
662 | /* Free all resources if necessary. */ | |
663 | static void __attribute__ ((unused)) | |
664 | free_mem (void) | |
665 | { | |
0e255b9c | 666 | free (ifaddrs); |
f720d3d2 UD |
667 | } |
668 | ||
669 | text_set_element (__libc_subfreeres, free_mem); |