relay.py 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. #!/usr/bin/env python3
  2. import random # For simulation, not cryptography!
  3. import math
  4. import nacl.utils
  5. import nacl.signing
  6. import nacl.public
  7. import network
  8. import dirauth
  9. class Relay(network.Server):
  10. """The class representing an onion relay."""
  11. def __init__(self, dirauthaddrs, bw, flags):
  12. self.consensus = None
  13. self.dirauthaddrs = dirauthaddrs
  14. # Create the identity and onion keys
  15. self.idkey = nacl.signing.SigningKey.generate()
  16. self.onionkey = nacl.public.PrivateKey.generate()
  17. self.name = self.idkey.verify_key.encode(encoder=nacl.encoding.HexEncoder).decode("ascii")
  18. # Bind to the network to get a network address
  19. self.netaddr = network.thenetwork.bind(self)
  20. # Our bandwidth and flags
  21. self.bw = bw
  22. self.flags = flags
  23. # Register for epoch change notification
  24. network.thenetwork.wantepochticks(self, True, end=True)
  25. network.thenetwork.wantepochticks(self, True)
  26. self.uploaddesc()
  27. def epoch_ending(self, epoch):
  28. # Download the new consensus, which will have been created
  29. # already since the dirauths' epoch_ending callbacks happened
  30. # before the relays'.
  31. a = random.choice(self.dirauthaddrs)
  32. c = network.thenetwork.connect(self, a)
  33. self.consensus = c.getconsensus()
  34. c.close()
  35. def newepoch(self, epoch):
  36. self.uploaddesc()
  37. def uploaddesc(self):
  38. # Upload the descriptor for the epoch to come
  39. descdict = dict();
  40. descdict["epoch"] = network.thenetwork.getepoch() + 1
  41. descdict["idkey"] = self.idkey.verify_key
  42. descdict["onionkey"] = self.onionkey.public_key
  43. descdict["addr"] = self.netaddr
  44. descdict["bw"] = self.bw
  45. descdict["flags"] = self.flags
  46. desc = dirauth.RelayDescriptor(descdict)
  47. desc.sign(self.idkey)
  48. desc.verify()
  49. descmsg = dirauth.DirAuthUploadDescMsg(desc)
  50. # Upload them
  51. for a in self.dirauthaddrs:
  52. c = network.thenetwork.connect(self, a)
  53. c.sendmsg(descmsg)
  54. c.close()
  55. if __name__ == '__main__':
  56. # Start some dirauths
  57. numdirauths = 9
  58. dirauthaddrs = []
  59. for i in range(numdirauths):
  60. dira = dirauth.DirAuth(i, numdirauths)
  61. dirauthaddrs.append(network.thenetwork.bind(dira))
  62. # Start some relays
  63. numrelays = 10
  64. for i in range(numrelays):
  65. # Relay bandwidths (at least the ones fast enough to get used)
  66. # in the live Tor network (as of Dec 2019) are well approximated
  67. # by (200000-(200000-25000)/3*log10(x)) where x is a
  68. # uniform integer in [1,2500]
  69. x = random.randint(1,2500)
  70. bw = int(200000-(200000-25000)/3*math.log10(x))
  71. Relay(dirauthaddrs, bw, 0)
  72. # Tick the epoch
  73. network.thenetwork.nextepoch()
  74. dirauth.DirAuth.consensus.verify(network.thenetwork.dirauthkeys())
  75. print('ticked; epoch=', network.thenetwork.getepoch())