better support for rapid onion cycling #1

Merged
sarah merged 1 commits from detports into master 2018-10-09 21:36:52 +00:00
Owner

this PR does two things: (1) detaches created onion services from the control port so that the circuits to the introduction points are cached, and (2) checks the revision counter on older versions of tor to see if it has been successfully updated or not. these changes combined greatly reduce the flakiness of cwtch onion service connections, especially for apps that restart frequently, and prevent a state where the app thinks it's hosting an onion but actually is not.

this PR requires changes to several interfaces, and thus has corresponding "detports" PRs in libricochet-go and asaur as well. this description applies to all of them collectively.

note that checking the revision counter on live HSDirs takes a little while, so I've added a flag to NewOnion() to disable the checking if you so desire. do this at your own risk, as it introduces the risk of a silent bug that prevents your onion from being available to the world

=== detach onion services ===

problem: currently, ADD_ONION does not use the "Detach" flag, and thus the onion service goes away when the invoking process closes. this means every time a service is re-created it runs ADD_ONION again, with all the performance hits this entails (choosing and connecting to new introduction points, publishing new descriptors to HSDirs, etc). it also makes the bug described below occur more often.

solution: add the Detach flag so the onion service stays up as long as the tor process does. attempting to re-create it later will silently fail. this does mean we're not updating the local (real) port number anymore, so we need to either (a) cache the random port we generated last time, (b) pick a static port for all cwtch applications to share, or (c) deterministically generate a unique port for each onion address. i went with (c) as it means we don't need to cache things ourselves and it allows multiple cwtch apps to run on the same machine.

a fun consequence of deterministically generating port numbers from the .onion is that you can use a vanity address generator to find a .onion that binds to a port of your choosing.

side effects:

  • some .onion addresses will run on a port that the local machine is already using for something longterm. this will result in errors being thrown immediately. the fix would be to generate a new onion address.
  • the onion service remains listening even after the invoking cwtch app has closed. if another process later comes along and binds to the same port, it will be available at the .onion address. this seems unlikely but there's not much we can do to prevent it.

=== check revision counter on HSDirs ===

problem: tor onion service descriptors published on HSDirs include a "revision counter", and HSDirs reject new descriptors that have a lower revision than their currently stored one. on tor < 0.3.5.1-alpha, the revision counter starts from 1 and is incremented each time ADD_ONION is called. this works fine unless the tor process is restarted (or you try to host the same onion on another machine/tor process), at which point the counter is reset and the new descriptors will fail to publish.

