作為連線類型中最重要的一種串連,OR串連對OP與OR之間,OR與OR之間的通訊負全責。也就是說,OR串連的存在,是解決底層兩機之間通訊的必要條件。所以,有必要對OR串連的源碼檔案進行深入分析,並對OR串連先做簡要介紹。後期,在介紹Tor系統的全部串連之時,會更加詳細地介紹各種串連及他們的作用。
OR串連,即Onion Router串連,是用以串連Tor系統內兩結點的串連。該串連的主要功能包括:管理結點間TLS串連;管理活動連結;管理CELL的發送和接收等。OR串連處於Tor系統的最底層,其下層即為TLS層。所以,OR串連負責的主要部分就是可靠的CELL傳遞以及與其上層連結層的互動。
DIR串連…… 應用程式層
------------------------
AP串連,EXIT串連……
------------------
Circuit鏈路…… Tor協議層
------------------
OR串連……
------------------------
TLS串連 傳輸層
同時,在此處值得一提的是,Tor系統的應用串連AP,鏈路Circuit,OR串連三者之間的複用情況:(多AP串連複用Circuit,多Circuit複用OR串連)
AP Stream 1 -->
AP Stream 2 --> Circuit 1 ->
... ... 3 -->
Circuit 2 -> OR Connection 1
Circuit 3 ->
0. 全域變數 1)orconn_identity_map
/** Map from identity digest of connected OR or desired OR to a connection_t * with that identity digest. If there is more than one such connection_t, * they form a linked list, with next_with_same_id as the next pointer. */static digestmap_t *orconn_identity_map = NULL;
該全域變數是個鏈地址法處理衝突的雜湊表,雜湊表的鍵為OR的ID摘要,雜湊表的值為OR串連鏈表(可能有多個OR串連連往同一個OR,或不同的OR可能有相同的ID摘要)。該雜湊表所能提供的功能便是插入刪除OR索引值對。其主要用途是為OP建立鏈路第一跳與OR建立連結下一跳服務。詳細可見下列代碼:
// OP建立鏈路第一跳時使用本地OR串連複用服務/** Start establishing the first hop of our circuit. Figure out what * OR we should connect to, and if necessary start the connection to * it. If we're already connected, then send the 'create' cell. * Return 0 for ok, -reason if circ should be marked-for-close. */intcircuit_handle_first_hop(origin_circuit_t *circ){ ...... /* now see if we're already connected to the first OR in 'route' */ log_debug(LD_CIRC,"Looking for firsthop '%s:%u'", fmt_addr(&firsthop->extend_info->addr), firsthop->extend_info->port); n_conn = connection_or_get_for_extend(firsthop->extend_info->identity_digest, &firsthop->extend_info->addr, &msg, &should_launch); if (!n_conn) { /* it's not open. create one */ ...... } else { /* it's already open. use it. */ ...... } return 0;}
// OR擴充鏈路時使用本地OR串連複用服務/** Take the 'extend' <b>cell</b>, pull out addr/port plus the onion * skin and identity digest for the next hop. If we're already connected, * pass the onion skin to the next hop using a create cell; otherwise * launch a new OR connection, and <b>circ</b> will notice when the * connection succeeds or fails. * * Return -1 if we want to warn and tear down the circuit, else return 0. */intcircuit_extend(cell_t *cell, circuit_t *circ){ ...... n_conn = connection_or_get_for_extend(id_digest, &n_addr, &msg, &should_launch); if (!n_conn) { /* it's not open. create one */ ...... if (should_launch) { /* we should try to open a connection */ n_conn = connection_or_connect(&n_addr, n_port, id_digest); ...... } /* return success. The onion/circuit/etc will be taken care of * automatically (may already have been) whenever n_conn reaches * OR_CONN_STATE_OPEN. */ return 0; } tor_assert(!circ->n_hop); /* Connection is already established. */ circ->n_conn = n_conn; log_debug(LD_CIRC,"n_conn is %s:%u", n_conn->_base.address,n_conn->_base.port); if (circuit_deliver_create_cell(circ, CELL_CREATE, onionskin) < 0) return -1; return 0;}
2)broken_connection_counts
/** Map from a string describing what a non-open OR connection was doing when * failed, to an intptr_t describing the count of connections that failed that * way. Note that the count is stored _as_ the pointer. */static strmap_t *broken_connection_counts;/** If true, do not record information in <b>broken_connection_counts</b>. */static int disable_broken_connection_counts = 0;
該部分全域變數是用來記錄Tor系統錯誤資訊的變數,是個字串到整形資料的雜湊表(對應表,無需鏈表解決衝突)。對該雜湊表的添加刪除操作,就可以記錄或抹去系統中串連發生錯誤的相關狀態資訊。最終資訊的報告位置為函數connection_or_report_broken_states。變數主要的處理函數如下:
/** Record that an OR connection failed in <b>state</b>. */static voidnote_broken_connection(const char *state){ void *ptr; intptr_t val; if (disable_broken_connection_counts) return; if (!broken_connection_counts) broken_connection_counts = strmap_new(); ptr = strmap_get(broken_connection_counts, state); val = (intptr_t)ptr; val++; ptr = (void*)val; strmap_set(broken_connection_counts, state, ptr);}/** Forget all recorded states for failed connections. If * <b>stop_recording</b> is true, don't record any more. */voidclear_broken_connection_map(int stop_recording){ if (broken_connection_counts) strmap_free(broken_connection_counts, NULL); broken_connection_counts = NULL; if (stop_recording) disable_broken_connection_counts = 1;}
3)version
/** Array of recognized link protocol versions. */static const uint16_t or_protocol_versions[] = { 1, 2, 3 };/** Number of versions in <b>or_protocol_versions</b>. */static const int n_or_protocol_versions = (int)( sizeof(or_protocol_versions)/sizeof(uint16_t) );
該部分全域變數用於儲存系統會使用到的協議版本號碼與協議版本數,基本是固定值,只有在新增版本時才會改變。引用處少且簡單,所以暫時略去。
1. 全域變數控制函數
connection_or_set_identity_digest
connection_or_remove_from_identity_map
connection_or_clear_identity_map
ID摘要到OR串連的雜湊表條目的增刪及清除操作;
note_broken_connection <-- 2 connection_or_note_state_when_broken 1 --> connection_or_get_state_description
clear_broken_connection_map
connection_or_report_broken_states
錯誤狀態字串到錯誤串連個數的雜湊表(對應表)條目的增加,清除操作以及綜合資訊輸出操作;
2. OR串連的Cell控制
cell_pack
cell_unpack
本機cell與網路內傳輸的cell存在位元組序上的差別,所以需要特地用兩個分別的結構體進行表示和轉換,簡單稱之為打包和解包;(網路:packed_cell_t;本機:cell_t)
var_cell_pack_header
var_cell_new
var_cell_free
變長cell的相關操作;
3. OR串連的讀寫控制
connection_or_process_inbuf --> connection_or_process_cells_from_inbuf
connection_or_reached_eof
OR串連處理輸入緩衝區內的資料,不同資料的處理方式不同,一般為cell資料或eof資料;
connection_or_flushed_some // 目的:從活動連結中擷取更多的需要寫出的資料
connection_or_finished_flushing
connection_or_finished_connecting // 目的:普通socket串連完成後,需要調用此函數進行下一步的TLS串連
OR串連完成某些操作時調用的函數操作,操作包括完成輸出部分資料,完成輸出資料,完成串連等;
connection_or_write_cell_to_buf
connection_or_write_var_cell_to_buf
將cell或者變長cell寫入到OR輸出緩衝區內等待輸出;
4. OR串連的管理
connection_or_about_to_close
進行串連關閉前的掃尾工作,並關閉OR串連;
connection_or_update_token_buckets
重新設定OR串連的令牌桶;
connection_or_digest_is_known_relay
判斷選定的OR是否為已知的可以使用的Relay伺服器;
connection_or_set_state_open
結束TLS握手及OR握手之後,設定串連的狀態為開啟狀態,並通知其他所有相關子系統;
5. OR串連的使用
connection_or_connect
發起到指定OR的OR串連,成功返回建立的OR串連結構體;其內容包括建立串連,開啟socket串連,其後開啟TLS串連等;
connection_tls_start_handshake
connection_tls_continue_handshake
在OR串連開啟了非阻塞的socket串連之後,系統根據讀寫規則,會在適當的時機開啟OR串連的TLS握手過程;
connection_init_or_handshake_state
or_handshake_state_free
or_handshake_state_record_cell
or_handshake_state_record_var_cell
在OR串連進行OR層握手時,handshake_state用於記錄整個過程中的握手包的摘要資訊,以保證握手正確;(握手的層次:socket握手,TLS握手,OR握手)
connection_or_send_destroy
connection_or_send_versions
connection_or_send_versions
connection_or_send_certs_cell
connection_or_send_auth_challenge_cell
connection_or_send_authenticate_cell --> connection_or_compute_authenticate_cell_body
構造OR握手相關握手包,利用函數connection_or_write_cell_to_buf或者connection_or_write_var_cell_to_buf寫入OR串連緩衝區等待輸出;
從整個以上OR串連的使用函數中就可以窺見整個OR串連建立的過程:
1)建立OR串連;
2)建立socket串連,進行socket握手;(三向交握)
3)建立TLS串連,進行TLS握手;(TLS握手協議)
4)進行OR握手,握手過程中要保證所有的握手包計算摘要的正確性;(OR握手協議參見tor_spec.txt)