本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。
msn:
[email protected]
来源: http://yfydz.cublog.cn
10. 主机对(host_pair)
主机对(host_pair)是连接结构的组成部分, 也都是在program/pluto/connections.c中定义, 只用来定义连接双方的地址对信息, 但又是相对独立的, 不是一一对应的, 也就是每个连接有一个主机对, 但一个主机对可能对应多个连接, 系统里的主机对单独形成了一个链表。
10.1 数据结构
struct host_pair {
// 本地和对端的地址和端口信息
struct {
ip_address addr;
u_int16_t host_port; /* IKE port */
bool host_port_specific; /* if above is interesting */
} me, him;
bool initial_connection_sent;
// 相关的连接结构
struct connection *connections; /* connections with this pair */
// 等待加密通道建立的等待结构
struct pending *pending; /* awaiting Keying Channel */
// 主机对链表的下一项
struct host_pair *next;
};
10.2 查找主机对
根据本地和对端的地址端口信息查找主机对
static struct host_pair *
find_host_pair(const ip_address *myaddr
, u_int16_t myport
, const ip_address *hisaddr
, u_int16_t hisport)
{
struct host_pair *p, *prev;
char b1[ADDRTOT_BUF],b2[ADDRTOT_BUF];
/* default hisaddr to an appropriate any */
if (hisaddr == NULL)
hisaddr = aftoinfo(addrtypeof(myaddr))->any;
/*
* look for a host-pair that has the right set of ports/address.
*
*/
/*
* for the purposes of comparison, port 500 and 4500 are identical,
* but other ports are not.
* So if any port==4500, then set it to 500.
*/
// 500和4500端口是等价的
if(myport == 4500) myport=500;
if(hisport== 4500) hisport=500;
// 遍历主机对链表, prev参数准备用于节点的断开
for (prev = NULL, p = host_pairs; p != NULL; prev = p, p = p->next)
{
DBG(DBG_CONTROLMORE
, DBG_log("find_host_pair: comparing to %s:%d %s:%d\n"
, (addrtot(&p->me.addr, 0, b1, sizeof(b1)), b1)
, p->me.host_port
, (addrtot(&p->him.addr, 0, b2, sizeof(b2)), b2)
, p->him.host_port));
// 比较地址端口是否匹配
if (sameaddr(&p->me.addr, myaddr)
&& (!p->me.host_port_specific || p->me.host_port == myport)
&& sameaddr(&p->him.addr, hisaddr)
&& (!p->him.host_port_specific || p->him.host_port == hisport)
)
{
// 匹配
if (prev != NULL)
{
// 将该节点从当前位置断开, 插到链表头, 而如果prev为空,则说明该节点本来就是链表头
// 不需要调整了
prev->next = p->next; /* remove p from list */
p->next = host_pairs; /* and stick it on front */
host_pairs = p;
}
break;
}
}
return p;
}
10.3 从连接生成主机对
static void
connect_to_host_pair(struct connection *c)
{
// 连接是否已经确定方向,即本地和对端谁是left, 谁是right
if (oriented(*c))
{
// 根据连接安全策略连接的本地和对端地址端口查找主机对结构
struct host_pair *hp = find_host_pair(&c->spd.this.host_addr
, c->spd.this.host_port
, &c->spd.that.host_addr
, c->spd.that.host_port);
char b1[ADDRTOT_BUF],b2[ADDRTOT_BUF];
DBG(DBG_CONTROLMORE
, DBG_log("connect_to_host_pair: %s:%d %s:%d -> hp:%s\n"
, (addrtot(&c->spd.this.host_addr, 0, b1,sizeof(b1)), b1)
, c->spd.this.host_port
, (addrtot(&c->spd.that.host_addr, 0, b2,sizeof(b2)), b2)
, c->spd.that.host_port
, (hp && hp->connections) ? hp->connections->name : "none"));
// 没找到, 新建主机对结构
if (hp == NULL)
{
/* no suitable host_pair -- build one */
// 分配结构
hp = alloc_thing(struct host_pair, "host_pair");
// 本地地址
hp->me.addr = c->spd.this.host_addr;
// 对端地址
hp->him.addr = c->spd.that.host_addr;
#ifdef NAT_TRAVERSAL
// 本地端口
hp->me.host_port = nat_traversal_enabled ? pluto_port : c->spd.this.host_port;
// 对端端口
hp->him.host_port = nat_traversal_enabled ? pluto_port : c->spd.that.host_port;
#else
hp->me.host_port = c->spd.this.host_port;
hp->him.host_port = c->spd.that.host_port;
#endif
hp->initial_connection_sent = FALSE;
hp->connections = NULL;
hp->pending = NULL;
// 添加到系统的主机对链表头
hp->next = host_pairs;
host_pairs = hp;
}
// 连接和主机对结构互指
c->host_pair = hp;
// 将该连接作为主机对的连接链表的链表头
c->hp_next = hp->connections;
hp->connections = c;
}
else
{
/* since this connection isn't oriented, we place it
* in the unoriented_connections list instead.
*/
// 主机对为空
c->host_pair = NULL;
// 连接挂接到未定向连接链表的链表头
c->hp_next = unoriented_connections;
unoriented_connections = c;
}
}
10.4 连接方向调整
根据连接所定义的双方地址和自己的ipsec*网卡地址确定连接的方向
/* adjust orientations of connections to reflect newly added interfaces */
void
check_orientations(void)
{
/* try to orient all the unoriented connections */
{
// 未定向的连接链表头
struct connection *c = unoriented_connections;
// 经过该函数处理后将没有未定向的连接
unoriented_connections = NULL;
// 遍历链表
while (c != NULL)
{
struct connection *nxt = c->hp_next;
// 连接定向操作
(void)orient(c);
// 连接转主机对处理
connect_to_host_pair(c);
c = nxt;
}
}
/* Check that no oriented connection has become double-oriented.
* In other words, the far side must not match one of our new interfaces.
*/
{
struct iface_port *i;
// 遍历ipsec*网卡链表
for (i = interfaces; i != NULL; i = i->next)
{
// 表示是新加的网卡
if (i->change == IFN_ADD)
{
struct host_pair *hp;
// 遍历主机对链表
for (hp = host_pairs; hp != NULL; hp = hp->next)
{
// 对端地址和网卡地址相同? 表示是定向错了, 需要重新调整
if (sameaddr(&hp->him.addr, &i->ip_addr)
&& (kern_interface!=NO_KERNEL || hp->him.host_port == pluto_port))
{
/* bad news: the whole chain of connections
* hanging off this host pair has both sides
* matching an interface.
* We'll get rid of them, using orient and
* connect_to_host_pair. But we'll be lazy
* and not ditch the host_pair itself (the
* cost of leaving it is slight and cannot
* be induced by a foe).
*/
// 该主机对相关的连接链表, 这些连接方向都错了
struct connection *c = hp->connections;
// 清空该主机对相关链表
hp->connections = NULL;
while (c != NULL)
{
struct connection *nxt = c->hp_next;
// 重新调整原来各个连接的方向, 重新建立主机对
// 设置连接的网卡为空, 表示尾定向
c->interface = NULL;
(void)orient(c);
connect_to_host_pair(c);
c = nxt;
}
}
}
}
}
}
}
// 连接定向
bool
orient(struct connection *c)
{
struct spd_route *sr;
// 如果连接没定向, 即连接的网卡为空
if (!oriented(*c))
{
struct iface_port *p;
// 遍历连接的安全策略路由链表
for (sr = &c->spd; sr; sr = sr->next)
{
/* Note: this loop does not stop when it finds a match:
* it continues checking to catch any ambiguity.
*/
// 遍历系统网卡链表
for (p = interfaces; p != NULL; p = p->next)
{
#ifdef NAT_TRAVERSAL
// NAT穿越时,端口不固定, 跳过
if (p->ike_float) continue;
#endif
// 又加一个死循环,为什么要死循环呢?虽然正常应该是最多循环两次就成,出现异常呢?
for (;;)
{
/* check if this interface matches this end */
// 检查安全策略路由的本地地址和网卡地址是否匹配
if (sameaddr(&sr->this.host_addr, &p->ip_addr)
&& (kern_interface != NO_KERNEL
|| sr->this.host_port == pluto_port))
{
if (oriented(*c))
{
// 如果该连接已经定向, 即连接的ipsec*网卡非空
// 说明有地址重复的ipsec*网卡
if (c->interface->ip_dev == p->ip_dev)
loglog(RC_LOG_SERIOUS
, "both sides of \"%s\" are our interface %s!"
, c->name, p->ip_dev->id_rname);
else
loglog(RC_LOG_SERIOUS, "two interfaces match \"%s\" (%s, %s)"
, c->name, c->interface->ip_dev->id_rname, p->ip_dev->id_rname);
// 取消连接的定向, 返回失败
c->interface = NULL; /* withdraw orientation */
return FALSE;
}
// 连接的网卡指定为该地址匹配的网卡
c->interface = p;
}
/* done with this interface if it doesn't match that end */
// 如果该网卡地址不匹配对端地址, 说明查找成功
if (!(sameaddr(&sr->that.host_addr, &p->ip_addr)
&& (kern_interface!=NO_KERNEL
|| sr->that.host_port == pluto_port)))
break;
/* swap ends and try again.
* It is a little tricky to see that this loop will stop.
* Only continue if the far side matches.
* If both sides match, there is an error-out.
*/
// 否则对调安全策略路由的本地和对端的地址信息
{
struct end t = sr->this;
sr->this = sr->that;
sr->that = t;
}
}
}
}
}
return oriented(*c);
}
...... 待续 ......