solution: the best solution for this is to upgrade to tor >= 0.3.5.1 (which at the time of writing is an alpha so you'll have to build 0.3.5.2 yourself, unfortunately). 0.3.5.1 introduces stateless revision counters: the revision counter for a new service descriptor is an order-preserving encryption of the seconds since the last SRV was issued, so descriptors created later always take precedence (assuming clocks are set approximately correctly). (nb: the OPE is to prevent leaking your clock skew by sending the elapsed time directly)

if you can't update tor, the only solution one you've gotten into the stale state is to invoke ADD_ONION over and over until tor's cached revision id caches up to what's live on the HSDirs. this thrashes your introduction circuits over and over, takes ages, and is generally a bad idea, but it works. i did not implement this. instead, iff the current tor version is old and we are creating the onion for the first time (not resuming, as described above) then asaur will now poll the HSDirs for the live revision and compare it against the local one. if a discrepancy is found, we know the onion service is dysfunctional and return an error (along with a friendly log message letting the dev know how many times they're going to have to rerun the app to fix it).

as a final note, HSFETCH does not support v3 onions (and that's ALL cwtch is supporting now) per https://trac.torproject.org/projects/tor/ticket/25417 so we have to make an actual connection attempt to ourselves in order to populate the local client cache with the live descriptor. i thought about submitting a patch for 25417, but the 0.3.5.1 changes fix this problem anyway so the workaround would be irrelevant. if anyone knows a way to cause an HSFETCH to happen without issuing a connection request to the .onion, please let me know! alternatively, we could write a custom HSFETCH routine to poll the HSDirs (but this would be a large-ish effort as it requires using blinded addresses). this workaround is slow and annoying and hence my inclusion of the new dontCheckDescriptor flag).

this PR does two things: (1) detaches created onion services from the control port so that the circuits to the introduction points are cached, and (2) checks the revision counter on older versions of tor to see if it has been successfully updated or not. these changes combined greatly reduce the flakiness of cwtch onion service connections, especially for apps that restart frequently, and prevent a state where the app thinks it's hosting an onion but actually is not. this PR requires changes to several interfaces, and thus has corresponding "detports" PRs in libricochet-go and asaur as well. this description applies to all of them collectively. note that checking the revision counter on live HSDirs takes a little while, so I've added a flag to NewOnion() to disable the checking if you so desire. do this at your own risk, as it introduces the risk of a silent bug that prevents your onion from being available to the world === detach onion services === problem: currently, ADD_ONION does not use the "Detach" flag, and thus the onion service goes away when the invoking process closes. this means every time a service is re-created it runs ADD_ONION again, with all the performance hits this entails (choosing and connecting to new introduction points, publishing new descriptors to HSDirs, etc). it also makes the bug described below occur more often. solution: add the Detach flag so the onion service stays up as long as the tor process does. attempting to re-create it later will silently fail. this does mean we're not updating the local (real) port number anymore, so we need to either (a) cache the random port we generated last time, (b) pick a static port for all cwtch applications to share, or (c) deterministically generate a unique port for each onion address. i went with (c) as it means we don't need to cache things ourselves and it allows multiple cwtch apps to run on the same machine. a fun consequence of deterministically generating port numbers from the .onion is that you can use a vanity address generator to find a .onion that binds to a port of your choosing. side effects: - some .onion addresses will run on a port that the local machine is already using for something longterm. this will result in errors being thrown immediately. the fix would be to generate a new onion address. - the onion service remains listening even after the invoking cwtch app has closed. if another process later comes along and binds to the same port, it will be available at the .onion address. this seems unlikely but there's not much we can do to prevent it. === check revision counter on HSDirs === problem: tor onion service descriptors published on HSDirs include a "revision counter", and HSDirs reject new descriptors that have a lower revision than their currently stored one. on tor < 0.3.5.1-alpha, the revision counter starts from 1 and is incremented each time ADD_ONION is called. this works fine unless the tor process is restarted (or you try to host the same onion on another machine/tor process), at which point the counter is reset and the new descriptors will fail to publish. solution: the best solution for this is to upgrade to tor >= 0.3.5.1 (which at the time of writing is an alpha so you'll have to build 0.3.5.2 yourself, unfortunately). 0.3.5.1 introduces stateless revision counters: the revision counter for a new service descriptor is an order-preserving encryption of the seconds since the last SRV was issued, so descriptors created later always take precedence (assuming clocks are set approximately correctly). (nb: the OPE is to prevent leaking your clock skew by sending the elapsed time directly) if you can't update tor, the only solution one you've gotten into the stale state is to invoke ADD_ONION over and over until tor's cached revision id caches up to what's live on the HSDirs. this thrashes your introduction circuits over and over, takes ages, and is generally a bad idea, but it works. i did not implement this. instead, iff the current tor version is old and we are creating the onion for the first time (not resuming, as described above) then asaur will now poll the HSDirs for the live revision and compare it against the local one. if a discrepancy is found, we know the onion service is dysfunctional and return an error (along with a friendly log message letting the dev know how many times they're going to have to rerun the app to fix it). as a final note, HSFETCH does not support v3 onions (and that's ALL cwtch is supporting now) per https://trac.torproject.org/projects/tor/ticket/25417 so we have to make an actual connection attempt to ourselves in order to populate the local client cache with the live descriptor. i thought about submitting a patch for 25417, but the 0.3.5.1 changes fix this problem anyway so the workaround would be irrelevant. if anyone knows a way to cause an HSFETCH to happen without issuing a connection request to the .onion, please let me know! alternatively, we could write a custom HSFETCH routine to poll the HSDirs (but this would be a large-ish effort as it requires using blinded addresses). this workaround is slow and annoying and hence my inclusion of the new dontCheckDescriptor flag).
sarah closed this pull request 2018-10-09 21:36:52 +00:00
This repo is archived. You cannot comment on pull requests.
No reviewers
No Label
No Milestone
No Assignees
1 Participants
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: openprivacy/asaur#1
No description provided.