aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2014-04-07 22:03:19 -0400
committerNick Mathewson <nickm@torproject.org>2014-04-07 22:08:41 -0400
commit6d0991ea0872bf8a7b093709a4c7bf1619433917 (patch)
tree209d8c13ed1b0ce3366b8558707aaffc67dd32ac
parentbc0882c868c0cb61ade0f8b500c4392c889d6d0e (diff)
downloadtor-6d0991ea0872bf8a7b093709a4c7bf1619433917.tar
tor-6d0991ea0872bf8a7b093709a4c7bf1619433917.tar.gz
Give no answer, not NOTIMPL, for unsupported DNS query types
According to reports, most programs degrade somewhat gracefully on getting no answer for an MX or a CERT for www.example.com, but many flip out completely on a NOTIMPL error. Also, treat a QTYPE_ALL query as just asking for an A record. The real fix here is to implement proposal 219 or something like it. Fixes bug 10268; bugfix on 0.2.0.1-alpha. Based on a patch from "epoch".
-rw-r--r--changes/bug102686
-rw-r--r--src/or/dnsserv.c29
2 files changed, 25 insertions, 10 deletions
diff --git a/changes/bug10268 b/changes/bug10268
new file mode 100644
index 000000000..3035e7636
--- /dev/null
+++ b/changes/bug10268
@@ -0,0 +1,6 @@
+ o Minor bugfixes:
+ - When receing a DNS query for an unsupported type, reply with
+ no answer rather than with a NOTIMPL error. This behavior isn't
+ correct either, but it will break fewer client programs, we hope.
+ Fixes bug 10268; bugfix on 0.2.0.1-alpha. Original patch
+ from "epoch".
diff --git a/src/or/dnsserv.c b/src/or/dnsserv.c
index 4190e9cc2..ecd45be77 100644
--- a/src/or/dnsserv.c
+++ b/src/or/dnsserv.c
@@ -35,7 +35,7 @@ evdns_server_callback(struct evdns_server_request *req, void *data_)
entry_connection_t *entry_conn;
edge_connection_t *conn;
int i = 0;
- struct evdns_server_question *q = NULL;
+ struct evdns_server_question *q = NULL, *supported_q = NULL;
struct sockaddr_storage addr;
struct sockaddr *sa;
int addrlen;
@@ -87,31 +87,37 @@ evdns_server_callback(struct evdns_server_request *req, void *data_)
for (i = 0; i < req->nquestions; ++i) {
if (req->questions[i]->dns_question_class != EVDNS_CLASS_INET)
continue;
+ if (! q)
+ q = req->questions[i];
switch (req->questions[i]->type) {
case EVDNS_TYPE_A:
case EVDNS_TYPE_AAAA:
case EVDNS_TYPE_PTR:
- q = req->questions[i];
+ /* We always pick the first one of these questions, if there is
+ one. */
+ if (! supported_q)
+ supported_q = q;
+ break;
default:
break;
}
}
+ if (supported_q)
+ q = supported_q;
if (!q) {
log_info(LD_APP, "None of the questions we got were ones we're willing "
"to support. Sending NOTIMPL.");
evdns_server_request_respond(req, DNS_ERR_NOTIMPL);
return;
}
- if (q->type != EVDNS_TYPE_A && q->type != EVDNS_TYPE_AAAA) {
- tor_assert(q->type == EVDNS_TYPE_PTR);
- }
/* Make sure the name isn't too long: This should be impossible, I think. */
if (err == DNS_ERR_NONE && strlen(q->name) > MAX_SOCKS_ADDR_LEN-1)
err = DNS_ERR_FORMAT;
- if (err != DNS_ERR_NONE) {
- /* We got an error? Then send back an answer immediately; we're done. */
+ if (err != DNS_ERR_NONE || !supported_q) {
+ /* We got an error? There's no question we're willing to answer? Then
+ * send back an answer immediately; we're done. */
evdns_server_request_respond(req, err);
return;
}
@@ -126,12 +132,15 @@ evdns_server_callback(struct evdns_server_request *req, void *data_)
TO_CONN(conn)->port = port;
TO_CONN(conn)->address = tor_dup_addr(&tor_addr);
- if (q->type == EVDNS_TYPE_A || q->type == EVDNS_TYPE_AAAA)
+ if (q->type == EVDNS_TYPE_A || q->type == EVDNS_TYPE_AAAA ||
+ q->type == EVDNS_QTYPE_ALL) {
entry_conn->socks_request->command = SOCKS_COMMAND_RESOLVE;
- else
+ } else {
+ tor_assert(q->type == EVDNS_TYPE_PTR);
entry_conn->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR;
+ }
- if (q->type == EVDNS_TYPE_A) {
+ if (q->type == EVDNS_TYPE_A || q->type == EVDNS_QTYPE_ALL) {
entry_conn->ipv4_traffic_ok = 1;
entry_conn->ipv6_traffic_ok = 0;
entry_conn->prefer_ipv6_traffic = 0;