主模式第一包:main_outI1()

1. 序言

main_outI1()作为主模式主动发起连接请求的核心处理函数,我们可以通过学习该函数的处理流程来探究openswan中报文封装的基本思想。如果之前没有学习基本的函数接口(如in_struct, out_struct, out_sa等),那么直接学习main_outI1()流程是比较困难的。如果想快速学习这几个函数接口,可以查看我先前的文章,我把需要的基本知识、思想等做了基本介绍,看完那几个接口再来学习此后的ISAKMP协商流程会容易很多,起到事半功倍的效果。

ISAKMP协商报文的处理流程都比较复杂,一个函数有几百行都是很常见的,因此个人学习期间难免有遗漏和理解错误的地方,请大家多多批评指正。

2. main_outI1()流程图

下面两个流程图中主要描述了三个函数的处理流程,后面我会分别附上这三个函数的源码信息。


3. main_outI1()源码注释

stf_status
main_outI1(int whack_sock
, struct connection *c
, struct state *predecessor
, so_serial_t *newstateno
, lset_t policy
, unsigned long try
, enum crypto_importance importance
, struct xfrm_user_sec_ctx_ike * uctx
)
{
struct state *st = new_state();/*创建一个新的状态*/
struct msg_digest md; /* use reply/rbody found inside */ int numvidtosend = 1; /* we always send DPD VID */
#ifdef NAT_TRAVERSAL
if (nat_traversal_enabled) {
numvidtosend++;
}
#endif
#if SEND_PLUTO_VID || defined(openpgp_peer)
numvidtosend++;
#endif
#ifdef XAUTH
if(c->spd.this.xauth_client || c->spd.this.xauth_server) {
numvidtosend++;
}
#endif
/*统计VID个数*/
/* set up new state *//*根据对端IP地址信息生成一个新的cookie*/
get_cookie(TRUE, st->st_icookie, COOKIE_SIZE, &c->spd.that.host_addr); /*初始化新的state结构*/
initialize_new_state(st, c, policy, try, whack_sock, importance); if(newstateno) *newstateno = st->st_serialno; /* IKE version numbers -- used mostly in logging */
st->st_ike_maj = IKEv1_MAJOR_VERSION;
st->st_ike_min = IKEv1_MINOR_VERSION; change_state(st, STATE_MAIN_I1);/*设置当前的状态为STATE_MAIN_I1*/ if (HAS_IPSEC_POLICY(policy))
add_pending(dup_any(whack_sock), st, c, policy, 1
, predecessor == NULL? SOS_NOBODY : predecessor->st_serialno
, uctx
); #ifdef HAVE_LABELED_IPSEC
/*For main modes states, sec ctx is always null*/
st->sec_ctx = NULL;
#endif if (predecessor == NULL)
openswan_log("initiating Main Mode");
else
openswan_log("initiating Main Mode to replace #%lu", predecessor->st_serialno); /* set up reply */
zero(reply_buffer);/*初始化应答报文(发送的报文)的结构*/
init_pbs(&reply_stream, reply_buffer, sizeof(reply_buffer), "reply packet"); /* HDR out */
{/*添加isakmp头部信息*/
struct isakmp_hdr hdr; zero(&hdr); /* default to 0 */
hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION;
hdr.isa_np = ISAKMP_NEXT_SA;
hdr.isa_xchg = ISAKMP_XCHG_IDPROT;
memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE);
/* R-cookie, flags and MessageID are left zero */
/*长度字段最后设置: close_output_pbs(&reply_stream);*/
if (!out_struct(&hdr, &isakmp_hdr_desc, &reply_stream, &md.rbody))
{
reset_cur_state();
return STF_INTERNAL_ERROR;
}
} /* SA out */
{/************封装SA载荷**************/
u_char *sa_start = md.rbody.cur;
int policy_index = POLICY_ISAKMP(policy
, c->spd.this.xauth_server
, c->spd.this.xauth_client); /* if we have an OpenPGP certificate we assume an
* OpenPGP peer and have to send the Vendor ID
*/
/*如果存在VID,则需要设置下一载荷的值*/
int np = numvidtosend > 0 ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE;
if (!out_sa(&md.rbody
, &oakley_sadb[policy_index], st, TRUE, FALSE, np))
{
openswan_log("outsa fail");
reset_cur_state();
return STF_INTERNAL_ERROR;
}
/* save initiator SA for later HASH */
passert(st->st_p1isa.ptr == NULL); /* no leak! (MUST be first time) */
clonetochunk(st->st_p1isa, sa_start, md.rbody.cur - sa_start
, "sa in main_outI1");
} if (SEND_PLUTO_VID || c->spd.this.cert.type == CERT_PGP)
{
char *vendorid = (c->spd.this.cert.type == CERT_PGP) ?
pgp_vendorid : pluto_vendorid;
int np = --numvidtosend > 0 ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE; if (!out_generic_raw(np, &isakmp_vendor_id_desc, &md.rbody
, vendorid, strlen(vendorid), "Vendor ID"))
return STF_INTERNAL_ERROR;
} /* Send DPD VID */
{
int np = --numvidtosend > 0 ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE;
if(!out_vid(np, &md.rbody, VID_MISC_DPD)) {
reset_cur_state();
return STF_INTERNAL_ERROR;
}
} #ifdef NAT_TRAVERSAL
DBG(DBG_NATT, DBG_log("nat traversal enabled: %d"
, nat_traversal_enabled));
if (nat_traversal_enabled) {
int np = --numvidtosend > 0 ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE; /* Add supported NAT-Traversal VID */
if (!nat_traversal_insert_vid(np, &md.rbody, st)) {
reset_cur_state();
return STF_INTERNAL_ERROR;
}
}
#endif #ifdef XAUTH
if(c->spd.this.xauth_client || c->spd.this.xauth_server) {
int np = --numvidtosend > 0 ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE;
if(!out_vid(np, &md.rbody, VID_MISC_XAUTH)) {
reset_cur_state();
return STF_INTERNAL_ERROR;
}
}
#endif #ifdef DEBUG
/* if we are not 0 then something went very wrong above */
if(numvidtosend != 0) {
openswan_log("payload alignment problem please check the code in main_inR1_outR2 (num=%d)", numvidtosend);
}
#endif close_message(&md.rbody);
close_output_pbs(&reply_stream); /* let TCL hack it before we mark the length and copy it */
TCLCALLOUT("avoidEmitting", st, st->st_connection, &md);
clonetochunk(st->st_tpacket, reply_stream.start, pbs_offset(&reply_stream)
, "reply packet for main_outI1"); /* Transmit */
send_packet(st, "main_outI1", TRUE); /* Set up a retransmission event, half a minute henceforth */
TCLCALLOUT("adjustTimers", st, st->st_connection, &md); #ifdef TPM
tpm_stolen:
tpm_ignore:
#endif
delete_event(st);
event_schedule(EVENT_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0, st); if (predecessor != NULL)
{
update_pending(predecessor, st);
whack_log(RC_NEW_STATE + STATE_MAIN_I1
, "%s: initiate, replacing #%lu"
, enum_name(&state_names, st->st_state)
, predecessor->st_serialno);
}
else
{
whack_log(RC_NEW_STATE + STATE_MAIN_I1
, "%s: initiate", enum_name(&state_names, st->st_state));
}
reset_cur_state();
return STF_OK;
}

