pluto实现分析(18)

 
本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。
msn: [email protected]
来源: http://yfydz.cublog.cn

14. 野蛮模式协商

IKE野蛮协商处理函数基本都在programs/pluto目录下的ikev1_aggr.c和ipsec_doi.c中定义, 野蛮模式通常用在已经建好连接的断开后快速恢复连接, 数据交互较少, 只需三个数据包就可以完成第一阶段协商, 而主模式需要6个数据包才能完成协商。

14.1 过程
 
野蛮模式:

        Initiator                          Responder
       -----------                        -----------
        HDR, SA, KE, Ni, IDii       -->
aggr_outI1(发送初始化数据1)
                                    <--    HDR, SA, KE, Nr, IDir,
                                                [ CERT, ] SIG_R
                           aggr_inI1_outR1_psk(接收到初始化数据1, 发送响应数据1)
                           aggr_inI1_outR1_rsasig(根据认证方式分别用不同函数处理)
        HDR, [ CERT, ] SIG_I        -->
aggr_inR1_outI2(接收到响应数据1,发送初始化数据2)
                           aggr_inI2(接收到初始化数据2,完成野蛮模式协商, 建立ISAKMP SA)
 
连接发起函数为ipsecdoi_initiate()函数, 在其中调用了main_outI1(), aggr_outI1()和quick_outI1()函数分别发起主模式,野蛮模式和快速模式的协商。
 
14.2 发起方的第一个初始包

stf_status
aggr_outI1(int whack_sock,
    struct connection *c,
    struct state *predecessor,
    lset_t policy,
    unsigned long try
    , enum crypto_importance importance)
{
    struct state *st;
    /* set up new state */
// 新分配状态结构, 准备建立新状态
    cur_state = st = new_state();
// 状态所在连接
    st->st_connection = c;
// 设置状态结构中的双方地址端口信息
    set_state_ike_endpoints(st, c);
#ifdef DEBUG
    extra_debugging(c);
#endif
// 状态相关参数: 策略
    st->st_policy = policy & ~POLICY_IPSEC_MASK;
// 和whack的通信套接口
    st->st_whack_sock = whack_sock;
// 重试次数
    st->st_try = try;
// 状态类型: AGGR_I1
    st->st_state = STATE_AGGR_I1;
// 获取发起方cookie
    get_cookie(TRUE, st->st_icookie, COOKIE_SIZE, &c->spd.that.host_addr);
// 将状态结构插入系统的状态哈希表
    insert_state(st); /* needs cookies, connection, and msgid (0) */
// 初始化状态结构中的st_oakley域,为一个struct oakley_trans_attrs结构
    if(init_am_st_oakley(st, policy) == FALSE) {
 loglog(RC_AGGRALGO, "can not initiate aggressive mode, at most one algorithm may be provided");
 reset_globals();
 return STF_FAIL;
    }
    if (HAS_IPSEC_POLICY(policy))
 add_pending(dup_any(whack_sock), st, c, policy, 1
     , predecessor == NULL? SOS_NOBODY : predecessor->st_serialno);
// 记录野蛮模式状态初始化信息, predecessor为该当前状态之前可能的状态
// (新状态是该状态的替换者)
    if (predecessor == NULL) {
 openswan_log("initiating Aggressive Mode #%lu, connection \"%s\""
       , st->st_serialno, st->st_connection->name);
    }
    else {
 openswan_log("initiating Aggressive Mode #%lu to replace #%lu, connection \"%s\""
       , st->st_serialno, predecessor->st_serialno
       , st->st_connection->name);
    }
    {
// 分配密钥交换结构
 struct ke_continuation *ke = alloc_thing(struct ke_continuation
       , "outI2 KE");
 stf_status e;
// 分配消息摘要结构
 ke->md = alloc_md();
 ke->md->st = st;
 st->st_suspended_md = ke->md;
 if (!st->st_sec_in_use) {
// 如果数据还没加密, 准备密钥交换, 然后重新继续
     ke->ke_pcrc.pcrc_func = aggr_outI1_continue;
// 密钥交换处理
     e = build_ke(&ke->ke_pcrc, st, st->st_oakley.group, importance);
     if(e != STF_SUSPEND) {
       loglog(RC_CRYPTOFAILED, "system too busy");
       delete_state(st);
     }
 } else {
// 已经加密了, 继续完成outI1过程
     e = aggr_outI1_tail((struct pluto_crypto_req_cont *)ke
     , NULL);
 }
// 复位全局变量 
 reset_globals();
 return e;
    }
}

// 加密处理完成后的继续操作函数
static void
aggr_outI1_continue(struct pluto_crypto_req_cont *pcrc
      , struct pluto_crypto_req *r
      , err_t ugh)
{
// 密钥交换结构
  struct ke_continuation *ke = (struct ke_continuation *)pcrc;
  struct msg_digest *md = ke->md;
  struct state *const st = md->st;
  stf_status e;
 
  DBG(DBG_CONTROLMORE
      , DBG_log("aggr outI1: calculated ke+nonce, sending I1"));
 
  /* XXX should check out ugh */
  passert(ugh == NULL);
  passert(cur_state == NULL);
  passert(st != NULL);
  passert(st->st_suspended_md == ke->md);
  st->st_suspended_md = NULL; /* no longer connected or suspended */
// 设置当前状态
  set_cur_state(st);
  st->st_calculating = FALSE;
// 完成outI1过程
  e = aggr_outI1_tail(pcrc, r);
 
  if(ke->md != NULL) {
// 如果消息摘要非空(应该是likely的), 完成状态转移操作
      complete_state_transition(&ke->md, e);
// 释放消息摘要结构
      release_md(ke->md);
  }
// 复位全局变量
  reset_globals();
  passert(GLOBALS_ARE_RESET());
}

// 结束处理, 构造发送包
static stf_status
aggr_outI1_tail(struct pluto_crypto_req_cont *pcrc
  , struct pluto_crypto_req *r)
{
    struct ke_continuation *ke = (struct ke_continuation *)pcrc;
    struct msg_digest *md = ke->md;
    struct state *const st = md->st;
    struct connection *c = st->st_connection;
    u_char space[8192]; /* NOTE: we assume 8192 is big enough to build the packet */
    pb_stream reply; /* not actually a reply, but you know what I mean */
    pb_stream rbody;
    /* set up reply */
// 初始化回应包
    init_pbs(&reply, space, sizeof(space), "reply packet");
    /* HDR out */
    {
 struct isakmp_hdr hdr;
// 填充ISAKMP头结构
 memset(&hdr, '\0', sizeof(hdr)); /* default to 0 */
// 版本
 hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION;
// 下一载荷为SA载荷
 hdr.isa_np = ISAKMP_NEXT_SA;
// 野蛮模式
 hdr.isa_xchg = ISAKMP_XCHG_AGGR;
// 发起方cookie
 memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE);
 /* R-cookie, flags and MessageID are left zero */
// 输出到缓冲区
 if (!out_struct(&hdr, &isakmp_hdr_desc, &reply, &rbody))
 {
     cur_state = NULL;
     return STF_INTERNAL_ERROR;
 }
    }
    /* SA out */
    {
// 填充SA载荷
 u_char *sa_start = rbody.cur;
 int    policy_index = POLICY_ISAKMP(st->st_policy
         , c->spd.this.xauth_server
         , c->spd.this.xauth_client);
 
 if (!out_sa(&rbody
      , &oakley_am_sadb[policy_index], st
// 下一载荷是KE载荷
      , TRUE, TRUE, ISAKMP_NEXT_KE))
 {
     return STF_INTERNAL_ERROR;
     cur_state = NULL;
 }
 /* save initiator SA for later HASH */
 passert(st->st_p1isa.ptr == NULL); /* no leak! */
 clonetochunk(st->st_p1isa, sa_start, rbody.cur - sa_start,
       "sa in aggr_outI1");
    }
    /* KE out */
// 填充密钥交换载荷
    if (!ship_KE(st, r, &st->st_gi,
// 下一载荷是NONCE载荷
      &rbody, ISAKMP_NEXT_NONCE))
 return STF_INTERNAL_ERROR;
    /* Ni out */
// 填充NONCE载荷, 下一载荷是ID载荷
    if (!ship_nonce(&st->st_ni, r, &rbody, ISAKMP_NEXT_ID, "Ni"))
 return STF_INTERNAL_ERROR;
    /* IDii out */
    {
 struct isakmp_ipsec_id id_hd;
 chunk_t id_b;
 pb_stream id_pbs;
// 构造ID载荷
 build_id_payload(&id_hd, &id_b, &st->st_connection->spd.this);
// 下一载荷是VID载荷
 id_hd.isaiid_np = ISAKMP_NEXT_VID;
 if (!out_struct(&id_hd, &isakmp_ipsec_identification_desc, &rbody, &id_pbs)
 || !out_chunk(id_b, &id_pbs, "my identity"))
     return STF_INTERNAL_ERROR;
 close_output_pbs(&id_pbs);
    }
    /* ALWAYS Announce our ability to do Dead Peer Detection to the peer */
    {
// 没有NAT穿越时的下一载荷为空
      int np = ISAKMP_NEXT_NONE;
#ifdef NAT_TRAVERSAL
      if (nat_traversal_enabled
   || c->spd.this.xauth_client
   || c->spd.this.xauth_server) {
// 如果打开NAT穿越或使用XAUTH, 下一载荷是VID载荷 
 /* Add supported NAT-Traversal VID */
 np = ISAKMP_NEXT_VID;
      }
#endif
// 构造DPD VID载荷, 下一载荷是由np指定
      if( !out_generic_raw(np, &isakmp_vendor_id_desc
      , &rbody
      , dpd_vendorid, dpd_vendorid_len
      , "V_ID"))
        return STF_INTERNAL_ERROR;
    }
#ifdef NAT_TRAVERSAL
    if (nat_traversal_enabled) {
 /* Add supported NAT-Traversal VID */
 int np = ISAKMP_NEXT_NONE;
#ifdef XAUTH
 if(c->spd.this.xauth_client || c->spd.this.xauth_server) {
// 如果是使用XAUTH, 下一载荷还是VID载荷
     np = ISAKMP_NEXT_VID;
 }
#endif
// 添加NAT穿越VID载荷, 下一载荷如果有XAUTH的将是XAUTH的VID载荷
 if (!nat_traversal_add_vid(np, &rbody)) {
     reset_cur_state();
     return STF_INTERNAL_ERROR;
 }
    }
#endif
#ifdef XAUTH
    if(c->spd.this.xauth_client || c->spd.this.xauth_server)
    {
// 填充XAUTH的VID载荷, 下一载荷是空
 if(!out_vendorid(ISAKMP_NEXT_NONE, &rbody, VID_MISC_XAUTH))
 {
     return STF_INTERNAL_ERROR;
 }
    }
#endif
 
    /* finish message */
// 结束数据包构造
    close_message(&rbody);
    close_output_pbs(&reply);
    clonetochunk(st->st_tpacket, reply.start, pbs_offset(&reply),
   "reply packet from aggr_outI1");
    /* Transmit */
// 输出数据包具体原始信息
    DBG_cond_dump(DBG_RAW, "sending:\n",
    st->st_tpacket.ptr, st->st_tpacket.len);
// 发送数据包
    send_packet(st, "aggr_outI1", TRUE);
    /* Set up a retransmission event, half a minute henceforth */
// 删除状态的原始事件
    delete_event(st);
// 重新挂接状态事件: 超时重发
    event_schedule(EVENT_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0, st);
    whack_log(RC_NEW_STATE + STATE_AGGR_I1,
       "%s: initiate", enum_name(&state_names, st->st_state));
    cur_state = NULL;
    return STF_IGNORE;
}

14.3 响应方收到发起方初始化包, 发送第一响应包

以下函数都在ipsec_doi.c中定义, 对于按预共享密钥认证还是RSA签名认证分别使用不同的函数进行处理:

stf_status
aggr_inI1_outR1_psk(struct msg_digest *md)
{
    return aggr_inI1_outR1_common(md, OAKLEY_PRESHARED_KEY);
}
stf_status
aggr_inI1_outR1_rsasig(struct msg_digest *md)
{
    return aggr_inI1_outR1_common(md, OAKLEY_RSA_SIG);
}

// 则两个函数都是aggr_inI1_outR1_common()函数的包裹函数

static stf_status
aggr_inI1_outR1_common(struct msg_digest *md
         , int authtype)
{
    /* With Aggressive Mode, we get an ID payload in this, the first
     * message, so we can use it to index the preshared-secrets
     * when the IP address would not be meaningful (i.e. Road
     * Warrior).  So our first task is to unravel the ID payload.
     */
    struct state *st;
// SA载荷链表
    struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA];
// 密钥交换载荷链表
    pb_stream *keyex_pbs = &md->chain[ISAKMP_NEXT_KE]->pbs;
// 根据地址端口查找连接
    struct connection *c = find_host_connection(&md->iface->ip_addr
      , md->iface->port
      , &md->sender
      , md->sender_port);

#if 0   
#ifdef NAT_TRAVERSAL
    if (c == NULL && md->iface->ike_float)
    {
 c = find_host_connection(&md->iface->addr, NAT_T_IKE_FLOAT_PORT
  , &md->sender, md->sender_port);
    }
#endif
#endif
    if (c == NULL)
    {
// 如果没找到连接, 可能是动态连接, 将对方地址置空后重新查找连接
 /* see if a wildcarded connection can be found */
 c = find_host_connection(&md->iface->ip_addr, pluto_port
     , (ip_address*)NULL, md->sender_port);
 if (c != NULL && c->policy & POLICY_AGGRESSIVE)
 {
     /* Create a temporary connection that is a copy of this one.
      * His ID isn't declared yet.
      */
// 如果找到连接而且该根据支持野蛮模式, 将连接实例化
     c = rw_instantiate(c, &md->sender,
          NULL,
          NULL);
 }
 else
 {
// 否则失败返回
     loglog(RC_LOG_SERIOUS, "initial Aggressive Mode message from %s"
  " but no (wildcard) connection has been configured"
  , ip_str(&md->sender));
     /* XXX notification is in order! */
     return STF_IGNORE;
 }
    }
    /* Set up state */
