git: b5fb1f44ed43 - main - Issue #237 : Resolver uses nameserver commented out in /etc/resolv.conf

From: Dag-Erling Smørgrav <des_at_FreeBSD.org>
Date: Wed, 15 May 2024 09:53:57 UTC
The branch main has been updated by des:

URL: https://cgit.FreeBSD.org/src/commit/?id=b5fb1f44ed435fa25fe3de87c9b9ee6c0aad5125

commit b5fb1f44ed435fa25fe3de87c9b9ee6c0aad5125
Author:     Willem Toorop <willem@nlnetlabs.nl>
AuthorDate: 2024-05-07 12:43:16 +0000
Commit:     Dag-Erling Smørgrav <des@FreeBSD.org>
CommitDate: 2024-05-15 09:52:49 +0000

    Issue #237 : Resolver uses nameserver commented out in /etc/resolv.conf
    
    This /etc/resolv.conf:
        # x
    
        # nameserver 8.8.8.8
    
    Still configured 8.8.8.8 as nameserver, because the comment detection in `ldns_resolver_new_frm_fp_l()` didn't anticipate empty lines before the comment.
    This fix removed all comment handling from `ldns_resolver_new_frm_fp_l()`. Instead a new function is introduced `ldns_fget_token_l_resolv_conf()` that skips comments that start with '#' and ';'. The old `ldns_fget_token_l()` (that is used for zonefiles too) still accepts only ';' for comments.
---
 contrib/ldns/parse.c    | 35 +++++++++++++++++++++++++++----
 contrib/ldns/resolver.c | 55 ++++++++++---------------------------------------
 2 files changed, 42 insertions(+), 48 deletions(-)

diff --git a/contrib/ldns/parse.c b/contrib/ldns/parse.c
index 9698ba71e881..af8b2c1321b2 100644
--- a/contrib/ldns/parse.c
+++ b/contrib/ldns/parse.c
@@ -27,9 +27,14 @@ ldns_fget_token(FILE *f, char *token, const char *delim, size_t limit)
 	return ldns_fget_token_l(f, token, delim, limit, NULL);
 }
 
