作为连接类型中最重要的一种连接,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. */
int
circuit_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' cell, 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 circ will notice when the
* connection succeeds or fails.
*
* Return -1 if we want to warn and tear down the circuit, else return 0.
*/
int
circuit_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 broken_connection_counts. */
static int disable_broken_connection_counts = 0;
该部分全局变量是用来记录Tor系统错误信息的变量,是个字符串到整形数据的哈希表(对应表,无需链表解决冲突)。对该哈希表的添加删除操作,就可以记录或抹去系统中连接发生错误的相关状态信息。最终信息的报告位置为函数connection_or_report_broken_states。变量主要的处理函数如下:
/** Record that an OR connection failed in state. */
static void
note_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
* stop_recording is true, don't record any more. */
void
clear_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 or_protocol_versions. */
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)