NLnetLabs / ldns

LDNS is a DNS library that facilitates DNS tool programming

Home Page:https://nlnetlabs.nl/ldns

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[BUG] Resolver uses nameserver commented out in /etc/resolv.conf

grembo opened this issue · comments

TL;DR

Comment parsing in /etc/resolv.conf is broken since 889f7c7

How to reproduce

Create a basic resolv.conf containing comments:

cat<<EOF >/etc/resolv.conf
# x

# nameserver 8.8.8.8
EOF

Then run drill on some zone:

drill wikipedia.org

Expected outcome

Since there are no nameservers configured, this outcome would be expected:

Error: error sending query: No (valid) nameservers defined in the resolver

Actual outcome

The commented out nameserver entry is used:

;; ->>HEADER<<- opcode: QUERY, rcode: NOERROR, id: 17996
;; flags: qr rd ra ; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 
;; QUESTION SECTION:
;; wikipedia.org.	IN	A

;; ANSWER SECTION:
wikipedia.org.	77	IN	A	185.15.59.224

;; AUTHORITY SECTION:

;; ADDITIONAL SECTION:

;; Query time: 20 msec
;; SERVER: 8.8.8.8
;; WHEN: Fri May  3 15:40:07 2024
;; MSG SIZE  rcvd: 47

Analysis

Commit 889f7c7 introduced this change:

diff --git a/parse.c b/parse.c
index 3c737620..9698ba71 100644
--- a/parse.c
+++ b/parse.c
@@ -187,6 +187,9 @@ ldns_fget_token_l_st(FILE *f, char **token, size_t *limit, bool fixed
                if (c != '\0' && c != '\n') {
                        *t++ = c;
                }
+               if (c == '\n' && line_nr) {
+                       *line_nr = *line_nr + 1;
+               }
                if (c == '\\' && prev_c == '\\')
                        prev_c = 0;
                else    prev_c = c;

Which breaks comment handling in resolver.c, which only removes characters until the end of line, in case line_nr doesn't change:

                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;
                }

Potential Fixes

The parser isn't necessarily the kind of code one just jumps into and reasons about, yet the three suggestions below worked for my limited use case:

  1. Rollback 889f7c7 (from the commit it's unclear, if it fixed a cosmetic or a functional issue)
  2. Make ldns_fget_token_l_st understand comments starting with # (unclear which side-effects this might have)
diff --git a/parse.c b/parse.c
index 9698ba71..a2478f66 100644
--- a/parse.c
+++ b/parse.c
@@ -98,7 +98,7 @@ 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 == '#') && quoted == 0) {
                        if (prev_c != '\\') {
                                com = 1;
                        }
  1. Patch resolver.c's comment handling (again, might have unwanted side effects):
diff --git a/resolver.c b/resolver.c
index f9ec65a5..e8921dbc 100644
--- a/resolver.c
+++ b/resolver.c
@@ -815,14 +815,12 @@ ldns_resolver_new_frm_fp_l(ldns_resolver **res, FILE *fp, int *line_nr)
                /* 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;

Real life resolv.conf

This is the configuration where we first encountered issues (it would request a local zone from google DNS and fail with NXDOMAIN, even though we would expect the call to be handled by unbound running locally)

# Generated by resolvconf
# nameserver 192.168.1.1

# nameserver 8.8.8.8
nameserver 127.0.0.1
options edns0

Hopefully found a title that makes more sense now 😄

  1. Make ldns_fget_token_l_st understand comments starting with # (unclear which side-effects this might have)

Thank you @grembo . I prefer that one, and then remove all comment handling from resolver.c. I just added a bit more (in PR #238) so that zonefile parsing does not accept comments to start with '#' too.

Fixed by #238, thank you guys!

And thank you for reporting!

@dag-erling I've put a bugfix release on the calender for June.