快速模式第三包:quick_inR1_outI2()

1. 序言

在上一篇中博客中长话短说了第二包的处理流程,前两个报文的交互是快速模式的关键交互,用来协商会话参数(加解密算法、会话秘钥等),而第三包则是对前两个报文的认证,流程上简单了很多 。quick_inR1_outI2()处理流程实现的功能如下:

  • 解析SA载荷(对端选择的加解密算法信息)、KE载荷(pfs)、Nonce载荷
  • 构造第三个报文
  • 生成密钥生成材料keymats
  • 建立完整的IPsec SA
    • 发起端建立的为完整IPSec SA,包括入SA和出SA,响应端有所不同。
  • 启动DPD检测

2. quick_inR1_outI2()的处理流程

第三个报文的完整处理流程如下:

3. 快速模式第③包报文格式

该报文中的杂凑载荷是对前面交换的认证。第③包仅有ISAKMP头部和杂凑载荷构成,杂凑载荷的消息摘要是以一个0字节的MsgID、去掉载荷头的发起者Nonce以及去掉了载荷头的响应者Nonce为输入参数生成的,计算公式如下:

H

A

S

H

(

3

)

=

P

R

F

(

S

K

E

Y

a

,

0

M

s

g

I

D

N

i

b

N

r

b

)

HASH(3) = PRF(SKEY-a, 0|MsgID|Ni_b|Nr_b)

HASH(3)=PRF(SKEY−a,0∣MsgID∣Nib​∣Nrb​)

4. quick_inR1_outI2()源码分析

接口quick_inR1_outI2()的主要功能如下:

  • 验证报文的完整性
  • 解析响应端选择的SA载荷
    • 加解密算法(ESP协议、AH协议,…)
    • 认证算法
    • 封装模式(隧道模式 ?传输模式)
  • 解析Nonce载荷
  • 如果启用PFS
    • 解析KE载荷
    • 再次计算DH交换值
  1. stf_status
  2. quick_inR1_outI2(struct msg_digest *md)
  3. {
  4. struct state *const st = md->st;
  5. /* HASH(2) in *//*验证报文的哈希载荷*/
  6. CHECK_QUICK_HASH(md
  7. , quick_mode_hash12(hash_val, hash_pbs->roof, md->message_pbs.roof
  8. , st, &st->st_msgid, TRUE)
  9. , "HASH(2)", "Quick R1");
  10. /* SA in */
  11. {
  12. struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA];
  13. /*解析对端选择的SA载荷*/
  14. RETURN_STF_FAILURE(parse_ipsec_sa_body(&sa_pd->pbs
  15. , &sa_pd->payload.sa, NULL, TRUE, st));
  16. }
  17. /* Nr in *//*解析对端Nonce载荷*/
  18. RETURN_STF_FAILURE(accept_v1_nonce(md, &st->st_nr, "Nr"));
  19. /* [ KE ] in (for PFS) *//*根据配置策略解析对端KE载荷*/
  20. RETURN_STF_FAILURE(accept_PFS_KE(md, &st->st_gr, "Gr", "Quick Mode R1"));
  21. if(st->st_pfs_group) {/*如果支持PFS功能,则需要进行DH算法计算*/
  22. struct dh_continuation *dh = alloc_thing(struct dh_continuation
  23. , "quick outI2 DH");
  24. /* set up DH calculation */
  25. dh->md = md;
  26. passert(st != NULL);
  27. set_suspended(st, md);
  28. pcrc_init(&dh->dh_pcrc);
  29. dh->dh_pcrc.pcrc_func = quick_inR1_outI2_continue;
  30. return start_dh_secret(&dh->dh_pcrc, st
  31. , st->st_import
  32. , INITIATOR
  33. , st->st_pfs_group->group);
  34. } else {
  35. /* just call the tail function */
  36. struct dh_continuation dh;
  37. dh.md=md;
  38. return quick_inR1_outI2_cryptotail(&dh, NULL);
  39. }
  40. }

4. quick_inR1_outI2_cryptotail()源码分析

