Beispiel #1
0
def create_circuit(cons_rel_stats, cons_valid_after, cons_fresh_until,
    cons_bw_weights, cons_bwweightscale, descriptors, hibernating_status,
    guards, circ_time, circ_fast, circ_stable, circ_internal, circ_ip,
    circ_port, congmodel, pdelmodel, weighted_exits=None,
    exits_exact=False, weighted_middles=None, weighted_guards=None, callbacks=None):
    """Creates path for requested circuit based on the input consensus
    statuses and descriptors. Uses congestion-aware path selection.
    Inputs:
        cons_rel_stats: (dict) relay fingerprint keys and relay status vals
        cons_valid_after: (int) timestamp of valid_after for consensus
        cons_fresh_until: (int) timestamp of fresh_until for consensus
        cons_bw_weights: (dict) bw_weights of consensus
        cons_bwweightscale: (should be float()able) bwweightscale of consensus
        descriptors: (dict) relay fingerprint keys and descriptor vals
        hibernating_status: (dict) indicates hibernating relays
        guards: (dict) contains guards of requesting client
        circ_time: (int) timestamp of circuit request
        circ_fast: (bool) all relays should be fast
        circ_stable: (bool) all relays should be stable
        circ_internal: (bool) circuit is for name resolution or hidden service
        circ_ip: (str) IP address of destination (None if not known)
        circ_port: (int) desired TCP port (None if not known)
        congmodel: congestion model
        pdelmodel: propagation delay model
        weighted_exits: (list) (middle, cum_weight) pairs for exit position
        exits_exact: (bool) Is weighted_exits exact or does it need rechecking?
            weighed_exits is special because exits are chosen first and thus
            don't depend on the other circuit positions, and so potentially are
            precomputed exactly.
        weighted_middles: (list) (middle, cum_weight) pairs for middle position
        weighted_guards: (list) (middle, cum_weight) pairs for middle position
        callbacks: object w/ method circuit_creation(circuit)
    Output:
        circuit: (dict) a newly created circuit with keys
            'time': (int) seconds from time zero
            'fast': (bool) relays must have Fast flag
            'stable': (bool) relays must have Stable flag
            'internal': (bool) is internal (e.g. for hidden service)
            'dirty_time': (int) timestamp of time dirtied, None if clean
            'path': (tuple) list in-order fingerprints for path's nodes
            'covering': (set) ports with needs covered by circuit
    """
#            'cons_rel_stats': (dict) relay stats for active consensus

    if (circ_time < cons_valid_after) or\
        (circ_time >= cons_fresh_until):
        raise ValueError('consensus not fresh for circ_time in create_circuit')

    # choose num_paths_choose paths, and choose one with best predicted latency
    best_latency = None
    best_path = None
    for k in xrange(num_paths_choose):
        print('Choosing path #{0} to predict latency'.format(k))
        num_attempts = 0
        ntor_supported = False
        while (num_attempts < pathsim.TorOptions.max_populate_attempts) and\
            (not ntor_supported):
            # select exit node
            i = 1
            while (True):
                exit_node = pathsim.select_exit_node(cons_bw_weights,
                    cons_bwweightscale,
                    cons_rel_stats, descriptors, circ_fast, circ_stable,
                    circ_internal, circ_ip, circ_port, weighted_exits, exits_exact)
        #        exit_node = select_weighted_node(weighted_exits)
                if (not hibernating_status[exit_node]):
                    break
                if _testing:
                    print('Exit selection #{0} is hibernating - retrying.'.\
                        format(i))
                i += 1
            if _testing:
                print('Exit node: {0} [{1}]'.format(
                    cons_rel_stats[exit_node].nickname,
                    cons_rel_stats[exit_node].fingerprint))

            # select guard node
            # Hibernation status again checked here to reflect how in Tor
            # new guards would be chosen and added to the list prior to a circuit-
            # creation attempt. If the circuit fails at a new guard, that guard
            # gets removed from the list.
            while True:
                # get first <= num_guards guards suitable for circuit
                circ_guards = pathsim.get_guards_for_circ(cons_bw_weights,\
                    cons_bwweightscale, cons_rel_stats, descriptors,\
                    circ_fast, circ_stable, guards,\
                    exit_node, circ_time, weighted_guards)
                guard_node = choice(circ_guards)
                if (hibernating_status[guard_node]):
                    if (not guards[guard_node]['made_contact']):
                        if _testing:
                            print(\
                            '[Time {0}]: Removing new hibernating guard: {1}.'.\
                            format(circ_time, cons_rel_stats[guard_node].nickname))
                        del guards[guard_node]
                    elif (guards[guard_node]['unreachable_since'] != None):
                        if _testing:
                            print(\
                            '[Time {0}]: Guard retried but hibernating: {1}'.\
                            format(circ_time, cons_rel_stats[guard_node].nickname))
                        guards[guard_node]['last_attempted'] = circ_time
                    else:
                        if _testing:
                            print('[Time {0}]: Guard newly hibernating: {1}'.\
                            format(circ_time, \
                            cons_rel_stats[guard_node].nickname))
                        guards[guard_node]['unreachable_since'] = circ_time
                        guards[guard_node]['last_attempted'] = circ_time
                else:
                    guards[guard_node]['unreachable_since'] = None
                    guards[guard_node]['made_contact'] = True
                    break
            if _testing:
                print('Guard node: {0} [{1}]'.format(
                    cons_rel_stats[guard_node].nickname,
                    cons_rel_stats[guard_node].fingerprint))

            # select middle node
            # As with exit selection, hibernating status checked here to mirror Tor
            # selecting middle, having the circuit fail, reselecting a path,
            # and attempting circuit creation again.
            i = 1
            while (True):
                middle_node = pathsim.select_middle_node(cons_bw_weights,\
                    cons_bwweightscale, cons_rel_stats, descriptors, circ_fast,\
                    circ_stable, exit_node, guard_node, weighted_middles)
                if (not hibernating_status[middle_node]):
                    break
                if _testing:
                    print(\
                    'Middle selection #{0} is hibernating - retrying.'.format(i))
                i += 1
            if _testing:
                print('Middle node: {0} [{1}]'.format(
                    cons_rel_stats[middle_node].nickname,
                    cons_rel_stats[middle_node].fingerprint))

            # ensure one member of the circuit supports the ntor handshake
            ntor_supported = pathsim.circuit_supports_ntor(guard_node, middle_node,
                exit_node, descriptors)
            num_attempts += 1
        if pathsim._testing:
            if ntor_supported:
                print('Chose ntor-compatible circuit in {} tries'.\
                    format(num_attempts))
        if (not ntor_supported):
            raise ValueError('ntor-compatible circuit not found in {} tries'.\
                format(num_attempts))

        latency = #SAFEST TODO: get latency for circuit from SAFEST VCS service

        if (best_latency == None) or (latency < best_latency):
            best_latency = latency
            best_circ = (guard_node, middle_node, exit_node)

    circuit = {'time':circ_time,
            'fast':circ_fast,
            'stable':circ_stable,
            'internal':circ_internal,
            'dirty_time':None,
            'path':best_circ,
            'covering':set(),
            'avg_ping':None}

    # execute callback to allow logging on circuit creation
    if (callbacks is not None):
        callbacks.circuit_creation(circuit)

    return circuit
