Date: Wed, 22 Mar 2006 14:18:35 +0100 (CET) From: VANHULLEBUS Yvan <vanhu@netasq.com> To: FreeBSD-gnats-submit@FreeBSD.org Subject: kern/94829: OpenBSD's enc0 support for FreeBSD Message-ID: <20060322131835.F2BABF7430@darkstar.netasq.com> Resent-Message-ID: <200603221320.k2MDKI5x095808@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 94829 >Category: kern >Synopsis: OpenBSD's enc0 support for FreeBSD >Confidential: no >Severity: non-critical >Priority: medium >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: update >Submitter-Id: current-users >Arrival-Date: Wed Mar 22 13:20:18 GMT 2006 >Closed-Date: >Last-Modified: >Originator: VANHULLEBUS Yvan, THOMAS Fabien >Release: FreeBSD 6.1-PRERELEASE i386 >Organization: NETASQ >Environment: System: FreeBSD darkstar.netasq.com 6.1-PRERELEASE FreeBSD 6.1-PRERELEASE #1: Tue Mar 21 17:44:54 CET 2006 root@darkstar.netasq.com:/usr/src/sys/i386/compile/Darkstar i386 >Description: Actually, there is no possibility to do a tcpdump on incoming/outgoing encrypted traffic, and there is no way to ensure at filtering level that some specific traffic was encrypted. This patch adds an optionnal enc0 support "a la OpenBSD", with tcpdump support for both incoming/outgoing traffic, and sets incoming packet's interface as enc0. Note: authentication mark on incoming packets doesn't seems to work for FAST_IPSEC, I'll try to fix it. >How-To-Repeat: >Fix: --- ./conf/options.orig Thu Mar 16 15:27:31 2006 +++ ./conf/options Thu Mar 16 15:27:31 2006 @@ -338,6 +338,7 @@ DEVICE_POLLING DEV_PF opt_pf.h DEV_PFLOG opt_pf.h DEV_PFSYNC opt_pf.h +DEV_ENC opt_enc.h ETHER_II opt_ef.h ETHER_8023 opt_ef.h ETHER_8022 opt_ef.h --- ./conf/files.orig Thu Mar 16 15:27:31 2006 +++ ./conf/files Thu Mar 16 15:27:31 2006 @@ -1450,6 +1450,7 @@ net/if_stf.c optional stf net/if_tun.c optional tun net/if_tap.c optional tap net/if_vlan.c optional vlan +net/if_enc.c optional enc net/netisr.c standard net/ppp_deflate.c optional ppp_deflate net/ppp_tty.c optional ppp --- ./net/if_types.h.orig Thu Mar 16 15:27:31 2006 +++ ./net/if_types.h Thu Mar 16 15:27:31 2006 @@ -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 */ --- ./net/if_enc.c.orig Tue Mar 21 17:33:49 2006 +++ ./net/if_enc.c Tue Mar 21 17:32:45 2006 @@ -0,0 +1,227 @@ +#include "opt_atalk.h" +#include "opt_inet.h" +#include "opt_inet6.h" +#include "opt_ipx.h" + +#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/netisr.h> +#include <net/route.h> +#include <net/bpf.h> +#include <net/bpfdesc.h> + +#ifdef INET +#include <netinet/in.h> +#include <netinet/in_var.h> +#endif + +#ifdef IPX +#include <netipx/ipx.h> +#include <netipx/ipx_if.h> +#endif + +#ifdef INET6 +#ifndef INET +#include <netinet/in.h> +#endif +#include <netinet6/in6_var.h> +#include <netinet/ip6.h> +#endif + +#ifdef NETATALK +#include <netatalk/at.h> +#include <netatalk/at_var.h> +#endif + +#include <net/if_enc.h> + +#define ENCNAME "enc" + +struct enc_softc { + struct ifnet *sc_ifp; + LIST_ENTRY(enc_softc) sc_next; +}; + +int encioctl(struct ifnet *, u_long, caddr_t); +static void encrtrequest(int, struct rtentry *, struct rt_addrinfo *); +int encoutput(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 *); + +struct ifnet *encif = NULL; /* Used externally */ + +static MALLOC_DEFINE(M_ENC, ENCNAME, "IPsec Enc Interface"); + +static struct mtx enc_mtx; +static LIST_HEAD(enc_list, enc_softc) enc_list; + +IFC_SIMPLE_DECLARE(enc, 1); + +static void +enc_clone_destroy(ifp) + struct ifnet *ifp; +{ + struct enc_softc *sc; + + sc = ifp->if_softc; + + /* XXX: destroying enc0 will lead to panics. */ + KASSERT(encif != ifp, ("%s: destroying enc0", __func__)); +} + +static int +enc_clone_create(ifc, unit) + struct if_clone *ifc; + int unit; +{ + struct ifnet *ifp; + struct enc_softc *sc; + + MALLOC(sc, struct enc_softc *, sizeof(*sc), M_ENC, M_WAITOK | M_ZERO); + ifp = sc->sc_ifp = if_alloc(IFT_ENC); + if (ifp == NULL) { + free(sc, M_ENC); + return (ENOSPC); + } + + if_initname(ifp, ifc->ifc_name, unit); + ifp->if_mtu = ENCMTU; + ifp->if_flags = IFF_MULTICAST; + ifp->if_ioctl = encioctl; + ifp->if_output = encoutput; + ifp->if_snd.ifq_maxlen = ifqmaxlen; + ifp->if_softc = sc; + if_attach(ifp); + bpfattach(ifp, DLT_ENC, ENC_HDRLEN); + mtx_lock(&enc_mtx); + LIST_INSERT_HEAD(&enc_list, sc, sc_next); + mtx_unlock(&enc_mtx); + if (encif == NULL) + encif = ifp; + + 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); + LIST_INIT(&enc_list); + if_clone_attach(&enc_cloner); + break; + case MOD_UNLOAD: + printf("enc module unload - not possible for this module type\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); + +int +encoutput(ifp, m, dst, rt) + struct ifnet *ifp; + register struct mbuf *m; + struct sockaddr *dst; + register struct rtentry *rt; +{ + m_freem(m); + return (0); +} + +/* ARGSUSED */ +static void +encrtrequest(cmd, rt, info) + int cmd; + struct rtentry *rt; + struct rt_addrinfo *info; +{ + RT_LOCK_ASSERT(rt); + rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; +} + +/* + * Process an ioctl request. + */ +/* ARGSUSED */ +int +encioctl(ifp, cmd, data) + register struct ifnet *ifp; + u_long cmd; + caddr_t data; +{ + register struct ifaddr *ifa; + register struct ifreq *ifr = (struct ifreq *)data; + register int error = 0; + + switch (cmd) { + + case SIOCSIFADDR: + ifp->if_flags |= IFF_UP; + ifp->if_drv_flags |= IFF_DRV_RUNNING; + ifa = (struct ifaddr *)data; + ifa->ifa_rtrequest = encrtrequest; + /* + * Everything else is done at a higher level. + */ + break; + + case SIOCADDMULTI: + case SIOCDELMULTI: + if (ifr == 0) { + error = EAFNOSUPPORT; /* XXX */ + break; + } + switch (ifr->ifr_addr.sa_family) { + +#ifdef INET + case AF_INET: + break; +#endif +#ifdef INET6 + case AF_INET6: + break; +#endif + + default: + error = EAFNOSUPPORT; + break; + } + break; + + case SIOCSIFMTU: + ifp->if_mtu = ifr->ifr_mtu; + break; + + case SIOCSIFFLAGS: + break; + + default: + error = EINVAL; + } + return (error); +} --- ./net/if_enc.h.orig Tue Mar 21 17:33:51 2006 +++ ./net/if_enc.h Tue Mar 21 17:32:45 2006 @@ -0,0 +1,21 @@ +#ifndef _NET_IF_ENC_H_ +#define _NET_IF_ENC_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; +}; + +extern struct ifnet *encif; + +#endif /* _NET_IF_ENC_H_ */ --- ./netinet6/esp_input.c.orig Thu Mar 16 15:27:31 2006 +++ ./netinet6/esp_input.c Thu Mar 16 15:27:31 2006 @@ -36,6 +36,7 @@ #include "opt_inet.h" #include "opt_inet6.h" +#include "opt_enc.h" #include <sys/param.h> #include <sys/systm.h> @@ -48,6 +49,8 @@ #include <sys/syslog.h> #include <net/if.h> +#include <net/if_enc.h> +#include <net/bpf.h> #include <net/route.h> #include <net/netisr.h> #include <machine/cpu.h> @@ -388,6 +391,34 @@ noreplaycheck: ipsecstat.in_nomem++; goto bad; } +#ifdef DEV_ENC + m->m_pkthdr.rcvif = encif; + + if (encif->if_bpf != NULL) { + /* + * 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). + */ + struct mbuf m1; + struct enchdr hdr; + + hdr.af = AF_INET; + hdr.spi = spi; + hdr.flags = M_CONF; + if ((m->m_flags & M_AUTHIPDGM) != 0) + hdr.flags |= M_AUTH; + + m1.m_flags = 0; + m1.m_next = m; + m1.m_len = ENC_HDRLEN; + m1.m_data = (char *) &hdr; + + bpf_mtap(encif->if_bpf, &m1); + } +#endif if (netisr_queue(NETISR_IP, m)) { /* (0) on success. */ ipsecstat.in_inval++; @@ -744,6 +775,35 @@ noreplaycheck: ipsec6stat.in_nomem++; goto bad; } + +#ifdef DEV_ENC + m->m_pkthdr.rcvif = encif; + + if (encif->if_bpf) { + /* + * 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). + */ + struct mbuf m1; + struct enchdr hdr; + + hdr.af = AF_INET6; + hdr.spi = spi; + hdr.flags = M_CONF; + if ((m->m_flags & M_AUTHIPDGM) != 0) + hdr.flags |= M_AUTH; + + m1.m_flags = 0; + m1.m_next = m; + m1.m_len = ENC_HDRLEN; + m1.m_data = (char *) &hdr; + + bpf_mtap(encif->if_bpf, &m1); + } +#endif if (netisr_queue(NETISR_IPV6, m)) { /* (0) on success. */ ipsec6stat.in_inval++; --- ./netinet6/esp_output.c.orig Thu Mar 16 15:27:31 2006 +++ ./netinet6/esp_output.c Thu Mar 16 15:27:31 2006 @@ -32,6 +32,7 @@ #include "opt_inet.h" #include "opt_inet6.h" +#include "opt_enc.h" /* * RFC1827/2406 Encapsulated Security Payload. @@ -49,6 +50,8 @@ #include <sys/syslog.h> #include <net/if.h> +#include <net/if_enc.h> +#include <net/bpf.h> #include <net/route.h> #include <netinet/in.h> @@ -196,6 +199,33 @@ esp_output(m, nexthdrp, md, isr, af) size_t extendsiz; int error = 0; struct ipsecstat *stat; + +#ifdef DEV_ENC + if (encif->if_bpf) { + /* + * 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). + */ + struct mbuf m1; + struct enchdr hdr; + + hdr.af = af; + hdr.spi = sav->spi; + hdr.flags = M_CONF; + if (sav->alg_auth != SADB_AALG_NONE) + hdr.flags |= M_AUTH; + + m1.m_flags = 0; + m1.m_next = m; + m1.m_len = ENC_HDRLEN; + m1.m_data = (char *) &hdr; + + bpf_mtap(encif->if_bpf, &m1); + } +#endif switch (af) { #ifdef INET --- ./netipsec/ipsec_input.c.orig Thu Mar 16 15:27:31 2006 +++ ./netipsec/ipsec_input.c Thu Mar 16 15:27:31 2006 @@ -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> @@ -57,6 +58,8 @@ #include <net/if.h> #include <net/route.h> #include <net/netisr.h> +#include <net/if_enc.h> +#include <net/bpf.h> #include <netinet/in.h> #include <netinet/in_systm.h> @@ -443,6 +446,34 @@ ipsec4_common_input_cb(struct mbuf *m, s } key_sa_recordxfer(sav, m); /* record data transfer */ + +#ifdef DEV_ENC + m->m_pkthdr.rcvif = encif; + + if (encif->if_bpf != NULL) { + /* + * 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). + */ + struct mbuf m1; + struct enchdr hdr; + + hdr.af = af; + hdr.spi = sav->spi; + hdr.flags = M_CONF; + if ((m->m_flags & M_AUTHIPDGM) != 0) + hdr.flags |= M_AUTH; + + m1.m_flags = 0; + m1.m_next = m; + m1.m_len = ENC_HDRLEN; + m1.m_data = (char *) &hdr; + bpf_mtap(encif->if_bpf, &m1); + } +#endif /* * Re-dispatch via software interrupt. --- ./netipsec/ipsec_output.c.orig Thu Mar 16 15:27:32 2006 +++ ./netipsec/ipsec_output.c Thu Mar 16 15:27:31 2006 @@ -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> @@ -44,6 +45,8 @@ #include <net/if.h> #include <net/route.h> +#include <net/if_enc.h> +#include <net/bpf.h> #include <netinet/in.h> #include <netinet/in_systm.h> @@ -353,6 +356,32 @@ ipsec4_process_packet( IPSECREQUEST_LOCK(isr); /* insure SA contents don't change */ +#ifdef DEV_ENC + if (encif->if_bpf) { + /* + * 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). + */ + struct mbuf m1; + struct enchdr hdr; + + hdr.af = AF_INET; + hdr.spi = sav->spi; + hdr.flags = M_CONF; + if (sav->alg_auth != SADB_AALG_NONE) + hdr.flags |= M_AUTH; + + m1.m_flags = 0; + m1.m_next = m; + m1.m_len = ENC_HDRLEN; + m1.m_data = (char *) &hdr; + bpf_mtap(encif->if_bpf, &m1); + } +#endif + isr = ipsec_nextisr(m, isr, AF_INET, &saidx, &error); if (isr == NULL) goto bad; @@ -558,6 +587,32 @@ ipsec6_output_trans( *tun = 0; m = state->m; + +#ifdef DEV_ENC + if (encif->if_bpf) { + /* + * 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). + */ + struct mbuf m1; + struct enchdr hdr; + + hdr.af = AF_INET6; + hdr.spi = sav->spi; + hdr.flags = M_CONF; + if (sav->alg_auth != SADB_AALG_NONE) + hdr.flags |= M_AUTH; + + m1.m_flags = 0; + m1.m_next = m; + m1.m_len = ENC_HDRLEN; + m1.m_data = (char *) &hdr; + bpf_mtap(encif->if_bpf, &m1); + } +#endif isr = ipsec_nextisr(m, isr, AF_INET6, &saidx, &error); if (isr == NULL) { >Release-Note: >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20060322131835.F2BABF7430>