接口quick_inR1_outI2_cryptotail()的主要功能如下:

  • 检验ID载荷收发是否一致

    这里是通过ID载荷来协商IPSec隧道的保护子网信息

  • NAT-T相关处理

  • 构造应答报文

  • 计算keymats值

  • 建立IPSecSA

  • 初始化本隧道的DPD定时器

  1. stf_status
  2. quick_inR1_outI2_cryptotail(struct dh_continuation *dh
  3. , struct pluto_crypto_req *r)
  4. {
  5. struct msg_digest *md = dh->md;
  6. struct state *st = md->st;
  7. struct connection *c = st->st_connection;
  8. if (st->st_pfs_group != NULL && r!=NULL) {
  9. finish_dh_secret(st, r);/*获取密钥信息*/
  10. if(!r->pcr_success) {
  11. return STF_FAIL + INVALID_KEY_INFORMATION;
  12. }
  13. }
  14. #ifdef NAT_TRAVERSAL
  15. ... ...
  16. #endif
  17. /* [ IDci, IDcr ] in; these must match what we sent */
  18. {
  19. struct payload_digest *const IDci = md->chain[ISAKMP_NEXT_ID];
  20. struct payload_digest *IDcr;
  21. if (IDci != NULL)/*应答报文中包含ID载荷*/
  22. {
  23. /* ??? we are assuming IPSEC_DOI */
  24. /* IDci (we are initiator) *//*确定收发ID载荷是否一致*/
  25. if (!check_net_id(&IDci->payload.ipsec_id, &IDci->pbs
  26. , &st->st_myuserprotoid, &st->st_myuserport
  27. , &st->st_connection->spd.this
  28. , &st->st_localaddr
  29. , "our client"))
  30. return STF_FAIL + INVALID_ID_INFORMATION;
  31. /* we checked elsewhere that we got two of them */
  32. IDcr = IDci->next;/*响应端ID载荷是否匹配*/
  33. passert(IDcr != NULL);
  34. /* IDcr (responder is peer) */
  35. if (!check_net_id(&IDcr->payload.ipsec_id, &IDcr->pbs
  36. , &st->st_peeruserprotoid, &st->st_peeruserport
  37. , &st->st_connection->spd.that
  38. , &st->st_remoteaddr
  39. , "peer client"))
  40. return STF_FAIL + INVALID_ID_INFORMATION;
  41. /*
  42. * if there is a NATOA payload, then use it as
  43. * &st->st_connection->spd.that.client, if the type
  44. * of the ID was FQDN
  45. */
  46. #ifdef NAT_TRAVERSAL
  47. ... ...
  48. #endif
  49. }
  50. else
  51. {
  52. /* no IDci, IDcr: we must check that the defaults match our proposal */
  53. if (!subnetisaddr(&c->spd.this.client, &c->spd.this.host_addr)/*两个地址一样即可*/
  54. || !subnetisaddr(&c->spd.that.client, &c->spd.that.host_addr))
  55. {
  56. loglog(RC_LOG_SERIOUS, "IDci, IDcr payloads missing in message"
  57. " but default does not match proposal");
  58. return STF_FAIL + INVALID_ID_INFORMATION;
  59. }
  60. }
  61. }
  62. /**************** build reply packet HDR*, HASH(3) ****************/
  63. /* HDR* out done ISAKMP头部已经填充完毕*/
  64. /* HASH(3) out -- sometimes, we add more content */
  65. {
  66. u_char /* set by START_HASH_PAYLOAD: */
  67. *r_hashval, /* where in reply to jam hash value */
  68. *r_hash_start; /* start of what is to be hashed */
  69. /*填充hash载荷*/
  70. START_HASH_PAYLOAD(md->rbody, ISAKMP_NEXT_NONE);
  71. /*计算哈希载荷值,用于对端检测报文的完整性*/
  72. (void)quick_mode_hash3(r_hashval, st);
  73. r_hash_start = r_hash_start; /* otherwise complaint about never used */
  74. }
  75. /* Derive new keying material *//*计算密钥生成材料*/
  76. compute_keymats(st);
  77. /* Tell the kernel to establish the inbound, outbound, and routing part
  78. * of the new SA (unless the commit bit is set -- which we don't support).
  79. * We do this before any state updating so that
  80. * failure won't look like success.
  81. */
  82. if (!install_ipsec_sa(md->pst, st, TRUE))/*建立IPsecSA*/
  83. return STF_INTERNAL_ERROR;
  84. /* encrypt message, except for fixed part of header */
  85. /*加密*/
  86. if (!encrypt_message(&md->rbody, st))
  87. {
  88. delete_ipsec_sa(st, FALSE);
  89. return STF_INTERNAL_ERROR; /* ??? we may be partly committed */
  90. }
  91. st->st_connection->newest_ipsec_sa = st->st_serialno;
  92. /* note (presumed) success */
  93. if (c->gw_info != NULL)
  94. c->gw_info->key->last_worked_time = now();
  95. /* If we have dpd delay and dpdtimeout set, then we are doing DPD
  96. on this conn, so initialize it */
  97. if (st->st_connection->dpd_delay && st->st_connection->dpd_timeout) {
  98. if(dpd_init(st) != STF_OK) {/*启动DPD定时器*/
  99. delete_ipsec_sa(st, FALSE);
  100. return STF_FAIL;
  101. }
  102. }
  103. return STF_OK;
  104. }