4. out_sa()源码注释

略。此函数400多行,由于流程图上比较详细就不再列出。

5. oakley_alg_makedb()源码注释

/*
* Create an OAKLEY proposal based on alg_info and policy
*
* Note: maxtrans is an enum, not a count
* Should probably be declared an enum at some point.
* -1 - ???
* 0 - No limit
* 1 - One proposal - period
* 2 - One DH group, take first DH group and ignore any that don't match
*根据配置的秘钥算法信息重新生成一个sadb信息
*传入的sadb应该为固定的秘钥算法信息,因此需要根据策略来重新生成一个新的sadb
*/
struct db_sa *
oakley_alg_makedb(struct alg_info_ike *ai
, struct db_sa *base
, int maxtrans)
{
/* struct db_context inprog UNUSED; */
struct db_sa *gsp = NULL;
struct db_sa *emp_sp = NULL;
struct ike_info *ike_info;
unsigned ealg, halg, modp, eklen=0;
/* Next two are for multiple proposals in agressive mode... */
unsigned last_modp=0, wrong_modp=0;
struct encrypt_desc *enc_desc;
int transcnt = 0;
int i; /*
* start by copying the proposal that would have been picked by
* standard defaults.
*/ if (!ai) {
DBG(DBG_CRYPT,DBG_log("no IKE algorithms for this connection ")); return NULL;
} gsp = NULL; /*
* for each group, we will create a new proposal item, and then
* append it to the list of transforms in the conjoint point.
*
* when creating each item, we will use the first transform
* from the base item as the template.
*/
ALG_INFO_IKE_FOREACH(ai, ike_info, i) {//遍历策略中的算法信息 if(ike_info->ike_default == FALSE) {
struct db_attr *enc, *hash, *auth, *grp, *enc_keylen, *new_auth;
struct db_trans *trans;
struct db_prop *prop;
struct db_prop_conj *cprop; /*获取到加密算法、哈希算法、认证算法、加密秘钥长度等信息*/
ealg = ike_info->ike_ealg;
halg = ike_info->ike_halg;
modp = ike_info->ike_modp;
eklen= ike_info->ike_eklen; #if 1 /*判断这几个算法是否合法、是否存在等*/
if (!ike_alg_enc_present(ealg)) {
DBG_log("oakley_alg_makedb() "
"ike enc ealg=%d not present",
ealg);
continue;
}
if (!ike_alg_hash_present(halg)) {
DBG_log("oakley_alg_makedb() "
"ike hash halg=%d not present",
halg);
continue;
}
enc_desc = ike_alg_get_encrypter(ealg); passert(enc_desc != NULL);
if (eklen /*秘钥长度是否符合要求*/
&& (eklen < enc_desc->keyminlen
|| eklen > enc_desc->keymaxlen)) {
DBG_log("ike_alg_db_new() "
"ealg=%d (specified) keylen:%d, "
"not valid "
"min=%d, max=%d"
, ealg
, eklen
, enc_desc->keyminlen
, enc_desc->keymaxlen
);
continue;
}
#endif
/* okay copy the basic item, and modify it. */
if(eklen > 0)
{
emp_sp = sa_copy_sa(&oakley_empty, 0);/*重新分配一个新的描述信息*/
cprop = &base->prop_conjs[0];/*从定义的描述信息中获取参数*/
prop = &cprop->props[0];/*建议载荷*/
trans = &prop->trans[0];/*变换载荷*/
new_auth = &trans->attrs[2];/*属性载荷*/ cprop = &emp_sp->prop_conjs[0];
prop = &cprop->props[0];
trans = &prop->trans[0];
auth = &trans->attrs[2];
*auth = *new_auth; /*给新的描述结构中设置认证算法*/
}
else
emp_sp = sa_copy_sa_first(base); passert(emp_sp->prop_conj_cnt == 1);
cprop = &emp_sp->prop_conjs[0]; passert(cprop->prop_cnt == 1);
prop = &cprop->props[0]; passert(prop->trans_cnt == 1);
trans = &prop->trans[0]; passert(trans->attr_cnt == 4 || trans->attr_cnt == 5);
enc = &trans->attrs[0]; /*加密*/
hash = &trans->attrs[1];/*哈希*/
auth = &trans->attrs[2];/*认证*/
grp = &trans->attrs[3];/*DH组?*/ if(eklen > 0) {
enc_keylen = &trans->attrs[4];
enc_keylen->val = eklen;/*设置加密算法长度*/
} else
trans->attr_cnt = 4; passert(enc->type.oakley == OAKLEY_ENCRYPTION_ALGORITHM);
if(ealg > 0) {
enc->val = ealg;/*设置加密算法*/
} modp = ike_info->ike_modp;
eklen= ike_info->ike_eklen; passert(hash->type.oakley == OAKLEY_HASH_ALGORITHM);
if(halg > 0) {
hash->val = halg;/*设置哈希算法*/
} passert(auth->type.oakley == OAKLEY_AUTHENTICATION_METHOD);
/* no setting for auth type for IKE */ passert(grp->type.oakley == OAKLEY_GROUP_DESCRIPTION);
if(modp > 0) {
grp->val = modp; /*设置认证算法*/
}
} else {
emp_sp = sa_copy_sa(base, 0);
} if(maxtrans == 1) {/*最大变换载荷数*/
/*
* We're going to leave maxtrans == 1 alone in case there
* really really is a case where we only want 1.
*/ if(transcnt == 0) {
DBG(DBG_CONTROL, DBG_log("using transform (%d,%d,%d,%ld)"
, ike_info->ike_ealg
, ike_info->ike_halg
, ike_info->ike_modp
, (long)ike_info->ike_eklen));
if(gsp) {
free_sa(gsp);
}
gsp = emp_sp;
} else {
free_sa(emp_sp);
} if(transcnt > 0) {
if(transcnt == 1) {
loglog(RC_LOG_SERIOUS , "multiple transforms were set in aggressive mode. Only first one used.");
} loglog(RC_LOG_SERIOUS
, "transform (%d,%d,%d,%ld) ignored."
, ike_info->ike_ealg
, ike_info->ike_halg
, ike_info->ike_modp
, (long)ike_info->ike_eklen);
} } else {
/*
* Now... We're allowing multiple proposals... Are we allowing
* multiple DH groups?
*/ struct db_sa *new; if(maxtrans == 2 && transcnt > 0 && ike_info->ike_modp != last_modp ) {
/* Not good.
* Already got a DH group and this one doesn't match */
if(wrong_modp == 0) {
loglog(RC_LOG_SERIOUS
, "multiple DH groups were set in aggressive mode. Only first one used.");
} loglog(RC_LOG_SERIOUS
, "transform (%d,%d,%d,%ld) ignored."
, ike_info->ike_ealg
, ike_info->ike_halg
, ike_info->ike_modp
, (long)ike_info->ike_eklen); wrong_modp++; free_sa(emp_sp);
} else if(gsp) {
/* now merge emp_sa and gsp */
new = sa_merge_proposals(gsp, emp_sp);/*变换载荷合并*/
free_sa(gsp);
free_sa(emp_sp);
emp_sp = NULL;
gsp = new;
} else {
gsp = emp_sp;
}
last_modp = ike_info->ike_modp;
}
transcnt++;
}
gsp->parentSA = TRUE; return gsp;
}

