Add a pseudo interface for packet filtering IPSec connections before or after
encryption. There are two functions, a bpf tap which has a basic header with the SPI number which our current tcpdump knows how to display, and handoff to pfil(9) for packet filtering. Obtained from: OpenBSD Based on: kern/94829 No objections: arch, net MFC after: 1 month
This commit is contained in:
parent
d81175c738
commit
bdea400f3b
82
share/man/man4/enc.4
Normal file
82
share/man/man4/enc.4
Normal file
@ -0,0 +1,82 @@
|
||||
.\" $OpenBSD: enc.4,v 1.22 2006/05/26 08:51:29 jmc Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1999 Angelos D. Keromytis
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\"
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by Angelos D. Keromytis.
|
||||
.\" 4. The name of the author may not be used to endorse or promote products
|
||||
.\" derived from this software without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd June 16, 2006
|
||||
.Dt ENC 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm enc
|
||||
.Nd Encapsulating Interface
|
||||
.Sh SYNOPSIS
|
||||
.Cd "device enc"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
interface is a software loopback mechanism that allows hosts or
|
||||
firewalls to filter
|
||||
.Xr fast_ipsec 4
|
||||
traffic using any firewall package that hooks in via the
|
||||
.Xr pfil 9
|
||||
framework.
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
interface allows an administrator
|
||||
to see outgoing packets before they have been processed by
|
||||
.Xr fast_ipsec 4 ,
|
||||
or incoming packets after they have been similarly processed, via
|
||||
.Xr tcpdump 8 .
|
||||
.Pp
|
||||
The
|
||||
.Dq enc0
|
||||
interface inherits all IPsec traffic.
|
||||
Thus all IPsec traffic can be filtered based on
|
||||
.Dq enc0 ,
|
||||
and all IPsec traffic could be seen by invoking
|
||||
.Xr tcpdump 8
|
||||
on the
|
||||
.Dq enc0
|
||||
interface.
|
||||
.Sh EXAMPLES
|
||||
To see all outgoing packets before they have been processed via
|
||||
.Xr fast_ipsec 4 ,
|
||||
or all incoming packets after they have been similarly processed:
|
||||
.Pp
|
||||
.Dl # tcpdump -i enc0
|
||||
.Sh SEE ALSO
|
||||
.Xr bpf 4 ,
|
||||
.Xr fast_ipsec 4 ,
|
||||
.Xr ipf 4 ,
|
||||
.Xr ipfw 4 ,
|
||||
.Xr pf 4 ,
|
||||
.Xr tcpdump 8
|
@ -78,10 +78,16 @@ When the
|
||||
protocols are configured for use, all protocols are included in the system.
|
||||
To selectively enable/disable protocols, use
|
||||
.Xr sysctl 8 .
|
||||
.Pp
|
||||
The packets can be passed to a virtual interface,
|
||||
.Dq enc0 ,
|
||||
to perform packet filtering before outbound encryption and after decapsulation
|
||||
inbound.
|
||||
.Sh DIAGNOSTICS
|
||||
To be added.
|
||||
.Sh SEE ALSO
|
||||
.Xr crypto 4 ,
|
||||
.Xr enc 4 ,
|
||||
.Xr ipsec 4 ,
|
||||
.Xr setkey 8 ,
|
||||
.Xr sysctl 8
|
||||
|
@ -1459,6 +1459,7 @@ net/if_bridge.c optional if_bridge
|
||||
net/if_clone.c standard
|
||||
net/if_disc.c optional disc
|
||||
net/if_ef.c optional ef
|
||||
net/if_enc.c optional enc
|
||||
net/if_ethersubr.c optional ether
|
||||
net/if_faith.c optional faith
|
||||
net/if_fddisubr.c optional fddi
|
||||
|
@ -340,6 +340,7 @@ BOOTP_NFSROOT opt_bootp.h
|
||||
BOOTP_NFSV3 opt_bootp.h
|
||||
BOOTP_WIRED_TO opt_bootp.h
|
||||
DEVICE_POLLING
|
||||
DEV_ENC opt_enc.h
|
||||
DEV_PF opt_pf.h
|
||||
DEV_PFLOG opt_pf.h
|
||||
DEV_PFSYNC opt_pf.h
|
||||
|
323
sys/net/if_enc.c
Normal file
323
sys/net/if_enc.c
Normal file
@ -0,0 +1,323 @@
|
||||
/*-
|
||||
* Copyright (c) 2006 The FreeBSD Project.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/module.h>
|
||||
#include <machine/bus.h>
|
||||
#include <sys/rman.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/if_clone.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/pfil.h>
|
||||
#include <net/route.h>
|
||||
#include <net/netisr.h>
|
||||
#include <net/bpf.h>
|
||||
#include <net/bpfdesc.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_var.h>
|
||||
#include <netinet/in_var.h>
|
||||
#include "opt_inet6.h"
|
||||
|
||||
#ifdef INET6
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet6/ip6_var.h>
|
||||
#endif
|
||||
|
||||
#include <netipsec/ipsec.h>
|
||||
|
||||
#define ENCMTU (1024+512)
|
||||
#define ENC_HDRLEN 12
|
||||
|
||||
/* XXX this define must have the same value as in OpenBSD */
|
||||
#define M_CONF 0x0400 /* payload was encrypted (ESP-transport) */
|
||||
#define M_AUTH 0x0800 /* payload was authenticated (AH or ESP auth) */
|
||||
#define M_AUTH_AH 0x2000 /* header was authenticated (AH) */
|
||||
|
||||
struct enchdr {
|
||||
u_int32_t af;
|
||||
u_int32_t spi;
|
||||
u_int32_t flags;
|
||||
};
|
||||
|
||||
static struct ifnet *encif;
|
||||
static struct mtx enc_mtx;
|
||||
|
||||
struct enc_softc {
|
||||
struct ifnet *sc_ifp;
|
||||
};
|
||||
|
||||
static int enc_ioctl(struct ifnet *, u_long, caddr_t);
|
||||
static int enc_output(struct ifnet *ifp, struct mbuf *m,
|
||||
struct sockaddr *dst, struct rtentry *rt);
|
||||
static int enc_clone_create(struct if_clone *, int);
|
||||
static void enc_clone_destroy(struct ifnet *);
|
||||
|
||||
IFC_SIMPLE_DECLARE(enc, 1);
|
||||
|
||||
static void
|
||||
enc_clone_destroy(struct ifnet *ifp)
|
||||
{
|
||||
|
||||
KASSERT(encif == ifp, ("%s: unknown ifnet", __func__));
|
||||
|
||||
mtx_lock(&enc_mtx);
|
||||
encif = NULL;
|
||||
mtx_unlock(&enc_mtx);
|
||||
|
||||
bpfdetach(ifp);
|
||||
if_detach(ifp);
|
||||
if_free(ifp);
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
enc_clone_create(struct if_clone *ifc, int unit)
|
||||
{
|
||||
struct ifnet *ifp;
|
||||
struct enc_softc *sc;
|
||||
|
||||
mtx_lock(&enc_mtx);
|
||||
if (encif != NULL)
|
||||
return (EBUSY);
|
||||
mtx_unlock(&enc_mtx);
|
||||
|
||||
sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO);
|
||||
ifp = sc->sc_ifp = if_alloc(IFT_ENC);
|
||||
if (ifp == NULL) {
|
||||
free(sc, M_DEVBUF);
|
||||
return (ENOSPC);
|
||||
}
|
||||
|
||||
if_initname(ifp, ifc->ifc_name, unit);
|
||||
ifp->if_mtu = ENCMTU;
|
||||
ifp->if_ioctl = enc_ioctl;
|
||||
ifp->if_output = enc_output;
|
||||
ifp->if_snd.ifq_maxlen = ifqmaxlen;
|
||||
ifp->if_softc = sc;
|
||||
if_attach(ifp);
|
||||
bpfattach(ifp, DLT_ENC, ENC_HDRLEN);
|
||||
|
||||
mtx_lock(&enc_mtx);
|
||||
encif = ifp;
|
||||
mtx_unlock(&enc_mtx);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
enc_modevent(module_t mod, int type, void *data)
|
||||
{
|
||||
switch (type) {
|
||||
case MOD_LOAD:
|
||||
mtx_init(&enc_mtx, "enc mtx", NULL, MTX_DEF);
|
||||
if_clone_attach(&enc_cloner);
|
||||
break;
|
||||
case MOD_UNLOAD:
|
||||
printf("enc module unload - not possible for this module\n");
|
||||
return (EINVAL);
|
||||
default:
|
||||
return (EOPNOTSUPP);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static moduledata_t enc_mod = {
|
||||
"enc",
|
||||
enc_modevent,
|
||||
0
|
||||
};
|
||||
|
||||
DECLARE_MODULE(enc, enc_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
|
||||
|
||||
static int
|
||||
enc_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
|
||||
struct rtentry *rt)
|
||||
{
|
||||
m_freem(m);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process an ioctl request.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
enc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
switch (cmd) {
|
||||
|
||||
case SIOCSIFFLAGS:
|
||||
if (ifp->if_flags & IFF_UP)
|
||||
ifp->if_drv_flags |= IFF_DRV_RUNNING;
|
||||
else
|
||||
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
error = EINVAL;
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
ipsec_filter(struct mbuf **mp, int dir)
|
||||
{
|
||||
int error, i;
|
||||
struct ip *ip;
|
||||
|
||||
mtx_lock(&enc_mtx);
|
||||
if (encif == NULL || (encif->if_drv_flags & IFF_DRV_RUNNING) == 0) {
|
||||
mtx_unlock(&enc_mtx);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Skip pfil(9) if no filters are loaded */
|
||||
if (!(PFIL_HOOKED(&inet_pfil_hook)
|
||||
#ifdef INET6
|
||||
|| PFIL_HOOKED(&inet6_pfil_hook)
|
||||
#endif
|
||||
)) {
|
||||
mtx_unlock(&enc_mtx);
|
||||
return (0);
|
||||
}
|
||||
|
||||
i = min((*mp)->m_pkthdr.len, max_protohdr);
|
||||
if ((*mp)->m_len < i) {
|
||||
*mp = m_pullup(*mp, i);
|
||||
if (*mp == NULL) {
|
||||
printf("%s: m_pullup failed\n", __func__);
|
||||
mtx_unlock(&enc_mtx);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
error = 0;
|
||||
ip = mtod(*mp, struct ip *);
|
||||
switch (ip->ip_v) {
|
||||
case 4:
|
||||
/*
|
||||
* before calling the firewall, swap fields the same as
|
||||
* IP does. here we assume the header is contiguous
|
||||
*/
|
||||
ip->ip_len = ntohs(ip->ip_len);
|
||||
ip->ip_off = ntohs(ip->ip_off);
|
||||
|
||||
error = pfil_run_hooks(&inet_pfil_hook, mp,
|
||||
encif, dir, NULL);
|
||||
|
||||
if (*mp == NULL || error != 0)
|
||||
break;
|
||||
|
||||
/* restore byte ordering */
|
||||
ip = mtod(*mp, struct ip *);
|
||||
ip->ip_len = htons(ip->ip_len);
|
||||
ip->ip_off = htons(ip->ip_off);
|
||||
break;
|
||||
|
||||
#ifdef INET6
|
||||
case 6:
|
||||
error = pfil_run_hooks(&inet6_pfil_hook, mp,
|
||||
encif, dir, NULL);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
printf("%s: unknown IP version\n", __func__);
|
||||
}
|
||||
|
||||
mtx_unlock(&enc_mtx);
|
||||
if (*mp == NULL)
|
||||
return (error);
|
||||
if (error != 0)
|
||||
goto bad;
|
||||
|
||||
return (error);
|
||||
|
||||
bad:
|
||||
mtx_unlock(&enc_mtx);
|
||||
m_freem(*mp);
|
||||
*mp = NULL;
|
||||
return (error);
|
||||
}
|
||||
|
||||
void
|
||||
ipsec_bpf(struct mbuf *m, struct secasvar *sav, int af)
|
||||
{
|
||||
int flags;
|
||||
struct enchdr hdr;
|
||||
struct mbuf m1;
|
||||
|
||||
KASSERT(sav != NULL, ("%s: sav is null", __func__));
|
||||
|
||||
mtx_lock(&enc_mtx);
|
||||
if (encif == NULL || (encif->if_drv_flags & IFF_DRV_RUNNING) == 0) {
|
||||
mtx_unlock(&enc_mtx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (encif->if_bpf) {
|
||||
flags = 0;
|
||||
if (sav->alg_enc != SADB_EALG_NONE)
|
||||
flags |= M_CONF;
|
||||
if (sav->alg_auth != SADB_AALG_NONE)
|
||||
flags |= M_AUTH;
|
||||
|
||||
/*
|
||||
* We need to prepend the address family as a four byte
|
||||
* field. Cons up a dummy header to pacify bpf. This
|
||||
* is safe because bpf will only read from the mbuf
|
||||
* (i.e., it won't try to free it or keep a pointer a
|
||||
* to it).
|
||||
*/
|
||||
hdr.af = af;
|
||||
hdr.spi = sav->spi;
|
||||
hdr.flags = flags;
|
||||
|
||||
m1.m_flags = 0;
|
||||
m1.m_next = m;
|
||||
m1.m_len = ENC_HDRLEN;
|
||||
m1.m_data = (char *) &hdr;
|
||||
|
||||
bpf_mtap(encif->if_bpf, &m1);
|
||||
}
|
||||
mtx_unlock(&enc_mtx);
|
||||
}
|
@ -246,6 +246,7 @@
|
||||
#define IFT_GIF 0xf0
|
||||
#define IFT_PVC 0xf1
|
||||
#define IFT_FAITH 0xf2
|
||||
#define IFT_ENC 0xf4
|
||||
#define IFT_PFLOG 0xf6
|
||||
#define IFT_PFSYNC 0xf7
|
||||
#define IFT_CARP 0xf8 /* Common Address Redundancy Protocol */
|
||||
|
@ -417,6 +417,8 @@ extern void m_checkalignment(const char* where, struct mbuf *m0,
|
||||
extern struct mbuf *m_makespace(struct mbuf *m0, int skip, int hlen, int *off);
|
||||
extern caddr_t m_pad(struct mbuf *m, int n);
|
||||
extern int m_striphdr(struct mbuf *m, int skip, int hlen);
|
||||
extern int ipsec_filter(struct mbuf **, int);
|
||||
extern void ipsec_bpf(struct mbuf *, struct secasvar *, int);
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#ifndef _KERNEL
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "opt_inet.h"
|
||||
#include "opt_inet6.h"
|
||||
#include "opt_ipsec.h"
|
||||
#include "opt_enc.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
@ -442,6 +443,18 @@ ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav,
|
||||
|
||||
key_sa_recordxfer(sav, m); /* record data transfer */
|
||||
|
||||
#ifdef DEV_ENC
|
||||
/*
|
||||
* Pass the mbuf to enc0 for bpf and pfil. We will filter the IPIP
|
||||
* packet later after it has been decapsulated.
|
||||
*/
|
||||
ipsec_bpf(m, sav, AF_INET);
|
||||
|
||||
if (prot != IPPROTO_IPIP)
|
||||
if ((error = ipsec_filter(&m, 1)) != 0)
|
||||
return (error);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Re-dispatch via software interrupt.
|
||||
*/
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "opt_inet.h"
|
||||
#include "opt_inet6.h"
|
||||
#include "opt_ipsec.h"
|
||||
#include "opt_enc.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
@ -358,6 +359,13 @@ ipsec4_process_packet(
|
||||
goto bad;
|
||||
|
||||
sav = isr->sav;
|
||||
|
||||
#ifdef DEV_ENC
|
||||
/* pass the mbuf to enc0 for packet filtering */
|
||||
if ((error = ipsec_filter(&m, 2)) != 0)
|
||||
goto bad;
|
||||
#endif
|
||||
|
||||
if (!tunalready) {
|
||||
union sockaddr_union *dst = &sav->sah->saidx.dst;
|
||||
int setdf;
|
||||
@ -455,6 +463,11 @@ ipsec4_process_packet(
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEV_ENC
|
||||
/* pass the mbuf to enc0 for bpf processing */
|
||||
ipsec_bpf(m, sav, AF_INET);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Dispatch to the appropriate IPsec transform logic. The
|
||||
* packet will be returned for transmission after crypto
|
||||
|
@ -41,6 +41,7 @@
|
||||
*/
|
||||
#include "opt_inet.h"
|
||||
#include "opt_inet6.h"
|
||||
#include "opt_enc.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
@ -345,6 +346,12 @@ _ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp)
|
||||
/* Statistics */
|
||||
ipipstat.ipips_ibytes += m->m_pkthdr.len - iphlen;
|
||||
|
||||
#ifdef DEV_ENC
|
||||
/* pass the mbuf to enc0 for packet filtering */
|
||||
if (ipsec_filter(&m, 1) != 0)
|
||||
return;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Interface pointer stays the same; if no IPsec processing has
|
||||
* been done (or will be done), this will point to a normal
|
||||
|
Loading…
x
Reference in New Issue
Block a user