def __init__(self, areaMapper, nClusters, key, ipCategories=None, answerParameters=None): """Create a Distributor that decides which bridges to distribute based upon the client's IP address and the current time. :type areaMapper: callable :param areaMapper: A function that maps IP addresses arbitrarily to strings, such that addresses which map to identical strings are considered to be in the same "area" (for some arbitrary definition of "area"). See :func:`bridgedb.Dist.uniformMap` for an example. :param integer nClusters: The number of clusters to group IP addresses into. Note that if PROXY_LIST_FILES is set in bridgedb.conf, then the actual number of clusters is one higher than ``nClusters``, because the set of known open proxies constitutes its own category. DOCDOC What exactly does a cluster *do*? :param bytes key: The master HMAC key for this distributor. All added bridges are HMACed with this key in order to place them into the hashrings. :type ipCategories: iterable or None :param ipCategories: DOCDOC :type answerParameters: :class:`bridgedb.Bridges.BridgeRingParameters` :param answerParameters: A mechanism for ensuring that the set of bridges that this distributor answers a client with fit certain parameters, i.e. that an answer has "at least two obfsproxy bridges" or "at least one bridge on port 443", etc. """ self.areaMapper = areaMapper self.nClusters = nClusters self.answerParameters = answerParameters if not ipCategories: ipCategories = [] if not answerParameters: answerParameters = [] self.rings = [] self.categories = [] for c in ipCategories: self.categories.append(c) key2 = getHMAC(key, "Assign-Bridges-To-Rings") key3 = getHMAC(key, "Order-Areas-In-Rings") self.areaOrderHmac = getHMACFunc(key3, hex=False) key4 = getHMAC(key, "Assign-Areas-To-Rings") self.areaClusterHmac = getHMACFunc(key4, hex=True) # add splitter and cache the default rings # plus leave room for dynamic filters # # XXX Why is the "extra room" hardcoded to be 5? Shouldn't it be some # fraction of the number of clusters/categories? --isis ring_cache_size = self.nClusters + len(ipCategories) + 5 self.splitter = bridgedb.Bridges.FilteredBridgeSplitter( key2, max_cached_rings=ring_cache_size) logging.debug("Added splitter %s to IPBasedDistributor." % self.splitter.__class__) self.setDistributorName('HTTPS')
def __init__(self, totalSubrings, key, proxies=None, answerParameters=None): """Create a Distributor that decides which bridges to distribute based upon the client's IP address and the current time. :param int totalSubrings: The number of subhashrings to group clients into. Note that if ``PROXY_LIST_FILES`` is set in bridgedb.conf, then the actual number of clusters is one higher than ``totalSubrings``, because the set of all known open proxies is given its own subhashring. :param bytes key: The master HMAC key for this distributor. All added bridges are HMACed with this key in order to place them into the hashrings. :type proxies: :class:`~bridgedb.proxy.ProxySet` :param proxies: A :class:`bridgedb.proxy.ProxySet` containing known Tor Exit relays and other known proxies. These will constitute the extra cluster, and any client requesting bridges from one of these **proxies** will be distributed bridges from a separate subhashring that is specific to Tor/proxy users. :type answerParameters: :class:`bridgedb.bridgerings.BridgeRingParameters` :param answerParameters: A mechanism for ensuring that the set of bridges that this distributor answers a client with fit certain parameters, i.e. that an answer has "at least two obfsproxy bridges" or "at least one bridge on port 443", etc. """ super(HTTPSDistributor, self).__init__(key) self.totalSubrings = totalSubrings self.answerParameters = answerParameters if proxies: logging.info("Added known proxies to HTTPS distributor...") self.proxies = proxies self.totalSubrings += 1 self.proxySubring = self.totalSubrings else: logging.warn("No known proxies were added to HTTPS distributor!") self.proxies = proxy.ProxySet() self.proxySubring = 0 self.ringCacheSize = self.totalSubrings * 3 key2 = getHMAC(key, "Assign-Bridges-To-Rings") key3 = getHMAC(key, "Order-Areas-In-Rings") key4 = getHMAC(key, "Assign-Areas-To-Rings") self._clientToPositionHMAC = getHMACFunc(key3, hex=False) self._subnetToSubringHMAC = getHMACFunc(key4, hex=True) self.hashring = FilteredBridgeSplitter(key2, self.ringCacheSize) self.name = 'HTTPS' logging.debug("Added %s to %s distributor." % (self.hashring.__class__.__name__, self.name))
def __init__(self, totalSubrings, key, proxies=None, answerParameters=None): """Create a Distributor that decides which bridges to distribute based upon the client's IP address and the current time. :param int totalSubrings: The number of subhashrings to group clients into. Note that if ``PROXY_LIST_FILES`` is set in bridgedb.conf, then the actual number of clusters is one higher than ``totalSubrings``, because the set of all known open proxies is given its own subhashring. :param bytes key: The master HMAC key for this distributor. All added bridges are HMACed with this key in order to place them into the hashrings. :type proxies: :class:`~bridgedb.proxy.ProxySet` :param proxies: A :class:`bridgedb.proxy.ProxySet` containing known Tor Exit relays and other known proxies. These will constitute the extra cluster, and any client requesting bridges from one of these **proxies** will be distributed bridges from a separate subhashring that is specific to Tor/proxy users. :type answerParameters: :class:`bridgedb.Bridges.BridgeRingParameters` :param answerParameters: A mechanism for ensuring that the set of bridges that this distributor answers a client with fit certain parameters, i.e. that an answer has "at least two obfsproxy bridges" or "at least one bridge on port 443", etc. """ super(HTTPSDistributor, self).__init__(key) self.totalSubrings = totalSubrings self.answerParameters = answerParameters if proxies: logging.info("Added known proxies to HTTPS distributor...") self.proxies = proxies self.totalSubrings += 1 self.proxySubring = self.totalSubrings else: logging.warn("No known proxies were added to HTTPS distributor!") self.proxies = proxy.ProxySet() self.proxySubring = 0 self.ringCacheSize = self.totalSubrings * 3 key2 = getHMAC(key, "Assign-Bridges-To-Rings") key3 = getHMAC(key, "Order-Areas-In-Rings") key4 = getHMAC(key, "Assign-Areas-To-Rings") self._clientToPositionHMAC = getHMACFunc(key3, hex=False) self._subnetToSubringHMAC = getHMACFunc(key4, hex=True) self.hashring = FilteredBridgeSplitter(key2, self.ringCacheSize) self.name = 'HTTPS' logging.debug("Added %s to %s distributor." % (self.hashring.__class__.__name__, self.name))
def __init__(self, key): self.hmac = getHMACFunc(key, hex=True) self.ringsByName = {} self.totalP = 0 self.pValues = [] self.rings = [] self.statsHolders = []
def __init__(self, key, max_cached_rings=3): """Create a hashring which filters bridges into sub hashrings. :type key: DOCDOC :param key: An HMAC key. :param int max_cached_rings: XXX max_cached_rings appears to not be used anywhere. :ivar filterRings: A dictionary of subrings which has the form ``{ringname: (filterFn, subring)}``, where: - ``ringname`` is a unique string identifying the subring. - ``filterFn`` is a callable which filters Bridges in some manner, i.e. by whether they are IPv4 or IPv6, etc. - ``subring`` is any of the horribly-implemented, I-guess-it-passes-for-some-sort-of-hashring classes in this module. :ivar hmac: DOCDOC :ivar bridges: DOCDOC :type distributorName: str :ivar distributorName: The name of this splitter's distributor. See :meth:`~bridgedb.distributors.https.distributor.HTTPSDistributor.setDistributorName`. """ self.key = key self.filterRings = {} self.hmac = getHMACFunc(key, hex=True) self.bridges = [] self.distributorName = '' #XXX: unused self.max_cached_rings = max_cached_rings
def __init__(self, key, domainmap, domainrules, answerParameters=None, whitelist=None): """Create a bridge distributor which uses email. :type emailHmac: callable :param emailHmac: An hmac function used to order email addresses within a ring. See :func:`~bridgedb.crypto.getHMACFunc`. :param dict domainmap: A map from lowercase domains that we support mail from to their canonical forms. See `EMAIL_DOMAIN_MAP` option in `bridgedb.conf`. :param domainrules: DOCDOC :param answerParameters: DOCDOC :type whitelist: dict or ``None`` :param whitelist: A dictionary that maps whitelisted email addresses to GnuPG fingerprints. """ super(EmailDistributor, self).__init__(key) self.domainmap = domainmap self.domainrules = domainrules self.whitelist = whitelist or dict() self.answerParameters = answerParameters key1 = getHMAC(key, "Map-Addresses-To-Ring") key2 = getHMAC(key, "Order-Bridges-In-Ring") self.emailHmac = getHMACFunc(key1, hex=False) #XXX cache options not implemented self.hashring = FilteredBridgeSplitter(key2, max_cached_rings=5) self.name = "Email"
def __init__(self, key, domainmap, domainrules, answerParameters=None): """Create a bridge distributor which uses email. :type emailHmac: callable :param emailHmac: An hmac function used to order email addresses within a ring. See :func:`~bridgedb.crypto.getHMACFunc`. :param dict domainmap: A map from lowercase domains that we support mail from to their canonical forms. See `EMAIL_DOMAIN_MAP` option in `bridgedb.conf`. :param domainrules: DOCDOC :param answerParameters: DOCDOC """ key1 = getHMAC(key, "Map-Addresses-To-Ring") self.emailHmac = getHMACFunc(key1, hex=False) key2 = getHMAC(key, "Order-Bridges-In-Ring") # XXXX clear the store when the period rolls over! self.domainmap = domainmap self.domainrules = domainrules self.answerParameters = answerParameters #XXX cache options not implemented self.splitter = bridgedb.Bridges.FilteredBridgeSplitter( key2, max_cached_rings=5) self.setDistributorName('Email')
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 getHashringPlacement(self, key, client=None): """Create an HMAC of some **client** info using a **key**. :param str key: The key to use for HMACing. :param str client: Some (hopefully unique) information about the client who is requesting bridges, such as an IP or email address. :rtype: long :returns: A long specifying index of the first node in a hashring to be distributed to the client. This value should obviously be used mod the number of nodes in the hashring. """ if not client: client = self.client # Get an HMAC with the key of the client identifier: digest = getHMACFunc(key)(client) # Take the lower 8 bytes of the digest and convert to a long: position = long(digest[:8], 16) return position
def getHashringPlacement(self, key, client=None): """Create an HMAC of some **client** info using a **key**. :param str key: The key to use for HMACing. :param str client: Some (hopefully unique) information about the client who is requesting bridges, such as an IP or email address. :rtype: long :returns: A long specifying index of the first node in a hashring to be distributed to the client. This value should obviously be used mod the number of nodes in the hashring. """ if not client: client = type('')(self.client) # Get an HMAC with the key of the client identifier: digest = getHMACFunc(key)(client) # Take the lower 8 bytes of the digest and convert to a long: position = int(digest[:8], 16) return position
def __init__(self, key, rings): self.hmac = getHMACFunc(key, hex=True) self.rings = rings[:]
def __init__(self, key, rings): self.hmac = getHMACFunc(key, hex=True) self.rings = rings[:] for r in self.rings: assert (isinstance(r, BridgeHolder))
def __init__(self, key, rings): self.hmac = getHMACFunc(key, hex=True) self.rings = rings[:] for r in self.rings: assert(isinstance(r, BridgeHolder))
def __init__(self, key, answerParameters=None): """Create a new BridgeRing, using key as its hmac key. :type key: bytes :param key: The HMAC key, generated with :func:`~bridgedb.crypto.getKey`. :type answerParameters: :class:`BridgeRingParameters` :param answerParameters: DOCDOC :ivar dict bridges: A dictionary which maps HMAC keys to :class:`~bridgedb.bridges.Bridge`s. :ivar dict bridgesByID: A dictionary which maps raw hash digests of bridge ID keys to :class:`~bridgedb.bridges.Bridge`s. :type hmac: callable :ivar hmac: An HMAC function, which uses the **key** parameter to generate new HMACs for storing, inserting, and retrieving :class:`~bridgedb.bridges.Bridge`s within mappings. :ivar bool isSorted: ``True`` if ``sortedKeys`` is currently sorted. :ivar list sortedKeys: A sorted list of all of the HMACs. :ivar str name: A string which identifies this hashring, used mostly for differentiating this hashring in log messages, but it is also used for naming subrings. If this hashring is a subring, the ``name`` will include whatever distinguishing parameters differentiate that particular subring (i.e. ``'(port-443 subring)'`` or ``'(Stable subring)'``) :type subrings: list :ivar subrings: A list of other ``BridgeRing``s, each of which contains bridges of a particular type. For example, a subring might contain only ``Bridge``s which have been given the "Stable" flag, or it might contain only IPv6 bridges. Each item in this list should be a 4-tuple:: (type, value, count, ring) where: - ``type`` is a string which describes what kind of parameter is used to determine if a ``Bridge`` belongs in that subring, i.e. ``'port'`` or ``'flag'``. - ``value`` is a specific value pertaining to the ``type``, e.g. ``type='port'; value=443``. - ``count`` is an integer for the current total number of bridges in the subring. - ``ring`` is a :class:`BridgeRing`; it is the subhashring which contains ``count`` number of :class:`~bridgedb.bridges.Bridge`s of a certain ``type``. """ self.bridges = {} self.bridgesByID = {} self.hmac = getHMACFunc(key, hex=False) self.isSorted = False self.sortedKeys = [] if answerParameters is None: answerParameters = BridgeRingParameters() self.answerParameters = answerParameters self.subrings = [] for port, count in self.answerParameters.needPorts: #note that we really need to use the same key here, so that # the mapping is in the same order for all subrings. self.subrings.append(('port', port, count, BridgeRing(key, None))) for flag, count in self.answerParameters.needFlags: self.subrings.append(('flag', flag, count, BridgeRing(key, None))) self.setName("Ring")
def __init__(self, key, answerParameters=None): """Create a new BridgeRing, using key as its hmac key. :type key: bytes :param key: The HMAC key, generated with :func:`~bridgedb.crypto.getKey`. :type answerParameters: :class:`BridgeRingParameters` :param answerParameters: DOCDOC :ivar dict bridges: A dictionary which maps HMAC keys to :class:`~bridgedb.bridges.Bridge`s. :ivar dict bridgesByID: A dictionary which maps raw hash digests of bridge ID keys to :class:`~bridgedb.bridges.Bridge`s. :type hmac: callable :ivar hmac: An HMAC function, which uses the **key** parameter to generate new HMACs for storing, inserting, and retrieving :class:`~bridgedb.bridges.Bridge`s within mappings. :ivar bool isSorted: ``True`` if ``sortedKeys`` is currently sorted. :ivar list sortedKeys: A sorted list of all of the HMACs. :ivar str name: A string which identifies this hashring, used mostly for differentiating this hashring in log messages, but it is also used for naming subrings. If this hashring is a subring, the ``name`` will include whatever distinguishing parameters differentiate that particular subring (i.e. ``'(port-443 subring)'`` or ``'(Stable subring)'``) :type subrings: list :ivar subrings: A list of other ``BridgeRing``s, each of which contains bridges of a particular type. For example, a subring might contain only ``Bridge``s which have been given the "Stable" flag, or it might contain only IPv6 bridges. Each item in this list should be a 4-tuple:: (type, value, count, ring) where: - ``type`` is a string which describes what kind of parameter is used to determine if a ``Bridge`` belongs in that subring, i.e. ``'port'`` or ``'flag'``. - ``value`` is a specific value pertaining to the ``type``, e.g. ``type='port'; value=443``. - ``count`` is an integer for the current total number of bridges in the subring. - ``ring`` is a :class:`BridgeRing`; it is the subhashring which contains ``count`` number of :class:`~bridgedb.bridges.Bridge`s of a certain ``type``. """ self.bridges = {} self.bridgesByID = {} self.hmac = getHMACFunc(key, hex=False) self.isSorted = False self.sortedKeys = [] if answerParameters is None: answerParameters = BridgeRingParameters() self.answerParameters = answerParameters self.subrings = [] for port,count in self.answerParameters.needPorts: #note that we really need to use the same key here, so that # the mapping is in the same order for all subrings. self.subrings.append( ('port',port,count,BridgeRing(key,None)) ) for flag,count in self.answerParameters.needFlags: self.subrings.append( ('flag',flag,count,BridgeRing(key,None)) ) self.setName("Ring")