Пример #1
0
/*
  The tdb table better be locked before it is handed in, or races might happen
*/
int
ipsec_sa_delchain(struct ipsec_sa *ips)
{
	struct ipsec_sa *tdbdel;
	int error = 0;
        char sa[SATOA_BUF];
	size_t sa_len;

	if(!ips) {
		KLIPS_PRINT(debug_xform,
			    "klips_error:deltdbchain: "
			    "null pointer passed in!\n");
		return -ENODATA;
	}

	sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
	KLIPS_PRINT(debug_xform,
		    "klips_debug:deltdbchain: "
		    "passed SA:%s\n",
		    sa_len ? sa : " (error)");
	while(ips->ips_onext) {
		ips = ips->ips_onext;
	}

	while(ips) {
		/* XXX send a pfkey message up to advise of deleted TDB */
		sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
		KLIPS_PRINT(debug_xform,
			    "klips_debug:deltdbchain: "
			    "unlinking and delting SA:%s",
			    sa_len ? sa : " (error)");
		tdbdel = ips;
		ips = ips->ips_inext;
		if(ips) {
			sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
			KLIPS_PRINT(debug_xform,
				    ", inext=%s",
				    sa_len ? sa : " (error)");
			tdbdel->ips_inext = NULL;
			ips->ips_onext = NULL;
		}
		KLIPS_PRINT(debug_xform,
			    ".\n");
		if((error = ipsec_sa_del(tdbdel))) {
			KLIPS_PRINT(debug_xform,
				    "klips_debug:deltdbchain: "
				    "deltdb returned error %d.\n", -error);
			return error;
		}
		if((error = ipsec_sa_wipe(tdbdel))) {
			KLIPS_PRINT(debug_xform,
				    "klips_debug:deltdbchain: "
				    "ipsec_tdbwipe returned error %d.\n", -error);
			return error;
		}
	}
	return error;
}
Пример #2
0
struct ipsec_sa *
ipsec_sa_getbyid(struct sa_id *said)
{
	int hashval;
	struct ipsec_sa *ips;
        char sa[SATOA_BUF];
	size_t sa_len;

	if(!said) {
		KLIPS_PRINT(debug_xform,
			    "klips_error:gettdb: "
			    "null pointer passed in!\n");
		return NULL;
	}

	sa_len = satoa(*said, 0, sa, SATOA_BUF);

	hashval = (said->spi+said->dst.s_addr+said->proto) % SADB_HASHMOD;
	
	KLIPS_PRINT(debug_xform,
		    "klips_debug:gettdb: "
		    "linked entry in tdb table for hash=%d of SA:%s requested.\n",
		    hashval,
		    sa_len ? sa : " (error)");

	if(!(ips = ipsec_sadb_hash[hashval])) {
		KLIPS_PRINT(debug_xform,
			    "klips_debug:gettdb: "
			    "no entries in tdb table for hash=%d of SA:%s.\n",
			    hashval,
			    sa_len ? sa : " (error)");
		return NULL;
	}

	for (; ips; ips = ips->ips_hnext) {
		if ((ips->ips_said.spi == said->spi) &&
		    (ips->ips_said.dst.s_addr == said->dst.s_addr) &&
		    (ips->ips_said.proto == said->proto)) {
			return ips;
		}
	}
	
	KLIPS_PRINT(debug_xform,
		    "klips_debug:gettdb: "
		    "no entry in linked list for hash=%d of SA:%s.\n",
		    hashval,
		    sa_len ? sa : " (error)");
	return NULL;
}
Пример #3
0
/*
 * IPSEC <> netlink interface
 * Copyright (C) 1996, 1997  John Ioannidis.
 * Copyright (C) 1998, 1999, 2000, 2001  Richard Guy Briggs.
 * 
 * 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.
 */

char ipsec_netlink_c_version[] = "RCSID $Id: ipsec_netlink.c,v 1.56 2002/01/29 17:17:55 mcr Exp $";

#include <linux/config.h>
#include <linux/version.h>
#include <linux/kernel.h> /* printk() */

#include "ipsec_param.h"