-ldns_status
-ldns_fget_token_l_st(FILE *f, char **token, size_t *limit, bool fixed
-                    , const char *delim, int *line_nr)
+enum file_type2parse {
+	zone_file_type, resolv_conf_file_type
+};
+
+static ldns_status
+ldns_fget_token_l_st_file_type(FILE *f, char **token, size_t *limit,
+		bool fixed, const char *delim, int *line_nr,
+		enum file_type2parse file_type)
 {
 	int c, prev_c;
 	int p; /* 0 -> no parentheses seen, >0 nr of ( seen */
@@ -98,7 +103,9 @@ ldns_fget_token_l_st(FILE *f, char **token, size_t *limit, bool fixed
 		}
 
 		/* do something with comments ; */
-		if (c == ';' && quoted == 0) {
+		if ((c == ';'
+		||  (c == '#' && file_type == resolv_conf_file_type))
+				&& quoted == 0) {
 			if (prev_c != '\\') {
 				com = 1;
 			}
@@ -215,6 +222,26 @@ tokenread:
 	return i == 0 ? LDNS_STATUS_SYNTAX_EMPTY : LDNS_STATUS_OK;
 }
 
+ldns_status
+ldns_fget_token_l_st(FILE *f, char **token, size_t *limit, bool fixed
+                    , const char *delim, int *line_nr)
+{
+	return ldns_fget_token_l_st_file_type(
+		f, token, limit, fixed, delim, line_nr, zone_file_type);
+}
+
+ssize_t
+ldns_fget_token_l_resolv_conf(FILE *f, char *token, const char *delim,
+		size_t limit, int *line_nr)
+{
+	if (limit == 0)
+		limit = LDNS_MAX_LINELEN;
+	if (ldns_fget_token_l_st_file_type(f, &token, &limit, true, delim,
+				line_nr, resolv_conf_file_type))
+		return -1;
+	else
+		return (ssize_t)strlen(token);
+}
 
 ssize_t
 ldns_fget_token_l(FILE *f, char *token, const char *delim, size_t limit, int *line_nr)
diff --git a/contrib/ldns/resolver.c b/contrib/ldns/resolver.c
index f9ec65a55966..4b398abb4418 100644
--- a/contrib/ldns/resolver.c
+++ b/contrib/ldns/resolver.c
@@ -761,6 +761,8 @@ ldns_resolver_new_frm_fp(ldns_resolver **res, FILE *fp)
 	return ldns_resolver_new_frm_fp_l(res, fp, NULL);
 }
 
+ssize_t ldns_fget_token_l_resolv_conf(FILE *f, char *token, const char *delim,
+		size_t limit, int *line_nr);
 ldns_status
 ldns_resolver_new_frm_fp_l(ldns_resolver **res, FILE *fp, int *line_nr)
 {
@@ -775,7 +777,7 @@ ldns_resolver_new_frm_fp_l(ldns_resolver **res, FILE *fp, int *line_nr)
 #endif
 	ssize_t gtr, bgtr;
 	ldns_buffer *b;
-        int lnr = 0, oldline;
+        int lnr = 0;
 	FILE* myfp = fp;
         if(!line_nr) line_nr = &lnr;
 
@@ -809,36 +811,18 @@ ldns_resolver_new_frm_fp_l(ldns_resolver **res, FILE *fp, int *line_nr)
 
 	gtr = 1;
 	word[0] = 0;
-        oldline = *line_nr;
         expect = LDNS_RESOLV_KEYWORD;
 	while (gtr > 0) {
-		/* check comments */
-		if (word[0] == '#') {
-                        word[0]='x';
-                        if(oldline == *line_nr) {
-                                /* skip until end of line */
-                                int c;
-                                do {
-                                        c = fgetc(myfp);
-                                } while(c != EOF && c != '\n');
-                                if(c=='\n') (*line_nr)++;
-                        }
-			/* and read next to prepare for further parsing */
-                        oldline = *line_nr;
-			continue;
-		}
-                oldline = *line_nr;
 		switch(expect) {
 			case LDNS_RESOLV_KEYWORD:
 				/* keyword */
-				gtr = ldns_fget_token_l(myfp, word, LDNS_PARSE_NORMAL, 0, line_nr);
+				gtr = ldns_fget_token_l_resolv_conf(myfp, word, LDNS_PARSE_NORMAL, 0, line_nr);
 				if (gtr != 0) {
-                                        if(word[0] == '#') continue;
 					for(i = 0; i < LDNS_RESOLV_KEYWORDS; i++) {
 						if (strcasecmp(keyword[i], word) == 0) {
 							/* chosen the keyword and
 							 * expect values carefully
-	        					 */
+							 */
 							expect = i;
 							break;
 						}
@@ -856,16 +840,12 @@ ldns_resolver_new_frm_fp_l(ldns_resolver **res, FILE *fp, int *line_nr)
 				break;
 			case LDNS_RESOLV_DEFDOMAIN:
 				/* default domain dname */
-				gtr = ldns_fget_token_l(myfp, word, LDNS_PARSE_NORMAL, 0, line_nr);
+				gtr = ldns_fget_token_l_resolv_conf(myfp, word, LDNS_PARSE_NORMAL, 0, line_nr);
 				if (gtr == 0) {
 					if(!fp) fclose(myfp);
 					ldns_resolver_deep_free(r);
 					return LDNS_STATUS_SYNTAX_MISSING_VALUE_ERR;
 				}
-                                if(word[0] == '#') {
-                                        expect = LDNS_RESOLV_KEYWORD;
-                                        continue;
-                                }
 				tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, word);
 				if (!tmp) {
 					if(!fp) fclose(myfp);
@@ -879,16 +859,12 @@ ldns_resolver_new_frm_fp_l(ldns_resolver **res, FILE *fp, int *line_nr)
 				break;
 			case LDNS_RESOLV_NAMESERVER:
 				/* NS aaaa or a record */
-				gtr = ldns_fget_token_l(myfp, word, LDNS_PARSE_NORMAL, 0, line_nr);
+				gtr = ldns_fget_token_l_resolv_conf(myfp, word, LDNS_PARSE_NORMAL, 0, line_nr);
 				if (gtr == 0) {
 					if(!fp) fclose(myfp);
 					ldns_resolver_deep_free(r);
 					return LDNS_STATUS_SYNTAX_MISSING_VALUE_ERR;
 				}
-                                if(word[0] == '#') {
-                                        expect = LDNS_RESOLV_KEYWORD;
-                                        continue;
-                                }
                                 if(strchr(word, '%')) {
                                         /* snip off interface labels,
                                          * fe80::222:19ff:fe31:4222%eth0 */
@@ -911,7 +887,7 @@ ldns_resolver_new_frm_fp_l(ldns_resolver **res, FILE *fp, int *line_nr)
 				break;
 			case LDNS_RESOLV_SEARCH:
 				/* search list domain dname */
-				gtr = ldns_fget_token_l(myfp, word, LDNS_PARSE_SKIP_SPACE, 0, line_nr);
+				gtr = ldns_fget_token_l_resolv_conf(myfp, word, LDNS_PARSE_SKIP_SPACE, 0, line_nr);
 				b = LDNS_MALLOC(ldns_buffer);
 				if(!b) {
 					ldns_resolver_deep_free(r);
@@ -929,10 +905,6 @@ ldns_resolver_new_frm_fp_l(ldns_resolver **res, FILE *fp, int *line_nr)
 				bgtr = ldns_bget_token(b, word, LDNS_PARSE_NORMAL, (size_t) gtr + 1);
 				while (bgtr > 0) {
 					gtr -= bgtr;
-                                        if(word[0] == '#') {
-                                                expect = LDNS_RESOLV_KEYWORD;
-                                                break;
-                                        }
 					tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, word);
 					if (!tmp) {
 						ldns_resolver_deep_free(r);
@@ -954,28 +926,23 @@ ldns_resolver_new_frm_fp_l(ldns_resolver **res, FILE *fp, int *line_nr)
 				}
 				break;
 			case LDNS_RESOLV_SORTLIST:
-				gtr = ldns_fget_token_l(myfp, word, LDNS_PARSE_SKIP_SPACE, 0, line_nr);
+				gtr = ldns_fget_token_l_resolv_conf(myfp, word, LDNS_PARSE_SKIP_SPACE, 0, line_nr);
 				/* sortlist not implemented atm */
 				expect = LDNS_RESOLV_KEYWORD;
 				break;
 			case LDNS_RESOLV_OPTIONS:
-				gtr = ldns_fget_token_l(myfp, word, LDNS_PARSE_SKIP_SPACE, 0, line_nr);
+				gtr = ldns_fget_token_l_resolv_conf(myfp, word, LDNS_PARSE_SKIP_SPACE, 0, line_nr);
 				/* options not implemented atm */
 				expect = LDNS_RESOLV_KEYWORD;
 				break;
 			case LDNS_RESOLV_ANCHOR:
 				/* a file containing a DNSSEC trust anchor */
-				gtr = ldns_fget_token_l(myfp, word, LDNS_PARSE_NORMAL, 0, line_nr);
+				gtr = ldns_fget_token_l_resolv_conf(myfp, word, LDNS_PARSE_NORMAL, 0, line_nr);
 				if (gtr == 0) {
 					ldns_resolver_deep_free(r);
 					if(!fp) fclose(myfp);
 					return LDNS_STATUS_SYNTAX_MISSING_VALUE_ERR;
 				}
-                                if(word[0] == '#') {
-                                        expect = LDNS_RESOLV_KEYWORD;
-                                        continue;
-                                }
-
 #ifdef HAVE_SSL
 				tmp_rr = ldns_read_anchor_file(word);
 				(void) ldns_resolver_push_dnssec_anchor(r, tmp_rr);