2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-29 05:28:00 +00:00

fix: dev: Accept resolv.conf with more than 8 search domains

Closes #1259

Merge branch '1259-irs-search-unlimited' into 'main'

See merge request isc-projects/bind9!2446
This commit is contained in:
Mark Andrews 2024-12-10 01:39:04 +00:00
commit eda02dc342
2 changed files with 77 additions and 105 deletions

View File

@ -72,7 +72,6 @@
*/ */
#define RESCONFMAXNAMESERVERS 3U /*%< max 3 "nameserver" entries */ #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 RESCONFMAXLINELEN 256U /*%< max size of a line */
#define RESCONFMAXSORTLIST 10U /*%< max 10 */ #define RESCONFMAXSORTLIST 10U /*%< max 10 */
@ -99,7 +98,6 @@ struct irs_resconf {
unsigned int numns; /*%< number of configured servers */ unsigned int numns; /*%< number of configured servers */
char *domainname; char *domainname;
char *search[RESCONFMAXSEARCH];
uint8_t searchnxt; /*%< index for next free slot */ uint8_t searchnxt; /*%< index for next free slot */
irs_resconf_searchlist_t searchlist; irs_resconf_searchlist_t searchlist;
@ -139,10 +137,9 @@ static int
eatline(FILE *fp) { eatline(FILE *fp) {
int ch; int ch;
ch = fgetc(fp); do {
while (ch != '\n' && ch != EOF) {
ch = fgetc(fp); ch = fgetc(fp);
} } while (ch != '\n' && ch != EOF);
return ch; return ch;
} }
@ -156,10 +153,9 @@ static int
eatwhite(FILE *fp) { eatwhite(FILE *fp) {
int ch; int ch;
ch = fgetc(fp); do {
while (ch != '\n' && ch != EOF && isspace((unsigned char)ch)) {
ch = fgetc(fp); ch = fgetc(fp);
} } while (ch != EOF && ch != '\n' && isspace((unsigned char)ch));
if (ch == ';' || ch == '#') { if (ch == ';' || ch == '#') {
ch = eatline(fp); ch = eatline(fp);
@ -186,7 +182,6 @@ getword(FILE *fp, char *buffer, size_t size) {
*p = '\0'; *p = '\0';
ch = eatwhite(fp); ch = eatwhite(fp);
if (ch == EOF) { if (ch == EOF) {
return EOF; return EOF;
} }
@ -194,7 +189,7 @@ getword(FILE *fp, char *buffer, size_t size) {
do { do {
*p = '\0'; *p = '\0';
if (ch == EOF || isspace((unsigned char)ch)) { if (isspace((unsigned char)ch)) {
break; break;
} else if ((size_t)(p - buffer) == size - 1) { } else if ((size_t)(p - buffer) == size - 1) {
return EOF; /* Not enough space. */ return EOF; /* Not enough space. */
@ -202,7 +197,7 @@ getword(FILE *fp, char *buffer, size_t size) {
*p++ = (char)ch; *p++ = (char)ch;
ch = fgetc(fp); ch = fgetc(fp);
} while (1); } while (ch != EOF);
return ch; return ch;
} }
@ -298,7 +293,7 @@ resconf_parsenameserver(irs_resconf_t *conf, FILE *fp) {
isc_result_t result; isc_result_t result;
cp = getword(fp, word, sizeof(word)); cp = getword(fp, word, sizeof(word));
if (strlen(word) == 0U) { if (cp == EOF || strlen(word) == 0U) {
return ISC_R_UNEXPECTEDEND; /* Nothing on line. */ return ISC_R_UNEXPECTEDEND; /* Nothing on line. */
} else if (cp == ' ' || cp == '\t') { } else if (cp == ' ' || cp == '\t') {
cp = eatwhite(fp); cp = eatwhite(fp);
@ -325,10 +320,9 @@ static isc_result_t
resconf_parsedomain(irs_resconf_t *conf, FILE *fp) { resconf_parsedomain(irs_resconf_t *conf, FILE *fp) {
char word[RESCONFMAXLINELEN]; char word[RESCONFMAXLINELEN];
int res; int res;
unsigned int i;
res = getword(fp, word, sizeof(word)); res = getword(fp, word, sizeof(word));
if (strlen(word) == 0U) { if (res == EOF || strlen(word) == 0U) {
return ISC_R_UNEXPECTEDEND; /* Nothing else on line. */ return ISC_R_UNEXPECTEDEND; /* Nothing else on line. */
} else if (res == ' ' || res == '\t') { } else if (res == ' ' || res == '\t') {
res = eatwhite(fp); res = eatwhite(fp);
@ -344,25 +338,50 @@ resconf_parsedomain(irs_resconf_t *conf, FILE *fp) {
/* /*
* Search and domain are mutually exclusive. * 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); conf->domainname = isc_mem_strdup(conf->mctx, word);
return ISC_R_SUCCESS; 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 static isc_result_t
resconf_parsesearch(irs_resconf_t *conf, FILE *fp) { resconf_parsesearch(irs_resconf_t *conf, FILE *fp) {
int delim; int delim;
unsigned int idx;
char word[RESCONFMAXLINELEN]; char word[RESCONFMAXLINELEN];
isc_result_t result;
if (conf->domainname != NULL) { if (conf->domainname != NULL) {
/* /*
@ -375,37 +394,27 @@ resconf_parsesearch(irs_resconf_t *conf, FILE *fp) {
/* /*
* Remove any previous search definitions. * Remove any previous search definitions.
*/ */
for (idx = 0; idx < RESCONFMAXSEARCH; idx++) { free_search(conf);
if (conf->search[idx] != NULL) {
isc_mem_free(conf->mctx, conf->search[idx]);
conf->search[idx] = NULL;
}
}
conf->searchnxt = 0;
delim = getword(fp, word, sizeof(word)); delim = getword(fp, word, sizeof(word));
if (strlen(word) == 0U) { if (delim == EOF || strlen(word) == 0U) {
return ISC_R_UNEXPECTEDEND; /* Nothing else on line. */ return ISC_R_UNEXPECTEDEND; /* Nothing else on line. */
} }
do {
idx = 0; result = add_search(conf, word);
while (strlen(word) > 0U) { if (result != ISC_R_SUCCESS) {
if (conf->searchnxt == RESCONFMAXSEARCH) { return result;
goto ignore; /* Too many domains. */
} }
INSIST(idx < sizeof(conf->search) / sizeof(conf->search[0])); if (delim == '\n') {
conf->search[idx] = isc_mem_strdup(conf->mctx, word);
idx++;
conf->searchnxt++;
ignore:
if (delim == EOF || delim == '\n') {
break; 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; return ISC_R_SUCCESS;
} }
@ -418,11 +427,11 @@ resconf_parsesortlist(irs_resconf_t *conf, FILE *fp) {
char *p; char *p;
delim = getword(fp, word, sizeof(word)); delim = getword(fp, word, sizeof(word));
if (strlen(word) == 0U) { if (delim == EOF || strlen(word) == 0U) {
return ISC_R_UNEXPECTEDEND; /* Empty line after keyword. */ return ISC_R_UNEXPECTEDEND; /* Empty line after keyword. */
} }
while (strlen(word) > 0U) { while (delim != EOF && strlen(word) > 0U) {
if (conf->sortlistnxt == RESCONFMAXSORTLIST) { if (conf->sortlistnxt == RESCONFMAXSORTLIST) {
return ISC_R_QUOTA; /* Too many values. */ return ISC_R_QUOTA; /* Too many values. */
} }
@ -515,19 +524,6 @@ cleanup:
return result; 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. */ /*% parses a file and fills in the data structure. */
isc_result_t isc_result_t
irs_resconf_load(isc_mem_t *mctx, const char *filename, irs_resconf_t **confp) { 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]; char word[256];
isc_result_t rval, ret = ISC_R_SUCCESS; isc_result_t rval, ret = ISC_R_SUCCESS;
irs_resconf_t *conf; irs_resconf_t *conf;
unsigned int i; int stopchar = EOF;
int stopchar;
REQUIRE(mctx != NULL); REQUIRE(mctx != NULL);
REQUIRE(filename != 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); REQUIRE(confp != NULL && *confp == NULL);
conf = isc_mem_get(mctx, sizeof(*conf)); conf = isc_mem_get(mctx, sizeof(*conf));
*conf = (irs_resconf_t){
conf->mctx = mctx; .mctx = mctx,
ISC_LIST_INIT(conf->nameservers); .nameservers = ISC_LIST_INITIALIZER,
ISC_LIST_INIT(conf->searchlist); .searchlist = ISC_LIST_INITIALIZER,
conf->numns = 0; .ndots = 1,
conf->domainname = NULL; .attempts = 3,
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;
}
errno = 0; errno = 0;
if ((fp = fopen(filename, "r")) != NULL) { if ((fp = fopen(filename, "r")) != NULL) {
do { while (!feof(fp) && !ferror(fp)) {
stopchar = getword(fp, word, sizeof(word)); stopchar = getword(fp, word, sizeof(word));
if (stopchar == EOF) { if (stopchar == EOF) {
rval = ISC_R_SUCCESS; if (strlen(word) != 0) {
POST(rval); if (ret == ISC_R_SUCCESS) {
ret = ISC_R_UNEXPECTEDEND;
}
}
break; 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) { } else if (strcmp(word, "options") == 0) {
rval = resconf_parseoption(conf, fp); rval = resconf_parseoption(conf, fp);
} else { } else {
/* unrecognised word. Ignore entire line */ /* Unrecognised word. Ignore entire line. */
rval = ISC_R_SUCCESS; rval = ISC_R_SUCCESS;
if (stopchar != '\n') { if (stopchar != '\n') {
stopchar = eatline(fp); if (eatline(fp) == EOF) {
if (stopchar == EOF) {
break; 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) { if (ret == ISC_R_SUCCESS && rval != ISC_R_SUCCESS) {
ret = rval; ret = rval;
} }
} while (1); }
fclose(fp); fclose(fp);
} else { } 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 * Construct unified search list from domain or configured
* search list * search list. Last specified is used.
*/ */
if (conf->domainname != NULL) { if (conf->domainname != NULL) {
free_search(conf);
ret = add_search(conf, conf->domainname); 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 */ /* 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_destroy(irs_resconf_t **confp) {
irs_resconf_t *conf; irs_resconf_t *conf;
isc_sockaddr_t *address; isc_sockaddr_t *address;
irs_resconf_search_t *searchentry;
unsigned int i;
REQUIRE(confp != NULL); REQUIRE(confp != NULL);
conf = *confp; conf = *confp;
*confp = NULL; *confp = NULL;
REQUIRE(IRS_RESCONF_VALID(conf)); REQUIRE(IRS_RESCONF_VALID(conf));
while ((searchentry = ISC_LIST_HEAD(conf->searchlist)) != NULL) { free_search(conf);
ISC_LIST_UNLINK(conf->searchlist, searchentry, link);
isc_mem_put(conf->mctx, searchentry, sizeof(*searchentry));
}
while ((address = ISC_LIST_HEAD(conf->nameservers)) != NULL) { while ((address = ISC_LIST_HEAD(conf->nameservers)) != NULL) {
ISC_LIST_UNLINK(conf->nameservers, address, link); 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); 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)); isc_mem_put(conf->mctx, conf, sizeof(*conf));
} }

View File

@ -9,4 +9,4 @@
# See the COPYRIGHT file distributed with this work for additional # See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership. # 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