#ifdef MALLOC_SLAB
# include <linux/slab.h> /* kmalloc() */
#else /* MALLOC_SLAB */
# include <linux/malloc.h> /* kmalloc() */
#endif /* MALLOC_SLAB */
#include <linux/errno.h>  /* error codes */
#include <linux/types.h>  /* size_t */
#include <linux/interrupt.h> /* mark_bh */

#include <linux/netdevice.h>   /* struct device, and other headers */
#include <linux/etherdevice.h> /* eth_type_trans */
#include <linux/ip.h>          /* struct iphdr */
#include <linux/skbuff.h>
#include <freeswan.h>
#ifdef SPINLOCK
# ifdef SPINLOCK_23
#  include <linux/spinlock.h> /* *lock* */
# else /* 23_SPINLOCK */
#  include <asm/spinlock.h> /* *lock* */
# endif /* 23_SPINLOCK */
#endif /* SPINLOCK */
#ifdef NET_21
# include <asm/uaccess.h>
# include <linux/in6.h>
# define ip_chk_addr inet_addr_type
# define IS_MYADDR RTN_LOCAL
#endif
#include <asm/checksum.h>
#include <net/ip.h>
#ifdef NETLINK_SOCK
# include <linux/netlink.h>
#else
# include <net/netlink.h>
#endif

#include "radij.h"
#include "ipsec_encap.h"
#include "ipsec_radij.h"
#include "ipsec_netlink.h"
#include "ipsec_xform.h"

#include "ipsec_rcv.h"
#include "ipsec_ah.h"
#include "ipsec_esp.h"

#ifdef CONFIG_IPSEC_DEBUG
# include "ipsec_tunnel.h"
#endif /* CONFIG_IPSEC_DEBUG */

#include <pfkeyv2.h>
#include <pfkey.h>

#ifdef CONFIG_IPSEC_DEBUG
 int debug_netlink = 0;
#endif /* CONFIG_IPSEC_DEBUG */

#define SENDERR(_x) do { len = -(_x); goto errlab; } while (0)

