From e7ddd3d7b42ffe4783d723af448b307caa9a5e0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= Date: Sat, 5 Oct 2019 00:20:54 +0200 Subject: [PATCH] Remove artificial search limit from libirs Search directive from resolv.conf had a maximum of 8 domains. Any more were ignored. Do not ignore them anymore; iterate over any number of domains. Test resolv.conf support by checking the first and last domain in the search list. Ignore the domains between; just ensure that the last domain in the configuration is the last domain parsed. --- lib/dns/resconf.c | 180 ++++++++++++++------------------- tests/irs/testdata/search.conf | 2 +- 2 files changed, 77 insertions(+), 105 deletions(-) diff --git a/lib/dns/resconf.c b/lib/dns/resconf.c index d1d660e60a..c21df4a511 100644 --- a/lib/dns/resconf.c +++ b/lib/dns/resconf.c @@ -72,7 +72,6 @@ */ #define RESCONFMAXNAMESERVERS 3U /*%< max 3 "nameserver" entries */ -#define RESCONFMAXSEARCH 8U /*%< max 8 domains in "search" entry */ #define RESCONFMAXLINELEN 256U /*%< max size of a line */ #define RESCONFMAXSORTLIST 10U /*%< max 10 */ @@ -99,7 +98,6 @@ struct irs_resconf { unsigned int numns; /*%< number of configured servers */ char *domainname; - char *search[RESCONFMAXSEARCH]; uint8_t searchnxt; /*%< index for next free slot */ irs_resconf_searchlist_t searchlist; @@ -139,10 +137,9 @@ static int eatline(FILE *fp) { int ch; - ch = fgetc(fp); - while (ch != '\n' && ch != EOF) { + do { ch = fgetc(fp); - } + } while (ch != '\n' && ch != EOF); return ch; } @@ -156,10 +153,9 @@ static int eatwhite(FILE *fp) { int ch; - ch = fgetc(fp); - while (ch != '\n' && ch != EOF && isspace((unsigned char)ch)) { + do { ch = fgetc(fp); - } + } while (ch != EOF && ch != '\n' && isspace((unsigned char)ch)); if (ch == ';' || ch == '#') { ch = eatline(fp); @@ -186,7 +182,6 @@ getword(FILE *fp, char *buffer, size_t size) { *p = '\0'; ch = eatwhite(fp); - if (ch == EOF) { return EOF; } @@ -194,7 +189,7 @@ getword(FILE *fp, char *buffer, size_t size) { do { *p = '\0'; - if (ch == EOF || isspace((unsigned char)ch)) { + if (isspace((unsigned char)ch)) { break; } else if ((size_t)(p - buffer) == size - 1) { return EOF; /* Not enough space. */ @@ -202,7 +197,7 @@ getword(FILE *fp, char *buffer, size_t size) { *p++ = (char)ch; ch = fgetc(fp); - } while (1); + } while (ch != EOF); return ch; } @@ -298,7 +293,7 @@ resconf_parsenameserver(irs_resconf_t *conf, FILE *fp) { isc_result_t result; cp = getword(fp, word, sizeof(word)); - if (strlen(word) == 0U) { + if (cp == EOF || strlen(word) == 0U) { return ISC_R_UNEXPECTEDEND; /* Nothing on line. */ } else if (cp == ' ' || cp == '\t') { cp = eatwhite(fp); @@ -325,10 +320,9 @@ static isc_result_t resconf_parsedomain(irs_resconf_t *conf, FILE *fp) { char word[RESCONFMAXLINELEN]; int res; - unsigned int i; res = getword(fp, word, sizeof(word)); - if (strlen(word) == 0U) { + if (res == EOF || strlen(word) == 0U) { return ISC_R_UNEXPECTEDEND; /* Nothing else on line. */ } else if (res == ' ' || res == '\t') { res = eatwhite(fp); @@ -344,25 +338,50 @@ resconf_parsedomain(irs_resconf_t *conf, FILE *fp) { /* * Search and domain are mutually exclusive. + * Search is cleared later. */ - for (i = 0; i < RESCONFMAXSEARCH; i++) { - if (conf->search[i] != NULL) { - isc_mem_free(conf->mctx, conf->search[i]); - conf->search[i] = NULL; - } - } - conf->searchnxt = 0; conf->domainname = isc_mem_strdup(conf->mctx, word); return ISC_R_SUCCESS; } +static void +free_search(irs_resconf_t *conf) { + irs_resconf_search_t *searchentry; + + while ((searchentry = ISC_LIST_HEAD(conf->searchlist)) != NULL) { + ISC_LIST_UNLINK(conf->searchlist, searchentry, link); + isc_mem_free(conf->mctx, searchentry->domain); + isc_mem_put(conf->mctx, searchentry, sizeof(*searchentry)); + } +} + +/*! + * Append new search entry to searchlist. + * + * Always copy domain name passed. + */ +static isc_result_t +add_search(irs_resconf_t *conf, char *domain) { + irs_resconf_search_t *entry = NULL; + + entry = isc_mem_get(conf->mctx, sizeof(*entry)); + *entry = (irs_resconf_search_t){ + .domain = isc_mem_strdup(conf->mctx, domain), + .link = ISC_LINK_INITIALIZER, + }; + + ISC_LIST_APPEND(conf->searchlist, entry, link); + + return ISC_R_SUCCESS; +} + static isc_result_t resconf_parsesearch(irs_resconf_t *conf, FILE *fp) { int delim; - unsigned int idx; char word[RESCONFMAXLINELEN]; + isc_result_t result; if (conf->domainname != NULL) { /* @@ -375,37 +394,27 @@ resconf_parsesearch(irs_resconf_t *conf, FILE *fp) { /* * Remove any previous search definitions. */ - for (idx = 0; idx < RESCONFMAXSEARCH; idx++) { - if (conf->search[idx] != NULL) { - isc_mem_free(conf->mctx, conf->search[idx]); - conf->search[idx] = NULL; - } - } - conf->searchnxt = 0; + free_search(conf); delim = getword(fp, word, sizeof(word)); - if (strlen(word) == 0U) { + if (delim == EOF || strlen(word) == 0U) { return ISC_R_UNEXPECTEDEND; /* Nothing else on line. */ } - - idx = 0; - while (strlen(word) > 0U) { - if (conf->searchnxt == RESCONFMAXSEARCH) { - goto ignore; /* Too many domains. */ + do { + result = add_search(conf, word); + if (result != ISC_R_SUCCESS) { + return result; } - INSIST(idx < sizeof(conf->search) / sizeof(conf->search[0])); - conf->search[idx] = isc_mem_strdup(conf->mctx, word); - idx++; - conf->searchnxt++; - - ignore: - if (delim == EOF || delim == '\n') { + if (delim == '\n') { break; - } else { - delim = getword(fp, word, sizeof(word)); } - } + + delim = getword(fp, word, sizeof(word)); + if (delim == EOF) { + return ISC_R_UNEXPECTEDEND; + } + } while (strlen(word) > 0U); return ISC_R_SUCCESS; } @@ -418,11 +427,11 @@ resconf_parsesortlist(irs_resconf_t *conf, FILE *fp) { char *p; delim = getword(fp, word, sizeof(word)); - if (strlen(word) == 0U) { + if (delim == EOF || strlen(word) == 0U) { return ISC_R_UNEXPECTEDEND; /* Empty line after keyword. */ } - while (strlen(word) > 0U) { + while (delim != EOF && strlen(word) > 0U) { if (conf->sortlistnxt == RESCONFMAXSORTLIST) { return ISC_R_QUOTA; /* Too many values. */ } @@ -515,19 +524,6 @@ cleanup: return result; } -static isc_result_t -add_search(irs_resconf_t *conf, char *domain) { - irs_resconf_search_t *entry; - - entry = isc_mem_get(conf->mctx, sizeof(*entry)); - - entry->domain = domain; - ISC_LINK_INIT(entry, link); - ISC_LIST_APPEND(conf->searchlist, entry, link); - - return ISC_R_SUCCESS; -} - /*% parses a file and fills in the data structure. */ isc_result_t irs_resconf_load(isc_mem_t *mctx, const char *filename, irs_resconf_t **confp) { @@ -535,8 +531,7 @@ irs_resconf_load(isc_mem_t *mctx, const char *filename, irs_resconf_t **confp) { char word[256]; isc_result_t rval, ret = ISC_R_SUCCESS; irs_resconf_t *conf; - unsigned int i; - int stopchar; + int stopchar = EOF; REQUIRE(mctx != NULL); REQUIRE(filename != NULL); @@ -544,29 +539,24 @@ irs_resconf_load(isc_mem_t *mctx, const char *filename, irs_resconf_t **confp) { REQUIRE(confp != NULL && *confp == NULL); conf = isc_mem_get(mctx, sizeof(*conf)); - - conf->mctx = mctx; - ISC_LIST_INIT(conf->nameservers); - ISC_LIST_INIT(conf->searchlist); - conf->numns = 0; - conf->domainname = NULL; - conf->searchnxt = 0; - conf->sortlistnxt = 0; - conf->resdebug = 0; - conf->ndots = 1; - conf->attempts = 3; - conf->timeout = 0; - for (i = 0; i < RESCONFMAXSEARCH; i++) { - conf->search[i] = NULL; - } + *conf = (irs_resconf_t){ + .mctx = mctx, + .nameservers = ISC_LIST_INITIALIZER, + .searchlist = ISC_LIST_INITIALIZER, + .ndots = 1, + .attempts = 3, + }; errno = 0; if ((fp = fopen(filename, "r")) != NULL) { - do { + while (!feof(fp) && !ferror(fp)) { stopchar = getword(fp, word, sizeof(word)); if (stopchar == EOF) { - rval = ISC_R_SUCCESS; - POST(rval); + if (strlen(word) != 0) { + if (ret == ISC_R_SUCCESS) { + ret = ISC_R_UNEXPECTEDEND; + } + } break; } @@ -583,11 +573,10 @@ irs_resconf_load(isc_mem_t *mctx, const char *filename, irs_resconf_t **confp) { } else if (strcmp(word, "options") == 0) { rval = resconf_parseoption(conf, fp); } else { - /* unrecognised word. Ignore entire line */ + /* Unrecognised word. Ignore entire line. */ rval = ISC_R_SUCCESS; if (stopchar != '\n') { - stopchar = eatline(fp); - if (stopchar == EOF) { + if (eatline(fp) == EOF) { break; } } @@ -595,7 +584,7 @@ irs_resconf_load(isc_mem_t *mctx, const char *filename, irs_resconf_t **confp) { if (ret == ISC_R_SUCCESS && rval != ISC_R_SUCCESS) { ret = rval; } - } while (1); + } fclose(fp); } else { @@ -614,17 +603,11 @@ irs_resconf_load(isc_mem_t *mctx, const char *filename, irs_resconf_t **confp) { /* * Construct unified search list from domain or configured - * search list + * search list. Last specified is used. */ if (conf->domainname != NULL) { + free_search(conf); ret = add_search(conf, conf->domainname); - } else if (conf->searchnxt > 0) { - for (i = 0; i < conf->searchnxt; i++) { - ret = add_search(conf, conf->search[i]); - if (ret != ISC_R_SUCCESS) { - break; - } - } } /* If we don't find a nameserver fall back to localhost */ @@ -655,18 +638,13 @@ void irs_resconf_destroy(irs_resconf_t **confp) { irs_resconf_t *conf; isc_sockaddr_t *address; - irs_resconf_search_t *searchentry; - unsigned int i; REQUIRE(confp != NULL); conf = *confp; *confp = NULL; REQUIRE(IRS_RESCONF_VALID(conf)); - while ((searchentry = ISC_LIST_HEAD(conf->searchlist)) != NULL) { - ISC_LIST_UNLINK(conf->searchlist, searchentry, link); - isc_mem_put(conf->mctx, searchentry, sizeof(*searchentry)); - } + free_search(conf); while ((address = ISC_LIST_HEAD(conf->nameservers)) != NULL) { ISC_LIST_UNLINK(conf->nameservers, address, link); @@ -677,12 +655,6 @@ irs_resconf_destroy(irs_resconf_t **confp) { isc_mem_free(conf->mctx, conf->domainname); } - for (i = 0; i < RESCONFMAXSEARCH; i++) { - if (conf->search[i] != NULL) { - isc_mem_free(conf->mctx, conf->search[i]); - } - } - isc_mem_put(conf->mctx, conf, sizeof(*conf)); } diff --git a/tests/irs/testdata/search.conf b/tests/irs/testdata/search.conf index f019ab9817..a507fefb5b 100644 --- a/tests/irs/testdata/search.conf +++ b/tests/irs/testdata/search.conf @@ -9,4 +9,4 @@ # See the COPYRIGHT file distributed with this work for additional # information regarding copyright ownership. -search example.com example.net +search example.com n1.example.org n2.example.org n3.example.org n4.example.org n5.example.org n6.example.org n7.example.org n8.example.org example.net