Hi,
I decided to give it a shot in implementing full DNS/DNSSEC resolution support for Tor, here's the branch:
ATM the biggest limitation is that reply DNS packet must fit in a single cell (i.e. max size is RELAY_PAYLOAD_SIZE).
How it's implemented:
There's new command SOCKS_COMMAND_RESOLVE_FULL for SOCKS interface and new cells RELAY_COMMAND_RESOLVE(D)_FULL. The RESOLVE_FULL cell contains query string and RR-type, RESOLVED_FULL just the DNS packet in wire format.
Resolving is implemented via libunbound on the relay's side, ldns parses packet on client's side.
The tor-resolve now uses the new SOCKS command and accepts -t parameter with RR-type (numeric, default 1 - RR-type 'A'), e.g.:
./src/tools/tor-resolve -t 28 lupa.cz localhost:10050
Packet size: 319 Flags: qr: 1, aa: 0, tc: 0, rd: 1, cd: 0, ra: 1, ad: 1 -- Rcode: NOERROR -- Opcode: QUERY -- Question section lupa.cz. IN AAAA -- Answer section lupa.cz. 600 IN AAAA 2001:67c:68::7b lupa.cz. 600 IN RRSIG AAAA 5 2 600 20121022235305 20111023235305 8130 lupa.cz. wFdVqKCEh4Nmac3v5K9y6HT+aIBAtF4Q9QIqHjlAl/ljp4m5TKkgKCF083zFTMh0LqfwdODfQdSNTKAwO55hyw== -- Authority section lupa.cz. 600 IN NS ns.iinfo.cz. lupa.cz. 600 IN NS ns6.adminit.cz. lupa.cz. 600 IN RRSIG NS 5 2 600 20121022235305 20111023235305 8130 lupa.cz. SpqkpBlK1dzrfACHh3yfUp01Vr/w9qzVYQms4RDXNQZW1Hwr5WYMHIuGrFEgOOrjyg1vB01HENXJf4i2ISx51g== -- Additional section
Other implementation notes: - some checks like whether private address is resolved are missing (also a whitelist of allowed RR-types might be implemented) - in the SOCKS5 request, RR-type is hacked onto port number - in SOCKS5 reply, high byte of length is hacked onto SOCKS5 reserved byte - libunbound supports async resolving, for now synchronous is used - there are more details, grep FIXDNS in code - Makefile.am's have -lldns and -lunbound hardwired - new code may not be pretty at some places (getting to know Tor code)
Also, this seems to be a bug in relay.c:connection_edge_process_relay_cell_not_open(), the RELAY_COMMAND_RESOLVED case:
answer_len = cell->payload[RELAY_HEADER_SIZE+1]; if (rh->length < 2 || answer_len+2>rh->length) {...}
Payload is accessed before checking bounds.
Ondrej
On Thu, Jan 26, 2012 at 10:42:53PM +0100, Ondrej Mikle wrote:
I decided to give it a shot in implementing full DNS/DNSSEC resolution support for Tor, here's the branch:
ATM the biggest limitation is that reply DNS packet must fit in a single cell (i.e. max size is RELAY_PAYLOAD_SIZE).
Hi Ondrej,
Neat stuff! It's always nice to see people show up with patches.
So it looks like Tor would get two new libraries linked in, and exit relays would inherit whatever security/stability issues libunbound has since clients can basically hand them packets that they have to parse and deal with.
How to handle more of the dns protocol has always been a messy design question for Tor. More people are getting interested in it as we add more ipv6 support.
The previous hack recommendation had been for the client to use ttdnsd to run dns queries as normal Tor TCP flows: https://gitweb.torproject.org/ioerror/ttdnsd.git https://gitweb.torproject.org/ioerror/ttdnsd.git/blob_plain/HEAD:/README.Tor... which resolves the "what about answers bigger than Tor's cell size" question, as well as the "are we really sure we want a whole dns server implementation inside Tor" question, but leaves such niggling issues as "so do you direct the streams to 8.8.8.8, or what?" It also has the advantage that 8.8.8.8 runs a single known version of its nameserver, rather than a collection of exit relays that each offer whichever version they linked.
What do you think about the tradeoffs here? I'd like Tor to support more of dns, but I also think it's important to avoid needing exit relays to know all the details.
--Roger
On 01/30/2012 07:34 AM, Roger Dingledine wrote:
On Thu, Jan 26, 2012 at 10:42:53PM +0100, Ondrej Mikle wrote:
I decided to give it a shot in implementing full DNS/DNSSEC resolution support for Tor, here's the branch:
So it looks like Tor would get two new libraries linked in, and exit relays would inherit whatever security/stability issues libunbound has since clients can basically hand them packets that they have to parse and deal with.
In my implementation, client sends only query string and RR-type (16-bit integer), relay builds the actual query packet. Thus no "funny multiple queries", leaking of transaction IDs or other corner cases. Flags are set to "default recursive query" when relay makes the query (if anyone wants to e.g. query an authoritative server directly, he needs to make a "normal" TCP connection over Tor). Note that libunbound links with ldns itself.
I understand your concern about adding additional binary dependencies. I can try fuzzing libunbound and ldns - I've found some issues in Knot DNS server this way. It's no model-checking, but it has the capacity to unveil weird bugs. (So far I've "bent" libunbound quite hard while using in various tools and from experience I can say it's pretty solid - not a single segfault or abort due to memory corruption.)
The previous hack recommendation had been for the client to use ttdnsd to run dns queries as normal Tor TCP flows: https://gitweb.torproject.org/ioerror/ttdnsd.git https://gitweb.torproject.org/ioerror/ttdnsd.git/blob_plain/HEAD:/README.Tor... which resolves the "what about answers bigger than Tor's cell size" question, as well as the "are we really sure we want a whole dns server implementation inside Tor" question, but leaves such niggling issues as "so do you direct the streams to 8.8.8.8, or what?" It also has the advantage that 8.8.8.8 runs a single known version of its nameserver, rather than a collection of exit relays that each offer whichever version they linked.
There are few open recursive DNS (also validating) resolvers besides Google's I know of:
149.20.64.20 (DNS-OARC) 217.31.204.130 (CZ.NIC - my employer, just saying to get conflict-of-interest out of the way)
Concerning Google's resolvers: I am pretty sure that there are many machines running different software "hidden" behind a load-balancer of 8.8.8.8 and 8.8.4.4 IPs. While I was testing DNSSEC over Tor with unbound+socat, sometimes validation worked and sometimes it didn't.
What do you think about the tradeoffs here? I'd like Tor to support more of dns, but I also think it's important to avoid needing exit relays to know all the details.
Short answer: at this point, I'd go for libunbound (seems good enough for the job).
Long answer: we need to gather all the requirements. The "Tor and DNS" thread raised some important points, like masking client's transaction IDs. (lib)unbound should employ randomized IDs (in my proto-design I accidentally side-stepped the issue ;-) )
I looked at the proposals in torspec, references to DNS were mostly related to IPv6. I can write new spec for DNS resolution, and also fix/rewrite the PoC code to use begin_dns so that we can have responses longer than cell size.
Little over-engineering: Having unbound server running accessible as exit-enclave in chroot on relay (with PIE, grsecurity/SELinux/AppArmor or other hardening) would be really nice, but it would also be a major pain for operators.
Ondrej
On Mon, Jan 30, 2012 at 1:34 AM, Roger Dingledine arma@mit.edu wrote:
So it looks like Tor would get two new libraries linked in, and exit relays would inherit whatever security/stability issues libunbound has since clients can basically hand them packets that they have to parse and deal with.
FWIW, I'm okay thinking about adding new library dependencies so long as the libraries are portable enough; libunbound and ldns have a reasonably good reputation. (And our friends at NLnet labs probably wouldn't mind another bunch of users.)
I believe that as we add dnssec support, we are going to cross the threshold of stuff we'd be willing to clone ourselves, since writing our own dnssec code would be absurd.
On Tue, Jan 31, 2012 at 10:04:21AM -0500, Nick Mathewson wrote:
On Mon, Jan 30, 2012 at 1:34 AM, Roger Dingledine arma@mit.edu wrote:
So it looks like Tor would get two new libraries linked in, and exit relays would inherit whatever security/stability issues libunbound has since clients can basically hand them packets that they have to parse and deal with.
FWIW, I'm okay thinking about adding new library dependencies so long as the libraries are portable enough; libunbound and ldns have a reasonably good reputation. (And our friends at NLnet labs probably wouldn't mind another bunch of users.)
I believe that as we add dnssec support, we are going to cross the threshold of stuff we'd be willing to clone ourselves, since writing our own dnssec code would be absurd.
I totally agree that writing our own dnssec code would be absurd.
But I'm confused here about why we're adding dns support to Tor itself. Are we doing it to be able to proxy more requests from applications to dns servers? Or are we doing it because the Tor client itself wants to be able to learn the answers to dnssec questions?
If it's the former, then we should try as much as we can to *not* learn the details of the protocol. After all, Tor doesn't have an ssh protocol parser or validator, but it can proxy ssh traffic just fine.
--Roger
On Tue, Jan 31, 2012 at 3:35 PM, Roger Dingledine arma@mit.edu wrote:
On Tue, Jan 31, 2012 at 10:04:21AM -0500, Nick Mathewson wrote:
On Mon, Jan 30, 2012 at 1:34 AM, Roger Dingledine arma@mit.edu wrote:
So it looks like Tor would get two new libraries linked in, and exit relays would inherit whatever security/stability issues libunbound has since clients can basically hand them packets that they have to parse and deal with.
FWIW, I'm okay thinking about adding new library dependencies so long as the libraries are portable enough; libunbound and ldns have a reasonably good reputation. (And our friends at NLnet labs probably wouldn't mind another bunch of users.)
I believe that as we add dnssec support, we are going to cross the threshold of stuff we'd be willing to clone ourselves, since writing our own dnssec code would be absurd.
I totally agree that writing our own dnssec code would be absurd.
But I'm confused here about why we're adding dns support to Tor itself. Are we doing it to be able to proxy more requests from applications to dns servers? Or are we doing it because the Tor client itself wants to be able to learn the answers to dnssec questions?
If it's the former, then we should try as much as we can to *not* learn the details of the protocol. After all, Tor doesn't have an ssh protocol parser or validator, but it can proxy ssh traffic just fine.
I guess it depends on what you think should happen for SOCKS+hostname connections.
One possibility is this:
Browser -> Tor Client: "SOCKS5: Connect to www.example.com,port 80" Tor client -> Tor net -> Exit node: "BEGIN+: Connect to www.example.com, port 80, and answer the following DNS questions about it." Exit node -> Tor net-> Tor Client: "CONNECTED+: Connection is open. Here's a bunch of DNS replies for you." Tor Client -> Browser: "SOCKS5 connection complete."
But that would require that Tor recognize DNSSEC traffic.
Another possibility is this:
Browser's resolver -> Tor Client (as DNSPort): "Resolve www.example.com, give me an A, and give me DNSSec stuff too." Tor Client-> Tor net-> Tor Exit: "Yeah, resolve that stuff." Tor Exit -> Tor net -> Tor client: "Here's your answer." Tor client -> Browser's resolver: "Here's that A record you wanted, and some dnssec stuff." Browser -> Tor client: "Okay, now connect there." Tor client -> Tor net -> Tor exit: "Connect to <ip address>:80!" Exit node -> Tor net-> Tor Client: "CONNECTED: Connection is open." Tor Client -> Browser: "SOCKS5 connection complete."
But that would involve an extra round trip that I'd rather save if possible.
On Tue, Jan 31, 2012 at 2:57 PM, Nick Mathewson nickm@alum.mit.edu wrote:
On Tue, Jan 31, 2012 at 3:35 PM, Roger Dingledine arma@mit.edu wrote:
On Tue, Jan 31, 2012 at 10:04:21AM -0500, Nick Mathewson wrote:
On Mon, Jan 30, 2012 at 1:34 AM, Roger Dingledine arma@mit.edu wrote:
So it looks like Tor would get two new libraries linked in, and exit relays would inherit whatever security/stability issues libunbound has since clients can basically hand them packets that they have to parse and deal with.
FWIW, I'm okay thinking about adding new library dependencies so long as the libraries are portable enough; libunbound and ldns have a reasonably good reputation. (And our friends at NLnet labs probably wouldn't mind another bunch of users.)
I believe that as we add dnssec support, we are going to cross the threshold of stuff we'd be willing to clone ourselves, since writing our own dnssec code would be absurd.
I totally agree that writing our own dnssec code would be absurd.
But I'm confused here about why we're adding dns support to Tor itself. Are we doing it to be able to proxy more requests from applications to dns servers? Or are we doing it because the Tor client itself wants to be able to learn the answers to dnssec questions?
If it's the former, then we should try as much as we can to *not* learn the details of the protocol. After all, Tor doesn't have an ssh protocol parser or validator, but it can proxy ssh traffic just fine.
I guess it depends on what you think should happen for SOCKS+hostname connections.
One possibility is this:
Browser -> Tor Client: "SOCKS5: Connect to www.example.com,port 80" Tor client -> Tor net -> Exit node: "BEGIN+: Connect to www.example.com, port 80, and answer the following DNS questions about it." Exit node -> Tor net-> Tor Client: "CONNECTED+: Connection is open. Here's a bunch of DNS replies for you." Tor Client -> Browser: "SOCKS5 connection complete."
This would also break things like DNSSEC certificate stapling without some hackery or standards.
But that would require that Tor recognize DNSSEC traffic.
Another possibility is this:
Browser's resolver -> Tor Client (as DNSPort): "Resolve www.example.com, give me an A, and give me DNSSec stuff too." Tor Client-> Tor net-> Tor Exit: "Yeah, resolve that stuff." Tor Exit -> Tor net -> Tor client: "Here's your answer." Tor client -> Browser's resolver: "Here's that A record you wanted, and some dnssec stuff." Browser -> Tor client: "Okay, now connect there." Tor client -> Tor net -> Tor exit: "Connect to <ip address>:80!" Exit node -> Tor net-> Tor Client: "CONNECTED: Connection is open." Tor Client -> Browser: "SOCKS5 connection complete."
But that would involve an extra round trip that I'd rather save if possible.
We could cross our fingers and be optimistic, opening a connection to the server queried. Probably a bad idea.
-- Nick _______________________________________________ tor-dev mailing list tor-dev@lists.torproject.org https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-dev
On Feb 1, 2012, at 2:48 AM, Watson Ladd wrote:
On Tue, Jan 31, 2012 at 2:57 PM, Nick Mathewson nickm@alum.mit.edu wrote:
Another possibility is this:
Browser's resolver -> Tor Client (as DNSPort): "Resolve www.example.com, give me an A, and give me DNSSec stuff too." Tor Client-> Tor net-> Tor Exit: "Yeah, resolve that stuff." Tor Exit -> Tor net -> Tor client: "Here's your answer." Tor client -> Browser's resolver: "Here's that A record you wanted, and some dnssec stuff." Browser -> Tor client: "Okay, now connect there." Tor client -> Tor net -> Tor exit: "Connect to <ip address>:80!" Exit node -> Tor net-> Tor Client: "CONNECTED: Connection is open." Tor Client -> Browser: "SOCKS5 connection complete."
But that would involve an extra round trip that I'd rather save if possible.
We could cross our fingers and be optimistic, opening a connection to the server queried. Probably a bad idea.
I'm not sure, maybe the idea isn't so bad after all. If we wait for the client to tell us whether it likes the dnssec stuff, I could easily be convinced that this can be used to fingerprint clients. We have the TLS false start stuff which is kind of similar, I feel. Maybe that means for us to go ahead, make the connection, and if we as a client decide not to like it we just try again on a new exit node a couple of times?
On 01/31/2012 09:35 PM, Roger Dingledine wrote:
I totally agree that writing our own dnssec code would be absurd.
But I'm confused here about why we're adding dns support to Tor itself. Are we doing it to be able to proxy more requests from applications to dns servers? Or are we doing it because the Tor client itself wants to be able to learn the answers to dnssec questions?
If it's the former, then we should try as much as we can to *not* learn the details of the protocol. After all, Tor doesn't have an ssh protocol parser or validator, but it can proxy ssh traffic just fine.
This question comes up very often when dnssec is considered: where should it be implemented? At client program? A daemon in OS? A server on a network of an ISP? There is never an unanimous agreement, dnssec just seems to "not exactly fit anywhere" (it's not a transport protocol and it's not really an application protocol; it's just at the same level as DNS).
I thought a bit about (dis)advantages of each, some key points:
1. open DNS resolver listening on TCP somewhere
+ works with current Tor implementation - there is potential loss of anonymity - there are not many open resolvers and the issue with transaction IDs was already mentioned - bit worse performance (creating multiple connections when validating on client's side)
2. unbound running locally on OR (as exit-enclave)
+ requires only change in packaging - more code needs to be reviewed compared to libunbound (more code => higher chance of bug) - multiple connections when validating
3. libunbound in Tor
+ less code to review than complete unbound - implementation is more complex
Ondrej
On Thu, Jan 26, 2012 at 10:42:53PM +0100, Ondrej Mikle wrote:
Also, this seems to be a bug in relay.c:connection_edge_process_relay_cell_not_open(), the RELAY_COMMAND_RESOLVED case:
answer_len = cell->payload[RELAY_HEADER_SIZE+1]; if (rh->length < 2 || answer_len+2>rh->length) {...}
Payload is accessed before checking bounds.
cell->payload is a fixed-size array. It's going to be there no matter what values are in it.
Unless I'm misunderstanding you?
--Roger
On 01/30/2012 10:45 AM, Roger Dingledine wrote:
On Thu, Jan 26, 2012 at 10:42:53PM +0100, Ondrej Mikle wrote:
Also, this seems to be a bug in relay.c:connection_edge_process_relay_cell_not_open(), the RELAY_COMMAND_RESOLVED case:
answer_len = cell->payload[RELAY_HEADER_SIZE+1]; if (rh->length < 2 || answer_len+2>rh->length) {...}
Payload is accessed before checking bounds.
cell->payload is a fixed-size array. It's going to be there no matter what values are in it.
Unless I'm misunderstanding you?
You're right. For some reason I thought it was malloc-ed buffer, but it's not.
Ondrej
On Thu, Jan 26, 2012 at 3:42 PM, Ondrej Mikle ondrej.mikle@gmail.com wrote:
Hi,
I decided to give it a shot in implementing full DNS/DNSSEC resolution support for Tor, here's the branch:
ATM the biggest limitation is that reply DNS packet must fit in a single cell (i.e. max size is RELAY_PAYLOAD_SIZE).
How it's implemented:
There's new command SOCKS_COMMAND_RESOLVE_FULL for SOCKS interface and new cells RELAY_COMMAND_RESOLVE(D)_FULL. The RESOLVE_FULL cell contains query string and RR-type, RESOLVED_FULL just the DNS packet in wire format.
Resolving is implemented via libunbound on the relay's side, ldns parses packet on client's side.
The tor-resolve now uses the new SOCKS command and accepts -t parameter with RR-type (numeric, default 1 - RR-type 'A'), e.g.:
./src/tools/tor-resolve -t 28 lupa.cz localhost:10050
Packet size: 319 Flags: qr: 1, aa: 0, tc: 0, rd: 1, cd: 0, ra: 1, ad: 1 -- Rcode: NOERROR -- Opcode: QUERY -- Question section lupa.cz. IN AAAA -- Answer section lupa.cz. 600 IN AAAA 2001:67c:68::7b lupa.cz. 600 IN RRSIG AAAA 5 2 600 20121022235305 20111023235305 8130 lupa.cz. wFdVqKCEh4Nmac3v5K9y6HT+aIBAtF4Q9QIqHjlAl/ljp4m5TKkgKCF083zFTMh0LqfwdODfQdSNTKAwO55hyw== -- Authority section lupa.cz. 600 IN NS ns.iinfo.cz. lupa.cz. 600 IN NS ns6.adminit.cz. lupa.cz. 600 IN RRSIG NS 5 2 600 20121022235305 20111023235305 8130 lupa.cz. SpqkpBlK1dzrfACHh3yfUp01Vr/w9qzVYQms4RDXNQZW1Hwr5WYMHIuGrFEgOOrjyg1vB01HENXJf4i2ISx51g== -- Additional section
Other implementation notes:
- some checks like whether private address is resolved are missing (also a
whitelist of allowed RR-types might be implemented)
- in the SOCKS5 request, RR-type is hacked onto port number
- in SOCKS5 reply, high byte of length is hacked onto SOCKS5 reserved byte
- libunbound supports async resolving, for now synchronous is used
- there are more details, grep FIXDNS in code
- Makefile.am's have -lldns and -lunbound hardwired
- new code may not be pretty at some places (getting to know Tor code)
I've got a more basic question: does the OP get enough information to validate the DNSSEC data, or does it have to trust the OR? I don't quite know enough to tell from the above. Sincerely, Watson Ladd
On 01/31/2012 05:17 PM, Watson Ladd wrote:
I've got a more basic question: does the OP get enough information to validate the DNSSEC data, or does it have to trust the OR? I don't quite know enough to tell from the above.
I forgot to mention: validation on the client side is not finished in the PoC code. Both ldns and libunbound are capable of DNSSEC validation (libunbound has simpler API, thus lower chance in making mistakes).
Trust anchors (for root zone and maybe others) would be simply in the configuration file and distributed with Tor.
I don't know yet what the best API on the client side would be. For example, there's an evdns server code in connection_edge.c:connection_ap_handshake_socks_resolved() - the "if (ENTRY_TO_EDGE_CONN(conn)->is_dns_request)" branch. Is the evdns server actively used?
Ondrej