本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,
9. 连接处理
关于连接的基本处理在programs/pluto/connections.c中定义,该文件是一个很大的文件,差不多
130K,只是拣主要的处理函数进行分析, 而且关于OE的处理就忽略了。
9.1 新增连接
该函数被whack_handle (rcv_whack.c)函数调用,用于系统初始化从配置文件读取的连接信息,建立
连接结构。
void
add_connection(const struct whack_message *wm)
{
struct alg_info_ike *alg_info_ike;
const char *ugh;
// IKE算法指针初始化清零
alg_info_ike = NULL;
// 检查连接名称对应的连接是否已经存在, 是则打印一个警告信息,但仍继续操作
if (con_by_name(wm->name, FALSE) != NULL)
{
loglog(RC_DUPNAME, "attempt to redefine connection \"%s\"", wm->name);
}
// 检查连接左右双方的协议是否相同, 是必须要求相同的
else if (wm->right.protocol != wm->left.protocol)
{
/* this should haven been diagnosed by whack
* !!! overloaded use of RC_CLASH
*/
loglog(RC_CLASH, "the protocol must be the same for leftport and rightport");
}
// 检查配置文件中"ike="定义的算法信息是否存在,如果定义"ike=",表示协商过程中的算法是
// 固定的,不是协商的
else if(wm->ike != NULL
&& ((alg_info_ike = alg_info_ike_create_from_str(wm->ike, &ugh))==NULL
|| alg_info_ike->alg_info_cnt==0)) {
if (alg_info_ike!= NULL && alg_info_ike->alg_info_cnt==0) {
loglog(RC_NOALGO
, "got 0 transforms for ike=\"%s\""
, wm->esp);
return;
}
loglog(RC_NOALGO
, "esp string error: %s"
, ugh? ugh : "Unknown");
return;
}
// IKE算法存在或需要自动协商算法的情况
else if ((wm->ike == NULL || alg_info_ike != NULL)
// 检查连接的左右端点的地址信息是否合法,可以允许一边地址是ANY,但不能两边都是ANY
&& check_connection_end(&wm->right, &wm->left, wm)
&& check_connection_end(&wm->left, &wm->right, wm))
{
bool same_rightca, same_leftca;
// 分配新连接
struct connection *c = alloc_thing(struct connection, "struct connection");
, "esp string error: %s"
, ugh? ugh : "Unknown");
return;
}
// IKE算法存在或需要自动协商算法的情况
else if ((wm->ike == NULL || alg_info_ike != NULL)
// 检查连接的左右端点的地址信息是否合法,可以允许一边地址是ANY,但不能两边都是ANY
&& check_connection_end(&wm->right, &wm->left, wm)
&& check_connection_end(&wm->left, &wm->right, wm))
{
bool same_rightca, same_leftca;
// 分配新连接
struct connection *c = alloc_thing(struct connection, "struct connection");
same_rightca = same_leftca = FALSE;
// 连接名称
c->name = wm->name;
// 连接策略
c->policy = wm->policy;
// 连接名称
c->name = wm->name;
// 连接策略
c->policy = wm->policy;
DBG(DBG_CONTROL,
DBG_log("Added new connection %s with policy %s"
, c->name
, prettypolicy(c->policy)));
// 检查是否定义压缩处理而内核却不支持压缩
if ((c->policy & POLICY_COMPRESS) && !can_do_IPcomp)
loglog(RC_COMMENT
, "ignoring --compress in \"%s\" because KLIPS is not configured to do
DBG_log("Added new connection %s with policy %s"
, c->name
, prettypolicy(c->policy)));
// 检查是否定义压缩处理而内核却不支持压缩
if ((c->policy & POLICY_COMPRESS) && !can_do_IPcomp)
loglog(RC_COMMENT
, "ignoring --compress in \"%s\" because KLIPS is not configured to do
IPCOMP"
, c->name);
, c->name);
c->alg_info_esp = NULL;
#ifdef KERNEL_ALG
// 解析"esp="定义的ESP算法
if (wm->esp)
{
DBG(DBG_CONTROL, DBG_log("from whack: got --esp=%s", wm->esp ? wm->esp:
#ifdef KERNEL_ALG
// 解析"esp="定义的ESP算法
if (wm->esp)
{
DBG(DBG_CONTROL, DBG_log("from whack: got --esp=%s", wm->esp ? wm->esp:
"NULL"));
// 解析算法信息
c->alg_info_esp = alg_info_esp_create_from_str(wm->esp? wm->esp : "",
// 解析算法信息
c->alg_info_esp = alg_info_esp_create_from_str(wm->esp? wm->esp : "",
&ugh, FALSE);
DBG(DBG_CRYPT|DBG_CONTROL,
static char buf[256]="<NULL>";
if (c->alg_info_esp)
alg_info_snprint(buf, sizeof(buf),
(struct alg_info *)c->alg_info_esp,
static char buf[256]="<NULL>";
if (c->alg_info_esp)
alg_info_snprint(buf, sizeof(buf),
(struct alg_info *)c->alg_info_esp,
TRUE);
DBG_log("esp string values: %s", buf);
);
if (c->alg_info_esp) {
if (c->alg_info_esp->alg_info_cnt==0) {
loglog(RC_NOALGO
, "got 0 transforms for esp=\"%s\""
, wm->esp);
return;
}
} else {
loglog(RC_NOALGO
, "esp string error: %s"
, ugh? ugh : "Unknown");
return;
}
c->alg_esp = clone_str(wm->esp, "esp string");
}
#endif
DBG_log("esp string values: %s", buf);
);
if (c->alg_info_esp) {
if (c->alg_info_esp->alg_info_cnt==0) {
loglog(RC_NOALGO
, "got 0 transforms for esp=\"%s\""
, wm->esp);
return;
}
} else {
loglog(RC_NOALGO
, "esp string error: %s"
, ugh? ugh : "Unknown");
return;
}
c->alg_esp = clone_str(wm->esp, "esp string");
}
#endif
c->alg_info_ike = NULL;
#ifdef IKE_ALG
// 解析"ike="定义的IKE算法
if (wm->ike)
{
// 这是刚才解析的IKE算法结构
c->alg_info_ike = alg_info_ike;
#ifdef IKE_ALG
// 解析"ike="定义的IKE算法
if (wm->ike)
{
// 这是刚才解析的IKE算法结构
c->alg_info_ike = alg_info_ike;
DBG(DBG_CONTROL, DBG_log("from whack: got --ike=%s", wm->ike));
DBG(DBG_CRYPT|DBG_CONTROL,
char buf[256];
alg_info_snprint(buf, sizeof(buf),
(struct alg_info *)c->alg_info_ike, TRUE);
DBG_log("ike string values: %s", buf);
);
if (c->alg_info_ike) {
if (c->alg_info_ike->alg_info_cnt==0) {
loglog(RC_NOALGO
, "got 0 transforms for ike=\"%s\""
, wm->ike);
return;
}
} else {
loglog(RC_NOALGO
, "ike string error: %s"
, ugh? ugh : "Unknown");
return;
}
c->alg_ike = clone_str(wm->ike, "ike string");
}
#endif
// SA参数: IKE生命期
c->sa_ike_life_seconds = wm->sa_ike_life_seconds;
// IPSEC生命期
c->sa_ipsec_life_seconds = wm->sa_ipsec_life_seconds;
// 重协商间隔
c->sa_rekey_margin = wm->sa_rekey_margin;
c->sa_rekey_fuzz = wm->sa_rekey_fuzz;
// 重协商尝试次数
c->sa_keying_tries = wm->sa_keying_tries;
DBG(DBG_CRYPT|DBG_CONTROL,
char buf[256];
alg_info_snprint(buf, sizeof(buf),
(struct alg_info *)c->alg_info_ike, TRUE);
DBG_log("ike string values: %s", buf);
);
if (c->alg_info_ike) {
if (c->alg_info_ike->alg_info_cnt==0) {
loglog(RC_NOALGO
, "got 0 transforms for ike=\"%s\""
, wm->ike);
return;
}
} else {
loglog(RC_NOALGO
, "ike string error: %s"
, ugh? ugh : "Unknown");
return;
}
c->alg_ike = clone_str(wm->ike, "ike string");
}
#endif
// SA参数: IKE生命期
c->sa_ike_life_seconds = wm->sa_ike_life_seconds;
// IPSEC生命期
c->sa_ipsec_life_seconds = wm->sa_ipsec_life_seconds;
// 重协商间隔
c->sa_rekey_margin = wm->sa_rekey_margin;
c->sa_rekey_fuzz = wm->sa_rekey_fuzz;
// 重协商尝试次数
c->sa_keying_tries = wm->sa_keying_tries;
/* RFC 3706 DPD */
// DPD参数
c->dpd_delay = wm->dpd_delay;
// DPD超时
c->dpd_timeout = wm->dpd_timeout;
// DPD超时后的动作
c->dpd_action = wm->dpd_action;
// DPD参数
c->dpd_delay = wm->dpd_delay;
// DPD超时
c->dpd_timeout = wm->dpd_timeout;
// DPD超时后的动作
c->dpd_action = wm->dpd_action;
// 强制UDP封装
c->forceencaps = wm->forceencaps;
c->forceencaps = wm->forceencaps;
// 地址协议族
c->addr_family = wm->addr_family;
// 通道内地址协议族
c->tunnel_addr_family = wm->tunnel_addr_family;
c->addr_family = wm->addr_family;
// 通道内地址协议族
c->tunnel_addr_family = wm->tunnel_addr_family;
c->requested_ca = NULL;
// 解析连接端点地址信息
same_leftca = extract_end(&c->spd.this, &wm->left, "left");
same_rightca = extract_end(&c->spd.that, &wm->right, "right");
// 解析连接端点地址信息
same_leftca = extract_end(&c->spd.this, &wm->left, "left");
same_rightca = extract_end(&c->spd.that, &wm->right, "right");
// 填充安全策略的路由结构参数
// CA名称
if (same_rightca)
c->spd.that.ca = c->spd.this.ca;
else if (same_leftca)
c->spd.this.ca = c->spd.that.ca;
// 建立端点地址信息
default_end(&c->spd.this, &c->spd.that.host_addr);
default_end(&c->spd.that, &c->spd.this.host_addr);
// CA名称
if (same_rightca)
c->spd.that.ca = c->spd.this.ca;
else if (same_leftca)
c->spd.this.ca = c->spd.that.ca;
// 建立端点地址信息
default_end(&c->spd.this, &c->spd.that.host_addr);
default_end(&c->spd.that, &c->spd.this.host_addr);
/* force any wildcard host IP address, any wildcard subnet
* or any wildcard ID to that end
*/
if (isanyaddr(&c->spd.this.host_addr) || c->spd.this.has_client_wildcard
|| c->spd.this.has_port_wildcard || c->spd.this.has_id_wildcards)
{
struct end t = c->spd.this;
* or any wildcard ID to that end
*/
if (isanyaddr(&c->spd.this.host_addr) || c->spd.this.has_client_wildcard
|| c->spd.this.has_port_wildcard || c->spd.this.has_id_wildcards)
{
struct end t = c->spd.this;
c->spd.this = c->spd.that;
c->spd.that = t;
}
c->spd.that = t;
}
c->spd.next = NULL;
// 请求ID,唯一值
c->spd.reqid = gen_reqid();
// 请求ID,唯一值
c->spd.reqid = gen_reqid();
/* set internal fields */
c->instance_serial = 0;
// 添加到系统连接链表的链表头
c->ac_next = connections;
connections = c;
// 初始化参数为无效值
c->interface = NULL;
c->spd.routing = RT_UNROUTED;
c->newest_isakmp_sa = SOS_NOBODY;
c->newest_ipsec_sa = SOS_NOBODY;
c->spd.eroute_owner = SOS_NOBODY;
c->instance_serial = 0;
// 添加到系统连接链表的链表头
c->ac_next = connections;
connections = c;
// 初始化参数为无效值
c->interface = NULL;
c->spd.routing = RT_UNROUTED;
c->newest_isakmp_sa = SOS_NOBODY;
c->newest_ipsec_sa = SOS_NOBODY;
c->spd.eroute_owner = SOS_NOBODY;
// 确定连接类型
if (c->policy & POLICY_GROUP)
{
// 组策略
c->kind = CK_GROUP;
add_group(c);
}
else if ((isanyaddr(&c->spd.that.host_addr) && !NEVER_NEGOTIATE(c->policy))
|| c->spd.that.has_client_wildcard || c->spd.that.has_port_wildcard
|| ((c->policy & POLICY_SHUNT_MASK) == 0 && c-
if (c->policy & POLICY_GROUP)
{
// 组策略
c->kind = CK_GROUP;
add_group(c);
}
else if ((isanyaddr(&c->spd.that.host_addr) && !NEVER_NEGOTIATE(c->policy))
|| c->spd.that.has_client_wildcard || c->spd.that.has_port_wildcard
|| ((c->policy & POLICY_SHUNT_MASK) == 0 && c-
>spd.that.has_id_wildcards ))
{
// 一端地址不固定的动态连接,此时的连接结构只相对于一个连接模板,等具体有端点连接
// 时才具体实例化
DBG(DBG_CONTROL, DBG_log("based upon policy, the connection is a
{
// 一端地址不固定的动态连接,此时的连接结构只相对于一个连接模板,等具体有端点连接
// 时才具体实例化
DBG(DBG_CONTROL, DBG_log("based upon policy, the connection is a
template."));
/* Opportunistic or Road Warrior or wildcard client subnet
* or wildcard ID */
c->kind = CK_TEMPLATE;
}
else
{
// 固定连接, 双方地址固定
c->kind = CK_PERMANENT;
}
// 确定策略优先级
set_policy_prio(c); /* must be after kind is set */
* or wildcard ID */
c->kind = CK_TEMPLATE;
}
else
{
// 固定连接, 双方地址固定
c->kind = CK_PERMANENT;
}
// 确定策略优先级
set_policy_prio(c); /* must be after kind is set */
#ifdef DEBUG
c->extra_debugging = wm->debugging;
#endif
c->extra_debugging = wm->debugging;
#endif
c->gw_info = NULL;
#ifdef VIRTUAL_IP
passert(!(wm->left.virt && wm->right.virt));
// 虚拟IP参数设置
if (wm->left.virt || wm->right.virt) {
passert(isanyaddr(&c->spd.that.host_addr));
c->spd.that.virt = create_virtual(c,
wm->left.virt ? wm->left.virt : wm->right.virt);
if (c->spd.that.virt)
c->spd.that.has_client = TRUE;
}
#endif
passert(!(wm->left.virt && wm->right.virt));
// 虚拟IP参数设置
if (wm->left.virt || wm->right.virt) {
passert(isanyaddr(&c->spd.that.host_addr));
c->spd.that.virt = create_virtual(c,
wm->left.virt ? wm->left.virt : wm->right.virt);
if (c->spd.that.virt)
c->spd.that.has_client = TRUE;
}
#endif
// 去共享化,将原来共享的参数重新分配各自的空间保存,不再共享
unshare_connection_strings(c);
#ifdef KERNEL_ALG
// 内核算法引用数增加
alg_info_addref((struct alg_info *)c->alg_info_esp);
#endif
#ifdef IKE_ALG
// IKE算法引用数增加
alg_info_addref((struct alg_info *)c->alg_info_ike);
#endif
// 确定方向, 确定使用的ipsec*网卡
(void)orient(c);
// 将连接转换为主机对
connect_to_host_pair(c);
unshare_connection_strings(c);
#ifdef KERNEL_ALG
// 内核算法引用数增加
alg_info_addref((struct alg_info *)c->alg_info_esp);
#endif
#ifdef IKE_ALG
// IKE算法引用数增加
alg_info_addref((struct alg_info *)c->alg_info_ike);
#endif
// 确定方向, 确定使用的ipsec*网卡
(void)orient(c);
// 将连接转换为主机对
connect_to_host_pair(c);
/* log all about this connection */
// 在日志中记录详细的连接信息
openswan_log("added connection description \"%s\"", c->name);
DBG(DBG_CONTROL,
char topo[CONNECTION_BUF];
// 在日志中记录详细的连接信息
openswan_log("added connection description \"%s\"", c->name);
DBG(DBG_CONTROL,
char topo[CONNECTION_BUF];
(void) format_connection(topo, sizeof(topo), c, &c->spd);
DBG_log("%s", topo);
/* Make sure that address families can be correctly inferred
* from printed ends.
*/
passert(c->addr_family == addrtypeof(&c->spd.this.host_addr)
&& c->addr_family == addrtypeof(&c->spd.this.host_nexthop)
&& (c->spd.this.has_client? c->tunnel_addr_family : c->addr_family)
== subnettypeof(&c->spd.this.client)
* from printed ends.
*/
passert(c->addr_family == addrtypeof(&c->spd.this.host_addr)
&& c->addr_family == addrtypeof(&c->spd.this.host_nexthop)
&& (c->spd.this.has_client? c->tunnel_addr_family : c->addr_family)
== subnettypeof(&c->spd.this.client)
&& c->addr_family == addrtypeof(&c->spd.that.host_addr)
&& c->addr_family == addrtypeof(&c->spd.that.host_nexthop)
&& (c->spd.that.has_client? c->tunnel_addr_family : c->addr_family)
== subnettypeof(&c->spd.that.client));
&& c->addr_family == addrtypeof(&c->spd.that.host_nexthop)
&& (c->spd.that.has_client? c->tunnel_addr_family : c->addr_family)
== subnettypeof(&c->spd.that.client));
DBG_log("ike_life: %lus; ipsec_life: %lus; rekey_margin: %lus;"
" rekey_fuzz: %lu%%; keyingtries: %lu; policy: %s"
, (unsigned long) c->sa_ike_life_seconds
, (unsigned long) c->sa_ipsec_life_seconds
, (unsigned long) c->sa_rekey_margin
, (unsigned long) c->sa_rekey_fuzz
, (unsigned long) c->sa_keying_tries
, prettypolicy(c->policy));
);
} else {
loglog(RC_FATAL, "attempt to load incomplete connection");
}
" rekey_fuzz: %lu%%; keyingtries: %lu; policy: %s"
, (unsigned long) c->sa_ike_life_seconds
, (unsigned long) c->sa_ipsec_life_seconds
, (unsigned long) c->sa_rekey_margin
, (unsigned long) c->sa_rekey_fuzz
, (unsigned long) c->sa_keying_tries
, prettypolicy(c->policy));
);
} else {
loglog(RC_FATAL, "attempt to load incomplete connection");
}
}
9.2 启动连接
该函数可能被whack_handle (rcv_whack.c)函数或dpd_timeout (dpd.c)调用, 启动连接, 如果连接
双方地址固定就发起IKE协商, 如果是动态连接的服务器端, 无法启动, 继续监听状态。
void
initiate_connection(const char *name, int whackfd
, lset_t moredebug
, enum crypto_importance importance)
{
// 根据名称查找连接结构
struct connection *c = con_by_name(name, TRUE);
initiate_connection(const char *name, int whackfd
, lset_t moredebug
, enum crypto_importance importance)
{
// 根据名称查找连接结构
struct connection *c = con_by_name(name, TRUE);
if (c != NULL)
{
// 连接找到
// 将该连接作为系统当前连接
set_cur_connection(c);
{
// 连接找到
// 将该连接作为系统当前连接
set_cur_connection(c);
/* turn on any extra debugging asked for */
c->extra_debugging |= moredebug;
c->extra_debugging |= moredebug;
if (!oriented(*c))
{
// 没确定方向的连接
loglog(RC_ORIENT, "We cannot identify ourselves with either end of this
{
// 没确定方向的连接
loglog(RC_ORIENT, "We cannot identify ourselves with either end of this
connection.");
}
else if (NEVER_NEGOTIATE(c->policy))
{
// 无协商连接, 不需要进入协商
loglog(RC_INITSHUNT
, "cannot initiate an authby=never connection");
}
else if (c->kind != CK_PERMANENT)
{
// 非固定连接, 是动态连接, 不能启动, 继续监听
if (isanyaddr(&c->spd.that.host_addr))
loglog(RC_NOPEERIP, "cannot initiate connection without knowing peer IP
}
else if (NEVER_NEGOTIATE(c->policy))
{
// 无协商连接, 不需要进入协商
loglog(RC_INITSHUNT
, "cannot initiate an authby=never connection");
}
else if (c->kind != CK_PERMANENT)
{
// 非固定连接, 是动态连接, 不能启动, 继续监听
if (isanyaddr(&c->spd.that.host_addr))
loglog(RC_NOPEERIP, "cannot initiate connection without knowing peer IP
address (kind=%s)"
, enum_show(&connection_kind_names, c->kind));
else
loglog(RC_WILDCARD, "cannot initiate connection with ID wildcards
, enum_show(&connection_kind_names, c->kind));
else
loglog(RC_WILDCARD, "cannot initiate connection with ID wildcards
(kind=%s)"
, enum_show(&connection_kind_names, c->kind));
}
else
{
// 可以启动连接
/* We will only request an IPsec SA if policy isn't empty
* (ignoring Main Mode items).
* This is a fudge, but not yet important.
* If we are to proceed asynchronously, whackfd will be NULL_FD.
*/
// 策略启动
c->policy |= POLICY_UP;
, enum_show(&connection_kind_names, c->kind));
}
else
{
// 可以启动连接
/* We will only request an IPsec SA if policy isn't empty
* (ignoring Main Mode items).
* This is a fudge, but not yet important.
* If we are to proceed asynchronously, whackfd will be NULL_FD.
*/
// 策略启动
c->policy |= POLICY_UP;
if(c->policy & POLICY_ENCRYPT) {
// 需要加密的话获取算法和SADB
struct alg_info_esp *alg = c->alg_info_esp;
struct db_sa *phase2_sa = kernel_alg_makedb(alg, TRUE);
if(alg != NULL && phase2_sa == NULL) {
whack_log(RC_NOALGO, "can not initiate: no acceptable kernel
// 需要加密的话获取算法和SADB
struct alg_info_esp *alg = c->alg_info_esp;
struct db_sa *phase2_sa = kernel_alg_makedb(alg, TRUE);
if(alg != NULL && phase2_sa == NULL) {
whack_log(RC_NOALGO, "can not initiate: no acceptable kernel
algorithms loaded");
reset_cur_connection();
close_any(whackfd);
return;
}
free_sa(phase2_sa);
}
reset_cur_connection();
close_any(whackfd);
return;
}
free_sa(phase2_sa);
}
#ifdef SMARTCARD
// 进行smartcard验证, 失败时也不能启动
/* do we have to prompt for a PIN code? */
if (c->spd.this.sc != NULL && !c->spd.this.sc->valid && whackfd != NULL_FD)
scx_get_pin(c->spd.this.sc, whackfd);
// 进行smartcard验证, 失败时也不能启动
/* do we have to prompt for a PIN code? */
if (c->spd.this.sc != NULL && !c->spd.this.sc->valid && whackfd != NULL_FD)
scx_get_pin(c->spd.this.sc, whackfd);
if (c->spd.this.sc != NULL && !c->spd.this.sc->valid)
{
loglog(RC_NOVALIDPIN, "cannot initiate connection without valid PIN");
}
else
#endif
{
// 发起IKE协商
ipsecdoi_initiate(whackfd, c, c->policy, 1
, SOS_NOBODY, importance);
whackfd = NULL_FD; /* protect from close */
}
}
reset_cur_connection();
}
close_any(whackfd);
}
{
loglog(RC_NOVALIDPIN, "cannot initiate connection without valid PIN");
}
else
#endif
{
// 发起IKE协商
ipsecdoi_initiate(whackfd, c, c->policy, 1
, SOS_NOBODY, importance);
whackfd = NULL_FD; /* protect from close */
}
}
reset_cur_connection();
}
close_any(whackfd);
}
9.3 删除连接
删除连接有几个不同的函数:
/* Delete connections with the specified name */
// 按名称删除连接,函数被whack_handle (rcv_whack.c)函数调用
void
delete_connections_by_name(const char *name, bool strict)
{
// 根据名称查找连接
struct connection *c = con_by_name(name, strict);
// 删除连接,循环删除所有同名的连接
for (; c != NULL; c = con_by_name(name, FALSE))
delete_connection(c, FALSE);
}
for (; c != NULL; c = con_by_name(name, FALSE))
delete_connection(c, FALSE);
}
// 删除全部连接
void
delete_every_connection(void)
{
// 遍历连接链表,删除连接
while (connections != NULL)
delete_connection(connections, TRUE);
}
// 释放连接
void
release_connection(struct connection *c, bool relations)
{
if (c->kind == CK_INSTANCE)
{
// 如果连接是实例化所得的连接,删除该连接
/* This does everything we need.
* Note that we will be called recursively by delete_connection,
* but kind will be CK_GOING_AWAY.
*/
delete_connection(c, relations);
}
else
{
// 否则清除连接相关的状态
flush_pending_by_connection(c);
delete_states_by_connection(c, relations);
unroute_connection(c);
}
}
// 删除连接的核心函数
void
delete_connection(struct connection *c, bool relations)
{
struct spd_route *sr;
// 备份当前连接作为返回时系统的当前连接, 如果要删除的连接就是当前连接,为空
struct connection *old_cur_connection
= cur_connection == c? NULL : cur_connection;
#ifdef DEBUG
lset_t old_cur_debugging = cur_debugging;
#endif
// 设置连接为当前连接
set_cur_connection(c);
void
delete_connection(struct connection *c, bool relations)
{
struct spd_route *sr;
// 备份当前连接作为返回时系统的当前连接, 如果要删除的连接就是当前连接,为空
struct connection *old_cur_connection
= cur_connection == c? NULL : cur_connection;
#ifdef DEBUG
lset_t old_cur_debugging = cur_debugging;
#endif
// 设置连接为当前连接
set_cur_connection(c);
/* Must be careful to avoid circularity:
* we mark c as going away so it won't get deleted recursively.
*/
passert(c->kind != CK_GOING_AWAY);
if (c->kind == CK_INSTANCE)
{
// 如果是实例化后得到的连接, 将连接类型改为CK_GOING_AWAY
openswan_log("deleting connection \"%s\" instance with peer %s {isakmp=#%
* we mark c as going away so it won't get deleted recursively.
*/
passert(c->kind != CK_GOING_AWAY);
if (c->kind == CK_INSTANCE)
{
// 如果是实例化后得到的连接, 将连接类型改为CK_GOING_AWAY
openswan_log("deleting connection \"%s\" instance with peer %s {isakmp=#%
lu/ipsec=#%lu}"
, c->name
, ip_str(&c->spd.that.host_addr)
, c->newest_isakmp_sa, c->newest_ipsec_sa);
c->kind = CK_GOING_AWAY;
}
else
{
openswan_log("deleting connection");
}
// 释放连接的相关状态,注意这时连接的类型已经肯定不是CK_INSTANCE了,
// 所以不会出现递归调用的情况
release_connection(c, relations); /* won't delete c */
, c->name
, ip_str(&c->spd.that.host_addr)
, c->newest_isakmp_sa, c->newest_ipsec_sa);
c->kind = CK_GOING_AWAY;
}
else
{
openswan_log("deleting connection");
}
// 释放连接的相关状态,注意这时连接的类型已经肯定不是CK_INSTANCE了,
// 所以不会出现递归调用的情况
release_connection(c, relations); /* won't delete c */
// 释放组
if (c->kind == CK_GROUP)
delete_group(c);
if (c->kind == CK_GROUP)
delete_group(c);
/* free up any logging resources */
// 关闭日志资源
perpeer_logfree(c);
// 关闭日志资源
perpeer_logfree(c);
/* find and delete c from connections list */
// 将连接从系统连接链表中断开
list_rm(struct connection, ac_next, c, connections);
// 恢复系统原来的当前连接
cur_connection = old_cur_connection;
// 将连接从系统连接链表中断开
list_rm(struct connection, ac_next, c, connections);
// 恢复系统原来的当前连接
cur_connection = old_cur_connection;
/* find and delete c from the host pair list */
// 从主机对链表中删除连接
if (c->host_pair == NULL)
{
// 从unoriented_connections链表中断开
list_rm(struct connection, hp_next, c, unoriented_connections);
}
else
{
struct host_pair *hp = c->host_pair;
// 从主机对链表中断开
list_rm(struct connection, hp_next, c, hp->connections);
c->host_pair = NULL; /* redundant, but safe */
// 从主机对链表中删除连接
if (c->host_pair == NULL)
{
// 从unoriented_connections链表中断开
list_rm(struct connection, hp_next, c, unoriented_connections);
}
else
{
struct host_pair *hp = c->host_pair;
// 从主机对链表中断开
list_rm(struct connection, hp_next, c, hp->connections);
c->host_pair = NULL; /* redundant, but safe */
/* if there are no more connections with this host_pair
* and we haven't even made an initial contact, let's delete
* this guy in case we were created by an attempted DOS attack.
*/
// 如果该主机对已经没有其他连接, 释放该主机对
if (hp->connections == NULL
&& !hp->initial_connection_sent)
{
passert(hp->pending == NULL); /* ??? must deal with this! */
list_rm(struct host_pair, next, hp, host_pairs);
pfree(hp);
}
}
* and we haven't even made an initial contact, let's delete
* this guy in case we were created by an attempted DOS attack.
*/
// 如果该主机对已经没有其他连接, 释放该主机对
if (hp->connections == NULL
&& !hp->initial_connection_sent)
{
passert(hp->pending == NULL); /* ??? must deal with this! */
list_rm(struct host_pair, next, hp, host_pairs);
pfree(hp);
}
}
#ifdef VIRTUAL_IP
// 释放虚拟IP资源
if (c->kind != CK_GOING_AWAY) pfreeany(c->spd.that.virt);
#endif
// 释放虚拟IP资源
if (c->kind != CK_GOING_AWAY) pfreeany(c->spd.that.virt);
#endif
#ifdef DEBUG
set_debugging(old_cur_debugging);
#endif
// 释放连接名称空间
pfreeany(c->name);
set_debugging(old_cur_debugging);
#endif
// 释放连接名称空间
pfreeany(c->name);
sr = &c->spd;
// 释放连接的所有安全策略路由
while(sr) {
delete_sr(c, sr);
sr = sr->next;
}
// 释放CA信息
free_generalNames(c->requested_ca, TRUE);
// 释放连接的所有安全策略路由
while(sr) {
delete_sr(c, sr);
sr = sr->next;
}
// 释放CA信息
free_generalNames(c->requested_ca, TRUE);
// 减少网关使用计数
gw_delref(&c->gw_info);
#ifdef KERNEL_ALG
// 减少内核算法使用计数
alg_info_delref((struct alg_info **)&c->alg_info_esp);
#endif
#ifdef IKE_ALG
// 减少IKE算法使用计数
alg_info_delref((struct alg_info **)&c->alg_info_ike);
#endif
// 释放连接空间
pfree(c);
}
gw_delref(&c->gw_info);
#ifdef KERNEL_ALG
// 减少内核算法使用计数
alg_info_delref((struct alg_info **)&c->alg_info_esp);
#endif
#ifdef IKE_ALG
// 减少IKE算法使用计数
alg_info_delref((struct alg_info **)&c->alg_info_ike);
#endif
// 释放连接空间
pfree(c);
}
9.4 停止连接
该函数被whack_handle (rcv_whack.c)函数调用,用于停止连接, 释放连接相关的SA。
void
terminate_connection(const char *nm)
{
/* Loop because more than one may match (master and instances)
* But at least one is required (enforced by con_by_name).
*/
struct connection *c, *n;
// 只要还能找到连接就循环操作
for (c = con_by_name(nm, TRUE); c != NULL; c = n)
{
// 该连接的链表下一项, 会在循环时赋值给c
n = c->ac_next; /* grab this before c might disappear */
// 名称匹配
if (streq(c->name, nm)
// 类型是永久,实例,或要死的
&& c->kind >= CK_PERMANENT
// 策略需协商
&& !NEVER_NEGOTIATE(c->policy))
{
// 设置为当前连接
set_cur_connection(c);
openswan_log("terminating SAs using this connection");
// 策略停
c->policy &= ~POLICY_UP;
// 释放连接相关所有状态
flush_pending_by_connection(c);
delete_states_by_connection(c, FALSE);
reset_cur_connection();
}
}
}
9.5 查找连接
9.5.1 根据名称查找连接
/* find a connection by name.
* If strict, don't accept a CK_INSTANCE.
* Move the winner (if any) to the front.
* If none is found, and strict, a diagnostic is logged to whack.
*/
struct connection *
con_by_name(const char *nm, bool strict)
{
struct connection *p, *prev;
// 遍历连接链表
for (prev = NULL, p = connections; ; prev = p, p = p->ac_next)
{
if (p == NULL)
{
// 到链表末尾,中断
if (strict)
whack_log(RC_UNKNOWN_NAME
, "no connection named \"%s\"", nm);
break;
}
// 名称要相同
if (streq(p->name, nm)
// 如果是严格情况,连接类型不能是实例化的连接
&& (!strict || p->kind != CK_INSTANCE))
{
if (prev != NULL)
{
// 从当前位置断开
prev->ac_next = p->ac_next; /* remove p from list */
// 设置为链表头
p->ac_next = connections; /* and stick it on front */
connections = p;
}
break;
}
}
return p;
}
* If strict, don't accept a CK_INSTANCE.
* Move the winner (if any) to the front.
* If none is found, and strict, a diagnostic is logged to whack.
*/
struct connection *
con_by_name(const char *nm, bool strict)
{
struct connection *p, *prev;
// 遍历连接链表
for (prev = NULL, p = connections; ; prev = p, p = p->ac_next)
{
if (p == NULL)
{
// 到链表末尾,中断
if (strict)
whack_log(RC_UNKNOWN_NAME
, "no connection named \"%s\"", nm);
break;
}
// 名称要相同
if (streq(p->name, nm)
// 如果是严格情况,连接类型不能是实例化的连接
&& (!strict || p->kind != CK_INSTANCE))
{
if (prev != NULL)
{
// 从当前位置断开
prev->ac_next = p->ac_next; /* remove p from list */
// 设置为链表头
p->ac_next = connections; /* and stick it on front */
connections = p;
}
break;
}
}
return p;
}
9.5.2 查找子连接
通常是连接是动态连接时使用, 在quick_inI1_outR1_authtail()和info_lookuphostpair()等函数中
调用:
struct connection *
find_client_connection(struct connection *c
, const ip_subnet *our_net
, const ip_subnet *peer_net
, const u_int8_t our_protocol
, const u_int16_t our_port
, const u_int8_t peer_protocol
, const u_int16_t peer_port)
{
struct connection *d;
struct spd_route *sr;
find_client_connection(struct connection *c
, const ip_subnet *our_net
, const ip_subnet *peer_net
, const u_int8_t our_protocol
, const u_int16_t our_port
, const u_int8_t peer_protocol
, const u_int16_t peer_port)
{
struct connection *d;
struct spd_route *sr;
#ifdef DEBUG
if (DBGP(DBG_CONTROLMORE))
{
char s1[SUBNETTOT_BUF],d1[SUBNETTOT_BUF];
if (DBGP(DBG_CONTROLMORE))
{
char s1[SUBNETTOT_BUF],d1[SUBNETTOT_BUF];
subnettot(our_net, 0, s1, sizeof(s1));
subnettot(peer_net, 0, d1, sizeof(d1));
subnettot(peer_net, 0, d1, sizeof(d1));
DBG_log("find_client_connection starting with %s"
, (c ? c->name : "(none)"));
DBG_log(" looking for %s:%d/%d -> %s:%d/%d"
, s1, our_protocol, our_port
, d1, peer_protocol, peer_port);
}
#endif /* DEBUG */
, (c ? c->name : "(none)"));
DBG_log(" looking for %s:%d/%d -> %s:%d/%d"
, s1, our_protocol, our_port
, d1, peer_protocol, peer_port);
}
#endif /* DEBUG */
/* give priority to current connection
* but even greater priority to a routed concrete connection
*/
{
struct connection *unrouted = NULL;
int srnum = -1;
// 遍历连接的安全策略路由,如果找到未路由的连接(unrouted != NULL),中断循环
for (sr = &c->spd; unrouted == NULL && sr != NULL; sr = sr->next)
{
srnum++;
* but even greater priority to a routed concrete connection
*/
{
struct connection *unrouted = NULL;
int srnum = -1;
// 遍历连接的安全策略路由,如果找到未路由的连接(unrouted != NULL),中断循环
for (sr = &c->spd; unrouted == NULL && sr != NULL; sr = sr->next)
{
srnum++;
#ifdef DEBUG
if (DBGP(DBG_CONTROLMORE))
{
char s2[SUBNETTOT_BUF],d2[SUBNETTOT_BUF];
if (DBGP(DBG_CONTROLMORE))
{
char s2[SUBNETTOT_BUF],d2[SUBNETTOT_BUF];
subnettot(&sr->this.client, 0, s2, sizeof(s2));
subnettot(&sr->that.client, 0, d2, sizeof(d2));
DBG_log(" concrete checking against sr#%d %s -> %s"
, srnum, s2, d2);
}
#endif /* DEBUG */
// 比较安全策略路由的本地子网,对端子网,本地协议,本地端口,对端协议,对端端口是否匹配
if (samesubnet(&sr->this.client, our_net)
&& samesubnet(&sr->that.client, peer_net)
&& (sr->this.protocol == our_protocol)
&& (!sr->this.port || (sr->this.port == our_port))
&& (sr->that.protocol == peer_protocol)
&& (!sr->that.port || (sr->that.port == peer_port)))
{
passert(oriented(*c));
// 如果已经路由过了,返回该连接
if (routed(sr->routing))
return c;
// 没路由过的连接, 可以中断循环了
unrouted = c;
}
}
subnettot(&sr->that.client, 0, d2, sizeof(d2));
DBG_log(" concrete checking against sr#%d %s -> %s"
, srnum, s2, d2);
}
#endif /* DEBUG */
// 比较安全策略路由的本地子网,对端子网,本地协议,本地端口,对端协议,对端端口是否匹配
if (samesubnet(&sr->this.client, our_net)
&& samesubnet(&sr->that.client, peer_net)
&& (sr->this.protocol == our_protocol)
&& (!sr->this.port || (sr->this.port == our_port))
&& (sr->that.protocol == peer_protocol)
&& (!sr->that.port || (sr->that.port == peer_port)))
{
passert(oriented(*c));
// 如果已经路由过了,返回该连接
if (routed(sr->routing))
return c;
// 没路由过的连接, 可以中断循环了
unrouted = c;
}
}
/* exact match? */
// 目前最多只有未路由的连接,进行更详细地查找
d = fc_try(c, c->host_pair, NULL, our_net, peer_net
, our_protocol, our_port, peer_protocol, peer_port);
// 目前最多只有未路由的连接,进行更详细地查找
d = fc_try(c, c->host_pair, NULL, our_net, peer_net
, our_protocol, our_port, peer_protocol, peer_port);
DBG(DBG_CONTROLMORE,
DBG_log(" fc_try %s gives %s"
, c->name
, (d ? d->name : "none"))
)
// 没找到,还是用未路由的连接
if (d == NULL)
d = unrouted;
}
DBG_log(" fc_try %s gives %s"
, c->name
, (d ? d->name : "none"))
)
// 没找到,还是用未路由的连接
if (d == NULL)
d = unrouted;
}
// 如果d为空, 没有找到合适的连接
if (d == NULL)
{
/* look for an abstract connection to match */
struct spd_route *sr;
struct host_pair *hp = NULL;
// 遍历连接的安全策略路由,如果找到主机对(hp!=NULL),中断循环
for (sr = &c->spd; hp==NULL && sr != NULL; sr = sr->next)
{
// 根据连接双方的地址查找合适的主机对
hp = find_host_pair(&sr->this.host_addr
, sr->this.host_port
, NULL
, sr->that.host_port);
#ifdef DEBUG
if (DBGP(DBG_CONTROLMORE))
{
char s2[SUBNETTOT_BUF],d2[SUBNETTOT_BUF];
for (sr = &c->spd; hp==NULL && sr != NULL; sr = sr->next)
{
// 根据连接双方的地址查找合适的主机对
hp = find_host_pair(&sr->this.host_addr
, sr->this.host_port
, NULL
, sr->that.host_port);
#ifdef DEBUG
if (DBGP(DBG_CONTROLMORE))
{
char s2[SUBNETTOT_BUF],d2[SUBNETTOT_BUF];
subnettot(&sr->this.client, 0, s2, sizeof(s2));
subnettot(&sr->that.client, 0, d2, sizeof(d2));
subnettot(&sr->that.client, 0, d2, sizeof(d2));
DBG_log(" checking hostpair %s -> %s is %s"
, s2, d2
, (hp ? "found" : "not found"));
}
#endif /* DEBUG */
}
, s2, d2
, (hp ? "found" : "not found"));
}
#endif /* DEBUG */
}
if (hp != NULL)
{
// 找到, 使用该主机对作为参数重新查找
/* RW match with actual peer_id or abstract peer_id? */
d = fc_try(c, hp, NULL, our_net, peer_net
, our_protocol, our_port, peer_protocol, peer_port);
{
// 找到, 使用该主机对作为参数重新查找
/* RW match with actual peer_id or abstract peer_id? */
d = fc_try(c, hp, NULL, our_net, peer_net
, our_protocol, our_port, peer_protocol, peer_port);
// 如果还是没找到,重新进行OE查找
if (d == NULL
&& subnetishost(our_net)
&& subnetishost(peer_net))
{
/* Opportunistic match?
* Always use abstract peer_id.
* Note that later instantiation will result in the same peer_id.
*/
d = fc_try_oppo(c, hp, our_net, peer_net
, our_protocol, our_port, peer_protocol, peer_port);
}
}
}
DBG(DBG_CONTROLMORE,
DBG_log(" concluding with d = %s"
, (d ? d->name : "none"))
)
return d;
}
DBG_log(" concluding with d = %s"
, (d ? d->name : "none"))
)
return d;
}
/* find_client_connection: given a connection suitable for ISAKMP
* (i.e. the hosts match), find a one suitable for IPSEC
* (i.e. with matching clients).
*
* If we don't find an exact match (not even our current connection),
* we try for one that still needs instantiation. Try Road Warrior
* abstract connections and the Opportunistic abstract connections.
* This requires inverse instantiation: abstraction.
*
* After failing to find an exact match, we abstract the peer
* to be NO_IP (the wildcard value). This enables matches with
* Road Warrior and Opportunistic abstract connections.
*
* After failing that search, we also abstract the Phase 1 peer ID
* if possible. If the peer's ID was the peer's IP address, we make
* it NO_ID; instantiation will make it the peer's IP address again.
*
* If searching for a Road Warrior abstract connection fails,
* and conditions are suitable, we search for the best Opportunistic
* abstract connection.
*
* Note: in the end, both Phase 1 IDs must be preserved, after any
* instantiation. They are the IDs that have been authenticated.
*/
#define PATH_WEIGHT 1
#define WILD_WEIGHT (MAX_CA_PATH_LEN+1)
#define PRIO_WEIGHT (MAX_WILDCARDS+1)*WILD_WEIGHT
#define WILD_WEIGHT (MAX_CA_PATH_LEN+1)
#define PRIO_WEIGHT (MAX_WILDCARDS+1)*WILD_WEIGHT
/* fc_try: a helper function for find_client_connection */
static struct connection *
fc_try(const struct connection *c
, struct host_pair *hp
, const struct id *peer_id UNUSED
, const ip_subnet *our_net
, const ip_subnet *peer_net
, const u_int8_t our_protocol
, const u_int16_t our_port
, const u_int8_t peer_protocol
, const u_int16_t peer_port)
{
struct connection *d;
struct connection *best = NULL;
policy_prio_t best_prio = BOTTOM_PRIO;
int wildcards, pathlen;
const bool peer_net_is_host = subnetisaddr(peer_net, &c->spd.that.host_addr);
static struct connection *
fc_try(const struct connection *c
, struct host_pair *hp
, const struct id *peer_id UNUSED
, const ip_subnet *our_net
, const ip_subnet *peer_net
, const u_int8_t our_protocol
, const u_int16_t our_port
, const u_int8_t peer_protocol
, const u_int16_t peer_port)
{
struct connection *d;
struct connection *best = NULL;
policy_prio_t best_prio = BOTTOM_PRIO;
int wildcards, pathlen;
const bool peer_net_is_host = subnetisaddr(peer_net, &c->spd.that.host_addr);
// 遍历主机对相关的所有连接
for (d = hp->connections; d != NULL; d = d->hp_next)
{
struct spd_route *sr;
// 忽略组连接
if (d->policy & POLICY_GROUP)
continue;
for (d = hp->connections; d != NULL; d = d->hp_next)
{
struct spd_route *sr;
// 忽略组连接
if (d->policy & POLICY_GROUP)
continue;
// 检查本地ID,对端ID,对端CA是否匹配
if (!(same_id(&c->spd.this.id, &d->spd.this.id)
&& match_id(&c->spd.that.id, &d->spd.that.id, &wildcards)
&& trusted_ca(c->spd.that.ca, d->spd.that.ca, &pathlen)))
continue;
if (!(same_id(&c->spd.this.id, &d->spd.this.id)
&& match_id(&c->spd.that.id, &d->spd.that.id, &wildcards)
&& trusted_ca(c->spd.that.ca, d->spd.that.ca, &pathlen)))
continue;
/* compare protocol and ports */
// 检查本地协议,本地端口,对端协议,对端端口是否匹配
if (d->spd.this.protocol != our_protocol
|| (d->spd.this.port && d->spd.this.port != our_port)
|| d->spd.that.protocol != peer_protocol
|| (d->spd.that.port != peer_port && !d->spd.that.has_port_wildcard))
continue;
// 检查本地协议,本地端口,对端协议,对端端口是否匹配
if (d->spd.this.protocol != our_protocol
|| (d->spd.this.port && d->spd.this.port != our_port)
|| d->spd.that.protocol != peer_protocol
|| (d->spd.that.port != peer_port && !d->spd.that.has_port_wildcard))
continue;
/* non-Opportunistic case:
* our_client must match.
*
* So must peer_client, but the testing is complicated
* by the fact that the peer might be a wildcard
* and if so, the default value of that.client
* won't match the default peer_net. The appropriate test:
*
* If d has a peer client, it must match peer_net.
* If d has no peer client, peer_net must just have peer itself.
*/
// 该连接的以上参数全部匹配
// 遍历该连接的安全策略路由,判断是否是最优连接
for (sr = &d->spd; best != d && sr != NULL; sr = sr->next)
{
policy_prio_t prio;
#ifdef DEBUG
if (DBGP(DBG_CONTROLMORE))
{
char s1[SUBNETTOT_BUF],d1[SUBNETTOT_BUF];
char s3[SUBNETTOT_BUF],d3[SUBNETTOT_BUF];
* our_client must match.
*
* So must peer_client, but the testing is complicated
* by the fact that the peer might be a wildcard
* and if so, the default value of that.client
* won't match the default peer_net. The appropriate test:
*
* If d has a peer client, it must match peer_net.
* If d has no peer client, peer_net must just have peer itself.
*/
// 该连接的以上参数全部匹配
// 遍历该连接的安全策略路由,判断是否是最优连接
for (sr = &d->spd; best != d && sr != NULL; sr = sr->next)
{
policy_prio_t prio;
#ifdef DEBUG
if (DBGP(DBG_CONTROLMORE))
{
char s1[SUBNETTOT_BUF],d1[SUBNETTOT_BUF];
char s3[SUBNETTOT_BUF],d3[SUBNETTOT_BUF];
subnettot(our_net, 0, s1, sizeof(s1));
subnettot(peer_net, 0, d1, sizeof(d1));
subnettot(&sr->this.client, 0, s3, sizeof(s3));
subnettot(&sr->that.client, 0, d3, sizeof(d3));
DBG_log(" fc_try trying "
"%s:%s:%d/%d -> %s:%d/%d vs %s:%s:%d/%d -> %s:%d/%d"
, c->name, s1, c->spd.this.protocol, c->spd.this.port
, d1, c->spd.that.protocol, c->spd.that.port
, d->name, s3, sr->this.protocol, sr->this.port
, d3, sr->that.protocol, sr->that.port);
}
#endif /* DEBUG */
// 检查本地子网是否相同
if (!samesubnet(&sr->this.client, our_net))
continue;
subnettot(peer_net, 0, d1, sizeof(d1));
subnettot(&sr->this.client, 0, s3, sizeof(s3));
subnettot(&sr->that.client, 0, d3, sizeof(d3));
DBG_log(" fc_try trying "
"%s:%s:%d/%d -> %s:%d/%d vs %s:%s:%d/%d -> %s:%d/%d"
, c->name, s1, c->spd.this.protocol, c->spd.this.port
, d1, c->spd.that.protocol, c->spd.that.port
, d->name, s3, sr->this.protocol, sr->this.port
, d3, sr->that.protocol, sr->that.port);
}
#endif /* DEBUG */
// 检查本地子网是否相同
if (!samesubnet(&sr->this.client, our_net))
continue;
if (sr->that.has_client)
{
// 检查对端子网是否匹配
if (sr->that.has_client_wildcard) {
if (!subnetinsubnet(peer_net, &sr->that.client))
continue;
} else {
#ifdef VIRTUAL_IP
if ((!samesubnet(&sr->that.client, peer_net)) && (!
{
// 检查对端子网是否匹配
if (sr->that.has_client_wildcard) {
if (!subnetinsubnet(peer_net, &sr->that.client))
continue;
} else {
#ifdef VIRTUAL_IP
if ((!samesubnet(&sr->that.client, peer_net)) && (!
is_virtual_connection(d)))
#else
if (!samesubnet(&sr->that.client, peer_net))
#endif
continue;
#ifdef VIRTUAL_IP
if ((is_virtual_connection(d)) &&
( (!is_virtual_net_allowed(d, peer_net, &c->spd.that.host_addr))
#else
if (!samesubnet(&sr->that.client, peer_net))
#endif
continue;
#ifdef VIRTUAL_IP
if ((is_virtual_connection(d)) &&
( (!is_virtual_net_allowed(d, peer_net, &c->spd.that.host_addr))
||
(is_virtual_net_used(peer_net, peer_id?peer_id:&c->spd.that.id))
(is_virtual_net_used(peer_net, peer_id?peer_id:&c->spd.that.id))
))
continue;
#endif
}
}
else
{
// 如果对端是子网,循环跳过
if (!peer_net_is_host)
continue;
}
continue;
#endif
}
}
else
{
// 如果对端是子网,循环跳过
if (!peer_net_is_host)
continue;
}
/* We've run the gauntlet -- success:
* We've got an exact match of subnets.
* The connection is feasible, but we continue looking for the best.
* The highest priority wins, implementing eroute-like rule.
* - a routed connection is preferrred
* - given that, the smallest number of ID wildcards are preferred
* - given that, the shortest CA pathlength is preferred
*/
// 计算优先权
prio = PRIO_WEIGHT * routed(sr->routing)
+ WILD_WEIGHT * (MAX_WILDCARDS - wildcards)
+ PATH_WEIGHT * (MAX_CA_PATH_LEN - pathlen)
+ 1;
// 如果该优先权超过限值,可以算最优的连接了
if (prio > best_prio)
{
best = d;
best_prio = prio;
}
}
}
* We've got an exact match of subnets.
* The connection is feasible, but we continue looking for the best.
* The highest priority wins, implementing eroute-like rule.
* - a routed connection is preferrred
* - given that, the smallest number of ID wildcards are preferred
* - given that, the shortest CA pathlength is preferred
*/
// 计算优先权
prio = PRIO_WEIGHT * routed(sr->routing)
+ WILD_WEIGHT * (MAX_WILDCARDS - wildcards)
+ PATH_WEIGHT * (MAX_CA_PATH_LEN - pathlen)
+ 1;
// 如果该优先权超过限值,可以算最优的连接了
if (prio > best_prio)
{
best = d;
best_prio = prio;
}
}
}
if (best != NULL && NEVER_NEGOTIATE(best->policy))
best = NULL;
best = NULL;
DBG(DBG_CONTROLMORE,
DBG_log(" fc_try concluding with %s [%ld]"
, (best ? best->name : "none"), best_prio)
)
return best;
}
DBG_log(" fc_try concluding with %s [%ld]"
, (best ? best->name : "none"), best_prio)
)
return best;
}
9.5.3 根据状态精炼合适的连接
/* given an up-until-now satisfactory connection, find the best connection
* now that we just got the Phase 1 Id Payload from the peer.
*
* Comments in the code describe the (tricky!) matching criteria.
* Although this routine could handle the initiator case,
* it isn't currently called in this case.
* If it were, it could "upgrade" an Opportunistic Connection
* to a Road Warrior Connection if a suitable Peer ID were found.
*
* In RFC 2409 "The Internet Key Exchange (IKE)",
* in 5.1 "IKE Phase 1 Authenticated With Signatures", describing Main
* Mode:
*
* Initiator Responder
* ----------- -----------
* HDR, SA -->
* <-- HDR, SA
* HDR, KE, Ni -->
* <-- HDR, KE, Nr
* HDR*, IDii, [ CERT, ] SIG_I -->
* <-- HDR*, IDir, [ CERT, ] SIG_R
*
* In 5.4 "Phase 1 Authenticated With a Pre-Shared Key":
*
* HDR, SA -->
* <-- HDR, SA
* HDR, KE, Ni -->
* <-- HDR, KE, Nr
* HDR*, IDii, HASH_I -->
* <-- HDR*, IDir, HASH_R
*
* refine_host_connection could be called in two case:
*
* - the Responder receives the IDii payload:
* + [PSK] after using PSK to decode this message
* + before sending its IDir payload
* + before using its ID in HASH_R computation
* + [DSig] before using its private key to sign SIG_R
* + before using the Initiator's ID in HASH_I calculation
* + [DSig] before using the Initiator's public key to check SIG_I
*
* - the Initiator receives the IDir payload:
* + [PSK] after using PSK to encode previous message and decode this message
* + after sending its IDii payload
* + after using its ID in HASH_I computation
* + [DSig] after using its private key to sign SIG_I
* + before using the Responder's ID to compute HASH_R
* + [DSig] before using Responder's public key to check SIG_R
*
* refine_host_connection can choose a different connection, as long as
* nothing already used is changed.
*
* In the Initiator case, the particular connection might have been
* specified by whatever provoked Pluto to initiate. For example:
* whack --initiate connection-name
* The advantages of switching connections when we're the Initiator seem
* less important than the disadvantages, so after FreeS/WAN 1.9, we
* don't do this.
*/
struct connection *
refine_host_connection(const struct state *st, const struct id *peer_id
, bool initiator, bool aggrmode)
{
// 状态对应的连接
struct connection *c = st->st_connection;
// 认证方法
u_int16_t auth = st->st_oakley.auth;
struct connection *d;
struct connection *best_found = NULL;
lset_t auth_policy;
// 策略模式
lset_t p1mode_policy = aggrmode ? POLICY_AGGRESSIVE : LEMPTY;
const struct RSA_private_key *my_RSA_pri = NULL;
// 对方IP是否不确定
bool wcpip; /* wildcard Peer IP? */
int wildcards, best_wildcards;
int our_pathlen, best_our_pathlen, peer_pathlen, best_peer_pathlen;
chunk_t peer_ca;
const chunk_t *psk;
refine_host_connection(const struct state *st, const struct id *peer_id
, bool initiator, bool aggrmode)
{
// 状态对应的连接
struct connection *c = st->st_connection;
// 认证方法
u_int16_t auth = st->st_oakley.auth;
struct connection *d;
struct connection *best_found = NULL;
lset_t auth_policy;
// 策略模式
lset_t p1mode_policy = aggrmode ? POLICY_AGGRESSIVE : LEMPTY;
const struct RSA_private_key *my_RSA_pri = NULL;
// 对方IP是否不确定
bool wcpip; /* wildcard Peer IP? */
int wildcards, best_wildcards;
int our_pathlen, best_our_pathlen, peer_pathlen, best_peer_pathlen;
chunk_t peer_ca;
const chunk_t *psk;
psk = NULL;
our_pathlen = peer_pathlen = 0;
best_our_pathlen = 0;
best_peer_pathlen = 0;
wildcards = best_wildcards = 0;
best_our_pathlen = 0;
best_peer_pathlen = 0;
wildcards = best_wildcards = 0;
DBG(DBG_CONTROLMORE
, DBG_log("refine_connection: starting with %s"
, c->name));
// 根据对方ID获取对方CA
peer_ca = get_peer_ca(peer_id);
, DBG_log("refine_connection: starting with %s"
, c->name));
// 根据对方ID获取对方CA
peer_ca = get_peer_ca(peer_id);
// 检查对端ID是否匹配
if (same_id(&c->spd.that.id, peer_id)
// 是否是信任的CA
&& trusted_ca(peer_ca, c->spd.that.ca, &peer_pathlen)
&& peer_pathlen == 0
// 是否是请求的CA
&& match_requested_ca(c->requested_ca, c->spd.this.ca, &our_pathlen)
&& our_pathlen == 0
) {
if (same_id(&c->spd.that.id, peer_id)
// 是否是信任的CA
&& trusted_ca(peer_ca, c->spd.that.ca, &peer_pathlen)
&& peer_pathlen == 0
// 是否是请求的CA
&& match_requested_ca(c->requested_ca, c->spd.this.ca, &our_pathlen)
&& our_pathlen == 0
) {
DBG(DBG_CONTROLMORE
, DBG_log("refine_connection: happy with starting point: %s"
, c->name));
// OK, 返回状态对应连接
return c; /* peer ID matches current connection -- look no further */
}
, DBG_log("refine_connection: happy with starting point: %s"
, c->name));
// OK, 返回状态对应连接
return c; /* peer ID matches current connection -- look no further */
}
#if defined(XAUTH)
// 如果是XAUTH, 更新认证方法
auth = xauth_calcbaseauth(auth);
#endif
switch (auth)
{
// 共享密钥认证
case OAKLEY_PRESHARED_KEY:
auth_policy = POLICY_PSK;
// 获取共享密钥
psk = get_preshared_secret(c);
/* It should be virtually impossible to fail to find PSK:
* we just used it to decode the current message!
*/
if (psk == NULL)
return NULL; /* cannot determine PSK! */
break;
// RSA签名认证
case OAKLEY_RSA_SIG:
auth_policy = POLICY_RSASIG;
if (initiator && c->spd.this.sc == NULL)
{
/* at this point, we've committed to our RSA private key:
* we used it in our previous message.
*/
// 获取RSA密钥
my_RSA_pri = get_RSA_private_key(c);
if (my_RSA_pri == NULL)
return NULL; /* cannot determine my RSA private key! */
}
break;
// 如果是XAUTH, 更新认证方法
auth = xauth_calcbaseauth(auth);
#endif
switch (auth)
{
// 共享密钥认证
case OAKLEY_PRESHARED_KEY:
auth_policy = POLICY_PSK;
// 获取共享密钥
psk = get_preshared_secret(c);
/* It should be virtually impossible to fail to find PSK:
* we just used it to decode the current message!
*/
if (psk == NULL)
return NULL; /* cannot determine PSK! */
break;
// RSA签名认证
case OAKLEY_RSA_SIG:
auth_policy = POLICY_RSASIG;
if (initiator && c->spd.this.sc == NULL)
{
/* at this point, we've committed to our RSA private key:
* we used it in our previous message.
*/
// 获取RSA密钥
my_RSA_pri = get_RSA_private_key(c);
if (my_RSA_pri == NULL)
return NULL; /* cannot determine my RSA private key! */
}
break;
default:
bad_case(auth);
}
bad_case(auth);
}
/* The current connection won't do: search for one that will.
* First search for one with the same pair of hosts.
* If that fails, search for a suitable Road Warrior or Opportunistic
* connection (i.e. wildcard peer IP).
* We need to match:
* - peer_id (slightly complicated by instantiation)
* - if PSK auth, the key must not change (we used it to decode message)
* - policy-as-used must be acceptable to new connection
* - if initiator, also:
* + our ID must not change (we sent it in previous message)
* + our RSA key must not change (we used in in previous message)
*/
// 连接C对应的主机对相关的连接链表
d = c->host_pair->connections;
for (wcpip = FALSE; ; wcpip = TRUE)
{
// 遍历链表
for (; d != NULL; d = d->hp_next)
{
// 对端ID匹配
bool match1 = match_id(peer_id, &d->spd.that.id, &wildcards);
// 是否信任的CA
bool match2 = trusted_ca(peer_ca, d->spd.that.ca, &peer_pathlen);
// 是否是请求的CA
bool match3 = match_requested_ca(c->requested_ca, d->spd.this.ca,
* First search for one with the same pair of hosts.
* If that fails, search for a suitable Road Warrior or Opportunistic
* connection (i.e. wildcard peer IP).
* We need to match:
* - peer_id (slightly complicated by instantiation)
* - if PSK auth, the key must not change (we used it to decode message)
* - policy-as-used must be acceptable to new connection
* - if initiator, also:
* + our ID must not change (we sent it in previous message)
* + our RSA key must not change (we used in in previous message)
*/
// 连接C对应的主机对相关的连接链表
d = c->host_pair->connections;
for (wcpip = FALSE; ; wcpip = TRUE)
{
// 遍历链表
for (; d != NULL; d = d->hp_next)
{
// 对端ID匹配
bool match1 = match_id(peer_id, &d->spd.that.id, &wildcards);
// 是否信任的CA
bool match2 = trusted_ca(peer_ca, d->spd.that.ca, &peer_pathlen);
// 是否是请求的CA
bool match3 = match_requested_ca(c->requested_ca, d->spd.this.ca,
&our_pathlen);
// 三个条件都要满足
bool match = match1 && match2 && match3;
// 三个条件都要满足
bool match = match1 && match2 && match3;
DBG(DBG_CONTROLMORE
, DBG_log("refine_connection: checking %s against %s, best=%s with
, DBG_log("refine_connection: checking %s against %s, best=%s with
match=%d(id=%d/ca=%d/reqca=%d)"
, c->name, d->name, best_found ? best_found->name : "(none)"
, match, match1, match2, match3));
, c->name, d->name, best_found ? best_found->name : "(none)"
, match, match1, match2, match3));
/* ignore group connections */
// 组策略跳过
if (d->policy & POLICY_GROUP)
continue;
// 组策略跳过
if (d->policy & POLICY_GROUP)
continue;
/* check if peer_id matches, exactly or after instantiation */
// 不匹配跳过
if (!match)
continue;
// 不匹配跳过
if (!match)
continue;
/* if initiator, our ID must match exactly */
// 如果是初始方, 检查本地ID是否匹配
if (initiator && !same_id(&c->spd.this.id, &d->spd.this.id))
continue;
// 如果是初始方, 检查本地ID是否匹配
if (initiator && !same_id(&c->spd.this.id, &d->spd.this.id))
continue;
/* authentication used must fit policy of this connection */
// 策略检查
if ((d->policy & auth_policy) == LEMPTY)
continue; /* our auth isn't OK for this connection */
// 策略检查
if ((d->policy & auth_policy) == LEMPTY)
continue; /* our auth isn't OK for this connection */
// 策略模式检查
if ((d->policy & POLICY_AGGRESSIVE) ^ p1mode_policy)
continue; /* disallow phase1 main/aggressive mode mismatch */
if ((d->policy & POLICY_AGGRESSIVE) ^ p1mode_policy)
continue; /* disallow phase1 main/aggressive mode mismatch */
#ifdef XAUTH
// 是否是相同的XAUTH角色, 都是服务器还是都是客户端
if (d->spd.this.xauth_server != c->spd.this.xauth_server)
continue; /* disallow xauth/no xauth mismatch */
// 是否是相同的XAUTH角色, 都是服务器还是都是客户端
if (d->spd.this.xauth_server != c->spd.this.xauth_server)
continue; /* disallow xauth/no xauth mismatch */
if (d->spd.this.xauth_client != c->spd.this.xauth_client)
continue; /* disallow xauth/no xauth mismatch */
#endif
continue; /* disallow xauth/no xauth mismatch */
#endif
DBG(DBG_CONTROLMORE
, DBG_log("refine_connection: checked %s against %s, now for see if
, DBG_log("refine_connection: checked %s against %s, now for see if
best"
, c->name, d->name));
, c->name, d->name));
switch (auth)
{
case OAKLEY_PRESHARED_KEY:
/* secret must match the one we already used */
{
// 获取连接d的共享密钥
const chunk_t *dpsk = get_preshared_secret(d);
{
case OAKLEY_PRESHARED_KEY:
/* secret must match the one we already used */
{
// 获取连接d的共享密钥
const chunk_t *dpsk = get_preshared_secret(d);
if (dpsk == NULL)
continue; /* no secret */
// 如果此共享密钥和连接c的共享密钥不匹配,跳过
if (psk != dpsk)
if (psk->len != dpsk->len
|| memcmp(psk->ptr, dpsk->ptr, psk->len) != 0)
continue; /* different secret */
}
break;
continue; /* no secret */
// 如果此共享密钥和连接c的共享密钥不匹配,跳过
if (psk != dpsk)
if (psk->len != dpsk->len
|| memcmp(psk->ptr, dpsk->ptr, psk->len) != 0)
continue; /* different secret */
}
break;
case OAKLEY_RSA_SIG:
/* We must at least be able to find our private key.
* If we initiated, it must match the one we
* used in the SIG_I payload that we sent previously.
*/
if (d->spd.this.sc == NULL) /* no smartcard */
{
// 获取连接d的RSA密钥
const struct RSA_private_key *pri
= get_RSA_private_key(d);
// 如果和连接c的RSA密钥不匹配,跳过
if (pri == NULL
|| (initiator && (c->spd.this.sc != NULL
|| !same_RSA_public_key(&my_RSA_pri->pub, &pri->pub))))
continue;
}
else if (initiator && c->spd.this.sc != d->spd.this.sc)
continue;
break;
/* We must at least be able to find our private key.
* If we initiated, it must match the one we
* used in the SIG_I payload that we sent previously.
*/
if (d->spd.this.sc == NULL) /* no smartcard */
{
// 获取连接d的RSA密钥
const struct RSA_private_key *pri
= get_RSA_private_key(d);
// 如果和连接c的RSA密钥不匹配,跳过
if (pri == NULL
|| (initiator && (c->spd.this.sc != NULL
|| !same_RSA_public_key(&my_RSA_pri->pub, &pri->pub))))
continue;
}
else if (initiator && c->spd.this.sc != d->spd.this.sc)
continue;
break;
default:
bad_case(auth);
}
bad_case(auth);
}
/* d has passed all the tests.
* We'll go with it if the Peer ID was an exact match.
*/
// 前面都匹配,而且匹配时的各返回参数都是0, 可返回该连接
if (match && wildcards == 0 && peer_pathlen == 0 && our_pathlen == 0)
return d;
* We'll go with it if the Peer ID was an exact match.
*/
// 前面都匹配,而且匹配时的各返回参数都是0, 可返回该连接
if (match && wildcards == 0 && peer_pathlen == 0 && our_pathlen == 0)
return d;
/* We'll remember it as best_found in case an exact
* match doesn't come along.
*/
// 根据这3个返回参数更新最优连接
if (best_found == NULL || wildcards < best_wildcards
|| ((wildcards == best_wildcards && peer_pathlen < best_peer_pathlen)
|| (peer_pathlen == best_peer_pathlen && our_pathlen <
* match doesn't come along.
*/
// 根据这3个返回参数更新最优连接
if (best_found == NULL || wildcards < best_wildcards
|| ((wildcards == best_wildcards && peer_pathlen < best_peer_pathlen)
|| (peer_pathlen == best_peer_pathlen && our_pathlen <
best_our_pathlen)))
{
DBG(DBG_CONTROLMORE
, DBG_log("refine_connection: picking new best %s (wild=%d,
{
DBG(DBG_CONTROLMORE
, DBG_log("refine_connection: picking new best %s (wild=%d,
peer_pathlen=%d/our=%d)"
, d->name
, wildcards, peer_pathlen, our_pathlen));
best_found = d;
best_wildcards = wildcards;
best_peer_pathlen = peer_pathlen;
best_our_pathlen = our_pathlen;
}
}
// 如果是动态对端,返回该最合适连接
if (wcpip)
return best_found; /* been around twice already */
, d->name
, wildcards, peer_pathlen, our_pathlen));
best_found = d;
best_wildcards = wildcards;
best_peer_pathlen = peer_pathlen;
best_our_pathlen = our_pathlen;
}
}
// 如果是动态对端,返回该最合适连接
if (wcpip)
return best_found; /* been around twice already */
/* Starting second time around.
* We're willing to settle for a connection that needs Peer IP
* instantiated: Road Warrior or Opportunistic.
* Look on list of connections for host pair with wildcard Peer IP
*/
// 根据本地地址端口和对方端口查找主机对的连接
d = find_host_pair_connections(__FUNCTION__, &c->spd.this.host_addr
, c->spd.this.host_port
, (ip_address *)NULL
, c->spd.that.host_port);
}
}
* We're willing to settle for a connection that needs Peer IP
* instantiated: Road Warrior or Opportunistic.
* Look on list of connections for host pair with wildcard Peer IP
*/
// 根据本地地址端口和对方端口查找主机对的连接
d = find_host_pair_connections(__FUNCTION__, &c->spd.this.host_addr
, c->spd.this.host_port
, (ip_address *)NULL
, c->spd.that.host_port);
}
}
9.5.4 根据地址端口查找连接
/* find head of list of connections with this pair of hosts */
static struct connection *
find_host_pair_connections(const char *func
, const ip_address *myaddr, u_int16_t myport
, const ip_address *hisaddr, u_int16_t hisport)
{
char b1[ADDRTOT_BUF],b2[ADDRTOT_BUF];
// 根据本地地址,本地端口,对端地址,对端端口查找主机对
struct host_pair *hp = find_host_pair(myaddr, myport, hisaddr, hisport);
DBG(DBG_CONTROLMORE
, DBG_log("find_host_pair_conn (%s): %s:%d %s:%d -> hp:%s\n"
, func
, (addrtot(myaddr, 0, b1, sizeof(b1)), b1)
, myport
, hisaddr ? (addrtot(hisaddr, 0, b2, sizeof(b2)), b2) : "%any"
, hisport
, (hp && hp->connections) ? hp->connections->name : "none"));
// 如果找到主机对, 返回主机对对应的连接(这是个链表, 返回的是链表头)
return hp == NULL? NULL : hp->connections;
}
, DBG_log("find_host_pair_conn (%s): %s:%d %s:%d -> hp:%s\n"
, func
, (addrtot(myaddr, 0, b1, sizeof(b1)), b1)
, myport
, hisaddr ? (addrtot(hisaddr, 0, b2, sizeof(b2)), b2) : "%any"
, hisport
, (hp && hp->connections) ? hp->connections->name : "none"));
// 如果找到主机对, 返回主机对对应的连接(这是个链表, 返回的是链表头)
return hp == NULL? NULL : hp->connections;
}
9.5.5 查找合适安全策略路由的连接
/* Find the connection to connection c's peer's client with the
* largest value of .routing. All other things being equal,
* preference is given to c. If none is routed, return NULL.
*
* If erop is non-null, set *erop to a connection sharing both
* our client subnet and peer's client subnet with the largest value
* of .routing. If none is erouted, set *erop to NULL.
*
* The return value is used to find other connections sharing a route.
* *erop is used to find other connections sharing an eroute.
*/
struct connection *
route_owner(struct connection *c
, struct spd_route **srp
, struct connection **erop
, struct spd_route **esrp)
{
struct connection *d
, *best_ro = c
, *best_ero = c;
struct spd_route *srd, *src;
struct spd_route *best_sr, *best_esr;
enum routing_t best_routing, best_erouting;
* largest value of .routing. All other things being equal,
* preference is given to c. If none is routed, return NULL.
*
* If erop is non-null, set *erop to a connection sharing both
* our client subnet and peer's client subnet with the largest value
* of .routing. If none is erouted, set *erop to NULL.
*
* The return value is used to find other connections sharing a route.
* *erop is used to find other connections sharing an eroute.
*/
struct connection *
route_owner(struct connection *c
, struct spd_route **srp
, struct connection **erop
, struct spd_route **esrp)
{
struct connection *d
, *best_ro = c
, *best_ero = c;
struct spd_route *srd, *src;
struct spd_route *best_sr, *best_esr;
enum routing_t best_routing, best_erouting;
passert(oriented(*c));
best_sr = NULL;
best_esr = NULL;
best_routing = c->spd.routing;
best_erouting = best_routing;
best_sr = NULL;
best_esr = NULL;
best_routing = c->spd.routing;
best_erouting = best_routing;
// 遍历系统连接链表
for (d = connections; d != NULL; d = d->ac_next)
{
// 遍历每个连接的安全策略路由连接
for (srd = &d->spd; srd; srd = srd->next)
{
// 非路由,跳过
if (srd->routing == RT_UNROUTED)
continue;
// 遍历连接c的安全策略路由链表
for (src = &c->spd; src; src=src->next)
{
// 比较这两个安全策略路由参数是否匹配
// 对端子网
if (!samesubnet(&src->that.client, &srd->that.client))
continue;
// 对端协议
if (src->that.protocol != srd->that.protocol)
continue;
// 对端端口
if (src->that.port != srd->that.port)
continue;
passert(oriented(*d));
// best_routing初始化为c的路由
// 如果新路由的路由值更大, 更新best_ro
if (srd->routing > best_routing)
{
best_ro = d;
best_sr = srd;
best_routing = srd->routing;
}
// 比较本地子网
if (!samesubnet(&src->this.client, &srd->this.client))
continue;
// 本地协议
if (src->this.protocol != srd->this.protocol)
continue;
// 本地端口
if (src->this.port != srd->this.port)
continue;
// best_erouting初始化为c的路由
// 如果新路由的路由值更大, 更新best_ero
if (srd->routing > best_erouting)
{
best_ero = d;
best_esr = srd;
best_erouting = srd->routing;
}
}
}
}
// 打印调试信息
DBG(DBG_CONTROL,
{
char cib[CONN_INST_BUF];
err_t m = builddiag("route owner of \"%s\"%s %s:"
, c->name
, (fmt_conn_instance(c, cib), cib)
, enum_name(&routing_story, c->spd.routing));
for (d = connections; d != NULL; d = d->ac_next)
{
// 遍历每个连接的安全策略路由连接
for (srd = &d->spd; srd; srd = srd->next)
{
// 非路由,跳过
if (srd->routing == RT_UNROUTED)
continue;
// 遍历连接c的安全策略路由链表
for (src = &c->spd; src; src=src->next)
{
// 比较这两个安全策略路由参数是否匹配
// 对端子网
if (!samesubnet(&src->that.client, &srd->that.client))
continue;
// 对端协议
if (src->that.protocol != srd->that.protocol)
continue;
// 对端端口
if (src->that.port != srd->that.port)
continue;
passert(oriented(*d));
// best_routing初始化为c的路由
// 如果新路由的路由值更大, 更新best_ro
if (srd->routing > best_routing)
{
best_ro = d;
best_sr = srd;
best_routing = srd->routing;
}
// 比较本地子网
if (!samesubnet(&src->this.client, &srd->this.client))
continue;
// 本地协议
if (src->this.protocol != srd->this.protocol)
continue;
// 本地端口
if (src->this.port != srd->this.port)
continue;
// best_erouting初始化为c的路由
// 如果新路由的路由值更大, 更新best_ero
if (srd->routing > best_erouting)
{
best_ero = d;
best_esr = srd;
best_erouting = srd->routing;
}
}
}
}
// 打印调试信息
DBG(DBG_CONTROL,
{
char cib[CONN_INST_BUF];
err_t m = builddiag("route owner of \"%s\"%s %s:"
, c->name
, (fmt_conn_instance(c, cib), cib)
, enum_name(&routing_story, c->spd.routing));
if (!routed(best_ro->spd.routing))
m = builddiag("%s NULL", m);
else if (best_ro == c)
m = builddiag("%s self", m);
else
m = builddiag("%s \"%s\"%s %s", m
, best_ro->name
, (fmt_conn_instance(best_ro, cib), cib)
, enum_name(&routing_story, best_ro->spd.routing));
m = builddiag("%s NULL", m);
else if (best_ro == c)
m = builddiag("%s self", m);
else
m = builddiag("%s \"%s\"%s %s", m
, best_ro->name
, (fmt_conn_instance(best_ro, cib), cib)
, enum_name(&routing_story, best_ro->spd.routing));
if (erop != NULL)
{
m = builddiag("%s; eroute owner:", m);
if (!erouted(best_ero->spd.routing))
m = builddiag("%s NULL", m);
else if (best_ero == c)
m = builddiag("%s self", m);
else
m = builddiag("%s \"%s\"%s %s", m
, best_ero->name
, (fmt_conn_instance(best_ero, cib), cib)
, enum_name(&routing_story, best_ero->spd.routing));
}
{
m = builddiag("%s; eroute owner:", m);
if (!erouted(best_ero->spd.routing))
m = builddiag("%s NULL", m);
else if (best_ero == c)
m = builddiag("%s self", m);
else
m = builddiag("%s \"%s\"%s %s", m
, best_ero->name
, (fmt_conn_instance(best_ero, cib), cib)
, enum_name(&routing_story, best_ero->spd.routing));
}
DBG_log("%s", m);
});
// 将best_ero返回
if (erop != NULL)
*erop = erouted(best_erouting)? best_ero : NULL;
});
// 将best_ero返回
if (erop != NULL)
*erop = erouted(best_erouting)? best_ero : NULL;
// 将best_sr和best_esr返回
if (srp != NULL )
{
*srp = best_sr;
if (esrp != NULL )
*esrp = best_esr;
}
// 返回找到的best_ro
return routed(best_routing)? best_ro : NULL;
}
if (srp != NULL )
{
*srp = best_sr;
if (esrp != NULL )
*esrp = best_esr;
}
// 返回找到的best_ro
return routed(best_routing)? best_ro : NULL;
}
9.6 输出连接状态
void
show_connections_status(void)
{
struct connection *c;
int count, i;
struct connection **array;
/* make an array of connections, and sort it */
count=0;
// 连接链表计数
for (c = connections; c != NULL; c = c->ac_next)
{
count++;
}
// 分配能容纳所有连接指针的空间, 注意只是指针, 不是整个结构
array = alloc_bytes(sizeof(struct connection *)*count, "connection array");
count=0;
// 复制所有连接指针
for (c = connections; c != NULL; c = c->ac_next)
{
array[count++]=c;
}
// 复制所有连接指针
for (c = connections; c != NULL; c = c->ac_next)
{
array[count++]=c;
}
/* sort it! */
// 快速排序,按名称,类型,优先权值排序
qsort(array, count, sizeof(struct connection *), connection_compare_qsort);
// 快速排序,按名称,类型,优先权值排序
qsort(array, count, sizeof(struct connection *), connection_compare_qsort);
// 遍历所有连接
for (i=0; i<count; i++)
{
const char *ifn;
char instance[1 + 10 + 1];
char prio[POLICY_PRIO_BUF];
for (i=0; i<count; i++)
{
const char *ifn;
char instance[1 + 10 + 1];
char prio[POLICY_PRIO_BUF];
c = array[i];
// ipsec网卡名称
ifn = oriented(*c)? c->interface->ip_dev->id_rname : "";
// ipsec网卡名称
ifn = oriented(*c)? c->interface->ip_dev->id_rname : "";
instance[0] = '\0';
// 将实例连接的序列号转换为字符串
if (c->kind == CK_INSTANCE && c->instance_serial != 0)
snprintf(instance, sizeof(instance), "[%lu]", c->instance_serial);
// 将实例连接的序列号转换为字符串
if (c->kind == CK_INSTANCE && c->instance_serial != 0)
snprintf(instance, sizeof(instance), "[%lu]", c->instance_serial);
/* show topology */
{
char topo[CONNECTION_BUF];
struct spd_route *sr = &c->spd;
int num=0;
// 遍历安全策略路由
while (sr != NULL)
{
char srcip[ADDRTOT_BUF], dstip[ADDRTOT_BUF];
char thissemi[3+sizeof("srcup=")];
char thatsemi[3+sizeof("dstup=")];
char *thisup, *thatup;
// 输出连接信息到topo数组
(void) format_connection(topo, sizeof(topo), c, sr);
// 向whack输出
whack_log(RC_COMMENT, "\"%s\"%s: %s; %s; eroute owner: #%lu"
, c->name, instance, topo
, enum_name(&routing_story, sr->routing)
, sr->eroute_owner);
// 本地地址
if(addrbytesptr(&c->spd.this.host_srcip, NULL) == 0
|| isanyaddr(&c->spd.this.host_srcip)) {
strcpy(srcip, "unset");
} else {
addrtot(&sr->this.host_srcip, 0, srcip, sizeof(srcip));
}
// 对端地址
if(addrbytesptr(&c->spd.that.host_srcip, NULL) == 0
|| isanyaddr(&c->spd.that.host_srcip)) {
strcpy(dstip, "unset");
} else {
addrtot(&sr->that.host_srcip, 0, dstip, sizeof(dstip));
}
{
char topo[CONNECTION_BUF];
struct spd_route *sr = &c->spd;
int num=0;
// 遍历安全策略路由
while (sr != NULL)
{
char srcip[ADDRTOT_BUF], dstip[ADDRTOT_BUF];
char thissemi[3+sizeof("srcup=")];
char thatsemi[3+sizeof("dstup=")];
char *thisup, *thatup;
// 输出连接信息到topo数组
(void) format_connection(topo, sizeof(topo), c, sr);
// 向whack输出
whack_log(RC_COMMENT, "\"%s\"%s: %s; %s; eroute owner: #%lu"
, c->name, instance, topo
, enum_name(&routing_story, sr->routing)
, sr->eroute_owner);
// 本地地址
if(addrbytesptr(&c->spd.this.host_srcip, NULL) == 0
|| isanyaddr(&c->spd.this.host_srcip)) {
strcpy(srcip, "unset");
} else {
addrtot(&sr->this.host_srcip, 0, srcip, sizeof(srcip));
}
// 对端地址
if(addrbytesptr(&c->spd.that.host_srcip, NULL) == 0
|| isanyaddr(&c->spd.that.host_srcip)) {
strcpy(dstip, "unset");
} else {
addrtot(&sr->that.host_srcip, 0, dstip, sizeof(dstip));
}
thissemi[0]='\0';
thisup=thissemi;
if(sr->this.updown) {
thissemi[0]=';';
thissemi[1]=' ';
thissemi[2]='\0';
strcat(thissemi, "srcup=");
thisup=sr->this.updown;
}
thatsemi[0]='\0';
thatup=thatsemi;
if(sr->that.updown) {
thatsemi[0]=';';
thatsemi[1]=' ';
thatsemi[2]='\0';
strcat(thatsemi, "dstup=");
thatup=sr->that.updown;
}
// 向whack输出
whack_log(RC_COMMENT, "\"%s\"%s: srcip=%s; dstip=%s%s%s%s%s;"
, c->name, instance, srcip, dstip
, thissemi, thisup
, thatsemi, thatup);
sr = sr->next;
num++;
}
}
// 输出CA信息
/* show CAs */
if (c->spd.this.ca.ptr != NULL || c->spd.that.ca.ptr != NULL)
{
char this_ca[IDTOA_BUF], that_ca[IDTOA_BUF];
thisup=thissemi;
if(sr->this.updown) {
thissemi[0]=';';
thissemi[1]=' ';
thissemi[2]='\0';
strcat(thissemi, "srcup=");
thisup=sr->this.updown;
}
thatsemi[0]='\0';
thatup=thatsemi;
if(sr->that.updown) {
thatsemi[0]=';';
thatsemi[1]=' ';
thatsemi[2]='\0';
strcat(thatsemi, "dstup=");
thatup=sr->that.updown;
}
// 向whack输出
whack_log(RC_COMMENT, "\"%s\"%s: srcip=%s; dstip=%s%s%s%s%s;"
, c->name, instance, srcip, dstip
, thissemi, thisup
, thatsemi, thatup);
sr = sr->next;
num++;
}
}
// 输出CA信息
/* show CAs */
if (c->spd.this.ca.ptr != NULL || c->spd.that.ca.ptr != NULL)
{
char this_ca[IDTOA_BUF], that_ca[IDTOA_BUF];
dntoa_or_null(this_ca, IDTOA_BUF, c->spd.this.ca, "%any");
dntoa_or_null(that_ca, IDTOA_BUF, c->spd.that.ca, "%any");
dntoa_or_null(that_ca, IDTOA_BUF, c->spd.that.ca, "%any");
whack_log(RC_COMMENT
, "\"%s\"%s: CAs: '%s'...'%s'"
, c->name
, instance
, this_ca
, that_ca);
}
// 输出生命期
whack_log(RC_COMMENT
, "\"%s\"%s: ike_life: %lus; ipsec_life: %lus;"
" rekey_margin: %lus; rekey_fuzz: %lu%%; keyingtries: %lu"
, c->name
, instance
, (unsigned long) c->sa_ike_life_seconds
, (unsigned long) c->sa_ipsec_life_seconds
, (unsigned long) c->sa_rekey_margin
, (unsigned long) c->sa_rekey_fuzz
, (unsigned long) c->sa_keying_tries);
, "\"%s\"%s: CAs: '%s'...'%s'"
, c->name
, instance
, this_ca
, that_ca);
}
// 输出生命期
whack_log(RC_COMMENT
, "\"%s\"%s: ike_life: %lus; ipsec_life: %lus;"
" rekey_margin: %lus; rekey_fuzz: %lu%%; keyingtries: %lu"
, c->name
, instance
, (unsigned long) c->sa_ike_life_seconds
, (unsigned long) c->sa_ipsec_life_seconds
, (unsigned long) c->sa_rekey_margin
, (unsigned long) c->sa_rekey_fuzz
, (unsigned long) c->sa_keying_tries);
if (c->policy_next)
{
whack_log(RC_COMMENT
, "\"%s\"%s: policy_next: %s"
, c->name, instance, c->policy_next->name);
}
{
whack_log(RC_COMMENT
, "\"%s\"%s: policy_next: %s"
, c->name, instance, c->policy_next->name);
}
/* Note: we display key_from_DNS_on_demand as if policy [lr]KOD */
// 输出策略优先级信息
fmt_policy_prio(c->prio, prio);
whack_log(RC_COMMENT
, "\"%s\"%s: policy: %s%s%s; prio: %s; interface: %s; encap: %s;"
, c->name
, instance
, prettypolicy(c->policy)
, c->spd.this.key_from_DNS_on_demand? "+lKOD" : ""
, c->spd.that.key_from_DNS_on_demand? "+rKOD" : ""
, prio
, ifn
,c->forceencaps ? "udp" : "esp");
// 输出DPD信息
/* slightly complicated stuff to avoid extra crap */
if(c->dpd_timeout > 0 || DBGP(DBG_DPD)) {
whack_log(RC_COMMENT
, "\"%s\"%s: dpd: %s; delay:%lu; timeout:%lu; "
, c->name
, instance
, enum_name(&dpd_action_names, c->dpd_action)
, c->dpd_delay, c->dpd_timeout);
}
// 输出策略优先级信息
fmt_policy_prio(c->prio, prio);
whack_log(RC_COMMENT
, "\"%s\"%s: policy: %s%s%s; prio: %s; interface: %s; encap: %s;"
, c->name
, instance
, prettypolicy(c->policy)
, c->spd.this.key_from_DNS_on_demand? "+lKOD" : ""
, c->spd.that.key_from_DNS_on_demand? "+rKOD" : ""
, prio
, ifn
,c->forceencaps ? "udp" : "esp");
// 输出DPD信息
/* slightly complicated stuff to avoid extra crap */
if(c->dpd_timeout > 0 || DBGP(DBG_DPD)) {
whack_log(RC_COMMENT
, "\"%s\"%s: dpd: %s; delay:%lu; timeout:%lu; "
, c->name
, instance
, enum_name(&dpd_action_names, c->dpd_action)
, c->dpd_delay, c->dpd_timeout);
}
if(c->extra_debugging) {
whack_log(RC_COMMENT, "\"%s\"%s: debug: %s"
, c->name
, instance
, bitnamesof(debug_bit_names
, c->extra_debugging));
}
// 输出SA信息
whack_log(RC_COMMENT
, "\"%s\"%s: newest ISAKMP SA: #%ld; newest IPsec SA: #%ld; "
, c->name
, instance
, c->newest_isakmp_sa
, c->newest_ipsec_sa);
#ifdef IKE_ALG
// 输出IKE算法信息
ike_alg_show_connection(c, instance);
#endif
#ifdef KERNEL_ALG
// 输出内核算法信息
kernel_alg_show_connection(c, instance);
#endif
}
// 释放数组
pfree(array);
}
whack_log(RC_COMMENT, "\"%s\"%s: debug: %s"
, c->name
, instance
, bitnamesof(debug_bit_names
, c->extra_debugging));
}
// 输出SA信息
whack_log(RC_COMMENT
, "\"%s\"%s: newest ISAKMP SA: #%ld; newest IPsec SA: #%ld; "
, c->name
, instance
, c->newest_isakmp_sa
, c->newest_ipsec_sa);
#ifdef IKE_ALG
// 输出IKE算法信息
ike_alg_show_connection(c, instance);
#endif
#ifdef KERNEL_ALG
// 输出内核算法信息
kernel_alg_show_connection(c, instance);
#endif
}
// 释放数组
pfree(array);
}
...... 待续 ......
转载于:https://blog.51cto.com/enchen/157909