Your Ad Here
首页 | 编程语言 | 网站建设 | 游戏天堂 | 冲浪宝典 | 网络安全 | 操作系统 | 软件时空 | 硬件指南 | 病毒相关 | IT 认证
软讯网络 > 操作系统 > Linux > 改后的freeswan\pluto\kernel.c(1)
【标  题】:改后的freeswan\pluto\kernel.c(1)
【关键字】:freeswan,pluto,kernel.c
【来  源】:http://blog.chinaunix.net/article.php?articleId=17491&blogId=4329

改后的freeswan\pluto\kernel.c(1)

Your Ad Here

/* 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.
 *                             2005/03/25 13:47    zqqa <zqqa@163.com> modify
 * RCSID $Id: kernel.c,v 1.149 2002/04/01 08:46:54 dhr 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/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <freeswan.h>

#ifdef KLIPS
#include <sys/time.h>    /* for select(2) */
#include <sys/types.h>    /* for select(2) */
# include <signal.h>
# include <pfkeyv2.h>
# include <pfkey.h>
#endif /* KLIPS */

#include <linux/config.h>
#ifdef CONFIG_LEDMAN
#include <linux/ledman.h>
#endif

#include "constants.h"
#include "defs.h"
#include "rnd.h"
#include "id.h"
#include "x509.h"
#include "connections.h"    /* needs id.h */
#include "state.h"
#include "timer.h"
#include "kernel.h"
#include "log.h"
#include "server.h"
#include "whack.h"    /* for RC_LOG_SERIOUS */

#include "alg_info.h"
#include "kernel_alg.h"

#ifdef NAT_TRAVERSAL
#include "packet.h"  /* for pb_stream in nat_traversal.h */
#include "nat_traversal.h"
#endif

bool 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

static bool route_and_eroute(struct connection *c
    , struct state *st);    /* forward declaration */

static bool onlyeroute(struct connection *c
    , struct state *st);    /* zqqa modified ,forward declaration */

/* 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)->this.host_nexthop, &(d)->this.host_nexthop))

#ifndef KLIPS

bool no_klips = TRUE;    /* don't actually use KLIPS */

#else /* !KLIPS */

/* Declare eroute things early enough for uses.
 *
 * Flags are encoded above the low-order byte of verbs.
 * "real" eroutes are only outbound.  Inbound eroutes don't exist,
 * but an addflow with an INBOUND flag allows IPIP tunnels to be
 * limited to appropriate source and destination addresses.
 */

#define ERO_MASK    0xFF
#define ERO_FLAG_SHIFT    8

#define ERO_DELETE    SADB_X_DELFLOW
#define ERO_ADD    SADB_X_ADDFLOW
#define ERO_REPLACE    (SADB_X_ADDFLOW | (SADB_X_SAFLAGS_REPLACEFLOW << ERO_FLAG_SHIFT))
#define ERO_ADD_INBOUND    (SADB_X_ADDFLOW | (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT))

/* 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.
 * Bare shunts are either %hold or %pass.
 * We record them so that, with scanning, we can discover
 * which %holds are news and which %passes 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 {
    ip_subnet ours;
    ip_subnet his;
    ip_said said;
    unsigned long count;
    time_t last_activity;
    struct bare_shunt *next;
};

static struct bare_shunt *bare_shunts = NULL;

#ifdef DEBUG
static void
DBG_bare_shunt(const char *op, const struct bare_shunt *bs)
{
    DBG(DBG_KLIPS,
    {
        char ourst[SUBNETTOT_BUF];
        char hist[SUBNETTOT_BUF];
        char sat[SATOT_BUF];

        subnettot(&(bs)->ours, 0, ourst, sizeof(ourst));
        subnettot(&(bs)->his, 0, hist, sizeof(hist));
        satot(&(bs)->said, 0, sat, sizeof(sat));
        DBG_log("%s bare shunt %p %s -> %s => %s"
        , op, (const void *)(bs), ourst, hist, sat);
    });
}
#else /* !DEBUG */
#define DBG_bare_shunt(op, bs) {}
#endif /* !DEBUG */

/* information from /proc/net/ipsec_eroute */

struct eroute_info {
    unsigned long count;
    ip_subnet ours;
    ip_subnet his;
    ip_address dst;
    ip_said    said;
    struct eroute_info *next;
};

/* 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;

static bool shunt_eroute(struct connection *c
    , unsigned int op, const char *opname);    /* forward declaration */

bool no_klips = FALSE;    /* don't actually use KLIPS */

int pfkeyfd = NULL_FD;

typedef u_int32_t pfkey_seq_t;
static pfkey_seq_t pfkey_seq = 0;    /* sequence number for our PF_KEY messages */

