|
@@ -71,6 +71,19 @@ class RelayConsensusMsg(RelayNetMsg):
|
|
|
self.consensus = consensus
|
|
|
|
|
|
|
|
|
+class RelayGetDescMsg(RelayNetMsg):
|
|
|
+ """The subclass of RelayNetMsg sent by clients to their guards for
|
|
|
+ retrieving the guard's current descriptor."""
|
|
|
+
|
|
|
+
|
|
|
+class RelayDescMsg(RelayNetMsg):
|
|
|
+ """The subclass of RelayNetMsg sent by guards to clients for
|
|
|
+ reporting their current descriptor."""
|
|
|
+
|
|
|
+ def __init__(self, desc):
|
|
|
+ self.desc = desc
|
|
|
+
|
|
|
+
|
|
|
class RelayGetConsensusDiffMsg(RelayNetMsg):
|
|
|
"""The subclass of RelayNetMsg for fetching the consensus, if the
|
|
|
requestor already has the previous consensus. Sent by clients to
|
|
@@ -886,15 +899,16 @@ class RelayChannelManager(ChannelManager):
|
|
|
"""The subclass of ChannelManager for relays."""
|
|
|
|
|
|
def __init__(self, myaddr, dirauthaddrs, onionprivkey, idpubkey,
|
|
|
- path_selection_key, perfstats):
|
|
|
+ desc_getter, path_selection_key_getter, perfstats):
|
|
|
super().__init__(myaddr, dirauthaddrs, perfstats)
|
|
|
self.onionkey = onionprivkey
|
|
|
self.idpubkey = idpubkey
|
|
|
if network.thenetwork.womode != network.WOMode.VANILLA:
|
|
|
self.endive = None
|
|
|
+ self.desc_getter = desc_getter
|
|
|
|
|
|
if network.thenetwork.womode == network.WOMode.SINGLEPASS:
|
|
|
- self.path_selection_key = path_selection_key
|
|
|
+ self.path_selection_key_getter = path_selection_key_getter
|
|
|
|
|
|
def get_consensus(self):
|
|
|
"""Download a fresh consensus (and ENDIVE if using Walking
|
|
@@ -938,6 +952,8 @@ class RelayChannelManager(ChannelManager):
|
|
|
self.send_msg(RelayConsensusMsg(self.consensus), peeraddr)
|
|
|
elif isinstance(msg, RelayGetConsensusDiffMsg):
|
|
|
self.send_msg(RelayConsensusDiffMsg(self.consensus), peeraddr)
|
|
|
+ elif isinstance(msg, RelayGetDescMsg):
|
|
|
+ self.send_msg(RelayDescMsg(self.desc_getter()), peeraddr)
|
|
|
elif isinstance(msg, VanillaCreateCircuitMsg):
|
|
|
# A new circuit has arrived
|
|
|
circhandler = channel.new_circuit_with_circid(msg.circid)
|
|
@@ -1021,11 +1037,12 @@ class RelayChannelManager(ChannelManager):
|
|
|
Sphinx.server(nacl.public.PublicKey(msg.clipathselkey),
|
|
|
self.onionkey, b'pathsel', False, self.perfstats)
|
|
|
|
|
|
+ pathselkey = self.path_selection_key_getter()
|
|
|
# Simulate the VRF output for now (but it has the right
|
|
|
# size, and charges the right number of group operations to
|
|
|
# the perfstats)
|
|
|
- vrf_output = VRF.get_output(self.path_selection_key,
|
|
|
- pathsel_rand, self.perfstats)
|
|
|
+ vrf_output = VRF.get_output(pathselkey, pathsel_rand,
|
|
|
+ self.perfstats)
|
|
|
|
|
|
index = int.from_bytes(vrf_output[0][:4], 'big', signed=False)
|
|
|
|
|
@@ -1096,16 +1113,22 @@ class Relay(network.Server):
|
|
|
network.thenetwork.wantepochticks(self, True, end=True)
|
|
|
network.thenetwork.wantepochticks(self, True)
|
|
|
|
|
|
+ self.current_desc = None
|
|
|
+ self.next_desc = None
|
|
|
+
|
|
|
# Create the path selection key for Single-Pass Walking Onions
|
|
|
if network.thenetwork.womode == network.WOMode.SINGLEPASS:
|
|
|
self.path_selection_key = nacl.public.PrivateKey.generate()
|
|
|
+ self.next_path_selection_key = self.path_selection_key
|
|
|
self.perfstats.keygens += 1
|
|
|
else:
|
|
|
self.path_selection_key = None
|
|
|
|
|
|
# Create the RelayChannelManager connection manager
|
|
|
self.channelmgr = RelayChannelManager(self.netaddr, dirauthaddrs,
|
|
|
- self.onionkey, self.idkey.verify_key, self.path_selection_key, self.perfstats)
|
|
|
+ self.onionkey, self.idkey.verify_key,
|
|
|
+ lambda: self.current_desc, lambda: self.path_selection_key,
|
|
|
+ self.perfstats)
|
|
|
|
|
|
# Initially, we're not a fallback relay
|
|
|
self.is_fallbackrelay = False
|
|
@@ -1146,8 +1169,11 @@ class Relay(network.Server):
|
|
|
def newepoch(self, epoch):
|
|
|
# Rotate the path selection key for Single-Pass Walking Onions
|
|
|
if network.thenetwork.womode == network.WOMode.SINGLEPASS:
|
|
|
- self.path_selection_key = nacl.public.PrivateKey.generate()
|
|
|
+ self.path_selection_key = self.next_path_selection_key
|
|
|
+ self.next_path_selection_key = nacl.public.PrivateKey.generate()
|
|
|
self.perfstats.keygens += 1
|
|
|
+ # Upload the descriptor for the *next* epoch (the one after the
|
|
|
+ # one that just started)
|
|
|
self.uploaddesc()
|
|
|
|
|
|
def uploaddesc(self, upload=True):
|
|
@@ -1162,11 +1188,14 @@ class Relay(network.Server):
|
|
|
descdict["flags"] = self.flags
|
|
|
|
|
|
if network.thenetwork.womode == network.WOMode.SINGLEPASS:
|
|
|
- descdict["pathselkey"] = bytes(self.path_selection_key)
|
|
|
+ descdict["pathselkey"] = \
|
|
|
+ bytes(self.next_path_selection_key.public_key)
|
|
|
|
|
|
desc = dirauth.RelayDescriptor(descdict)
|
|
|
desc.sign(self.idkey, self.perfstats)
|
|
|
dirauth.RelayDescriptor.verify(desc, self.perfstats)
|
|
|
+ self.current_desc = self.next_desc
|
|
|
+ self.next_desc = desc
|
|
|
|
|
|
if upload:
|
|
|
descmsg = dirauth.DirAuthUploadDescMsg(desc)
|