4. compute_keymats()源码分析

compute_keymats()是一个很重的函数,功能是第二阶段计算生成密钥材料,它的计算方式如下:

  • 如果启用PFS功能:

K

E

Y

M

A

T

S

=

P

R

F

(

S

K

E

Y

S

T

R

d

,

g

x

y

p

r

o

t

o

c

o

l

S

P

I

N

i

b

N

r

b

)

KEYMATS = PRF(SKEYSTR-d, g^{xy} | protocol | SPI | Ni-b |Nr-b )

KEYMATS=PRF(SKEYSTR−d,gxy∣protocol∣SPI∣Ni−b∣Nr−b)

  • 未用PFS功能:

K

E

Y

M

A

T

S

=

P

R

F

(

S

K

E

Y

S

T

R

d

,

p

r

o

t

o

c

o

l

S

P

I

N

i

b

N

r

b

)

KEYMATS = PRF(SKEYSTR-d, protocol | SPI | Ni-b |Nr-b )

KEYMATS=PRF(SKEYSTR−d,protocol∣SPI∣Ni−b∣Nr−b)

需要注意的是:

  • g

    x

    y

    g^{xy}

    gxy是第二阶段通过额外的DH交换计算得到的(DH计算出的共享秘钥),存储在st->st_shared中。此变量虽然在第一阶段时也有生成,但是第二阶段使用了第一阶段复制的state状态,并未使用第一阶段中的st_shared的值,因此第二阶段的st->st_shared只有在进行额外的DH交换后才会生成,且不会使用第一阶段的共享密钥的值。

  1. static void
  2. compute_keymats(struct state *st)
  3. {
  4. if (st->st_ah.present)
  5. compute_proto_keymat(st, PROTO_IPSEC_AH, &st->st_ah, "AH");
  6. if (st->st_esp.present)
  7. compute_proto_keymat(st, PROTO_IPSEC_ESP, &st->st_esp, "ESP");
  8. }
  9. /*
  10. * Produce the new key material of Quick Mode.
  11. * RFC 2409 "IKE" section 5.5
  12. * specifies how this is to be done.
  13. *###############################################
  14. * compute_proto_keymat非常重要的密钥协商函数
  15. *###############################################
  16. */
  17. static void
  18. compute_proto_keymat(struct state *st
  19. , u_int8_t protoid
  20. , struct ipsec_proto_info *pi
  21. , const char *satypename)
  22. {
  23. size_t needed_len = 0; /* bytes of keying material needed */
  24. /* Add up the requirements for keying material
  25. * (It probably doesn't matter if we produce too much!)
  26. */
  27. switch (protoid)
  28. {
  29. case PROTO_IPSEC_ESP:
  30. switch (pi->attrs.transattrs.encrypt)/*加密算法*/
  31. {
  32. case ESP_NULL:
  33. needed_len = 0;
  34. break;
  35. case ESP_DES:
  36. needed_len = DES_CBC_BLOCK_SIZE;
  37. break;
  38. case ESP_3DES:
  39. needed_len = DES_CBC_BLOCK_SIZE * 3;
  40. break;
  41. case ESP_AES:
  42. needed_len = AES_CBC_BLOCK_SIZE;
  43. /* if an attribute is set, then use that! */
  44. if(st->st_esp.attrs.transattrs.enckeylen) {/*如果属性载荷设置了此参数,则使用此参数的值*/
  45. needed_len = st->st_esp.attrs.transattrs.enckeylen/8;
  46. }
  47. break;
  48. default:
  49. #ifdef KERNEL_ALG
  50. if((needed_len=kernel_alg_esp_enc_keylen(pi->attrs.transattrs.encrypt))>0) {
  51. /* XXX: check key_len "coupling with kernel.c's */
  52. if (pi->attrs.transattrs.enckeylen) {
  53. needed_len=pi->attrs.transattrs.enckeylen/8;
  54. DBG(DBG_PARSING, DBG_log("compute_proto_keymat:"
  55. "key_len=%d from peer",
  56. (int)needed_len));
  57. }
  58. break;
  59. }
  60. #endif
  61. bad_case(pi->attrs.transattrs.encrypt);
  62. }
  63. DBG(DBG_PARSING, DBG_log("compute_proto_keymat:"
  64. "needed_len (after ESP enc)=%d",
  65. (int)needed_len));
  66. switch (pi->attrs.transattrs.integ_hash)/*哈希算法*/
  67. {
  68. case AUTH_ALGORITHM_NONE:
  69. break;
  70. case AUTH_ALGORITHM_HMAC_MD5:
  71. needed_len += HMAC_MD5_KEY_LEN;
  72. break;
  73. case AUTH_ALGORITHM_HMAC_SHA1:
  74. needed_len += HMAC_SHA1_KEY_LEN;
  75. break;
  76. default:
  77. #ifdef KERNEL_ALG
  78. if (kernel_alg_esp_auth_ok(pi->attrs.transattrs.integ_hash, NULL) == NULL) {
  79. needed_len += kernel_alg_esp_auth_keylen(pi->attrs.transattrs.integ_hash);
  80. break;
  81. }
  82. #endif
  83. case AUTH_ALGORITHM_DES_MAC:
  84. bad_case(pi->attrs.transattrs.integ_hash);
  85. break;
  86. }
  87. DBG(DBG_PARSING, DBG_log("compute_proto_keymat:"
  88. "needed_len (after ESP auth)=%d",
  89. (int)needed_len));
  90. break;
  91. case PROTO_IPSEC_AH:
  92. switch (pi->attrs.transattrs.encrypt)
  93. {
  94. case AH_MD5:
  95. needed_len = HMAC_MD5_KEY_LEN;
  96. break;
  97. case AH_SHA:
  98. needed_len = HMAC_SHA1_KEY_LEN;
  99. break;
  100. default:
  101. #ifdef KERNEL_ALG
  102. if (kernel_alg_ah_auth_ok(pi->attrs.transattrs.integ_hash, NULL)) {
  103. needed_len += kernel_alg_ah_auth_keylen(pi->attrs.transattrs.integ_hash);
  104. break;
  105. }
  106. #endif
  107. bad_case(pi->attrs.transattrs.encrypt);
  108. }
  109. break;
  110. default:
  111. bad_case(protoid);
  112. }
  113. /*将所有算法需要的密钥长度全部相加,从而生成所需长度的密钥材料*/
  114. pi->keymat_len = needed_len;
  115. /* Allocate space for the keying material.
  116. * Although only needed_len bytes are desired, we
  117. * must round up to a multiple of ctx.hmac_digest_len
  118. * so that our buffer isn't overrun.
  119. */
  120. {
  121. struct hmac_ctx ctx_me, ctx_peer;
  122. size_t needed_space; /* space needed for keying material (rounded up) */
  123. size_t i;
  124. hmac_init_chunk(&ctx_me, st->st_oakley.prf_hasher, st->st_skeyid_d);
  125. ctx_peer = ctx_me; /* duplicate initial conditions */
  126. needed_space = needed_len + pad_up(needed_len, ctx_me.hmac_digest_len);
  127. replace(pi->our_keymat, alloc_bytes(needed_space, "keymat in compute_keymat()"));
  128. replace(pi->peer_keymat, alloc_bytes(needed_space, "peer_keymat in quick_inI1_outR1()"));
  129. /*
  130. * 准备计算秘钥所需的所有材料
  131. * 1. DH交换生成的共享秘钥
  132. * 2. 协议protocol
  133. * 3. SPI
  134. * 4. Ni_b
  135. * 5. Nr_b
  136. */
  137. for (i = 0;; )
  138. {
  139. /*1. DH交换生成的共享秘钥*/
  140. if (st->st_shared.ptr != NULL)
  141. {
  142. /* PFS: include the g^xy */
  143. hmac_update_chunk(&ctx_me, st->st_shared);
  144. hmac_update_chunk(&ctx_peer, st->st_shared);
  145. }
  146. /*2. 协议protocol*/
  147. hmac_update(&ctx_me, &protoid, sizeof(protoid));
  148. hmac_update(&ctx_peer, &protoid, sizeof(protoid));
  149. /*3. SPI*/
  150. hmac_update(&ctx_me, (u_char *)&pi->our_spi, sizeof(pi->our_spi));
  151. hmac_update(&ctx_peer, (u_char *)&pi->attrs.spi, sizeof(pi->attrs.spi));
  152. /*4. Ni_b*/
  153. hmac_update_chunk(&ctx_me, st->st_ni);
  154. hmac_update_chunk(&ctx_peer, st->st_ni);
  155. /*5. Nr_b*/
  156. hmac_update_chunk(&ctx_me, st->st_nr);
  157. hmac_update_chunk(&ctx_peer, st->st_nr);
  158. hmac_final(pi->our_keymat + i, &ctx_me);
  159. hmac_final(pi->peer_keymat + i, &ctx_peer);
  160. i += ctx_me.hmac_digest_len;
  161. if (i >= needed_space)
  162. break;
  163. /* more keying material needed: prepare to go around again */
  164. hmac_reinit(&ctx_me);
  165. hmac_reinit(&ctx_peer);
  166. hmac_update(&ctx_me, pi->our_keymat + i - ctx_me.hmac_digest_len, ctx_me.hmac_digest_len);
  167. hmac_update(&ctx_peer, pi->peer_keymat + i - ctx_peer.hmac_digest_len, ctx_peer.hmac_digest_len);
  168. }
  169. }
  170. /*双方能计算出对端的密钥材料信息???*/
  171. DBG(DBG_CRYPT,
  172. DBG_log("%s KEYMAT\n",satypename);
  173. DBG_dump(" KEYMAT computed:\n", pi->our_keymat, pi->keymat_len);
  174. DBG_dump(" Peer KEYMAT computed:\n", pi->peer_keymat, pi->keymat_len));
  175. }

