1
0
Fork 0
walkingonions-boosted/msg.py

258 lines
7.9 KiB
Python

import pickle
import math
import network
# Set this to True if you want the bytes sent and received to be added
# symbolically, in terms of the numbers of each type of network message.
# You will need sympy installed for this to work.
symbolic_byte_counters = False
try:
import sympy
except:
pass
class NetMsg:
"""The parent class of network messages. Subclass this class to
implement specific kinds of network messages."""
def size(self):
"""Return the size of this network message. For now, just
pickle it and return the length of that. There's some
unnecessary overhead in this method; if you want specific
messages to have more accurate sizes, override this method in
the subclass. Alternately, if symbolic_byte_counters is set,
return a symbolic representation of the message size instead, so
that the total byte counts will clearly show how many of each
message type were sent and received."""
if symbolic_byte_counters:
sz = sympy.symbols(type(self).__name__)
else:
sz = len(pickle.dumps(self))
# logging.info("%s size %d", type(self).__name__, sz)
return sz
class StringNetMsg(NetMsg):
"""Send an arbitratry string as a NetMsg."""
def __init__(self, data):
self.data = data
def __str__(self):
return self.data.__str__()
#########################
# DIRAUTH
#########################
class DirAuthNetMsg(NetMsg):
"""The subclass of NetMsg for messages to and from directory
authorities."""
class DirAuthUploadDescMsg(DirAuthNetMsg):
"""The subclass of DirAuthNetMsg for uploading a relay
descriptor."""
def __init__(self, desc):
self.desc = desc
class DirAuthDelDescMsg(DirAuthNetMsg):
"""The subclass of DirAuthNetMsg for deleting a relay
descriptor."""
def __init__(self, desc):
self.desc = desc
class DirAuthGetConsensusMsg(DirAuthNetMsg):
"""The subclass of DirAuthNetMsg for fetching the consensus."""
class DirAuthConsensusMsg(DirAuthNetMsg):
"""The subclass of DirAuthNetMsg for returning the consensus."""
def __init__(self, consensus):
self.consensus = consensus
class DirAuthGetConsensusDiffMsg(DirAuthNetMsg):
"""The subclass of DirAuthNetMsg for fetching the consensus, if the
requestor already has the previous consensus."""
class DirAuthConsensusDiffMsg(DirAuthNetMsg):
"""The subclass of DirAuthNetMsg for returning the consensus, if the
requestor already has the previous consensus. We don't _actually_
produce the diff at this time; we just charge fewer bytes for this
message."""
def __init__(self, consensus):
self.consensus = consensus
def size(self):
if symbolic_byte_counters:
return super().size()
return math.ceil(DirAuthConsensusMsg(self.consensus).size() \
* network.P_Delta)
class DirAuthGetENDIVEMsg(DirAuthNetMsg):
"""The subclass of DirAuthNetMsg for fetching the ENDIVE."""
class DirAuthENDIVEMsg(DirAuthNetMsg):
"""The subclass of DirAuthNetMsg for returning the ENDIVE."""
def __init__(self, endive):
self.endive = endive
class DirAuthGetENDIVEDiffMsg(DirAuthNetMsg):
"""The subclass of DirAuthNetMsg for fetching the ENDIVE, if the
requestor already has the previous ENDIVE."""
class DirAuthENDIVEDiffMsg(DirAuthNetMsg):
"""The subclass of DirAuthNetMsg for returning the ENDIVE, if the
requestor already has the previous consensus. We don't _actually_
produce the diff at this time; we just charge fewer bytes for this
message in Merkle mode. In threshold signature mode, we would still
need to download at least the new signatures for every SNIP in the
ENDIVE, so for now, just assume there's no gain from ENDIVE diffs in
threshold signature mode."""
def __init__(self, endive):
self.endive = endive
def size(self):
if symbolic_byte_counters:
return super().size()
if network.thenetwork.snipauthmode == \
network.SNIPAuthMode.THRESHSIG:
return DirAuthENDIVEMsg(self.endive).size()
return math.ceil(DirAuthENDIVEMsg(self.endive).size() \
* network.P_Delta)
#########################
# RELAY
#########################
class RelayNetMsg(NetMsg):
"""The subclass of NetMsg for messages between relays and either
relays or clients."""
class RelayGetConsensusMsg(RelayNetMsg):
"""The subclass of RelayNetMsg for fetching the consensus. Sent by
clients to relays."""
class RelayConsensusMsg(RelayNetMsg):
"""The subclass of RelayNetMsg for returning the consensus from
relays to clients, in response to RelayGetConsensusMsg."""
def __init__(self, consensus):
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
relays."""
class RelayConsensusDiffMsg(RelayNetMsg):
"""The subclass of RelayNetMsg for returning the consensus, if the
requestor already has the previous consensus. We don't _actually_
produce the diff at this time; we just charge fewer bytes for this
message. Sent by relays to clients in response to
RelayGetConsensusDiffMsg."""
def __init__(self, consensus):
self.consensus = consensus
def size(self):
if symbolic_byte_counters:
return super().size()
return math.ceil(RelayConsensusMsg(self.consensus).size() \
* network.P_Delta)
class RelayRandomHopMsg(RelayNetMsg):
"""A message used for testing, that hops from relay to relay
randomly until its TTL expires."""
def __init__(self, ttl):
self.ttl = ttl
def __str__(self):
return "RandomHop TTL=%d" % self.ttl
class CircuitCellMsg(RelayNetMsg):
"""Send a message tagged with a circuit id. This is the container
class for all RelayCell messages."""
def __init__(self, circuitid, cell):
self.circid = circuitid
self.cell = cell
def __str__(self):
return "C%d:%s" % (self.circid, self.cell)
def size(self):
# circuitids are 4 bytes
return 4 + self.cell.size()
# It is intentional that VanillaCreateCircuitMsg is a RelayNetMsg and
# not a RelayCell. This is the message that _creates_ the circuit, so
# it can't be sent as a cell _within_ the circuit.
class VanillaCreateCircuitMsg(RelayNetMsg):
"""The message for requesting circuit creation in Vanilla Onion
Routing."""
def __init__(self, circid, ntor_request):
self.circid = circid
self.ntor_request = ntor_request
# It is intentional that TelescopingCreateCircuitMsg is a RelayNetMsg and
# not a RelayCell. This is the message that _creates_ the circuit, so
# it can't be sent as a cell _within_ the circuit.
class TelescopingCreateCircuitMsg(RelayNetMsg):
"""The message for requesting circuit creation in Telescoping Onion
Routing."""
def __init__(self, circid, ntor_request):
self.circid = circid
self.ntor_request = ntor_request
class SinglePassCreateCircuitMsg(RelayNetMsg):
"""The message for requesting circuit creation in Single Pass Onion
Routing. This is used to extend a Single-Pass circuit by clients."""
def __init__(self, circid, ntor_request, client_path_selection_key,
ttl=2):
self.circid = circid
self.ntor_request = ntor_request
self.clipathselkey = bytes(client_path_selection_key)
self.ttl = ttl