[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[tor-commits] [compass/master] Refactor Sathya's almost-fast exits code a bit.



commit 3ba4dcbe55d7a50bb3ed3eddc6a6a545087fe4e3
Author: Karsten Loesing <karsten.loesing@xxxxxxx>
Date:   Fri Aug 24 09:25:40 2012 +0200

    Refactor Sathya's almost-fast exits code a bit.
---
 compass.py |  212 +++++++++++++++++++++++++++++-------------------------------
 1 files changed, 103 insertions(+), 109 deletions(-)

diff --git a/compass.py b/compass.py
index 04b8313..770e563 100755
--- a/compass.py
+++ b/compass.py
@@ -76,119 +76,101 @@ class ExitFilter(BaseFilter):
     def accept(self, relay):
         return relay.get('exit_probability', -1) > 0.0
 
-class SameNetworkFilter(BaseFilter):
+class GuardFilter(BaseFilter):
+    def accept(self, relay):
+        return relay.get('guard_probability', -1) > 0.0
+
+class FastExitFilter(BaseFilter):
+
     class Relay(object):
         def __init__(self, relay):
             self.exit = relay.get('exit_probability')
             self.fp = relay.get('fingerprint')
             self.relay = relay
-    
-    def __init__(self):
-        self.network_data = {}
-        self.relays = []        
-    
-    def load(self, all_relays):
-        for relay in all_relays:
-            or_addresses = relay.get("or_addresses")
-            no_of_addresses = 0
-            for ip in or_addresses:
-                ip, port = ip.rsplit(':', 1)
-                # skip if ipv6
-                if ':' in ip:
-                    continue
-                no_of_addresses += 1
-                if no_of_addresses > 1:
-                    print "[WARNING] - %s has more than two OR Addresses - %s" % relay.get("fingerprint"), or_addresses
-                network = ip.rsplit('.', 1)[0]
-                relay_info = self.Relay(relay)
-                if self.network_data.has_key(network):
-                    if len(self.network_data[network]) > 1:
-                        # assume current relay to have smallest exit_probability
-                        min_exit = relay.get('exit_probability')
-                        min_id = -1
-                        for id, value in enumerate(self.network_data[network]):
-                            if value.exit < min_exit:
-                                min_exit = value.exit
-                                min_id = id
-                        if min_id != -1:
-                            del self.network_data[network][min_id]
-                            self.network_data[network].append(relay_info)
-                    else:
-                        self.network_data[network].append(relay_info)
-                else:
-                    self.network_data[network] = [relay_info]
-
-        for relay_list in self.network_data.values():
-            self.relays.extend([relay.relay for relay in relay_list])
-        return self.relays
-    
-    def accept(self, relay):
-        return relay.get('fingerprint') in self.relays_fp
-    
-class GuardFilter(BaseFilter):
-    def accept(self, relay):
-        return relay.get('guard_probability', -1) > 0.0
 
-class FastExitFilter(BaseFilter):
-    def __init__(self, bandwidth_rate, advertised_bandwidth, ports, inverse=False):
+    def __init__(self, bandwidth_rate, advertised_bandwidth, ports, same_network, inverse=False):
         self.bandwidth_rate = bandwidth_rate
         self.advertised_bandwidth = advertised_bandwidth
         self.ports = ports
+        self.same_network = same_network
         self.inverse = inverse
-    
-    def accept(self, relay):
-        if relay.get('bandwidth_rate', -1) < self.bandwidth_rate:
-            return self.inverse
-        if relay.get('advertised_bandwidth', -1) < self.advertised_bandwidth:
-            return self.inverse
-        relevant_ports = set(self.ports)
-        summary = relay.get('exit_policy_summary', {})
-        if 'accept' in summary:
-            portlist = summary['accept']
-        elif 'reject' in summary:
-            portlist = summary['reject']
-        else:
-            return self.inverse
-        ports = []
-        for p in portlist:
-            if '-' in p:
-                ports.extend(range(int(p.split('-')[0]),
-                                   int(p.split('-')[1]) + 1))
+
+    def load(self, all_relays):
+
+        # First, filter relays based on bandwidth and port requirements.
+        matching_relays = []
+        for relay in all_relays:
+            if relay.get('bandwidth_rate', -1) < self.bandwidth_rate:
+                continue
+            if relay.get('advertised_bandwidth', -1) < self.advertised_bandwidth:
+                continue
+            relevant_ports = set(self.ports)
+            summary = relay.get('exit_policy_summary', {})
+            if 'accept' in summary:
+                portlist = summary['accept']
+            elif 'reject' in summary:
+                portlist = summary['reject']
             else:
-                ports.append(int(p))
-        policy_ports = set(ports)
-        if 'accept' in summary and not relevant_ports.issubset(policy_ports):
-            return self.inverse
-        if 'reject' in summary and not relevant_ports.isdisjoint(policy_ports):
-            return self.inverse
-        return not self.inverse
-
-class AlmostFastExitFilter(BaseFilter):    
-    def load(self, relays):
-        exit_filter = FastExitFilter(95 * 125 * 1024, 5000 * 1024, [80, 443, 554, 1755], False)
-        fast_relays = exit_filter.load(relays)
-        same_network_filter = SameNetworkFilter()
-        fast_relays_with_network_restriction = same_network_filter.load(fast_relays)
-        almost_exit_filter = FastExitFilter(80* 125* 1024, 2000 * 1024, [80, 443], False)
-        almost_fast_relays = almost_exit_filter.load(relays)
-        almost_exit_filter = FastExitFilter(95 * 125 * 1024, 5000 * 1024, [80, 443, 554, 1755], True)
-        almost_fast_relays = almost_exit_filter.load(almost_fast_relays)
-        diffed_relays = self.diff(fast_relays, fast_relays_with_network_restriction)
-        return self.union(diffed_relays, almost_fast_relays)
-    
-    def diff(self, relays_a, relays_b):
-        relays_a = dict([(relay.get('fingerprint'), relay) for relay in relays_a])
-        relays_b = dict([(relay.get('fingerprint'), relay) for relay in relays_b])
-        total_relays = dict(relays_a.items() + relays_b.items())
-        set_diff = set(relays_a.keys()) - set(relays_b.keys())
-        return [total_relays[fp] for fp in set_diff]
-
-    def union(self, relays_a, relays_b):
-        relays_a = dict([(relay.get('fingerprint'), relay) for relay in relays_a])
-        relays_b = dict([(relay.get('fingerprint'), relay) for relay in relays_b])
-        total_relays = dict(relays_a.items() + relays_b.items())
-        set_union = set(relays_a.keys()) | set(relays_b.keys())
-        return [total_relays[fp] for fp in set_union]
+                continue
+            ports = []
+            for p in portlist:
+                if '-' in p:
+                    ports.extend(range(int(p.split('-')[0]),
+                                       int(p.split('-')[1]) + 1))
+                else:
+                    ports.append(int(p))
+            policy_ports = set(ports)
+            if 'accept' in summary and not relevant_ports.issubset(policy_ports):
+                continue
+            if 'reject' in summary and not relevant_ports.isdisjoint(policy_ports):
+                continue
+            matching_relays.append(relay)
+
+        # Second, filter relays based on same /24 requirement.
+        if self.same_network:
+            network_data = {}
+            for relay in matching_relays:
+                or_addresses = relay.get("or_addresses")
+                no_of_addresses = 0
+                for ip in or_addresses:
+                    ip, port = ip.rsplit(':', 1)
+                    # skip if ipv6
+                    if ':' in ip:
+                        continue
+                    no_of_addresses += 1
+                    if no_of_addresses > 1:
+                        print "[WARNING] - %s has more than one IPv4 OR address - %s" % relay.get("fingerprint"), or_addresses
+                    network = ip.rsplit('.', 1)[0]
+                    relay_info = self.Relay(relay)
+                    if network_data.has_key(network):
+                        if len(network_data[network]) > 1:
+                            # assume current relay to have smallest exit_probability
+                            min_exit = relay.get('exit_probability')
+                            min_id = -1
+                            for id, value in enumerate(network_data[network]):
+                                if value.exit < min_exit:
+                                    min_exit = value.exit
+                                    min_id = id
+                            if min_id != -1:
+                                del network_data[network][min_id]
+                                network_data[network].append(relay_info)
+                        else:
+                            network_data[network].append(relay_info)
+                    else:
+                        network_data[network] = [relay_info]
+            matching_relays = []
+            for relay_list in network_data.values():
+                matching_relays.extend([relay.relay for relay in relay_list])
+
+        # Either return relays meeting all requirements, or the inverse set.
+        if self.inverse:
+            inverse_relays = []
+            for relay in all_relays:
+                if relay not in matching_relays:
+                    inverse_relays.append(relay)
+            return inverse_relays
+        else:
+            return matching_relays
 
 class RelayStats(object):
     def __init__(self, options):
@@ -233,10 +215,12 @@ class RelayStats(object):
         if options.guards_only:
             filters.append(GuardFilter())
         if options.fast_exits_only:
-            filters.append(FastExitFilter(95 * 125 * 1024, 5000 * 1024, [80, 443, 554, 1755], False))
-            filters.append(SameNetworkFilter())
+            filters.append(FastExitFilter(95 * 125 * 1024, 5000 * 1024, [80, 443, 554, 1755], True, False))
         if options.almost_fast_exits_only:
-            filters.append(AlmostFastExitFilter())
+            filters.append(FastExitFilter(80 * 125 * 1024, 2000 * 1024, [80, 443], False, False))
+            filters.append(FastExitFilter(95 * 125 * 1024, 5000 * 1024, [80, 443, 554, 1755], True, True))
+        if options.fast_exits_only_any_network:
+            filters.append(FastExitFilter(95 * 125 * 1024, 5000 * 1024, [80, 443, 554, 1755], False, False))
         return filters
 
     def _get_group_function(self, options):
@@ -355,10 +339,12 @@ def create_option_parser():
                      help="select family by fingerprint or nickname (for named relays)")
     group.add_option("-g", "--guards-only", action="store_true",
                      help="select only relays suitable for guard position")
