📄 connections.c
字号:
#endif /* add to connections list */ t->ac_next = connections; connections = t; /* same host_pair as parent: stick after parent on list */ group->hp_next = t; /* route if group is routed */ if (group->policy & POLICY_GROUTED) { if (!trap_connection(t)) whack_log(RC_ROUTE, "could not route"); } } return name;}/* an old target has disappeared for a group: delete instance */voidremove_group_instance(const struct connection *group USED_BY_DEBUG, const char *name){ passert(group->kind == CK_GROUP); passert(oriented(*group)); delete_connections_by_name(name, FALSE);}/* Common part of instantiating a Road Warrior or Opportunistic connection. * his_id can be used to carry over an ID discovered in Phase 1. * It must not disagree with the one in c, but if that is unspecified, * the new connection will use his_id. * If his_id is NULL, and c.that.id is uninstantiated (ID_NONE), the * new connection will continue to have an uninstantiated that.id. * Note: instantiation does not affect port numbers. * * Note that instantiate can only deal with a single SPD/eroute. */static struct connection *instantiate(struct connection *c, const ip_address *him , const struct id *his_id){ struct connection *d; int wildcards; passert(c->kind == CK_TEMPLATE); passert(c->spd.next == NULL); c->instance_serial++; d = clone_thing(*c, "temporary connection"); if (his_id != NULL) { passert(match_id(his_id, &d->spd.that.id, &wildcards)); d->spd.that.id = *his_id; d->spd.that.has_id_wildcards = FALSE; } unshare_connection_strings(d); unshare_ietfAttrList(&d->spd.this.groups); unshare_ietfAttrList(&d->spd.that.groups);#ifdef KERNEL_ALG alg_info_addref((struct alg_info *)d->alg_info_esp);#endif#ifdef IKE_ALG alg_info_addref((struct alg_info *)d->alg_info_ike);#endif d->kind = CK_INSTANCE; passert(oriented(*d)); d->spd.that.host_addr = *him; setportof(htons(c->spd.that.port), &d->spd.that.host_addr); default_end(&d->spd.that, &d->spd.this.host_addr); /* We cannot guess what our next_hop should be, but if it was * explicitly specified as 0.0.0.0, we set it to be him. * (whack will not allow nexthop to be elided in RW case.) */ default_end(&d->spd.this, &d->spd.that.host_addr); d->spd.next = NULL; d->spd.reqid = gen_reqid(); /* set internal fields */ d->ac_next = connections; connections = d; d->spd.routing = RT_UNROUTED; d->newest_isakmp_sa = SOS_NOBODY; d->newest_ipsec_sa = SOS_NOBODY; d->spd.eroute_owner = SOS_NOBODY; /* reset log file info */ d->log_file_name = NULL; d->log_file = NULL; d->log_file_err = FALSE; connect_to_host_pair(d); return d;}struct connection *rw_instantiate(struct connection *c, const ip_address *him, const ip_subnet *his_net, const struct id *his_id){ struct connection *d = instantiate(c, him, his_id);#ifdef VIRTUAL_IP if (d && his_net && is_virtual_connection(c)) { d->spd.that.client = *his_net; d->spd.that.virt = NULL; if (subnetishost(his_net) && addrinsubnet(him, his_net)) d->spd.that.has_client = FALSE; }#endif if (d->policy & POLICY_OPPO) { /* This must be before we know the client addresses. * Fill in one that is impossible. This prevents anyone else from * trying to use this connection to get to a particular client */ d->spd.that.client = *aftoinfo(subnettypeof(&d->spd.that.client))->none; } DBG(DBG_CONTROL , DBG_log("instantiated \"%s\" for %s" , d->name, ip_str(him))); return d;}struct connection *oppo_instantiate(struct connection *c , const ip_address *him , const struct id *his_id , struct gw_info *gw , const ip_address *our_client USED_BY_DEBUG , const ip_address *peer_client){ struct connection *d = instantiate(c, him, his_id); DBG(DBG_CONTROL, DBG_log("oppo instantiate d=%s from c=%s with c->routing %s, d->routing %s" , d->name, c->name , enum_name(&routing_story, c->spd.routing) , enum_name(&routing_story, d->spd.routing))); passert(d->spd.next == NULL); /* fill in our client side */ if (d->spd.this.has_client) { /* there was a client in the abstract connection * so we demand that the required client is within that subnet. */ passert(addrinsubnet(our_client, &d->spd.this.client)); happy(addrtosubnet(our_client, &d->spd.this.client)); /* opportunistic connections do not use port selectors */ setportof(0, &d->spd.this.client.addr); } else { /* there was no client in the abstract connection * so we demand that the required client be the host */ passert(sameaddr(our_client, &d->spd.this.host_addr)); } /* * fill in peer's client side. * If the client is the peer, excise the client from the connection. */ passert((d->policy & POLICY_OPPO) && addrinsubnet(peer_client, &d->spd.that.client)); happy(addrtosubnet(peer_client, &d->spd.that.client)); /* opportunistic connections do not use port selectors */ setportof(0, &d->spd.that.client.addr); if (sameaddr(peer_client, &d->spd.that.host_addr)) d->spd.that.has_client = FALSE; passert(d->gw_info == NULL); gw_addref(gw); d->gw_info = gw; /* Adjust routing if something is eclipsing c. * It must be a %hold for us (hard to passert this). * If there was another instance eclipsing, we'd be using it. */ if (c->spd.routing == RT_ROUTED_ECLIPSED) d->spd.routing = RT_ROUTED_PROSPECTIVE; /* Remember if the template is routed: * if so, this instance applies for initiation * even if it is created for responding. */ if (routed(c->spd.routing)) d->instance_initiation_ok = TRUE; DBG(DBG_CONTROL, char topo[CONNECTION_BUF]; (void) format_connection(topo, sizeof(topo), d, &d->spd); DBG_log("instantiated \"%s\": %s", d->name, topo); ); return d;}/* priority formatting */voidfmt_policy_prio(policy_prio_t pp, char buf[POLICY_PRIO_BUF]){ if (pp == BOTTOM_PRIO) snprintf(buf, POLICY_PRIO_BUF, "0"); else snprintf(buf, POLICY_PRIO_BUF, "%lu,%lu" , pp>>16, (pp & ~(~(policy_prio_t)0 << 16)) >> 8);}/* Format any information needed to identify an instance of a connection. * Fills any needed information into buf which MUST be big enough. * Road Warrior: peer's IP address * Opportunistic: [" " myclient "==="] " ..." peer ["===" hisclient] '\0' */static size_tfmt_client(const ip_subnet *client, const ip_address *gw, const char *prefix, char buf[ADDRTOT_BUF]){ if (subnetisaddr(client, gw)) { buf[0] = '\0'; /* compact denotation for "self" */ } else { char *ap; strcpy(buf, prefix); ap = buf + strlen(prefix); if (subnetisnone(client)) strcpy(ap, "?"); /* unknown */ else subnettot(client, 0, ap, SUBNETTOT_BUF); } return strlen(buf);}voidfmt_conn_instance(const struct connection *c, char buf[CONN_INST_BUF]){ char *p = buf; *p = '\0'; if (c->kind == CK_INSTANCE) { if (c->instance_serial != 0) { snprintf(p, CONN_INST_BUF, "[%lu]", c->instance_serial); p += strlen(p); } if (c->policy & POLICY_OPPO) { size_t w = fmt_client(&c->spd.this.client, &c->spd.this.host_addr, " ", p); p += w; strcpy(p, w == 0? " ..." : "=== ..."); p += strlen(p); addrtot(&c->spd.that.host_addr, 0, p, ADDRTOT_BUF); p += strlen(p); (void) fmt_client(&c->spd.that.client, &c->spd.that.host_addr, "===", p); } else { *p++ = ' '; addrtot(&c->spd.that.host_addr, 0, p, ADDRTOT_BUF); } }}/* Find an existing connection for a trapped outbound packet. * This is attempted before we bother with gateway discovery. * + this connection is routed or instance_of_routed_template * (i.e. approved for on-demand) * + this subnet contains our_client (or we are our_client) * + that subnet contains peer_client (or peer is peer_client) * + don't care about Phase 1 IDs (we don't know) * Note: result may still need to be instantiated. * The winner has the highest policy priority. * * If there are several with that priority, we give preference to * the first one that is an instance. * * See also build_outgoing_opportunistic_connection. */struct connection *find_connection_for_clients(struct spd_route **srp, const ip_address *our_client, const ip_address *peer_client, int transport_proto){ struct connection *c = connections, *best = NULL; policy_prio_t best_prio = BOTTOM_PRIO; struct spd_route *sr; struct spd_route *best_sr; int our_port = ntohs(portof(our_client)); int peer_port = ntohs(portof(peer_client)); best_sr = NULL; passert(!isanyaddr(our_client) && !isanyaddr(peer_client));#ifdef DEBUG if (DBGP(DBG_CONTROL)) { char ocb[ADDRTOT_BUF], pcb[ADDRTOT_BUF]; addrtot(our_client, 0, ocb, sizeof(ocb)); addrtot(peer_client, 0, pcb, sizeof(pcb)); DBG_log("find_connection: " "looking for policy for connection: %s:%d/%d -> %s:%d/%d" , ocb, transport_proto, our_port, pcb, transport_proto, peer_port); }#endif /* DEBUG */ for (c = connections; c != NULL; c = c->ac_next) { if (c->kind == CK_GROUP) continue; for (sr = &c->spd; best!=c && sr; sr = sr->next) { if ((routed(sr->routing) || c->instance_initiation_ok) && addrinsubnet(our_client, &sr->this.client) && addrinsubnet(peer_client, &sr->that.client) && (!sr->this.protocol || transport_proto == sr->this.protocol) && (!sr->this.port || our_port == sr->this.port) && (!sr->that.port || peer_port == sr->that.port)) { char cib[CONN_INST_BUF]; char cib2[CONN_INST_BUF]; policy_prio_t prio = 8 * (c->prio + (c->kind == CK_INSTANCE)) + 2 * (sr->this.port == our_port) + 2 * (sr->that.port == peer_port) + (sr->this.protocol == transport_proto);#ifdef DEBUG if (DBGP(DBG_CONTROL|DBG_CONTROLMORE)) { char c_ocb[SUBNETTOT_BUF], c_pcb[SUBNETTOT_BUF]; subnettot(&c->spd.this.client, 0, c_ocb, sizeof(c_ocb)); subnettot(&c->spd.that.client, 0, c_pcb, sizeof(c_pcb)); DBG_log("find_connection: " "conn \"%s\"%s has compatible peers: %s -> %s [pri: %ld]" , c->name , (fmt_conn_instance(c, cib), cib) , c_ocb, c_pcb, prio); }#endif /* DEBUG */ if (best == NULL) { best = c; best_sr = sr; best_prio = prio; } DBG(DBG_CONTROLMORE, DBG_log("find_connection: comparing best \"%s\"%s [pri:%ld]{%p} (child %s) to \"%s\"%s [pri:%ld]{%p} (child %s)" , best->name , (fmt_conn_instance(best, cib), cib) , best_prio , best , (best->policy_next ? best->policy_next->name : "none") , c->name , (fmt_conn_instance(c, cib2), cib2) , prio , c , (c->policy_next ? c->policy_next->name : "none"))); if (prio > best_prio) { best = c; best_sr = sr; best_prio = prio; } } } } if (best!= NULL && NEVER_NEGOTIATE(best->policy)) best = NULL; if (srp != NULL && best != NULL) *srp = best_sr;#ifdef DEBUG if (DBGP(DBG_CONTROL)) { if (best) { char cib[CONN_INST_BUF]; DBG_log("find_connection: concluding with \"%s\"%s [pri:%ld]{%p} kind=%s" , best->name , (fmt_conn_instance(best, cib), cib) , best_prio , best , enum_name(&connection_kind_names, best->kind)); } else { DBG_log("find_connection: concluding with empty"); } }#endif /* DEBUG */ return best;}/* Find and instantiate a connection for an outgoing Opportunistic connection. * We've already discovered its gateway. * We look for a the connection such that: * + this is one of our interfaces * + this subnet contains our_client (or we are our_client) * (we will specialize the client). We prefer the smallest such subnet. * + that subnet contains peer_clent (we will specialize the client). * We prefer the smallest such subnet. * + is opportunistic * + that peer is NO_IP * + don't care about Phase 1 IDs (probably should be default) * We could look for a connection that already had the desired peer * (rather than NO_IP) specified, but it doesn't seem worth the * bother. * * We look for the routed policy applying to the narrowest subnets. * We only succeed if we find such a policy AND it is satisfactory. * * The body of the inner loop is a lot like that in * find_connection_for_clients. In this case, we know the gateways * that we need to instantiate an opportunistic connection. */struct connection *build_outgoing_opportunistic_connection(struct gw_info *gw ,const ip_address *our_client ,const ip_address *peer_client){ struct iface_port *p; struct connection *best = NULL; struct spd_route *sr, *bestsr; char ocb[ADDRTOT_BUF], pcb[ADDRTOT_BUF]; addrtot(our_client, 0, ocb, sizeof(ocb)); addrtot(peer_client, 0, pcb, sizeof(pcb)); passert(!isanyaddr(our_client) && !isanyaddr(peer_client)); /* We don't know his ID yet, so gw id must be an ipaddr */ passert(gw->key != NULL); passert(id_is_ipaddr(&gw->gw_id)); /* for each of our addresses... */ for (p = interfaces; p != NULL; p = p->next) { /* go through those connections with our address and NO_IP as hosts * We cannot know what port the peer would use, so we assume * that it is pluto_port (makes debugging easier). */ struct connection *c = find_host_pair_connections(__FUNCTION__, &p->ip_addr , pluto_port , (ip_address *)NULL , pluto_port); for (; c != NULL; c = c->hp_next) { DBG(DBG_OPPO, DBG_log("checking %s", c->name)); if (c->kind == CK_GROUP) { continue; } for (sr = &c->spd; best!=c && sr; sr = sr->next) { if (routed(sr->routing) && addrinsubnet(our_client, &sr->this.client) && addrinsubnet(peer_client, &sr->that.client)) { if (best == NULL) { best = c; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -