ikev1_quick.c
来自「ipsec vpn」· C语言 代码 · 共 2,176 行 · 第 1/4 页
C
2,176 行
/* IDcr (we are responder) */ 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 { /* implicit IDci and IDcr: peer and self */ if (!sameaddrtype(&c->spd.this.host_addr, &c->spd.that.host_addr)) return STF_FAIL; happy(addrtosubnet(&c->spd.this.host_addr, &b.my.net)); happy(addrtosubnet(&c->spd.that.host_addr, &b.his.net)); 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 voidreport_verify_failure(struct verify_oppo_bundle *b, err_t ugh){ struct state *st = b->md->st; char fgwb[ADDRTOT_BUF] , cb[ADDRTOT_BUF]; ip_address client; err_t which; switch (b->step) { case vos_our_client: case vos_our_txt:#ifdef USE_KEYRR case vos_our_key:#endif /* USE_KEYRR */ which = "our"; networkof(&b->my.net, &client); break; case vos_his_client: which = "his"; networkof(&b->his.net, &client); break; case vos_start: case vos_done: case vos_fail: default: bad_case(b->step); } addrtot(&st->st_connection->spd.that.host_addr, 0, fgwb, sizeof(fgwb)); addrtot(&client, 0, cb, sizeof(cb)); loglog(RC_OPPOFAILURE , "gateway %s wants connection with %s as %s client, but DNS fails to confirm delegation: %s {msgid:%08x}" , fgwb, cb, which, ugh, st->st_msgid);}static voidquick_inI1_outR1_continue(struct adns_continuation *cr, err_t ugh){ stf_status r; struct verify_oppo_continuation *vc = (void *)cr; struct verify_oppo_bundle *b = &vc->b; struct state *st = b->md->st; DBG(DBG_CONTROLMORE , DBG_log("quick inI1_outR1: adns continuation: %s", ugh)); passert(cur_state == NULL); /* if st == NULL, our state has been deleted -- just clean up */ if (st != NULL) { passert(st->st_suspended_md == b->md); st->st_suspended_md = NULL; /* no longer connected or suspended */ cur_state = st; if (!b->failure_ok && ugh != NULL) { report_verify_failure(b, ugh); r = STF_FAIL + INVALID_ID_INFORMATION; } else { r = quick_inI1_outR1_authtail(b, cr); } complete_state_transition(&b->md, r); } if (b->md != NULL) release_md(b->md); cur_state = NULL;}static stf_statusquick_inI1_outR1_start_query(struct verify_oppo_bundle *b, enum verify_oppo_step next_step){ struct msg_digest *md = b->md; struct state *p1st = md->st; struct connection *c = p1st->st_connection; struct verify_oppo_continuation *vc = alloc_thing(struct verify_oppo_continuation, "verify continuation"); struct id id /* subject of query */ , *our_id /* needed for myid playing */ , our_id_space; /* ephemeral: no need for unshare_id_content */ ip_address client; err_t ugh; /* Record that state is used by a suspended md */ b->step = next_step; /* not just vc->b.step */ vc->b = *b; passert(p1st->st_suspended_md == NULL); p1st->st_suspended_md = b->md; 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)); DBG_log("responding with DNS query - from %s to %s new state: %s" , ours, his, verify_step_name[b->step]); }); /* Resolve %myid in a cheesy way. * We have to do the resolution because start_adns_query * et al have insufficient information to do so. * If %myid is already known, we'll use that value * (XXX this may be a mistake: it could be stale). * If %myid is unknown, we should check to see if * there are credentials for the IP address or the FQDN. * Instead, we'll just assume the IP address since we are * acting as the responder and only the IP address would * have gotten it to us. * We don't even try to do this for the other side: * %myid makes no sense for the other side (but it is syntactically * legal). */ our_id = resolve_myid(&c->spd.this.id); if (our_id->kind == ID_NONE) { iptoid(&c->spd.this.host_addr, &our_id_space); our_id = &our_id_space; } switch (next_step) { case vos_our_client: networkof(&b->my.net, &client); iptoid(&client, &id); vc->b.failure_ok = b->failure_ok = FALSE; ugh = start_adns_query(&id , our_id , T_TXT , quick_inI1_outR1_continue , &vc->ac); break; case vos_our_txt: vc->b.failure_ok = b->failure_ok = TRUE; ugh = start_adns_query(our_id , our_id /* self as SG */ , T_TXT , quick_inI1_outR1_continue , &vc->ac); break;#ifdef USE_KEYRR case vos_our_key: vc->b.failure_ok = b->failure_ok = FALSE; ugh = start_adns_query(our_id , NULL , T_KEY , quick_inI1_outR1_continue , &vc->ac); break;#endif case vos_his_client: networkof(&b->his.net, &client); iptoid(&client, &id); vc->b.failure_ok = b->failure_ok = FALSE; ugh = start_adns_query(&id , &c->spd.that.id , T_TXT , quick_inI1_outR1_continue , &vc->ac); break; default: bad_case(next_step); } if (ugh != NULL) { /* note: we'd like to use vc->b but vc has been freed * so we have to use b. This is why we plunked next_state * into b, not just vc->b. */ report_verify_failure(b, ugh); p1st->st_suspended_md = NULL; return STF_FAIL + INVALID_ID_INFORMATION; } else { return STF_SUSPEND; }}static enum verify_oppo_stepquick_inI1_outR1_process_answer(struct verify_oppo_bundle *b, struct adns_continuation *ac, struct state *p1st){ struct connection *c = p1st->st_connection; enum verify_oppo_step next_step; err_t ugh = NULL; 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)); DBG_log("responding on demand from %s to %s state: %s" , ours, his, verify_step_name[b->step]); }); /* process just completed DNS query (if any) */ switch (b->step) { case vos_start: /* no query to digest */ next_step = vos_our_client; break; case vos_our_client: next_step = vos_his_client; { const struct RSA_private_key *pri = get_RSA_private_key(c); struct gw_info *gwp; if (pri == NULL) { ugh = "we don't know our own key"; break; } ugh = "our client does not delegate us as its Security Gateway"; for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next) { ugh = "our client delegates us as its Security Gateway but with the wrong public key"; /* If there is no key in the TXT record, * we count it as a win, but we will have * to separately fetch and check the KEY record. * If there is a key from the TXT record, * we count it as a win if we match the key. */ if (!gwp->gw_key_present) { next_step = vos_our_txt; ugh = NULL; /* good! */ break; } else if (same_RSA_public_key(&pri->pub, &gwp->key->u.rsa)) { ugh = NULL; /* good! */ break; } } } break; case vos_our_txt: next_step = vos_his_client; { const struct RSA_private_key *pri = get_RSA_private_key(c); if (pri == NULL) { ugh = "we don't know our own key"; break; } { struct gw_info *gwp; for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next) {#ifdef USE_KEYRR /* not an error yet, because we have to check KEY RR as well */ ugh = NULL;#else ugh = "our client delegation depends on our " RRNAME " record, but it has the wrong public key";#endif if (gwp->gw_key_present && same_RSA_public_key(&pri->pub, &gwp->key->u.rsa)) { ugh = NULL; /* good! */ break; }#ifdef USE_KEYRR next_step = vos_our_key;#endif } } } break;#ifdef USE_KEYRR case vos_our_key: next_step = vos_his_client; { const struct RSA_private_key *pri = get_RSA_private_key(c); if (pri == NULL) { ugh = "we don't know our own key"; break; } { struct pubkey_list *kp; ugh = "our client delegation depends on our missing " RRNAME " record"; for (kp = ac->keys_from_dns; kp != NULL; kp = kp->next) { ugh = "our client delegation depends on our " RRNAME " record, but it has the wrong public key"; if (same_RSA_public_key(&pri->pub, &kp->key->u.rsa)) { /* do this only once a day */ if (!logged_txt_warning) { loglog(RC_LOG_SERIOUS, "found KEY RR but not TXT RR. See http://www.freeswan.org/err/txt-change.html."); logged_txt_warning = TRUE; } ugh = NULL; /* good! */ break; } } } } break;#endif /* USE_KEYRR */ case vos_his_client: next_step = vos_done; { struct gw_info *gwp; /* check that the public key that authenticated * the ISAKMP SA (p1st) will do for this gateway. */ ugh = "peer's client does not delegate to peer"; for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next) { ugh = "peer and its client disagree about public key"; /* If there is a key from the TXT record, * we count it as a win if we match the key. * If there was no key, we claim a match since * it implies fetching a KEY from the same * place we must have gotten it. */ if (!gwp->gw_key_present || same_RSA_public_key(&p1st->st_peer_pubkey->u.rsa , &gwp->key->u.rsa)) { ugh = NULL; /* good! */ break; } } } break; default: bad_case(b->step); } if (ugh != NULL) { report_verify_failure(b, ugh); next_step = vos_fail; } return next_step;}static stf_statusquick_inI1_outR1_cryptotail(struct qke_continuation *qke , struct pluto_crypto_req *r);static voidquick_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")); /* XXX should check out ugh */ 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); if(qke->md != NULL) { complete_state_transition(&qke->md, e); release_md(qke->md); } reset_cur_state();}static stf_statusquick_inI1_outR1_authtail(struct verify_oppo_bundle *b , struct adns_continuation *ac){ struct msg_digest *md = b->md; struct state *const p1st = md->st; 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). */ { struct connection *p = find_client_connection(c , our_net, his_net, b->my.proto, b->my.port, b->his.proto, b->his.port);#if 0#ifdef NAT_TRAVERSAL#ifdef I_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT if( (p1st->hidden_variables.st_nat_traversal & NAT_T_DETECTED) && !(p1st->st_policy & POLICY_TUNNEL) && (p1st->hidden_variables.st_nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME)) && (p == NULL) ) { p = c; DBG(DBG_CONTROL, DBG_log("using (something) old for transport mode connection \"%s\"", p->name)); }#endif#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; me.client = *our_net; 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) { /* 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) { /* 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); next_step = quick_inI1_outR1_process_answer(b, ac, p1st); 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; /* the second chunk: initiate the next DNS query (if any) */ 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)); DBG_log("responding on demand from %s to %s new state: %s" , 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); /* Instantiate inbound Opportunistic connection, * carrying over authenticated peer ID
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?