// 分配新状态结构
    cur_state = md->st = st = new_state(); /* (caller will reset cur_state) */
// 状态所处连接
    st->st_connection = c;
// 远程对方的地址端口
    st->st_remoteaddr = md->sender;
    st->st_remoteport = md->sender_port;
// 网卡位置
    st->st_interface  = md->iface;
// 状态类型值为AGGR_R1
    st->st_state = STATE_AGGR_R1;
    /* until we have clue who this is, then be conservative about allocating
     * them any crypto bandwidth */
// 重要性
    st->st_import = pcim_stranger_crypto;
// 状态策略中带上野蛮模式标志
    st->st_policy |= POLICY_AGGRESSIVE;
// 认证类型
    st->st_oakley.auth = authtype; 
// 解码对方ID信息
    if (!decode_peer_id(md, FALSE, TRUE))
    {
 char buf[IDTOA_BUF];
// 如果解码失败, 错误返回
 (void) idtoa(&st->st_connection->spd.that.id, buf, sizeof(buf));
 loglog(RC_LOG_SERIOUS,
      "initial Aggressive Mode packet claiming to be from %s"
      " on %s but no connection has been authorized",
     buf, ip_str(&md->sender));
 /* XXX notification is in order! */
 return STF_FAIL + INVALID_ID_INFORMATION;
    }
    c = st->st_connection;
#ifdef DEBUG
    extra_debugging(c);
#endif
// 尝试次数
    st->st_try = 0; /* Not our job to try again from start */
// 状态策略
    st->st_policy = c->policy & ~POLICY_IPSEC_MASK; /* only as accurate as connection */
// 复制数据包中的发起方的cookie
    memcpy(st->st_icookie, md->hdr.isa_icookie, COOKIE_SIZE);
// 构造响应方(本地)的cookie
    get_cookie(FALSE, st->st_rcookie, COOKIE_SIZE, &md->sender);
// 将状态插入系统状态哈希链表
    insert_state(st); /* needs cookies, connection, and msgid (0) */
    st->st_doi = ISAKMP_DOI_IPSEC;
    st->st_situation = SIT_IDENTITY_ONLY; /* We only support this */
// 日志记录信息
    openswan_log("responding to Aggressive Mode, state #%lu, connection \"%s\""
 " from %s"
 , st->st_serialno, st->st_connection->name
 , ip_str(&c->spd.that.host_addr));
#ifdef NAT_TRAVERSAL
// 如果对方支持NAT穿越, 本地也支持NAT穿越
    if (md->quirks.nat_traversal_vid && nat_traversal_enabled) {
 /* reply if NAT-Traversal draft is supported */
// 支持的NAT穿越策略
 st->hidden_variables.st_nat_traversal = nat_traversal_vid_to_method(md->quirks.nat_traversal_vid);
    }
#endif
    /* save initiator SA for HASH */
// 保存发起方的SA和哈希载荷
    clonereplacechunk(st->st_p1isa, sa_pd->pbs.start, pbs_room(&sa_pd->pbs),
        "sa in aggr_inI1_outR1()");
    /*
     * parse_isakmp_sa picks the right group, which we need to know
     * before we do any calculations. We will call it again to have it
     * emit the winning SA into the output.
     */
    /* SA body in */
    {
 pb_stream sabs = sa_pd->pbs;
// 读取输入数据包的SA载荷 
 RETURN_STF_FAILURE(parse_isakmp_sa_body(&sabs
      , &sa_pd->payload.sa
      , NULL, FALSE, st));
    }
    /* KE in */
// 读取KE载荷
    RETURN_STF_FAILURE(accept_KE(&st->st_gi, "Gi", st->st_oakley.group, keyex_pbs));
    /* Ni in */
// 读取NONCE载荷
    RETURN_STF_FAILURE(accept_nonce(md, &st->st_ni, "Ni"));
    {
// 分配密钥交换结构
 struct ke_continuation *ke = alloc_thing(struct ke_continuation
       , "outI2 KE");
 ke->md = md;
 st->st_suspended_md = md;
 if (!st->st_sec_in_use) {
// 如果没有加密处理, 先进行加密准备处理
     ke->ke_pcrc.pcrc_func = aggr_inI1_outR1_continue;
// 密钥交换处理
     return build_ke(&ke->ke_pcrc, st, st->st_oakley.group
       , st->st_import);
 } else {
// 否则已经支持加密了, 完成inI1_outR1的后续操作
     return aggr_inI1_outR1_tail((struct pluto_crypto_req_cont *)ke
     , NULL);
 }
    }
}

