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 + -
显示快捷键?