Beispiel #1
0
def _pick_ideal_second_hop(relay, dest, rl, cont, is_exit):
    '''
    Sbws builds two hop circuits. Given the **relay** to measure with
    destination **dest**, pick a second relay that is or is not an exit
    according to **is_exit**.
    '''
    candidates = []
    candidates.extend(rl.exits if is_exit else rl.non_exits)
    if not len(candidates):
        return None
    log.debug('Picking a 2nd hop to measure %s from %d choices. is_exit=%s',
              relay.nickname, len(candidates), is_exit)
    for min_bw_factor in [2, 1.75, 1.5, 1.25, 1]:
        min_bw = relay.bandwidth * min_bw_factor
        new_candidates = stem_utils.only_relays_with_bandwidth(cont,
                                                               candidates,
                                                               min_bw=min_bw)
        if len(new_candidates) > 0:
            chosen = rng.choice(new_candidates)
            log.debug(
                'Found %d candidate 2nd hops with at least %sx the bandwidth '
                'of %s. Returning %s (bw=%s).', len(new_candidates),
                min_bw_factor, relay.nickname, chosen.nickname,
                chosen.bandwidth)
            return chosen
    candidates = sorted(candidates, key=lambda r: r.bandwidth, reverse=True)
    chosen = candidates[0]
    log.debug(
        'Didn\'t find any 2nd hops at least as fast as %s (bw=%s). It\'s '
        'probably really fast. Returning %s (bw=%s), the fastest '
        'candidate we have.', relay.nickname, relay.bandwidth, chosen.nickname,
        chosen.bandwidth)
    return chosen
Beispiel #2
0
def _pick_ideal_second_hop(relay, dest, rl, cont, is_exit):
    '''
    Sbws builds two hop circuits. Given the **relay** to measure with
    destination **dest**, pick a second relay that is or is not an exit
    according to **is_exit**.
    '''
    # 40041: Instead of using exits that can exit to all IPs, to ensure that
    # they can make requests to the Web servers, try with the exits that
    # allow some IPs, since there're more.
    # In the case that a concrete exit can't exit to the Web server, it is not
    # a problem since the relay will be measured in the next loop with other
    # random exit.
    candidates = rl.exits_not_bad_allowing_port(dest.port) \
        if is_exit else rl.non_exits
    if not len(candidates):
        return None
    # In the case the helper is an exit, the entry could be an exit too
    # (#40041), so ensure the helper is not the same as the entry, likely to
    # happen in a test network.
    if is_exit:
        candidates = [
            c for c in candidates if c.fingerprint != relay.fingerprint
        ]
    min_relay_bw = rl.exit_min_bw() if is_exit else rl.non_exit_min_bw()
    log.debug('Picking a 2nd hop to measure %s from %d choices. is_exit=%s',
              relay.nickname, len(candidates), is_exit)
    for min_bw_factor in [2, 1.75, 1.5, 1.25, 1]:
        min_bw = relay.consensus_bandwidth * min_bw_factor
        # We might have a really slow/new relay. Try to measure it properly by
        # using only relays with or above our calculated min_relay_bw (see:
        # _calculate_min_bw_second_hop() in relaylist.py).
        if min_bw < min_relay_bw:
            min_bw = min_relay_bw
        new_candidates = stem_utils.only_relays_with_bandwidth(cont,
                                                               candidates,
                                                               min_bw=min_bw)
        if len(new_candidates) > 0:
            chosen = rng.choice(new_candidates)
            log.debug(
                'Found %d candidate 2nd hops with at least %sx the bandwidth '
                'of %s. Returning %s (bw=%s).', len(new_candidates),
                min_bw_factor, relay.nickname, chosen.nickname,
                chosen.consensus_bandwidth)
            return chosen
    candidates = sorted(candidates,
                        key=lambda r: r.consensus_bandwidth,
                        reverse=True)
    chosen = candidates[0]
    log.debug(
        'Didn\'t find any 2nd hops at least as fast as %s (bw=%s). It\'s '
        'probably really fast. Returning %s (bw=%s), the fastest '
        'candidate we have.', relay.nickname, relay.consensus_bandwidth,
        chosen.nickname, chosen.consensus_bandwidth)
    return chosen
Beispiel #3
0
def _pick_ideal_second_hop(relay, dest, rl, cont, is_exit):
    '''
    Sbws builds two hop circuits. Given the **relay** to measure with
    destination **dest**, pick a second relay that is or is not an exit
    according to **is_exit**.
    '''
    candidates = rl.exits_not_bad_allowing_port(dest.port) if is_exit \
        else rl.non_exits
    if not len(candidates):
        return None
    min_relay_bw = rl.exit_min_bw() if is_exit else rl.non_exit_min_bw()
    log.debug('Picking a 2nd hop to measure %s from %d choices. is_exit=%s',
              relay.nickname, len(candidates), is_exit)
    for min_bw_factor in [2, 1.75, 1.5, 1.25, 1]:
        min_bw = relay.consensus_bandwidth * min_bw_factor
        # We might have a really slow/new relay. Try to measure it properly by
        # using only relays with or above our calculated min_relay_bw (see:
        # _calculate_min_bw_second_hop() in relaylist.py).
        if min_bw < min_relay_bw:
            min_bw = min_relay_bw
        new_candidates = stem_utils.only_relays_with_bandwidth(cont,
                                                               candidates,
                                                               min_bw=min_bw)
        if len(new_candidates) > 0:
            chosen = rng.choice(new_candidates)
            log.debug(
                'Found %d candidate 2nd hops with at least %sx the bandwidth '
                'of %s. Returning %s (bw=%s).', len(new_candidates),
                min_bw_factor, relay.nickname, chosen.nickname,
                chosen.consensus_bandwidth)
            return chosen
    candidates = sorted(candidates,
                        key=lambda r: r.consensus_bandwidth,
                        reverse=True)
    chosen = candidates[0]
    log.debug(
        'Didn\'t find any 2nd hops at least as fast as %s (bw=%s). It\'s '
        'probably really fast. Returning %s (bw=%s), the fastest '
        'candidate we have.', relay.nickname, relay.consensus_bandwidth,
        chosen.nickname, chosen.consensus_bandwidth)
    return chosen
Beispiel #4
0
def measure_relay(args, conf, destinations, cb, rl, relay):
    s = requests_utils.make_session(cb.controller,
                                    conf.getfloat('general', 'http_timeout'))
    # Pick a destionation
    dest = destinations.next()
    if not dest:
        log.warning('Unable to get destination to measure %s %s',
                    relay.nickname, relay.fingerprint[0:8])
        return None
    # Pick an exit
    exits = rl.exits_can_exit_to(dest.hostname, dest.port)
    exits = [e for e in exits if e.fingerprint != relay.fingerprint]
    exits = stem_utils.only_relays_with_bandwidth(
        cb.controller,
        exits,
        min_bw=round(relay.bandwidth * 1.25),
        max_bw=max(round(relay.bandwidth * 2.00), 100))
    if len(exits) < 1:
        log.warning('No available exits to help measure %s %s', relay.nickname,
                    relay.fingerprint[0:8])
        # TODO: Return ResultError of some sort
        return None
    exit = rng.choice(exits)
    # Build the circuit
    log.debug('We selected exit %s %s (cw=%d) to help measure %s %s (cw=%d)',
              exit.nickname, exit.fingerprint[0:8], exit.bandwidth,
              relay.nickname, relay.fingerprint[0:8], relay.bandwidth)
    our_nick = conf['scanner']['nickname']
    circ_fps = [relay.fingerprint, exit.fingerprint]
    circ_id = cb.build_circuit(circ_fps)
    if not circ_id:
        log.warning('Could not build circuit involving %s', relay.nickname)
        msg = 'Unable to complete circuit'
        return [
            ResultErrorCircuit(relay, circ_fps, dest.url, our_nick, msg=msg),
        ]
    log.debug('Built circ %s %s for relay %s %s', circ_id,
              stem_utils.circuit_str(cb.controller, circ_id), relay.nickname,
              relay.fingerprint[0:8])
    # Make a connection to the destionation webserver and make sure it can
    # still help us measure
    is_usable, usable_data = dest.is_usable(circ_id, s, cb.controller)
    if not is_usable:
        log.warning(
            'When measuring %s %s the destination seemed to have '
            'stopped being usable: %s', relay.nickname, relay.fingerprint[0:8],
            usable_data)
        cb.close_circuit(circ_id)
        # TODO: Return a different/new type of ResultError?
        msg = 'The destination seemed to have stopped being usable'
        return [
            ResultErrorStream(relay, circ_fps, dest.url, our_nick, msg=msg),
        ]
    assert is_usable
    assert 'content_length' in usable_data
    # FIRST: measure RTT
    rtts = measure_rtt_to_server(s, conf, dest, usable_data['content_length'])
    if rtts is None:
        log.warning('Unable to measure RTT to %s via relay %s %s', dest.url,
                    relay.nickname, relay.fingerprint[0:8])
        cb.close_circuit(circ_id)
        # TODO: Return a different/new type of ResultError?
        msg = 'Something bad happened while measuring RTTs'
        return [
            ResultErrorStream(relay, circ_fps, dest.url, our_nick, msg=msg),
        ]
    # SECOND: measure bandwidth
    bw_results = measure_bandwidth_to_server(s, conf, dest,
                                             usable_data['content_length'])
    if bw_results is None:
        log.warning('Unable to measure bandwidth to %s via relay %s %s',
                    dest.url, relay.nickname, relay.fingerprint[0:8])
        cb.close_circuit(circ_id)
        # TODO: Return a different/new type of ResultError?
        msg = 'Something bad happened while measuring bandwidth'
        return [
            ResultErrorStream(relay, circ_fps, dest.url, our_nick, msg=msg),
        ]
    cb.close_circuit(circ_id)
    # Finally: store result
    return [
        ResultSuccess(rtts, bw_results, relay, circ_fps, dest.url, our_nick),
    ]