-    group.add_option("-x", "--fast-exits-only", action="store_true",
-                     help="select only 100+ Mbit/s exits allowing ports 80, 443, 554, and 1755")
-    group.add_option("-w", "--almost-fast-exits-only", action="store_true",
-                     help="select only 80+ & 95- Mbit/s exits allowing ports 80, 443, 554, and 1755")
+    group.add_option("--fast-exits-only", action="store_true",
+                     help="select only fast exits (95+ Mbit/s, 5000+ KB/s, 80/443/554/1755, 2- per /24)")
+    group.add_option("--almost-fast-exits-only", action="store_true",
+                     help="select only almost fast exits (80+ Mbit/s, 2000+ KB/s, 80/443, not in set of fast exits)")
+    group.add_option("--fast-exits-only-any-network", action="store_true",
+                     help="select only fast exits without network restriction (95+ Mbit/s, 5000+ KB/s, 80/443/554/1755")
     parser.add_option_group(group)
     group = OptionGroup(parser, "Grouping options")
     group.add_option("-A", "--by-as", action="store_true", default=False,
@@ -391,6 +377,14 @@ if '__main__' == __name__:
 
     if options.family and not re.match(r'^[A-F0-9]{40}$', options.family) and not re.match(r'^[A-Za-z0-9]{1,19}$', options.family):
         parser.error("Not a valid fingerprint or nickname: %s" % options.family)
+
+    fast_exit_options = 0
+    if options.fast_exits_only: fast_exit_options += 1
+    if options.almost_fast_exits_only: fast_exit_options += 1
+    if options.fast_exits_only_any_network: fast_exit_options += 1
+    if fast_exit_options > 1:
+        parser.error("Can only filter by one fast-exit option.")
+
     if options.download:
         download_details_file()
         print "Downloaded details.json.  Re-run without --download option."



_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits