From a1c4eb8794e789b5055d7ceb13b2b3231abf5e26 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Fri, 30 Jun 2017 20:19:10 +0200 Subject: resolv: Mirror the entire resolver configuration in struct resolv_conf This commit adds the remaining unchanging members (which are loaded from /etc/resolv.conf) to struct resolv_conf. The extended name server list is currently not used by the stub resolver. The switch depends on a cleanup: The _u._ext.nssocks array stores just a single socket, and needs to be replaced with a single socket value. (The compatibility gethostname implementation does not use the extended addres sort list, either. Updating the compat code is not worthwhile.) --- resolv/res_init.c | 219 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 131 insertions(+), 88 deletions(-) (limited to 'resolv/res_init.c') diff --git a/resolv/res_init.c b/resolv/res_init.c index 5941d37f32..80a21fb90d 100644 --- a/resolv/res_init.c +++ b/resolv/res_init.c @@ -104,7 +104,6 @@ #include #include -static void res_setoptions (res_state, const char *); static uint32_t net_mask (struct in_addr); unsigned long long int __res_initstamp; @@ -124,28 +123,70 @@ is_sort_mask (char ch) return ch == '/' || ch == '&'; } +/* Array of name server addresses. */ +#define DYNARRAY_STRUCT nameserver_list +#define DYNARRAY_ELEMENT const struct sockaddr * +#define DYNARRAY_ELEMENT_FREE(e) free ((struct sockaddr *) *(e)) +#define DYNARRAY_INITIAL_SIZE 3 +#define DYNARRAY_PREFIX nameserver_list_ +#include + /* Array of strings for the search array. The backing store is managed separately. */ #define DYNARRAY_STRUCT search_list #define DYNARRAY_ELEMENT const char * -#define DYNARRAY_INITIAL_SIZE 4 +#define DYNARRAY_INITIAL_SIZE 6 #define DYNARRAY_PREFIX search_list_ #include +/* Array of name server addresses. */ +#define DYNARRAY_STRUCT sort_list +#define DYNARRAY_ELEMENT struct resolv_sortlist_entry +#define DYNARRAY_INITIAL_SIZE 0 +#define DYNARRAY_PREFIX sort_list_ +#include + /* resolv.conf parser state and results. */ struct resolv_conf_parser { char *buffer; /* Temporary buffer for reading lines. */ + + struct nameserver_list nameserver_list; /* Nameserver addresses. */ + char *search_list_store; /* Backing storage for search list entries. */ struct search_list search_list; /* Points into search_list_store. */ + + struct sort_list sort_list; /* Address preference sorting list. */ + + /* Configuration template. The non-array elements are filled in + directly. The array elements are updated prior to the call to + __resolv_conf_attach. */ + struct resolv_conf template; }; static void -resolv_conf_parser_init (struct resolv_conf_parser *parser) +resolv_conf_parser_init (struct resolv_conf_parser *parser, + const struct __res_state *preinit) { parser->buffer = NULL; parser->search_list_store = NULL; + nameserver_list_init (&parser->nameserver_list); search_list_init (&parser->search_list); + sort_list_init (&parser->sort_list); + + if (preinit != NULL) + { + parser->template.retrans = preinit->retrans; + parser->template.retry = preinit->retry; + parser->template.options = preinit->options | RES_INIT; + } + else + { + parser->template.retrans = RES_TIMEOUT; + parser->template.retry = RES_DFLRETRY; + parser->template.options = RES_DEFAULT | RES_INIT; + } + parser->template.ndots = 1; } static void @@ -153,7 +194,23 @@ resolv_conf_parser_free (struct resolv_conf_parser *parser) { free (parser->buffer); free (parser->search_list_store); + nameserver_list_free (&parser->nameserver_list); search_list_free (&parser->search_list); + sort_list_free (&parser->sort_list); +} + +/* Allocate a struct sockaddr_in object on the heap, with the + specified address and port. */ +static struct sockaddr * +allocate_address_v4 (struct in_addr a, uint16_t port) +{ + struct sockaddr_in *sa4 = malloc (sizeof (*sa4)); + if (sa4 == NULL) + return NULL; + sa4->sin_family = AF_INET; + sa4->sin_addr = a; + sa4->sin_port = htons (port); + return (struct sockaddr *) sa4; } /* Try to obtain the domain name from the host name and store it in @@ -181,40 +238,17 @@ domain_from_hostname (char **result) return true; } +static void res_setoptions (struct resolv_conf_parser *, const char *options); + /* Internal helper function for __res_vinit, to aid with resource deallocation and error handling. Return true on success, false on failure. */ static bool -res_vinit_1 (res_state statp, bool preinit, FILE *fp, - struct resolv_conf_parser *parser) +res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser) { char *cp; size_t buffer_size = 0; - int nserv = 0; /* Number of nameservers read from file. */ - bool have_serv6 = false; bool haveenv = false; - int nsort = 0; - char *net; - - if (!preinit) - { - statp->retrans = RES_TIMEOUT; - statp->retry = RES_DFLRETRY; - statp->options = RES_DEFAULT; - statp->id = res_randomid (); - } - - statp->nscount = 0; - statp->defdname[0] = '\0'; - statp->ndots = 1; - statp->pfcode = 0; - statp->_vcsock = -1; - statp->_flags = 0; - statp->__glibc_unused_qhook = NULL; - statp->__glibc_unused_rhook = NULL; - statp->_u._ext.nscount = 0; - for (int n = 0; n < MAXNS; n++) - statp->_u._ext.nsaddrs[n] = NULL; /* Allow user to override the local domain definition. */ if ((cp = getenv ("LOCALDOMAIN")) != NULL) @@ -350,19 +384,19 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp, continue; } /* Read nameservers to query. */ - if (MATCH (parser->buffer, "nameserver") && nserv < MAXNS) + if (MATCH (parser->buffer, "nameserver")) { struct in_addr a; cp = parser->buffer + sizeof ("nameserver") - 1; while (*cp == ' ' || *cp == '\t') cp++; + struct sockaddr *sa; if ((*cp != '\0') && (*cp != '\n') && __inet_aton (cp, &a)) { - statp->nsaddr_list[nserv].sin_addr = a; - statp->nsaddr_list[nserv].sin_family = AF_INET; - statp->nsaddr_list[nserv].sin_port = htons (NAMESERVER_PORT); - nserv++; + sa = allocate_address_v4 (a, NAMESERVER_PORT); + if (sa == NULL) + return false; } else { @@ -392,13 +426,18 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp, compatibility. */ __inet6_scopeid_pton (&a6, el + 1, &sa6->sin6_scope_id); - - statp->nsaddr_list[nserv].sin_family = 0; - statp->_u._ext.nsaddrs[nserv] = sa6; - statp->_u._ext.nssocks[nserv] = -1; - have_serv6 = true; - nserv++; + sa = (struct sockaddr *) sa6; } + else + /* IPv6 address parse failure. */ + sa = NULL; + } + if (sa != NULL) + { + const struct sockaddr **p = nameserver_list_emplace + (&parser->nameserver_list); + if (p != NULL) + *p = sa; } continue; } @@ -407,21 +446,22 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp, struct in_addr a; cp = parser->buffer + sizeof ("sortlist") - 1; - while (nsort < MAXRESOLVSORT) + while (true) { while (*cp == ' ' || *cp == '\t') cp++; if (*cp == '\0' || *cp == '\n' || *cp == ';') break; - net = cp; + char *net = cp; while (*cp && !is_sort_mask (*cp) && *cp != ';' && isascii (*cp) && !isspace (*cp)) cp++; char separator = *cp; *cp = 0; + struct resolv_sortlist_entry e; if (__inet_aton (net, &a)) { - statp->sort_list[nsort].addr = a; + e.addr = a; if (is_sort_mask (separator)) { *cp++ = separator; @@ -432,15 +472,13 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp, separator = *cp; *cp = 0; if (__inet_aton (net, &a)) - statp->sort_list[nsort].mask = a.s_addr; + e.mask = a.s_addr; else - statp->sort_list[nsort].mask - = net_mask (statp->sort_list[nsort].addr); + e.mask = net_mask (e.addr); } else - statp->sort_list[nsort].mask - = net_mask (statp->sort_list[nsort].addr); - nsort++; + e.mask = net_mask (e.addr); + sort_list_add (&parser->sort_list, e); } *cp = separator; } @@ -448,23 +486,22 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp, } if (MATCH (parser->buffer, "options")) { - res_setoptions (statp, parser->buffer + sizeof ("options") - 1); + res_setoptions (parser, parser->buffer + sizeof ("options") - 1); continue; } } - statp->nscount = nserv; - if (have_serv6) - /* We try IPv6 servers again. */ - statp->ipv6_unavail = false; - statp->nsort = nsort; fclose (fp); } - if (__glibc_unlikely (statp->nscount == 0)) + if (__glibc_unlikely (nameserver_list_size (&parser->nameserver_list) == 0)) { - statp->nsaddr.sin_addr = __inet_makeaddr (IN_LOOPBACKNET, 1); - statp->nsaddr.sin_family = AF_INET; - statp->nsaddr.sin_port = htons (NAMESERVER_PORT); - statp->nscount = 1; + const struct sockaddr **p + = nameserver_list_emplace (&parser->nameserver_list); + if (p == NULL) + return false; + *p = allocate_address_v4 (__inet_makeaddr (IN_LOOPBACKNET, 1), + NAMESERVER_PORT); + if (*p == NULL) + return false; } if (search_list_size (&parser->search_list) == 0) @@ -481,15 +518,16 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp, } if ((cp = getenv ("RES_OPTIONS")) != NULL) - res_setoptions (statp, cp); + res_setoptions (parser, cp); - if (search_list_has_failed (&parser->search_list)) + if (nameserver_list_has_failed (&parser->nameserver_list) + || search_list_has_failed (&parser->search_list) + || sort_list_has_failed (&parser->sort_list)) { __set_errno (ENOMEM); return false; } - statp->options |= RES_INIT; return true; } @@ -525,17 +563,27 @@ __res_vinit (res_state statp, int preinit) } struct resolv_conf_parser parser; - resolv_conf_parser_init (&parser); - bool ok = res_vinit_1 (statp, preinit, fp, &parser); + if (preinit) + { + resolv_conf_parser_init (&parser, statp); + statp->id = res_randomid (); + } + else + resolv_conf_parser_init (&parser, NULL); + bool ok = res_vinit_1 (fp, &parser); if (ok) { - struct resolv_conf init = - { - .search_list = search_list_begin (&parser.search_list), - .search_list_size = search_list_size (&parser.search_list), - }; - struct resolv_conf *conf = __resolv_conf_allocate (&init); + parser.template.nameserver_list + = nameserver_list_begin (&parser.nameserver_list); + parser.template.nameserver_list_size + = nameserver_list_size (&parser.nameserver_list); + parser.template.search_list = search_list_begin (&parser.search_list); + parser.template.search_list_size + = search_list_size (&parser.search_list); + parser.template.sort_list = sort_list_begin (&parser.sort_list); + parser.template.sort_list_size = sort_list_size (&parser.sort_list); + struct resolv_conf *conf = __resolv_conf_allocate (&parser.template); if (conf == NULL) ok = false; else @@ -547,18 +595,13 @@ __res_vinit (res_state statp, int preinit) resolv_conf_parser_free (&parser); if (!ok) - { - /* Deallocate the name server addresses which have been - allocated. */ - for (int n = 0; n < MAXNS; n++) - free (statp->_u._ext.nsaddrs[n]); - return -1; - } - return 0; + return -1; + else + return 0; } static void -res_setoptions (res_state statp, const char *options) +res_setoptions (struct resolv_conf_parser *parser, const char *options) { const char *cp = options; @@ -572,25 +615,25 @@ res_setoptions (res_state statp, const char *options) { int i = atoi (cp + sizeof ("ndots:") - 1); if (i <= RES_MAXNDOTS) - statp->ndots = i; + parser->template.ndots = i; else - statp->ndots = RES_MAXNDOTS; + parser->template.ndots = RES_MAXNDOTS; } else if (!strncmp (cp, "timeout:", sizeof ("timeout:") - 1)) { int i = atoi (cp + sizeof ("timeout:") - 1); if (i <= RES_MAXRETRANS) - statp->retrans = i; + parser->template.retrans = i; else - statp->retrans = RES_MAXRETRANS; + parser->template.retrans = RES_MAXRETRANS; } else if (!strncmp (cp, "attempts:", sizeof ("attempts:") - 1)) { int i = atoi (cp + sizeof ("attempts:") - 1); if (i <= RES_MAXRETRY) - statp->retry = i; + parser->template.retry = i; else - statp->retry = RES_MAXRETRY; + parser->template.retry = RES_MAXRETRY; } else { @@ -616,9 +659,9 @@ res_setoptions (res_state statp, const char *options) if (strncmp (cp, options[i].str, options[i].len) == 0) { if (options[i].clear) - statp->options &= options[i].flag; + parser->template.options &= options[i].flag; else - statp->options |= options[i].flag; + parser->template.options |= options[i].flag; break; } } -- cgit v1.2.3