5. dpd_init()源码分析

DPD功能对应有两个事件:

  • EVENT_DPD_TIMEOUT

    第一阶段的定时器,在第二阶段已经断开的情况下,用来检测第一阶段是否超时

  • DPD_EVENT

    第二阶段的定时器,长时间未通讯时断开连接,并启动第一阶段的定时器

这个定时器机制实际使用时会复杂一点。可以参考注释说明。

  1. /**
  2. * Initialize RFC 3706 Dead Peer Detection
  3. *
  4. * @param st An initialized state structure
  5. * @return void
  6. *
  7. * How DPD works.
  8. *
  9. * There are two kinds of events that can be scheduled.
  10. * At most one of them is schedule at any given time.
  11. *
  12. * The EVENT_DPD_TIMEOUT event, if it ever goes off, means that
  13. * neither the ISAKMP SA nor the IPsec SA has *RECEIVED* any DPD
  14. * events lately.
  15. *
  16. * 0) So, every time we receive a DPD (R_U_THERE or R_U_ACK), then
  17. * we delete any DPD event (EVENT_DPD or EVENT_DPD_TIMEOUT), and
  18. * we schedule a new DPD_EVENT (sending) for "delay" in the future.
  19. *
  20. * 1) When the DPD_EVENT goes off, we check the phase 2 (if there is one)
  21. * SA to see if there was incoming traffic. If there was, then we are happy,
  22. * we set a new DPD_EVENT, and we are done.
  23. *
  24. * 2) If there was no phase 2 activity, we check if there was a recent enough
  25. * DPD activity (st->st_last_dpd). If so, we just reschedule, and do
  26. * nothing.
  27. *
  28. * 3) Otherwise, we send a DPD R_U_THERE message, and set the
  29. * EVENT_DPD_TIMEOUT on the phase 1.
  30. *
  31. * One thing to realize when looking at "ipsec whack --listevents" output,
  32. * is there there will only be DPD_EVENT_TIMEOUT events if there are
  33. * outstanding R_U_THERE messages.
  34. *
  35. * The above is the basic idea, but things are a bit more complicated because
  36. * multiple phase 2s can share the same phase 1 ISAKMP SA. Each phase 2 state
  37. * has its own DPD_EVENT. Further, we start a DPD_EVENT for phase 1 when it
  38. * gets established. This is because the phase 2 may never actually succeed
  39. * (usually due to authorization issues, which may be DNS or otherwise related)
  40. * and if the responding end dies (gets restarted, or the conn gets reloaded
  41. * with the right policy), then we may have a bum phase 1 SA, and we can not
  42. * re-negotiate. (This happens WAY too often)
  43. *
  44. * The phase 2 dpd_init() will attempt to kill the phase 1 DPD_EVENT, if it
  45. * can, to reduce the amount of work.
  46. *
  47. * The st_last_dpd member which is used is always the one from the phase 1.
  48. * So, if there are multiple phase 2s, then if any of them receive DPD data
  49. * they will update the st_last_dpd, so the test in #2 will avoid the traffic
  50. * for all by one phase 2.
  51. *
  52. * Note that the EVENT_DPD are attached to phase 2s (typically), while the
  53. * EVENT_DPD_TIMEOUT are attached to phase 1s only.
  54. *
  55. * Finally, if the connection is using NAT-T, then we ignore the phase 2
  56. * activity check, because in the case of a unidirectional stream (VoIP for
  57. * a conference call, for instance), we may not send enough traffic to keep
  58. * the NAT port mapping valid.
  59. *
  60. */
  61. stf_status
  62. dpd_init(struct state *st)
  63. {
  64. /**
  65. * Used to store the 1st state
  66. */
  67. #ifdef HAVE_LABELED_IPSEC
  68. if(st->st_connection->loopback) {
  69. openswan_log("dpd is not required for ipsec connections over loopback");
  70. return STF_OK;
  71. }
  72. #endif
  73. struct state *p1st;
  74. /* find the related Phase 1 state */
  75. p1st = find_state_ikev1(st->st_icookie, st->st_rcookie,
  76. &st->st_connection->spd.that.host_addr, 0);/*第一阶段的msgid为0*/
  77. if (p1st == NULL) {
  78. loglog(RC_LOG_SERIOUS, "could not find phase 1 state for DPD");
  79. /*
  80. * if the phase 1 state has gone away, it really should have
  81. * deleted all of its children.
  82. * Why would this happen? because a quick mode SA can take
  83. * some time to create (DNS lookups for instance), and the phase 1
  84. * might have been taken down for some reason in the meantime.
  85. * We really can not do anything here --- attempting to invoke
  86. * the DPD action would be a good idea, but we really should
  87. * do that outside this function.
  88. */
  89. return STF_FAIL;
  90. }
  91. /* if it was enabled, and we haven't turned it on already */
  92. if (p1st->hidden_variables.st_dpd) {
  93. time_t n = now();
  94. openswan_log("Dead Peer Detection (RFC 3706): enabled");
  95. if(st->st_dpd_event == NULL || (st->st_connection->dpd_delay + n) < st->st_dpd_event->ev_time) {
  96. delete_dpd_event(st);
  97. event_schedule(EVENT_DPD, st->st_connection->dpd_delay, st);
  98. }
  99. } else {
  100. openswan_log("Dead Peer Detection (RFC 3706): not enabled because peer did not advertise it");
  101. }
  102. if(p1st != st) {/*第一阶段的DPD_EVENT事件已经没有必要,可以进行删除了,第二阶段会有自己的DPD_EVENT*/
  103. /* st was not a phase 1 SA, so kill the DPD_EVENT on the phase 1 */
  104. if(p1st->st_dpd_event != NULL
  105. && p1st->st_dpd_event->ev_type == EVENT_DPD) {
  106. delete_dpd_event(p1st);
  107. }
  108. }
  109. return STF_OK;
  110. }