Beispiel #2
0
def create_circuit(cons_rel_stats,
                   cons_valid_after,
                   cons_fresh_until,
                   cons_bw_weights,
                   cons_bwweightscale,
                   descriptors,
                   hibernating_status,
                   guards,
                   circ_time,
                   circ_fast,
                   circ_stable,
                   circ_internal,
                   circ_ip,
                   circ_port,
                   congmodel,
                   pdelmodel,
                   weighted_exits=None,
                   exits_exact=False,
                   weighted_middles=None,
                   weighted_guards=None,
                   callbacks=None):
    """Creates path for requested circuit based on the input consensus
    statuses and descriptors. Uses congestion-aware path selection.
    Inputs:
        cons_rel_stats: (dict) relay fingerprint keys and relay status vals
        cons_valid_after: (int) timestamp of valid_after for consensus
        cons_fresh_until: (int) timestamp of fresh_until for consensus
        cons_bw_weights: (dict) bw_weights of consensus
        cons_bwweightscale: (should be float()able) bwweightscale of consensus
        descriptors: (dict) relay fingerprint keys and descriptor vals
        hibernating_status: (dict) indicates hibernating relays
        guards: (dict) contains guards of requesting client
        circ_time: (int) timestamp of circuit request
        circ_fast: (bool) all relays should be fast
        circ_stable: (bool) all relays should be stable
        circ_internal: (bool) circuit is for name resolution or hidden service
        circ_ip: (str) IP address of destination (None if not known)
        circ_port: (int) desired TCP port (None if not known)
        congmodel: congestion model
        pdelmodel: propagation delay model
        weighted_exits: (list) (middle, cum_weight) pairs for exit position
        exits_exact: (bool) Is weighted_exits exact or does it need rechecking?
            weighed_exits is special because exits are chosen first and thus
            don't depend on the other circuit positions, and so potentially are        
            precomputed exactly.
        weighted_middles: (list) (middle, cum_weight) pairs for middle position
        weighted_guards: (list) (middle, cum_weight) pairs for middle position
        callbacks: object w/ method circuit_creation(circuit)        
    Output:
        circuit: (dict) a newly created circuit with keys
            'time': (int) seconds from time zero
            'fast': (bool) relays must have Fast flag
            'stable': (bool) relays must have Stable flag
            'internal': (bool) is internal (e.g. for hidden service)
            'dirty_time': (int) timestamp of time dirtied, None if clean
            'path': (tuple) list in-order fingerprints for path's nodes
            'covering': (set) ports with needs covered by circuit
            'avg_ping': (float) average ping time during most-recent use
    """
    #            'cons_rel_stats': (dict) relay stats for active consensus

    if (circ_time < cons_valid_after) or\
        (circ_time >= cons_fresh_until):
        raise ValueError('consensus not fresh for circ_time in create_circuit')

    num_attempts = 0
    ntor_supported = False
    while (num_attempts < pathsim.TorOptions.max_populate_attempts) and\
        (not ntor_supported):
        # select exit node
        i = 1
        while (True):
            exit_node = pathsim.select_exit_node(
                cons_bw_weights, cons_bwweightscale, cons_rel_stats,
                descriptors, circ_fast, circ_stable, circ_internal, circ_ip,
                circ_port, weighted_exits, exits_exact)
            #        exit_node = pathsim.select_weighted_node(weighted_exits)
            if (not hibernating_status[exit_node]):
                break
            if pathsim._testing:
                print('Exit selection #{0} is hibernating - retrying.'.\
                    format(i))
            i += 1
        if pathsim._testing:
            print('Exit node: {0} [{1}]'.format(
                cons_rel_stats[exit_node].nickname,
                cons_rel_stats[exit_node].fingerprint))

        # select guard node
        # Hibernation status again checked here to reflect how in Tor
        # new guards would be chosen and added to the list prior to a circuit-
        # creation attempt. If the circuit fails at a new guard, that guard
        # gets removed from the list.
        while True:
            # get first <= num_guards guards suitable for circuit
            circ_guards = pathsim.get_guards_for_circ(cons_bw_weights,\
                cons_bwweightscale, cons_rel_stats, descriptors,\
                circ_fast, circ_stable, guards,\
                exit_node, circ_time, weighted_guards)
            guard_node = choice(circ_guards)
            if (hibernating_status[guard_node]):
                if (not guards[guard_node]['made_contact']):
                    if pathsim._testing:
                        print(\
                        '[Time {0}]: Removing new hibernating guard: {1}.'.\
                        format(circ_time, cons_rel_stats[guard_node].nickname))
                    del guards[guard_node]
                elif (guards[guard_node]['unreachable_since'] != None):
                    if pathsim._testing:
                        print(\
                        '[Time {0}]: Guard retried but hibernating: {1}'.\
                        format(circ_time, cons_rel_stats[guard_node].nickname))
                    guards[guard_node]['last_attempted'] = circ_time
                else:
                    if pathsim._testing:
                        print('[Time {0}]: Guard newly hibernating: {1}'.\
                        format(circ_time, \
                        cons_rel_stats[guard_node].nickname))
                    guards[guard_node]['unreachable_since'] = circ_time
                    guards[guard_node]['last_attempted'] = circ_time
            else:
                guards[guard_node]['unreachable_since'] = None
                guards[guard_node]['made_contact'] = True
                break
        if pathsim._testing:
            print('Guard node: {0} [{1}]'.format(
                cons_rel_stats[guard_node].nickname,
                cons_rel_stats[guard_node].fingerprint))

        # select middle node
        # As with exit selection, hibernating status checked here to mirror Tor
        # selecting middle, having the circuit fail, reselecting a path,
        # and attempting circuit creation again.
        i = 1
        while (True):
            middle_node = pathsim.select_middle_node(cons_bw_weights,\
                cons_bwweightscale, cons_rel_stats, descriptors, circ_fast,\
                circ_stable, exit_node, guard_node, weighted_middles)
            if (not hibernating_status[middle_node]):
                break
            if pathsim._testing:
                print(\
                'Middle selection #{0} is hibernating - retrying.'.format(i))
            i += 1
        if pathsim._testing:
            print('Middle node: {0} [{1}]'.format(
                cons_rel_stats[middle_node].nickname,
                cons_rel_stats[middle_node].fingerprint))

        # ensure one member of the circuit supports the ntor handshake
        ntor_supported = pathsim.circuit_supports_ntor(guard_node, middle_node,
                                                       exit_node, descriptors)
        num_attempts += 1

    if pathsim._testing:
        if ntor_supported:
            print('Chose ntor-compatible circuit in {} tries'.\
                format(num_attempts))
    if (not ntor_supported):
        raise ValueError('ntor-compatible circuit not found in {} tries'.\
            format(num_attempts))

    cum_ping_time = 0
    if pathsim._testing:
        print 'Doing {0} circuit pings on creation... '.format(
            num_pings_create),
    for i in xrange(num_pings_create):
        cum_ping_time += ping_circuit(client_ip, guard_node, middle_node,\
            exit_node, cons_rel_stats, descriptors, congmodel, pdelmodel)
    avg_ping_time = float(cum_ping_time) / num_pings_create
    if pathsim._testing: print "ave congestion is {0}".format(avg_ping_time)

    circuit = {
        'time': circ_time,
        'fast': circ_fast,
        'stable': circ_stable,
        'internal': circ_internal,
        'dirty_time': None,
        'path': (guard_node, middle_node, exit_node),
        'covering': set(),
        'initial_avg_ping': avg_ping_time,
        'avg_ping': None
    }

    # execute callback to allow logging on circuit creation
    if (callbacks is not None):
        callbacks.circuit_creation(circuit)

    return circuit