kernel.c

来自「ipsec vpn」· C语言 代码 · 共 2,050 行 · 第 1/5 页

C
2,050
字号
                                bs->said.dst = *null_host;                                bs->count = 0;                                bs->last_activity = now();                                bs->next = bare_shunts;                                bare_shunts = bs;                                DBG_bare_shunt("add", bs);                            }                    }                shunt_spi = SPI_HOLD;            }                if (raw_eroute(null_host, &this_client, null_host, &that_client                       , htonl(shunt_spi)                       , SA_INT                       , transport_proto                       , SADB_X_SATYPE_INT, narrow_proto_info                       , SHUNT_PATIENCE, ERO_ADD, why))            {                struct bare_shunt **bs_pp = bare_shunt_ptr(&this_client, &that_client                                                           , transport_proto);                                /* delete bare eroute */                free_bare_shunt(bs_pp);                                return TRUE;            }        else            {                return FALSE;            }    }    else {        unsigned int op = repl? ERO_REPLACE : ERO_DELETE;                if (raw_eroute(null_host, &this_client, null_host, &that_client                       , htonl(shunt_spi), SA_INT                       , 0 /* transport_proto */                       , SADB_X_SATYPE_INT, narrow_proto_info                       , SHUNT_PATIENCE, op, why))            {                struct bare_shunt **bs_pp = bare_shunt_ptr(&this_client                                                           , &that_client, 0);                                if (repl)                    {                        /* change over to new bare eroute */                        struct bare_shunt *bs = *bs_pp;                                                pfree(bs->why);                        bs->why = clone_str(why, "bare shunt story");                        bs->policy_prio = policy_prio;                        bs->said.spi = htonl(shunt_spi);                        bs->said.proto = SA_INT;                        bs->said.dst = *null_host;                        bs->count = 0;                        bs->last_activity = now();                        DBG_bare_shunt("change", bs);                    }                else                    {                        /* delete bare eroute */                        free_bare_shunt(bs_pp);                    }                return TRUE;            }        else            {                return FALSE;            }    }        }static booleroute_connection(struct spd_route *sr, ipsec_spi_t spi, unsigned int proto, unsigned int satype, const struct pfkey_proto_info *proto_info, unsigned int op, const char *opname){    const ip_address *peer = &sr->that.host_addr;    char buf2[256];    snprintf(buf2, sizeof(buf2)             , "eroute_connection %s", opname);    if (proto == SA_INT)        peer = aftoinfo(addrtypeof(peer))->any;    return raw_eroute(&sr->this.host_addr, &sr->this.client                      , peer                      , &sr->that.client                      , spi                      , proto                      , sr->this.protocol                      , satype                      , proto_info, 0, op, buf2);}/* assign a bare hold to a connection */boolassign_hold(struct connection *c USED_BY_DEBUG            , struct spd_route *sr            , int transport_proto            , const ip_address *src, const ip_address *dst){    /* either the automatically installed %hold eroute is broad enough     * or we try to add a broader one and delete the automatic one.     * Beware: this %hold might be already handled, but still squeak     * through because of a race.     */    enum routing_t ro = sr->routing     /* routing, old */        , rn = ro;                      /* routing, new */    passert(LHAS(LELEM(CK_PERMANENT) | LELEM(CK_INSTANCE), c->kind));    /* figure out what routing should become */    switch (ro)    {    case RT_UNROUTED:        rn = RT_UNROUTED_HOLD;        break;    case RT_ROUTED_PROSPECTIVE:        rn = RT_ROUTED_HOLD;        break;    default:        /* no change: this %hold is old news and should just be deleted */        break;    }    DBG(DBG_CONTROL,        DBG_log("assign hold, routing was %s, needs to be %s"                , enum_name(&routing_story, ro)                , enum_name(&routing_story, rn)));    if (eclipsable(sr))    {        /* although %hold is appropriately broad, it will no longer be bare         * so we must ditch it from the bare table.         */        free_bare_shunt(bare_shunt_ptr(&sr->this.client, &sr->that.client, sr->this.protocol));    }    else    {        /* we need a broad %hold, not the narrow one.         * First we ensure that there is a broad %hold.         * There may already be one (race condition): no need to create one.         * There may already be a %trap: replace it.         * There may not be any broad eroute: add %hold.         * Once the broad %hold is in place, delete the narrow one.         */        if (rn != ro)        {            if (erouted(ro)            ? !eroute_connection(sr, htonl(SPI_HOLD), SA_INT, SADB_X_SATYPE_INT                                 , broad_proto_info                                 , ERO_REPLACE                                 , "replace %trap with broad %hold")            : !eroute_connection(sr, htonl(SPI_HOLD), SA_INT, SADB_X_SATYPE_INT                                 , broad_proto_info                , ERO_ADD, "add broad %hold"))            {                return FALSE;            }        }        if (!replace_bare_shunt(src, dst                                , BOTTOM_PRIO                                , SPI_HOLD                                , FALSE                                , transport_proto                                , "delete narrow %hold"))            return FALSE;    }    sr->routing = rn;    return TRUE;}/* install or remove eroute for SA Group */static boolsag_eroute(struct state *st, struct spd_route *sr           , unsigned op, const char *opname){    unsigned int        inner_proto,        inner_satype;    ipsec_spi_t inner_spi;    struct pfkey_proto_info proto_info[4];    int i;    bool tunnel;    /* figure out the SPI and protocol (in two forms)     * for the innermost transformation.     */    i = sizeof(proto_info) / sizeof(proto_info[0]) - 1;    proto_info[i].proto = 0;    tunnel = FALSE;    inner_proto = 0;    inner_satype= 0;    inner_spi = 0;    if (st->st_ah.present)    {        inner_spi = st->st_ah.attrs.spi;        inner_proto = SA_AH;        inner_satype = SADB_SATYPE_AH;        i--;        proto_info[i].proto = IPPROTO_AH;        proto_info[i].encapsulation = st->st_ah.attrs.encapsulation;        tunnel |= proto_info[i].encapsulation == ENCAPSULATION_MODE_TUNNEL;        proto_info[i].reqid = sr->reqid;    }    if (st->st_esp.present)    {        inner_spi = st->st_esp.attrs.spi;        inner_proto = SA_ESP;        inner_satype = SADB_SATYPE_ESP;        i--;        proto_info[i].proto = IPPROTO_ESP;        proto_info[i].encapsulation = st->st_esp.attrs.encapsulation;        tunnel |= proto_info[i].encapsulation == ENCAPSULATION_MODE_TUNNEL;        proto_info[i].reqid = sr->reqid + 1;    }    if (st->st_ipcomp.present)    {        inner_spi = st->st_ipcomp.attrs.spi;        inner_proto = SA_COMP;        inner_satype = SADB_X_SATYPE_COMP;        i--;        proto_info[i].proto = IPPROTO_COMP;        proto_info[i].encapsulation = st->st_ipcomp.attrs.encapsulation;        tunnel |= proto_info[i].encapsulation == ENCAPSULATION_MODE_TUNNEL;        proto_info[i].reqid = sr->reqid + 2;    }    if (i == sizeof(proto_info) / sizeof(proto_info[0]) - 1)    {        impossible();   /* no transform at all! */    }    if (tunnel)    {        int j;        inner_spi = st->st_tunnel_out_spi;        inner_proto = SA_IPIP;        inner_satype = SADB_X_SATYPE_IPIP;        proto_info[i].encapsulation = ENCAPSULATION_MODE_TUNNEL;        for (j = i + 1; proto_info[j].proto; j++)        {            proto_info[j].encapsulation = ENCAPSULATION_MODE_TRANSPORT;        }    }    return eroute_connection(sr        , inner_spi, inner_proto, inner_satype, proto_info + i        , op, opname);}/* compute a (host-order!) SPI to implement the policy in connection c */ipsec_spi_tshunt_policy_spi(struct connection *c, bool prospective){    /* note: these are in host order :-( */    static const ipsec_spi_t shunt_spi[] =    {        SPI_TRAP,       /* --initiateontraffic */        SPI_PASS,       /* --pass */        SPI_DROP,       /* --drop */        SPI_REJECT,     /* --reject */    };    static const ipsec_spi_t fail_spi[] =    {        0,      /* --none*/        SPI_PASS,       /* --failpass */        SPI_DROP,       /* --faildrop */        SPI_REJECT,     /* --failreject */    };    return prospective        ? shunt_spi[(c->policy & POLICY_SHUNT_MASK) >> POLICY_SHUNT_SHIFT]        : fail_spi[(c->policy & POLICY_FAIL_MASK) >> POLICY_FAIL_SHIFT];}/* Add/replace/delete a shunt eroute. * Such an eroute determines the fate of packets without the use * of any SAs.  These are defaults, in effect. * If a negotiation has not been attempted, use %trap. * If negotiation has failed, the choice between %trap/%pass/%drop/%reject * is specified in the policy of connection c. */static boolshunt_eroute(struct connection *c             , struct spd_route *sr             , enum routing_t rt_kind             , unsigned int op, const char *opname){    /* We are constructing a special SAID for the eroute.     * The destination doesn't seem to matter, but the family does.     * The protocol is SA_INT -- mark this as shunt.     * The satype has no meaning, but is required for PF_KEY header!     * The SPI signifies the kind of shunt.     */    ipsec_spi_t spi = shunt_policy_spi(c, rt_kind == RT_ROUTED_PROSPECTIVE);    bool ok;    if (spi == 0)    {        /* we're supposed to end up with no eroute: rejig op and opname */        switch (op)        {        case ERO_REPLACE:            /* replace with nothing == delete */            op = ERO_DELETE;            opname = "delete";            break;        case ERO_ADD:            /* add nothing == do nothing */            return TRUE;        case ERO_DELETE:            /* delete remains delete */            break;        default:            bad_case(op);        }    }    if (sr->routing == RT_ROUTED_ECLIPSED && c->kind == CK_TEMPLATE)    {        /* We think that we have an eroute, but we don't.         * Adjust the request and account for eclipses.         */        passert(eclipsable(sr));        switch (op)        {        case ERO_REPLACE:            /* really an add */            op = ERO_ADD;            opname = "replace eclipsed";            eclipse_count--;            break;        case ERO_DELETE:            /* delete unnecessary: we don't actually have an eroute */            eclipse_count--;            return TRUE;        case ERO_ADD:        default:            bad_case(op);        }    }    else if (eclipse_count > 0 && op == ERO_DELETE && eclipsable(sr))    {        /* maybe we are uneclipsing something */        struct spd_route *esr;        struct connection *ue = eclipsed(c, &esr);        if (ue != NULL)        {            esr->routing = RT_ROUTED_PROSPECTIVE;            return shunt_eroute(ue, esr                                , RT_ROUTED_PROSPECTIVE, ERO_REPLACE, "restoring eclipsed");        }    }    ok = TRUE;    if (kernel_ops->inbound_eroute)    {        ok = raw_eroute(&c->spd.that.host_addr, &c->spd.that.client                        , &c->spd.this.host_addr, &c->spd.this.client                        , htonl(spi)                        , SA_INT                        , 0 /* transport_proto is not relevant */                        , SADB_X_SATYPE_INT, broad_proto_info                        , 0      /* use lifetime */                        , op | (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT)                        , opname);    }    return eroute_connection(sr, htonl(spi), SA_INT, SADB_X_SATYPE_INT        , broad_proto_info, op, opname) && ok;}/* * This is only called when s is a likely SAID with  trailing protocol i.e. * it has the form :- * *   %<keyword>:p *   <ip-proto><spi>@a.b.c.d:p * * The task here is to remove the ":p" part so that the rest can be read * by another routine. */static const char *read_proto(const char * s, size_t * len, int * transport_proto){    const char * p;    const char * ugh;    unsigned long proto;    size_t l;    l = *len;    p = memchr(s, ':', l);    if (p == 0) {        *transport_proto = 0;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?