1
0
walkingonions-boosted/analysis/bytecounts.py

251 lines
8.6 KiB
Python
Raw Normal View History

2022-03-17 16:05:34 +00:00
#!/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])