static pid_t pid;
static void pfkey_register(void);

#define NE(x) { x, #x }    /* Name Entry -- shorthand for sparse_names */

static sparse_names pfkey_type_names = {
    NE(SADB_RESERVED),
    NE(SADB_GETSPI),
    NE(SADB_UPDATE),
    NE(SADB_ADD),
    NE(SADB_DELETE),
    NE(SADB_GET),
    NE(SADB_ACQUIRE),
    NE(SADB_REGISTER),
    NE(SADB_EXPIRE),
    NE(SADB_FLUSH),
    NE(SADB_DUMP),
    NE(SADB_X_PROMISC),
    NE(SADB_X_PCHANGE),
    NE(SADB_X_GRPSA),
    NE(SADB_X_ADDFLOW),
    NE(SADB_X_DELFLOW),
    NE(SADB_X_DEBUG),
#ifdef NAT_TRAVERSAL
    NE(SADB_X_NAT_T_NEW_MAPPING),
#endif
    NE(SADB_MAX),
    { 0, sparse_end }
};

#ifdef NEVER /* not needed yet */
static sparse_names pfkey_ext_names = {
    NE(SADB_EXT_RESERVED),
    NE(SADB_EXT_SA),
    NE(SADB_EXT_LIFETIME_CURRENT),
    NE(SADB_EXT_LIFETIME_HARD),
    NE(SADB_EXT_LIFETIME_SOFT),
    NE(SADB_EXT_ADDRESS_SRC),
    NE(SADB_EXT_ADDRESS_DST),
    NE(SADB_EXT_ADDRESS_PROXY),
    NE(SADB_EXT_KEY_AUTH),
    NE(SADB_EXT_KEY_ENCRYPT),
    NE(SADB_EXT_IDENTITY_SRC),
    NE(SADB_EXT_IDENTITY_DST),
    NE(SADB_EXT_SENSITIVITY),
    NE(SADB_EXT_PROPOSAL),
    NE(SADB_EXT_SUPPORTED_AUTH),
    NE(SADB_EXT_SUPPORTED_ENCRYPT),
    NE(SADB_EXT_SPIRANGE),
    NE(SADB_X_EXT_KMPRIVATE),
    NE(SADB_X_EXT_SATYPE2),
    NE(SADB_X_EXT_SA2),
    NE(SADB_X_EXT_ADDRESS_DST2),
    NE(SADB_X_EXT_ADDRESS_SRC_FLOW),
    NE(SADB_X_EXT_ADDRESS_DST_FLOW),
    NE(SADB_X_EXT_ADDRESS_SRC_MASK),
    NE(SADB_X_EXT_ADDRESS_DST_MASK),
    NE(SADB_X_EXT_DEBUG),
    { 0, sparse_end }
};
#endif /* NEVER */

#undef NE

static void
init_pfkey(void)
{
    pid = getpid();

    /* open PF_KEY socket */

    pfkeyfd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);

    if (pfkeyfd == -1)
    exit_log_errno((e, "socket() in init_pfkeyfd()"));

#ifdef NEVER    /* apparently unsupported! */
    if (fcntl(pfkeyfd, F_SETFL, O_NONBLOCK) != 0)
    exit_log_errno((e, "fcntl() in init_pfkeyfd()"));
#endif

    DBG(DBG_KLIPS,
    DBG_log("process %u listening for PF_KEY_V2 on file descriptor %d", (unsigned)pid, pfkeyfd));

    pfkey_register();    /* register SA types that we can negotiate */
}

/* Kinds of PF_KEY message from the kernel:
 * - response to a request from us
 *   + ACK/NAK
 *   + Register: indicates transforms supported by kernel
 *   + SPI requested by getspi
 * - Acquire, requesting us to deal with trapped clear packet
 * - expiration of of one of our SAs
 * - messages to other processes
 *
 * To minimize the effect on the event-driven structure of Pluto,
 * responses are dealt with synchronously.  We hope that the Kernel
 * produces them synchronously.  We must "read ahead" in the PF_KEY
 * stream, saving Acquire and Expiry messages that are encountered.
 * We ignore messages to other processes.
 */

typedef union {
    unsigned char bytes[PFKEYv2_MAX_MSGSIZE];
    struct sadb_msg msg;
    } pfkey_buf;

/* queue of unprocessed PF_KEY messages input from kernel
 * Note that the pfkey_buf may be partly allocated, reflecting
 * the variable length nature of the messages.  So the link field
 * must come first.
 */
typedef struct pfkey_item {
    struct pfkey_item *next;
    pfkey_buf buf;
    } pfkey_item;

static pfkey_item *pfkey_iq_head = NULL;    /* oldest */
static pfkey_item *pfkey_iq_tail;    /* youngest */

static bool
pfkey_input_ready(void)
{
    fd_set readfds;
    int ndes;
    struct timeval tm;

    tm.tv_sec = 0;    /* don't wait at all */
    tm.tv_usec = 0;

    FD_ZERO(&readfds);    /* we only care about pfkeyfd */
    FD_SET(pfkeyfd, &readfds);

    do {
    ndes = select(pfkeyfd + 1, &readfds, NULL, NULL, &tm);
    } while (ndes == -1 && errno == EINTR);

    if (ndes < 0)
    {
    log_errno((e, "select() failed in pfkey_get()"));
    return FALSE;
    }

    if (ndes == 0)
    return FALSE;    /* nothing to read */

    passert(ndes == 1 && FD_ISSET(pfkeyfd, &readfds));
    return TRUE;
}

/* get a PF_KEY message from kernel.
 * Returns TRUE is message found, FALSE if no message pending,
 * and aborts or keeps trying when an error is encountered.
 * The only validation of the message is that the message length
 * received matches that in the message header, and that the message
 * is for this process.
 */
static bool
pfkey_get(pfkey_buf *buf)
{
    for (;;)
    {
    ssize_t len;

    if (!pfkey_input_ready())
        return FALSE;

    len = read(pfkeyfd, buf->bytes, sizeof(buf->bytes));

    if (len < 0)
    {
        if (errno == EAGAIN)
        return FALSE;

        log_errno((e, "read() failed in pfkey_get()"));
        return FALSE;
    }
    else if ((size_t) len < sizeof(buf->msg))
    {
        log("pfkey_get read truncated PF_KEY message: %d bytes; ignoring message", len);
    }
    else if ((size_t) len != buf->msg.sadb_msg_len * IPSEC_PFKEYv2_ALIGN)
    {
        log("pfkey_get read PF_KEY message with length %d that doesn't equal sadb_msg_len %u * %d; ignoring message"
        , len, (unsigned) buf->msg.sadb_msg_len, IPSEC_PFKEYv2_ALIGN);
    }
    /*    for now, unsolicited messages can be:
     *    SADB_ACQUIRE, SADB_REGISTER
     */
    else if (!(buf->msg.sadb_msg_pid == (unsigned)pid
    || (buf->msg.sadb_msg_pid == 0 && buf->msg.sadb_msg_type == SADB_ACQUIRE)
#ifdef NAT_TRAVERSAL
    || (buf->msg.sadb_msg_pid == 0 && buf->msg.sadb_msg_type == SADB_X_NAT_T_NEW_MAPPING)
#endif
    || (buf->msg.sadb_msg_type == SADB_REGISTER)))
    {
        /* not for us: ignore */
        DBG(DBG_KLIPS,
        DBG_log("pfkey_get: ignoring PF_KEY %s message %u for process %u"
            , sparse_val_show(pfkey_type_names, buf->msg.sadb_msg_type)
            , buf->msg.sadb_msg_seq
            , buf->msg.sadb_msg_pid));
    }
    else
    {
        DBG(DBG_KLIPS,
        DBG_log("pfkey_get: %s message %u"
            , sparse_val_show(pfkey_type_names, buf->msg.sadb_msg_type)
            , buf->msg.sadb_msg_seq));
        return TRUE;
    }
    }
}

/* get a response to a specific message */
static bool
pfkey_get_response(pfkey_buf *buf, pfkey_seq_t seq)
{
    while (pfkey_get(buf))
    {
    if (buf->msg.sadb_msg_pid == (unsigned)pid
    && buf->msg.sadb_msg_seq == seq)
    {
        return TRUE;
    }
    else
    {
        /* Not for us: queue it. */
        size_t bl = buf->msg.sadb_msg_len * IPSEC_PFKEYv2_ALIGN;
        pfkey_item *it = alloc_bytes(offsetof(pfkey_item, buf) + bl, "pfkey_item");

        memcpy(&it->buf, buf, bl);

        it->next = NULL;
        if (pfkey_iq_head == NULL)
        {
        pfkey_iq_head = it;
        }
        else
        {
        pfkey_iq_tail->next = it;
        }
        pfkey_iq_tail = it;
    }
    }
    return FALSE;
}

/* Process a SADB_REGISTER message from KLIPS.
 * This will be a response to one of ours, but it may be asynchronous
 * (if KLIPS modules are loaded and unloaded).
 * Some sanity checking has already been performed.
 */
