3 # This file is part of BridgeDB, a Tor bridge distribution system.
14 # A bunch of Tor version numbers.
15 SERVER_VERSIONS = ["0.2.2.39",
38 import stem.descriptor
39 from stem.descriptor.server_descriptor import RelayDescriptor
40 from stem.descriptor.extrainfo_descriptor import RelayExtraInfoDescriptor
41 from stem.descriptor.networkstatus import NetworkStatusDocumentV3
43 print("Creating descriptors requires stem <https://stem.torproject.org>")
46 if not hasattr(stem.descriptor, "create_signing_key"):
47 print("This requires stem version 1.6 or later but you are running "
48 "version %s" % stem.__version__)
52 def make_output_dir():
53 if not os.path.exists(os.getcwd()):
57 def write_descriptors(descs, filename):
59 with open(os.path.join(os.getcwd(), filename), "w") as descriptor_file:
60 for descriptor in descs:
61 descriptor_file.write(str(descriptor))
64 def write_descriptor(desc, filename):
66 with open(os.path.join(os.getcwd(), filename), "w") as descriptor_file:
67 descriptor_file.write(str(desc))
70 def check_ip_validity(ip):
71 if (ip.is_link_local or
76 ((ip.version == 6) and ip.is_site_local) or
77 ((ip.version == 4) and ip.is_reserved)):
82 def get_transport_line(probing_resistant, addr, port):
84 If probing_resistant is True, add a transport protocol that's resistant to
85 active probing attacks.
88 # Make sure that we won't end up with a negative port.
94 transports.append("obfs2 %s:%s" % (addr, port-10))
95 iat_mode = random.randint(0, 1)
96 node_id = hashlib.sha1(bytes(random.getrandbits(8))).hexdigest()
97 public_key = hashlib.sha256(bytes(random.getrandbits(8))).hexdigest()
98 transports.append("obfs4 %s:%s iat-mode=%s,node-id=%s,public-key=%s" %
99 (addr, port-20, iat_mode, node_id, public_key))
101 # Always include obfs4 and occasionally include scramblesuit.
103 if random.randint(0, 1) > 0:
104 transports.append("scramblesuit 216.117.3.62:63174 "
105 "password=ABCDEFGHIJKLMNOPQRSTUVWXYZ234567")
107 transports.append("obfs2 %s:%s" % (addr, port-10))
108 transports.append("obfs3 %s:%s" % (addr, port-20))
110 return "\ntransport ".join(transports)
113 def get_hex_string(size):
115 for _ in range(size):
116 hexstr += random.choice("ABCDEF0123456789")
120 def get_random_addr(ip_version=4):
122 while not valid_addr:
124 maybe = ipaddress.IPv4Address(random.getrandbits(32))
126 maybe = ipaddress.IPv6Address(random.getrandbits(128))
127 valid = check_ip_validity(maybe)
131 return str(valid_addr)
134 def get_protocol(tor_version):
136 if tor_version is not None:
138 line += "protocols Link 1 2 Circuit 1"
142 def make_timestamp(now=None, fmt=None, variation=False, period=None):
143 now = int(now) if now is not None else int(time.time())
144 fmt = fmt if fmt else "%Y-%m-%d %H:%M:%S"
148 if period is not None:
149 secs = int(period) * 3600
151 # Get a random number between one epochseconds number and another
152 diff = random.randint(then, now)
153 # Then rewind the clock
156 return time.strftime(fmt, time.localtime(now))
159 def make_bandwidth(variance=30):
160 observed = random.randint(20 * 2**10, 2 * 2**30)
161 percentage = float(variance) / 100.
162 burst = int(observed + math.ceil(observed * percentage))
163 bandwidths = [burst, observed]
164 nitems = len(bandwidths) if (len(bandwidths) > 0) else float("nan")
165 avg = int(math.ceil(float(sum(bandwidths)) / nitems))
166 return "%s %s %s" % (avg, burst, observed)
169 def make_bridge_distribution_request():
179 return random.choice(methods)
182 def create_server_desc(signing_key):
184 Create and return a server descriptor.
187 nickname = ("Unnamed%i" % random.randint(0, 100000000000000))[:19]
189 # We start at port 10 because we subtract from this port to get port
190 # numbers for IPv6 and obfuscation protocols.
192 port = random.randint(10, 65535)
193 tor_version = random.choice(SERVER_VERSIONS)
194 timestamp = make_timestamp(variation=True, period=36)
196 server_desc = RelayDescriptor.create({
197 "router": "%s %s %s 0 0" % (nickname, get_random_addr(ip_version=4), port),
198 "or-address": "[%s]:%s" % (get_random_addr(ip_version=6), port-1),
199 "platform": "Tor %s on Linux" % tor_version,
200 get_protocol(tor_version): "",
201 "published": timestamp,
202 "uptime": str(int(random.randint(1800, 63072000))),
203 "bandwidth": make_bandwidth(),
204 "contact": "Somebody <somebody@example.com>",
205 "bridge-distribution-request": make_bridge_distribution_request(),
207 }, signing_key=signing_key)
212 def create_extrainfo_desc(server_desc, signing_key, probing_resistant):
214 Create and return an extrainfo descriptor.
217 ts = server_desc.published
219 extrainfo_desc = RelayExtraInfoDescriptor.create({
220 "extra-info": "%s %s" % (server_desc.nickname,
221 server_desc.fingerprint),
222 "transport": get_transport_line(probing_resistant,
224 server_desc.or_port),
225 "write-history": "%s (900 s) 3188736,2226176,2866176" % ts,
226 "read-history": "%s (900 s) 3891200,2483200,2698240" % ts,
227 "dirreq-write-history": "%s (900 s) 1024,0,2048" % ts,
228 "dirreq-read-history": "%s (900 s) 0,0,0" % ts,
229 "geoip-db-digest": "%s" % get_hex_string(40),
230 "geoip6-db-digest": "%s" % get_hex_string(40),
231 "dirreq-stats-end": "%s (86400 s)" % ts,
233 "dirreq-v3-reqs": "",
234 "dirreq-v3-resp": "ok=16,not-enough-sigs=0,unavailable=0,"
235 "not-found=0,not-modified=0,busy=0",
236 "dirreq-v3-direct-dl": "complete=0,timeout=0,running=0",
237 "dirreq-v3-tunneled-dl": "complete=12,timeout=0,running=0",
238 "bridge-stats-end": "%s (86400 s)" % ts,
239 "bridge-ips": "ca=8",
240 "bridge-ip-versions": "v4=8,v6=0",
241 "bridge-ip-transports": "<OR>=8",
242 }, signing_key=signing_key)
244 return extrainfo_desc
247 def make_descriptors(count, num_probing_resistant):
249 Create fake descriptors and write them to the working directory.
252 consensus_entries = []
253 server_descriptors = []
257 for i in range(count):
258 signing_key = stem.descriptor.create_signing_key()
260 server_desc = create_server_desc(signing_key)
261 server_descriptors.append(server_desc)
262 consensus_entries.append(server_desc.make_router_status_entry())
264 extrainfo_desc = create_extrainfo_desc(server_desc,
266 num_probing_resistant > 0)
267 if random.random() > 0.75:
268 extrainfos_new.append(extrainfo_desc)
270 extrainfos_old.append(extrainfo_desc)
272 if num_probing_resistant > 0:
273 num_probing_resistant -= 1
275 consensus = NetworkStatusDocumentV3.create(routers=consensus_entries)
276 write_descriptor(consensus, "networkstatus-bridges")
277 write_descriptors(server_descriptors, "bridge-descriptors")
278 write_descriptors(extrainfos_old, "cached-extrainfo")
279 write_descriptors(extrainfos_new, "cached-extrainfo.new")
282 if __name__ == "__main__":
284 parser = argparse.ArgumentParser(description="Create fake descriptors.")
285 parser.add_argument("num_descs",
287 help="The number of descriptors to create.")
288 parser.add_argument("--num-resistant-descs",
289 dest="num_resistant_descs",
292 help="The number of active probing-resistant "
293 "descriptors to create")
294 args = parser.parse_args()
295 if args.num_resistant_descs == -1:
296 args.num_resistant_descs = args.num_descs
298 make_descriptors(args.num_descs, args.num_resistant_descs)