(Set to 0.2.5 so it will get properly triaged. Is there a component for "I haven't decided what milestone this should be", which won't get lost in a pile of tickets that nobody looks at?)
Well, the Exit flag and the short policy are both computed based on the original exit policy. So the authorities are sure doing something inconsistent.
Changing how short policy generation works would require a new consensus method, methinks. Changing the it works when we vote for the exit flag wouldn't.
Seems like the simple approach is to find the place in dirserv.c that assigns the exit flag, and find the place in policy_summarize() that decides that such relays summarize as reject :, and not give the Exit flag if the relay summarizes as reject :.
Maybe this is a fine introductory Tor ticket for TWN readers?
Maybe this is a fine introductory Tor ticket for TWN readers?
How about the following paragraph for TWN? (Feel free to tweak!)
Tor relays define an exit policy in the format "reject 0.0.0.0/8:*" thatsays which addresses and ports are accepted or rejected for outgoingconnections. The directory authorities summarize this exit policy intoa list of rejected or accepted ports, like "reject 1-65535", and theyassign the "Exit" flag if two ports out of 80, 443, 6667 are permittedfor "most" addresses. Apparently, there are edge cases when the summaryis "reject 1-65535" but the relay still gets the "Exit" flag, whichseems inconsistent. An easy fix would be to not assign the "Exit" flagin this specific case. Roger sketched out the relevant functions tolook at in the ticket (#12264). Ideally, this fix comes with a shortanalysis what the edge cases are and with a specification update. Thisis probably a one-line patch, the difficulty is just in finding outwhich line that is.
Actually, in this case the C documentation was wrong: according to the spec,
As an exception to this rule an allow-all policy is represented as "accept 1-65535" instead of "reject " and a reject-all policy is similarly given as "reject 1-65535".
So, I'm going to fix the comment in the C file (commit 0fc2d0edce72) and put this ticket back into "new" for a fix of the Exit flag issue.
Nick, I worry this patch changes the definition of "Exit" to be more complex (adding more edge cases, not decreasing them), without changing the documentation.
The directory specification defines the "Exit" flag as: 0
1614 "Exit" if the router is more useful for building1615 general-purpose exit circuits than for relay circuits.
This patch substantially changes the specification of the Exit flag from:
1845 "Exit" -- A router is called an 'Exit' iff it allows exits to at1846 least two of the ports 80, 443, and 6667 and allows exits to at1847 least one /8 address space.
To:
A router is called an 'Exit' iff it allows exits to at least two of the ports 80, 443, and 6667 and:
where the accept summary is shorter: there is at least one port that allows exits to the entire IPv4 or IPv6 address space; or,
where the reject summary is shorter: there is at least one port for which exits are not rejected to any non-private addresses (alternately, it is not the case that: every port is rejected to at least one non-private address); and allows exits to at least one /8 address space. (The /8 is not required in the "accept" case, because "entire address space" implies "at least one /8".)
(I think - it's hard to tell exactly how policy_summarize() and exit_policy_is_general_exit() interact.)
This change in Exit flag definition is caused by the patch depending on not only exit_policy_is_general_exit(), but the exact implementation of policy_summarize(), including the length comparison of accept and reject summaries, and the implementation of policy_summary_add_item():
Add a single exit policy item to our summary:If it is an accept ignore it unless it is for all IP addresses("*"), i.e. it's prefixlen/maskbits is 0, else callpolicy_summary_accept().If it's a reject ignore it if it is about one of the privatenetworks, else call policy_summary_reject().
This leaves a large number of corner cases where:
accept policies do not allow exiting to the entire address space; or
reject policies block all ports to parts of the address space (or, more precisely, block each port to at least one address); or
minor changes to policies flip the summary from accept to reject, causing instability;
and potentially other cases I haven't picked up on yet.
In short, these cases are where policy_is_reject_star() is not the same as policy_summarize() == "reject 1-65535".
I'd feel much more comfortable with some unit tests for these cases, to make sure we don't take away too many Exit flags with this change.
In particular, I'd like to compare the results of:
!exit_policy_is_general_exit()
policy_summarize() == "reject 1-65535"
policy_is_reject_star()
Ideally, we could do this for the entire consensus, and see how many Exits would be affected.
And, of course, there's an awful lot of doco that would need to change with it, both in code comments and the dirspec.
I think you're probably right; let's come up with a description of exactly what we'd like policy_summarize() and Exit to do, write a short proposal describing the exact behavior, and then implement it in a new consensus method.