openswan协商流程之(一):main_outI1()的更多相关文章

  1. openswan协商流程之(七):main_inR3

    主模式第六包(收包):main_inR3 1. 序言 main_inR3()函数是ISAKMP协商过程中第一阶段的最后一个报文的接收处理函数,它的作用同main_inI3_outR3()部分功能相同: ...

  2. openswan协商流程之(六):main_inI3_outR3()

    主模式第六包:main_inI3_outR3 1. 序言 main_inI3_outR3()函数是ISAKMP协商过程中第六包的核心处理函数的入口,第五六包主要用来验证对方的身份信息,同时此报文也是加 ...

  3. openswan协商流程之(五):main_inR2_outI3()

    主模式第五包:main_inR2_outI3 文章目录 主模式第五包:main_inR2_outI3 1. 序言 2.函数调用关系 3. 第五个报文流程图 4. main_inR2_outI3()源码 ...

  4. openswan协商流程之(四):main_inI2_outR2()

    主模式第四包:main_inI2_outR2 1. 序言 main_inI2_outR2()函数是ISAKMP协商过程中第四包的核心处理函数的入口,同时在此处理流程中已经获取到足够的隧道信息,可以生成 ...

  5. openswan协商流程之(三):main_inR1_outI2

    主模式第三包:main_inR1_outI2 1. 序言 main_inR1_outI2()函数是ISAKMP协商过程中第三包的核心处理函数的入口.这里我们主要说明main_inR1_outI2的函数 ...

  6. openswan协商流程之(二):main_inI1_outR1()

    主模式第二包:main_inI1_outR1() 文章目录 主模式第二包:main_inI1_outR1() 1. 序言 2. `main_inI1_outR1()`处理流程图 3. `main_in ...

  7. IKEv2协议协商流程: (IKE-SA-INIT 交换)第二包

    IKEv2协议协商流程: (IKE-SA-INIT 交换)第二包 文章目录 IKEv2协议协商流程: (IKE-SA-INIT 交换)第二包 1. IKEv2 协商总体框架 2. 第二包流程图 3. ...

  8. IKEv2协议协商流程: (IKE-SA-INIT 交换)第一包

    文章目录 1. IKEv2 协商总体框架 2. 第一包流程图 3. openswan源码学习 3.1 ikev2parent_outI1() 3.2 ikev2parent_outI1_withsta ...

  9. openswan IPSec专栏目录锦集

    为了方便查阅现有的文章,特准备一个目录页供后续查询使用 专栏序言 1. 基础知识 openswan任务调度基础知识之信号 2. openswan环境搭建 openswan框架和编译时说明 opensw ...

随机推荐

  1. vulnhub-DC:6靶机渗透记录

    准备工作 在vulnhub官网下载DC:6靶机DC: 6 ~ VulnHub 导入到vmware,设置成NAT模式 打开kali准备进行渗透(ip:192.168.200.6) 信息收集 利用nmap ...

  2. Dubbo 实现一个Load Balance (用于灰度发布)

    Dubbo 可以实现的扩展很多, 官方文档在这: https://dubbo.apache.org/zh/docs/v2.7/dev/impls/ (太简单了....) 下面我们实现一个Load Ba ...

  3. BUUCTF-[HCTF 2018]admin(Unicode欺骗&伪造session)

    目录 方法一:Unicode欺骗 方法二:伪造session 参考文章 记一道flask下session伪造的题. 方法一:Unicode欺骗 拿到题目f12提示you are not admin,显 ...

  4. C++ 友元 (全局函数做友元) (类做友元) (成员函数做友元)

    1 //友元 全局函数做友元 2 /* 3 #include <iostream> 4 #include <string> 5 using namespace std; 6 7 ...

  5. 37岁Android程序员裸辞,四个月被497家公司拒绝,问猎头后懵了

    一位网友在职场论坛上发了一个帖子,他说自己今年三十七岁了,是一名Android老兵,因为和上家公司的领导闹矛盾有了嫌隙,一气之下就裸辞了,如今已经辞职四个月了,也失业了四个月. 每天都在努力投简历,共 ...

  6. python中两种拷贝目录方法的比较

    首先是用python自己的api: shutil.copytree('./build/tested/doc', './build/tested/build/doc') 优点是改变平台时不需要修改代码, ...

  7. 22javascript笔记(2)

    JavaScript 1.js事件和作用域 js事件:html页面中每一个元素都可以产生某些触发js函数的事件.这些事件是可以被js侦测到的一种行为,并且js程序能应对这些事件. 常见的html事件 ...

  8. iOS-block循环引用详解和应用

    Block循环引用 什么情况下block会造成循环引用 ARC 情况下 block为了保证代码块内部对象不被提前释放,会对block中的对象进行强引用,就相当于持有了其中的对象,而如果此时block中 ...

  9. XXXMapper.xml中嵌套查询

    XXXMapper.xml中嵌套查询 <resultMap id="LiveUserNocticeMap" type="com.fxkj.common.vo.Liv ...

  10. Spring中的@Transactional必须要了解的概念

    spring中的@Transactional基于动态代理的机制,提供了一种透明的事务管理机制,方便快捷解决在开发中碰到的问题. 一般使用是通过如下代码对方法或接口或类注释: 1 @Transactio ...