OpenCores
URL https://opencores.org/ocsvn/scarts/scarts/trunk

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-newlib/] [newlib-1.17.0/] [newlib/] [libc/] [sys/] [linux/] [net/] [res_hconf.c] - Blame information for rev 9

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.