⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 kernel.c

📁 This a good VPN source
💻 C
📖 第 1 页 / 共 5 页
字号:
/* routines that interface with the kernel's IPsec mechanism * Copyright (C) 1997 Angelos D. Keromytis. * Copyright (C) 1998-2002  D. Hugh Redelmeier. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * for more details. * * RCSID $Id: kernel.c,v 1.215 2004/12/09 18:13:29 mcr Exp $ */#include <stddef.h>#include <string.h>#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <wait.h>#include <unistd.h>#include <fcntl.h>#include <sys/queue.h>#include <sys/stat.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <openswan.h>#include <openswan/ipsec_policy.h>#ifdef KLIPS#include <signal.h>#include <sys/time.h>   /* for select(2) */#include <sys/types.h>  /* for select(2) */#include <pfkeyv2.h>#include <pfkey.h>#include "kameipsec.h"#endif /* KLIPS */#include "constants.h"#include "oswlog.h"#include "defs.h"#include "rnd.h"#include "id.h"#include "connections.h"        /* needs id.h */#include "state.h"#include "timer.h"#include "kernel.h"#include "kernel_netlink.h"#include "kernel_pfkey.h"#include "kernel_noklips.h"#include "packet.h"#include "x509.h"#include "log.h"#include "server.h"#include "whack.h"      /* for RC_LOG_SERIOUS */#include "keys.h"#ifdef XAUTH_USEPAM#include <security/pam_appl.h>#endif#ifdef NAT_TRAVERSAL#include "packet.h"  /* for pb_stream in nat_traversal.h */#include "nat_traversal.h"#endif#ifdef NAT_TRAVERSAL#include "packet.h"  /* for pb_stream in nat_traversal.h */#include "nat_traversal.h"#endifbool can_do_IPcomp = TRUE;  /* can system actually perform IPCOMP? *//* How far can IPsec messages arrive out of order before the anti-replay * logic loses track and swats them?  64 is the best KLIPS can do. */#define REPLAY_WINDOW   64/* test if the routes required for two different connections agree * It is assumed that the destination subnets agree; we are only * testing that the interfaces and nexthops match. */#define routes_agree(c, d) ((c)->interface == (d)->interface \        && sameaddr(&(c)->spd.this.host_nexthop, &(d)->spd.this.host_nexthop))#ifndef KLIPSbool no_klips = TRUE;   /* don't actually use KLIPS */#else /* !KLIPS *//* bare (connectionless) shunt (eroute) table * * Bare shunts are those that don't "belong" to a connection. * This happens because some %trapped traffic hasn't yet or cannot be * assigned to a connection.  The usual reason is that we cannot discover * the peer SG.  Another is that even when the peer has been discovered, * it may be that no connection matches all the particulars. * We record them so that, with scanning, we can discover * which %holds are news and which others should expire. */#define SHUNT_SCAN_INTERVAL     (60 * 2)   /* time between scans of eroutes *//* SHUNT_PATIENCE only has resolution down to a multiple of the sample rate, * SHUNT_SCAN_INTERVAL. * By making SHUNT_PATIENCE an odd multiple of half of SHUNT_SCAN_INTERVAL, * we minimize the effects of jitter. */#define SHUNT_PATIENCE  (SHUNT_SCAN_INTERVAL * 15 / 2)  /* inactivity timeout */struct bare_shunt {    policy_prio_t policy_prio;    ip_subnet ours;    ip_subnet his;    ip_said said;    int transport_proto;    unsigned long count;    time_t last_activity;    char *why;    struct bare_shunt *next;};static struct bare_shunt *bare_shunts = NULL;#ifdef DEBUGstatic voidDBG_bare_shunt(const char *op, const struct bare_shunt *bs){    DBG(DBG_KLIPS,        {            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);            DBG_log("%s bare shunt %p %s:%d -%d-> %s:%d => %s %s    %s"                , op, (const void *)(bs), ourst, ourport, (bs)->transport_proto, hist, hisport                , sat, prio, (bs)->why);        });}#else /* !DEBUG */#define DBG_bare_shunt(op, bs) {}#endif /* !DEBUG *//* The orphaned_holds table records %holds for which we * scan_proc_shunts found no representation of in any connection. * The corresponding ACQUIRE message might have been lost. */struct eroute_info *orphaned_holds = NULL;/* forward declaration */static bool shunt_eroute(struct connection *c                         , struct spd_route *sr                         , enum routing_t rt_kind                         , unsigned int op, const char *opname);static void set_text_said(char *text_said                          , const ip_address *dst                          , ipsec_spi_t spi                          , int proto);bool no_klips = FALSE;  /* don't actually use KLIPS */static const struct pfkey_proto_info null_proto_info[2] = {        {                proto: IPPROTO_ESP,                encapsulation: ENCAPSULATION_MODE_TRANSPORT,                reqid: 0        },        {                proto: 0,                encapsulation: 0,                reqid: 0        }};voidrecord_and_initiate_opportunistic(const ip_subnet *ours                                  , const ip_subnet *his                                  , int transport_proto                                  , const char *why){    passert(samesubnettype(ours, his));    /* Add to bare shunt list.     * We need to do this because the shunt was installed by KLIPS     * which can't do this itself.     */    {        struct bare_shunt *bs = alloc_thing(struct bare_shunt, "bare shunt");        bs->why = clone_str(why, "story for bare shunt");        bs->ours = *ours;        bs->his = *his;        bs->transport_proto = transport_proto;        bs->policy_prio = BOTTOM_PRIO;        bs->said.proto = SA_INT;        bs->said.spi = htonl(SPI_HOLD);        bs->said.dst = *aftoinfo(subnettypeof(ours))->any;        bs->count = 0;        bs->last_activity = now();        bs->next = bare_shunts;        bare_shunts = bs;        DBG_bare_shunt("add", bs);    }    /* actually initiate opportunism */    {        ip_address src, dst;        networkof(ours, &src);        networkof(his, &dst);        initiate_opportunistic(&src, &dst, transport_proto, TRUE, NULL_FD, "acquire");    }    /*     * if present, remove from orphaned_holds list.     * NOTE: we do this last in case ours or his is a pointer into a member.     */    {        struct eroute_info **pp, *p;        for (pp = &orphaned_holds; (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))            {                *pp = p->next;                pfree(p);                break;            }        }    }}#endif /* KLIPS */static unsigned get_proto_reqid(unsigned base, int proto){    switch (proto)    {    default:    case IPPROTO_COMP:        base++;        /* fall through */    case IPPROTO_ESP:        base++;        /* fall through */    case IPPROTO_AH:        break;    }    return base;}/* Generate Unique SPI numbers. * * The specs say that the number must not be less than IPSEC_DOI_SPI_MIN. * Pluto generates numbers not less than IPSEC_DOI_SPI_OUR_MIN, * reserving numbers in between for manual keying (but we cannot so * restrict numbers generated by our peer). * XXX This should be replaced by a call to the kernel when * XXX we get an API. * The returned SPI is in network byte order. * We use a random number as the initial SPI so that there is * a good chance that different Pluto instances will choose * different SPIs.  This is good for two reasons. * - the keying material for the initiator and responder only *   differs if the SPIs differ. * - if Pluto is restarted, it would otherwise recycle the SPI *   numbers and confuse everything.  When the kernel generates *   SPIs, this will no longer matter. * We then allocate numbers sequentially.  Thus we don't have to * check if the number was previously used (assuming that no * SPI lives longer than 4G of its successors). */ipsec_spi_tget_ipsec_spi(ipsec_spi_t avoid, int proto, struct spd_route *sr, bool tunnel){    static ipsec_spi_t spi = 0; /* host order, so not returned directly! */    char text_said[SATOT_BUF];    set_text_said(text_said, &sr->this.host_addr, 0, proto);    if (kernel_ops->get_spi)        return kernel_ops->get_spi(&sr->that.host_addr            , &sr->this.host_addr, proto, tunnel            , get_proto_reqid(sr->reqid, proto)            , IPSEC_DOI_SPI_OUR_MIN, 0xffffffff            , text_said);    spi++;    while (spi < IPSEC_DOI_SPI_OUR_MIN || spi == ntohl(avoid))        get_rnd_bytes((u_char *)&spi, sizeof(spi));    DBG(DBG_CONTROL,        {            ipsec_spi_t spi_net = htonl(spi);            DBG_dump("generate SPI:", (u_char *)&spi_net, sizeof(spi_net));        });    return htonl(spi);}/* Generate Unique CPI numbers. * The result is returned as an SPI (4 bytes) in network order! * The real bits are in the nework-low-order 2 bytes. * Modelled on get_ipsec_spi, but range is more limited: * 256-61439. * If we can't find one easily, return 0 (a bad SPI, * no matter what order) indicating failure. */ipsec_spi_tget_my_cpi(struct spd_route *sr, bool tunnel){    static cpi_t        first_busy_cpi = 0,        latest_cpi;    char text_said[SATOT_BUF];    set_text_said(text_said, &sr->this.host_addr, 0, IPPROTO_COMP);    if (kernel_ops->get_spi)        return kernel_ops->get_spi(&sr->that.host_addr            , &sr->this.host_addr, IPPROTO_COMP, tunnel            , get_proto_reqid(sr->reqid, IPPROTO_COMP)            , IPCOMP_FIRST_NEGOTIATED, IPCOMP_LAST_NEGOTIATED            , text_said);    while (!(IPCOMP_FIRST_NEGOTIATED <= first_busy_cpi && first_busy_cpi < IPCOMP_LAST_NEGOTIATED))    {        get_rnd_bytes((u_char *)&first_busy_cpi, sizeof(first_busy_cpi));        latest_cpi = first_busy_cpi;    }    latest_cpi++;    if (latest_cpi == first_busy_cpi)        find_my_cpi_gap(&latest_cpi, &first_busy_cpi);    if (latest_cpi > IPCOMP_LAST_NEGOTIATED)        latest_cpi = IPCOMP_FIRST_NEGOTIATED;    return htonl((ipsec_spi_t)latest_cpi);}/* invoke the updown script to do the routing and firewall commands required * * The user-specified updown script is run.  Parameters are fed to it in * the form of environment variables.  All such environment variables * have names starting with "PLUTO_". * * The operation to be performed is specified by PLUTO_VERB.  This * verb has a suffix "-host" if the client on this end is just the * host; otherwise the suffix is "-client".  If the address family * of the host is IPv6, an extra suffix of "-v6" is added. * * "prepare-host" and "prepare-client" are used to delete a route * that may exist (due to forces outside of Pluto).  It is used to * prepare for pluto creating a route. * * "route-host" and "route-client" are used to install a route. * Since routing is based only on destination, the PLUTO_MY_CLIENT_* * values are probably of no use (using them may signify a bug). * * "unroute-host" and "unroute-client" are used to delete a route. * Since routing is based only on destination, the PLUTO_MY_CLIENT_* * values are probably of no use (using them may signify a bug). * * "up-host" and "up-client" are run when an eroute is added (not replaced). * They are useful for adjusting a firewall: usually for adding a rule * to let processed packets flow between clients.  Note that only * one eroute may exist for a pair of client subnets but inbound * IPsec SAs may persist without an eroute. * * "down-host" and "down-client" are run when an eroute is deleted. * They are useful for adjusting a firewall. */#ifndef DEFAULT_UPDOWN# define DEFAULT_UPDOWN "ipsec _updown"#endifstatic booldo_command(struct connection *c, struct spd_route *sr, const char *verb){    char cmd[1536];     /* arbitrary limit on shell command length */    const char *verb_suffix;

⌨️ 快捷键说明

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