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

📄 kernel_pfkey.c

📁 This a good VPN source
💻 C
📖 第 1 页 / 共 2 页
字号:
/* pfkey interface to the kernel's IPsec mechanism * Copyright (C) 1997 Angelos D. Keromytis. * Copyright (C) 1998-2002  D. Hugh Redelmeier. * Copyright (C) 2003 Herbert Xu. * * 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_pfkey.c,v 1.14 2004/06/01 14:43:20 ken Exp $ */#ifdef KLIPS#include <errno.h>#include <fcntl.h>#include <stddef.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/select.h>#include <sys/time.h>#include <sys/socket.h>#include <sys/types.h>#include <sys/queue.h>#include <openswan.h>#include <pfkeyv2.h>#include <pfkey.h>#include "constants.h"#include "oswlog.h"#include "defs.h"#include "id.h"#include "connections.h"#include "kernel.h"#include "kernel_pfkey.h"#include "log.h"#include "whack.h"	/* for RC_LOG_SERIOUS */#ifdef NAT_TRAVERSAL#include "packet.h"  /* for pb_stream in nat_traversal.h */#include "nat_traversal.h"#endif#include "alg_info.h"#include "kernel_alg.h"static 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;#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 NEvoidinit_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(O_NONBLOCK) in init_pfkeyfd()"));#endif    if (fcntl(pfkeyfd, F_SETFD, FD_CLOEXEC) != 0)	exit_log_errno((e, "fcntl(FD_CLOEXEC) in init_pfkeyfd()"));    DBG(DBG_KLIPS,	DBG_log("process %u listening for PF_KEY_V2 on file descriptor %d", (unsigned)pid, pfkeyfd));}/* 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 boolpfkey_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 boolpfkey_get(pfkey_buf *buf){    for (;;)    {	/* len must be less than PFKEYv2_MAX_MSGSIZE,	 * so it should fit in an int.  We use this fact when printing it.	 */	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))	{	    plog("pfkey_get read truncated PF_KEY message: %d bytes; ignoring message"		, (int) len);	}	else if ((size_t) len != buf->msg.sadb_msg_len * IPSEC_PFKEYv2_ALIGN)	{	    plog("pfkey_get read PF_KEY message with length %d that doesn't equal sadb_msg_len %u * %u; ignoring message"		, (int) len		, (unsigned) buf->msg.sadb_msg_len		, (unsigned) IPSEC_PFKEYv2_ALIGN);	}	else if (!(buf->msg.sadb_msg_pid == (unsigned)pid	/*	for now, unsolicited messages can be: 	 *	SADB_ACQUIRE, SADB_REGISTER, SADB_X_NAT_T_NEW_MAPPING	 */	|| (buf->msg.sadb_msg_pid == 0 && buf->msg.sadb_msg_type == SADB_ACQUIRE)#ifdef KERNEL_ALG	|| (buf->msg.sadb_msg_type == SADB_REGISTER)#endif#ifdef NAT_TRAVERSAL	|| (buf->msg.sadb_msg_pid == 0 && buf->msg.sadb_msg_type == SADB_X_NAT_T_NEW_MAPPING)#endif	))	{	    /* 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 boolpfkey_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 the kernel. * This will be a response to one of ours, but it may be asynchronous * (if kernel modules are loaded and unloaded). * Some sanity checking has already been performed. */static voidklips_pfkey_register_response(const struct sadb_msg *msg){    /* 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 (msg->sadb_msg_satype)    {    case SADB_SATYPE_AH:	break;    case SADB_SATYPE_ESP:#ifdef KERNEL_ALG	kernel_alg_register_pfkey(msg, 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;    }}/* 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 voidprocess_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];    int src_proto = srcx->sadb_address_proto;    int dst_proto = dstx->sadb_address_proto;    ip_address *src = (ip_address*)&srcx[1];    ip_address *dst = (ip_address*)&dstx[1];    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 = src_proto == dst_proto? NULL : "src and dst protocols differ")	&& !(ugh = addrtypeof(src) == addrtypeof(dst)? NULL : "conflicting address types")	&& !(ugh = addrtosubnet(src, &ours))	&& !(ugh = addrtosubnet(dst, &his)))      record_and_initiate_opportunistic(&ours, &his, 0, "%acquire-pfkey");    if (ugh != NULL)	plog("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 voidpfkey_async(pfkey_buf *buf){    struct sadb_ext *extensions[SADB_EXT_MAX + 1];    if (pfkey_msg_parse(&buf->msg, NULL, extensions, EXT_BITS_OUT))    {	plog("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:	    kernel_ops->pfkey_register_response(&buf->msg);	    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 */static voidpfkey_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

⌨️ 快捷键说明

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