git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 8/5] srv: tolerate broken DNS replies

From
Jonathan Nieder <jrnieder@gmail.com>
Date
Mar 8, 2012, 13:23 UTC
Message-ID
<20120308132339.GH9426@burratino>
In-Reply-To
<20120308124857.GA7666@burratino>

At a hotel with a very broken Wi-Fi setup, Richard found his copy of git unable to cope:

	% git clone git://git.kitenet.net/mr
	Cloning into 'mr'...
	error: cannot initialize DNS parser: Message too long
	fatal: Unable to look up git.kitenet.net

Other programs gave some warnings but otherwise worked fine. From a packet capture, it seems that the response to a SRV query for _git._tcp.git.kitenet.net in this setup was a single A resource record pointing to the link-local address 169.254.1.1, followed by two trailing bytes: c0 1a. The trailing bytes cause the underlying parser to fail.

It would not be good to silently tolerate this and similar kinds of brokenness, but working around it would help people on affected systems to recover. Luckily RFC2782 gives us enough leeway to act as we please for this particular kind of error, so give a warning and fall back to an A/AAAA query (which should work).

Similarly, if we receive non-SRV RRs in response to a SRV query, RFC2782 does not say to error out, so in the spirit of graceful degradation let's warn and skip those records.

Reported-by: Richard Hartmann <richih.mailinglist@gmail.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
Thanks for reading.  That's the end of the series.

Good night, Jonathan

 srv.c |   40 ++++++++++++++++++++++++++--------------
 1 file changed, 26 insertions(+), 14 deletions(-)
diff --git a/srv.c b/srv.c
index 2716206e..829ef762 100644
--- a/srv.c
+++ b/srv.c
@@ -83,7 +83,6 @@ static int srv_parse(ns_msg *msg, struct parsed_srv_rr **res)
 {
 	struct parsed_srv_rr *rrs = NULL;
 	int nr_parsed = 0;
-	int cnames = 0;
 	int i, n;
 
 	n = ns_msg_count(*msg, ns_s_an);
@@ -98,30 +97,33 @@ static int srv_parse(ns_msg *msg, struct parsed_srv_rr **res)
 		if (ns_rr_type(rr) != ns_t_cname)
 			break;
 	}
-	cnames = i;
-	n -= cnames;
 
-	rrs = xmalloc(n * sizeof(*rrs));
-	for (i = 0; i < n; i++) {
+	rrs = xmalloc((n - i) * sizeof(*rrs));
+	for (; i < n; i++) {
 		ns_rr rr;
 
-		if (ns_parserr(msg, ns_s_an, cnames + i, &rr)) {
+		if (ns_parserr(msg, ns_s_an, i, &rr)) {
 			error("cannot parse DNS RR: %s", strerror(errno));
 			goto fail;
 		}
 		if (ns_rr_type(rr) != ns_t_srv) {
-			error("expected SRV RR, found RR type %d",
+			/*
+			 * Maybe the server is playing tricks and returned
+			 * an A record.  Let it pass and if we don't get
+			 * any SRV RRs, we can fall back to an A lookup.
+			 */
+			warning("expected SRV RR, found RR type %d",
 						(int) ns_rr_type(rr));
-			goto fail;
+			continue;
 		}
-		if (srv_parse_rr(msg, &rr, rrs + i))
+		if (srv_parse_rr(msg, &rr, rrs + nr_parsed))
 			/* srv_parse_rr writes a message */
 			goto fail;
 		nr_parsed++;
 	}
 
 	*res = rrs;
-	return n;
+	return nr_parsed;
 fail:
 	for (i = 0; i < nr_parsed; i++)
 		free(rrs[i].target);
@@ -274,13 +276,23 @@ int get_srv(const char *host, struct host **hosts)
 	if (len < 0)
 		goto out;
 
+	/*
+	 * If the reply to a SRV query is malformed, fall back to an
+	 * A query.
+	 *
+	 * The RFC2782 usage rules don't say anything about this, but
+	 * in practice, it seems that some firewalls or DNS servers
+	 * (think: captive portal) handle A queries sensibly and
+	 * provide malformed replies in response to SRV queries.
+	 */
+	if (ns_initparse(buf, len, &msg)) {
+		warning("cannot parse SRV response: %s", strerror(errno));
+		goto out;
+	}
+
 	/* If a SRV RR cannot be parsed, give up. */
 	ret = -1;
 
-	if (ns_initparse(buf, len, &msg)) {
-		error("cannot initialize DNS parser: %s", strerror(errno));
-		goto out;
-	}
 	n = srv_parse(&msg, &rrs);
 	if (n < 0)
 		/* srv_parse writes a message */
-- 
1.7.9.2
Previous: Jonathan NiederNext: Richard Hartmann
Message 16 of 20 in “transport: unify ipv4 and ipv6 code paths”
  1. 0/5 transport: unify ipv4 and ipv6 code pathsJonathan Nieder, Mar 8, 2012
  2. 1/5 transport: expose git_tcp_connect() and friends in new tcp.hJonathan Nieder, Mar 8, 2012
  3. Erik Faye-LundMar 8, 2012
  4. 2/5 daemon: make host resolution a separate functionJonathan Nieder, Mar 8, 2012
  5. 3/5 daemon: move locate_host() to tcp libJonathan Nieder, Mar 8, 2012
  6. 4/5 tcp: unify ipv4 and ipv6 code pathsJonathan Nieder, Mar 8, 2012
  7. Erik Faye-LundMar 8, 2012
  8. Jonathan NiederMar 8, 2012
  9. 5/5 daemon: check for errors retrieving IP addressJonathan Nieder, Mar 8, 2012
  10. 6/5 tcp: make dns_resolve() return an error codeJonathan Nieder, Mar 8, 2012
  11. 7/5 transport: optionally honor DNS SRV recordsJonathan Nieder, Mar 8, 2012
  12. Erik Faye-LundMar 8, 2012
  13. Jonathan NiederMar 8, 2012
  14. Johannes SixtMar 9, 2012
  15. Jonathan NiederMar 9, 2012
  16. 8/5 srv: tolerate broken DNS repliesJonathan Nieder, Mar 8, 2012
  17. Richard HartmannMar 8, 2012
  18. Erik Faye-LundJun 11, 2012
  19. Junio C HamanoJun 11, 2012
  20. Jonathan NiederJun 14, 2012

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.