diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1997-02-20 01:08:13 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1997-02-20 01:08:13 +0000 |
commit | 27f7e7b789913e142fd048ad0f5e9fe6fee94c27 (patch) | |
tree | 92f475f4da1f7ac2c6a9fac20881c666173e7600 /sys/netinet/ip_ipsp.c | |
parent | 64c38b22e9e85f411969b697297f6dfd609dc83c (diff) |
IPSEC package by John Ioannidis and Angelos D. Keromytis. Written in
Greece. From ftp.funet.fi:/pub/unix/security/net/ip/BSDipsec.tar.gz
Diffstat (limited to 'sys/netinet/ip_ipsp.c')
-rw-r--r-- | sys/netinet/ip_ipsp.c | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/sys/netinet/ip_ipsp.c b/sys/netinet/ip_ipsp.c new file mode 100644 index 00000000000..390745def98 --- /dev/null +++ b/sys/netinet/ip_ipsp.c @@ -0,0 +1,259 @@ +/* + * The author of this code is John Ioannidis, ji@tla.org, + * (except when noted otherwise). + * + * This code was written for BSD/OS in Athens, Greece, in November 1995. + * + * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996, + * by Angelos D. Keromytis, kermit@forthnet.gr. + * + * Copyright (C) 1995, 1996, 1997 by John Ioannidis and Angelos D. Keromytis. + * + * Permission to use, copy, and modify this software without fee + * is hereby granted, provided that this entire notice is included in + * all copies of any software which is or includes a copy or + * modification of this software. + * + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTY. IN PARTICULAR, NEITHER AUTHOR MAKES ANY + * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE + * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR + * PURPOSE. + */ + +/* + * IPSP Processing + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/domain.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/errno.h> +#include <sys/time.h> +#include <sys/kernel.h> + +#include <net/if.h> +#include <net/route.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/in_pcb.h> +#include <netinet/in_var.h> +#include <netinet/ip_var.h> +#include <netinet/ip_icmp.h> + +#include <net/raw_cb.h> +#include <net/encap.h> + +#define IPSEC_IPSP_C +#include <netinet/ip_ipsp.h> +#undef IPSEC_IPSP_C +#include <netinet/ip_ah.h> +#include <netinet/ip_esp.h> + +#ifdef ENCDEBUG +int encdebug = 1; +#endif + +/* + * This is the proper place to define the various encapsulation transforms. + * CAUTION: the human-readable string should be LESS than 200 bytes if the + * kernfs is to work properly. + */ + +struct xformsw xformsw[] = { +{ XF_IP4, 0, "IPv4 Simple Encapsulation", + ipe4_attach, ipe4_init, ipe4_zeroize, + (struct mbuf * (*)(struct mbuf *, struct tdb *))ipe4_input, ipe4_output, }, +{ XF_AHMD5, XFT_AUTH, "Keyed MD5 Authentication", + ahmd5_attach, ahmd5_init, ahmd5_zeroize, + ahmd5_input, ahmd5_output, }, +{ XF_ESPDES, XFT_CONF, "DES-CBC Encryption", + espdes_attach, espdes_init, espdes_zeroize, + espdes_input, espdes_output, }, +{ XF_AHHMACMD5, XFT_AUTH, "HMAC MD5 Authentication", + ahhmacmd5_attach, ahhmacmd5_init, ahhmacmd5_zeroize, + ahhmacmd5_input, ahhmacmd5_output, }, +{ XF_AHHMACSHA1, XFT_AUTH, "HMAC SHA1 Authentication", + ahhmacsha1_attach, ahhmacsha1_init, ahhmacsha1_zeroize, + ahhmacsha1_input, ahhmacsha1_output, }, +{ XF_ESPDESMD5, XFT_CONF, "DES-CBC Encryption + MD5 Authentication", + espdesmd5_attach, espdesmd5_init, espdesmd5_zeroize, + espdesmd5_input, espdesmd5_output, }, +{ XF_ESP3DESMD5, XFT_CONF, "3DES-CBC Encryption + MD5 Authentication", + esp3desmd5_attach, esp3desmd5_init, esp3desmd5_zeroize, + esp3desmd5_input, esp3desmd5_output, }, +}; + +struct xformsw *xformswNXFORMSW = &xformsw[sizeof(xformsw)/sizeof(xformsw[0])]; + +unsigned char ipseczeroes[IPSEC_ZEROES_SIZE]; /* zeroes! */ + +static char *ipspkernfs = NULL; +static int ipspkernfs_len = 0; +int ipspkernfs_dirty = 1; + +/* + * An IPSP SAID is really the concatenation of the SPI found in the + * packet and the destination address of the packet. When we receive + * an IPSP packet, we need to look up its tunnel descriptor block, + * based on the SPI in the packet and the destination address (which is + * really one of our addresses if we received the packet! + */ + +struct tdb * +gettdb(u_long spi, struct in_addr dst) +{ + int hashval; + struct tdb *tdbp; + + hashval = (spi+dst.s_addr) % TDB_HASHMOD; + + for (tdbp = tdbh[hashval]; tdbp; tdbp = tdbp->tdb_hnext) + if ((tdbp->tdb_spi == spi) && (tdbp->tdb_dst.s_addr == dst.s_addr)) + break; + + return tdbp; +} + +void +puttdb(struct tdb *tdbp) +{ + int hashval; + hashval = ((tdbp->tdb_spi + tdbp->tdb_dst.s_addr) % TDB_HASHMOD); + tdbp->tdb_hnext = tdbh[hashval]; + tdbh[hashval] = tdbp; + ipspkernfs_dirty = 1; +} + +int +tdb_delete(struct tdb *tdbp, int delchain) +{ + struct tdb *tdbpp; + int hashval; + + hashval = ((tdbp->tdb_spi + tdbp->tdb_dst.s_addr) % TDB_HASHMOD); + + if (tdbh[hashval] == tdbp) + { + tdbpp = tdbp; + tdbh[hashval] = tdbp->tdb_hnext; + } + else + for (tdbpp = tdbh[hashval]; tdbpp != NULL; tdbpp = tdbpp->tdb_hnext) + if (tdbpp->tdb_hnext == tdbp) + { + tdbpp->tdb_hnext = tdbp->tdb_hnext; + tdbpp = tdbp; + } + + if (tdbp != tdbpp) + return EINVAL; /* Should never happen */ + + ipspkernfs_dirty = 1; + tdbpp = tdbp->tdb_onext; + (*(tdbp->tdb_xform->xf_zeroize))(tdbp); + FREE(tdbp, M_TDB); + if (delchain && tdbpp) + return tdb_delete(tdbpp, delchain); + else + return 0; +} + +int +tdb_init(struct tdb *tdbp, struct mbuf *m) +{ + int alg; + struct encap_msghdr *em; + struct xformsw *xsp; + + em = mtod(m, struct encap_msghdr *); + alg = em->em_alg; + + for (xsp = xformsw; xsp < xformswNXFORMSW; xsp++) + if (xsp->xf_type == alg) + return (*(xsp->xf_init))(tdbp, xsp, m); + + printf("tdbinit: no alg %d for spi %x, addr %x\n", alg, tdbp->tdb_spi, ntohl(tdbp->tdb_dst.s_addr)); + + m_freem(m); + return EINVAL; +} + + +int +ipsp_kern(int off, char **bufp, int len) +{ + struct tdb *tdbp; + int i, k; + char *b, buf[512]; + + if (off != 0) + return 0; + + if ((!ipspkernfs_dirty) && (ipspkernfs)) + { + *bufp = ipspkernfs; + return ipspkernfs_len; + } + else + ipspkernfs_dirty = 0; + + if (ipspkernfs) + { + FREE(ipspkernfs, M_XDATA); + ipspkernfs = NULL; + } + + for (i = 0, k = 0; i < TDB_HASHMOD; i++) + for (tdbp = tdbh[i]; tdbp != (struct tdb *) NULL; tdbp = tdbp->tdb_hnext) + { + /* Being paranoid to avoid buffer overflows */ + + if (strlen(tdbp->tdb_xform->xf_name) >= 200) + return 0; + + b = (char *)&(tdbp->tdb_dst.s_addr); + k += sprintf(buf, + "SPI=%x, destination=%d.%d.%d.%d, interface=%s\n algorithm=%d (%s)\n next SPI=%x, previous SPI=%x\n", + ntohl(tdbp->tdb_spi), ((int)b[0] & 0xff), ((int)b[1] & 0xff), + ((int)b[2] & 0xff), ((int)b[3] & 0xff), + (tdbp->tdb_rcvif ? tdbp->tdb_rcvif->if_xname : "none"), + tdbp->tdb_xform->xf_type, tdbp->tdb_xform->xf_name, + (tdbp->tdb_onext ? ntohl(tdbp->tdb_onext->tdb_spi) : 0), + (tdbp->tdb_inext ? ntohl(tdbp->tdb_inext->tdb_spi) : 0)); + } + + if (k == 0) + return 0; + + MALLOC(ipspkernfs, char *, k + 1, M_XDATA, M_DONTWAIT); + if (!ipspkernfs) + return 0; + + ipspkernfs_len = k + 1; + + for (i = 0, k = 0; i < TDB_HASHMOD; i++) + for (tdbp = tdbh[i]; tdbp != (struct tdb *) NULL; tdbp = tdbp->tdb_hnext) + { + b = (char *)&(tdbp->tdb_dst.s_addr); + k += sprintf(ipspkernfs + k, + "SPI=%x, destination=%d.%d.%d.%d, interface=%s\n algorithm=%d (%s)\n next SPI=%x, previous SPI=%x\n", + ntohl(tdbp->tdb_spi), ((int)b[0] & 0xff), ((int)b[1] & 0xff), + ((int)b[2] & 0xff), ((int)b[3] & 0xff), + (tdbp->tdb_rcvif ? tdbp->tdb_rcvif->if_xname : "none"), + tdbp->tdb_xform->xf_type, tdbp->tdb_xform->xf_name, + (tdbp->tdb_onext ? ntohl(tdbp->tdb_onext->tdb_spi) : 0), + (tdbp->tdb_inext ? ntohl(tdbp->tdb_inext->tdb_spi) : 0)); + } + + ipspkernfs[k] = '\0'; + *bufp = ipspkernfs; + return ipspkernfs_len; +} |