static void
process_pfkey_register_response(pfkey_buf *buf)
{
    /* Find out what the kernel can support.
     * In fact, the only question at the moment
     * is whether it can support IPcomp.
     * So we ignore the rest.
     * ??? we really should pay attention to what transforms are supported.
     */
    switch (buf->msg.sadb_msg_satype)
    {
    case SADB_SATYPE_AH:
    break;
    case SADB_SATYPE_ESP:
#ifndef NO_KERNEL_ALG
    kernel_alg_register_pfkey(buf, sizeof (pfkey_buf));
#endif
    break;
    case SADB_X_SATYPE_COMP:
    /* ??? There ought to be an extension to list the
     * supported algorithms, but RFC 2367 doesn't
     * list one for IPcomp.  KLIPS uses SADB_X_CALG_DEFLATE.
     * Since we only implement deflate, we'll assume this.
     */
    can_do_IPcomp = TRUE;
    break;
    case SADB_X_SATYPE_IPIP:
    break;
    default:
    break;
    }
}

/* Create ip_address out of sockaddr.  Ignore port! */
static err_t
sockaddr_to_ip_address(const struct sockaddr *src, ip_address *dest)
{
    switch (src->sa_family)
    {
    case AF_INET:
    initaddr((const void *) &((const struct sockaddr_in *)src)->sin_addr
        , sizeof(((const struct sockaddr_in *)src)->sin_addr)
        , src->sa_family, dest);
    return NULL;
    case AF_INET6:
    initaddr((const void *) &((const struct sockaddr_in6 *)src)->sin6_addr
        , sizeof(((const struct sockaddr_in6 *)src)->sin6_addr)
        , src->sa_family, dest);
    return NULL;
    default:
    return "unknown address family";
    }
}

static void
record_and_initiate_opportunistic(ip_subnet *ours, ip_subnet *his)
{
    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->ours = *ours;
    bs->his = *his;

    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, TRUE, NULL_FD);
    }

    /* 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))
        {
        *pp = p->next;
        pfree(p);
        break;
        }
    }
    }
}

/* Processs a SADB_ACQUIRE message from KLIPS.
 * Try to build an opportunistic connection!
 * See RFC 2367 "PF_KEY Key Management API, Version 2" 3.1.6
 * <base, address(SD), (address(P)), (identity(SD),) (sensitivity,) proposal>
 * - extensions for source and data IP addresses
 * - optional extensions for identity [not useful for us?]
 * - optional extension for sensitivity [not useful for us?]
 * - expension for proposal [not useful for us?]
 *
 * ??? We must use the sequence number in creating an SA.
 * We actually need to create up to 4 SAs each way.  Which one?
 * I guess it depends on the protocol present in the sadb_msg_satype.
 * For now, we'll ignore this requirement.
 *
 * ??? We need some mechanism to make sure that multiple ACQUIRE messages
 * don't cause a whole bunch of redundant negotiations.
 */
static void
process_pfkey_acquire(pfkey_buf *buf, struct sadb_ext *extensions[SADB_EXT_MAX + 1])
{
    struct sadb_address *srcx = (void *) extensions[SADB_EXT_ADDRESS_SRC];
    struct sadb_address *dstx = (void *) extensions[SADB_EXT_ADDRESS_DST];
    ip_address src, dst;
    ip_subnet ours, his;
    err_t ugh = NULL;

    /* assumption: we're only catching our own outgoing packets
     * so source is our end and destination is the other end.
     * Verifying this is not actually convenient.
     *
     * This stylized control structure yields a complaint or
     * desired results.  For compactness, a pointer value is
     * treated as a boolean.  Logically, the structure is:
     * keep going as long as things are OK.
     */
    if (buf->msg.sadb_msg_pid == 0    /* we only wish to hear from kernel */
    && !(ugh = sockaddr_to_ip_address((struct sockaddr *)(void *)&srcx[1], &src))
    && !(ugh = sockaddr_to_ip_address((struct sockaddr *)(void *)&dstx[1], &dst))
    && !(ugh = addrtypeof(&src) == addrtypeof(&dst)? NULL : "conflicting address types")
    && !(ugh = addrtosubnet(&src, &ours))
    && !(ugh = addrtosubnet(&dst, &his)))
    record_and_initiate_opportunistic(&ours, &his);

    if (ugh != NULL)
    log("SADB_ACQUIRE message from KLIPS malformed: %s", ugh);

}

/* Handle PF_KEY messages from the kernel that are not dealt with
 * synchronously.  In other words, all but responses to PF_KEY messages
 * that we sent.
 */
static void
pfkey_async(pfkey_buf *buf)
{
    struct sadb_ext *extensions[SADB_EXT_MAX + 1];

    if (pfkey_msg_parse(&buf->msg, NULL, extensions, EXT_BITS_OUT))
    {
    log("pfkey_async:"
        " unparseable PF_KEY message:"
        " %s len=%d, errno=%d, seq=%d, pid=%d; message ignored"
        , sparse_val_show(pfkey_type_names, buf->msg.sadb_msg_type)
        , buf->msg.sadb_msg_len
        , buf->msg.sadb_msg_errno
        , buf->msg.sadb_msg_seq
        , buf->msg.sadb_msg_pid);
    }
    else
    {
    DBG(DBG_CONTROL | DBG_KLIPS, DBG_log("pfkey_async:"
        " %s len=%u, errno=%u, satype=%u, seq=%u, pid=%u"
        , sparse_val_show(pfkey_type_names, buf->msg.sadb_msg_type)
        , buf->msg.sadb_msg_len
        , buf->msg.sadb_msg_errno
        , buf->msg.sadb_msg_satype
        , buf->msg.sadb_msg_seq
        , buf->msg.sadb_msg_pid));

    switch (buf->msg.sadb_msg_type)
    {
    case SADB_REGISTER:
        process_pfkey_register_response(buf);
        break;
    case SADB_ACQUIRE:
        /* to simulate loss of ACQUIRE, delete this call */
        process_pfkey_acquire(buf, extensions);
        break;
#ifdef NAT_TRAVERSAL
    case SADB_X_NAT_T_NEW_MAPPING:
        process_pfkey_nat_t_new_mapping(&(buf->msg), extensions);
        break;
#endif
    default:
        /* ignored */
        break;
    }
    }
}

/* asynchronous messages from our queue */
void
pfkey_dequeue(void)
{
    while (pfkey_iq_head != NULL)
    {
    pfkey_item *it = pfkey_iq_head;

    pfkey_async(&it->buf);
    pfkey_iq_head = it->next;
    pfree(it);
    }

    /* Handle any orphaned holds, but only if no pfkey input is pending.
     * For each, we initiate Opportunistic.
     * note: we don't need to advance the pointer because
     * record_and_initiate_opportunistic will remove the current
     * record each time we call it.
     */
    while (orphaned_holds != NULL && !pfkey_input_ready())
    record_and_initiate_opportunistic(&orphaned_holds->ours
        , &orphaned_holds->his);

}

/* asynchronous messages directly from PF_KEY socket */
void
pfkey_event(void)
{
    pfkey_buf buf;

    if (pfkey_get(&buf))
    pfkey_async(&buf);
}

#endif /* KLIPS */

/* 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_t
get_ipsec_spi(ipsec_spi_t avoid)
{
    static ipsec_spi_t spi = 0;    /* host order, so not returned directly! */

    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_t
get_my_cpi(void)
{
    static cpi_t
    first_busy_cpi = 0,
    latest_cpi;

    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"
#endif

static bool
do_command(struct connection *c, const char *verb)
{
    char cmd[1536];    /* arbitrary limit on shell command length */
    const char *verb_suffix;

    /* figure out which verb suffix applies */
    {
    const char *hs, *cs;

    switch (addrtypeof(&c->this.host_addr))
    {
        case AF_INET:
        hs = "-host";
        cs = "-client";
        break;
        case AF_INET6:
        hs = "-host-v6";
        cs = "-client-v6";
        break;
        default:
        loglog(RC_LOG_SERIOUS, "unknown address family");
        return FALSE;
    }
    verb_suffix = subnetishost(&c->this.client) && addrinsubnet(&c->this.host_addr, &c->this.client)
        ? hs : cs;
    }

    /* form the command string */
    {
    const ip_subnet *epc = EffectivePeerClient(c);
    char
        nexthop_str[ADDRTOT_BUF],
        me_str[ADDRTOT_BUF],
        myid_str[IDTOA_BUF],
        myclient_str[SUBNETTOT_BUF],
        myclientnet_str[ADDRTOT_BUF],
        myclientmask_str[ADDRTOT_BUF],
        peer_str[ADDRTOT_BUF],
        peerid_str[IDTOA_BUF],
        peerclient_str[SUBNETTOT_BUF],
        peerclientnet_str[ADDRTOT_BUF],
        peerclientmask_str[ADDRTOT_BUF];
    ip_address ta;

    addrtot(&c->this.host_nexthop, 0, nexthop_str, sizeof(nexthop_str));

    addrtot(&c->this.host_addr, 0, me_str, sizeof(me_str));
    idtoa(&c->this.id, myid_str, sizeof(myid_str));
    subnettot(&c->this.client, 0, myclient_str, sizeof(myclientnet_str));
    networkof(&c->this.client, &ta);
    addrtot(&ta, 0, myclientnet_str, sizeof(myclientnet_str));
    maskof(&c->this.client, &ta);
    addrtot(&ta, 0, myclientmask_str, sizeof(myclientmask_str));

    addrtot(&c->that.host_addr, 0, peer_str, sizeof(peer_str));
    idtoa(&c->that.id, peerid_str, sizeof(peerid_str));
    subnettot(epc, 0, peerclient_str, sizeof(peerclientnet_str));
    networkof(epc, &ta);
    addrtot(&ta, 0, peerclientnet_str, sizeof(peerclientnet_str));
    maskof(epc, &ta);
    addrtot(&ta, 0, peerclientmask_str, sizeof(peerclientmask_str));

#ifdef SIMPLE_SCRIPTS
# define SE "setenv "
# define EQ " "
# define NL "\n"
#else
# define SE ""
# define EQ "="
# define NL " "
#endif
    if (-1 == snprintf(cmd, sizeof(cmd),
#ifdef SIMPLE_SCRIPTS
        "#!/bin/sh" NL
#endif
         /* change VERSION when interface spec changes */
        SE "PLUTO_VERSION"          EQ "'1.1'" NL
        SE "PLUTO_VERB"             EQ "'%s%s'" NL
        SE "PLUTO_CONNECTION"       EQ "'%s'" NL
        SE "PLUTO_NEXT_HOP"         EQ "'%s'" NL
        SE "PLUTO_INTERFACE"        EQ "'%s'" NL
        SE "PLUTO_ME"               EQ "'%s'" NL
        SE "PLUTO_MY_ID"            EQ "'%s'" NL
        SE "PLUTO_MY_CLIENT"        EQ "'%s'" NL
        SE "PLUTO_MY_CLIENT_NET"    EQ "'%s'" NL
        SE "PLUTO_MY_CLIENT_MASK"   EQ "'%s'" NL
        SE "PLUTO_MY_PORT"          EQ "'%u'" NL
        SE "PLUTO_MY_PROTOCOL"      EQ "'%u'" NL
        SE "PLUTO_PEER"             EQ "'%s'" NL
        SE "PLUTO_PEER_ID"          EQ "'%s'" NL
        SE "PLUTO_PEER_CLIENT"      EQ "'%s'" NL
        SE "PLUTO_PEER_CLIENT_NET"  EQ "'%s'" NL
        SE "PLUTO_PEER_CLIENT_MASK" EQ "'%s'" NL
        SE "PLUTO_PEER_PORT"        EQ "'%u'" NL
        SE "PLUTO_PEER_PROTOCOL"    EQ "'%u'" NL
        "%s"                                  NL    /* actual script */
#ifndef SIMPLE_SCRIPTS
        "2>&1 "    /* capture stderr along with stdout */
#endif
        , verb, verb_suffix
        , c->name
        , nexthop_str
        , c->interface->vname
        , me_str
        , myid_str
        , myclient_str
        , myclientnet_str
        , myclientmask_str
        , c->this.port
        , c->this.protocol
        , peer_str
        , peerid_str
        , peerclient_str
        , peerclientnet_str
        , peerclientmask_str
        , c->that.port
        , c->that.protocol
        , c->this.updown == NULL? DEFAULT_UPDOWN : c->this.updown))
    {
        loglog(RC_LOG_SERIOUS, "%s%s command too long!", verb, verb_suffix);
        return FALSE;
    }
    }

    DBG(DBG_CONTROL, DBG_log("executing %s%s: %s"
    , verb, verb_suffix, cmd));

#ifdef KLIPS

#ifdef SIMPLE_SCRIPTS
    if (!no_klips)
    {
        const char *temp_name = "/var/log/pluto_script";
    int fd;

    unlink(temp_name);
        fd = open(temp_name, O_WRONLY|O_CREAT|O_TRUNC, 0777);
    if (fd == -1) {
        loglog(RC_LOG_SERIOUS, "unable to open %s", temp_name);
        return FALSE;
    }
    if (write(fd, cmd, strlen(cmd)) != strlen(cmd)) {
        loglog(RC_LOG_SERIOUS, "unable to write to %s", temp_name);
        return FALSE;
    }
    if (close(fd) == -1) {
        loglog(RC_LOG_SERIOUS, "unable to close %s", temp_name);
        return FALSE;
    }
    strncpy(cmd, temp_name, sizeof(cmd));
    }
#endif

    if (!no_klips)
    {
    /* invoke the script, catching stderr and stdout
     * It may be of concern that some file descriptors will
     * be inherited.  For the ones under our control, we
     * have done fcntl(fd, F_SETFD, FD_CLOEXEC) to prevent this.
     * Any used by library routines (perhaps the resolver or syslog)
     * will remain.
     */
    FILE *f = popen(cmd, "r");
    
    if (f == NULL)
    {
        loglog(RC_LOG_SERIOUS, "unable to popen %s%s command", verb, verb_suffix);
#ifdef SIMPLE_SCRIPTS
        unlink(cmd); /* don't need it now */
#endif
        return FALSE;
    }

    /* log any output */
    for (;;)
    {
        /* if response doesn't fit in this buffer, it will be folded */
        char resp[256];

        if (fgets(resp, sizeof(resp), f) == NULL)
        {
        if (ferror(f))
        {
            log_errno((e, "fgets failed on output of %s%s command"
            , verb, verb_suffix));
#ifdef SIMPLE_SCRIPTS
            unlink(cmd); /* don't need it now */
#endif
            return FALSE;
        }
        else
        {
            passert(feof(f));
            break;
        }
        }
        else
        {
        char *e = resp + strlen(resp);

        if (e > resp && e[-1] == '\n')
            e[-1] = '';    /* trim trailing '\n' */
        //log("%s%s output: %s", verb, verb_suffix, resp);
        }
    }
   
#ifdef SIMPLE_SCRIPTS
    unlink(cmd); /* don't need it now */
#endif
    /* report on and react to return code */
    {
        int r = pclose(f);

        if (r == -1)
        {
        if (errno ==  ECHILD)
             return TRUE;
        log_errno((e, "pclose failed for %s%s command"
            , verb, verb_suffix));
        return FALSE;
        }
        else if (WIFEXITED(r))
        {
        if (WEXITSTATUS(r) != 0)
        {
            loglog(RC_LOG_SERIOUS, "%s%s command exited with status %d"
            , verb, verb_suffix, WEXITSTATUS(r));
            return FALSE;
        }
        }
        else if (WIFSIGNALED(r))
        {
        loglog(RC_LOG_SERIOUS, "%s%s command exited with signal %d"
            , verb, verb_suffix, WTERMSIG(r));
        return FALSE;
        }
        else
        {
        loglog(RC_LOG_SERIOUS, "%s%s command exited with unknown status %d"
            , verb, verb_suffix, r);
        return FALSE;
        }
    }
    }
#endif /* KLIPS */
    return TRUE;
}

/* Check that we can route (and eroute).  Diagnose if we cannot. */

static bool
could_route(struct connection *c)
{
    struct connection *ero    /* who, if anyone, owns our eroute? */
    , *ro = route_owner(c, &ero);    /* who owns our route? */

    /* if this is a Road Warrior template, we cannot route.
     * Opportunistic template is OK.
     */
    if (c->kind == CK_TEMPLATE && !(c->policy & POLICY_OPPO))
    {
    loglog(RC_ROUTE, "cannot route Road Warrior template");
    return FALSE;
    }

    /* if we don't know nexthop, we cannot route */
    if (isanyaddr(&c->this.host_nexthop))
    {
    loglog(RC_ROUTE, "cannot route connection without knowing our nexthop");
    return FALSE;
    }

    /* if routing would affect IKE messages, reject */
    if (!no_klips
#ifdef NAT_TRAVERSAL
    && c->this.host_port != NAT_T_IKE_FLOAT_PORT
#endif
    && c->this.host_port != IKE_UDP_PORT
    && addrinsubnet(&c->that.host_addr, EffectivePeerClient(c)))
    {
    loglog(RC_LOG_SERIOUS, "cannot install route: peer is within its client");
    return FALSE;
    }

    /* 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 FALSE;    /* 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)
    {
    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, ero->eroute_owner);
    return FALSE;    /* another connection already using the eroute */
    }
#endif /* KLIPS */
    return TRUE;
}

bool
trap_connection(struct connection *c)
{
    /* RT_ROUTED_TUNNEL is treated specially: we don't override
     * because we don't want to lose track of the IPSEC_SAs etc.
     */
    return could_route(c)
    && (c->routing == RT_ROUTED_TUNNEL || onlyeroute(c, NULL)); /*zqqa modified*/
}

/* delete any eroute for a connection and unroute it if route isn't shared */
void
unroute_connection(struct connection *c)
{
    enum routing_t cr = c->routing;

    if (erouted(cr))
    {
    passert(cr != RT_ROUTED_TUNNEL);    /* cannot handle a live one */
#ifdef KLIPS
    shunt_eroute(c, ERO_DELETE, "delete");
#endif
    }

    c->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)
    (void) do_command(c, "unroute");
}


#ifdef KLIPS

static void
set_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);
}

static bool
pfkey_build(int error
, const char *description
, const char *text_said
, struct sadb_ext *extensions[SADB_EXT_MAX + 1])
{
    if (error == 0)
    {
    return TRUE;
    }
    else
    {
    loglog(RC_LOG_SERIOUS, "building of %s %s failed, code %d"
        , description, text_said, error);
    pfkey_extensions_free(extensions);
    return FALSE;
    }
}

/* pfkey_extensions_init + pfkey_build + pfkey_msg_hdr_build */
static bool
pfkey_msg_start(u_int8_t msg_type
, u_int8_t satype
, const char *description
, const char *text_said
, struct sadb_ext *extensions[SADB_EXT_MAX + 1])
{
    pfkey_extensions_init(extensions);
    return pfkey_build(pfkey_msg_hdr_build(&extensions[0], msg_type
        , satype, 0, ++pfkey_seq, pid)
    , description, text_said, extensions);
}

/* pfkey_build + pfkey_address_build */
static bool
pfkeyext_address(u_int16_t exttype
, const ip_address *address
, const char *description
, const char *text_said
, struct sadb_ext *extensions[SADB_EXT_MAX + 1])
{
    /* the following variable is only needed to silence
     * a warning caused by the fact that the argument
     * to sockaddrof is NOT pointer to const!
     */
    ip_address t = *address;

    return pfkey_build(pfkey_address_build(extensions + exttype
        , exttype, 0, 0, sockaddrof(&t))
    , description, text_said, extensions);
}

/* Finish (building, sending, accepting response for) PF_KEY message.
 * If response isn't NULL, the response from the kernel will be
 * placed there (and its errno field will not be examined).
 * Returns TRUE iff all appears well.
 */
static bool
finish_pfkey_msg(struct sadb_ext *extensions[SADB_EXT_MAX + 1]
, const char *description
, const char *text_said
, pfkey_buf *response)
{
    struct sadb_msg *pfkey_msg;
    bool success = TRUE;
    int error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_IN);

    if (error != 0)
    {
    loglog(RC_LOG_SERIOUS, "pfkey_msg_build of %s %s failed, code %d"
        , description, text_said, error);
    success = FALSE;
    }
    else
    {
    size_t len = pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN;

    DBG(DBG_KLIPS,
        DBG_log("finish_pfkey_msg: %s message %u for %s %s"
        , sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type)
        , pfkey_msg->sadb_msg_seq
        , description, text_said);
        DBG_dump(NULL, (void *) pfkey_msg, len));

    if (!no_klips)
    {
        ssize_t r = write(pfkeyfd, pfkey_msg, len);

        if (r != (ssize_t)len)
        {
        if (r < 0)
        {
            log("This connection is probably expecting a road warrior or the IP address"
                " of the remote host's DNS hostname has changed");
            log_errno((e
            , "pfkey write() of %s message %u"
              " for %s %s failed"
            , sparse_val_show(pfkey_type_names
                , pfkey_msg->sadb_msg_type)
            , pfkey_msg->sadb_msg_seq
            , description, text_said));
        }
        else
        {
            loglog(RC_LOG_SERIOUS
            , "ERROR: pfkey write() of %s message %u"
              " for %s %s truncated: %ld instead of %ld"
            , sparse_val_show(pfkey_type_names
                , pfkey_msg->sadb_msg_type)
            , pfkey_msg->sadb_msg_seq
            , description, text_said
            , (long)r, (long)len);
        }
        success = FALSE;

        /* if we were compiled with debugging, but we haven't already
         * dumped the KLIPS command, do so.
         */
#ifdef DEBUG
        if ((cur_debugging & DBG_KLIPS) == 0)
            DBG_dump(NULL, (void *) pfkey_msg, len);
#endif
        }
        else
        {
        /* Check response from KLIPS.
         * It ought to be an echo, perhaps with additional info.
         * If the caller wants it, response will point to space.
         */
        pfkey_buf b;
        pfkey_buf *bp = response != NULL? response : &b;

        if (!pfkey_get_response(bp, ((struct sadb_msg *) extensions[0])->sadb_msg_seq))
        {
            loglog(RC_LOG_SERIOUS
            , "ERROR: no response to our PF_KEY %s message for %s %s"
            , sparse

改后的freeswan\pluto\kernel.c(2):【上一篇】
最后一关攻克(应该是最后一关了吧):【下一篇】
【相关文章】
  • 改后的freeswan\pluto\kernel.c(2)
  • freeswan找不到eth设备的问题终极解决
  • 【随机文章】
  • PHP3中文文档 二
  • Samab文件服务器<跟我学系列>
  • 巧妙设定Word启动后的默认文件夹
  • 信息安全,富人当道
  • 在php中取得image按钮传递的name值
  • 学习笔迹续(二)
  • IT人的通病
  • 入侵检测技术综述(4)
  • 很高兴入住博客堂
  • 难忘的爱
  • 【相关评论】
    没有相关评论
    【发表评论】
    姓名:
    邮件:
    随机码*
    评论*
          
    |  首 页  |  版权声明  |  联系我们   |  网站地图  |
    CopyRight © 2004-2007 bbb软讯网络 All Rigths Reserved.