#if 0
int 
#ifdef NETLINK_SOCK
ipsec_callback(int proto, struct sk_buff *skb)
#else /* NETLINK_SOCK */
ipsec_callback(struct sk_buff *skb)
#endif /* NETLINK_SOCK */
{
	/*
	 * this happens when we write to /dev/ipsec (c 36 10)
	 */
	int len = skb->len;
	u_char *dat = (u_char *)skb->data;
	struct encap_msghdr *em	= (struct encap_msghdr *)dat;
	struct tdb *tdbp, *tprev;
	int i, nspis, error = 0;
#ifdef CONFIG_IPSEC_DEBUG
	struct eroute *eret;
	char sa[SATOA_BUF];
	size_t sa_len;
	struct sk_buff *first, *last;


	sa_len = satoa(em->em_said, 0, sa, SATOA_BUF);

	if(debug_netlink) {
		printk("klips_debug:ipsec_callback: "
		       "skb=0x%p skblen=%ld em_magic=%d em_type=%d\n",
		       skb,
		       (unsigned long int)skb->len,
		       em->em_magic,
		       em->em_type);
		switch(em->em_type) {
		case EMT_SETDEBUG:
			printk("klips_debug:ipsec_callback: "
			       "set ipsec_debug level\n");
			break;
		case EMT_DELEROUTE:
		case EMT_CLREROUTE:
		case EMT_CLRSPIS:
			break;
		default:
			printk("klips_debug:ipsec_callback: "
			       "called for SA:%s\n",
			       sa_len ? sa : " (error)");
		}
	}
#endif /* CONFIG_IPSEC_DEBUG */

	/* XXXX Temporarily disable netlink I/F code until it gets permanantly
	   ripped out in favour of PF_KEYv2 I/F. */
	SENDERR(EPROTONOSUPPORT);

	/*	em = (struct encap_msghdr *)dat; */
	if (em->em_magic != EM_MAGIC) {
		printk("klips_debug:ipsec_callback: "
		       "bad magic=%d failed, should be %d\n",
		       em->em_magic,
		       EM_MAGIC);
		SENDERR(EINVAL);
	}
	switch (em->em_type) {
	case EMT_SETDEBUG:
#ifdef CONFIG_IPSEC_DEBUG
		if(em->em_db_nl >> (sizeof(em->em_db_nl) * 8 - 1)) {
			em->em_db_nl &= ~(1 << (sizeof(em->em_db_nl) * 8 -1));
			debug_tunnel  |= em->em_db_tn;
			debug_netlink |= em->em_db_nl;
			debug_xform   |= em->em_db_xf;
			debug_eroute  |= em->em_db_er;
			debug_spi     |= em->em_db_sp;
			debug_radij   |= em->em_db_rj;
			debug_esp     |= em->em_db_es;
			debug_ah      |= em->em_db_ah;
			debug_rcv     |= em->em_db_rx;
			debug_pfkey   |= em->em_db_ky;
			if(debug_netlink)
				printk("klips_debug:ipsec_callback: set\n");
		} else {
			if(debug_netlink)
				printk("klips_debug:ipsec_callback: unset\n");
			debug_tunnel  &= em->em_db_tn;
			debug_netlink &= em->em_db_nl;
			debug_xform   &= em->em_db_xf;
			debug_eroute  &= em->em_db_er;
			debug_spi     &= em->em_db_sp;
			debug_radij   &= em->em_db_rj;
			debug_esp     &= em->em_db_es;
			debug_ah      &= em->em_db_ah;
			debug_rcv     &= em->em_db_rx;
			debug_pfkey   &= em->em_db_ky;
		}
#else /* CONFIG_IPSEC_DEBUG */
		printk("klips_debug:ipsec_callback: "
		       "debugging not enabled\n");
		SENDERR(EINVAL);
#endif /* CONFIG_IPSEC_DEBUG */
		break;

	case EMT_SETEROUTE:
		if ((error = ipsec_makeroute(&(em->em_eaddr), &(em->em_emask), em->em_ersaid, 0, NULL, NULL, NULL)))
			SENDERR(-error);
		break;

	case EMT_REPLACEROUTE:
		if ((error = ipsec_breakroute(&(em->em_eaddr), &(em->em_emask), &first, &last)) == EINVAL) {
			kfree_skb(first);
			kfree_skb(last);
			SENDERR(-error);
		}
		if ((error = ipsec_makeroute(&(em->em_eaddr), &(em->em_emask), em->em_ersaid, NULL, NULL)))
			SENDERR(-error);
		break;

	case EMT_DELEROUTE:
		if ((error = ipsec_breakroute(&(em->em_eaddr), &(em->em_emask), &first, &last)))
			kfree_skb(first);
			kfree_skb(last);
			SENDERR(-error);
		break;

	case EMT_CLREROUTE:
		if ((error = ipsec_cleareroutes()))
			SENDERR(-error);
		break;

	case EMT_SETSPI:
		if (em->em_if >= 5)	/* XXX -- why 5? */
			SENDERR(ENODEV);
		
		tdbp = gettdb(&(em->em_said));
		if (tdbp == NULL) {
			tdbp = (struct tdb *)kmalloc(sizeof (*tdbp), GFP_ATOMIC);

			if (tdbp == NULL)
				SENDERR(ENOBUFS);
			
			memset((caddr_t)tdbp, 0, sizeof(*tdbp));
			
			tdbp->tdb_said = em->em_said;
			tdbp->tdb_flags = em->em_flags;
			
			if(ip_chk_addr((unsigned long)em->em_said.dst.s_addr) == IS_MYADDR) {
				tdbp->tdb_flags |= EMT_INBOUND;
			}
			KLIPS_PRINT(debug_netlink & DB_NL_TDBCB,
				    "klips_debug:ipsec_callback: "
				    "existing Tunnel Descriptor Block not found (this is good) for SA: %s, %s-bound, allocating.\n",
				    sa_len ? sa : " (error)",
				    (tdbp->tdb_flags & EMT_INBOUND) ? "in" : "out");

/* XXX  		tdbp->tdb_rcvif = &(enc_softc[em->em_if].enc_if);*/
			tdbp->tdb_rcvif = NULL;
		} else {
			KLIPS_PRINT(debug_netlink & DB_NL_TDBCB,
				    "klips_debug:ipsec_callback: "
				    "EMT_SETSPI found an old Tunnel Descriptor Block for SA: %s, delete it first.\n",
				    sa_len ? sa : " (error)");
			SENDERR(EEXIST);
		}
		
		if ((error = tdb_init(tdbp, em))) {
			KLIPS_PRINT(debug_netlink & DB_NL_TDBCB,
				    "klips_debug:ipsec_callback: "
				    "EMT_SETSPI not successful for SA: %s, deleting.\n",
				    sa_len ? sa : " (error)");
			ipsec_tdbwipe(tdbp);
			
			SENDERR(-error);
		}

		tdbp->tdb_lifetime_addtime_c = jiffies/HZ;
		tdbp->tdb_state = 1;
		if(!tdbp->tdb_lifetime_allocations_c) {
			tdbp->tdb_lifetime_allocations_c += 1;
		}

		puttdb(tdbp);
		KLIPS_PRINT(debug_netlink & DB_NL_TDBCB,
			    "klips_debug:ipsec_callback: "
			    "EMT_SETSPI successful for SA: %s\n",
			    sa_len ? sa : " (error)");
		break;
		
	case EMT_DELSPI:
		if (em->em_if >= 5)	/* XXX -- why 5? */
			SENDERR(ENODEV);
		
		spin_lock_bh(&tdb_lock);
		
		tdbp = gettdb(&(em->em_said));
		if (tdbp == NULL) {
			KLIPS_PRINT(debug_netlink & DB_NL_TDBCB,
				    "klips_debug:ipsec_callback: "
				    "EMT_DELSPI Tunnel Descriptor Block not found for SA%s, could not delete.\n",
				    sa_len ? sa : " (error)");
			spin_unlock_bh(&tdb_lock);
			SENDERR(ENXIO);  /* XXX -- wrong error message... */
		} else {
			if((error = deltdbchain(tdbp))) {
				spin_unlock_bh(&tdb_lock);
				SENDERR(-error);
			}
		}
		spin_unlock_bh(&tdb_lock);

		break;
		
	case EMT_GRPSPIS:
		nspis = (len - EMT_GRPSPIS_FLEN) / sizeof(em->em_rel[0]);
		if ((nspis * (sizeof(em->em_rel[0]))) != (len - EMT_GRPSPIS_FLEN)) {
			printk("klips_debug:ipsec_callback: "
			       "EMT_GRPSPI message size incorrect, expected nspis(%d)*%d, got %d.\n",
			       nspis,
			       sizeof(em->em_rel[0]),
			       (len - EMT_GRPSPIS_FLEN));
			SENDERR(EINVAL);
			break;
		}
		
		spin_lock_bh(&tdb_lock);

		for (i = 0; i < nspis; i++) {
			KLIPS_PRINT(debug_netlink,
				    "klips_debug:ipsec_callback: "
				    "EMT_GRPSPI for SA(%d) %s,\n",
				    i,
				    sa_len ? sa : " (error)");
			if ((tdbp = gettdb(&(em->em_rel[i].emr_said))) == NULL) {
				KLIPS_PRINT(debug_netlink,
					    "klips_debug:ipsec_callback: "
					    "EMT_GRPSPI Tunnel Descriptor Block not found for SA%s, could not group.\n",
					    sa_len ? sa : " (error)");
				spin_unlock_bh(&tdb_lock);
				SENDERR(ENXIO);
			} else {
				if(tdbp->tdb_inext || tdbp->tdb_onext) {
					KLIPS_PRINT(debug_netlink,
						    "klips_debug:ipsec_callback: "
						    "EMT_GRPSPI Tunnel Descriptor Block already grouped for SA: %s, can't regroup.\n",
						    sa_len ? sa : " (error)");
					spin_unlock_bh(&tdb_lock);
					SENDERR(EBUSY);
				}
				em->em_rel[i].emr_tdb = tdbp;
			}
		}
		tprev = em->em_rel[0].emr_tdb;
		tprev->tdb_inext = NULL;
		for (i = 1; i < nspis; i++) {
			tdbp = em->em_rel[i].emr_tdb;
			tprev->tdb_onext = tdbp;
			tdbp->tdb_inext = tprev;
			tprev = tdbp;
		}
		tprev->tdb_onext = NULL;

		spin_unlock_bh(&tdb_lock);

		error = 0;
		break;
		
	case EMT_UNGRPSPIS:
		if (len != (8 + (sizeof(struct sa_id) + sizeof(struct tdb *)) /* 12 */) ) {
			printk("klips_debug:ipsec_callback: "
			       "EMT_UNGRPSPIS message size incorrect, expected %d, got %d.\n",
			       8 + (sizeof(struct sa_id) + sizeof(struct tdb *)),
				    len);
			SENDERR(EINVAL);
			break;
		}
		
		spin_lock_bh(&tdb_lock);

		if ((tdbp = gettdb(&(em->em_rel[0].emr_said))) == NULL) {
			KLIPS_PRINT(debug_netlink,
				    "klips_debug:ipsec_callback: "
				    "EMT_UGRPSPI Tunnel Descriptor Block not found for SA%s, could not ungroup.\n",
				    sa_len ? sa : " (error)");
			spin_unlock_bh(&tdb_lock);
			SENDERR(ENXIO);
		}
		while(tdbp->tdb_onext) {
			tdbp = tdbp->tdb_onext;
		}
		while(tdbp->tdb_inext) {
			tprev = tdbp;
			tdbp = tdbp->tdb_inext;
			tprev->tdb_inext = NULL;
			tdbp->tdb_onext = NULL;
		}

		spin_unlock_bh(&tdb_lock);

		break;
		
	case EMT_CLRSPIS:
		KLIPS_PRINT(debug_netlink,
			    "klips_debug:ipsec_callback: "
			    "spi clear called.\n");
		if (em->em_if >= 5)	/* XXX -- why 5? */
			SENDERR(ENODEV);
		ipsec_tdbcleanup(0);
		break;
	default:
		KLIPS_PRINT(debug_netlink,
			    "klips_debug:ipsec_callback: "
			    "unknown message type\n");
		SENDERR(EINVAL);
	}
Пример #4
0
int 
ipsec_sadb_cleanup(__u8 proto)
{
	int i;
	int error = 0;
	struct ipsec_sa *ips, **ipsprev, *tdbdel;
        char sa[SATOA_BUF];
	size_t sa_len;

	KLIPS_PRINT(debug_xform,
		    "klips_debug:ipsec_tdbcleanup: "
		    "cleaning up proto=%d.\n",
		    proto);

	spin_lock_bh(&tdb_lock);

	for (i = 0; i < SADB_HASHMOD; i++) {
		ipsprev = &(ipsec_sadb_hash[i]);
		ips = ipsec_sadb_hash[i];
		for(; ips;) {
			sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
			KLIPS_PRINT(debug_xform,
				    "klips_debug:ipsec_tdbcleanup: "
				    "checking SA:%s, hash=%d",
				    sa_len ? sa : " (error)",
				    i);
			tdbdel = ips;
			ips = tdbdel->ips_hnext;
			if(ips) {
				sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
				KLIPS_PRINT(debug_xform,
					    ", hnext=%s",
					    sa_len ? sa : " (error)");
			}
			if(*ipsprev) {
				sa_len = satoa((*ipsprev)->ips_said, 0, sa, SATOA_BUF);
				KLIPS_PRINT(debug_xform,
					    ", *ipsprev=%s",
					    sa_len ? sa : " (error)");
				if((*ipsprev)->ips_hnext) {
					sa_len = satoa((*ipsprev)->ips_hnext->ips_said, 0, sa, SATOA_BUF);
					KLIPS_PRINT(debug_xform,
						    ", *ipsprev->ips_hnext=%s",
						    sa_len ? sa : " (error)");
				}
			}
			KLIPS_PRINT(debug_xform,
				    ".\n");
			if(!proto || (proto == tdbdel->ips_said.proto)) {
				sa_len = satoa(tdbdel->ips_said, 0, sa, SATOA_BUF);
				KLIPS_PRINT(debug_xform,
					    "klips_debug:ipsec_tdbcleanup: "
					    "deleting SA chain:%s.\n",
					    sa_len ? sa : " (error)");
				if((error = ipsec_sa_delchain(tdbdel))) {
					SENDERR(-error);
				}
				ipsprev = &(ipsec_sadb_hash[i]);
				ips = ipsec_sadb_hash[i];

				KLIPS_PRINT(debug_xform,
					    "klips_debug:ipsec_tdbcleanup: "
					    "deleted SA chain:%s",
					    sa_len ? sa : " (error)");
				if(ips) {
					sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
					KLIPS_PRINT(debug_xform,
						    ", tdbh[%d]=%s",
						    i,
						    sa_len ? sa : " (error)");
				}
				if(*ipsprev) {
					sa_len = satoa((*ipsprev)->ips_said, 0, sa, SATOA_BUF);
					KLIPS_PRINT(debug_xform,
						    ", *ipsprev=%s",
						    sa_len ? sa : " (error)");
					if((*ipsprev)->ips_hnext) {
						sa_len = satoa((*ipsprev)->ips_hnext->ips_said, 0, sa, SATOA_BUF);
						KLIPS_PRINT(debug_xform,
							    ", *ipsprev->ips_hnext=%s",
							    sa_len ? sa : " (error)");
					}
				}
				KLIPS_PRINT(debug_xform,
					    ".\n");
			} else {
				ipsprev = &tdbdel;
			}
		}
	}
 errlab:

	spin_unlock_bh(&tdb_lock);

	return(error);
}
Пример #5
0
/*
  The tdb table better be locked before it is handed in, or races might happen
*/
int
ipsec_sa_del(struct ipsec_sa *ips)
{
	unsigned int hashval;
	struct ipsec_sa *tdbtp;
        char sa[SATOA_BUF];
	size_t sa_len;

	if(!ips) {
		KLIPS_PRINT(debug_xform,
			    "klips_error:deltdb: "
			    "null pointer passed in!\n");
		return -ENODATA;
	}
	
	sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
	if(ips->ips_inext || ips->ips_onext) {
		KLIPS_PRINT(debug_xform,
			    "klips_error:deltdb: "
			    "SA:%s still linked!\n",
			    sa_len ? sa : " (error)");
		return -EMLINK;
	}
	
	hashval = ((ips->ips_said.spi + ips->ips_said.dst.s_addr + ips->ips_said.proto) % SADB_HASHMOD);
	
	KLIPS_PRINT(debug_xform,
		    "klips_debug:deltdb: "
		    "deleting SA:%s, hashval=%d.\n",
		    sa_len ? sa : " (error)",
		    hashval);
	if(!ipsec_sadb_hash[hashval]) {
		KLIPS_PRINT(debug_xform,
			    "klips_debug:deltdb: "
			    "no entries in tdb table for hash=%d of SA:%s.\n",
			    hashval,
			    sa_len ? sa : " (error)");
		return -ENOENT;
	}
	
	if (ips == ipsec_sadb_hash[hashval]) {
		ipsec_sadb_hash[hashval] = ipsec_sadb_hash[hashval]->ips_hnext;
		ips->ips_hnext = NULL;
		KLIPS_PRINT(debug_xform,
			    "klips_debug:deltdb: "
			    "successfully deleted first tdb in chain.\n");
		return 0;
	} else {
		for (tdbtp = ipsec_sadb_hash[hashval];
		     tdbtp;
		     tdbtp = tdbtp->ips_hnext) {
			if (tdbtp->ips_hnext == ips) {
				tdbtp->ips_hnext = ips->ips_hnext;
				ips->ips_hnext = NULL;
				KLIPS_PRINT(debug_xform,
					    "klips_debug:deltdb: "
					    "successfully deleted link in tdb chain.\n");
				return 0;
			}
		}
	}
	
	KLIPS_PRINT(debug_xform,
		    "klips_debug:deltdb: "
		    "no entries in linked list for hash=%d of SA:%s.\n",
		    hashval,
		    sa_len ? sa : " (error)");
	return -ENOENT;
}