1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32: #include <assert.h>
33: #include <errno.h>
34: #include <ctype.h>
35: #include <libintl.h>
36: #include <memory.h>
37: #include <stdio.h>
38: #include <stdio_ext.h>
39: #include <stdlib.h>
40: #include <string.h>
41: #include <net/if.h>
42: #include <sys/ioctl.h>
43: #include <unistd.h>
44: #include <netinet/in.h>
45: #include <bits/libc-lock.h>
46: #include "ifreq.h"
47: #include "res_hconf.h"
48: #ifdef USE_IN_LIBIO
49: # include <wchar.h>
50: #endif
51:
52: #define _PATH_HOSTCONF "/etc/host.conf"
53:
54:
55: #define ENV_HOSTCONF "RESOLV_HOST_CONF"
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:
62: enum parse_cbs
63: {
64: CB_none,
65: CB_arg_trimdomain_list,
66: CB_arg_spoof,
67: CB_arg_bool
68: };
69:
70: static const struct cmd
71: {
72: const char name[11];
73: uint8_t cb;
74: unsigned int arg;
75: } cmd[] =
76: {
77: {"order", CB_none, 0},
78: {"trim", CB_arg_trimdomain_list, 0},
79: {"spoof", CB_arg_spoof, 0},
80: {"multi", CB_arg_bool, HCONF_FLAG_MULTI},
81: {"nospoof", CB_arg_bool, HCONF_FLAG_SPOOF},
82: {"spoofalert", CB_arg_bool, HCONF_FLAG_SPOOFALERT},
83: {"reorder", CB_arg_bool, HCONF_FLAG_REORDER}
84: };
85:
86:
87: struct hconf _res_hconf;
88:
89:
90: static const char *
91: skip_ws (const char *str)
92: {
93: while (isspace (*str)) ++str;
94: return str;
95: }
96:
97:
98:
99: static const char *
100: skip_string (const char *str)
101: {
102: while (*str && !isspace (*str) && *str != '#' && *str != ',')
103: ++str;
104: return str;
105: }
106:
107:
108: static const char *
109: arg_trimdomain_list (const char *fname, int line_num, const char *args)
110: {
111: const char * start;
112: size_t len;
113:
114: do
115: {
116: start = args;
117: args = skip_string (args);
118: len = args - start;
119:
120: if (_res_hconf.num_trimdomains >= TRIMDOMAINS_MAX)
121: {
122: char *buf;
123:
124: if (__asprintf (&buf, _("\
125: %s: line %d: cannot specify more than %d trim domains"),
126: fname, line_num, TRIMDOMAINS_MAX) < 0)
127: return 0;
128:
129: __fxprintf (NULL, "%s", buf);
130:
131: free (buf);
132: return 0;
133: }
134: _res_hconf.trimdomain[_res_hconf.num_trimdomains++] =
135: __strndup (start, len);
136: args = skip_ws (args);
137: switch (*args)
138: {
139: case ',': case ';': case ':':
140: args = skip_ws (++args);
141: if (!*args || *args == '#')
142: {
143: char *buf;
144:
145: if (__asprintf (&buf, _("\
146: %s: line %d: list delimiter not followed by domain"),
147: fname, line_num) < 0)
148: return 0;
149:
150: __fxprintf (NULL, "%s", buf);
151:
152: free (buf);
153: return 0;
154: }
155: default:
156: break;
157: }
158: }
159: while (*args && *args != '#');
160: return args;
161: }
162:
163:
164: static const char *
165: arg_spoof (const char *fname, int line_num, const char *args)
166: {
167: const char *start = args;
168: size_t len;
169:
170: args = skip_string (args);
171: len = args - start;
172:
173: if (len == 3 && __strncasecmp (start, "off", len) == 0)
174: _res_hconf.flags &= ~(HCONF_FLAG_SPOOF | HCONF_FLAG_SPOOFALERT);
175: else
176: {
177: _res_hconf.flags |= (HCONF_FLAG_SPOOF | HCONF_FLAG_SPOOFALERT);
178: if ((len == 6 && __strncasecmp (start, "nowarn", len) == 0)
179: || !(len == 4 && __strncasecmp (start, "warn", len) == 0))
180: _res_hconf.flags &= ~HCONF_FLAG_SPOOFALERT;
181: }
182: return args;
183: }
184:
185:
186: static const char *
187: arg_bool (const char *fname, int line_num, const char *args, unsigned flag)
188: {
189: if (__strncasecmp (args, "on", 2) == 0)
190: {
191: args += 2;
192: _res_hconf.flags |= flag;
193: }
194: else if (__strncasecmp (args, "off", 3) == 0)
195: {
196: args += 3;
197: _res_hconf.flags &= ~flag;
198: }
199: else
200: {
201: char *buf;
202:
203: if (__asprintf (&buf,
204: _("%s: line %d: expected `on' or `off', found `%s'\n"),
205: fname, line_num, args) < 0)
206: return 0;
207:
208: __fxprintf (NULL, "%s", buf);
209:
210: free (buf);
211: return 0;
212: }
213: return args;
214: }
215:
216:
217: static void
218: parse_line (const char *fname, int line_num, const char *str)
219: {
220: const char *start;
221: const struct cmd *c = 0;
222: size_t len;
223: size_t i;
224:
225: str = skip_ws (str);
226:
227:
228: if (*str == '\0' || *str == '#') return;
229:
230: start = str;
231: str = skip_string (str);
232: len = str - start;
233:
234: for (i = 0; i < sizeof (cmd) / sizeof (cmd[0]); ++i)
235: {
236: if (__strncasecmp (start, cmd[i].name, len) == 0
237: && strlen (cmd[i].name) == len)
238: {
239: c = &cmd[i];
240: break;
241: }
242: }
243: if (c == NULL)
244: {
245: char *buf;
246:
247: if (__asprintf (&buf, _("%s: line %d: bad command `%s'\n"),
248: fname, line_num, start) < 0)
249: return;
250:
251: __fxprintf (NULL, "%s", buf);
252:
253: free (buf);
254: return;
255: }
256:
257:
258: str = skip_ws (str);
259:
260: if (c->cb == CB_arg_trimdomain_list)
261: str = arg_trimdomain_list (fname, line_num, str);
262: else if (c->cb == CB_arg_spoof)
263: str = arg_spoof (fname, line_num, str);
264: else if (c->cb == CB_arg_bool)
265: str = arg_bool (fname, line_num, str, c->arg);
266: else
267:
268: return;
269:
270: if (!str)
271: return;
272:
273:
274: while (*str)
275: {
276: if (!isspace (*str)) {
277: if (*str != '#')
278: {
279: char *buf;
280:
281: if (__asprintf (&buf,
282: _("%s: line %d: ignoring trailing garbage `%s'\n"),
283: fname, line_num, str) < 0)
284: break;
285:
286: __fxprintf (NULL, "%s", buf);
287:
288: free (buf);
289: }
290: break;
291: }
292: ++str;
293: }
294: }
295:
296:
297: static void
298: do_init (void)
299: {
300: const char *hconf_name;
301: int line_num = 0;
302: char buf[256], *envval;
303: FILE *fp;
304:
305: memset (&_res_hconf, '\0', sizeof (_res_hconf));
306:
307: hconf_name = getenv (ENV_HOSTCONF);
308: if (hconf_name == NULL)
309: hconf_name = _PATH_HOSTCONF;
310:
311: fp = fopen (hconf_name, "rc");
312: if (fp)
313: {
314:
315: __fsetlocking (fp, FSETLOCKING_BYCALLER);
316:
317: while (fgets_unlocked (buf, sizeof (buf), fp))
318: {
319: ++line_num;
320: *__strchrnul (buf, '\n') = '\0';
321: parse_line (hconf_name, line_num, buf);
322: }
323: fclose (fp);
324: }
325:
326: envval = getenv (ENV_SPOOF);
327: if (envval)
328: arg_spoof (ENV_SPOOF, 1, envval);
329:
330: envval = getenv (ENV_MULTI);
331: if (envval)
332: arg_bool (ENV_MULTI, 1, envval, HCONF_FLAG_MULTI);
333:
334: envval = getenv (ENV_REORDER);
335: if (envval)
336: arg_bool (ENV_REORDER, 1, envval, HCONF_FLAG_REORDER);
337:
338: envval = getenv (ENV_TRIM_ADD);
339: if (envval)
340: arg_trimdomain_list (ENV_TRIM_ADD, 1, envval);
341:
342: envval = getenv (ENV_TRIM_OVERR);
343: if (envval)
344: {
345: _res_hconf.num_trimdomains = 0;
346: arg_trimdomain_list (ENV_TRIM_OVERR, 1, envval);
347: }
348:
349: _res_hconf.initialized = 1;
350: }
351:
352:
353:
354:
355: void
356: _res_hconf_init (void)
357: {
358: __libc_once_define (static, once);
359:
360: __libc_once (once, do_init);
361: }
362:
363:
364: #ifndef NOT_IN_libc
365:
366: libc_freeres_ptr (
367: static struct netaddr
368: {
369: int addrtype;
370: union
371: {
372: struct
373: {
374: u_int32_t addr;
375: u_int32_t mask;
376: } ipv4;
377: } u;
378: } *ifaddrs);
379:
380:
381: __libc_lock_define_initialized (static, lock);
382:
383:
384:
385:
386:
387:
388:
389: void
390: _res_hconf_reorder_addrs (struct hostent *hp)
391: {
392: #if defined SIOCGIFCONF && defined SIOCGIFNETMASK
393: int i, j;
394:
395: static int num_ifs = -1;
396:
397:
398: if ((_res_hconf.flags & HCONF_FLAG_REORDER) == 0)
399: return;
400:
401:
402: if (hp->h_addrtype != AF_INET)
403: return;
404:
405: if (num_ifs <= 0)
406: {
407: struct ifreq *ifr, *cur_ifr;
408: int sd, num, i;
409:
410: int save = errno;
411:
412:
413:
414: num_ifs = 0;
415:
416:
417: sd = __socket (AF_INET, SOCK_DGRAM, 0);
418: if (sd < 0)
419: return;
420:
421:
422: __libc_lock_lock (lock);
423:
424:
425: __ifreq (&ifr, &num, sd);
426: if (!ifr)
427: goto cleanup;
428:
429: ifaddrs = malloc (num * sizeof (ifaddrs[0]));
430: if (!ifaddrs)
431: goto cleanup1;
432:
433:
434: for (cur_ifr = ifr, i = 0; i < num; cur_ifr = __if_nextreq (cur_ifr), ++i)
435: {
436: if (cur_ifr->ifr_addr.sa_family != AF_INET)
437: continue;
438:
439: ifaddrs[num_ifs].addrtype = AF_INET;
440: ifaddrs[num_ifs].u.ipv4.addr =
441: ((struct sockaddr_in *) &cur_ifr->ifr_addr)->sin_addr.s_addr;
442:
443: if (__ioctl (sd, SIOCGIFNETMASK, cur_ifr) < 0)
444: continue;
445:
446: ifaddrs[num_ifs].u.ipv4.mask =
447: ((struct sockaddr_in *) &cur_ifr->ifr_netmask)->sin_addr.s_addr;
448:
449:
450: ++num_ifs;
451: }
452:
453: ifaddrs = realloc (ifaddrs, num_ifs * sizeof (ifaddrs[0]));
454: assert (ifaddrs != NULL);
455:
456: cleanup1:
457: __if_freereq (ifr, num);
458:
459: cleanup:
460:
461: save = errno;
462: __libc_lock_unlock (lock);
463: __close (sd);
464: }
465:
466: if (num_ifs == 0)
467: return;
468:
469:
470: for (i = 0; hp->h_addr_list[i]; ++i)
471: {
472: struct in_addr *haddr = (struct in_addr *) hp->h_addr_list[i];
473:
474: for (j = 0; j < num_ifs; ++j)
475: {
476: u_int32_t if_addr = ifaddrs[j].u.ipv4.addr;
477: u_int32_t if_netmask = ifaddrs[j].u.ipv4.mask;
478:
479: if (((haddr->s_addr ^ if_addr) & if_netmask) == 0)
480: {
481: void *tmp;
482:
483: tmp = hp->h_addr_list[i];
484: hp->h_addr_list[i] = hp->h_addr_list[0];
485: hp->h_addr_list[0] = tmp;
486: return;
487: }
488: }
489: }
490: #endif
491: }
492:
493:
494:
495:
496:
497:
498:
499: void
500: _res_hconf_trim_domain (char *hostname)
501: {
502: size_t hostname_len, trim_len;
503: int i;
504:
505: hostname_len = strlen (hostname);
506:
507: for (i = 0; i < _res_hconf.num_trimdomains; ++i)
508: {
509: const char *trim = _res_hconf.trimdomain[i];
510:
511: trim_len = strlen (trim);
512: if (hostname_len > trim_len
513: && __strcasecmp (&hostname[hostname_len - trim_len], trim) == 0)
514: {
515: hostname[hostname_len - trim_len] = '\0';
516: break;
517: }
518: }
519: }
520:
521:
522:
523:
524: void
525: _res_hconf_trim_domains (struct hostent *hp)
526: {
527: int i;
528:
529: if (_res_hconf.num_trimdomains == 0)
530: return;
531:
532: _res_hconf_trim_domain (hp->h_name);
533: for (i = 0; hp->h_aliases[i]; ++i)
534: _res_hconf_trim_domain (hp->h_aliases[i]);
535: }
536: #endif