📄 connections.c
字号:
} DBG(DBG_OPPO, DBG_log("comparing best %s to %s" , best->name, c->name)); for (bestsr = &best->spd; best!=c && bestsr; bestsr=bestsr->next) { if (!subnetinsubnet(&bestsr->this.client, &sr->this.client) || (samesubnet(&bestsr->this.client, &sr->this.client) && !subnetinsubnet(&bestsr->that.client , &sr->that.client))) { best = c; } } } } } } if (best == NULL || NEVER_NEGOTIATE(best->policy) || (best->policy & POLICY_OPPO) == LEMPTY || best->kind != CK_TEMPLATE) return NULL; else return oppo_instantiate(best, &gw->gw_id.ip_addr, NULL, gw , our_client, peer_client);}boolorient(struct connection *c){ struct spd_route *sr; if (!oriented(*c)) { struct iface_port *p; for (sr = &c->spd; sr; sr = sr->next) { /* Note: this loop does not stop when it finds a match: * it continues checking to catch any ambiguity. */ for (p = interfaces; p != NULL; p = p->next) {#ifdef NAT_TRAVERSAL if (p->ike_float) continue;#endif for (;;) { /* check if this interface matches this end */ if (sameaddr(&sr->this.host_addr, &p->ip_addr) && (kern_interface != NO_KERNEL || sr->this.host_port == pluto_port)) { if (oriented(*c)) { if (c->interface->ip_dev == p->ip_dev) loglog(RC_LOG_SERIOUS , "both sides of \"%s\" are our interface %s!" , c->name, p->ip_dev->id_rname); else loglog(RC_LOG_SERIOUS, "two interfaces match \"%s\" (%s, %s)" , c->name, c->interface->ip_dev->id_rname, p->ip_dev->id_rname); c->interface = NULL; /* withdraw orientation */ return FALSE; } c->interface = p; } /* done with this interface if it doesn't match that end */ if (!(sameaddr(&sr->that.host_addr, &p->ip_addr) && (kern_interface!=NO_KERNEL || sr->that.host_port == pluto_port))) break; /* swap ends and try again. * It is a little tricky to see that this loop will stop. * Only continue if the far side matches. * If both sides match, there is an error-out. */ { struct end t = sr->this; sr->this = sr->that; sr->that = t; } } } } } return oriented(*c);}voidinitiate_connection(const char *name, int whackfd , lset_t moredebug , enum crypto_importance importance){ struct connection *c = con_by_name(name, TRUE); if (c != NULL) { set_cur_connection(c); /* turn on any extra debugging asked for */ c->extra_debugging |= moredebug; if (!oriented(*c)) { loglog(RC_ORIENT, "We cannot identify ourselves with either end of this connection."); } else if (NEVER_NEGOTIATE(c->policy)) { loglog(RC_INITSHUNT , "cannot initiate an authby=never connection"); } else if (c->kind != CK_PERMANENT) { if (isanyaddr(&c->spd.that.host_addr)) loglog(RC_NOPEERIP, "cannot initiate connection without knowing peer IP address (kind=%s)" , enum_show(&connection_kind_names, c->kind)); else loglog(RC_WILDCARD, "cannot initiate connection with ID wildcards (kind=%s)" , enum_show(&connection_kind_names, c->kind)); } else { /* We will only request an IPsec SA if policy isn't empty * (ignoring Main Mode items). * This is a fudge, but not yet important. * If we are to proceed asynchronously, whackfd will be NULL_FD. */ c->policy |= POLICY_UP; if(c->policy & POLICY_ENCRYPT) { struct alg_info_esp *alg = c->alg_info_esp; struct db_sa *phase2_sa = kernel_alg_makedb(alg, TRUE); if(alg != NULL && phase2_sa == NULL) { whack_log(RC_NOALGO, "can not initiate: no acceptable kernel algorithms loaded"); reset_cur_connection(); close_any(whackfd); return; } free_sa(phase2_sa); }#ifdef SMARTCARD /* do we have to prompt for a PIN code? */ if (c->spd.this.sc != NULL && !c->spd.this.sc->valid && whackfd != NULL_FD) scx_get_pin(c->spd.this.sc, whackfd); if (c->spd.this.sc != NULL && !c->spd.this.sc->valid) { loglog(RC_NOVALIDPIN, "cannot initiate connection without valid PIN"); } else#endif { ipsecdoi_initiate(whackfd, c, c->policy, 1 , SOS_NOBODY, importance); whackfd = NULL_FD; /* protect from close */ } } reset_cur_connection(); } close_any(whackfd);}/* (Possibly) Opportunistic Initiation: * Knowing clients (single IP addresses), try to build an tunnel. * This may involve discovering a gateway and instantiating an * Opportunistic connection. Called when a packet is caught by * a %trap, or when whack --oppohere --oppothere is used. * It may turn out that an existing or non-opporunistic connnection * can handle the traffic. * * Most of the code will be restarted if an ADNS request is made * to discover the gateway. The only difference between the first * and second entry is whether gateways_from_dns is NULL or not. * initiate_opportunistic: initial entrypoint * continue_oppo: where we pickup when ADNS result arrives * initiate_opportunistic_body: main body shared by above routines * cannot_oppo: a helper function to log a diagnostic * This structure repeats a lot of code when the ADNS result arrives. * This seems like a waste, but anything learned the first time through * may no longer be true! * * After the first IKE message is sent, the regular state machinery * carries negotiation forward. */enum find_oppo_step { fos_start, fos_myid_ip_txt, fos_myid_hostname_txt, fos_myid_ip_key, fos_myid_hostname_key, fos_our_client, fos_our_txt,#ifdef USE_KEYRR fos_our_key,#endif /* USE_KEYRR */ fos_his_client, fos_done};#ifdef DEBUGstatic const char *const oppo_step_name[] = { "fos_start", "fos_myid_ip_txt", "fos_myid_hostname_txt", "fos_myid_ip_key", "fos_myid_hostname_key", "fos_our_client", "fos_our_txt",#ifdef USE_KEYRR "fos_our_key",#endif /* USE_KEYRR */ "fos_his_client", "fos_done"};#endif /* DEBUG */struct find_oppo_bundle { enum find_oppo_step step; err_t want; bool failure_ok; /* if true, continue_oppo should not die on DNS failure */ ip_address our_client; /* not pointer! */ ip_address peer_client; int transport_proto; bool held; policy_prio_t policy_prio; ipsec_spi_t failure_shunt; /* in host order! 0 for delete. */ int whackfd;};struct find_oppo_continuation { struct adns_continuation ac; /* common prefix */ struct find_oppo_bundle b;};static voidcannot_oppo(struct connection *c , struct find_oppo_bundle *b , err_t ugh){ char pcb[ADDRTOT_BUF]; char ocb[ADDRTOT_BUF]; addrtot(&b->peer_client, 0, pcb, sizeof(pcb)); addrtot(&b->our_client, 0, ocb, sizeof(ocb)); openswan_log("Can not opportunistically initiate for %s to %s: %s" , ocb, pcb, ugh); whack_log(RC_OPPOFAILURE , "Can not opportunistically initiate for %s to %s: %s" , ocb, pcb, ugh); if (c != NULL && c->policy_next != NULL) { /* there is some policy that comes afterwards */ struct spd_route *shunt_spd; struct connection *nc = c->policy_next; struct state *st; passert(c->kind == CK_TEMPLATE); passert(c->policy_next->kind == CK_PERMANENT); DBG(DBG_OPPO, DBG_log("OE failed for %s to %s, but %s overrides shunt" , ocb, pcb, c->policy_next->name)); /* * okay, here we need add to the "next" policy, which is ought * to be an instance. * We will add another entry to the spd_route list for the specific * situation that we have. */ shunt_spd = clone_thing(nc->spd, "shunt eroute policy"); shunt_spd->next = nc->spd.next; nc->spd.next = shunt_spd; happy(addrtosubnet(&b->peer_client, &shunt_spd->that.client)); if (sameaddr(&b->peer_client, &shunt_spd->that.host_addr)) shunt_spd->that.has_client = FALSE; /* * override the tunnel destination with the one from the secondaried * policy */ shunt_spd->that.host_addr = nc->spd.that.host_addr; /* now, lookup the state, and poke it up. */ st = state_with_serialno(nc->newest_ipsec_sa); /* XXX what to do if the IPSEC SA has died? */ passert(st != NULL); /* link the new connection instance to the state's list of * connections */ DBG(DBG_OPPO, DBG_log("installing state: %ld for %s to %s" , nc->newest_ipsec_sa , ocb, pcb));#ifdef DEBUG if (DBGP(DBG_OPPO | DBG_CONTROLMORE)) { char state_buf[LOG_WIDTH]; char state_buf2[LOG_WIDTH]; time_t n = now(); fmt_state(st, n, state_buf, sizeof(state_buf) , state_buf2, sizeof(state_buf2)); DBG_log("cannot_oppo, failure SA1: %s", state_buf); DBG_log("cannot_oppo, failure SA2: %s", state_buf2); }#endif /* DEBUG */ if (!route_and_eroute(c, shunt_spd, st)) { whack_log(RC_OPPOFAILURE , "failed to instantiate shunt policy %s for %s to %s" , c->name , ocb, pcb); } return; }#ifdef KLIPS if (b->held) { /* Replace HOLD with b->failure_shunt. * If no b->failure_shunt specified, use SPI_PASS -- THIS MAY CHANGE. */ if (b->failure_shunt == 0) { DBG(DBG_OPPO, DBG_log("no explicit failure shunt for %s to %s; installing %%pass" , ocb, pcb)); } (void) replace_bare_shunt(&b->our_client, &b->peer_client , b->policy_prio , b->failure_shunt , b->failure_shunt != 0 , b->transport_proto , ugh); }#endif}static void initiate_opportunistic_body(struct find_oppo_bundle *b , struct adns_continuation *ac, err_t ac_ugh); /* forward */voidinitiate_opportunistic(const ip_address *our_client, const ip_address *peer_client, int transport_proto UNUSED, bool held, int whackfd, err_t why){ struct find_oppo_bundle b; b.want = why; /* fudge */ b.failure_ok = FALSE; b.our_client = *our_client; b.peer_client = *peer_client; b.transport_proto = 0; b.held = held; b.policy_prio = BOTTOM_PRIO; b.failure_shunt = 0; b.whackfd = whackfd; b.step = fos_start; initiate_opportunistic_body(&b, NULL, NULL);}static voidcontinue_oppo(struct adns_continuation *acr, err_t ugh){ struct find_oppo_continuation *cr = (void *)acr; /* inherit, damn you! */ struct connection *c; bool was_held = cr->b.held; int whackfd = cr->b.whackfd; /* note: cr->id has no resources; cr->sgw_id is id_none: * neither need freeing. */ whack_log_fd = whackfd;#ifdef KLIPS /* Discover and record whether %hold has gone away. * This could have happened while we were awaiting DNS. * We must check BEFORE any call to cannot_oppo. */ if (was_held) cr->b.held = has_bare_hold(&cr->b.our_client, &cr->b.peer_client , cr->b.transport_proto);#endif#ifdef DEBUG /* if we're going to ignore the error, at least note it in debugging log */ if (cr->b.failure_ok && ugh != NULL) { DBG(DBG_CONTROL | DBG_DNS, { char ocb[ADDRTOT_BUF]; char pcb[ADDRTOT_BUF]; addrtot(&cr->b.our_client, 0, ocb, sizeof(ocb)); addrtot(&cr->b.peer_client, 0, pcb, sizeof(pcb)); DBG_log("continuing from failed DNS lookup for %s, %s to %s: %s" , cr->b.want, ocb, pcb, ugh); }); }#endif if (!cr->b.failure_ok && ugh != NULL) { c = find_connection_for_clients(NULL, &cr->b.our_client, &cr->b.peer_client , cr->b.transport_proto); cannot_oppo(c, &cr->b , builddiag("%s: %s", cr->b.want, ugh)); } else if (was_held && !cr->b.held) { /* was_held indicates we were started due to a %trap firing * (as opposed to a "whack --oppohere --oppothere"). * Since the %hold has gone, we can assume that somebody else * has beaten us to the punch. We can go home. But lets log it. */ char ocb[ADDRTOT_BUF]; char pcb[ADDRTOT_BUF]; addrtot(&cr->b.our_client, 0, ocb, sizeof(ocb)); addrtot(&cr->b.peer_client, 0, pcb, sizeof(pcb)); loglog(RC_COMMENT , "%%hold otherwise handled during DNS lookup for Opportunistic Initiation for %s to %s" , ocb, pcb); } else { initiate_opportunistic_body(&cr->b, &cr->ac, ugh); whackfd = NULL_FD; /* was handed off */ } whack_log_fd = NULL_FD; close_any(whackfd);}#ifdef USE_KEYRRstatic err_tcheck_key_recs(enum myid_state try_state, const struct connection *c, struct adns_continuation *ac){ /* Check if KEY lookup yielded good results. * Looking up based on our ID. Used if * client is ourself, or if TXT had no public key. * Note: if c is different this time, there is * a chance that we did the wrong query. * If so, treat as a kind of failure. */ enum myid_state old_myid_state = myid_state; const struct RSA_private_key *our_RSA_pri; err_t ugh = NULL; myid_state = try_state; if (old_myid_state != myid_state && old_myid_state == MYID_SPECIFIED) { ugh = "%myid was specified while we were guessing"; } else if ((our_RSA_pri = get_RSA_private_key(c)) == NULL) { ugh = "we don't know our own RSA key"; } else if (!same_id(&ac->id, &c->spd.this.id)) { ugh = "our ID changed
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -