I have a hidden service, configured with
HiddenServicePort 6666 irc.oftc.net:6666
Now irc.oftc.net is a rotation that changes quite frequently and for that
reason the TTL of the A records it returns is only 60.
The problem is that Tor resolves the hostname only once, when it configures
the hidden service, not everytime a user establishes a new connection. This
causes problems since by the time a client request comes the information Tor
has often is long obsolete.
Please resolve it on connects, and don't cache it in a broken way (caching it
for TTL is fine).
Thanks
[Automatically added by flyspray2trac: Operating System: All]
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information
Child items ...
Show closed items
Linked items 0
Link issues together to show that they're related.
Learn more.
Dirty patch below resolves address every time it is requested. This could serve until a cleaner solution comes along.
This may even spoil the anonymity of the hidden service for all I know.
Index: src/or/rendservice.c===================================================================--- src/or/rendservice.c (revision 9613)+++ src/or/rendservice.c (working copy)@@ -20,7 +20,7 @@ typedef struct rend_service_port_config_t { uint16_t virtual_port; uint16_t real_port;- uint32_t real_addr;+ char *real_addr; } rend_service_port_config_t; /** Try to maintain this many intro points per service if possible. */@@ -113,7 +113,6 @@ { int i; rend_service_port_config_t *p;- struct in_addr addr; if (!service->intro_prefer_nodes) service->intro_prefer_nodes = tor_strdup("");@@ -129,16 +128,15 @@ log_debug(LD_REND,"Configuring service with directory "%s"", service->directory); for (i = 0; i < smartlist_len(service->ports); ++i) {- char addrbuf[INET_NTOA_BUF_LEN]; p = smartlist_get(service->ports, i);- addr.s_addr = htonl(p->real_addr);- tor_inet_ntoa(&addr, addrbuf, sizeof(addrbuf));- log_debug(LD_REND,"Service maps port %d to %s:%d",- p->virtual_port, addrbuf, p->real_port);+ log_debug(LD_REND,"Service maps port %d to %s",+ p->virtual_port, p->real_addr); } } }++ /** Parses a real-port to virtual-port mapping and returns a new * rend_service_port_config_t. *@@ -175,7 +173,7 @@ if (smartlist_len(sl) == 1) { /* No addr:port part; use default. */ realport = virtport;- addr = 0x7F000001u; /* 127.0.0.1 */+ addrport = tor_strdup("127.0.0.1"); /* 127.0.0.1 */ } else { addrport = smartlist_get(sl,1); if (strchr(addrport, ':') || strchr(addrport, '.')) {@@ -190,14 +188,14 @@ realport = atoi(addrport); if (realport < 1 || realport > 65535) goto err;- addr = 0x7F000001u; /* Default to 127.0.0.1 */+ addrport = tor_strdup("127.0.0.1"); /* 127.0.0.1 */ } } result = tor_malloc(sizeof(rend_service_port_config_t)); result->virtual_port = virtport; result->real_port = realport;- result->real_addr = addr;+ result->real_addr = tor_strdup(addrport); err: SMARTLIST_FOREACH(sl, char *, c, tor_free(c)); smartlist_free(sl);@@ -1157,6 +1155,8 @@ int i; rend_service_port_config_t *p; char serviceid[REND_SERVICE_ID_LEN+1];+ uint32_t addr;+ uint16_t port; tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_S_REND_JOINED); log_debug(LD_REND,"beginning to hunt for addr/port");@@ -1172,7 +1172,12 @@ for (i = 0; i < smartlist_len(service->ports); ++i) { p = smartlist_get(service->ports, i); if (conn->_base.port == p->virtual_port) {- conn->_base.addr = p->real_addr;+ addr = 0x7F000001u; /* Default to 127.0.0.1 */+ if (parse_addr_port(LOG_WARN, p->real_addr, NULL, &addr, &port)<0) {+ return -1;+ }++ conn->_base.addr = addr; conn->_base.port = p->real_port; return 0; }
There's a performance issue with the patch, and a couple of anonymity issues.
The performance issue is that parse_addr_port calls tor_lookup_hostname, which is blocking. If the nameserver is
slow, then the entire Tor process (not just the hidden service connection in question) blocks while the lookup is
happening.
There's an anonymity issue here in that a clever attacker could pretty easily use it to tell who else is connecting to
the same hidden service, by opening connections to cause gaps in their traffic. (This exists to a lesser extent with
bandwidth interference, but I believe the attack here is even easier.)
Another anonymity issue is that the nameserver learns every time somebody connects to the hidden service. Under some
circumstances, this could let the nameserver ID the hidden service.
I think I'd prefer an approach where instead of doing the resolve late, the hidden service could be configured
with a list of addresses. It could get these via DNS, or via the config file.
Tor getting them all from DNS and then updating them every TTL seconds would be
fine with me. Since most records out there have long TTLs that would be just fine
for those, and since my hostname has short TTLs that is good for me too. It's
probably way overkill in my case, because I have less than 30 connect per day,
but it's something I could live with.
You're right about the leak, sorry. Wouldn't observing the TTLs still endanger the service's anonymity though? Also,
if tor takes the 4 addresses currently reported as A records, wouldn't it take a while to give up on one before
trying the next? Hidden Service clients do take a good while before giving up on an address.
Sorry, the idea was for the hidden service to round-robin between its addresses. The client never knows how
many addresses the hidden server is using internally.
To implement this, you'd probably want to start with configuration support sans DNS: change real_addr and real_port
in struct rend_service_port_config_t so that they are instead a list of addr:port pairs; make it possible to set
these from the config file; and have rend_service_set_connection_addr_port pick one at random.
Next you'd want to expand tor_lookup_hostname so it can return multiple values if the underlying resolver supports it
and if the caller wants it.
Next you'd want to make this information propagate to parse_port_config somehow.
I don't mind the anonymity worry from an attacking nameserver. If
it wants to learn when somebody is hitting the hidden service, it
should give you an IP address it controls, and watch for the hit.
Robert has a good point that if we have a round-robin set and half
are down, then hidden services are going to suck even more; we
would want to remember which seem down and which don't, etc, and
that still doesn't entirely solve the problem.
This will get complex quickly. We should delay it til 0.2.0.x.
You don't have to solve all the things in one day. Tracking upness of hosts in a rotation
is really not required at this point. Just picking a random IP out of the many in DNS at
the point of connect is all that's needed to not suck.
It looks like multiple targets is easy, but mucking with the DNS code will be more involved than I'm
comfortable doing at this stage of the 0.1.2.x series (dns and config are "subtle and swift to anger,"
and I have a poor track record of messing with them successfully on my first attempt). Peter,
could you let me know if this patch makes stuff better for you? It lets you give multiple
HiddenServicePort directives with the same virtual port, and chooses randomly among them when you get
a connection.
=== src/or/rendservice.c==================================================================--- src/or/rendservice.c (revision 12009)+++ src/or/rendservice.c (local)@@ -1154,9 +1154,9 @@ origin_circuit_t *circ) { rend_service_t *service;- int i;- rend_service_port_config_t *p; char serviceid[REND_SERVICE_ID_LEN+1];+ smartlist_t *matching_ports;+ rend_service_port_config_t *chosen_port; tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_S_REND_JOINED); log_debug(LD_REND,"beginning to hunt for addr/port");@@ -1169,13 +1169,19 @@ serviceid, circ->_base.n_circ_id); return -1; }- for (i = 0; i < smartlist_len(service->ports); ++i) {- p = smartlist_get(service->ports, i);+ matching_ports = smartlist_create();+ SMARTLIST_FOREACH(service->ports, rend_service_port_config_t *, p,+ { if (conn->_base.port == p->virtual_port) {- conn->_base.addr = p->real_addr;- conn->_base.port = p->real_port;- return 0;+ smartlist_add(matching_ports, p); }+ });+ chosen_port = smartlist_choose(matching_ports);+ smartlist_free(matching_ports);+ if (chosen_port) {+ conn->_base.addr = chosen_port->real_addr;+ conn->_base.port = chosen_port->real_port;+ return 0; } log_info(LD_REND, "No virtual port mapping exists for port %d on service %s", conn->_base.port,serviceid);
Peter says that the above patch isn't good enough to meet his needs, so I'll instead mark this whole thing
as "post-0.1.2.x" and try to get to it soon in the 0.2.0.x series.
The "right" solution is probably some kind of hack in connection_exit_begin_conn() in the
circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED block. Right now, rend_service_set_connection_addr_port() just
replaces the addr and port fields of the connection, and returns -1 on error. It could become like dns_resolve,
and return a tristate of "I set the addr and port", "There's an error", and "I'm resolving the addr and port." The
rest of that block could move into a different function.
Doing resolves at connect-time rather than at runtime should probably be configurable, though.
Also, we should think about attacks where an adversary probes our DNS cache to see whether we're the ones who keep
resolving suspicious-server.com.
Trac: Parent: N/AtoN/A Keywords: N/Adeleted, hidden service, dns added Description: I have a hidden service, configured with
HiddenServicePort 6666 irc.oftc.net:6666
Now irc.oftc.net is a rotation that changes quite frequently and for that
reason the TTL of the A records it returns is only 60.
The problem is that Tor resolves the hostname only once, when it configures
the hidden service, not everytime a user establishes a new connection. This
causes problems since by the time a client request comes the information Tor
has often is long obsolete.
Please resolve it on connects, and don't cache it in a broken way (caching it
for TTL is fine).
Thanks
[Automatically added by flyspray2trac: Operating System: All]
to
I have a hidden service, configured with
HiddenServicePort 6666 irc.oftc.net:6666
Now irc.oftc.net is a rotation that changes quite frequently and for that
reason the TTL of the A records it returns is only 60.
The problem is that Tor resolves the hostname only once, when it configures
the hidden service, not everytime a user establishes a new connection. This
causes problems since by the time a client request comes the information Tor
has often is long obsolete.
Please resolve it on connects, and don't cache it in a broken way (caching it
for TTL is fine).
Thanks
[Automatically added by flyspray2trac: Operating System: All] Status: assigned to accepted Milestone: post 0.2.1.x to Tor: unspecified
Updating. To do the right solution here, we'd need to make it so that we use our existing evdns backend for asynchronous hostname lookups whenever we're also running about a hidden service. Then we could launch a lookup for the hidden service whenever we connected there.
On the other hand, we might want to make this feature RSOS-only, since doing hostname lookups in response to user requests for a hidden service seems like a good way to risk leaking.