6. install_ipsec_sa()源码分析

快速模式第三包:quick_inR1_outI2()的更多相关文章

  1. 快速模式第三包收尾之quick_inI2()

    快速模式第三包收尾之quick_inI2() 文章目录 快速模式第三包收尾之quick_inI2() 1. 序言 2. quick_inI2()处理流程图 3. 报文格式 4. quick_inI2( ...

  2. openswan中ISAKMP交互过程关键函数接口

    1. ISAKMP交互过程中关键函数接口 下面分别说明不同的阶段和模式下的函数接口以及对应的报文. 2. 第一阶段(Phase I)主模式函数接口 发送端 响应端 main_outI1 主模式第一包 ...

  3. IPsec 9个包分析(主模式+快速模式)

    第一阶段:ISAKMP协商阶段 1.1 第一包 包1:发起端协商SA,使用的是UDP协议,端口号是500,上层协议是ISAKMP,该协议提供的是一个框架,里面的负载Next payload类似模块,可 ...

  4. iPhone 6 被盗记录二【写在315前夕:苹果售后福州直信创邺在没有三包的情况下帮小偷翻新、助力小偷换机销赃!无视王法。让人震惊,痛心,憎恨!消费者很受伤很无奈】

    投诉公司: 北京直信创邺数码科技有限公司  标题: 写在315前夕:苹果售后在没有三包的情况下帮小偷翻新.助力小偷换机销赃!无视王法.让人震惊,痛心,憎恨!消费者很受伤很无奈 期望: 还我手机,或者赔 ...

  5. python能够执行,但编译第三包遇到 python.h no such file or directory

    python能够执行,但编译第三包遇到 python.h no such file or directory 这个问题是由于没有安装python-devel, 安装此包就能够解决次问题,在Linux下 ...

  6. 数据结构20:KMP算法(快速模式匹配算法)详解

    通过上一节的介绍,学习了串的普通模式匹配算法,大体思路是:模式串从主串的第一个字符开始匹配,每匹配失败,主串中记录匹配进度的指针 i 都要进行 i-j+1 的回退操作(这个过程称为“指针回溯”),同时 ...

  7. java普通项目打包成可执行jar文件时如何添加第三包

    在java的web项目中,引用第三方包的时候非常简单.因为在web项目上中,默认有一个web-inf文件夹.web-inf文件夹下有一个lib文件夹,如果有用到第三方包,直接丢进去就行了.但是对于普通 ...

  8. 快速模式第二包: quick_inI1_ouR1()

    文章目录 1. 序言 2. quick_inI1_outR1()流程图 3. 快速模式消息②数据包格式 4. 源码分析 4.1 quick_inI1_outR1() 4.2 quick_inI1_ou ...

  9. 快速模式第一包: quick_outI1()

    文章目录 1. 序言 2. quick_outI1()流程图 3. quick_outI1()源码分析 4. quick_outI1_continue()源码分析 5. quick_outI1_tai ...

随机推荐

  1. Zabbix中Agent自动注册

    目录 Active agent自动注册 以下情况,自动注册会自动运行: 配置 服务端配置 客户端配置 Active agent自动注册 zabbix Active agent可以实现自动注册,进而服务 ...

  2. 一文带你认识LPWA通信技术

    摘要:为了满足越来越多的远距离物联网设备的连接需求,LPWA应用而生. 本文分享自华为云社区<常见物联网通信技术之LPWA通信技术>,作者:爱吃面包的猫. 如果你比较关注物联网圈的话,想必 ...

  3. 破解加速乐-java

    记录一哈自己遇到的简单站点的破解 Talk is cheap,show you the code! import com.google.gson.Gson; import com.google.gso ...

  4. 记录21.07.21 —— ES6基础

    学习目录 课件地址: ES6核心技术课件 1.let关键字 1.1 let与var的区别 ①let不能重复定义 ②块作用域的区别 ③变量声明之前let不能使用,var可以 ④ 课件代码 <htm ...

  5. pwnable.kr之simple Login

    pwnable.kr之simple Login 懒了几天,一边看malloc.c的源码,一边看华庭的PDF.今天佛系做题,到pwnable.kr上打开了simple Login这道题,但是这道题个人觉 ...

  6. 2021年最新字节跳动Android面试真题解析

    概述 时间过得是真TM快,回想自己是16年从学校毕业,现在是出来工作的第五个年头啦.在不同的大小公司都待过,就在前段时间顺利的完成了一次跳槽涨薪,面试了几家公司,最终选择了字节跳动.今特此前来跟大家进 ...

  7. gRPC学习之二:GO的gRPC开发环境准备

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos gRPC学习系列文章链接 在CentOS7部署和设置G ...

  8. OEM 刷新配置方法

    一:设置>添加目标>配置自动搜索 二:主机上的目标>针对所选的主机 三:禁用调度 四:设置>添加目标>自动搜索结果 五:主机上的目标,搜索结果 六:删除 七:选择机器数据 ...

  9. mysql《一》

    一.启动和停止服务器 通过管理员权限打开cmd命令指示符 通过 net stop mysql(自己的服务器名字)  停止服务器 通过 net start mysql(自己的服务器名字)  启动服务器 ...

  10. FreeRTOS-05-队列

    说明 本文仅作为学习FreeRTOS的记录文档,作为初学者肯定很多理解不对甚至错误的地方,望网友指正. FreeRTOS是一个RTOS(实时操作系统)系统,支持抢占式.合作式和时间片调度.适用于微处理 ...