// inI1_outR1结尾部分, 构造要发送的数据包
static stf_status
aggr_inI1_outR1_tail(struct pluto_crypto_req_cont *pcrc
       , struct pluto_crypto_req *r)
{
// 密钥交换结构
    struct ke_continuation *ke = (struct ke_continuation *)pcrc;
    struct msg_digest *md = ke->md;
    struct state *st = md->st;
// SA载荷链表
    struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA];
    int auth_payload;
    pb_stream r_sa_pbs;
    pb_stream r_id_pbs; /* ID Payload; also used for hash calculation */
    /* parse_isakmp_sa also spits out a winning SA into our reply,
     * so we have to build our md->reply and emit HDR before calling it.
     */
// 初始化数据缓冲区
    init_pbs(&md->reply, reply_buffer, sizeof(reply_buffer), "reply packet");
    /* HDR out */
    {
 struct isakmp_hdr r_hdr = md->hdr;
// 填充ISAKMP头结构
 memcpy(r_hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE);
// 下一载荷是SA载荷
 r_hdr.isa_np = ISAKMP_NEXT_SA;
 if (!out_struct(&r_hdr, &isakmp_hdr_desc, &md->reply, &md->rbody))
     return STF_INTERNAL_ERROR;
    }
    /* start of SA out */
    {
 struct isakmp_sa r_sa = sa_pd->payload.sa;
 notification_t r;
// 填充SA载荷, 下一载荷是KE载荷
 r_sa.isasa_np = ISAKMP_NEXT_KE;
 if (!out_struct(&r_sa, &isakmp_sa_desc, &md->rbody, &r_sa_pbs))
     return STF_INTERNAL_ERROR;
 /* SA body in and out */
// 解析输入包中的SA提议, 同时输出自己可用的SA提议
 r = parse_isakmp_sa_body(&sa_pd->pbs, &sa_pd->payload.sa,
     &r_sa_pbs, FALSE, st);
 if (r != NOTHING_WRONG)
     return STF_FAIL + r;
    }
    /* don't know until after SA body has been parsed */
// 根据认证类型确定下一载荷是哈希载荷还是RSA签名载荷
    auth_payload = st->st_oakley.auth == OAKLEY_PRESHARED_KEY
 ? ISAKMP_NEXT_HASH : ISAKMP_NEXT_SIG;

    /************** build rest of output: KE, Nr, IDir, HASH_R/SIG_R ********/
    /* KE */
// 输出密钥交换载荷
    if (!ship_KE(st, r, &st->st_gr,
   &md->rbody, ISAKMP_NEXT_NONCE))
 return STF_INTERNAL_ERROR;
    /* Nr */
// 输出NONCE载荷
    if (!ship_nonce(&st->st_nr, r
      , &md->rbody, ISAKMP_NEXT_ID, "Nr"))
 return STF_INTERNAL_ERROR;
    /* IDir out */
    {
 struct isakmp_ipsec_id id_hd;
 chunk_t id_b;
// 输出ID载荷
 build_id_payload(&id_hd, &id_b, &st->st_connection->spd.this);
 id_hd.isaiid_np = auth_payload;
 if (!out_struct(&id_hd, &isakmp_ipsec_identification_desc, &md->rbody, &r_id_pbs)
 || !out_chunk(id_b, &r_id_pbs, "my identity"))
     return STF_INTERNAL_ERROR;
 close_output_pbs(&r_id_pbs);
    }
// DH交换计算
    (void)perform_dh_secretiv(st, RESPONDER, st->st_oakley.group->group);
// 更新初始化向量
    update_iv(st);

    /* HASH_R or SIG_R out */
    {
 u_char hash_val[MAX_DIGEST_LEN];
 size_t hash_len = main_mode_hash(st, hash_val, FALSE, &r_id_pbs);
 if (auth_payload == ISAKMP_NEXT_HASH)
 {
// 如果是预共享密钥认证, 输出哈希载荷
     /* HASH_R out */
     if (!out_generic_raw(ISAKMP_NEXT_VID
     , &isakmp_hash_desc
     , &md->rbody
     , hash_val
     , hash_len
     , "HASH_R"))
  return STF_INTERNAL_ERROR;
 }
 else
 {
// 是RSA签名认证
     /* SIG_R out */
     u_char sig_val[RSA_MAX_OCTETS];
     size_t sig_len = RSA_sign_hash(st->st_connection
  , sig_val, hash_val, hash_len);
     if (sig_len == 0)
     {
  loglog(RC_LOG_SERIOUS, "unable to locate my private key for RSA Signature");
  return STF_FAIL + AUTHENTICATION_FAILED;
     }
// 输出RSA签名载荷
     if (!out_generic_raw(ISAKMP_NEXT_VID, &isakmp_signature_desc
     , &md->rbody, sig_val, sig_len, "SIG_R"))
  return STF_INTERNAL_ERROR;
 }
    }
    /*
     * NOW SEND VENDOR ID payloads
     */
      
    /* Announce our ability to do RFC 3706 Dead Peer Detection to the peer
        if we have it enabled on this conn */
