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,則指示需要進行頻寬的測試。
後兩個全域變數主要用於鏈路錯誤的標誌與記錄。當鏈路發生錯誤的時候,需要進行錯誤計數的增加。當錯誤計數增加到一定的數量,系統會停止重新建立鏈路。在等待一定時間之後,系統才會重新設定錯誤計數,標記錯誤記錄是否為多,而後開始嘗試建立鏈路。