]>
Commit | Line | Data |
---|---|---|
f7a9f785 | 1 | /* Copyright (C) 1993-2016 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 | 15 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 PE |
16 | License along with the GNU C Library; if not, see |
17 | <http://www.gnu.org/licenses/>. */ | |
fa0bc87c RM |
18 | |
19 | /* This file provides a Linux /etc/host.conf compatible front end to | |
f720d3d2 UD |
20 | the various name resolvers (/etc/hosts, named, NIS server, etc.). |
21 | Though mostly compatibly, the following differences exist compared | |
22 | to the original implementation: | |
fa0bc87c RM |
23 | |
24 | - new command "spoof" takes an arguments like RESOLV_SPOOF_CHECK | |
25 | environment variable (i.e., `off', `nowarn', or `warn'). | |
26 | ||
27 | - line comments can appear anywhere (not just at the beginning of | |
28 | a line) | |
29 | */ | |
f720d3d2 | 30 | |
9be31a51 | 31 | #include <assert.h> |
f720d3d2 | 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> | |
ec999b8e | 44 | #include <libc-lock.h> |
f720d3d2 | 45 | #include "ifreq.h" |
fa0bc87c | 46 | #include "res_hconf.h" |
3ce1f295 | 47 | #include <wchar.h> |
f463c7b1 | 48 | #include <atomic.h> |
fa0bc87c | 49 | |
84e5e756 JM |
50 | #if IS_IN (libc) |
51 | # define fgets_unlocked __fgets_unlocked | |
52 | #endif | |
53 | ||
fa0bc87c RM |
54 | #define _PATH_HOSTCONF "/etc/host.conf" |
55 | ||
56 | /* Environment vars that all user to override default behavior: */ | |
57 | #define ENV_HOSTCONF "RESOLV_HOST_CONF" | |
fa0bc87c RM |
58 | #define ENV_SPOOF "RESOLV_SPOOF_CHECK" |
59 | #define ENV_TRIM_OVERR "RESOLV_OVERRIDE_TRIM_DOMAINS" | |
60 | #define ENV_TRIM_ADD "RESOLV_ADD_TRIM_DOMAINS" | |
61 | #define ENV_MULTI "RESOLV_MULTI" | |
62 | #define ENV_REORDER "RESOLV_REORDER" | |
63 | ||
bc054367 UD |
64 | enum parse_cbs |
65 | { | |
66 | CB_none, | |
67 | CB_arg_trimdomain_list, | |
68 | CB_arg_spoof, | |
69 | CB_arg_bool | |
70 | }; | |
5edb9387 | 71 | |
545f1b11 | 72 | static const struct cmd |
5edb9387 | 73 | { |
bc054367 UD |
74 | const char name[11]; |
75 | uint8_t cb; | |
5edb9387 UD |
76 | unsigned int arg; |
77 | } cmd[] = | |
78 | { | |
bc054367 UD |
79 | {"order", CB_none, 0}, |
80 | {"trim", CB_arg_trimdomain_list, 0}, | |
81 | {"spoof", CB_arg_spoof, 0}, | |
82 | {"multi", CB_arg_bool, HCONF_FLAG_MULTI}, | |
83 | {"nospoof", CB_arg_bool, HCONF_FLAG_SPOOF}, | |
84 | {"spoofalert", CB_arg_bool, HCONF_FLAG_SPOOFALERT}, | |
85 | {"reorder", CB_arg_bool, HCONF_FLAG_REORDER} | |
fa0bc87c RM |
86 | }; |
87 | ||
5edb9387 UD |
88 | /* Structure containing the state. */ |
89 | struct hconf _res_hconf; | |
fa0bc87c | 90 | |
fa0bc87c RM |
91 | /* Skip white space. */ |
92 | static const char * | |
5edb9387 | 93 | skip_ws (const char *str) |
fa0bc87c RM |
94 | { |
95 | while (isspace (*str)) ++str; | |
96 | return str; | |
97 | } | |
98 | ||
99 | ||
100 | /* Skip until whitespace, comma, end of line, or comment character. */ | |
101 | static const char * | |
5edb9387 | 102 | skip_string (const char *str) |
fa0bc87c | 103 | { |
5edb9387 UD |
104 | while (*str && !isspace (*str) && *str != '#' && *str != ',') |
105 | ++str; | |
fa0bc87c RM |
106 | return str; |
107 | } | |
108 | ||
109 | ||
a334319f | 110 | static const char * |
bc054367 | 111 | arg_trimdomain_list (const char *fname, int line_num, const char *args) |
fa0bc87c RM |
112 | { |
113 | const char * start; | |
114 | size_t len; | |
115 | ||
116 | do | |
117 | { | |
118 | start = args; | |
119 | args = skip_string (args); | |
120 | len = args - start; | |
121 | ||
122 | if (_res_hconf.num_trimdomains >= TRIMDOMAINS_MAX) | |
123 | { | |
51028f34 UD |
124 | char *buf; |
125 | ||
322861e8 | 126 | if (__asprintf (&buf, _("\ |
51028f34 | 127 | %s: line %d: cannot specify more than %d trim domains"), |
322861e8 UD |
128 | fname, line_num, TRIMDOMAINS_MAX) < 0) |
129 | return 0; | |
51028f34 | 130 | |
8a259a23 | 131 | __fxprintf (NULL, "%s", buf); |
51028f34 | 132 | |
df6f8969 | 133 | free (buf); |
fa0bc87c RM |
134 | return 0; |
135 | } | |
136 | _res_hconf.trimdomain[_res_hconf.num_trimdomains++] = | |
5edb9387 | 137 | __strndup (start, len); |
fa0bc87c RM |
138 | args = skip_ws (args); |
139 | switch (*args) | |
140 | { | |
141 | case ',': case ';': case ':': | |
142 | args = skip_ws (++args); | |
143 | if (!*args || *args == '#') | |
144 | { | |
51028f34 UD |
145 | char *buf; |
146 | ||
322861e8 | 147 | if (__asprintf (&buf, _("\ |
51028f34 | 148 | %s: line %d: list delimiter not followed by domain"), |
322861e8 UD |
149 | fname, line_num) < 0) |
150 | return 0; | |
51028f34 | 151 | |
8a259a23 | 152 | __fxprintf (NULL, "%s", buf); |
51028f34 UD |
153 | |
154 | free (buf); | |
fa0bc87c RM |
155 | return 0; |
156 | } | |
157 | default: | |
158 | break; | |
159 | } | |
160 | } | |
161 | while (*args && *args != '#'); | |
162 | return args; | |
163 | } | |
164 | ||
165 | ||
166 | static const char * | |
bc054367 | 167 | arg_spoof (const char *fname, int line_num, const char *args) |
fa0bc87c | 168 | { |
5edb9387 | 169 | const char *start = args; |
fa0bc87c RM |
170 | size_t len; |
171 | ||
172 | args = skip_string (args); | |
173 | len = args - start; | |
174 | ||
5edb9387 | 175 | if (len == 3 && __strncasecmp (start, "off", len) == 0) |
fa0bc87c RM |
176 | _res_hconf.flags &= ~(HCONF_FLAG_SPOOF | HCONF_FLAG_SPOOFALERT); |
177 | else | |
178 | { | |
179 | _res_hconf.flags |= (HCONF_FLAG_SPOOF | HCONF_FLAG_SPOOFALERT); | |
5edb9387 UD |
180 | if ((len == 6 && __strncasecmp (start, "nowarn", len) == 0) |
181 | || !(len == 4 && __strncasecmp (start, "warn", len) == 0)) | |
fa0bc87c RM |
182 | _res_hconf.flags &= ~HCONF_FLAG_SPOOFALERT; |
183 | } | |
184 | return args; | |
185 | } | |
186 | ||
187 | ||
188 | static const char * | |
5edb9387 | 189 | arg_bool (const char *fname, int line_num, const char *args, unsigned flag) |
fa0bc87c | 190 | { |
5edb9387 | 191 | if (__strncasecmp (args, "on", 2) == 0) |
fa0bc87c RM |
192 | { |
193 | args += 2; | |
194 | _res_hconf.flags |= flag; | |
195 | } | |
5edb9387 | 196 | else if (__strncasecmp (args, "off", 3) == 0) |
fa0bc87c RM |
197 | { |
198 | args += 3; | |
199 | _res_hconf.flags &= ~flag; | |
200 | } | |
201 | else | |
202 | { | |
51028f34 UD |
203 | char *buf; |
204 | ||
322861e8 UD |
205 | if (__asprintf (&buf, |
206 | _("%s: line %d: expected `on' or `off', found `%s'\n"), | |
207 | fname, line_num, args) < 0) | |
208 | return 0; | |
51028f34 | 209 | |
8a259a23 | 210 | __fxprintf (NULL, "%s", buf); |
51028f34 UD |
211 | |
212 | free (buf); | |
fa0bc87c RM |
213 | return 0; |
214 | } | |
215 | return args; | |
216 | } | |
217 | ||
218 | ||
219 | static void | |
5edb9387 | 220 | parse_line (const char *fname, int line_num, const char *str) |
fa0bc87c | 221 | { |
5edb9387 | 222 | const char *start; |
545f1b11 | 223 | const struct cmd *c = 0; |
fa0bc87c | 224 | size_t len; |
57b36a0a | 225 | size_t i; |
fa0bc87c RM |
226 | |
227 | str = skip_ws (str); | |
228 | ||
6dc25b55 UD |
229 | /* skip line comment and empty lines: */ |
230 | if (*str == '\0' || *str == '#') return; | |
fa0bc87c RM |
231 | |
232 | start = str; | |
233 | str = skip_string (str); | |
234 | len = str - start; | |
235 | ||
236 | for (i = 0; i < sizeof (cmd) / sizeof (cmd[0]); ++i) | |
237 | { | |
4aebaa6b | 238 | if (__strncasecmp (start, cmd[i].name, len) == 0 |
fa0bc87c RM |
239 | && strlen (cmd[i].name) == len) |
240 | { | |
241 | c = &cmd[i]; | |
242 | break; | |
243 | } | |
244 | } | |
5edb9387 | 245 | if (c == NULL) |
fa0bc87c | 246 | { |
51028f34 UD |
247 | char *buf; |
248 | ||
322861e8 UD |
249 | if (__asprintf (&buf, _("%s: line %d: bad command `%s'\n"), |
250 | fname, line_num, start) < 0) | |
251 | return; | |
51028f34 | 252 | |
8a259a23 | 253 | __fxprintf (NULL, "%s", buf); |
51028f34 UD |
254 | |
255 | free (buf); | |
fa0bc87c RM |
256 | return; |
257 | } | |
258 | ||
259 | /* process args: */ | |
260 | str = skip_ws (str); | |
bc054367 UD |
261 | |
262 | if (c->cb == CB_arg_trimdomain_list) | |
263 | str = arg_trimdomain_list (fname, line_num, str); | |
264 | else if (c->cb == CB_arg_spoof) | |
265 | str = arg_spoof (fname, line_num, str); | |
266 | else if (c->cb == CB_arg_bool) | |
267 | str = arg_bool (fname, line_num, str, c->arg); | |
268 | else | |
269 | /* Ignore the line. */ | |
270 | return; | |
271 | ||
fa0bc87c RM |
272 | if (!str) |
273 | return; | |
274 | ||
275 | /* rest of line must contain white space or comment only: */ | |
276 | while (*str) | |
277 | { | |
278 | if (!isspace (*str)) { | |
279 | if (*str != '#') | |
51028f34 UD |
280 | { |
281 | char *buf; | |
282 | ||
322861e8 UD |
283 | if (__asprintf (&buf, |
284 | _("%s: line %d: ignoring trailing garbage `%s'\n"), | |
285 | fname, line_num, str) < 0) | |
286 | break; | |
51028f34 | 287 | |
8a259a23 | 288 | __fxprintf (NULL, "%s", buf); |
51028f34 UD |
289 | |
290 | free (buf); | |
291 | } | |
fa0bc87c RM |
292 | break; |
293 | } | |
294 | ++str; | |
295 | } | |
296 | } | |
297 | ||
298 | ||
9d957ce2 UD |
299 | static void |
300 | do_init (void) | |
fa0bc87c | 301 | { |
5edb9387 | 302 | const char *hconf_name; |
fa0bc87c | 303 | int line_num = 0; |
2c68584c | 304 | char buf[256], *envval; |
5edb9387 | 305 | FILE *fp; |
fa0bc87c | 306 | |
5edb9387 | 307 | memset (&_res_hconf, '\0', sizeof (_res_hconf)); |
fa0bc87c | 308 | |
74955460 | 309 | hconf_name = getenv (ENV_HOSTCONF); |
5edb9387 | 310 | if (hconf_name == NULL) |
fa0bc87c RM |
311 | hconf_name = _PATH_HOSTCONF; |
312 | ||
312be3f9 | 313 | fp = fopen (hconf_name, "rce"); |
b9c65d09 | 314 | if (fp) |
fa0bc87c | 315 | { |
2706ee38 UD |
316 | /* No threads using this stream. */ |
317 | __fsetlocking (fp, FSETLOCKING_BYCALLER); | |
318 | ||
5edb9387 | 319 | while (fgets_unlocked (buf, sizeof (buf), fp)) |
fa0bc87c RM |
320 | { |
321 | ++line_num; | |
c4563d2d | 322 | *__strchrnul (buf, '\n') = '\0'; |
fa0bc87c RM |
323 | parse_line (hconf_name, line_num, buf); |
324 | } | |
325 | fclose (fp); | |
326 | } | |
327 | ||
fa0bc87c RM |
328 | envval = getenv (ENV_SPOOF); |
329 | if (envval) | |
bc054367 | 330 | arg_spoof (ENV_SPOOF, 1, envval); |
fa0bc87c RM |
331 | |
332 | envval = getenv (ENV_MULTI); | |
333 | if (envval) | |
334 | arg_bool (ENV_MULTI, 1, envval, HCONF_FLAG_MULTI); | |
335 | ||
336 | envval = getenv (ENV_REORDER); | |
337 | if (envval) | |
338 | arg_bool (ENV_REORDER, 1, envval, HCONF_FLAG_REORDER); | |
339 | ||
340 | envval = getenv (ENV_TRIM_ADD); | |
341 | if (envval) | |
bc054367 | 342 | arg_trimdomain_list (ENV_TRIM_ADD, 1, envval); |
fa0bc87c RM |
343 | |
344 | envval = getenv (ENV_TRIM_OVERR); | |
345 | if (envval) | |
346 | { | |
347 | _res_hconf.num_trimdomains = 0; | |
bc054367 | 348 | arg_trimdomain_list (ENV_TRIM_OVERR, 1, envval); |
fa0bc87c | 349 | } |
5edb9387 | 350 | |
6f9d4f59 TR |
351 | /* See comments on the declaration of _res_hconf. */ |
352 | atomic_store_release (&_res_hconf.initialized, 1); | |
fa0bc87c RM |
353 | } |
354 | ||
355 | ||
9d957ce2 UD |
356 | /* Initialize hconf datastructure by reading host.conf file and |
357 | environment variables. */ | |
358 | void | |
359 | _res_hconf_init (void) | |
360 | { | |
361 | __libc_once_define (static, once); | |
362 | ||
363 | __libc_once (once, do_init); | |
364 | } | |
365 | ||
366 | ||
4f41c682 | 367 | #if IS_IN (libc) |
f890a59b | 368 | # if defined SIOCGIFCONF && defined SIOCGIFNETMASK |
f720d3d2 | 369 | /* List of known interfaces. */ |
c877418f | 370 | libc_freeres_ptr ( |
f720d3d2 UD |
371 | static struct netaddr |
372 | { | |
373 | int addrtype; | |
374 | union | |
375 | { | |
376 | struct | |
377 | { | |
378 | u_int32_t addr; | |
379 | u_int32_t mask; | |
380 | } ipv4; | |
381 | } u; | |
c877418f | 382 | } *ifaddrs); |
f890a59b | 383 | # endif |
f720d3d2 | 384 | |
fa0bc87c RM |
385 | /* Reorder addresses returned in a hostent such that the first address |
386 | is an address on the local subnet, if there is such an address. | |
f720d3d2 UD |
387 | Otherwise, nothing is changed. |
388 | ||
389 | Note that this function currently only handles IPv4 addresses. */ | |
fa0bc87c RM |
390 | |
391 | void | |
5edb9387 | 392 | _res_hconf_reorder_addrs (struct hostent *hp) |
fa0bc87c | 393 | { |
5edb9387 | 394 | #if defined SIOCGIFCONF && defined SIOCGIFNETMASK |
f720d3d2 | 395 | int i, j; |
f463c7b1 FW |
396 | /* Number of interfaces. Also serves as a flag for the |
397 | double-checked locking idiom. */ | |
f720d3d2 | 398 | static int num_ifs = -1; |
f463c7b1 FW |
399 | /* Local copy of num_ifs, for non-atomic access. */ |
400 | int num_ifs_local; | |
401 | /* We need to protect the dynamic buffer handling. The lock is only | |
402 | acquired during initialization. Afterwards, a positive num_ifs | |
403 | value indicates completed initialization. */ | |
5c3a3dba | 404 | __libc_lock_define_initialized (static, lock); |
fa0bc87c | 405 | |
f720d3d2 UD |
406 | /* Only reorder if we're supposed to. */ |
407 | if ((_res_hconf.flags & HCONF_FLAG_REORDER) == 0) | |
408 | return; | |
4aebaa6b | 409 | |
f720d3d2 | 410 | /* Can't deal with anything but IPv4 for now... */ |
fa0bc87c | 411 | if (hp->h_addrtype != AF_INET) |
f720d3d2 | 412 | return; |
fa0bc87c | 413 | |
f463c7b1 FW |
414 | /* This load synchronizes with the release MO store in the |
415 | initialization block below. */ | |
416 | num_ifs_local = atomic_load_acquire (&num_ifs); | |
417 | if (num_ifs_local <= 0) | |
fa0bc87c | 418 | { |
f720d3d2 UD |
419 | struct ifreq *ifr, *cur_ifr; |
420 | int sd, num, i; | |
421 | /* Save errno. */ | |
422 | int save = errno; | |
4aebaa6b | 423 | |
f720d3d2 | 424 | /* Initialize interface table. */ |
fa0bc87c | 425 | |
7f1deee6 RM |
426 | /* The SIOCGIFNETMASK ioctl will only work on an AF_INET socket. */ |
427 | sd = __socket (AF_INET, SOCK_DGRAM, 0); | |
fa0bc87c RM |
428 | if (sd < 0) |
429 | return; | |
430 | ||
f720d3d2 UD |
431 | /* Get lock. */ |
432 | __libc_lock_lock (lock); | |
fa0bc87c | 433 | |
f463c7b1 FW |
434 | /* Recheck, somebody else might have done the work by now. No |
435 | ordering is required for the load because we have the lock, | |
436 | and num_ifs is only updated under the lock. Also see (3) in | |
437 | the analysis below. */ | |
438 | num_ifs_local = atomic_load_relaxed (&num_ifs); | |
439 | if (num_ifs_local <= 0) | |
5c3a3dba | 440 | { |
f463c7b1 FW |
441 | /* This is the only block which writes to num_ifs. It can |
442 | be executed several times (sequentially) if | |
443 | initialization does not yield any interfaces, and num_ifs | |
444 | remains zero. However, once we stored a positive value | |
445 | in num_ifs below, this block cannot be entered again due | |
446 | to the condition above. */ | |
5c3a3dba | 447 | int new_num_ifs = 0; |
fa0bc87c | 448 | |
5c3a3dba UD |
449 | /* Get a list of interfaces. */ |
450 | __ifreq (&ifr, &num, sd); | |
451 | if (!ifr) | |
452 | goto cleanup; | |
4aebaa6b | 453 | |
5c3a3dba UD |
454 | ifaddrs = malloc (num * sizeof (ifaddrs[0])); |
455 | if (!ifaddrs) | |
456 | goto cleanup1; | |
4aebaa6b | 457 | |
5c3a3dba UD |
458 | /* Copy usable interfaces in ifaddrs structure. */ |
459 | for (cur_ifr = ifr, i = 0; i < num; | |
460 | cur_ifr = __if_nextreq (cur_ifr), ++i) | |
461 | { | |
2483fa85 SE |
462 | union |
463 | { | |
464 | struct sockaddr sa; | |
465 | struct sockaddr_in sin; | |
466 | } ss; | |
467 | ||
5c3a3dba UD |
468 | if (cur_ifr->ifr_addr.sa_family != AF_INET) |
469 | continue; | |
fa0bc87c | 470 | |
5c3a3dba | 471 | ifaddrs[new_num_ifs].addrtype = AF_INET; |
2483fa85 SE |
472 | ss.sa = cur_ifr->ifr_addr; |
473 | ifaddrs[new_num_ifs].u.ipv4.addr = ss.sin.sin_addr.s_addr; | |
fa0bc87c | 474 | |
5c3a3dba UD |
475 | if (__ioctl (sd, SIOCGIFNETMASK, cur_ifr) < 0) |
476 | continue; | |
f720d3d2 | 477 | |
2483fa85 SE |
478 | ss.sa = cur_ifr->ifr_netmask; |
479 | ifaddrs[new_num_ifs].u.ipv4.mask = ss.sin.sin_addr.s_addr; | |
fa0bc87c | 480 | |
5c3a3dba UD |
481 | /* Now we're committed to this entry. */ |
482 | ++new_num_ifs; | |
483 | } | |
484 | /* Just keep enough memory to hold all the interfaces we want. */ | |
485 | ifaddrs = realloc (ifaddrs, new_num_ifs * sizeof (ifaddrs[0])); | |
486 | assert (ifaddrs != NULL); | |
487 | ||
488 | cleanup1: | |
489 | __if_freereq (ifr, num); | |
490 | ||
491 | cleanup: | |
492 | /* Release lock, preserve error value, and close socket. */ | |
5615eaf2 | 493 | errno = save; |
5c3a3dba | 494 | |
f463c7b1 FW |
495 | /* Advertise successful initialization if new_num_ifs is |
496 | positive (and no updates to ifaddrs are permitted after | |
497 | that). Otherwise, num_ifs remains unchanged, at zero. | |
498 | This store synchronizes with the initial acquire MO | |
499 | load. */ | |
500 | atomic_store_release (&num_ifs, new_num_ifs); | |
501 | /* Keep the local copy current, to save another load. */ | |
502 | num_ifs_local = new_num_ifs; | |
5c3a3dba | 503 | } |
f720d3d2 | 504 | |
b57525f1 DL |
505 | __libc_lock_unlock (lock); |
506 | ||
4aebaa6b | 507 | __close (sd); |
fa0bc87c RM |
508 | } |
509 | ||
f463c7b1 FW |
510 | /* num_ifs_local cannot be negative because the if statement above |
511 | covered this case. It can still be zero if we just performed | |
512 | initialization, but could not find any interfaces. */ | |
513 | if (num_ifs_local == 0) | |
fa0bc87c RM |
514 | return; |
515 | ||
f463c7b1 FW |
516 | /* The code below accesses ifaddrs, so we need to ensure that the |
517 | initialization happens-before this point. | |
518 | ||
519 | The actual initialization is sequenced-before the release store | |
520 | to num_ifs, and sequenced-before the end of the critical section. | |
521 | ||
522 | This means there are three possible executions: | |
523 | ||
524 | (1) The thread that initialized the data also uses it, so | |
525 | sequenced-before is sufficient to ensure happens-before. | |
526 | ||
527 | (2) The release MO store of num_ifs synchronizes-with the acquire | |
528 | MO load, and the acquire MO load is sequenced before the use | |
529 | of the initialized data below. | |
530 | ||
531 | (3) We enter the critical section, and the relaxed MO load of | |
532 | num_ifs yields a positive value. The write to ifaddrs is | |
533 | sequenced-before leaving the critical section. Leaving the | |
534 | critical section happens-before we entered the critical | |
535 | section ourselves, which means that the write to ifaddrs | |
536 | happens-before this point. | |
537 | ||
538 | Consequently, all potential writes to ifaddrs (and the data it | |
539 | points to) happens-before this point. */ | |
540 | ||
f720d3d2 | 541 | /* Find an address for which we have a direct connection. */ |
fa0bc87c RM |
542 | for (i = 0; hp->h_addr_list[i]; ++i) |
543 | { | |
f720d3d2 | 544 | struct in_addr *haddr = (struct in_addr *) hp->h_addr_list[i]; |
fa0bc87c | 545 | |
f463c7b1 | 546 | for (j = 0; j < num_ifs_local; ++j) |
fa0bc87c | 547 | { |
f720d3d2 UD |
548 | u_int32_t if_addr = ifaddrs[j].u.ipv4.addr; |
549 | u_int32_t if_netmask = ifaddrs[j].u.ipv4.mask; | |
fa0bc87c | 550 | |
f720d3d2 | 551 | if (((haddr->s_addr ^ if_addr) & if_netmask) == 0) |
fa0bc87c | 552 | { |
5edb9387 | 553 | void *tmp; |
fa0bc87c | 554 | |
5edb9387 | 555 | tmp = hp->h_addr_list[i]; |
fa0bc87c RM |
556 | hp->h_addr_list[i] = hp->h_addr_list[0]; |
557 | hp->h_addr_list[0] = tmp; | |
558 | return; | |
559 | } | |
560 | } | |
561 | } | |
562 | #endif /* defined(SIOCGIFCONF) && ... */ | |
563 | } | |
564 | ||
565 | ||
566 | /* If HOSTNAME has a postfix matching any of the trimdomains, trim away | |
567 | that postfix. Notice that HOSTNAME is modified inplace. Also, the | |
568 | original code applied all trimdomains in order, meaning that the | |
569 | same domainname could be trimmed multiple times. I believe this | |
570 | was unintentional. */ | |
571 | void | |
5edb9387 | 572 | _res_hconf_trim_domain (char *hostname) |
fa0bc87c RM |
573 | { |
574 | size_t hostname_len, trim_len; | |
575 | int i; | |
576 | ||
5edb9387 | 577 | hostname_len = strlen (hostname); |
fa0bc87c RM |
578 | |
579 | for (i = 0; i < _res_hconf.num_trimdomains; ++i) | |
580 | { | |
5edb9387 | 581 | const char *trim = _res_hconf.trimdomain[i]; |
fa0bc87c | 582 | |
5edb9387 | 583 | trim_len = strlen (trim); |
fa0bc87c | 584 | if (hostname_len > trim_len |
4c8b8cc3 | 585 | && __strcasecmp (&hostname[hostname_len - trim_len], trim) == 0) |
fa0bc87c RM |
586 | { |
587 | hostname[hostname_len - trim_len] = '\0'; | |
588 | break; | |
589 | } | |
590 | } | |
591 | } | |
592 | ||
593 | ||
594 | /* Trim all hostnames/aliases in HP according to the trimdomain list. | |
595 | Notice that HP is modified inplace! */ | |
596 | void | |
5edb9387 | 597 | _res_hconf_trim_domains (struct hostent *hp) |
fa0bc87c RM |
598 | { |
599 | int i; | |
600 | ||
601 | if (_res_hconf.num_trimdomains == 0) | |
602 | return; | |
603 | ||
604 | _res_hconf_trim_domain (hp->h_name); | |
605 | for (i = 0; hp->h_aliases[i]; ++i) | |
606 | _res_hconf_trim_domain (hp->h_aliases[i]); | |
607 | } | |
1ce7d80d | 608 | #endif |