0%

Conflux_Choose

Tor 入口节点 Conflux 机制分析报告

1. 概述

Tor 的 Conflux 机制允许客户端在多个电路(circuits)之间分流流量,以提高抗审查性和网络性能。本报告分析入口节点在发送数据时,如何决定是否启用 Conflux 机制,以及在 Conflux 机制下,如何选择合适的电路进行数据传输。

2. 入口节点如何决定是否启用 Conflux 机制

在 Tor 入口节点发送数据时,会调用 circuit_establish_circuit_conflux 来建立 Conflux 电路,该函数的主要流程如下:

  1. 验证 Conflux 目的

    1
    tor_assert(purpose == CIRCUIT_PURPOSE_CONFLUX_UNLINKED);

    入口节点仅在 CIRCUIT_PURPOSE_CONFLUX_UNLINKED 目的时才会使用 Conflux。

  2. 初始化电路

    1
    2
    3
    circ = origin_circuit_init(purpose, flags);
    TO_CIRCUIT(circ)->conflux_pending_nonce =
    tor_memdup(conflux_nonce, DIGEST256_LEN);

    这里初始化了 Conflux 电路并存储了 conflux_nonce

  3. 选择出口节点

    1
    2
    3
    4
    5
    if (onion_pick_cpath_exit(circ, exit_ei, 0) < 0 ||
    onion_populate_cpath(circ) < 0) {
    circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_NOPATH);
    return NULL;
    }

    若无法选择合适的出口节点,则直接关闭该电路。

  4. 建立连接

    1
    2
    3
    4
    if ((err_reason = circuit_handle_first_hop(circ)) < 0) {
    circuit_mark_for_close(TO_CIRCUIT(circ), -err_reason);
    return NULL;
    }

    这里尝试连接到第一跳的 OR(Onion Router),如果失败则关闭电路。

3. 入口节点如何决定是否切换电路

当入口节点决定通过 Conflux 机制发送数据时,会调用 conflux_decide_circ_for_send 选择合适的电路。该函数的逻辑如下:

3.1 判断是否需要多路复用

1
2
3
if (!conflux_should_multiplex(relay_command)) {
return orig_circ;
}

如果当前的 relay_command 不支持多路复用,则直接使用原始电路。

3.2 选择下一个电路

1
circuit_t *new_circ = conflux_decide_next_circ(cfx);

调用 conflux_decide_next_circ 选择下一个电路。

3.3 处理非数据命令

1
2
3
4
5
6
7
if (!new_circ && relay_command != RELAY_COMMAND_DATA) {
if (!cfx->curr_leg) {
log_warn(LD_BUG, "No current leg for conflux with relay command %d", relay_command);
return NULL;
}
return cfx->curr_leg->circ;
}

如果当前无可用电路,但命令不是 RELAY_COMMAND_DATA,则继续使用当前电路。

3.4 发送切换命令

1
2
3
4
5
6
7
8
9
if (new_circ) {
conflux_leg_t *new_leg = conflux_get_leg(cfx, new_circ);
tor_assert(cfx->curr_leg);
if (new_circ != cfx->curr_leg->circ) {
uint64_t relative_seq = cfx->prev_leg->last_seq_sent - cfx->curr_leg->last_seq_sent;
conflux_send_switch_command(cfx->curr_leg->circ, relative_seq);
cfx->curr_leg->last_seq_sent = cfx->prev_leg->last_seq_sent;
}
}

如果决定切换电路,则计算 relative_seq 并发送 SWITCH 命令。

4. 选择下一个电路的逻辑 (conflux_decide_next_circ)

conflux_decide_circ_for_send 中调用 conflux_decide_next_circ 选择下一个电路,该函数的逻辑如下:

  1. 检查是否正在关闭

    1
    2
    3
    if (cfx->in_full_teardown) {
    return NULL;
    }

    如果 Conflux 机制正在关闭,则不再选择新的电路。

  2. 初始化当前电路

    1
    2
    3
    4
    if (!cfx->curr_leg) {
    if (!conflux_pick_first_leg(cfx))
    return NULL;
    }

    如果当前没有电路,则尝试选择第一个电路。

  3. 判断是否允许切换

    1
    2
    3
    if (!conflux_can_switch(cfx)) {
    return cfx->curr_leg->circ;
    }

    如果不能切换,则返回当前电路。

  4. 根据不同策略选择电路

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    switch (cfx->params.alg) {
    case CONFLUX_ALG_MINRTT:
    return (circuit_t*)conflux_decide_circ_minrtt(cfx);
    case CONFLUX_ALG_LOWRTT:
    return (circuit_t*)conflux_decide_circ_lowrtt(cfx);
    case CONFLUX_ALG_CWNDRTT:
    return (circuit_t*)conflux_decide_circ_cwndrtt(cfx);
    default:
    return NULL;
    }

    其中:

    • CONFLUX_ALG_MINRTT 选择 RTT 最低的电路。
    • CONFLUX_ALG_LOWRTT 选择高吞吐量但可能有乱序的电路。
    • CONFLUX_ALG_CWNDRTT 选择考虑拥塞窗口的电路,以降低乱序问题。

5. 结论

Tor 入口节点在发送数据时,会根据目的和当前网络状况决定是否启用 Conflux 机制。如果 Conflux 机制被启用,则节点会基于 RTT、吞吐量或拥塞窗口选择最优的电路,并在合适的时机发送 SWITCH 命令以切换电路。通过这些策略,Tor 能够提高匿名性和数据传输效率。