Tor源码文件分析 — Circuits全局变量

  Tor系统源码中用于控制链路circuit的文件主要有三个,分别是:circuitlist.c,circuituse.c,circuitbuild.c。这三个文件分别主要针对的处理功能与他们的名字相类似,即分别处理链路的组织,使用和建立。在本篇中,我们只介绍主要用于链路部分的全局变量,即存在于这三个文件之中的全局变量的使用。此处不再罗列链路函数,因为链路部分的函数着实不少,尤其是链路建立部分。或许在本文之后会花专门的篇幅描述链路建立以及对链路建立的函数加以说明,不过这不是本篇的主要内容。

0. 全局变量 circuitlist.c

  circuitlist.c文件主要用于处理链路列表的组织,整理,计数等相关的操作。文件中前两个全局变量如下:

/** A global list of all circuits at this hop. */
circuit_t *global_circuitlist=NULL;

/** A list of all the circuits in CIRCUIT_STATE_OR_WAIT. */
static smartlist_t *circuits_pending_or_conns=NULL;

  第一个全局变量用于维护系统的链路列表。系统链路列表是每个Tor主机上维护的全局链路列表,也就是说所有的链路都挂接在这个链路列表之中。第二个全局变量用于维护系统等待链路的列表。系统等待链路的列表就是系统中正在等待OR连接完成的链路形成的列表。

  这两个列表的操作很简单,就是链表的插入和删除。其代码也可以很容易的用sourceinsight进行查找和分析,此处略去。在仔细研究代码之前我们就可以推测,全局链路列表必定是在链路被建立之时被使用到,一旦链路结构体被创建,链路设置完开始状态,就被加入全局链路列表。当然,若链路开始状态为等待OR连接,则也会被加入等待链路列表。这里的前后关系应该并不是那么重要,只是要保证两个列表的一致性:全局链路列表中状态为等待的链路一定会在等待列表中;等待链路列表中的所有链路都应该存在在全局链路列表之中。

  文件中后两个全局变量如下:(哈希表的使用请详细查看源代码)

/** Map from [orconn,circid] to circuit. */
static HT_HEAD(orconn_circid_map, orconn_circid_circuit_map_t)
     orconn_circid_circuit_map = HT_INITIALIZER();
HT_PROTOTYPE(orconn_circid_map, orconn_circid_circuit_map_t, node,
             _orconn_circid_entry_hash, _orconn_circid_entries_eq)
HT_GENERATE(orconn_circid_map, orconn_circid_circuit_map_t, node,
            _orconn_circid_entry_hash, _orconn_circid_entries_eq, 0.6,
            malloc, realloc, free)

/** The most recently returned entry from circuit_get_by_circid_orconn;
 * used to improve performance when many cells arrive in a row from the
 * same circuit.
 */
orconn_circid_circuit_map_t *_last_circid_orconn_ent = NULL;

  Tor系统的数据流图会在后面的分析中给出。在数据框图的分析之中,链路到OR连接的关联方向可以很清晰地找到,但是从OR连接到链路的查找却不那么容易。Tor系统是利用一个哈希表来进行从链路ID和OR连接到指定链路的映射的。上述两个全局变量就定义了这个全局哈希表。这个哈希表的主要作用是快速地完成从链路ID和OR连接到指定链路的映射,为了不每次都进行查询,第二个全局变量就存储了最近一次的查找结果,用于快速的返回以提升效率。该部分全局变量在函数circuit_get_by_circid_orconn之中可以看到详细的使用过程,此处略去代码的粘贴。

1. 全局变量 circuitbuild.c

  Tor系统中链路被使用的时候有个创建超时时间的问题:建立链路之时,尝试多长的时间?若在超时时间之内完成链接,则链接是成功的;反之,链接超时,则要放弃链接的建立。配置文件中的LearnCircuitBuildTimeout,CircuitBuildTimeout两个选项就是用来控制系统超时时间的选项。前者为设置系统是否自适应地选择超时时间;后者为超时时间设置一个初始值,但若自适应选项被关闭,则超时值始终保持在初始值不变。circuitbuild.c文件中用大量的函数来处理超时时间的相关问题,后期作为一个子功能部件进行介绍,此处略去。

/** Global list of circuit build times */
circuit_build_times_t circ_times;

  Tor系统中在链路建立之前要选择组成链路的各个结点。而结点之中最为重要的为入口结点。入口结点被文献称为entry guard。系统不可随意使用入口结点,而是从所有结点之中,选择几个固定的入口结点,之后每条链路的建立都以入口结点为起始。这样做的目的是降低由于敌手控制Tor结点而掌握用户信息的概率。所以,系统需要一个全局的入口结点列表,在选择入口结点之后,将结点加入到此列表之中以便以后链路的建立从列表中选取入口结点。下面为入口结点相关的全局变量:

/** A list of our chosen entry guards. */
static smartlist_t *entry_guards = NULL;
/** A value of 1 means that the entry_guards list has changed
 * and those changes need to be flushed to disk. */
static int entry_guards_dirty = 0;

// 指示在选择入口结点之时,是否先从配置选项中加入入口结点
/** When we try to choose an entry guard, should we parse and add
 * config's EntryNodes first? */
static int should_add_entry_nodes = 0;

  中间的全局变量的大致含义为观察入口结点列表是否被改变,如果被改变,则需要进行标记,以便在适当的时候将入口结点信息写回到硬盘。

  指示单元测试的全局变量,用处略少:

/** If set, we're running the unit tests: we should avoid clobbering
 * our state file or accessing get_options() or get_or_state() */
static int unit_tests = 0;

  下面为保存配置文件中读取的bridge和transport的全局列表:

/** A list of configured bridges. Whenever we actually get a descriptor
 * for one, we add it as an entry guard.  Note that the order of bridges
 * in this list does not necessarily correspond to the order of bridges
 * in the torrc. */
static smartlist_t *bridge_list = NULL;

/** A list of pluggable transports found in torrc. */
static smartlist_t *transport_list = NULL;

  此两者的具体用处有待分析系统身份逻辑时再详细说明。

2. 全局变量 circuituse.c

  本文件中使用的全局变量也很少,先简单罗列如下:

/** True iff we've ever had enough testing circuits open to test our
 * bandwidth. */
static int have_performed_bandwidth_test = 0;

/** Number of consecutive failures so far; should only be touched by
 * circuit_launch_new and circuit_*_failure_count.
 */
static int n_circuit_failures = 0;
/** Before the last time we called circuit_reset_failure_count(), were
 * there a lot of failures? */
static int did_circs_fail_last_period = 0;

  第一个全局变量主要用来指示系统是否还需要进行带宽测试。带宽测试的主要执行代码是在Relay.c文件中的函数进行的。此处的指示主要是用于判断是否还需要建立更多的链路以支持带宽测试。如果指示标志为1,则说明已经进行过测试;标志为0,则指示需要进行带宽的测试。

  后两个全局变量主要用于链路错误的标志与记录。当链路发生错误的时候,需要进行错误计数的增加。当错误计数增加到一定的数量,系统会停止重新创建链路。在等待一定时间之后,系统才会重新设置错误计数,标记错误记录是否为多,而后开始尝试创建链路。