1 /* Resolver state initialization and resolv.conf parsing.
2 Copyright (C) 1995-2018 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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.
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.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
20 * Copyright (c) 1985, 1989, 1993
21 * The Regents of the University of California. All rights reserved.
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
26 * 1. Redistributions of source code must retain the above copyright
27 * notice, this list of conditions and the following disclaimer.
28 * 2. Redistributions in binary form must reproduce the above copyright
29 * notice, this list of conditions and the following disclaimer in the
30 * documentation and/or other materials provided with the distribution.
31 * 4. Neither the name of the University nor the names of its contributors
32 * may be used to endorse or promote products derived from this software
33 * without specific prior written permission.
35 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
36 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
39 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
41 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
49 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
51 * Permission to use, copy, modify, and distribute this software for any
52 * purpose with or without fee is hereby granted, provided that the above
53 * copyright notice and this permission notice appear in all copies, and that
54 * the name of Digital Equipment Corporation not be used in advertising or
55 * publicity pertaining to distribution of the document or software without
56 * specific, written prior permission.
58 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
59 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
60 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
61 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
62 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
63 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
64 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
69 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
71 * Permission to use, copy, modify, and distribute this software for any
72 * purpose with or without fee is hereby granted, provided that the above
73 * copyright notice and this permission notice appear in all copies.
75 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
76 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
77 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
78 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
79 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
80 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
81 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
87 #include <resolv/resolv-internal.h>
88 #include <res_hconf.h>
90 #include <stdio_ext.h>
95 #include <arpa/inet.h>
96 #include <arpa/nameser.h>
98 #include <netinet/in.h>
99 #include <sys/param.h>
100 #include <sys/socket.h>
101 #include <sys/time.h>
102 #include <sys/types.h>
103 #include <inet/net-internal.h>
105 #include <resolv_conf.h>
107 static uint32_t net_mask (struct in_addr
);
110 res_ninit (res_state statp
)
112 return __res_vinit (statp
, 0);
114 libc_hidden_def (__res_ninit
)
116 /* Return true if CH separates the netmask in the "sortlist"
119 is_sort_mask (char ch
)
121 return ch
== '/' || ch
== '&';
124 /* Array of name server addresses. */
125 #define DYNARRAY_STRUCT nameserver_list
126 #define DYNARRAY_ELEMENT const struct sockaddr *
127 #define DYNARRAY_ELEMENT_FREE(e) free ((struct sockaddr *) *(e))
128 #define DYNARRAY_INITIAL_SIZE 3
129 #define DYNARRAY_PREFIX nameserver_list_
130 #include <malloc/dynarray-skeleton.c>
132 /* Array of strings for the search array. The backing store is
133 managed separately. */
134 #define DYNARRAY_STRUCT search_list
135 #define DYNARRAY_ELEMENT const char *
136 #define DYNARRAY_INITIAL_SIZE 6
137 #define DYNARRAY_PREFIX search_list_
138 #include <malloc/dynarray-skeleton.c>
140 /* Array of name server addresses. */
141 #define DYNARRAY_STRUCT sort_list
142 #define DYNARRAY_ELEMENT struct resolv_sortlist_entry
143 #define DYNARRAY_INITIAL_SIZE 0
144 #define DYNARRAY_PREFIX sort_list_
145 #include <malloc/dynarray-skeleton.c>
147 /* resolv.conf parser state and results. */
148 struct resolv_conf_parser
150 char *buffer
; /* Temporary buffer for reading lines. */
152 struct nameserver_list nameserver_list
; /* Nameserver addresses. */
154 char *search_list_store
; /* Backing storage for search list entries. */
155 struct search_list search_list
; /* Points into search_list_store. */
157 struct sort_list sort_list
; /* Address preference sorting list. */
159 /* Configuration template. The non-array elements are filled in
160 directly. The array elements are updated prior to the call to
161 __resolv_conf_attach. */
162 struct resolv_conf
template;
165 /* Return true if *PREINIT contains actual preinitialization. */
167 has_preinit_values (const struct __res_state
*preinit
)
169 return (preinit
->retrans
!= 0 && preinit
->retrans
!= RES_TIMEOUT
)
170 || (preinit
->retry
!= 0 && preinit
->retry
!= RES_DFLRETRY
)
171 || (preinit
->options
!= 0
172 && (preinit
->options
& ~RES_INIT
) != RES_DEFAULT
);
176 resolv_conf_parser_init (struct resolv_conf_parser
*parser
,
177 const struct __res_state
*preinit
)
179 parser
->buffer
= NULL
;
180 parser
->search_list_store
= NULL
;
181 nameserver_list_init (&parser
->nameserver_list
);
182 search_list_init (&parser
->search_list
);
183 sort_list_init (&parser
->sort_list
);
187 parser
->template.retrans
= preinit
->retrans
;
188 parser
->template.retry
= preinit
->retry
;
189 parser
->template.options
= preinit
->options
| RES_INIT
;
193 parser
->template.retrans
= RES_TIMEOUT
;
194 parser
->template.retry
= RES_DFLRETRY
;
195 parser
->template.options
= RES_DEFAULT
| RES_INIT
;
197 parser
->template.ndots
= 1;
201 resolv_conf_parser_free (struct resolv_conf_parser
*parser
)
203 free (parser
->buffer
);
204 free (parser
->search_list_store
);
205 nameserver_list_free (&parser
->nameserver_list
);
206 search_list_free (&parser
->search_list
);
207 sort_list_free (&parser
->sort_list
);
210 /* Allocate a struct sockaddr_in object on the heap, with the
211 specified address and port. */
212 static struct sockaddr
*
213 allocate_address_v4 (struct in_addr a
, uint16_t port
)
215 struct sockaddr_in
*sa4
= malloc (sizeof (*sa4
));
218 sa4
->sin_family
= AF_INET
;
220 sa4
->sin_port
= htons (port
);
221 return (struct sockaddr
*) sa4
;
224 /* Try to obtain the domain name from the host name and store it in
225 *RESULT. Return false on memory allocation failure. If the domain
226 name cannot be determined for any other reason, write NULL to
227 *RESULT and return true. */
229 domain_from_hostname (char **result
)
232 /* gethostbyname may not terminate the buffer. */
233 buf
[sizeof (buf
) - 1] = '\0';
234 if (__gethostname (buf
, sizeof (buf
) - 1) == 0)
236 char *dot
= strchr (buf
, '.');
239 *result
= __strdup (dot
+ 1);
249 static void res_setoptions (struct resolv_conf_parser
*, const char *options
);
251 /* Internal helper function for __res_vinit, to aid with resource
252 deallocation and error handling. Return true on success, false on
255 res_vinit_1 (FILE *fp
, struct resolv_conf_parser
*parser
)
258 size_t buffer_size
= 0;
259 bool haveenv
= false;
261 /* Allow user to override the local domain definition. */
262 if ((cp
= getenv ("LOCALDOMAIN")) != NULL
)
264 /* The code below splits the string in place. */
268 free (parser
->search_list_store
);
269 parser
->search_list_store
= cp
;
272 /* The string will be truncated as needed below. */
273 search_list_add (&parser
->search_list
, cp
);
275 /* Set search list to be blank-separated strings from rest of
276 env value. Permits users of LOCALDOMAIN to still have a
277 search list, and anyone to set the one that they want to use
278 as an individual (even more important now that the rfc1535
279 stuff restricts searches). */
280 for (bool in_name
= true; *cp
!= '\0'; cp
++)
287 else if (*cp
== ' ' || *cp
== '\t')
294 search_list_add (&parser
->search_list
, cp
);
300 #define MATCH(line, name) \
301 (!strncmp ((line), name, sizeof (name) - 1) \
302 && ((line)[sizeof (name) - 1] == ' ' \
303 || (line)[sizeof (name) - 1] == '\t'))
307 /* No threads use this stream. */
308 __fsetlocking (fp
, FSETLOCKING_BYCALLER
);
309 /* Read the config file. */
313 ssize_t ret
= __getline (&parser
->buffer
, &buffer_size
, fp
);
316 if (_IO_ferror_unlocked (fp
))
324 if (*parser
->buffer
== ';' || *parser
->buffer
== '#')
326 /* Read default domain name. */
327 if (MATCH (parser
->buffer
, "domain"))
330 /* LOCALDOMAIN overrides the configuration file. */
332 cp
= parser
->buffer
+ sizeof ("domain") - 1;
333 while (*cp
== ' ' || *cp
== '\t')
335 if ((*cp
== '\0') || (*cp
== '\n'))
341 free (parser
->search_list_store
);
342 parser
->search_list_store
= cp
;
343 search_list_clear (&parser
->search_list
);
344 search_list_add (&parser
->search_list
, cp
);
345 /* Replace trailing whitespace. */
346 if ((cp
= strpbrk (cp
, " \t\n")) != NULL
)
350 /* Set search list. */
351 if (MATCH (parser
->buffer
, "search"))
354 /* LOCALDOMAIN overrides the configuration file. */
356 cp
= parser
->buffer
+ sizeof ("search") - 1;
357 while (*cp
== ' ' || *cp
== '\t')
359 if ((*cp
== '\0') || (*cp
== '\n'))
363 char *p
= strchr (cp
, '\n');
370 free (parser
->search_list_store
);
371 parser
->search_list_store
= cp
;
373 /* The string is truncated below. */
374 search_list_clear (&parser
->search_list
);
375 search_list_add (&parser
->search_list
, cp
);
377 /* Set search list to be blank-separated strings on rest
379 for (bool in_name
= true; *cp
!= '\0'; cp
++)
381 if (*cp
== ' ' || *cp
== '\t')
388 search_list_add (&parser
->search_list
, cp
);
394 /* Read nameservers to query. */
395 if (MATCH (parser
->buffer
, "nameserver"))
399 cp
= parser
->buffer
+ sizeof ("nameserver") - 1;
400 while (*cp
== ' ' || *cp
== '\t')
403 if ((*cp
!= '\0') && (*cp
!= '\n') && __inet_aton (cp
, &a
))
405 sa
= allocate_address_v4 (a
, NAMESERVER_PORT
);
414 if ((el
= strpbrk (cp
, " \t\n")) != NULL
)
416 if ((el
= strchr (cp
, SCOPE_DELIMITER
)) != NULL
)
418 if ((*cp
!= '\0') && (__inet_pton (AF_INET6
, cp
, &a6
) > 0))
420 struct sockaddr_in6
*sa6
;
422 sa6
= malloc (sizeof (*sa6
));
426 sa6
->sin6_family
= AF_INET6
;
427 sa6
->sin6_port
= htons (NAMESERVER_PORT
);
428 sa6
->sin6_flowinfo
= 0;
431 sa6
->sin6_scope_id
= 0;
432 if (__glibc_likely (el
!= NULL
))
433 /* Ignore errors, for backwards
436 (&a6
, el
+ 1, &sa6
->sin6_scope_id
);
437 sa
= (struct sockaddr
*) sa6
;
440 /* IPv6 address parse failure. */
445 const struct sockaddr
**p
= nameserver_list_emplace
446 (&parser
->nameserver_list
);
457 if (MATCH (parser
->buffer
, "sortlist"))
461 cp
= parser
->buffer
+ sizeof ("sortlist") - 1;
464 while (*cp
== ' ' || *cp
== '\t')
466 if (*cp
== '\0' || *cp
== '\n' || *cp
== ';')
469 while (*cp
&& !is_sort_mask (*cp
) && *cp
!= ';'
470 && isascii (*cp
) && !isspace (*cp
))
472 char separator
= *cp
;
474 struct resolv_sortlist_entry e
;
475 if (__inet_aton (net
, &a
))
478 if (is_sort_mask (separator
))
482 while (*cp
&& *cp
!= ';'
483 && isascii (*cp
) && !isspace (*cp
))
487 if (__inet_aton (net
, &a
))
490 e
.mask
= net_mask (e
.addr
);
493 e
.mask
= net_mask (e
.addr
);
494 sort_list_add (&parser
->sort_list
, e
);
500 if (MATCH (parser
->buffer
, "options"))
502 res_setoptions (parser
, parser
->buffer
+ sizeof ("options") - 1);
508 if (__glibc_unlikely (nameserver_list_size (&parser
->nameserver_list
) == 0))
510 const struct sockaddr
**p
511 = nameserver_list_emplace (&parser
->nameserver_list
);
514 *p
= allocate_address_v4 (__inet_makeaddr (IN_LOOPBACKNET
, 1),
520 if (search_list_size (&parser
->search_list
) == 0)
523 if (!domain_from_hostname (&domain
))
527 free (parser
->search_list_store
);
528 parser
->search_list_store
= domain
;
529 search_list_add (&parser
->search_list
, domain
);
533 if ((cp
= getenv ("RES_OPTIONS")) != NULL
)
534 res_setoptions (parser
, cp
);
536 if (nameserver_list_has_failed (&parser
->nameserver_list
)
537 || search_list_has_failed (&parser
->search_list
)
538 || sort_list_has_failed (&parser
->sort_list
))
540 __set_errno (ENOMEM
);
548 __resolv_conf_load (struct __res_state
*preinit
)
550 /* Ensure that /etc/hosts.conf has been loaded (once). */
553 FILE *fp
= fopen (_PATH_RESCONF
, "rce");
563 /* Ignore these errors. They are persistent errors caused
564 by file system contents. */
567 /* Other errors refer to resource allocation problems and
568 need to be handled by the application. */
572 struct resolv_conf_parser parser
;
573 resolv_conf_parser_init (&parser
, preinit
);
575 struct resolv_conf
*conf
= NULL
;
576 if (res_vinit_1 (fp
, &parser
))
578 parser
.template.nameserver_list
579 = nameserver_list_begin (&parser
.nameserver_list
);
580 parser
.template.nameserver_list_size
581 = nameserver_list_size (&parser
.nameserver_list
);
582 parser
.template.search_list
= search_list_begin (&parser
.search_list
);
583 parser
.template.search_list_size
584 = search_list_size (&parser
.search_list
);
585 parser
.template.sort_list
= sort_list_begin (&parser
.sort_list
);
586 parser
.template.sort_list_size
= sort_list_size (&parser
.sort_list
);
587 conf
= __resolv_conf_allocate (&parser
.template);
589 resolv_conf_parser_free (&parser
);
594 /* Set up default settings. If the /etc/resolv.conf configuration
595 file exist, the values there will have precedence. Otherwise, the
596 server address is set to INADDR_LOOPBACK and the default domain
597 name comes from gethostname. The RES_OPTIONS and LOCALDOMAIN
598 environment variables can be used to override some settings.
599 Return 0 if completes successfully, -1 on error. */
601 __res_vinit (res_state statp
, int preinit
)
603 struct resolv_conf
*conf
;
604 if (preinit
&& has_preinit_values (statp
))
605 /* For the preinit case, we cannot use the cached configuration
606 because some settings could be different. */
607 conf
= __resolv_conf_load (statp
);
609 conf
= __resolv_conf_get_current ();
613 bool ok
= __resolv_conf_attach (statp
, conf
);
614 __resolv_conf_put (conf
);
618 statp
->id
= res_randomid ();
626 res_setoptions (struct resolv_conf_parser
*parser
, const char *options
)
628 const char *cp
= options
;
632 /* Skip leading and inner runs of spaces. */
633 while (*cp
== ' ' || *cp
== '\t')
635 /* Search for and process individual options. */
636 if (!strncmp (cp
, "ndots:", sizeof ("ndots:") - 1))
638 int i
= atoi (cp
+ sizeof ("ndots:") - 1);
639 if (i
<= RES_MAXNDOTS
)
640 parser
->template.ndots
= i
;
642 parser
->template.ndots
= RES_MAXNDOTS
;
644 else if (!strncmp (cp
, "timeout:", sizeof ("timeout:") - 1))
646 int i
= atoi (cp
+ sizeof ("timeout:") - 1);
647 if (i
<= RES_MAXRETRANS
)
648 parser
->template.retrans
= i
;
650 parser
->template.retrans
= RES_MAXRETRANS
;
652 else if (!strncmp (cp
, "attempts:", sizeof ("attempts:") - 1))
654 int i
= atoi (cp
+ sizeof ("attempts:") - 1);
655 if (i
<= RES_MAXRETRY
)
656 parser
->template.retry
= i
;
658 parser
->template.retry
= RES_MAXRETRY
;
667 unsigned long int flag
;
669 #define STRnLEN(str) str, sizeof (str) - 1
670 { STRnLEN ("inet6"), 0, DEPRECATED_RES_USE_INET6
},
671 { STRnLEN ("rotate"), 0, RES_ROTATE
},
672 { STRnLEN ("edns0"), 0, RES_USE_EDNS0
},
673 { STRnLEN ("single-request-reopen"), 0, RES_SNGLKUPREOP
},
674 { STRnLEN ("single-request"), 0, RES_SNGLKUP
},
675 { STRnLEN ("no_tld_query"), 0, RES_NOTLDQUERY
},
676 { STRnLEN ("no-tld-query"), 0, RES_NOTLDQUERY
},
677 { STRnLEN ("no-reload"), 0, RES_NORELOAD
},
678 { STRnLEN ("use-vc"), 0, RES_USEVC
}
680 #define noptions (sizeof (options) / sizeof (options[0]))
681 for (int i
= 0; i
< noptions
; ++i
)
682 if (strncmp (cp
, options
[i
].str
, options
[i
].len
) == 0)
684 if (options
[i
].clear
)
685 parser
->template.options
&= options
[i
].flag
;
687 parser
->template.options
|= options
[i
].flag
;
691 /* Skip to next run of spaces. */
692 while (*cp
&& *cp
!= ' ' && *cp
!= '\t')
698 net_mask (struct in_addr in
)
700 uint32_t i
= ntohl (in
.s_addr
);
703 return htonl (IN_CLASSA_NET
);
704 else if (IN_CLASSB (i
))
705 return htonl (IN_CLASSB_NET
);
706 return htonl (IN_CLASSC_NET
);