// 如果连接配置中设置了DPD尝试, 设置本地使用DPD标志
    if(st->st_connection->dpd_delay && st->st_connection->dpd_timeout) {
 /* Set local policy for DPD to be on */
 st->hidden_variables.st_dpd_local = 1;
    }
   
    {
// 下一载荷缺省为空
      int np = ISAKMP_NEXT_NONE;
#ifdef NAT_TRAVERSAL
      if (st->hidden_variables.st_nat_traversal) {
// 如果使用NAT穿越, 下一载荷为VID载荷
 np = ISAKMP_NEXT_VID;
      }
#endif
// 输出DPD VID载荷
      if( !out_generic_raw(np, &isakmp_vendor_id_desc
      , &md->rbody, dpd_vendorid
      , dpd_vendorid_len, "DPP Vendor ID")) {
 return STF_INTERNAL_ERROR;
      }
    }
#ifdef NAT_TRAVERSAL
    if (st->hidden_variables.st_nat_traversal) {
// 输出NAT穿越VID载荷
      if (!out_vendorid(auth_payload
   , &md->rbody
   , md->quirks.nat_traversal_vid)) {
 return STF_INTERNAL_ERROR;
      }
    }
    if (st->hidden_variables.st_nat_traversal & NAT_T_WITH_NATD) {
// 填充NATD载荷, 会自动修改前一载荷中的下一载荷字段类型值
      if (!nat_traversal_add_natd(auth_payload, &md->rbody, md))
 return STF_INTERNAL_ERROR;
    }
#endif
    /* finish message */
// 数据构造结束
    close_message(&md->rbody);
    return STF_OK;
}

14.4 发起方收到响应方第一回应包, 发送第2初始包

stf_status
aggr_inR1_outI2(struct msg_digest *md)
{
    /* With Aggressive Mode, we get an ID payload in this, the second
     * message, so we can use it to index the preshared-secrets
     * when the IP address would not be meaningful (i.e. Road
     * Warrior).  So our first task is to unravel the ID payload.
     */
// 所处状态
    struct state *st = md->st;
// KE载荷链表
    pb_stream *keyex_pbs = &md->chain[ISAKMP_NEXT_KE]->pbs;
// 状态策略带上野蛮协商标志
    st->st_policy |= POLICY_AGGRESSIVE;
// 解码对方ID载荷
    if (!decode_peer_id(md, FALSE, TRUE))
    {
 char buf[200];
// 失败的话记录日志返回错误
 (void) idtoa(&st->st_connection->spd.that.id, buf, sizeof(buf));
 loglog(RC_LOG_SERIOUS,
      "initial Aggressive Mode packet claiming to be from %s"
      " on %s but no connection has been authorized",
     buf, ip_str(&md->sender));
 /* XXX notification is in order! */
 return STF_FAIL + INVALID_ID_INFORMATION;
    }
    /* verify echoed SA */
    {
// 解析数据包中的SA载荷
 struct payload_digest *const sapd = md->chain[ISAKMP_NEXT_SA];
 notification_t r = \
     parse_isakmp_sa_body(&sapd->pbs, &sapd->payload.sa,
     NULL, TRUE, st);
// 出错返回
 if (r != NOTHING_WRONG)
     return STF_FAIL + r;
    }
    /* copy the quirks we might have accumulated */
    copy_quirks(&st->quirks, &md->quirks);
#ifdef NAT_TRAVERSAL
// 检查是否要进行NAT穿越处理
    if (nat_traversal_enabled && md->quirks.nat_traversal_vid) {
 st->hidden_variables.st_nat_traversal = nat_traversal_vid_to_method(md->quirks.nat_traversal_vid);
    }
#endif
    /* KE in */
// 读取KE载荷
    RETURN_STF_FAILURE(accept_KE(&st->st_gr, "Gr", st->st_oakley.group, keyex_pbs));
    /* Ni in */
// 读取NONCE载荷
    RETURN_STF_FAILURE(accept_nonce(md, &st->st_nr, "Nr"));
    /* moved the following up as we need Rcookie for hash, skeyids */
    /* Reinsert the state, using the responder cookie we just received */
// 将状态从系统哈希表中断开, 因为原来是按响应方cookie为空来查找哈希表的
    unhash_state(st);
// 复制对方cookie
    memcpy(st->st_rcookie, md->hdr.isa_rcookie, COOKIE_SIZE);
// 重新插入系统哈希表
    insert_state(st); /* needs cookies, connection, and msgid (0) */
#ifdef NAT_TRAVERSAL
// 查找NATD信息
    if (st->hidden_variables.st_nat_traversal & NAT_T_WITH_NATD) {
 nat_traversal_natd_lookup(md);
    }
// 输出NAT穿越信息
    if (st->hidden_variables.st_nat_traversal) {
 nat_traversal_show_result(st->hidden_variables.st_nat_traversal, md->sender_port);
    }
// 如果是NAT穿越保活信息, 设置保活事件
    if (st->hidden_variables.st_nat_traversal & NAT_T_WITH_KA) {
 nat_traversal_new_ka_event();
    }
#endif
    {
 stf_status stat;
// 进行DH交换计算密钥
 stat = perform_dh_secretiv(st, INITIATOR, st->st_oakley.group->group);
 if(stat != STF_OK) {
     return stat;
 }
    }
// 继续完成数据包构造
    return aggr_inR1_outI2_tail(md, NULL);
}

