kernel.c
来自「ipsec vpn」· C语言 代码 · 共 2,050 行 · 第 1/5 页
C
2,050 行
{ struct spd_route *esr, *rosr; struct connection *ero /* who, if anyone, owns our eroute? */ , *ro = route_owner(c, &rosr, &ero, &esr); /* who owns our route? */ DBG(DBG_CONTROL, DBG_log("could_route called for %s (kind=%s)" , c->name , enum_show(&connection_kind_names, c->kind))); /* it makes no sense to route a connection that is ISAKMP-only */ if (!NEVER_NEGOTIATE(c->policy) && !HAS_IPSEC_POLICY(c->policy)) { loglog(RC_ROUTE, "cannot route an ISAKMP-only connection"); return route_impossible; } /* if this is a Road Warrior template, we cannot route. * Opportunistic template is OK. */ if (!c->spd.that.has_client && c->kind == CK_TEMPLATE && !(c->policy & POLICY_OPPO)) { loglog(RC_ROUTE, "cannot route template policy of %s", prettypolicy(c->policy)); return route_impossible; } /* if we don't know nexthop, we cannot route */ if (isanyaddr(&c->spd.this.host_nexthop)) { loglog(RC_ROUTE, "cannot route connection without knowing our nexthop"); return route_impossible; } /* if routing would affect IKE messages, reject */ if (kern_interface != NO_KERNEL#ifdef NAT_TRAVERSAL && c->spd.this.host_port != NAT_T_IKE_FLOAT_PORT#endif && c->spd.this.host_port != IKE_UDP_PORT && addrinsubnet(&c->spd.that.host_addr, &c->spd.that.client)) { loglog(RC_LOG_SERIOUS, "cannot install route: peer is within its client"); return route_impossible; } /* If there is already a route for peer's client subnet * and it disagrees about interface or nexthop, we cannot steal it. * Note: if this connection is already routed (perhaps for another * state object), the route will agree. * This is as it should be -- it will arise during rekeying. */ if (ro != NULL && !routes_agree(ro, c)) { loglog(RC_LOG_SERIOUS, "cannot route -- route already in use for \"%s\"" , ro->name); return route_impossible; /* another connection already using the eroute */ }#ifdef KLIPS /* if there is an eroute for another connection, there is a problem */ if (ero != NULL && ero != c) { struct connection *ero2, *ero_top; struct connection *inside, *outside; /* * note, wavesec (PERMANENT) goes *outside* and * OE goes *inside* (TEMPLATE) */ inside = NULL; outside= NULL; if (ero->kind == CK_PERMANENT && c->kind == CK_TEMPLATE) { outside = ero; inside = c; } else if (c->kind == CK_PERMANENT && ero->kind == CK_TEMPLATE) { outside = c; inside = ero; } /* okay, check again, with correct order */ if (outside && outside->kind == CK_PERMANENT && inside && inside->kind == CK_TEMPLATE) { char inst[CONN_INST_BUF]; /* this is a co-terminal attempt of the "near" kind. */ /* when chaining, we chain from inside to outside */ /* XXX permit multiple deep connections? */ passert(inside->policy_next == NULL); inside->policy_next = outside; /* since we are going to steal the eroute from the secondary * policy, we need to make sure that it no longer thinks that * it owns the eroute. */ outside->spd.eroute_owner = SOS_NOBODY; outside->spd.routing = RT_UNROUTED_KEYED; /* set the priority of the new eroute owner to be higher * than that of the current eroute owner */ inside->prio = outside->prio + 1; fmt_conn_instance(inside, inst); loglog(RC_LOG_SERIOUS , "conflict on eroute (%s), switching eroute to %s and linking %s" , inst, inside->name, outside->name); return route_nearconflict; } /* look along the chain of policies for one with the same name */ ero_top = ero; for (ero2 = ero; ero2 != NULL; ero2 = ero->policy_next) { if (ero2->kind == CK_TEMPLATE && streq(ero2->name, c->name)) break; } /* If we fell of the end of the list, then we found no TEMPLATE * so there must be a conflict that we can't resolve. * As the names are not equal, then we aren't replacing/rekeying. */ if (ero2 == NULL) { char inst[CONN_INST_BUF]; fmt_conn_instance(ero, inst); loglog(RC_LOG_SERIOUS , "cannot install eroute -- it is in use for \"%s\"%s #%lu" , ero->name, inst, esr->eroute_owner); return FALSE; /* another connection already using the eroute */ } }#endif /* KLIPS */ return route_easy;}booltrap_connection(struct connection *c){ switch (could_route(c)) { case route_impossible: return FALSE; case route_nearconflict: case route_easy: /* RT_ROUTED_TUNNEL is treated specially: we don't override * because we don't want to lose track of the IPSEC_SAs etc. */ if (c->spd.routing < RT_ROUTED_TUNNEL) { return route_and_eroute(c, &c->spd, NULL); } return TRUE; case route_farconflict: return FALSE; } return FALSE;}/* delete any eroute for a connection and unroute it if route isn't shared */voidunroute_connection(struct connection *c){ struct spd_route *sr; enum routing_t cr; for (sr = &c->spd; sr; sr = sr->next) { cr = sr->routing; if (erouted(cr)) { /* cannot handle a live one */ passert(sr->routing != RT_ROUTED_TUNNEL);#ifdef KLIPS shunt_eroute(c, sr, RT_UNROUTED, ERO_DELETE, "delete");#endif } sr->routing = RT_UNROUTED; /* do now so route_owner won't find us */ /* only unroute if no other connection shares it */ if (routed(cr) && route_owner(c, NULL, NULL, NULL) == NULL) (void) do_command(c, sr, "unroute", NULL); }}#include "alg_info.h"#include "kernel_alg.h"#ifdef KLIPSstatic voidset_text_said(char *text_said, const ip_address *dst, ipsec_spi_t spi, int proto){ ip_said said; initsaid(dst, spi, proto, &said); satot(&said, 0, text_said, SATOT_BUF);}/* find an entry in the bare_shunt table. * Trick: return a pointer to the pointer to the entry; * this allows the entry to be deleted. */static struct bare_shunt **bare_shunt_ptr(const ip_subnet *ours, const ip_subnet *his, int transport_proto){ struct bare_shunt *p, **pp; for (pp = &bare_shunts; (p = *pp) != NULL; pp = &p->next) { if (samesubnet(ours, &p->ours) && samesubnet(his, &p->his) && transport_proto == p->transport_proto && portof(&ours->addr) == portof(&p->ours.addr) && portof(&his->addr) == portof(&p->his.addr)) return pp; } return NULL;}/* free a bare_shunt entry, given a pointer to the pointer */static voidfree_bare_shunt(struct bare_shunt **pp){ if (pp == NULL) { DBG(DBG_CONTROL, DBG_log("delete bare shunt: null pointer") ) } else { struct bare_shunt *p = *pp; *pp = p->next; DBG_bare_shunt("delete", p); pfree(p->why); pfree(p); }}voidshow_shunt_status(void){ struct bare_shunt *bs; for (bs = bare_shunts; bs != NULL; bs = bs->next) { /* Print interesting fields. Ignore count and last_active. */ int ourport = ntohs(portof(&bs->ours.addr)); int hisport = ntohs(portof(&bs->his.addr)); char ourst[SUBNETTOT_BUF]; char hist[SUBNETTOT_BUF]; char sat[SATOT_BUF]; char prio[POLICY_PRIO_BUF]; subnettot(&(bs)->ours, 0, ourst, sizeof(ourst)); subnettot(&(bs)->his, 0, hist, sizeof(hist)); satot(&(bs)->said, 0, sat, sizeof(sat)); fmt_policy_prio(bs->policy_prio, prio); whack_log(RC_COMMENT, "%s:%d -%d-> %s:%d => %s %s %s" , ourst, ourport, bs->transport_proto, hist, hisport, sat , prio, bs->why); }}/* Setup an IPsec route entry. * op is one of the ERO_* operators. */static boolraw_eroute(const ip_address *this_host , const ip_subnet *this_client , const ip_address *that_host , const ip_subnet *that_client , ipsec_spi_t spi , unsigned int proto , unsigned int transport_proto , unsigned int satype , const struct pfkey_proto_info *proto_info , time_t use_lifetime , unsigned int op , const char *opname USED_BY_DEBUG){ char text_said[SATOT_BUF]; int sport = ntohs(portof(&this_client->addr)); int dport = ntohs(portof(&that_client->addr)); set_text_said(text_said, that_host, spi, proto); DBG(DBG_CONTROL | DBG_KLIPS, { char mybuf[SUBNETTOT_BUF]; char peerbuf[SUBNETTOT_BUF]; subnettot(this_client, 0, mybuf, sizeof(mybuf)); subnettot(that_client, 0, peerbuf, sizeof(peerbuf)); DBG_log("%s eroute %s:%d --%d-> %s:%d => %s (raw_eroute)" , opname, mybuf, sport, transport_proto, peerbuf, dport , text_said); }); return kernel_ops->raw_eroute(this_host, this_client , that_host, that_client , spi, proto , transport_proto , satype, proto_info , use_lifetime, op, text_said);}/* test to see if %hold remains */boolhas_bare_hold(const ip_address *src, const ip_address *dst, int transport_proto){ ip_subnet this_client, that_client; struct bare_shunt **bspp; passert(addrtypeof(src) == addrtypeof(dst)); happy(addrtosubnet(src, &this_client)); happy(addrtosubnet(dst, &that_client)); bspp = bare_shunt_ptr(&this_client, &that_client, transport_proto); return bspp != NULL && (*bspp)->said.proto == SA_INT && (*bspp)->said.spi == htonl(SPI_HOLD);}/* Replace (or delete) a shunt that is in the bare_shunts table. * Issues the PF_KEY commands and updates the bare_shunts table. */boolreplace_bare_shunt(const ip_address *src, const ip_address *dst , policy_prio_t policy_prio , ipsec_spi_t shunt_spi /* in host order! */ , bool repl /* if TRUE, replace; if FALSE, delete */ , int transport_proto , const char *why){ ip_subnet this_client, that_client; const ip_address *null_host = aftoinfo(addrtypeof(src))->any; passert(addrtypeof(src) == addrtypeof(dst)); happy(addrtosubnet(src, &this_client)); happy(addrtosubnet(dst, &that_client)); /* * if the transport protocol is not the wildcard, then we need * to look for a host<->host shunt, and replace that with the * shunt spi, and then we add a %HOLD for what was there before. * * this is at ods with repl == 0, which should delete things. * */ if(transport_proto != 0) { ip_subnet this_broad_client, that_broad_client; this_broad_client = this_client; that_broad_client = that_client; setportof(0, &this_broad_client.addr); setportof(0, &that_broad_client.addr); if (repl) { struct bare_shunt **bs_pp = bare_shunt_ptr(&this_broad_client , &that_broad_client, 0); /* is there already a broad host-to-host bare shunt? */ if (bs_pp == NULL) { if (raw_eroute(null_host, &this_broad_client , null_host, &that_broad_client , htonl(shunt_spi), SA_INT , transport_proto , SADB_X_SATYPE_INT, narrow_proto_info , SHUNT_PATIENCE, ERO_REPLACE, why)) { struct bare_shunt *bs = alloc_thing(struct bare_shunt, "bare shunt"); bs->ours = this_broad_client; bs->his = that_broad_client; bs->transport_proto = 0; bs->said.proto = SA_INT; bs->why = clone_str(why, "bare shunt story"); bs->policy_prio = policy_prio; bs->said.spi = htonl(shunt_spi);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?