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

📄 kernel_netlink.c

📁 This a good VPN source
💻 C
📖 第 1 页 / 共 2 页
字号:
/* netlink interface to the kernel's IPsec mechanism * 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_netlink.c,v 1.20 2004/09/07 19:00:15 ken Exp $ */#if defined(linux) && defined(KERNEL26_SUPPORT)#include <errno.h>#include <fcntl.h>#include <string.h>#include <sys/queue.h>#include <sys/socket.h>#include <sys/types.h>#include <sys/queue.h>#include <unistd.h>#include "kameipsec.h"#include <rtnetlink.h>#include <xfrm.h>#include <openswan.h>#include <pfkeyv2.h>#include <pfkey.h>#include "constants.h"#include "defs.h"#include "id.h"#include "connections.h"#include "kernel.h"#include "kernel_netlink.h"#include "kernel_pfkey.h"#include "log.h"#include "whack.h"	/* for RC_LOG_SERIOUS */#include "kernel_alg.h"#ifdef XAUTH_USEPAM#include <security/pam_appl.h>#endif/* Minimum priority number in SPD used by pluto. */#define MIN_SPD_PRIORITY 1024static int netlinkfd = NULL_FD;static int netlink_bcast_fd = NULL_FD;#define NE(x) { x, #x }	/* Name Entry -- shorthand for sparse_names */static sparse_names xfrm_type_names = {	NE(NLMSG_NOOP),	NE(NLMSG_ERROR),	NE(NLMSG_DONE),	NE(NLMSG_OVERRUN),	NE(XFRM_MSG_NEWSA),	NE(XFRM_MSG_DELSA),	NE(XFRM_MSG_GETSA),	NE(XFRM_MSG_NEWPOLICY),	NE(XFRM_MSG_DELPOLICY),	NE(XFRM_MSG_GETPOLICY),	NE(XFRM_MSG_ALLOCSPI),	NE(XFRM_MSG_ACQUIRE),	NE(XFRM_MSG_EXPIRE),	NE(XFRM_MSG_UPDPOLICY),	NE(XFRM_MSG_UPDSA),	NE(XFRM_MSG_POLEXPIRE),	NE(XFRM_MSG_MAX),	{ 0, sparse_end }};#undef NE/** Authentication Algs */static sparse_names aalg_list = {	{ SADB_X_AALG_NULL, "digest_null" },	{ SADB_AALG_MD5HMAC, "md5" },	{ SADB_AALG_SHA1HMAC, "sha1" },	{ SADB_X_AALG_SHA2_256HMAC, "sha256" },	{ SADB_X_AALG_RIPEMD160HMAC, "ripemd160" },	{ 0, sparse_end }};/** Encryption algs */static sparse_names ealg_list = {	{ SADB_EALG_NULL, "cipher_null" },	{ SADB_EALG_DESCBC, "des" },	{ SADB_EALG_3DESCBC, "des3_ede" },	{ SADB_X_EALG_CASTCBC, "cast128" },	{ SADB_X_EALG_BLOWFISHCBC, "blowfish" },	{ SADB_X_EALG_AESCBC, "aes" },	{ 0, sparse_end }};/** Compress Algs */static sparse_names calg_list = {	{ SADB_X_CALG_DEFLATE, "deflate" },	{ SADB_X_CALG_LZS, "lzs" },	{ SADB_X_CALG_LZJH, "lzjh" },	{ 0, sparse_end }};/** ip2xfrm - Take an IP address and convert to an xfrm. * * @param addr ip_address * @param xaddr xfrm_address_t - IPv[46] Address from addr is copied here. */static void ip2xfrm(const ip_address *addr, xfrm_address_t *xaddr){    /* If it's an IPv4 address */    if (addr->u.v4.sin_family == AF_INET)    {	xaddr->a4 = addr->u.v4.sin_addr.s_addr;    }    else  /* Must be IPv6 */    {	memcpy(xaddr->a6, &addr->u.v6.sin6_addr, sizeof(xaddr->a6));    }}/** init_netlink - Initialize the netlink inferface.  Opens the sockets and * then binds to the broadcast socket. */static void init_netlink(void){    struct sockaddr_nl addr;    netlinkfd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_XFRM);    if (netlinkfd < 0)	exit_log_errno((e, "socket() in init_netlink()"));    if (fcntl(netlinkfd, F_SETFD, FD_CLOEXEC) != 0)	exit_log_errno((e, "fcntl(FD_CLOEXEC) in init_netlink()"));    netlink_bcast_fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_XFRM);    if (netlink_bcast_fd < 0)	exit_log_errno((e, "socket() for bcast in init_netlink()"));    if (fcntl(netlink_bcast_fd, F_SETFD, FD_CLOEXEC) != 0)	exit_log_errno((e, "fcntl(FD_CLOEXEC) for bcast in init_netlink()"));    if (fcntl(netlink_bcast_fd, F_SETFL, O_NONBLOCK) != 0)	exit_log_errno((e, "fcntl(O_NONBLOCK) for bcast in init_netlink()"));    addr.nl_family = AF_NETLINK;    addr.nl_pid = getpid();    addr.nl_groups = XFRMGRP_ACQUIRE | XFRMGRP_EXPIRE;    if (bind(netlink_bcast_fd, (struct sockaddr *)&addr, sizeof(addr)) != 0)	exit_log_errno((e, "Failed to bind bcast socket in init_netlink()"));}/** send_netlink_msg * * @param hdr - Data to be sent. * @param rbuf - Return Buffer - contains data returned from the send. * @param rbuf_len - Length of rbuf * @param description - String - user friendly description of what is  *                      being attempted.  Used for diagnostics * @param text_said - String * @return bool True if the message was succesfully sent. */static boolsend_netlink_msg(struct nlmsghdr *hdr, struct nlmsghdr *rbuf, size_t rbuf_len, const char *description, const char *text_said){    struct {	struct nlmsghdr n;	struct nlmsgerr e;	char data[1024];    } rsp;    size_t len;    ssize_t r;    struct sockaddr_nl addr;    static uint32_t seq;    if (no_klips)    {	return TRUE;    }    hdr->nlmsg_seq = ++seq;    len = hdr->nlmsg_len;    do {	r = write(netlinkfd, hdr, len);    } while (r < 0 && errno == EINTR);    if (r < 0)    {	log_errno((e	    , "netlink write() of %s message"	      " for %s %s failed"	    , sparse_val_show(xfrm_type_names, hdr->nlmsg_type)	    , description, text_said));	return FALSE;    }    else if ((size_t)r != len)    {	loglog(RC_LOG_SERIOUS	    , "ERROR: netlink write() of %s message"	      " for %s %s truncated: %ld instead of %lu"	    , sparse_val_show(xfrm_type_names, hdr->nlmsg_type)	    , description, text_said	    , (long)r, (unsigned long)len);	return FALSE;    }    for (;;) {	socklen_t alen;	alen = sizeof(addr);	r = recvfrom(netlinkfd, &rsp, sizeof(rsp), 0	    , (struct sockaddr *)&addr, &alen);	if (r < 0)	{	    if (errno == EINTR)	    {		continue;	    }	    log_errno((e		, "netlink recvfrom() of response to our %s message"		  " for %s %s failed"		, sparse_val_show(xfrm_type_names, hdr->nlmsg_type)		, description, text_said));	    return FALSE;	}	else if ((size_t) r < sizeof(rsp.n))	{	    openswan_log("netlink read truncated message: %ld bytes; ignore message"		, (long) r);	    continue;	}	else if (addr.nl_pid != 0)	{	    /* not for us: ignore */	    DBG(DBG_KLIPS,		DBG_log("netlink: ignoring %s message from process %u"		    , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type)		    , addr.nl_pid));	    continue;	}	else if (rsp.n.nlmsg_seq != seq)	{	    DBG(DBG_KLIPS,		DBG_log("netlink: ignoring out of sequence (%u/%u) message %s"		    , rsp.n.nlmsg_seq, seq		    , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type)));	    continue;	}	break;    }    if (rsp.n.nlmsg_len > (size_t) r)    {	loglog(RC_LOG_SERIOUS	    , "netlink recvfrom() of response to our %s message"	      " for %s %s was truncated: %ld instead of %lu"	    , sparse_val_show(xfrm_type_names, hdr->nlmsg_type)	    , description, text_said	    , (long) len, (unsigned long) rsp.n.nlmsg_len);	return FALSE;    }    else if (rsp.n.nlmsg_type != NLMSG_ERROR    && (rbuf && rsp.n.nlmsg_type != rbuf->nlmsg_type))    {	loglog(RC_LOG_SERIOUS	    , "netlink recvfrom() of response to our %s message"	      " for %s %s was of wrong type (%s)"	    , sparse_val_show(xfrm_type_names, hdr->nlmsg_type)	    , description, text_said	    , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type));	return FALSE;    }    else if (rbuf)    {	if ((size_t) r > rbuf_len)	{	    loglog(RC_LOG_SERIOUS		, "netlink recvfrom() of response to our %s message"		  " for %s %s was too long: %ld > %lu"		, sparse_val_show(xfrm_type_names, hdr->nlmsg_type)		, description, text_said		, (long)r, (unsigned long)rbuf_len);	    return FALSE;	}	memcpy(rbuf, &rsp, r);	return TRUE;    }    else if (rsp.n.nlmsg_type == NLMSG_ERROR && rsp.e.error)    {	loglog(RC_LOG_SERIOUS	    , "ERROR: netlink response for %s %s included errno %d: %s"	    , description, text_said	    , -rsp.e.error	    , strerror(-rsp.e.error));	return FALSE;    }    return TRUE;}/** netlink_policy -  * * @param hdr - Data to check * @param enoent_ok - Boolean - OK or not OK. * @param text_said - String * @return boolean  */static boolnetlink_policy(struct nlmsghdr *hdr, bool enoent_ok, const char *text_said){    struct {	struct nlmsghdr n;	struct nlmsgerr e;    } rsp;    int error;    rsp.n.nlmsg_type = NLMSG_ERROR;    if (!send_netlink_msg(hdr, &rsp.n, sizeof(rsp), "policy", text_said))    {	return FALSE;    }    error = -rsp.e.error;    if (!error)    {	return TRUE;    }    if (error == ENOENT && enoent_ok)    {	return TRUE;    }    loglog(RC_LOG_SERIOUS	, "ERROR: netlink %s response for flow %s included errno %d: %s"	, sparse_val_show(xfrm_type_names, hdr->nlmsg_type)	, text_said	, error	, strerror(error));    return FALSE;}/** netlink_raw_eroute * * @param this_host ip_address * @param this_client ip_subnet * @param that_host ip_address * @param that_client ip_subnet * @param spi * @param proto int (Currently unused) Contains protocol (u=tcp, 17=udp, etc...) * @param transport_proto int (Currently unused) 0=tunnel, 1=transport * @param satype int * @param proto_info  * @param lifetime (Currently unused) * @param ip int  * @return boolean True if successful  */static boolnetlink_raw_eroute(const ip_address *this_host		   , const ip_subnet *this_client		   , const ip_address *that_host		   , const ip_subnet *that_client		   , ipsec_spi_t spi		   , unsigned int proto UNUSED		   , unsigned int transport_proto UNUSED		   , unsigned int satype		   , const struct pfkey_proto_info *proto_info		   , time_t use_lifetime UNUSED		   , unsigned int op		   , const char *text_said){    struct {	struct nlmsghdr n;	union {	    struct xfrm_userpolicy_info p;	    struct xfrm_userpolicy_id id;	} u;	char data[1024];    } req;    int shift;    int dir;    int family;    int policy;    bool ok;    bool enoent_ok;    policy = IPSEC_POLICY_IPSEC;    if (satype == SADB_X_SATYPE_INT)    {	/* shunt route */	switch (ntohl(spi))	{	case SPI_PASS:	    policy = IPSEC_POLICY_NONE;	    break;	case SPI_DROP:	case SPI_REJECT:	default:	    policy = IPSEC_POLICY_DISCARD;	    break;	case SPI_TRAP:	case SPI_TRAPSUBNET:	case SPI_HOLD:	    if (op & (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT))	    {		return TRUE;	    }	    break;	}    }    memset(&req, 0, sizeof(req));    req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;    family = that_client->addr.u.v4.sin_family;    shift = (family == AF_INET) ? 5 : 7;    req.u.p.sel.sport = portof(&this_client->addr);    req.u.p.sel.dport = portof(&that_client->addr);    req.u.p.sel.sport_mask = (req.u.p.sel.sport) ? ~0:0;    req.u.p.sel.dport_mask = (req.u.p.sel.dport) ? ~0:0;    ip2xfrm(&this_client->addr, &req.u.p.sel.saddr);    ip2xfrm(&that_client->addr, &req.u.p.sel.daddr);    req.u.p.sel.prefixlen_s = this_client->maskbits;    req.u.p.sel.prefixlen_d = that_client->maskbits;    req.u.p.sel.proto = transport_proto;    req.u.p.sel.family = family;    dir = XFRM_POLICY_OUT;    if (op & (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT))    {	dir = XFRM_POLICY_IN;    }    if ((op & ERO_MASK) == ERO_DELETE)    {	req.u.id.dir = dir;	req.n.nlmsg_type = XFRM_MSG_DELPOLICY;	req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.u.id)));    }    else    {    	int src, dst;	req.u.p.dir = dir;    	src = req.u.p.sel.prefixlen_s;    	dst = req.u.p.sel.prefixlen_d;	if (dir != XFRM_POLICY_OUT) {	    src = req.u.p.sel.prefixlen_d;	    dst = req.u.p.sel.prefixlen_s;	}	req.u.p.priority = MIN_SPD_PRIORITY	    + (((2 << shift) - src) << shift)	    + (2 << shift) - dst;	req.u.p.action = XFRM_POLICY_ALLOW;	if (policy == IPSEC_POLICY_DISCARD)	{	    req.u.p.action = XFRM_POLICY_BLOCK;	}	req.u.p.lft.soft_use_expires_seconds = use_lifetime;	req.u.p.lft.soft_byte_limit = XFRM_INF;	req.u.p.lft.soft_packet_limit = XFRM_INF;	req.u.p.lft.hard_byte_limit = XFRM_INF;	req.u.p.lft.hard_packet_limit = XFRM_INF;	req.n.nlmsg_type = XFRM_MSG_NEWPOLICY;	if (op & (SADB_X_SAFLAGS_REPLACEFLOW << ERO_FLAG_SHIFT))	{	    req.n.nlmsg_type = XFRM_MSG_UPDPOLICY;	}	req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.u.p)));    }    if (policy == IPSEC_POLICY_IPSEC && (op & ERO_MASK) != ERO_DELETE)    {	struct rtattr *attr;	struct xfrm_user_tmpl tmpl[4];	int i;	memset(tmpl, 0, sizeof(tmpl));	for (i = 0; proto_info[i].proto; i++)	{	    tmpl[i].reqid = proto_info[i].reqid;	    tmpl[i].id.proto = proto_info[i].proto;	    tmpl[i].optional = proto_info[i].proto == IPPROTO_COMP;	    tmpl[i].aalgos = tmpl[i].ealgos = tmpl[i].calgos = ~0;	    tmpl[i].mode =		proto_info[i].encapsulation == ENCAPSULATION_MODE_TUNNEL;	    if (!tmpl[i].mode)	    {		continue;	    }	    ip2xfrm(this_host, &tmpl[i].saddr);	    ip2xfrm(that_host, &tmpl[i].id.daddr);	}	attr = (struct rtattr *)((char *)&req + req.n.nlmsg_len);	attr->rta_type = XFRMA_TMPL;	attr->rta_len = i * sizeof(tmpl[0]);	memcpy(RTA_DATA(attr), tmpl, attr->rta_len);	attr->rta_len = RTA_LENGTH(attr->rta_len);	req.n.nlmsg_len += attr->rta_len;    }    enoent_ok = FALSE;    if (op == ERO_DEL_INBOUND)    {	enoent_ok = TRUE;    }    else if (op == ERO_DELETE && ntohl(spi) == SPI_HOLD)    {	enoent_ok = TRUE;    }    ok = netlink_policy(&req.n, enoent_ok, text_said);    switch (dir)    {    case XFRM_POLICY_IN:	if (req.n.nlmsg_type == XFRM_MSG_DELPOLICY)	{	    req.u.id.dir = XFRM_POLICY_FWD;	}	else if (!ok)

⌨️ 快捷键说明

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