def generateFakeBridges(n=500): """Generate a set of **n** :class:`~bridgedb.bridges.Bridges` with random data. """ from bridgedb.bridges import Bridge from bridgedb.bridges import PluggableTransport global _FAKE_BRIDGES if _FAKE_BRIDGES: return _FAKE_BRIDGES bridges = [] for i in range(n): addr = randomValidIPv4String() nick = 'bridge-%d' % i port = randomHighPort() # Real tor currently only supports one extra ORAddress, and it can # only be IPv6. addrs = [(randomValidIPv6(), randomHighPort(), 6)] fpr = "".join(random.choice('abcdef0123456789') for _ in range(40)) supported = ["obfs2", "obfs3", "fte"] transports = [] for j, method in zip(range(1, len(supported) + 1), supported): pt = PluggableTransport(fpr, method, addr, port - j, {}) transports.append(pt) # Every tenth bridge supports obfs4. if i % 10 == 0: obfs4Args = { 'iat-mode': '1', 'node-id': '2a79f14120945873482b7823caabe2fcde848722', 'public-key': '0a5b046d07f6f971b7776de682f57c5b9cdc8fa060db7ef59de82e721c8098f4' } pt = PluggableTransport(fpr, "obfs4", addr, port - j, obfs4Args) transports.append(pt) # Every fifteenth bridge supports scramblesuit. if i % 15 == 0: scramblesuitArgs = {'password': '******'} pt = PluggableTransport(fpr, "scramblesuit", addr, port - j, scramblesuitArgs) transports.append(pt) bridge = Bridge(nick, addr, port, fpr) bridge.flags.update("Running Stable") bridge.transports = transports bridge.orAddresses = addrs bridges.append(bridge) _FAKE_BRIDGES = bridges return bridges
def setUp(self): """Create a Bridge whose address is 1.1.1.1, orPort is 1111, and fingerprint is 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'. Also, create an HMAC function whose key is 'plasma'. """ self.bridge = Bridge() self.bridge.address = '1.1.1.1' self.bridge.orPort = 1111 self.bridge.fingerprint = 'a' * 40 self.hmac = getHMACFunc('plasma')
def setUp(self): """Create a Bridge whose address is 1.1.1.1, orPort is 1111, and fingerprint is 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'. Also, create an HMAC function whose key is 'plasma'. """ self.bridge = Bridge() self.bridge.address = '1.1.1.1' self.bridge.orPort = 1111 self.bridge.fingerprint = 'a' * 40 self.hmac = getHMACFunc('plasma') PluggableTransport.probing_resistant_transports = [ 'scramblesuit', 'obfs4' ]
def generateFakeBridges(n=500): """Generate a set of **n** :class:`~bridgedb.bridges.Bridges` with random data. """ from bridgedb.bridges import Bridge from bridgedb.bridges import PluggableTransport global _FAKE_BRIDGES if _FAKE_BRIDGES: return _FAKE_BRIDGES bridges = [] for i in range(n): addr = randomValidIPv4String() nick = 'bridge-%d' % i port = randomHighPort() # Real tor currently only supports one extra ORAddress, and it can # only be IPv6. addrs = [(randomValidIPv6(), randomHighPort(), 6)] fpr = "".join(random.choice('abcdef0123456789') for _ in xrange(40)) # We only support the ones without PT args, because they're easier to fake. supported = ["obfs2", "obfs3", "fte"] transports = [] for j, method in zip(range(1, len(supported) + 1), supported): pt = PluggableTransport(fpr, method, addr, port - j, {}) transports.append(pt) bridge = Bridge(nick, addr, port, fpr) bridge.flags.update("Running Stable") bridge.transports = transports bridge.orAddresses = addrs bridges.append(bridge) _FAKE_BRIDGES = bridges return bridges
class FiltersTests(unittest.TestCase): """Tests for :mod:`bridgedb.filters`.""" def setUp(self): """Create a Bridge whose address is 1.1.1.1, orPort is 1111, and fingerprint is 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'. Also, create an HMAC function whose key is 'plasma'. """ self.bridge = Bridge() self.bridge.address = '1.1.1.1' self.bridge.orPort = 1111 self.bridge.fingerprint = 'a' * 40 self.hmac = getHMACFunc('plasma') def addIPv4VoltronPT(self): pt = PluggableTransport('a' * 40, 'voltron', '1.1.1.1', 1111, {}) self.bridge.transports.append(pt) def addIPv6VoltronPT(self): pt = PluggableTransport('a' * 40, 'voltron', '2006:2222::2222', 1111, {}) self.bridge.transports.append(pt) def test_bySubring_1_of_2(self): """A Bridge with fingerprint 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' should be assigned to sub-hashring 1-of-2 (in this case, using a particular HMAC key), and therefore filters.bySubring(HMAC, 1, 2) should return that Bridge (because it is in the sub-hashring we asked for). """ filtre = filters.bySubring(self.hmac, 1, 2) self.assertTrue(filtre(self.bridge)) def test_bySubring_2_of_2(self): """A Bridge with fingerprint 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' should be assigned to sub-hashring 1-of-2 (in this case, using a particular HMAC key), and therefore filters.bySubring(HMAC, 2, 2) should *not* return that Bridge (because it is in sub-hashring 1-of-2 and we asked for Bridges which are in sub-hashring 2-of-2). """ filtre = filters.bySubring(self.hmac, 2, 2) self.assertFalse(filtre(self.bridge)) def test_byFilters_bySubring_byTransport_correct_subhashring_with_transport( self): """Filtering byTransport('voltron') and bySubring(HMAC, 1, 2) when the Bridge has a voltron transport and is assigned to sub-hashring 1-of-2 should return True. """ self.addIPv4VoltronPT() filtre = filters.byFilters([ filters.bySubring(self.hmac, 1, 2), filters.byTransport('voltron') ]) self.assertTrue(filtre(self.bridge)) def test_byFilters_bySubring_byTransport_wrong_subhashring_with_transport( self): """Filtering byTransport('voltron') and bySubring(HMAC, 2, 2) when the Bridge has a voltron transport and is assigned to sub-hashring 1-of-2 should return False. """ self.addIPv4VoltronPT() filtre = filters.byFilters([ filters.bySubring(self.hmac, 2, 2), filters.byTransport('voltron') ]) self.assertFalse(filtre(self.bridge)) def test_byFilters_bySubring_byTransport_correct_subhashring_no_transport( self): """Filtering byTransport('voltron') and bySubring(HMAC, 1, 2) when the Bridge has no transports and is assigned to sub-hashring 1-of-2 should return False. """ filtre = filters.byFilters([ filters.bySubring(self.hmac, 1, 2), filters.byTransport('voltron') ]) self.assertFalse(filtre(self.bridge)) def test_byFilters_bySubring_byTransport_wrong_subhashring_no_transport( self): """Filtering byTransport('voltron') and bySubring(HMAC, 2, 2) when the Bridge has no transports and is assigned to sub-hashring 1-of-2 should return False. """ filtre = filters.byFilters([ filters.bySubring(self.hmac, 2, 2), filters.byTransport('voltron') ]) self.assertFalse(filtre(self.bridge)) def test_byFilters_no_filters(self): self.addIPv4VoltronPT() filtre = filters.byFilters([]) self.assertTrue(filtre(self.bridge)) def test_byIPv_ipv5(self): """Calling byIPv(ipVersion=5) should default to filterint by IPv4.""" filtre = filters.byIPv(5) self.assertTrue(filtre(self.bridge)) def test_byIPv4_address(self): """A bridge with an IPv4 address for its main orPort address should cause filters.byIPv4() to return True. """ self.assertTrue(filters.byIPv4(self.bridge)) def test_byIPv4_orAddress(self): """A bridge with an IPv4 address in its orAddresses address should cause filters.byIPv4() to return True. """ self.bridge.address = '2006:2222::2222' self.bridge.orAddresses = [(ipaddr.IPv4Address('2.2.2.2'), 2222, 4)] self.assertTrue(filters.byIPv4(self.bridge)) def test_byIPv4_none(self): """A bridge with no IPv4 addresses should cause filters.byIPv4() to return False. """ self.bridge.address = ipaddr.IPv6Address('2006:2222::2222') self.bridge.orAddresses = [(ipaddr.IPv6Address('2006:3333::3333'), 3333, 6)] self.assertFalse(filters.byIPv4(self.bridge)) def test_byIPv6_address(self): """A bridge with an IPv6 address for its main orPort address should cause filters.byIPv6() to return True. """ self.bridge.address = '2006:2222::2222' self.assertTrue(filters.byIPv6(self.bridge)) def test_byIPv6_orAddress(self): """A bridge with an IPv6 address in its orAddresses address should cause filters.byIPv6() to return True. """ self.bridge.orAddresses = [(ipaddr.IPv6Address('2006:3333::3333'), 3333, 6)] self.assertTrue(filters.byIPv6(self.bridge)) def test_byIPv6_none(self): """A bridge with no IPv6 addresses should cause filters.byIPv6() to return False. """ self.assertFalse(filters.byIPv6(self.bridge)) def test_byTransport_with_transport_ipv4(self): """A bridge with an IPv4 voltron transport should cause byTransport('voltron') to return True. """ self.addIPv4VoltronPT() filtre = filters.byTransport('voltron') self.assertTrue(filtre(self.bridge)) def test_byTransport_with_transport_ipv6(self): """A bridge with an IPv6 voltron transport should cause byTransport('voltron', ipVersion=6) to return True. """ self.addIPv6VoltronPT() filtre = filters.byTransport('voltron', ipVersion=6) self.assertTrue(filtre(self.bridge)) def test_byTransport_with_transport_ipv6_filtering_by_ipv4(self): """A bridge with an IPv6 voltron transport should cause byTransport('voltron') to return True. """ self.addIPv6VoltronPT() filtre = filters.byTransport('voltron') self.assertFalse(filtre(self.bridge)) def test_byTransport_no_transports(self): """A bridge without any transports should cause byTransport('voltron') to return False. """ filtre = filters.byTransport('voltron') self.assertFalse(filtre(self.bridge)) def test_byTransport_vanilla_ipv4(self): """byTransport() without namimg a transport to filter by should just return the bridge's IPv4 address. """ filtre = filters.byTransport() self.assertTrue(filtre(self.bridge)) def test_byTransport_vanilla_ipv6(self): """byTranspfort(ipVersion=6) without namimg a transport to filter by should just return the bridge's IPv4 address. """ self.bridge.orAddresses = [(ipaddr.IPv6Address('2006:3333::3333'), 3333, 6)] filtre = filters.byTransport(ipVersion=6) self.assertTrue(filtre(self.bridge)) def test_byTransport_wrong_transport(self): """A bridge with only a Voltron transport should cause byTransport('obfs3') to return False. """ self.addIPv4VoltronPT() filtre = filters.byTransport('obfs3') self.assertFalse(filtre(self.bridge)) def test_byNotBlockedIn_no_countryCode_with_transport_ipv4(self): """A bridge with an IPv4 voltron transport should cause byNotBlockedIn('voltron') to return True (because it calls filters.byTransport). """ self.addIPv4VoltronPT() filtre = filters.byNotBlockedIn(None, methodname='voltron') self.assertTrue(filtre(self.bridge)) def test_byNotBlockedIn_no_countryCode_with_transport_ipv6(self): """A bridge with an IPv6 voltron transport should cause byNotBlockedIn('voltron') to return True (because it calls filters.byTransport). """ self.addIPv6VoltronPT() filtre = filters.byNotBlockedIn(None, methodname='voltron', ipVersion=6) self.assertTrue(filtre(self.bridge)) def test_byNotBlockedIn_with_transport_ipv4(self): """A bridge with an IPv4 voltron transport should cause byNotBlockedIn('voltron') to return True. """ self.addIPv4VoltronPT() filtre = filters.byNotBlockedIn('CN', methodname='voltron') self.assertTrue(filtre(self.bridge)) def test_byNotBlockedIn_with_transport_ipv4_blocked(self): """A bridge with an IPv4 voltron transport which is blocked should cause byNotBlockedIn('voltron') to return False. """ self.addIPv4VoltronPT() self.bridge.setBlockedIn('CN') filtre = filters.byNotBlockedIn('CN', methodname='voltron') self.assertFalse(filtre(self.bridge)) def test_byNotBlockedIn_with_transport_ipv6(self): """A bridge with an IPv6 voltron transport should cause byNotBlockedIn('voltron') to return True. """ self.addIPv6VoltronPT() filtre = filters.byNotBlockedIn('cn', 'voltron', ipVersion=6) self.assertTrue(filtre(self.bridge)) def test_byNotBlockedIn_with_transport_ipv4_not_blocked_ipv4(self): """A bridge with an IPv6 voltron transport which is not blocked in China should cause byNotBlockedIn('cn', 'voltron') to return False, because the IP version is wrong. """ self.addIPv6VoltronPT() filtre = filters.byNotBlockedIn('cn', 'voltron') self.assertFalse(filtre(self.bridge)) def test_byNotBlockedIn_with_transport_ipv6_blocked(self): """A bridge with an IPv6 voltron transport which is blocked should cause byNotBlockedIn('voltron') to return False. """ self.addIPv6VoltronPT() self.bridge.setBlockedIn('CN') filtre = filters.byNotBlockedIn('cn', 'voltron', ipVersion=6) self.assertFalse(filtre(self.bridge)) def test_byNotBlockedIn_no_countryCode_no_transports(self): """A bridge without any transports should cause byNotBlockedIn('voltron') to return False (because it calls filters.byTransport('voltron')). """ filtre = filters.byNotBlockedIn(None, methodname='voltron') self.assertFalse(filtre(self.bridge)) def test_byNotBlockedIn_no_transports(self): """A bridge without any transports should cause byNotBlockedIn('cn', 'voltron') to return False. """ filtre = filters.byNotBlockedIn('cn', methodname='voltron') self.assertFalse(filtre(self.bridge)) def test_byNotBlockedIn_no_transports_blocked(self): """A bridge without any transports which is also blocked should cause byNotBlockedIn('voltron') to return False. """ self.bridge.setBlockedIn('cn') filtre = filters.byNotBlockedIn('cn', methodname='voltron') self.assertFalse(filtre(self.bridge)) def test_byNotBlockedIn_wrong_transport(self): """A bridge with only a Voltron transport should cause byNotBlockedIn('obfs3') to return False. """ self.addIPv4VoltronPT() filtre = filters.byNotBlockedIn('cn', methodname='obfs3') self.assertFalse(filtre(self.bridge)) def test_byNotBlockedIn_ipv5(self): """Calling byNotBlockedIn([…], ipVersion=5) should default to IPv4.""" self.bridge.setBlockedIn('ru') filtre = filters.byNotBlockedIn('cn', ipVersion=5) self.assertTrue(filtre(self.bridge)) def test_byNotBlockedIn_vanilla_not_blocked(self): """Calling byNotBlockedIn('vanilla') should return the IPv4 vanilla address, if it is not blocked. """ self.bridge.setBlockedIn('ru') filtre = filters.byNotBlockedIn('cn', methodname='vanilla') self.assertTrue(filtre(self.bridge)) def test_byNotBlockedIn_vanilla_not_blocked_ipv6(self): """Calling byNotBlockedIn('vanilla', ipVersion=6) should not return the IPv4 vanilla address, even if it is not blocked, because it has the wrong IP version. """ self.bridge.setBlockedIn('ru') filtre = filters.byNotBlockedIn('cn', methodname='vanilla', ipVersion=6) self.assertFalse(filtre(self.bridge)) def test_byNotBlockedIn_vanilla_blocked(self): """Calling byNotBlockedIn('vanilla') should not return the IPv4 vanilla address, if it is blocked. """ self.bridge.setBlockedIn('ru') filtre = filters.byNotBlockedIn('ru', methodname='vanilla') self.assertFalse(filtre(self.bridge))
class FiltersTests(unittest.TestCase): """Tests for :mod:`bridgedb.filters`.""" def setUp(self): """Create a Bridge whose address is 1.1.1.1, orPort is 1111, and fingerprint is 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'. Also, create an HMAC function whose key is 'plasma'. """ self.bridge = Bridge() self.bridge.address = '1.1.1.1' self.bridge.orPort = 1111 self.bridge.fingerprint = 'a' * 40 self.hmac = getHMACFunc('plasma') def addIPv4VoltronPT(self): pt = PluggableTransport('a' * 40, 'voltron', '1.1.1.1', 1111, {}) self.bridge.transports.append(pt) def addIPv6VoltronPT(self): pt = PluggableTransport('a' * 40, 'voltron', '2006:2222::2222', 1111, {}) self.bridge.transports.append(pt) def test_bySubring_1_of_2(self): """A Bridge with fingerprint 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' should be assigned to sub-hashring 1-of-2 (in this case, using a particular HMAC key), and therefore filters.bySubring(HMAC, 1, 2) should return that Bridge (because it is in the sub-hashring we asked for). """ filtre = filters.bySubring(self.hmac, 1, 2) self.assertTrue(filtre(self.bridge)) def test_bySubring_2_of_2(self): """A Bridge with fingerprint 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' should be assigned to sub-hashring 1-of-2 (in this case, using a particular HMAC key), and therefore filters.bySubring(HMAC, 2, 2) should *not* return that Bridge (because it is in sub-hashring 1-of-2 and we asked for Bridges which are in sub-hashring 2-of-2). """ filtre = filters.bySubring(self.hmac, 2, 2) self.assertFalse(filtre(self.bridge)) def test_byFilters_bySubring_byTransport_correct_subhashring_with_transport(self): """Filtering byTransport('voltron') and bySubring(HMAC, 1, 2) when the Bridge has a voltron transport and is assigned to sub-hashring 1-of-2 should return True. """ self.addIPv4VoltronPT() filtre = filters.byFilters([filters.bySubring(self.hmac, 1, 2), filters.byTransport('voltron')]) self.assertTrue(filtre(self.bridge)) def test_byFilters_bySubring_byTransport_wrong_subhashring_with_transport(self): """Filtering byTransport('voltron') and bySubring(HMAC, 2, 2) when the Bridge has a voltron transport and is assigned to sub-hashring 1-of-2 should return False. """ self.addIPv4VoltronPT() filtre = filters.byFilters([filters.bySubring(self.hmac, 2, 2), filters.byTransport('voltron')]) self.assertFalse(filtre(self.bridge)) def test_byFilters_bySubring_byTransport_correct_subhashring_no_transport(self): """Filtering byTransport('voltron') and bySubring(HMAC, 1, 2) when the Bridge has no transports and is assigned to sub-hashring 1-of-2 should return False. """ filtre = filters.byFilters([filters.bySubring(self.hmac, 1, 2), filters.byTransport('voltron')]) self.assertFalse(filtre(self.bridge)) def test_byFilters_bySubring_byTransport_wrong_subhashring_no_transport(self): """Filtering byTransport('voltron') and bySubring(HMAC, 2, 2) when the Bridge has no transports and is assigned to sub-hashring 1-of-2 should return False. """ filtre = filters.byFilters([filters.bySubring(self.hmac, 2, 2), filters.byTransport('voltron')]) self.assertFalse(filtre(self.bridge)) def test_byFilters_no_filters(self): self.addIPv4VoltronPT() filtre = filters.byFilters([]) self.assertTrue(filtre(self.bridge)) def test_byIPv_ipv5(self): """Calling byIPv(ipVersion=5) should default to filterint by IPv4.""" filtre = filters.byIPv(5) self.assertTrue(filtre(self.bridge)) def test_byIPv4_address(self): """A bridge with an IPv4 address for its main orPort address should cause filters.byIPv4() to return True. """ self.assertTrue(filters.byIPv4(self.bridge)) def test_byIPv4_orAddress(self): """A bridge with an IPv4 address in its orAddresses address should cause filters.byIPv4() to return True. """ self.bridge.address = '2006:2222::2222' self.bridge.orAddresses = [(ipaddr.IPv4Address('2.2.2.2'), 2222, 4)] self.assertTrue(filters.byIPv4(self.bridge)) def test_byIPv4_none(self): """A bridge with no IPv4 addresses should cause filters.byIPv4() to return False. """ self.bridge.address = ipaddr.IPv6Address('2006:2222::2222') self.bridge.orAddresses = [(ipaddr.IPv6Address('2006:3333::3333'), 3333, 6)] self.assertFalse(filters.byIPv4(self.bridge)) def test_byIPv6_address(self): """A bridge with an IPv6 address for its main orPort address should cause filters.byIPv6() to return True. """ self.bridge.address = '2006:2222::2222' self.assertTrue(filters.byIPv6(self.bridge)) def test_byIPv6_orAddress(self): """A bridge with an IPv6 address in its orAddresses address should cause filters.byIPv6() to return True. """ self.bridge.orAddresses = [(ipaddr.IPv6Address('2006:3333::3333'), 3333, 6)] self.assertTrue(filters.byIPv6(self.bridge)) def test_byIPv6_none(self): """A bridge with no IPv6 addresses should cause filters.byIPv6() to return False. """ self.assertFalse(filters.byIPv6(self.bridge)) def test_byTransport_with_transport_ipv4(self): """A bridge with an IPv4 voltron transport should cause byTransport('voltron') to return True. """ self.addIPv4VoltronPT() filtre = filters.byTransport('voltron') self.assertTrue(filtre(self.bridge)) def test_byTransport_with_transport_ipv6(self): """A bridge with an IPv6 voltron transport should cause byTransport('voltron', ipVersion=6) to return True. """ self.addIPv6VoltronPT() filtre = filters.byTransport('voltron', ipVersion=6) self.assertTrue(filtre(self.bridge)) def test_byTransport_with_transport_ipv6_filtering_by_ipv4(self): """A bridge with an IPv6 voltron transport should cause byTransport('voltron') to return True. """ self.addIPv6VoltronPT() filtre = filters.byTransport('voltron') self.assertFalse(filtre(self.bridge)) def test_byTransport_no_transports(self): """A bridge without any transports should cause byTransport('voltron') to return False. """ filtre = filters.byTransport('voltron') self.assertFalse(filtre(self.bridge)) def test_byTransport_vanilla_ipv4(self): """byTransport() without namimg a transport to filter by should just return the bridge's IPv4 address. """ filtre = filters.byTransport() self.assertTrue(filtre(self.bridge)) def test_byTransport_vanilla_ipv6(self): """byTranspfort(ipVersion=6) without namimg a transport to filter by should just return the bridge's IPv4 address. """ self.bridge.orAddresses = [(ipaddr.IPv6Address('2006:3333::3333'), 3333, 6)] filtre = filters.byTransport(ipVersion=6) self.assertTrue(filtre(self.bridge)) def test_byTransport_wrong_transport(self): """A bridge with only a Voltron transport should cause byTransport('obfs3') to return False. """ self.addIPv4VoltronPT() filtre = filters.byTransport('obfs3') self.assertFalse(filtre(self.bridge)) def test_byNotBlockedIn_no_countryCode_with_transport_ipv4(self): """A bridge with an IPv4 voltron transport should cause byNotBlockedIn('voltron') to return True (because it calls filters.byTransport). """ self.addIPv4VoltronPT() filtre = filters.byNotBlockedIn(None, methodname='voltron') self.assertTrue(filtre(self.bridge)) def test_byNotBlockedIn_no_countryCode_with_transport_ipv6(self): """A bridge with an IPv6 voltron transport should cause byNotBlockedIn('voltron') to return True (because it calls filters.byTransport). """ self.addIPv6VoltronPT() filtre = filters.byNotBlockedIn(None, methodname='voltron', ipVersion=6) self.assertTrue(filtre(self.bridge)) def test_byNotBlockedIn_with_transport_ipv4(self): """A bridge with an IPv4 voltron transport should cause byNotBlockedIn('voltron') to return True. """ self.addIPv4VoltronPT() filtre = filters.byNotBlockedIn('CN', methodname='voltron') self.assertTrue(filtre(self.bridge)) def test_byNotBlockedIn_with_transport_ipv4_blocked(self): """A bridge with an IPv4 voltron transport which is blocked should cause byNotBlockedIn('voltron') to return False. """ self.addIPv4VoltronPT() self.bridge.setBlockedIn('CN') filtre = filters.byNotBlockedIn('CN', methodname='voltron') self.assertFalse(filtre(self.bridge)) def test_byNotBlockedIn_with_transport_ipv6(self): """A bridge with an IPv6 voltron transport should cause byNotBlockedIn('voltron') to return True. """ self.addIPv6VoltronPT() filtre = filters.byNotBlockedIn('cn', 'voltron', ipVersion=6) self.assertTrue(filtre(self.bridge)) def test_byNotBlockedIn_with_transport_ipv4_not_blocked_ipv4(self): """A bridge with an IPv6 voltron transport which is not blocked in China should cause byNotBlockedIn('cn', 'voltron') to return False, because the IP version is wrong. """ self.addIPv6VoltronPT() filtre = filters.byNotBlockedIn('cn', 'voltron') self.assertFalse(filtre(self.bridge)) def test_byNotBlockedIn_with_transport_ipv6_blocked(self): """A bridge with an IPv6 voltron transport which is blocked should cause byNotBlockedIn('voltron') to return False. """ self.addIPv6VoltronPT() self.bridge.setBlockedIn('CN') filtre = filters.byNotBlockedIn('cn', 'voltron', ipVersion=6) self.assertFalse(filtre(self.bridge)) def test_byNotBlockedIn_no_countryCode_no_transports(self): """A bridge without any transports should cause byNotBlockedIn('voltron') to return False (because it calls filters.byTransport('voltron')). """ filtre = filters.byNotBlockedIn(None, methodname='voltron') self.assertFalse(filtre(self.bridge)) def test_byNotBlockedIn_no_transports(self): """A bridge without any transports should cause byNotBlockedIn('cn', 'voltron') to return False. """ filtre = filters.byNotBlockedIn('cn', methodname='voltron') self.assertFalse(filtre(self.bridge)) def test_byNotBlockedIn_no_transports_blocked(self): """A bridge without any transports which is also blocked should cause byNotBlockedIn('voltron') to return False. """ self.bridge.setBlockedIn('cn') filtre = filters.byNotBlockedIn('cn', methodname='voltron') self.assertFalse(filtre(self.bridge)) def test_byNotBlockedIn_wrong_transport(self): """A bridge with only a Voltron transport should cause byNotBlockedIn('obfs3') to return False. """ self.addIPv4VoltronPT() filtre = filters.byNotBlockedIn('cn', methodname='obfs3') self.assertFalse(filtre(self.bridge)) def test_byNotBlockedIn_ipv5(self): """Calling byNotBlockedIn([…], ipVersion=5) should default to IPv4.""" self.bridge.setBlockedIn('ru') filtre = filters.byNotBlockedIn('cn', ipVersion=5) self.assertTrue(filtre(self.bridge)) def test_byNotBlockedIn_vanilla_not_blocked(self): """Calling byNotBlockedIn('vanilla') should return the IPv4 vanilla address, if it is not blocked. """ self.bridge.setBlockedIn('ru') filtre = filters.byNotBlockedIn('cn', methodname='vanilla') self.assertTrue(filtre(self.bridge)) def test_byNotBlockedIn_vanilla_not_blocked_ipv6(self): """Calling byNotBlockedIn('vanilla', ipVersion=6) should not return the IPv4 vanilla address, even if it is not blocked, because it has the wrong IP version. """ self.bridge.setBlockedIn('ru') filtre = filters.byNotBlockedIn('cn', methodname='vanilla', ipVersion=6) self.assertFalse(filtre(self.bridge)) def test_byNotBlockedIn_vanilla_blocked(self): """Calling byNotBlockedIn('vanilla') should not return the IPv4 vanilla address, if it is blocked. """ self.bridge.setBlockedIn('ru') filtre = filters.byNotBlockedIn('ru', methodname='vanilla') self.assertFalse(filtre(self.bridge))
def load(state, hashring, clear=False): """Read and parse all descriptors, and load into a bridge hashring. Read all the appropriate bridge files from the saved :class:`~bridgedb.persistent.State`, parse and validate them, and then store them into our ``state.hashring`` instance. The ``state`` will be saved again at the end of this function. :type hashring: :class:`~bridgedb.bridgerings.BridgeSplitter` :param hashring: A class which provides a mechanism for HMACing Bridges in order to assign them to hashrings. :param boolean clear: If True, clear all previous bridges from the hashring before parsing for new ones. """ if not state: logging.fatal("bridgedb.main.load() could not retrieve state!") sys.exit(2) if clear: logging.info("Clearing old bridges...") hashring.clear() logging.info("Loading bridges...") ignoreNetworkstatus = state.IGNORE_NETWORKSTATUS if ignoreNetworkstatus: logging.info("Ignoring BridgeAuthority networkstatus documents.") for auth in state.BRIDGE_AUTHORITY_DIRECTORIES: logging.info("Processing descriptors in %s directory..." % auth) bridges = {} timestamps = {} fn = expandBridgeAuthDir(auth, state.STATUS_FILE) logging.info("Opening networkstatus file: %s" % fn) networkstatuses = descriptors.parseNetworkStatusFile(fn) logging.debug("Closing networkstatus file: %s" % fn) logging.info("Processing networkstatus descriptors...") for router in networkstatuses: bridge = Bridge() bridge.updateFromNetworkStatus(router, ignoreNetworkstatus) try: bridge.assertOK() except MalformedBridgeInfo as error: logging.warn(str(error)) else: bridges[bridge.fingerprint] = bridge for filename in state.BRIDGE_FILES: fn = expandBridgeAuthDir(auth, filename) logging.info("Opening bridge-server-descriptor file: '%s'" % fn) serverdescriptors = descriptors.parseServerDescriptorsFile(fn) logging.debug("Closing bridge-server-descriptor file: '%s'" % fn) for router in serverdescriptors: try: bridge = bridges[router.fingerprint] except KeyError: logging.warn(( "Received server descriptor for bridge '%s' which wasn't " "in the networkstatus!") % router.fingerprint) if ignoreNetworkstatus: bridge = Bridge() else: continue try: bridge.updateFromServerDescriptor(router, ignoreNetworkstatus) except (ServerDescriptorWithoutNetworkstatus, MissingServerDescriptorDigest, ServerDescriptorDigestMismatch) as error: logging.warn(str(error)) # Reject any routers whose server descriptors didn't pass # :meth:`~bridges.Bridge._checkServerDescriptor`, i.e. those # bridges who don't have corresponding networkstatus # documents, or whose server descriptor digests don't check # out: bridges.pop(router.fingerprint) continue if state.COLLECT_TIMESTAMPS: # Update timestamps from server descriptors, not from network # status descriptors (because networkstatus documents and # descriptors aren't authenticated in any way): if bridge.fingerprint in timestamps.keys(): timestamps[bridge.fingerprint].append(router.published) else: timestamps[bridge.fingerprint] = [router.published] eifiles = [ expandBridgeAuthDir(auth, fn) for fn in state.EXTRA_INFO_FILES ] extrainfos = descriptors.parseExtraInfoFiles(*eifiles) for fingerprint, router in extrainfos.items(): try: bridges[fingerprint].updateFromExtraInfoDescriptor(router) except MalformedBridgeInfo as error: logging.warn(str(error)) except KeyError as error: logging.warn( ("Received extrainfo descriptor for bridge '%s', " "but could not find bridge with that fingerprint.") % router.fingerprint) blacklist = parseBridgeBlacklistFile(state.NO_DISTRIBUTION_FILE) inserted = 0 logging.info( "Trying to insert %d bridges into hashring, %d of which " "have the 'Running' flag..." % (len(bridges), len(list(filter(lambda b: b.flags.running, bridges.values()))))) for fingerprint, bridge in bridges.items(): # Skip insertion of bridges which are geolocated to be in one of the # NO_DISTRIBUTION_COUNTRIES, a.k.a. the countries we don't distribute # bridges from: if bridge.country in state.NO_DISTRIBUTION_COUNTRIES: logging.warn( "Not distributing Bridge %s %s:%s in country %s!" % (bridge, bridge.address, bridge.orPort, bridge.country)) # Skip insertion of blacklisted bridges. elif bridge in blacklist.keys(): logging.warn( "Not distributing blacklisted Bridge %s %s:%s: %s" % (bridge, bridge.address, bridge.orPort, blacklist[bridge])) # Skip bridges that are running a blacklisted version of Tor. elif bridge.runsVersion(state.BLACKLISTED_TOR_VERSIONS): logging.warn( "Not distributing bridge %s because it runs blacklisted " "Tor version %s." % (router.fingerprint, bridge.software)) else: # If the bridge is not running, then it is skipped during the # insertion process. hashring.insert(bridge) inserted += 1 logging.info("Tried to insert %d bridges into hashring. Resulting " "hashring is of length %d." % (inserted, len(hashring))) if state.COLLECT_TIMESTAMPS: reactor.callInThread(updateBridgeHistory, bridges, timestamps) state.save()
def load(state, hashring, clear=False): """Read and parse all descriptors, and load into a bridge hashring. Read all the appropriate bridge files from the saved :class:`~bridgedb.persistent.State`, parse and validate them, and then store them into our ``state.hashring`` instance. The ``state`` will be saved again at the end of this function. :type hashring: :class:`~bridgedb.Bridges.BridgeSplitter` :param hashring: A class which provides a mechanism for HMACing Bridges in order to assign them to hashrings. :param boolean clear: If True, clear all previous bridges from the hashring before parsing for new ones. """ if not state: logging.fatal("bridgedb.main.load() could not retrieve state!") sys.exit(2) if clear: logging.info("Clearing old bridges...") hashring.clear() logging.info("Loading bridges...") ignoreNetworkstatus = state.IGNORE_NETWORKSTATUS if ignoreNetworkstatus: logging.info("Ignoring BridgeAuthority networkstatus documents.") for auth in state.BRIDGE_AUTHORITY_DIRECTORIES: logging.info("Processing descriptors in %s directory..." % auth) bridges = {} timestamps = {} fn = expandBridgeAuthDir(auth, state.STATUS_FILE) logging.info("Opening networkstatus file: %s" % fn) networkstatuses = descriptors.parseNetworkStatusFile(fn) logging.debug("Closing networkstatus file: %s" % fn) logging.info("Processing networkstatus descriptors...") for router in networkstatuses: bridge = Bridge() bridge.updateFromNetworkStatus(router, ignoreNetworkstatus) try: bridge.assertOK() except MalformedBridgeInfo as error: logging.warn(str(error)) else: bridges[bridge.fingerprint] = bridge for filename in state.BRIDGE_FILES: fn = expandBridgeAuthDir(auth, filename) logging.info("Opening bridge-server-descriptor file: '%s'" % fn) serverdescriptors = descriptors.parseServerDescriptorsFile(fn) logging.debug("Closing bridge-server-descriptor file: '%s'" % fn) for router in serverdescriptors: try: bridge = bridges[router.fingerprint] except KeyError: logging.warn( ("Received server descriptor for bridge '%s' which wasn't " "in the networkstatus!") % router.fingerprint) if ignoreNetworkstatus: bridge = Bridge() else: continue try: bridge.updateFromServerDescriptor(router, ignoreNetworkstatus) except (ServerDescriptorWithoutNetworkstatus, MissingServerDescriptorDigest, ServerDescriptorDigestMismatch) as error: logging.warn(str(error)) # Reject any routers whose server descriptors didn't pass # :meth:`~bridges.Bridge._checkServerDescriptor`, i.e. those # bridges who don't have corresponding networkstatus # documents, or whose server descriptor digests don't check # out: bridges.pop(router.fingerprint) continue if state.COLLECT_TIMESTAMPS: # Update timestamps from server descriptors, not from network # status descriptors (because networkstatus documents and # descriptors aren't authenticated in any way): if bridge.fingerprint in timestamps.keys(): timestamps[bridge.fingerprint].append(router.published) else: timestamps[bridge.fingerprint] = [router.published] eifiles = [expandBridgeAuthDir(auth, fn) for fn in state.EXTRA_INFO_FILES] extrainfos = descriptors.parseExtraInfoFiles(*eifiles) for fingerprint, router in extrainfos.items(): try: bridges[fingerprint].updateFromExtraInfoDescriptor(router) except MalformedBridgeInfo as error: logging.warn(str(error)) except KeyError as error: logging.warn(("Received extrainfo descriptor for bridge '%s', " "but could not find bridge with that fingerprint.") % router.fingerprint) blacklist = parseBridgeBlacklistFile(state.NO_DISTRIBUTION_FILE) inserted = 0 logging.info("Inserting %d bridges into hashring..." % len(bridges)) for fingerprint, bridge in bridges.items(): # Skip insertion of bridges which are geolocated to be in one of the # NO_DISTRIBUTION_COUNTRIES, a.k.a. the countries we don't distribute # bridges from: if bridge.country in state.NO_DISTRIBUTION_COUNTRIES: logging.warn("Not distributing Bridge %s %s:%s in country %s!" % (bridge, bridge.address, bridge.orPort, bridge.country)) # Skip insertion of blacklisted bridges. elif bridge in blacklist.keys(): logging.warn("Not distributing blacklisted Bridge %s %s:%s: %s" % (bridge, bridge.address, bridge.orPort, blacklist[bridge])) else: # If the bridge is not running, then it is skipped during the # insertion process. hashring.insert(bridge) inserted += 1 logging.info("Done inserting %d bridges into hashring." % inserted) if state.COLLECT_TIMESTAMPS: reactor.callInThread(updateBridgeHistory, bridges, timestamps) state.save()
def load(state, splitter, clear=False): """Read and parse all descriptors, and load into a bridge splitter. Read all the appropriate bridge files from the saved :class:`~bridgedb.persistent.State`, parse and validate them, and then store them into our ``state.splitter`` instance. The ``state`` will be saved again at the end of this function. :type splitter: :class:`BridgeSplitter <bridgedb.Bridges.BridgeHolder>` :param splitter: A class which provides a mechanism for HMACing Bridges in order to assign them to hashrings. :param boolean clear: If True, clear all previous bridges from the splitter before parsing for new ones. """ if not state: logging.fatal("bridgedb.Main.load() could not retrieve state!") sys.exit(2) if clear: logging.info("Clearing old bridges...") splitter.clear() logging.info("Loading bridges...") ignoreNetworkstatus = state.IGNORE_NETWORKSTATUS if ignoreNetworkstatus: logging.info("Ignoring BridgeAuthority networkstatus documents.") bridges = {} timestamps = {} logging.info("Opening networkstatus file: %s" % state.STATUS_FILE) networkstatuses = descriptors.parseNetworkStatusFile(state.STATUS_FILE) logging.debug("Closing networkstatus file: %s" % state.STATUS_FILE) logging.info("Processing networkstatus descriptors...") for router in networkstatuses: bridge = Bridge() bridge.updateFromNetworkStatus(router, ignoreNetworkstatus) try: bridge.assertOK() except MalformedBridgeInfo as error: logging.warn(str(error)) else: bridges[bridge.fingerprint] = bridge for filename in state.BRIDGE_FILES: logging.info("Opening bridge-server-descriptor file: '%s'" % filename) serverdescriptors = descriptors.parseServerDescriptorsFile(filename) logging.debug("Closing bridge-server-descriptor file: '%s'" % filename) for router in serverdescriptors: try: bridge = bridges[router.fingerprint] except KeyError: logging.warn( ("Received server descriptor for bridge '%s' which wasn't " "in the networkstatus!") % router.fingerprint) if ignoreNetworkstatus: bridge = Bridge() else: continue try: bridge.updateFromServerDescriptor(router, ignoreNetworkstatus) except (ServerDescriptorWithoutNetworkstatus, MissingServerDescriptorDigest, ServerDescriptorDigestMismatch) as error: logging.warn(str(error)) # Reject any routers whose server descriptors didn't pass # :meth:`~bridges.Bridge._checkServerDescriptor`, i.e. those # bridges who don't have corresponding networkstatus # documents, or whose server descriptor digests don't check # out: bridges.pop(router.fingerprint) continue if state.COLLECT_TIMESTAMPS: # Update timestamps from server descriptors, not from network # status descriptors (because networkstatus documents and # descriptors aren't authenticated in any way): if bridge.fingerprint in timestamps.keys(): timestamps[bridge.fingerprint].append(router.published) else: timestamps[bridge.fingerprint] = [router.published] extrainfos = descriptors.parseExtraInfoFiles(*state.EXTRA_INFO_FILES) for fingerprint, router in extrainfos.items(): try: bridges[fingerprint].updateFromExtraInfoDescriptor(router) except MalformedBridgeInfo as error: logging.warn(str(error)) except KeyError as error: logging.warn(("Received extrainfo descriptor for bridge '%s', " "but could not find bridge with that fingerprint.") % router.fingerprint) inserted = 0 logging.info("Inserting %d bridges into splitter..." % len(bridges)) for fingerprint, bridge in bridges.items(): # Skip insertion of bridges which are geolocated to be in one of the # NO_DISTRIBUTION_COUNTRIES, a.k.a. the countries we don't distribute # bridges from: if bridge.country in state.NO_DISTRIBUTION_COUNTRIES: logging.warn( "Not distributing Bridge %s %s:%s in country %s!" % (bridge, bridge.address, bridge.orPort, bridge.country)) else: # If the bridge is not running, then it is skipped during the # insertion process. splitter.insert(bridge) inserted += 1 logging.info("Done inserting %d bridges into splitter." % inserted) if state.COLLECT_TIMESTAMPS: reactor.callInThread(updateBridgeHistory, bridges, timestamps) state.save()