本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。
msn: yfydz_no1@hotmail.com
来源: http://yfydz.cublog.cn
msn: yfydz_no1@hotmail.com
来源: http://yfydz.cublog.cn
15. 快速模式协商
IKE野蛮协商处理函数基本都在programs/pluto/ikev1_quick.c中定义, 属于IKEv1协商的第2阶段, 协商完成后建立起两个方向的IPSEC SA用来保护实际的数据传输。
15.1 过程
快速模式:
Initiator Responder
----------- -----------
HDR*, HASH(1), SA0, SA1, Ni,
[, KE ] [, IDci, IDcr ] -->
qouck_outI1(发送初始化数据1)
<-- HDR*, HASH(2), SA0, SA1, Nr,
[, KE ] [, IDci, IDcr ]
quick_inI1_outR1(接收到初始化数据1, 发送响应数据1)
HDR*, HASH(3) -->
quick_inR1_outI2(接收到响应数据1,发送初始化数据2)
quick_inI2 (接收到初始化数据2,完成快速模式协商,
建立IPSec SA)
连接发起函数为ipsecdoi_initiate()函数, 在其中调用了main_outI1(), aggr_outI1()和quick_outI1()函数分别发起主模式,野蛮模式和快速模式的协商。另外也可以从complete_state_transition()函数(这里应该是主要的发起点), unpending()函数中发起。
15.2 发起方的第一个初始包
stf_status
quick_outI1(int whack_sock
, struct state *isakmp_sa
, struct connection *c
, lset_t policy
, unsigned long try
, so_serial_t replacing)
{
// 根据第一阶段协商出的ISAKMP SA状态复制出一个新的状态用于第2阶段
struct state *st = duplicate_state(isakmp_sa);
// 分配快速密钥交换结构
struct qke_continuation *qke = alloc_thing(struct qke_continuation
, "quick_outI1 KE");
stf_status e;
// 新状态的whack套接口
st->st_whack_sock = whack_sock;
// 新状态的连接
st->st_connection = c;
passert(c != NULL);
if(st->st_calculating) {
return STF_IGNORE;
}
// 设置新状态为当前状态
set_cur_state(st); /* we must reset before exit */
// 策略
st->st_policy = policy;
// 尝试次数
st->st_try = try;
// 协议端口信息
st->st_myuserprotoid = c->spd.this.protocol;
st->st_peeruserprotoid = c->spd.that.protocol;
st->st_myuserport = c->spd.this.port;
st->st_peeruserport = c->spd.that.port;
// 消息ID
st->st_msgid = generate_msgid(isakmp_sa);
// 状态类型为QUICK_I1
st->st_state = STATE_QUICK_I1;
// 将新状态插入系统状态哈希表
insert_state(st); /* needs cookies, connection, and msgid */
return STF_IGNORE;
}
// 设置新状态为当前状态
set_cur_state(st); /* we must reset before exit */
// 策略
st->st_policy = policy;
// 尝试次数
st->st_try = try;
// 协议端口信息
st->st_myuserprotoid = c->spd.this.protocol;
st->st_peeruserprotoid = c->spd.that.protocol;
st->st_myuserport = c->spd.this.port;
st->st_peeruserport = c->spd.that.port;
// 消息ID
st->st_msgid = generate_msgid(isakmp_sa);
// 状态类型为QUICK_I1
st->st_state = STATE_QUICK_I1;
// 将新状态插入系统状态哈希表
insert_state(st); /* needs cookies, connection, and msgid */
// 记录快速模式初始化信息, replacing为要替代的老的ISAKMP SA的序号
if (replacing == SOS_NOBODY)
openswan_log("initiating Quick Mode %s {using isakmp#%lu}"
, prettypolicy(policy)
, isakmp_sa->st_serialno);
else
openswan_log("initiating Quick Mode %s to replace #%lu {using isakmp#%lu}"
, prettypolicy(policy)
, replacing
, isakmp_sa->st_serialno);
/*
* See if pfs_group has been specified for this conn,
* if not, fallback to old use-same-as-P1 behaviour
*/
#ifdef IKE_ALG
// 查找该连接所用的PFS组, PFS: 完美向前加密
if (st->st_connection)
st->st_pfs_group = ike_alg_pfsgroup(st->st_connection
, st->st_policy);
if (!st->st_pfs_group)
#endif
/* If PFS specified, use the same group as during Phase 1:
* since no negotiation is possible, we pick one that is
* very likely supported.
*/
st->st_pfs_group = policy & POLICY_PFS? isakmp_sa->st_oakley.group : NULL;
// 填充快速模式密钥交换结构qke参数
// 第2阶段状态
qke->st = st;
// 第一阶段状态
qke->isakmp_sa = isakmp_sa;
// 替换的老状态
qke->replacing = replacing;
// 继续处理函数
qke->qke_pcrc.pcrc_func = quick_outI1_continue;
if(policy & POLICY_PFS) {
// 如果设置了PFS策略, 每次都要重新更新加密密钥, 进行密钥交换处理
e=build_ke(&qke->qke_pcrc, st, st->st_pfs_group, st->st_import);
} else {
// 否则构造NONCE载荷, 使用原来的密钥
e=build_nonce(&qke->qke_pcrc, st, st->st_import);
}
* See if pfs_group has been specified for this conn,
* if not, fallback to old use-same-as-P1 behaviour
*/
#ifdef IKE_ALG
// 查找该连接所用的PFS组, PFS: 完美向前加密
if (st->st_connection)
st->st_pfs_group = ike_alg_pfsgroup(st->st_connection
, st->st_policy);
if (!st->st_pfs_group)
#endif
/* If PFS specified, use the same group as during Phase 1:
* since no negotiation is possible, we pick one that is
* very likely supported.
*/
st->st_pfs_group = policy & POLICY_PFS? isakmp_sa->st_oakley.group : NULL;
// 填充快速模式密钥交换结构qke参数
// 第2阶段状态
qke->st = st;
// 第一阶段状态
qke->isakmp_sa = isakmp_sa;
// 替换的老状态
qke->replacing = replacing;
// 继续处理函数
qke->qke_pcrc.pcrc_func = quick_outI1_continue;
if(policy & POLICY_PFS) {
// 如果设置了PFS策略, 每次都要重新更新加密密钥, 进行密钥交换处理
e=build_ke(&qke->qke_pcrc, st, st->st_pfs_group, st->st_import);
} else {
// 否则构造NONCE载荷, 使用原来的密钥
e=build_nonce(&qke->qke_pcrc, st, st->st_import);
}
reset_globals();
return e;
}
}
// 继续函数, 完成了密钥处理后的执行函数
static void
quick_outI1_continue(struct pluto_crypto_req_cont *pcrc
, struct pluto_crypto_req *r
, err_t ugh)
{
struct qke_continuation *qke = (struct qke_continuation *)pcrc;
struct state *const st = qke->st;
stf_status e;
static void
quick_outI1_continue(struct pluto_crypto_req_cont *pcrc
, struct pluto_crypto_req *r
, err_t ugh)
{
struct qke_continuation *qke = (struct qke_continuation *)pcrc;
struct state *const st = qke->st;
stf_status e;
DBG(DBG_CONTROLMORE
, DBG_log("quick outI1: calculated ke+nonce, sending I1"));
, DBG_log("quick outI1: calculated ke+nonce, sending I1"));
st->st_calculating = FALSE;
/* XXX should check out ugh */
passert(ugh == NULL);
passert(cur_state == NULL);
passert(st != NULL);
// 设置当前状态
set_cur_state(st); /* we must reset before exit */
// 继续完成outI1操作
e = quick_outI1_tail(pcrc, r);
// 复位全局变量
reset_globals();
}
passert(ugh == NULL);
passert(cur_state == NULL);
passert(st != NULL);
// 设置当前状态
set_cur_state(st); /* we must reset before exit */
// 继续完成outI1操作
e = quick_outI1_tail(pcrc, r);
// 复位全局变量
reset_globals();
}
// outI1结尾操作,构造数据包
static stf_status
quick_outI1_tail(struct pluto_crypto_req_cont *pcrc
, struct pluto_crypto_req *r)
{
// 快速模式密钥交换结构
struct qke_continuation *qke = (struct qke_continuation *)pcrc;
// 状态
struct state *st = qke->st;
// 连接
struct connection *c = st->st_connection;
// 第一阶段状态, 描述ISAKMP SA, 用于保护第2阶段的协商
struct state *isakmp_sa = qke->isakmp_sa;
pb_stream reply; /* not really a reply */
pb_stream rbody;
u_char /* set by START_HASH_PAYLOAD: */
*r_hashval, /* where in reply to jam hash value */
*r_hash_start; /* start of what is to be hashed */
// 检查是否有内部机(是×××网关)
bool has_client = c->spd.this.has_client || c->spd.that.has_client ||
c->spd.this.protocol || c->spd.that.protocol ||
c->spd.this.port || c->spd.that.port;
// 这个有意义么?不刚从st->st_connection赋值过来的嘛
st->st_connection = c;
#ifdef NAT_TRAVERSAL
if (isakmp_sa->hidden_variables.st_nat_traversal & NAT_T_DETECTED) {
// 如果检测到了NAT穿越, 更新端口
/* Duplicate nat_traversal status in new state */
st->hidden_variables.st_nat_traversal = isakmp_sa->hidden_variables.st_nat_traversal;
if (isakmp_sa->hidden_variables.st_nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME)) {
has_client = TRUE;
}
nat_traversal_change_port_lookup(NULL, st);
}
else {
st->hidden_variables.st_nat_traversal = 0;
}
#endif
if (isakmp_sa->hidden_variables.st_nat_traversal & NAT_T_DETECTED) {
// 如果检测到了NAT穿越, 更新端口
/* Duplicate nat_traversal status in new state */
st->hidden_variables.st_nat_traversal = isakmp_sa->hidden_variables.st_nat_traversal;
if (isakmp_sa->hidden_variables.st_nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME)) {
has_client = TRUE;
}
nat_traversal_change_port_lookup(NULL, st);
}
else {
st->hidden_variables.st_nat_traversal = 0;
}
#endif
/* set up reply */
// 初始化回应包缓冲区
init_pbs(&reply, reply_buffer, sizeof(reply_buffer), "reply packet");
// 初始化回应包缓冲区
init_pbs(&reply, reply_buffer, sizeof(reply_buffer), "reply packet");
/* HDR* out */
{
struct isakmp_hdr hdr;
// 填充ISAKMP头结构
hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION;
// 下一载荷是哈希载荷
hdr.isa_np = ISAKMP_NEXT_HASH;
// 快速描述交换
hdr.isa_xchg = ISAKMP_XCHG_QUICK;
// 消息ID
hdr.isa_msgid = st->st_msgid;
// 数据是加密的
hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION;
// 拷贝双方的cookie
memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE);
memcpy(hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE);
if (!out_struct(&hdr, &isakmp_hdr_desc, &reply, &rbody))
{
reset_cur_state();
return STF_INTERNAL_ERROR;
}
}
{
struct isakmp_hdr hdr;
// 填充ISAKMP头结构
hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION;
// 下一载荷是哈希载荷
hdr.isa_np = ISAKMP_NEXT_HASH;
// 快速描述交换
hdr.isa_xchg = ISAKMP_XCHG_QUICK;
// 消息ID
hdr.isa_msgid = st->st_msgid;
// 数据是加密的
hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION;
// 拷贝双方的cookie
memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE);
memcpy(hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE);
if (!out_struct(&hdr, &isakmp_hdr_desc, &reply, &rbody))
{
reset_cur_state();
return STF_INTERNAL_ERROR;
}
}
/* HASH(1) -- create and note space to be filled later */
// 构造哈希载荷
START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_SA);
// 构造哈希载荷
START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_SA);
/* SA out */
/* Emit SA payload based on a subset of the policy bits.
* POLICY_COMPRESS is considered iff we can do IPcomp.
*/
{
lset_t pm = POLICY_ENCRYPT | POLICY_AUTHENTICATE;
// 检查是否能进行IP压缩处理
if (can_do_IPcomp)
pm |= POLICY_COMPRESS;
// 填充SA载荷, 下一载荷是NONCE载荷
if (!out_sa(&rbody
, &ipsec_sadb[(st->st_policy & pm) >> POLICY_IPSEC_SHIFT]
, st, FALSE, FALSE, ISAKMP_NEXT_NONCE))
{
reset_cur_state();
return STF_INTERNAL_ERROR;
}
}
* POLICY_COMPRESS is considered iff we can do IPcomp.
*/
{
lset_t pm = POLICY_ENCRYPT | POLICY_AUTHENTICATE;
// 检查是否能进行IP压缩处理
if (can_do_IPcomp)
pm |= POLICY_COMPRESS;
// 填充SA载荷, 下一载荷是NONCE载荷
if (!out_sa(&rbody
, &ipsec_sadb[(st->st_policy & pm) >> POLICY_IPSEC_SHIFT]
, st, FALSE, FALSE, ISAKMP_NEXT_NONCE))
{
reset_cur_state();
return STF_INTERNAL_ERROR;
}
}
{
int np;
int np;
if(st->st_policy & POLICY_PFS) {
// 如果使用PFS, NONCE载荷的下一载荷是KE载荷, 重新协商密钥
np = ISAKMP_NEXT_KE;
} else {
// 否则如果如果带内部机,下一载荷是ID载荷,否则不再带载荷
if(has_client) {
np = ISAKMP_NEXT_ID;
} else {
np = ISAKMP_NEXT_NONE;
}
}
// 如果使用PFS, NONCE载荷的下一载荷是KE载荷, 重新协商密钥
np = ISAKMP_NEXT_KE;
} else {
// 否则如果如果带内部机,下一载荷是ID载荷,否则不再带载荷
if(has_client) {
np = ISAKMP_NEXT_ID;
} else {
np = ISAKMP_NEXT_NONE;
}
}
/* Ni out */
// 填充NONCE载荷
if (!ship_nonce(&st->st_ni, r, &rbody
, np
, "Ni"))
{
reset_cur_state();
return STF_INTERNAL_ERROR;
}
}
// 填充NONCE载荷
if (!ship_nonce(&st->st_ni, r, &rbody
, np
, "Ni"))
{
reset_cur_state();
return STF_INTERNAL_ERROR;
}
}
/* [ KE ] out (for PFS) */
if (st->st_pfs_group != NULL)
{
// PFS情况下填充KE载荷
if (!ship_KE(st, r, &st->st_gi
, &rbody
, has_client? ISAKMP_NEXT_ID : ISAKMP_NEXT_NONE))
{
reset_cur_state();
return STF_INTERNAL_ERROR;
}
}
if (st->st_pfs_group != NULL)
{
// PFS情况下填充KE载荷
if (!ship_KE(st, r, &st->st_gi
, &rbody
, has_client? ISAKMP_NEXT_ID : ISAKMP_NEXT_NONE))
{
reset_cur_state();
return STF_INTERNAL_ERROR;
}
}
/* [ IDci, IDcr ] out */
if (has_client)
{
// 填充ID载荷, 包括发起方ID和响应方ID
/* IDci (we are initiator), then IDcr (peer is responder) */
if (!emit_subnet_id(&c->spd.this.client
, ISAKMP_NEXT_ID
, st->st_myuserprotoid
, st->st_myuserport, &rbody)
|| !emit_subnet_id(&c->spd.that.client
, ISAKMP_NEXT_NONE
, st->st_peeruserprotoid
, st->st_peeruserport, &rbody))
{
reset_cur_state();
return STF_INTERNAL_ERROR;
}
}
if (has_client)
{
// 填充ID载荷, 包括发起方ID和响应方ID
/* IDci (we are initiator), then IDcr (peer is responder) */
if (!emit_subnet_id(&c->spd.this.client
, ISAKMP_NEXT_ID
, st->st_myuserprotoid
, st->st_myuserport, &rbody)
|| !emit_subnet_id(&c->spd.that.client
, ISAKMP_NEXT_NONE
, st->st_peeruserprotoid
, st->st_peeruserport, &rbody))
{
reset_cur_state();
return STF_INTERNAL_ERROR;
}
}
#ifdef NAT_TRAVERSAL
if ((st->hidden_variables.st_nat_traversal & NAT_T_WITH_NATOA)
&& (!(st->st_policy & POLICY_TUNNEL))
&& (st->hidden_variables.st_nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME))) {
/** Send NAT-OA if our address is NATed */
// 如果需要进行NAT穿越,填充NAT信息ID载荷
if (!nat_traversal_add_natoa(ISAKMP_NEXT_NONE, &rbody, st)) {
reset_cur_state();
return STF_INTERNAL_ERROR;
}
}
#endif
if ((st->hidden_variables.st_nat_traversal & NAT_T_WITH_NATOA)
&& (!(st->st_policy & POLICY_TUNNEL))
&& (st->hidden_variables.st_nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME))) {
/** Send NAT-OA if our address is NATed */
// 如果需要进行NAT穿越,填充NAT信息ID载荷
if (!nat_traversal_add_natoa(ISAKMP_NEXT_NONE, &rbody, st)) {
reset_cur_state();
return STF_INTERNAL_ERROR;
}
}
#endif
/* finish computing HASH(1), inserting it in output */
// 完成快速模式的哈希计算
(void) quick_mode_hash12(r_hashval, r_hash_start, rbody.cur
, st, &st->st_msgid, FALSE);
// 完成快速模式的哈希计算
(void) quick_mode_hash12(r_hashval, r_hash_start, rbody.cur
, st, &st->st_msgid, FALSE);
/* encrypt message, except for fixed part of header */
// 初始化阶段2的初始化向量
init_phase2_iv(isakmp_sa, &st->st_msgid);
st->st_new_iv_len = isakmp_sa->st_new_iv_len;
set_new_iv(st, isakmp_sa->st_new_iv);
// 加密数据
if (!encrypt_message(&rbody, st))
{
reset_cur_state();
return STF_INTERNAL_ERROR;
}
// 初始化阶段2的初始化向量
init_phase2_iv(isakmp_sa, &st->st_msgid);
st->st_new_iv_len = isakmp_sa->st_new_iv_len;
set_new_iv(st, isakmp_sa->st_new_iv);
// 加密数据
if (!encrypt_message(&rbody, st))
{
reset_cur_state();
return STF_INTERNAL_ERROR;
}
/* save packet, now that we know its size */
clonetochunk(st->st_tpacket, reply.start, pbs_offset(&reply)
, "reply packet from quick_outI1");
clonetochunk(st->st_tpacket, reply.start, pbs_offset(&reply)
, "reply packet from quick_outI1");
/* send the packet */
// 发送数据包
send_packet(st, "quick_outI1", TRUE);
// 重新调度状态事件, 超时重发
delete_event(st);
event_schedule(EVENT_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0, st);
// 发送数据包
send_packet(st, "quick_outI1", TRUE);
// 重新调度状态事件, 超时重发
delete_event(st);
event_schedule(EVENT_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0, st);
// 输出信息
if (qke->replacing == SOS_NOBODY)
whack_log(RC_NEW_STATE + STATE_QUICK_I1
, "%s: initiate"
, enum_name(&state_names, st->st_state));
else
whack_log(RC_NEW_STATE + STATE_QUICK_I1
, "%s: initiate to replace #%lu"
, enum_name(&state_names, st->st_state)
, qke->replacing);
return STF_OK;
}
}
15.3 响应方收到发起方初始化包, 发送第一响应包
/* Handle first message of Phase 2 -- Quick Mode.
* HDR*, HASH(1), SA, Ni [, KE ] [, IDci, IDcr ] -->
* HDR*, HASH(2), SA, Nr [, KE ] [, IDci, IDcr ]
* (see RFC 2409 "IKE" 5.5)
* Installs inbound IPsec SAs.
* Although this seems early, we know enough to do so, and
* this way we know that it is soon enough to catch all
* packets that other side could send using this IPsec SA.
*
* Broken into parts to allow asynchronous DNS for TXT records:
*
* - quick_inI1_outR1 starts the ball rolling.
* It checks and parses enough to learn the Phase 2 IDs
*
* - quick_inI1_outR1_authtail does the rest of the job
* unless DNS must be consulted. In that case,
* it starts a DNS query, salts away what is needed
* to continue, and suspends. Calls
* + quick_inI1_outR1_start_query
* + quick_inI1_outR1_process_answer
*
* - quick_inI1_outR1_continue will restart quick_inI1_outR1_authtail
* when DNS comes back with an answer.
*
* A big chunk of quick_inI1_outR1_authtail is executed twice.
* This is necessary because the set of connections
* might change while we are awaiting DNS.
* When first called, gateways_from_dns == NULL. If DNS is
* consulted asynchronously, gateways_from_dns != NULL the second time.
* Remember that our state object might disappear too!
*
*
* If the connection is opportunistic, we must verify delegation.
*
* 1. Check that we are authorized to be SG for
* our client. We look for the TXT record that
* delegates us. We also check that the public
* key (if present) matches the private key we used.
* Eventually, we should probably require DNSsec
* authentication for our side.
*
* 2. If our client TXT record did not include a
* public key, check the KEY record indicated
* by the identity in the TXT record.
*
* 3. If the peer's client is the peer itself, we
* consider it authenticated. Otherwise, we check
* the TXT record for the client to see that
* the identity of the SG matches the peer and
* that some public key (if present in the TXT)
* matches. We need not check the public key if
* it isn't in the TXT record.
*
* Since p isn't yet instantiated, we need to look
* in c for description of peer.
*
* We cannot afford to block waiting for a DNS query.
* The code here is structured as two halves:
* - process the result of just completed
* DNS query (if any)
* - if another query is needed, initiate the next
* DNS query and suspend
*/
stf_status
quick_inI1_outR1(struct msg_digest *md)
{
// 相关状态, 这个状态是阶段1协商完的状态, 即描述ISAKMP SA的状态结构
const struct state *const p1st = md->st;
struct connection *c = p1st->st_connection;
// 输入数据包的ID载荷链表
struct payload_digest *const id_pd = md->chain[ISAKMP_NEXT_ID];
struct verify_oppo_bundle b;
quick_inI1_outR1(struct msg_digest *md)
{
// 相关状态, 这个状态是阶段1协商完的状态, 即描述ISAKMP SA的状态结构
const struct state *const p1st = md->st;
struct connection *c = p1st->st_connection;
// 输入数据包的ID载荷链表
struct payload_digest *const id_pd = md->chain[ISAKMP_NEXT_ID];
struct verify_oppo_bundle b;
/* HASH(1) in */
// 计算并检查输入包的哈希值,错误的话返回
CHECK_QUICK_HASH(md
, quick_mode_hash12(hash_val, hash_pbs->roof, md->message_pbs.roof
, p1st, &md->hdr.isa_msgid, FALSE)
, "HASH(1)", "Quick I1");
// 计算并检查输入包的哈希值,错误的话返回
CHECK_QUICK_HASH(md
, quick_mode_hash12(hash_val, hash_pbs->roof, md->message_pbs.roof
, p1st, &md->hdr.isa_msgid, FALSE)
, "HASH(1)", "Quick I1");
/* [ IDci, IDcr ] in
* We do this now (probably out of physical order) because
* we wish to select the correct connection before we consult
* it for policy.
*/
// ID载荷非空
if (id_pd != NULL)
{
/* ??? we are assuming IPSEC_DOI */
* We do this now (probably out of physical order) because
* we wish to select the correct connection before we consult
* it for policy.
*/
// ID载荷非空
if (id_pd != NULL)
{
/* ??? we are assuming IPSEC_DOI */
/* IDci (initiator is peer) */
// 解码发起方ID载荷, 对方是快速模式发起方
if (!decode_net_id(&id_pd->payload.ipsec_id, &id_pd->pbs
, &b.his.net, "peer client"))
return STF_FAIL + INVALID_ID_INFORMATION;
// 解码发起方ID载荷, 对方是快速模式发起方
if (!decode_net_id(&id_pd->payload.ipsec_id, &id_pd->pbs
, &b.his.net, "peer client"))
return STF_FAIL + INVALID_ID_INFORMATION;
/* Hack for MS 818043 NAT-T Update */
// 如果ID是FQDN格式(域名),将IP子网参数置0
if (id_pd->payload.ipsec_id.isaiid_idtype == ID_FQDN)
memset(&b.his.net, 0, sizeof(ip_subnet));
// 如果ID是FQDN格式(域名),将IP子网参数置0
if (id_pd->payload.ipsec_id.isaiid_idtype == ID_FQDN)
memset(&b.his.net, 0, sizeof(ip_subnet));
if (id_pd->payload.ipsec_id.isaiid_idtype == ID_FQDN)
happy(addrtosubnet(&c->spd.that.host_addr, &b.his.net));
happy(addrtosubnet(&c->spd.that.host_addr, &b.his.net));
/* End Hack for MS 818043 NAT-T Update */
// 对方的协议和端口参数
b.his.proto = id_pd->payload.ipsec_id.isaiid_protoid;
b.his.port = id_pd->payload.ipsec_id.isaiid_port;
b.his.net.addr.u.v4.sin_port = htons(b.his.port);
// 对方的协议和端口参数
b.his.proto = id_pd->payload.ipsec_id.isaiid_protoid;
b.his.port = id_pd->payload.ipsec_id.isaiid_port;
b.his.net.addr.u.v4.sin_port = htons(b.his.port);
/* IDcr (we are responder) */
// 解码响应方ID载荷,本地是快速模式响应方
if (!decode_net_id(&id_pd->next->payload.ipsec_id, &id_pd->next->pbs
, &b.my.net, "our client"))
return STF_FAIL + INVALID_ID_INFORMATION;
// 本地的协议和端口参数
b.my.proto = id_pd->next->payload.ipsec_id.isaiid_protoid;
b.my.port = id_pd->next->payload.ipsec_id.isaiid_port;
b.my.net.addr.u.v4.sin_port = htons(b.my.port);
}
else
{
// ID载荷为空, 使用地址作为ID
/* implicit IDci and IDcr: peer and self */
if (!sameaddrtype(&c->spd.this.host_addr, &c->spd.that.host_addr))
return STF_FAIL;
// 将连接地址作为bundle的地址参数
happy(addrtosubnet(&c->spd.this.host_addr, &b.my.net));
happy(addrtosubnet(&c->spd.that.host_addr, &b.his.net));
// 协议端口参数置为0
b.his.proto = b.my.proto = 0;
b.his.port = b.my.port = 0;
}
b.step = vos_start;
b.md = md;
// 初始化向量
b.new_iv_len = p1st->st_new_iv_len;
save_new_iv(p1st, b.new_iv);
// 认证结束处理
return quick_inI1_outR1_authtail(&b, NULL);
}
// 解码响应方ID载荷,本地是快速模式响应方
if (!decode_net_id(&id_pd->next->payload.ipsec_id, &id_pd->next->pbs
, &b.my.net, "our client"))
return STF_FAIL + INVALID_ID_INFORMATION;
// 本地的协议和端口参数
b.my.proto = id_pd->next->payload.ipsec_id.isaiid_protoid;
b.my.port = id_pd->next->payload.ipsec_id.isaiid_port;
b.my.net.addr.u.v4.sin_port = htons(b.my.port);
}
else
{
// ID载荷为空, 使用地址作为ID
/* implicit IDci and IDcr: peer and self */
if (!sameaddrtype(&c->spd.this.host_addr, &c->spd.that.host_addr))
return STF_FAIL;
// 将连接地址作为bundle的地址参数
happy(addrtosubnet(&c->spd.this.host_addr, &b.my.net));
happy(addrtosubnet(&c->spd.that.host_addr, &b.his.net));
// 协议端口参数置为0
b.his.proto = b.my.proto = 0;
b.his.port = b.my.port = 0;
}
b.step = vos_start;
b.md = md;
// 初始化向量
b.new_iv_len = p1st->st_new_iv_len;
save_new_iv(p1st, b.new_iv);
// 认证结束处理
return quick_inI1_outR1_authtail(&b, NULL);
}
static stf_status
quick_inI1_outR1_authtail(struct verify_oppo_bundle *b
, struct adns_continuation *ac)
{
// 消息摘要
struct msg_digest *md = b->md;
// 阶段1的状态
struct state *const p1st = md->st;
// 阶段1连接
struct connection *c = p1st->st_connection;
ip_subnet *our_net = &b->my.net
, *his_net = &b->his.net;
quick_inI1_outR1_authtail(struct verify_oppo_bundle *b
, struct adns_continuation *ac)
{
// 消息摘要
struct msg_digest *md = b->md;
// 阶段1的状态
struct state *const p1st = md->st;
// 阶段1连接
struct connection *c = p1st->st_connection;
ip_subnet *our_net = &b->my.net
, *his_net = &b->his.net;
/* Now that we have identities of client subnets, we must look for
* a suitable connection (our current one only matches for hosts).
*/
{
// 根据子网地址(subnet),协议,端口查找连接, 前面的连接c只是根据双方网关地址来找的,
// 两者可能相同, 也可能不同
struct connection *p = find_client_connection(c
, our_net, his_net, b->my.proto, b->my.port, b->his.proto, b->his.port);
* a suitable connection (our current one only matches for hosts).
*/
{
// 根据子网地址(subnet),协议,端口查找连接, 前面的连接c只是根据双方网关地址来找的,
// 两者可能相同, 也可能不同
struct connection *p = find_client_connection(c
, our_net, his_net, b->my.proto, b->my.port, b->his.proto, b->his.port);
#ifdef NAT_TRAVERSAL
// 这个宏是比较paranoid了, 表示传输模式虽然有安全问题但还是要用传输模式
// 对于网关, RFC中定义只需要支持通道(tunnel)模式就行了,不必要支持传输模式
#ifdef I_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT
// 如果检测到NAT穿越
if( (p1st->hidden_variables.st_nat_traversal & NAT_T_DETECTED)
// 是传输模式
&& !(p1st->st_policy & POLICY_TUNNEL)
// 本地是在NAT后?
&& (p1st->hidden_variables.st_nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME))
// 没找到客户端连接
&& (p == NULL) )
{
// 将p赋值为c
p = c;
DBG(DBG_CONTROL, DBG_log("using (something) old for transport mode connection \"%s\"", p->name));
}
#endif
#endif
// 这个宏是比较paranoid了, 表示传输模式虽然有安全问题但还是要用传输模式
// 对于网关, RFC中定义只需要支持通道(tunnel)模式就行了,不必要支持传输模式
#ifdef I_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT
// 如果检测到NAT穿越
if( (p1st->hidden_variables.st_nat_traversal & NAT_T_DETECTED)
// 是传输模式
&& !(p1st->st_policy & POLICY_TUNNEL)
// 本地是在NAT后?
&& (p1st->hidden_variables.st_nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME))
// 没找到客户端连接
&& (p == NULL) )
{
// 将p赋值为c
p = c;
DBG(DBG_CONTROL, DBG_log("using (something) old for transport mode connection \"%s\"", p->name));
}
#endif
#endif
if (p == NULL)
{
// 如果没找到合适连接, 输出相关信息, 返回错误
/* This message occurs in very puzzling circumstances
* so we must add as much information and beauty as we can.
*/
struct end
me = c->spd.this,
he = c->spd.that;
char buf[2*SUBNETTOT_BUF + 2*ADDRTOT_BUF + 2*IDTOA_BUF + 2*ADDRTOT_BUF + 12]; /* + 12 for separating */
size_t l;
{
// 如果没找到合适连接, 输出相关信息, 返回错误
/* This message occurs in very puzzling circumstances
* so we must add as much information and beauty as we can.
*/
struct end
me = c->spd.this,
he = c->spd.that;
char buf[2*SUBNETTOT_BUF + 2*ADDRTOT_BUF + 2*IDTOA_BUF + 2*ADDRTOT_BUF + 12]; /* + 12 for separating */
size_t l;
me.client = *our_net;
me.has_client = !subnetisaddr(our_net, &me.host_addr);
me.protocol = b->my.proto;
me.port = b->my.port;
me.has_client = !subnetisaddr(our_net, &me.host_addr);
me.protocol = b->my.proto;
me.port = b->my.port;
he.client = *his_net;
he.has_client = !subnetisaddr(his_net, &he.host_addr);
he.protocol = b->his.proto;
he.port = b->his.port;
// 格式化本地地址信息参数
l = format_end(buf, sizeof(buf), &me, NULL, TRUE, LEMPTY);
l += snprintf(buf + l, sizeof(buf) - l, "...");
// 格式化本地地址信息参数
(void)format_end(buf + l, sizeof(buf) - l, &he, NULL, FALSE, LEMPTY);
openswan_log("cannot respond to IPsec SA request"
" because no connection is known for %s"
, buf);
return STF_FAIL + INVALID_ID_INFORMATION;
}
else if (p != c)
{
// 两个连接不同
/* We've got a better connection: it can support the
* specified clients. But it may need instantiation.
*/
if (p->kind == CK_TEMPLATE)
{
// 如果p是模板连接(动态连接)
/* Yup, it needs instantiation. How much?
* Is it a Road Warrior connection (simple)
* or is it an Opportunistic connection (needing gw validation)?
*/
if (p->policy & POLICY_OPPO)
{
// 如果要使用OE处理, 进行相关处理, 分析略
/* Opportunistic case: delegation must be verified.
* Here be dragons.
*/
enum verify_oppo_step next_step;
ip_address our_client, his_client;
he.has_client = !subnetisaddr(his_net, &he.host_addr);
he.protocol = b->his.proto;
he.port = b->his.port;
// 格式化本地地址信息参数
l = format_end(buf, sizeof(buf), &me, NULL, TRUE, LEMPTY);
l += snprintf(buf + l, sizeof(buf) - l, "...");
// 格式化本地地址信息参数
(void)format_end(buf + l, sizeof(buf) - l, &he, NULL, FALSE, LEMPTY);
openswan_log("cannot respond to IPsec SA request"
" because no connection is known for %s"
, buf);
return STF_FAIL + INVALID_ID_INFORMATION;
}
else if (p != c)
{
// 两个连接不同
/* We've got a better connection: it can support the
* specified clients. But it may need instantiation.
*/
if (p->kind == CK_TEMPLATE)
{
// 如果p是模板连接(动态连接)
/* Yup, it needs instantiation. How much?
* Is it a Road Warrior connection (simple)
* or is it an Opportunistic connection (needing gw validation)?
*/
if (p->policy & POLICY_OPPO)
{
// 如果要使用OE处理, 进行相关处理, 分析略
/* Opportunistic case: delegation must be verified.
* Here be dragons.
*/
enum verify_oppo_step next_step;
ip_address our_client, his_client;
passert(subnetishost(our_net) && subnetishost(his_net));
networkof(our_net, &our_client);
networkof(his_net, &his_client);
networkof(our_net, &our_client);
networkof(his_net, &his_client);
next_step = quick_inI1_outR1_process_answer(b, ac, p1st);
if (next_step == vos_fail)
return STF_FAIL + INVALID_ID_INFORMATION;
if (next_step == vos_fail)
return STF_FAIL + INVALID_ID_INFORMATION;
/* short circuit: if peer's client is self,
* accept that we've verified delegation in Phase 1
*/
if (next_step == vos_his_client
&& sameaddr(&c->spd.that.host_addr, &his_client))
next_step = vos_done;
* accept that we've verified delegation in Phase 1
*/
if (next_step == vos_his_client
&& sameaddr(&c->spd.that.host_addr, &his_client))
next_step = vos_done;
/* the second chunk: initiate the next DNS query (if any) */
DBG(DBG_CONTROL,
{
char ours[SUBNETTOT_BUF];
char his[SUBNETTOT_BUF];
DBG(DBG_CONTROL,
{
char ours[SUBNETTOT_BUF];
char his[SUBNETTOT_BUF];
subnettot(&c->spd.this.client, 0, ours, sizeof(ours));
subnettot(&c->spd.that.client, 0, his, sizeof(his));
subnettot(&c->spd.that.client, 0, his, sizeof(his));
DBG_log("responding on demand from %s to %s new state: %s"
, ours, his, verify_step_name[next_step]);
});
, ours, his, verify_step_name[next_step]);
});
/* start next DNS query and suspend (if necessary) */
if (next_step != vos_done)
return quick_inI1_outR1_start_query(b, next_step);
if (next_step != vos_done)
return quick_inI1_outR1_start_query(b, next_step);
/* Instantiate inbound Opportunistic connection,
* carrying over authenticated peer ID
* and filling in a few more details.
* We used to include gateways_from_dns, but that
* seems pointless at this stage of negotiation.
* We should record DNS sec use, if any -- belongs in
* state during perhaps.
*/
p = oppo_instantiate(p, &c->spd.that.host_addr, &c->spd.that.id
, NULL, &our_client, &his_client);
}
else
{
// 将连接实例化, 使用阶段1连接的对方地址和ID
/* Plain Road Warrior:
* instantiate, carrying over authenticated peer ID
*/
p = rw_instantiate(p, &c->spd.that.host_addr,
his_net,
&c->spd.that.id);
}
}
#ifdef DEBUG
/* temporarily bump up cur_debugging to get "using..." message
* printed if we'd want it with new connection.
*/
{
lset_t old_cur_debugging = cur_debugging;
* carrying over authenticated peer ID
* and filling in a few more details.
* We used to include gateways_from_dns, but that
* seems pointless at this stage of negotiation.
* We should record DNS sec use, if any -- belongs in
* state during perhaps.
*/
p = oppo_instantiate(p, &c->spd.that.host_addr, &c->spd.that.id
, NULL, &our_client, &his_client);
}
else
{
// 将连接实例化, 使用阶段1连接的对方地址和ID
/* Plain Road Warrior:
* instantiate, carrying over authenticated peer ID
*/
p = rw_instantiate(p, &c->spd.that.host_addr,
his_net,
&c->spd.that.id);
}
}
#ifdef DEBUG
/* temporarily bump up cur_debugging to get "using..." message
* printed if we'd want it with new connection.
*/
{
lset_t old_cur_debugging = cur_debugging;
set_debugging(cur_debugging | p->extra_debugging);
DBG(DBG_CONTROL, DBG_log("using connection \"%s\"", p->name));
set_debugging(old_cur_debugging);
}
#endif
// 将阶段1用的连接更新为现在找到的连接
c = p;
}
/* fill in the client's true ip address/subnet */
// 如果连接配置中对方子网未明确定义, 将其赋为明确值
if (p->spd.that.has_client_wildcard)
{
p->spd.that.client = *his_net;
p->spd.that.has_client_wildcard = FALSE;
}
DBG(DBG_CONTROL, DBG_log("using connection \"%s\"", p->name));
set_debugging(old_cur_debugging);
}
#endif
// 将阶段1用的连接更新为现在找到的连接
c = p;
}
/* fill in the client's true ip address/subnet */
// 如果连接配置中对方子网未明确定义, 将其赋为明确值
if (p->spd.that.has_client_wildcard)
{
p->spd.that.client = *his_net;
p->spd.that.has_client_wildcard = FALSE;
}
/* fill in the client's true port */
// 如果连接配置中对方端口未明确定义, 将其赋为明确值
if (p->spd.that.has_port_wildcard)
{
int port = htons(b->his.port);
setportof(port, &p->spd.that.host_addr);
setportof(port, &p->spd.that.client.addr);
p->spd.that.port = b->his.port;
p->spd.that.has_port_wildcard = FALSE;
}
// 如果连接配置中对方端口未明确定义, 将其赋为明确值
if (p->spd.that.has_port_wildcard)
{
int port = htons(b->his.port);
setportof(port, &p->spd.that.host_addr);
setportof(port, &p->spd.that.client.addr);
p->spd.that.port = b->his.port;
p->spd.that.has_port_wildcard = FALSE;
}
#ifdef VIRTUAL_IP
else if (is_virtual_connection(c))
// 如果是虚拟连接(通常是×××客户端连接×××网关,虽然只有一台设备,但应用数据使用虚拟的
// 内部地址进行通信, 在外面封装外部地址, 而不是直接使用外部地址,这个内部地址通常可以
// 通过网关分配),更新内部地址
{
c->spd.that.client = *his_net;
c->spd.that.virt = NULL;
if (subnetishost(his_net) && addrinsubnet(&c->spd.that.host_addr, his_net))
c->spd.that.has_client = FALSE;
}
#endif
}
passert((p1st->st_policy & POLICY_PFS)==0 || p1st->st_pfs_group != NULL );
else if (is_virtual_connection(c))
// 如果是虚拟连接(通常是×××客户端连接×××网关,虽然只有一台设备,但应用数据使用虚拟的
// 内部地址进行通信, 在外面封装外部地址, 而不是直接使用外部地址,这个内部地址通常可以
// 通过网关分配),更新内部地址
{
c->spd.that.client = *his_net;
c->spd.that.virt = NULL;
if (subnetishost(his_net) && addrinsubnet(&c->spd.that.host_addr, his_net))
c->spd.that.has_client = FALSE;
}
#endif
}
passert((p1st->st_policy & POLICY_PFS)==0 || p1st->st_pfs_group != NULL );
/* now that we are sure of our connection, create our new state, and
* do any asynchronous cryptographic operations that we may need to
* make it all work.
*/
/* now that we are sure of our connection, create our new state */
{
// 复制ISAKMP SA状态,准备构造出第2阶段的状态, 用于描述IPSEC SA
struct state *const st = duplicate_state(p1st);
* do any asynchronous cryptographic operations that we may need to
* make it all work.
*/
/* now that we are sure of our connection, create our new state */
{
// 复制ISAKMP SA状态,准备构造出第2阶段的状态, 用于描述IPSEC SA
struct state *const st = duplicate_state(p1st);
/* first: fill in missing bits of our new state object
* note: we don't copy over st_peer_pubkey, the public key
* that authenticated the ISAKMP SA. We only need it in this
* routine, so we can "reach back" to p1st to get it.
*/
// 如果新状态所在连接不是刚才找到的连接c,将其释放,然后更新状态的连接
if (st->st_connection != c)
{
struct connection *t = st->st_connection;
* note: we don't copy over st_peer_pubkey, the public key
* that authenticated the ISAKMP SA. We only need it in this
* routine, so we can "reach back" to p1st to get it.
*/
// 如果新状态所在连接不是刚才找到的连接c,将其释放,然后更新状态的连接
if (st->st_connection != c)
{
struct connection *t = st->st_connection;
st->st_connection = c;
set_cur_connection(c);
connection_discard(t);
}
// 状态尝试次数
st->st_try = 0; /* not our job to try again from start */
// 消息ID
st->st_msgid = md->hdr.isa_msgid;
// 初始化向量
st->st_new_iv_len = b->new_iv_len;
set_new_iv(st, b->new_iv);
set_cur_connection(c);
connection_discard(t);
}
// 状态尝试次数
st->st_try = 0; /* not our job to try again from start */
// 消息ID
st->st_msgid = md->hdr.isa_msgid;
// 初始化向量
st->st_new_iv_len = b->new_iv_len;
set_new_iv(st, b->new_iv);
set_cur_state(st); /* (caller will reset) */
md->st = st; /* feed back new state */
// 本地和对方的ID和端口
st->st_peeruserprotoid = b->his.proto;
st->st_peeruserport = b->his.port;
st->st_myuserprotoid = b->my.proto;
st->st_myuserport = b->my.port;
// 状态类型设置为QUICK_R0
st->st_state = STATE_QUICK_R0;
// 插入系统状态哈希链表
insert_state(st); /* needs cookies, connection, and msgid */
md->st = st; /* feed back new state */
// 本地和对方的ID和端口
st->st_peeruserprotoid = b->his.proto;
st->st_peeruserport = b->his.port;
st->st_myuserprotoid = b->my.proto;
st->st_myuserport = b->my.port;
// 状态类型设置为QUICK_R0
st->st_state = STATE_QUICK_R0;
// 插入系统状态哈希链表
insert_state(st); /* needs cookies, connection, and msgid */
/* copy the connection's
* IPSEC policy into our state. The ISAKMP policy is water under
* the bridge, I think. It will reflect the ISAKMP SA that we
* are using.
*/
// 策略
st->st_policy = (p1st->st_policy & POLICY_ID_AUTH_MASK)
| (c->policy & ~POLICY_ID_AUTH_MASK);
* IPSEC policy into our state. The ISAKMP policy is water under
* the bridge, I think. It will reflect the ISAKMP SA that we
* are using.
*/
// 策略
st->st_policy = (p1st->st_policy & POLICY_ID_AUTH_MASK)
| (c->policy & ~POLICY_ID_AUTH_MASK);
#ifdef NAT_TRAVERSAL
// 需要NAT穿越时, 查找新端口
if (p1st->hidden_variables.st_nat_traversal & NAT_T_DETECTED) {
st->hidden_variables.st_nat_traversal = p1st->hidden_variables.st_nat_traversal;
nat_traversal_change_port_lookup(md, md->st);
}
else {
st->hidden_variables.st_nat_traversal = 0;
}
if ((st->hidden_variables.st_nat_traversal & NAT_T_DETECTED) &&
(st->hidden_variables.st_nat_traversal & NAT_T_WITH_NATOA)) {
// 读取NAT内部地址
nat_traversal_natoa_lookup(md);
}
#endif
// 需要NAT穿越时, 查找新端口
if (p1st->hidden_variables.st_nat_traversal & NAT_T_DETECTED) {
st->hidden_variables.st_nat_traversal = p1st->hidden_variables.st_nat_traversal;
nat_traversal_change_port_lookup(md, md->st);
}
else {
st->hidden_variables.st_nat_traversal = 0;
}
if ((st->hidden_variables.st_nat_traversal & NAT_T_DETECTED) &&
(st->hidden_variables.st_nat_traversal & NAT_T_WITH_NATOA)) {
// 读取NAT内部地址
nat_traversal_natoa_lookup(md);
}
#endif
passert(st->st_connection != NULL);
passert(st->st_connection == c);
passert(st->st_connection == c);
/* process SA in */
{
// 数据包中的SA载荷链表
struct payload_digest *const sapd = md->chain[ISAKMP_NEXT_SA];
pb_stream in_pbs = sapd->pbs;
/* parse and accept body, setting variables, but not forming
* our reply. We'll make up the reply later on.
*
* note that we process the copy of the pbs, so that
* we can process it again in the cryptotail().
*/
// 解析SA载荷
st->st_pfs_group = &unset_group;
RETURN_STF_FAILURE(parse_ipsec_sa_body(&in_pbs
, &sapd->payload.sa
, NULL
, FALSE, st));
}
{
// 数据包中的SA载荷链表
struct payload_digest *const sapd = md->chain[ISAKMP_NEXT_SA];
pb_stream in_pbs = sapd->pbs;
/* parse and accept body, setting variables, but not forming
* our reply. We'll make up the reply later on.
*
* note that we process the copy of the pbs, so that
* we can process it again in the cryptotail().
*/
// 解析SA载荷
st->st_pfs_group = &unset_group;
RETURN_STF_FAILURE(parse_ipsec_sa_body(&in_pbs
, &sapd->payload.sa
, NULL
, FALSE, st));
}
/* Ni in */
// 读取NONCE载荷
RETURN_STF_FAILURE(accept_nonce(md, &st->st_ni, "Ni"));
// 读取NONCE载荷
RETURN_STF_FAILURE(accept_nonce(md, &st->st_ni, "Ni"));
/* [ KE ] in (for PFS) */
// 读取PFS KE载荷
RETURN_STF_FAILURE(accept_PFS_KE(md, &st->st_gi
, "Gi", "Quick Mode I1"));
// 读取PFS KE载荷
RETURN_STF_FAILURE(accept_PFS_KE(md, &st->st_gi
, "Gi", "Quick Mode I1"));
passert(st->st_pfs_group != &unset_group);
passert(st->st_connection != NULL);
{
// 分配快速密钥交换结构
struct qke_continuation *qke = alloc_thing(struct qke_continuation
, "quick_outI1 KE");
// 分配快速密钥交换结构
struct qke_continuation *qke = alloc_thing(struct qke_continuation
, "quick_outI1 KE");
stf_status e;
enum crypto_importance ci;
enum crypto_importance ci;
ci = pcim_ongoing_crypto;
if(ci < st->st_import) ci = st->st_import;
// 填充快速密钥交换结构参数
qke->st = st;
qke->isakmp_sa = p1st;
qke->md = md;
// 加密继续函数, 可能需要使用OE机制来认证对方
qke->qke_pcrc.pcrc_func = quick_inI1_outR1_cryptocontinue;
if(ci < st->st_import) ci = st->st_import;
// 填充快速密钥交换结构参数
qke->st = st;
qke->isakmp_sa = p1st;
qke->md = md;
// 加密继续函数, 可能需要使用OE机制来认证对方
qke->qke_pcrc.pcrc_func = quick_inI1_outR1_cryptocontinue;
if (st->st_pfs_group != NULL) {
// 需要使用PFS, 由于需要重新协商密钥, 重新进行密钥交换
e = build_ke(&qke->qke_pcrc, st, st->st_pfs_group, ci);
} else {
// 这个和build_ke的区别在于没有用到st->st_pfs_group参数,其他都一样
e = build_nonce(&qke->qke_pcrc, st, ci);
}
passert(st->st_connection != NULL);
// 需要使用PFS, 由于需要重新协商密钥, 重新进行密钥交换
e = build_ke(&qke->qke_pcrc, st, st->st_pfs_group, ci);
} else {
// 这个和build_ke的区别在于没有用到st->st_pfs_group参数,其他都一样
e = build_nonce(&qke->qke_pcrc, st, ci);
}
passert(st->st_connection != NULL);
return e;
}
}
}
}
}
}
// 加密继续函数
static void
quick_inI1_outR1_cryptocontinue(struct pluto_crypto_req_cont *pcrc
, struct pluto_crypto_req *r
, err_t ugh)
{
// 快速密钥交换结构
struct qke_continuation *qke = (struct qke_continuation *)pcrc;
// 状态
struct state *const st = qke->st;
stf_status e;
DBG(DBG_CONTROLMORE
, DBG_log("quick inI1_outR1: calculated ke+nonce, sending R1"));
, DBG_log("quick inI1_outR1: calculated ke+nonce, sending R1"));
/* XXX should check out ugh */
passert(ugh == NULL);
passert(cur_state == NULL);
passert(st != NULL);
passert(ugh == NULL);
passert(cur_state == NULL);
passert(st != NULL);
passert(st->st_connection != NULL);
// 设置当前状态
set_cur_state(st); /* we must reset before exit */
st->st_calculating=FALSE;
// 加密结束处理函数
e = quick_inI1_outR1_cryptotail(qke, r);
// 设置当前状态
set_cur_state(st); /* we must reset before exit */
st->st_calculating=FALSE;
// 加密结束处理函数
e = quick_inI1_outR1_cryptotail(qke, r);
if(qke->md != NULL) {
// 如果消息摘要非空, 完成状态转换操作
complete_state_transition(&qke->md, e);
release_md(qke->md);
}
// 复位当前状态
reset_cur_state();
}
// 如果消息摘要非空, 完成状态转换操作
complete_state_transition(&qke->md, e);
release_md(qke->md);
}
// 复位当前状态
reset_cur_state();
}
// 加密结束处理函数, 构造回应数据包
static stf_status
quick_inI1_outR1_cryptotail(struct qke_continuation *qke
, struct pluto_crypto_req *r)
{
// 消息摘要
struct msg_digest *md = qke->md;
// 状态
struct state *st = md->st;
// 连接
struct connection *c = st->st_connection;
// 输入数据包的ID载荷
struct payload_digest *const id_pd = md->chain[ISAKMP_NEXT_ID];
// 输入数据包的SA载荷
struct payload_digest *const sapd = md->chain[ISAKMP_NEXT_SA];
struct isakmp_sa sa = sapd->payload.sa;
pb_stream r_sa_pbs;
u_char /* set by START_HASH_PAYLOAD: */
*r_hashval, /* where in reply to jam hash value */
*r_hash_start; /* from where to start hashing */
/* Start the output packet.
*
* proccess_packet() would automatically generate the HDR*
* payload if smc->first_out_payload is not ISAKMP_NEXT_NONE.
* We don't do this because we wish there to be no partially
* built output packet if we need to suspend for asynch DNS.
*
* We build the reply packet as we parse the message since
* the parse_ipsec_sa_body emits the reply SA
*/
/* HDR* out */
// 填充协议头, 下一载荷为哈希载荷
echo_hdr(md, TRUE, ISAKMP_NEXT_HASH);
/* HASH(2) out -- first pass */
// 填充哈希载荷, 下一载荷为SA载荷
START_HASH_PAYLOAD(md->rbody, ISAKMP_NEXT_SA);
*
* proccess_packet() would automatically generate the HDR*
* payload if smc->first_out_payload is not ISAKMP_NEXT_NONE.
* We don't do this because we wish there to be no partially
* built output packet if we need to suspend for asynch DNS.
*
* We build the reply packet as we parse the message since
* the parse_ipsec_sa_body emits the reply SA
*/
/* HDR* out */
// 填充协议头, 下一载荷为哈希载荷
echo_hdr(md, TRUE, ISAKMP_NEXT_HASH);
/* HASH(2) out -- first pass */
// 填充哈希载荷, 下一载荷为SA载荷
START_HASH_PAYLOAD(md->rbody, ISAKMP_NEXT_SA);
passert(st->st_connection == c);
passert(st->st_connection != NULL);
passert(st->st_connection != NULL);
/* sa header is unchanged -- except for np */
// SA载荷的下一载荷是NONCE载荷
sa.isasa_np = ISAKMP_NEXT_NONCE;
// 填充SA载荷
if (!out_struct(&sa, &isakmp_sa_desc, &md->rbody, &r_sa_pbs))
return STF_INTERNAL_ERROR;
// SA载荷的下一载荷是NONCE载荷
sa.isasa_np = ISAKMP_NEXT_NONCE;
// 填充SA载荷
if (!out_struct(&sa, &isakmp_sa_desc, &md->rbody, &r_sa_pbs))
return STF_INTERNAL_ERROR;
/* parse and accept body, this time recording our reply */
RETURN_STF_FAILURE(parse_ipsec_sa_body(&sapd->pbs
, &sapd->payload.sa
, &r_sa_pbs
, FALSE, st));
RETURN_STF_FAILURE(parse_ipsec_sa_body(&sapd->pbs
, &sapd->payload.sa
, &r_sa_pbs
, FALSE, st));
passert(st->st_pfs_group != &unset_group);
// 检查是否设置了PFS标志但没有进行PFS处理
if ((st->st_policy & POLICY_PFS) && st->st_pfs_group == NULL) {
loglog(RC_LOG_SERIOUS, "we require PFS but Quick I1 SA specifies no GROUP_DESCRIPTION");
return STF_FAIL + NO_PROPOSAL_CHOSEN; /* ??? */
}
openswan_log("responding to Quick Mode {msgid:%08x}", st->st_msgid);
// 检查是否设置了PFS标志但没有进行PFS处理
if ((st->st_policy & POLICY_PFS) && st->st_pfs_group == NULL) {
loglog(RC_LOG_SERIOUS, "we require PFS but Quick I1 SA specifies no GROUP_DESCRIPTION");
return STF_FAIL + NO_PROPOSAL_CHOSEN; /* ??? */
}
openswan_log("responding to Quick Mode {msgid:%08x}", st->st_msgid);
/**** finish reply packet: Nr [, KE ] [, IDci, IDcr ] ****/
{
int np;
{
int np;
if(st->st_pfs_group != NULL) {
// 如果使用PFS, NONCE载荷的下一载荷为密钥交换载荷
np = ISAKMP_NEXT_KE;
} else if(id_pd != NULL) {
// 不需要PFS, 有ID载荷的话NONCE载荷的下一载荷为ID载荷
np = ISAKMP_NEXT_ID;
} else {
// 否则NONCE载荷的下一载荷为NONE, 数据包结束
np = ISAKMP_NEXT_NONE;
}
// 如果使用PFS, NONCE载荷的下一载荷为密钥交换载荷
np = ISAKMP_NEXT_KE;
} else if(id_pd != NULL) {
// 不需要PFS, 有ID载荷的话NONCE载荷的下一载荷为ID载荷
np = ISAKMP_NEXT_ID;
} else {
// 否则NONCE载荷的下一载荷为NONE, 数据包结束
np = ISAKMP_NEXT_NONE;
}
/* Nr out */
// 填充NONCE载荷
if (!ship_nonce(&st->st_nr, r, &md->rbody
, np, "Nr"))
return STF_INTERNAL_ERROR;
}
/* [ KE ] out (for PFS) */
if (st->st_pfs_group != NULL) {
stf_status stat;
// 填充KE载荷, 下一载荷为ID载荷或空
if (!ship_KE(st, r, &st->st_gr
, &md->rbody
, id_pd != NULL? ISAKMP_NEXT_ID : ISAKMP_NEXT_NONE))
return STF_INTERNAL_ERROR;
// 进行DH交换计算
stat = perform_dh_secret(st, RESPONDER, st->st_pfs_group->group);
if(stat != STF_OK) {
return stat;
}
}
/* [ IDci, IDcr ] out */
if (id_pd != NULL) {
struct isakmp_ipsec_id *p = (void *)md->rbody.cur; /* UGH! */
// 填充ID载荷
if (!out_raw(id_pd->pbs.start, pbs_room(&id_pd->pbs), &md->rbody, "IDci"))
return STF_INTERNAL_ERROR;
p->isaiid_np = ISAKMP_NEXT_ID;
p = (void *)md->rbody.cur; /* UGH! */
if (!out_raw(id_pd->next->pbs.start, pbs_room(&id_pd->next->pbs), &md->rbody, "IDcr"))
return STF_INTERNAL_ERROR;
p->isaiid_np = ISAKMP_NEXT_NONE;
}
#ifdef NAT_TRAVERSAL
// NAT穿越处理
if ((st->hidden_variables.st_nat_traversal & NAT_T_DETECTED) &&
(st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TRANSPORT) &&
(c->spd.that.has_client)) {
/** Remove client **/
addrtosubnet(&c->spd.that.host_addr, &c->spd.that.client);
c->spd.that.has_client = FALSE;
}
#endif
// NAT穿越处理
if ((st->hidden_variables.st_nat_traversal & NAT_T_DETECTED) &&
(st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TRANSPORT) &&
(c->spd.that.has_client)) {
/** Remove client **/
addrtosubnet(&c->spd.that.host_addr, &c->spd.that.client);
c->spd.that.has_client = FALSE;
}
#endif
/* Compute reply HASH(2) and insert in output */
// 计算数据包的哈希值
(void)quick_mode_hash12(r_hashval, r_hash_start, md->rbody.cur
, st, &st->st_msgid, TRUE);
// 计算数据包的哈希值
(void)quick_mode_hash12(r_hashval, r_hash_start, md->rbody.cur
, st, &st->st_msgid, TRUE);
/* Derive new keying material */
// 计算新的加密信息
compute_keymats(st);
// 计算新的加密信息
compute_keymats(st);
/* Tell the kernel to establish the new inbound SA
* (unless the commit bit is set -- which we don't support).
* We do this before any state updating so that
* failure won't look like success.
*/
// 创建向内的IPSEC SA
if (!install_inbound_ipsec_sa(st))
return STF_INTERNAL_ERROR; /* ??? we may be partly committed */
/* encrypt message, except for fixed part of header */
// 加密消息
if (!encrypt_message(&md->rbody, st))
{
delete_ipsec_sa(st, TRUE);
return STF_INTERNAL_ERROR; /* ??? we may be partly committed */
}
* (unless the commit bit is set -- which we don't support).
* We do this before any state updating so that
* failure won't look like success.
*/
// 创建向内的IPSEC SA
if (!install_inbound_ipsec_sa(st))
return STF_INTERNAL_ERROR; /* ??? we may be partly committed */
/* encrypt message, except for fixed part of header */
// 加密消息
if (!encrypt_message(&md->rbody, st))
{
delete_ipsec_sa(st, TRUE);
return STF_INTERNAL_ERROR; /* ??? we may be partly committed */
}
DBG(DBG_CONTROLMORE, DBG_log("finished processing quick inI1"));
return STF_OK;
}
return STF_OK;
}
15.4 发起方收到响应方第一回应包, 发送第2初始包
/* Handle (the single) message from Responder in Quick Mode.
* HDR*, HASH(2), SA, Nr [, KE ] [, IDci, IDcr ] -->
* HDR*, HASH(3)
* (see RFC 2409 "IKE" 5.5)
* Installs inbound and outbound IPsec SAs, routing, etc.
*/
stf_status
quick_inR1_outI2(struct msg_digest *md)
{
// 相关状态结构
struct state *const st = md->st;
// 连接结构
const struct connection *c = st->st_connection;
/* HASH(2) in */
// 检查数据包哈希值是否正确
CHECK_QUICK_HASH(md
, quick_mode_hash12(hash_val, hash_pbs->roof, md->message_pbs.roof
, st, &st->st_msgid, TRUE)
, "HASH(2)", "Quick R1");
// 检查数据包哈希值是否正确
CHECK_QUICK_HASH(md
, quick_mode_hash12(hash_val, hash_pbs->roof, md->message_pbs.roof
, st, &st->st_msgid, TRUE)
, "HASH(2)", "Quick R1");
/* SA in */
{
struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA];
// 读取SA载荷
RETURN_STF_FAILURE(parse_ipsec_sa_body(&sa_pd->pbs
, &sa_pd->payload.sa, NULL, TRUE, st));
}
{
struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA];
// 读取SA载荷
RETURN_STF_FAILURE(parse_ipsec_sa_body(&sa_pd->pbs
, &sa_pd->payload.sa, NULL, TRUE, st));
}
/* Nr in */
// 读取NONCE载荷
RETURN_STF_FAILURE(accept_nonce(md, &st->st_nr, "Nr"));
// 读取NONCE载荷
RETURN_STF_FAILURE(accept_nonce(md, &st->st_nr, "Nr"));
/* [ KE ] in (for PFS) */
// 读取密钥交换载荷
RETURN_STF_FAILURE(accept_PFS_KE(md, &st->st_gr, "Gr", "Quick Mode R1"));
// 读取密钥交换载荷
RETURN_STF_FAILURE(accept_PFS_KE(md, &st->st_gr, "Gr", "Quick Mode R1"));
if (st->st_pfs_group != NULL) {
stf_status stat;
// 如果需要PFS支持, 进行DH交换计算
stat = perform_dh_secret(st, INITIATOR, st->st_pfs_group->group);
if(stat != STF_OK) {
return stat;
}
}
stf_status stat;
// 如果需要PFS支持, 进行DH交换计算
stat = perform_dh_secret(st, INITIATOR, st->st_pfs_group->group);
if(stat != STF_OK) {
return stat;
}
}
/* [ IDci, IDcr ] in; these must match what we sent */
{
// ID载荷链表
struct payload_digest *const id_pd = md->chain[ISAKMP_NEXT_ID];
// ID载荷链表
struct payload_digest *const id_pd = md->chain[ISAKMP_NEXT_ID];
if (id_pd != NULL)
{
// ID载荷非空
/* ??? we are assuming IPSEC_DOI */
{
// ID载荷非空
/* ??? we are assuming IPSEC_DOI */
/* IDci (we are initiator) */
// 检查发起方IDci载荷
if (!check_net_id(&id_pd->payload.ipsec_id, &id_pd->pbs
, &st->st_myuserprotoid, &st->st_myuserport
, &st->st_connection->spd.this.client
, "our client"))
return STF_FAIL + INVALID_ID_INFORMATION;
// 检查发起方IDci载荷
if (!check_net_id(&id_pd->payload.ipsec_id, &id_pd->pbs
, &st->st_myuserprotoid, &st->st_myuserport
, &st->st_connection->spd.this.client
, "our client"))
return STF_FAIL + INVALID_ID_INFORMATION;
/* IDcr (responder is peer) */
// 检查响应方IDcr载荷
if (!check_net_id(&id_pd->next->payload.ipsec_id, &id_pd->next->pbs
, &st->st_peeruserprotoid, &st->st_peeruserport
, &st->st_connection->spd.that.client
, "peer client"))
return STF_FAIL + INVALID_ID_INFORMATION;
}
else
{
// ID载荷为空
/* no IDci, IDcr: we must check that the defaults match our proposal */
// 检查地址参数是否匹配
if (!subnetisaddr(&c->spd.this.client, &c->spd.this.host_addr)
|| !subnetisaddr(&c->spd.that.client, &c->spd.that.host_addr))
{
loglog(RC_LOG_SERIOUS, "IDci, IDcr payloads missing in message"
" but default does not match proposal");
return STF_FAIL + INVALID_ID_INFORMATION;
}
}
}
// 检查响应方IDcr载荷
if (!check_net_id(&id_pd->next->payload.ipsec_id, &id_pd->next->pbs
, &st->st_peeruserprotoid, &st->st_peeruserport
, &st->st_connection->spd.that.client
, "peer client"))
return STF_FAIL + INVALID_ID_INFORMATION;
}
else
{
// ID载荷为空
/* no IDci, IDcr: we must check that the defaults match our proposal */
// 检查地址参数是否匹配
if (!subnetisaddr(&c->spd.this.client, &c->spd.this.host_addr)
|| !subnetisaddr(&c->spd.that.client, &c->spd.that.host_addr))
{
loglog(RC_LOG_SERIOUS, "IDci, IDcr payloads missing in message"
" but default does not match proposal");
return STF_FAIL + INVALID_ID_INFORMATION;
}
}
}
#ifdef NAT_TRAVERSAL
if ((st->hidden_variables.st_nat_traversal & NAT_T_DETECTED) &&
(st->hidden_variables.st_nat_traversal & NAT_T_WITH_NATOA)) {
// 读取NAT内部地址
nat_traversal_natoa_lookup(md);
}
#endif
if ((st->hidden_variables.st_nat_traversal & NAT_T_DETECTED) &&
(st->hidden_variables.st_nat_traversal & NAT_T_WITH_NATOA)) {
// 读取NAT内部地址
nat_traversal_natoa_lookup(md);
}
#endif
/* ??? We used to copy the accepted proposal into the state, but it was
* never used. From sa_pd->pbs.start, length pbs_room(&sa_pd->pbs).
*/
* never used. From sa_pd->pbs.start, length pbs_room(&sa_pd->pbs).
*/
/**************** build reply packet HDR*, HASH(3) ****************/
// 构建回应数据包
/* HDR* out done */
// 构建回应数据包
/* HDR* out done */
/* HASH(3) out -- since this is the only content, no passes needed */
{
u_char /* set by START_HASH_PAYLOAD: */
*r_hashval, /* where in reply to jam hash value */
*r_hash_start; /* start of what is to be hashed */
// 构造哈希载荷, 仅此载荷, 下一载荷类型为NONE
START_HASH_PAYLOAD(md->rbody, ISAKMP_NEXT_NONE);
// 计算哈希值
(void)quick_mode_hash3(r_hashval, st);
}
{
u_char /* set by START_HASH_PAYLOAD: */
*r_hashval, /* where in reply to jam hash value */
*r_hash_start; /* start of what is to be hashed */
// 构造哈希载荷, 仅此载荷, 下一载荷类型为NONE
START_HASH_PAYLOAD(md->rbody, ISAKMP_NEXT_NONE);
// 计算哈希值
(void)quick_mode_hash3(r_hashval, st);
}
/* Derive new keying material */
// 计算新的加密信息
compute_keymats(st);
// 计算新的加密信息
compute_keymats(st);
/* Tell the kernel to establish the inbound, outbound, and routing part
* of the new SA (unless the commit bit is set -- which we don't support).
* We do this before any state updating so that
* failure won't look like success.
*/
// 通知内核建立IPSEC SA, 包括向内和向外两个方向的SA
if (!install_ipsec_sa(st, TRUE))
return STF_INTERNAL_ERROR;
* of the new SA (unless the commit bit is set -- which we don't support).
* We do this before any state updating so that
* failure won't look like success.
*/
// 通知内核建立IPSEC SA, 包括向内和向外两个方向的SA
if (!install_ipsec_sa(st, TRUE))
return STF_INTERNAL_ERROR;
/* encrypt message, except for fixed part of header */
// 加密数据包
if (!encrypt_message(&md->rbody, st))
{
delete_ipsec_sa(st, FALSE);
return STF_INTERNAL_ERROR; /* ??? we may be partly committed */
}
// 加密数据包
if (!encrypt_message(&md->rbody, st))
{
delete_ipsec_sa(st, FALSE);
return STF_INTERNAL_ERROR; /* ??? we may be partly committed */
}
{
// 输出IPSEC SA建立信息
DBG(DBG_CONTROLMORE, DBG_log("inR1_outI2: instance %s[%ld], setting newest_ipsec_sa to #%ld (was #%ld) (spd.eroute=#%ld)"
, st->st_connection->name
, st->st_connection->instance_serial
, st->st_serialno
, st->st_connection->newest_ipsec_sa
, st->st_connection->spd.eroute_owner));
}
// 状态相关连接的最新IPSEC SA序号
st->st_connection->newest_ipsec_sa = st->st_serialno;
// 输出IPSEC SA建立信息
DBG(DBG_CONTROLMORE, DBG_log("inR1_outI2: instance %s[%ld], setting newest_ipsec_sa to #%ld (was #%ld) (spd.eroute=#%ld)"
, st->st_connection->name
, st->st_connection->instance_serial
, st->st_serialno
, st->st_connection->newest_ipsec_sa
, st->st_connection->spd.eroute_owner));
}
// 状态相关连接的最新IPSEC SA序号
st->st_connection->newest_ipsec_sa = st->st_serialno;
/* note (presumed) success */
// 网关最新IPSEC工作时间
if (c->gw_info != NULL)
c->gw_info->key->last_worked_time = now();
// 网关最新IPSEC工作时间
if (c->gw_info != NULL)
c->gw_info->key->last_worked_time = now();
/* If we have dpd delay and dpdtimeout set, then we are doing DPD
on this conn, so initialize it */
if (st->st_connection->dpd_delay && st->st_connection->dpd_timeout) {
// 如果需要使用DPD, 启动DPD处理
if(dpd_init(st) != STF_OK) {
delete_ipsec_sa(st, FALSE);
return STF_FAIL;
}
}
on this conn, so initialize it */
if (st->st_connection->dpd_delay && st->st_connection->dpd_timeout) {
// 如果需要使用DPD, 启动DPD处理
if(dpd_init(st) != STF_OK) {
delete_ipsec_sa(st, FALSE);
return STF_FAIL;
}
}
return STF_OK;
}
}
15.5 响应方接收到发起方的第2个数据包
/* Handle last message of Quick Mode.
* HDR*, HASH(3) -> done
* (see RFC 2409 "IKE" 5.5)
* Installs outbound IPsec SAs, routing, etc.
*/
stf_status
quick_inI2(struct msg_digest *md)
{
// 相关状态结构
struct state *const st = md->st;
/* HASH(3) in */
// 检查数据包哈希值
CHECK_QUICK_HASH(md, quick_mode_hash3(hash_val, st)
, "HASH(3)", "Quick I2");
// 检查数据包哈希值
CHECK_QUICK_HASH(md, quick_mode_hash3(hash_val, st)
, "HASH(3)", "Quick I2");
/* Tell the kernel to establish the outbound and routing part of the new SA
* (the previous state established inbound)
* (unless the commit bit is set -- which we don't support).
* We do this before any state updating so that
* failure won't look like success.
*/
// 通知内核建立IPSEC SA, 包括向内和向外两个方向的SA
if (!install_ipsec_sa(st, FALSE))
return STF_INTERNAL_ERROR;
* (the previous state established inbound)
* (unless the commit bit is set -- which we don't support).
* We do this before any state updating so that
* failure won't look like success.
*/
// 通知内核建立IPSEC SA, 包括向内和向外两个方向的SA
if (!install_ipsec_sa(st, FALSE))
return STF_INTERNAL_ERROR;
{
// 输出IPSEC SA建立信息
DBG(DBG_CONTROLMORE, DBG_log("inI2: instance %s[%ld], setting newest_ipsec_sa to #%ld (was #%ld) (spd.eroute=#%ld)"
, st->st_connection->name
, st->st_connection->instance_serial
, st->st_serialno
, st->st_connection->newest_ipsec_sa
, st->st_connection->spd.eroute_owner));
}
// 状态相关连接的最新IPSEC SA序号
st->st_connection->newest_ipsec_sa = st->st_serialno;
// 输出IPSEC SA建立信息
DBG(DBG_CONTROLMORE, DBG_log("inI2: instance %s[%ld], setting newest_ipsec_sa to #%ld (was #%ld) (spd.eroute=#%ld)"
, st->st_connection->name
, st->st_connection->instance_serial
, st->st_serialno
, st->st_connection->newest_ipsec_sa
, st->st_connection->spd.eroute_owner));
}
// 状态相关连接的最新IPSEC SA序号
st->st_connection->newest_ipsec_sa = st->st_serialno;
// 更新状态初始化向量
update_iv(st); /* not actually used, but tidy */
update_iv(st); /* not actually used, but tidy */
/* note (presumed) success */
{
struct gw_info *gw = st->st_connection->gw_info;
{
struct gw_info *gw = st->st_connection->gw_info;
// 网关最新IPSEC工作时间
if (gw != NULL)
gw->key->last_worked_time = now();
}
if (gw != NULL)
gw->key->last_worked_time = now();
}
/* If we have dpd delay and dpdtimeout set, then we are doing DPD
on this conn, so initialize it */
if(st->st_connection->dpd_delay && st->st_connection->dpd_timeout) {
// 如果需要使用DPD, 启动DPD处理
if(dpd_init(st) != STF_OK) {
delete_ipsec_sa(st, FALSE);
return STF_FAIL;
}
}
on this conn, so initialize it */
if(st->st_connection->dpd_delay && st->st_connection->dpd_timeout) {
// 如果需要使用DPD, 启动DPD处理
if(dpd_init(st) != STF_OK) {
delete_ipsec_sa(st, FALSE);
return STF_FAIL;
}
}
return STF_OK;
}
}
...... 待续 ......
转载于:https://blog.51cto.com/enchen/157923