kernel.c

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

C
2,050
字号
        return 0;    }    ugh = ttoul(p+1, l-((p-s)+1), 10, &proto);    if (ugh != 0)        return ugh;    if (proto > 65535)        return "protocol number is too large, legal range is 0-65535";    *len = p-s;    *transport_proto = proto;    return 0;}/* scan /proc/net/ipsec_eroute every once in a while, looking for: * * - %hold shunts of which Pluto isn't aware.  This situation could *   be caused by lost ACQUIRE messages.  When found, they will *   added to orphan_holds.  This in turn will lead to Opportunistic *   initiation. * * - other kinds of shunts that haven't been used recently.  These will be *   deleted.  They represent OE failures. * * - recording recent uses of tunnel eroutes so that rekeying decisions *   can be made for OE connections. * * Here are some sample lines: * 10         10.3.2.1.0/24    -> 0.0.0.0/0          => %trap * 259        10.3.2.1.115/32  -> 10.19.75.161/32    => tun0x1002@10.19.75.145 * 71         10.44.73.97/32   -> 0.0.0.0/0          => %trap * 4119       10.44.73.97/32   -> 10.114.121.41/32   => %pass * Newer versions of KLIPS start each line with a 32-bit packet count. * If available, the count is used to detect whether a %pass shunt is in use. * * NOTE: execution time is quadratic in the number of eroutes since the * searching for each is sequential.  If this becomes a problem, faster * searches could be implemented (hash or radix tree, for example). */voidscan_proc_shunts(void){    static const char procname[] = "/proc/net/ipsec_eroute";    FILE *f;    time_t nw = now();    int lino;    struct eroute_info *expired = NULL;    event_schedule(EVENT_SHUNT_SCAN, SHUNT_SCAN_INTERVAL, NULL);    DBG(DBG_CONTROL,        DBG_log("scanning for shunt eroutes")    )    /* free any leftover entries: they will be refreshed if still current */    while (orphaned_holds != NULL)    {        struct eroute_info *p = orphaned_holds;        orphaned_holds = p->next;        pfree(orphaned_holds);    }    /* decode the /proc file.  Don't do anything strenuous to it     * (certainly no PF_KEY stuff) to minimize the chance that it     * might change underfoot.     */    f = fopen(procname, "r");    if (f == NULL)        return;    /* for each line... */    for (lino = 1; ; lino++)    {        unsigned char buf[1024];        /* should be big enough */        chunk_t field[10];      /* 10 is loose upper bound */        chunk_t *ff;    /* fixed fields (excluding optional count) */        int fi;        struct eroute_info eri;        char *cp;        err_t context = ""            , ugh = NULL;	ff = NULL;        cp = fgets(buf, sizeof(buf), f);        if (cp == NULL)            break;        /* break out each field         * Note: if there are too many fields, just stop;         * it will be diagnosed a little later.         */        for (fi = 0; fi < (int)elemsof(field); fi++)        {            static const char sep[] = " \t\n";  /* field-separating whitespace */            size_t w;            cp += strspn(cp, sep);      /* find start of field */            w = strcspn(cp, sep);       /* find width of field */            setchunk(field[fi], cp, w);            cp += w;            if (w == 0)                break;        }        /* This odd do-hickey is to share error reporting code.         * A break will get to that common code.  The setting         * of "ugh" and "context" parameterize it.         */        do {            /* Old entries have no packet count; new ones do.             * check if things are as they should be.             */            if (fi == 5)                ff = &field[0]; /* old form, with no count */            else if (fi == 6)                ff = &field[1]; /* new form, with count */            else            {                ugh = "has wrong number of fields";                break;            }            if (ff[1].len != 2            || strncmp(ff[1].ptr, "->", 2) != 0            || ff[3].len != 2            || strncmp(ff[3].ptr, "=>", 2) != 0)            {                ugh = "is missing -> or =>";                break;            }            /* actually digest fields of interest */            /* packet count */            eri.count = 0;            if (ff != field)            {                context = "count field is malformed: ";                ugh = ttoul(field[0].ptr, field[0].len, 10, &eri.count);                if (ugh != NULL)                    break;            }            /* our client */            context = "source subnet field malformed: ";            ugh = ttosubnet(ff[0].ptr, ff[0].len, AF_INET, &eri.ours);            if (ugh != NULL)                break;            /* his client */            context = "destination subnet field malformed: ";            ugh = ttosubnet(ff[2].ptr, ff[2].len, AF_INET, &eri.his);            if (ugh != NULL)                break;            /* SAID */            context = "SA ID field malformed: ";            ugh = read_proto(ff[4].ptr, &ff[4].len, &eri.transport_proto);            if (ugh != NULL)                break;            ugh = ttosa(ff[4].ptr, ff[4].len, &eri.said);        } while (FALSE);        if (ugh != NULL)        {            openswan_log("INTERNAL ERROR: %s line %d %s%s"                , procname, lino, context, ugh);            continue;   /* ignore rest of line */        }        /* Now we have decoded eroute, let's consider it.         * For shunt eroutes:         *         * %hold: if not known, add to orphaned_holds list for initiation         *    because ACQUIRE might have been lost.         *         * %pass, %drop, %reject: determine if idle; if so, blast it away.         *    Can occur bare (if DNS provided insufficient information)         *    or with a connection (failure context).         *    Could even be installed by ipsec manual.         *         * %trap: always welcome.         *         * For other eroutes: find state and record count change         */        if (eri.said.proto == SA_INT)        {            /* shunt eroute */            switch (ntohl(eri.said.spi))            {            case SPI_HOLD:                if (bare_shunt_ptr(&eri.ours, &eri.his, eri.transport_proto) == NULL                && shunt_owner(&eri.ours, &eri.his) == NULL)                {                    int ourport = ntohs(portof(&eri.ours.addr));                    int hisport = ntohs(portof(&eri.his.addr));                    char ourst[SUBNETTOT_BUF];                    char hist[SUBNETTOT_BUF];                    char sat[SATOT_BUF];                    subnettot(&eri.ours, 0, ourst, sizeof(ourst));                    subnettot(&eri.his, 0, hist, sizeof(hist));                    satot(&eri.said, 0, sat, sizeof(sat));                    DBG(DBG_CONTROL,                        DBG_log("add orphaned shunt %s:%d -> %s:%d => %s:%d"                            , ourst, ourport, hist, hisport, sat, eri.transport_proto)                     )                    eri.next = orphaned_holds;                    orphaned_holds = clone_thing(eri, "orphaned %hold");                }                break;            case SPI_PASS:            case SPI_DROP:            case SPI_REJECT:                /* nothing sensible to do if we don't have counts */                if (ff != field)                {                    struct bare_shunt **bs_pp                        = bare_shunt_ptr(&eri.ours, &eri.his, eri.transport_proto);                    if (bs_pp != NULL)                    {                        struct bare_shunt *bs = *bs_pp;                        if (eri.count != bs->count)                        {                            bs->count = eri.count;                            bs->last_activity = nw;                        }                        else if (nw - bs->last_activity > SHUNT_PATIENCE)                        {                            eri.next = expired;                            expired = clone_thing(eri, "expired %pass");                        }                    }                }                break;            case SPI_TRAP:                break;            default:                bad_case(ntohl(eri.said.spi));            }        }        else        {            /* regular (non-shunt) eroute */            state_eroute_usage(&eri.ours, &eri.his, eri.count, nw);        }    }   /* for each line */    fclose(f);    /* Now that we've finished processing the /proc file,     * it is safe to delete the expired %pass shunts.     */    while (expired != NULL)    {        struct eroute_info *p = expired;        ip_address src, dst;        networkof(&p->ours, &src);        networkof(&p->his, &dst);        (void) replace_bare_shunt(&src, &dst            , BOTTOM_PRIO       /* not used because we are deleting.  This value is a filler */            , SPI_PASS  /* not used because we are deleting.  This value is a filler */            , FALSE, p->transport_proto, "delete expired bare shunts");        expired = p->next;        pfree(p);    }}static booldel_spi(ipsec_spi_t spi, int proto, const ip_address *src, const ip_address *dest){    char text_said[SATOT_BUF];    struct kernel_sa sa;    set_text_said(text_said, dest, spi, proto);    DBG(DBG_KLIPS, DBG_log("delete %s", text_said));    memset(&sa, 0, sizeof(sa));    sa.spi = spi;    sa.proto = proto;    sa.src = src;    sa.dst = dest;    sa.text_said = text_said;    return kernel_ops->del_sa(&sa);}/* * Setup a pair of SAs. * */static boolsetup_half_ipsec_sa(struct state *st, bool inbound){    /* Build an inbound or outbound SA */    struct connection *c = st->st_connection;    ip_subnet src, dst;    ip_subnet src_client, dst_client;    ipsec_spi_t inner_spi = 0;    unsigned int proto = 0, satype = 0;    bool replace;    /* SPIs, saved for spigrouping or undoing, if necessary */    struct kernel_sa        said[EM_MAXRELSPIS],        *said_next = said;    char text_said[SATOT_BUF];    int encapsulation;    replace = inbound && (kernel_ops->get_spi != NULL);    src.maskbits = 0;    dst.maskbits = 0;    if (inbound)    {        src.addr = c->spd.that.host_addr;        dst.addr = c->spd.this.host_addr;        src_client = c->spd.that.client;        dst_client = c->spd.this.client;    }    else    {        src.addr = c->spd.this.host_addr,        dst.addr = c->spd.that.host_addr;        src_client = c->spd.this.client;        dst_client = c->spd.that.client;    }    encapsulation = ENCAPSULATION_MODE_TRANSPORT;    if (st->st_ah.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL        || st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL        || st->st_ipcomp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL)    {        encapsulation = ENCAPSULATION_MODE_TUNNEL;    }    memset(said, 0, sizeof(said));    /* If we are tunnelling, set up IP in IP pseudo SA */    if (kernel_ops->inbound_eroute)    {        inner_spi = 256;        proto = SA_IPIP;        satype = SADB_SATYPE_UNSPEC;    }    else if (encapsulation == ENCAPSULATION_MODE_TUNNEL)    {        /* XXX hack alert -- we SHOULD NOT HAVE TO HAVE A DIFFERENT SPI         * XXX FOR IP-in-IP ENCAPSULATION!         */        ipsec_spi_t ipip_spi;        /* Allocate an SPI for the tunnel.         * Since our peer will never see this,         * and it comes from its own number space,         * it is purely a local implementation wart.         */        {            static ipsec_spi_t last_tunnel_spi = IPSEC_DOI_SPI_OUR_MIN;            ipip_spi = htonl(++last_tunnel_spi);            if (inbound)                st->st_tunnel_in_spi = ipip_spi;            else                st->st_tunnel_out_spi = ipip_spi;        }        set_text_said(text_said            , &c->spd.that.host_addr, ipip_spi, SA_IPIP);        said_next->src = &src.addr;        said_next->dst = &dst.addr;        said_next->src_client = &src_client;        said_next->dst_client = &dst_client;        said_next->spi = ipip_spi;        said_next->satype = SADB_X_SATYPE_IPIP;        said_next->text_said = text_said;        if (!kernel_ops->add_sa(said_next, replace)) {	    DBG_log("add_sa tunnel failed");            goto fail;	}        said_next++;        inner_spi = ipip_spi;        proto = SA_IPIP;        satype = SADB_X_SATYPE_IPIP;    }    /* set up IPCOMP SA, if any */

⌨️ 快捷键说明

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