// 继续函数, 在使用OE情况下有效
static void
aggr_inR1_outI2_continue(struct adns_continuation *cr, err_t ugh)
{
    key_continue(cr, ugh, aggr_inR1_outI2_tail);
}
 
static stf_status
aggr_inR1_outI2_tail(struct msg_digest *md
       , struct key_continuation *kc)
{
    struct state *const st = md->st;
    struct connection *c = st->st_connection;
    int auth_payload;
    /* HASH_R or SIG_R in */
    {
// 野蛮模式读取ID载荷和认证处理,如果需要使用OE来认证对方, 则启动OE认证后重新执行
// aggr_inR1_outI2_continue函数处理,一般情况下不需要
 stf_status r = aggr_id_and_auth(md, TRUE
     , aggr_inR1_outI2_continue, kc);
 if (r != STF_OK)
     return r;
    }
// 根据认证类型确定下一载荷是哈希载荷还是RSA签名载荷
    auth_payload = st->st_oakley.auth == OAKLEY_PRESHARED_KEY
 ? ISAKMP_NEXT_HASH : ISAKMP_NEXT_SIG;
    /**************** build output packet: HDR, HASH_I/SIG_I **************/
    /* HDR out */
    {
// 构造ISAKMP头结构
 struct isakmp_hdr r_hdr = md->hdr;
// 拷贝响应方的cookie
 memcpy(r_hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE);
 /* outputting should back-patch previous struct/hdr with payload type */
// 下一载荷
 r_hdr.isa_np = auth_payload;
// 数据是加密
 r_hdr.isa_flags |= ISAKMP_FLAG_ENCRYPTION;  /* KLUDGE */
// 填充ISAKMP头
 if (!out_struct(&r_hdr, &isakmp_hdr_desc, &md->reply, &md->rbody))
     return STF_INTERNAL_ERROR;
    }
#ifdef NAT_TRAVERSAL
    if (st->hidden_variables.st_nat_traversal & NAT_T_WITH_NATD) {
// 填充NATD载荷, 会自动修改前一载荷中的下一载荷字段类型值
 if (!nat_traversal_add_natd(auth_payload, &md->rbody, md))
     return STF_INTERNAL_ERROR;
    }
#endif
    /* HASH_I or SIG_I out */
    {
 u_char buffer[1024];
 struct isakmp_ipsec_id id_hd;
 chunk_t id_b;
 pb_stream id_pbs;
 u_char hash_val[MAX_DIGEST_LEN];
 size_t hash_len;
// 构造ID载荷
 build_id_payload(&id_hd, &id_b, &st->st_connection->spd.this);
 init_pbs(&id_pbs, buffer, sizeof(buffer), "identity payload");
 id_hd.isaiid_np = ISAKMP_NEXT_NONE;
 if (!out_struct(&id_hd, &isakmp_ipsec_identification_desc, &id_pbs, NULL)
 || !out_chunk(id_b, &id_pbs, "my identity"))
     return STF_INTERNAL_ERROR;
 hash_len = main_mode_hash(st, hash_val, TRUE, &id_pbs);
 if (auth_payload == ISAKMP_NEXT_HASH)
 {
// 填充哈希载荷
     /* HASH_I out */
     if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_hash_desc, &md->rbody
     , hash_val, hash_len, "HASH_I"))
  return STF_INTERNAL_ERROR;
 }
 else
 {
// 填充RSA签名载荷
     /* SIG_I out */
     u_char sig_val[RSA_MAX_OCTETS];
     size_t sig_len = RSA_sign_hash(st->st_connection
  , sig_val, hash_val, hash_len);
     if (sig_len == 0)
     {
  loglog(RC_LOG_SERIOUS, "unable to locate my private key for RSA Signature");
  return STF_FAIL + AUTHENTICATION_FAILED;
     }
     if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_signature_desc
     , &md->rbody, sig_val, sig_len, "SIG_I"))
  return STF_INTERNAL_ERROR;
 }
    }
    /* RFC2408 says we must encrypt at this point */
    /* st_new_iv was computed by generate_skeyids_iv */
// 加密消息
    if (!encrypt_message(&md->rbody, st))
 return STF_INTERNAL_ERROR; /* ??? we may be partly committed */
// 最新的ISAKMP SA的序号
    c->newest_isakmp_sa = st->st_serialno;
    /* save last IV from phase 1 so it can be restored later so anything
     * between the end of phase 1 and the start of phase 2 ie mode config
     * payloads etc will not loose our IV
     */
// 保存初始化向量用于第2阶段
    memcpy(st->st_ph1_iv, st->st_new_iv, st->st_new_iv_len);
    st->st_ph1_iv_len = st->st_new_iv_len;
   
    return STF_OK;
}
 
14.5 响应方接收到发起方的第2个数据包
 
// 就是aggr_inI2_tail()的包裹函数
stf_status
aggr_inI2(struct msg_digest *md)
{
    return aggr_inI2_tail(md, NULL);
}

// 同样该函数在使用OE进行认证时才用
static void
aggr_inI2_continue(struct adns_continuation *cr, err_t ugh)
{
    key_continue(cr, ugh, aggr_inI2_tail);
}

stf_status
aggr_inI2_tail(struct msg_digest *md
       , struct key_continuation *kc)
{
    struct state *const st = md->st;
    struct connection *c = st->st_connection;
    u_char buffer[1024];
    struct payload_digest id_pd;
#ifdef NAT_TRAVERSAL
// NAT信息查找
    if (st->hidden_variables.st_nat_traversal & NAT_T_WITH_NATD) {
 nat_traversal_natd_lookup(md);
    }
// 输出NAT穿越信息
    if (st->hidden_variables.st_nat_traversal) {
 nat_traversal_show_result(st->hidden_variables.st_nat_traversal, md->sender_port);
    }
// 如果要支持NAT穿越保活, 调度发送保活信息
    if (st->hidden_variables.st_nat_traversal & NAT_T_WITH_KA) {
 nat_traversal_new_ka_event();
    }
#endif
    /* Reconstruct the peer ID so the peer hash can be authenticated */
    {
// 重构对方的ID载荷来认证对方
 struct isakmp_ipsec_id id_hd;
 chunk_t id_b;
 pb_stream pbs;
 pb_stream id_pbs;
// 构造ID载荷
 build_id_payload(&id_hd, &id_b, &st->st_connection->spd.that);
 init_pbs(&pbs, buffer, sizeof(buffer), "identity payload");
 id_hd.isaiid_np = ISAKMP_NEXT_NONE;
// 输出ID载荷
 if (!out_struct(&id_hd, &isakmp_ipsec_identification_desc, &pbs, &id_pbs)
  || !out_chunk(id_b, &id_pbs, "my identity"))
     return STF_INTERNAL_ERROR;
 close_output_pbs(&id_pbs);
 id_pbs.roof = pbs.cur;
 id_pbs.cur = pbs.start;
// 读取自己构造的对方ID载荷信息
 in_struct(&id_pd.payload, &isakmp_identification_desc, &id_pbs, &id_pd.pbs);
    }
// ID载荷链表
    md->chain[ISAKMP_NEXT_ID] = &id_pd;
    /* HASH_I or SIG_I in */
    {
// 野蛮模式读取ID载荷和认证处理,如果需要使用OE来认证对方, 则启动OE认证后重新执行
// aggr_inI2_continue函数处理,一般情况下不需要
 stf_status r = aggr_id_and_auth(md, FALSE
     , aggr_inI2_continue, kc);
// 失败则返回
 if (r != STF_OK)
     return r;
    }
// 认证成功, 建立ISAKMP SA, 准备进入第2阶段
    /* And reset the md to not leave stale pointers to our private id payload */
    md->chain[ISAKMP_NEXT_ID] = NULL;
    /**************** done input ****************/
// 连接当前的最新ISAKMP SA序号
    c->newest_isakmp_sa = st->st_serialno;
// 更新初始化向量
    update_iv(st); /* Finalize our Phase 1 IV */
    /* save last IV from phase 1 so it can be restored later so anything
     * between the end of phase 1 and the start of phase 2 ie mode config
     * payloads etc will not loose our IV
     */
// 保存初始化向量用于第2阶段
    memcpy(st->st_ph1_iv, st->st_new_iv, st->st_new_iv_len);
    st->st_ph1_iv_len = st->st_new_iv_len;
   
    DBG(DBG_CONTROL, DBG_log("phase 1 complete"));
    return STF_OK;
}

...... 待续 ......
 

你可能感兴趣的:(职场,休闲)