251 lines
8.6 KiB
Python
Executable File
251 lines
8.6 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
import random # For simulation, not cryptography!
|
|
import math
|
|
import sys
|
|
import os
|
|
import logging
|
|
import resource
|
|
import sympy
|
|
import re
|
|
import statistics
|
|
|
|
sys.path.append("..")
|
|
|
|
import network
|
|
import dirauth
|
|
import relay
|
|
import client
|
|
|
|
from bwparser import JansenBandwidthParser, KomloBandwidthParser
|
|
|
|
class BandwidthMeasurer:
|
|
def __init__(self, total_numrelays, bw_parser, numdirauths, numrelays, numclients):
|
|
self.total_size = total_numrelays
|
|
self.bw_parser = bw_parser
|
|
|
|
# Start some dirauths
|
|
self.dirauthaddrs = []
|
|
self.dirauths = []
|
|
for i in range(numdirauths):
|
|
dira = dirauth.DirAuth(i, numdirauths)
|
|
self.dirauths.append(dira)
|
|
self.dirauthaddrs.append(dira.netaddr)
|
|
|
|
# Start some relays
|
|
self.relays = []
|
|
for i in range(numrelays):
|
|
self.startrelay()
|
|
|
|
# The fallback relays are a hardcoded list of a small fraction
|
|
# of the relays, used by clients for bootstrapping
|
|
numfallbackrelays = 1
|
|
fallbackrelays = self.relays[0:1]
|
|
for r in fallbackrelays:
|
|
r.set_is_fallbackrelay()
|
|
network.thenetwork.setfallbackrelays(fallbackrelays)
|
|
|
|
# Tick the epoch to build the first consensus
|
|
network.thenetwork.nextepoch()
|
|
|
|
# Start some clients
|
|
self.clients = []
|
|
for i in range(numclients):
|
|
self.startclient()
|
|
|
|
# Throw away all the performance statistics to this point
|
|
for d in self.dirauths: d.perfstats.reset()
|
|
for r in self.relays: r.perfstats.reset()
|
|
# The clients' stats are already at 0, but they have the
|
|
# "bootstrapping" flag set, which we want to keep, so we
|
|
# won't reset them.
|
|
|
|
self.allcircs = []
|
|
|
|
# Tick the epoch to bootstrap the clients
|
|
network.thenetwork.nextepoch()
|
|
|
|
def startrelay(self):
|
|
bw = int(self.calculate_relay_bandwidth())
|
|
new_relay = relay.Relay(self.dirauthaddrs, bw, 0)
|
|
self.relays.append(new_relay)
|
|
|
|
def calculate_relay_bandwidth(self):
|
|
return random.choice(bw_parser.get_distribution())
|
|
|
|
def stoprelay(self):
|
|
self.relays[1].terminate()
|
|
del self.relays[1]
|
|
|
|
def startclient(self):
|
|
self.clients.append(client.Client(self.dirauthaddrs))
|
|
|
|
def stopclient(self):
|
|
self.clients[0].terminate()
|
|
del self.clients[0]
|
|
|
|
def buildcircuit(self):
|
|
bwm.allcircs.append(bwm.clients[0].channelmgr.new_circuit())
|
|
|
|
def getstats(self):
|
|
|
|
# gather stats
|
|
totsent = 0
|
|
totrecv = 0
|
|
totbytes = 0
|
|
dirasent = 0
|
|
dirarecv = 0
|
|
dirabytes = 0
|
|
relaysent = 0
|
|
relayrecv = 0
|
|
relaybytes = 0
|
|
clisent = 0
|
|
clirecv = 0
|
|
clibytes = 0
|
|
for d in self.dirauths:
|
|
logging.debug("%s", d.perfstats)
|
|
dirasent += d.perfstats.bytes_sent
|
|
dirarecv += d.perfstats.bytes_received
|
|
dirabytes += d.perfstats.bytes_sent + d.perfstats.bytes_received
|
|
totsent += dirasent
|
|
totrecv += dirarecv
|
|
totbytes += dirabytes
|
|
for r in self.relays:
|
|
logging.debug("%s", r.perfstats)
|
|
relaysent += r.perfstats.bytes_sent
|
|
relayrecv += r.perfstats.bytes_received
|
|
relaybytes += r.perfstats.bytes_sent + r.perfstats.bytes_received
|
|
totsent += relaysent
|
|
totrecv += relayrecv
|
|
totbytes += relaybytes
|
|
for c in self.clients:
|
|
logging.debug("%s", c.perfstats)
|
|
clisent += c.perfstats.bytes_sent
|
|
clirecv += c.perfstats.bytes_received
|
|
clibytes += c.perfstats.bytes_sent + c.perfstats.bytes_received
|
|
totsent += clisent
|
|
totrecv += clirecv
|
|
totbytes += clibytes
|
|
logging.info("DirAuths sent=%s recv=%s bytes=%s" % \
|
|
(dirasent, dirarecv, dirabytes))
|
|
logging.info("Relays sent=%s recv=%s bytes=%s" % \
|
|
(relaysent, relayrecv, relaybytes))
|
|
logging.info("Client sent=%s recv=%s bytes=%s" % \
|
|
(clisent, clirecv, clibytes))
|
|
logging.info("Total sent=%s recv=%s bytes=%s" % \
|
|
(totsent, totrecv, totbytes))
|
|
|
|
# Reset bootstrap flag
|
|
for d in self.dirauths: d.perfstats.is_bootstrapping = False
|
|
for r in self.relays: r.perfstats.is_bootstrapping = False
|
|
for c in self.clients: c.perfstats.is_bootstrapping = False
|
|
|
|
return (dirabytes, relaybytes, clibytes)
|
|
|
|
def endepoch(self):
|
|
|
|
# Close circuits
|
|
for c in self.allcircs:
|
|
c.close()
|
|
self.allcircs = []
|
|
|
|
# Reset stats
|
|
for d in self.dirauths: d.perfstats.reset()
|
|
for r in self.relays: r.perfstats.reset()
|
|
for c in self.clients: c.perfstats.reset()
|
|
|
|
network.thenetwork.nextepoch()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
# Args: womode snipauthmode numrelays randseed
|
|
if len(sys.argv) != 5:
|
|
sys.stderr.write("Usage: womode snipauthmode numrelays randseed\n")
|
|
sys.exit(1)
|
|
|
|
bandwidth_file = os.getenv('BW_FILE')
|
|
|
|
womode = network.WOMode[sys.argv[1].upper()]
|
|
snipauthmode = network.SNIPAuthMode[sys.argv[2].upper()]
|
|
numrelays = int(sys.argv[3])
|
|
randseed = int(sys.argv[4])
|
|
|
|
bw_parser = None
|
|
if os.getenv('BW_ALGO') != "komlo":
|
|
bw_parser = JansenBandwidthParser(bw_file=bandwidth_file, sample_size=numrelays)
|
|
else:
|
|
# keep the original assumption
|
|
bw_parser = KomloBandwidthParser(sample_size=numrelays)
|
|
|
|
total_size = bw_parser.get_relay_num()
|
|
|
|
# Use symbolic byte counter mode
|
|
network.symbolic_byte_counters = True
|
|
|
|
# Seed the PRNG. On Ubuntu 18.04, this in fact makes future calls
|
|
# to (non-cryptographic) random numbers deterministic. On Ubuntu
|
|
# 16.04, it does not.
|
|
random.seed(randseed)
|
|
|
|
loglevel = logging.INFO
|
|
# Uncomment to see all the debug messages
|
|
# loglevel = logging.DEBUG
|
|
|
|
logging.basicConfig(level=loglevel,
|
|
format="%(asctime)s:%(levelname)s:%(message)s")
|
|
|
|
logging.info("Starting simulation")
|
|
|
|
# Set the Walking Onions style to use
|
|
network.thenetwork.set_wo_style(womode, snipauthmode)
|
|
|
|
bwm = BandwidthMeasurer(total_size, bw_parser, 9, numrelays, 0)
|
|
stats = dict()
|
|
|
|
logging.info("R_N = %d, R_B = 0, C_N = 0, C_B = 0, circs = 0", numrelays)
|
|
stats[(numrelays, 0, 0, 0, 0)] = bwm.getstats()
|
|
# Bootstrap one relay
|
|
bwm.startrelay()
|
|
bwm.endepoch()
|
|
logging.info("R_N = %d, R_B = 1, C_N = 0, C_B = 0, circs = 0", numrelays)
|
|
stats[(numrelays, 1, 0, 0, 0)] = bwm.getstats()
|
|
# Bootstrap one client
|
|
bwm.stoprelay()
|
|
bwm.startclient()
|
|
bwm.endepoch()
|
|
logging.info("R_N = %d, R_B = 0, C_N = 0, C_B = 1, circs = 0", numrelays)
|
|
stats[(numrelays, 0, 0, 1, 0)] = bwm.getstats()
|
|
# No changes, so the client is now not bootstrapping
|
|
bwm.endepoch()
|
|
logging.info("R_N = %d, R_B = 0, C_N = 1, C_B = 0, circs = 0", numrelays)
|
|
stats[(numrelays, 0, 1, 0, 0)] = bwm.getstats()
|
|
# No more bootstrapping, but build one circuit
|
|
bwm.buildcircuit()
|
|
logging.info("R_N = %d, R_B = 0, C_N = 1, C_B = 0, circs = 1", numrelays)
|
|
stats[(numrelays, 0, 1, 0, 1)] = bwm.getstats()
|
|
bwm.endepoch()
|
|
# No more bootstrapping, but build two circuits
|
|
bwm.buildcircuit()
|
|
bwm.buildcircuit()
|
|
logging.info("R_N = %d, R_B = 0, C_N = 1, C_B = 0, circs = 2", numrelays)
|
|
stats[(numrelays, 0, 1, 0, 2)] = bwm.getstats()
|
|
bwm.endepoch()
|
|
|
|
print("\n")
|
|
print('Total relay bytes:')
|
|
print(' R_N * (', stats[(numrelays, 0, 0, 0, 0)][1]/numrelays, ')')
|
|
print('+ R_B * (', stats[(numrelays, 1, 0, 0, 0)][1] - stats[(numrelays, 0, 0, 0, 0)][1], ')')
|
|
print('+ C_N * (', stats[(numrelays, 0, 1, 0, 0)][1] - stats[(numrelays, 0, 0, 0, 0)][1], ')')
|
|
print('+ C_B * (', stats[(numrelays, 0, 0, 1, 0)][1] - stats[(numrelays, 0, 0, 0, 0)][1], ')')
|
|
print('+ circ * (', stats[(numrelays, 0, 1, 0, 1)][1] - stats[(numrelays, 0, 1, 0, 0)][1], ')')
|
|
print(' check ', stats[(numrelays, 0, 1, 0, 2)][1] - stats[(numrelays, 0, 1, 0, 1)][1])
|
|
|
|
print("\n")
|
|
print('Total client bytes:')
|
|
print(' R_N * (', stats[(numrelays, 0, 0, 0, 0)][2]/numrelays, ')')
|
|
print('+ R_B * (', stats[(numrelays, 1, 0, 0, 0)][2] - stats[(numrelays, 0, 0, 0, 0)][2], ')')
|
|
print('+ C_N * (', stats[(numrelays, 0, 1, 0, 0)][2] - stats[(numrelays, 0, 0, 0, 0)][2], ')')
|
|
print('+ C_B * (', stats[(numrelays, 0, 0, 1, 0)][2] - stats[(numrelays, 0, 0, 0, 0)][2], ')')
|
|
print('+ circ * (', stats[(numrelays, 0, 1, 0, 1)][2] - stats[(numrelays, 0, 1, 0, 0)][2], ')')
|
|
print(' check ', stats[(numrelays, 0, 1, 0, 2)][2] - stats[(numrelays, 0, 1, 0, 1)][2])
|