summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjoern A. Zeeb <bz@FreeBSD.org>2008-10-05 17:41:46 +0000
committerBjoern A. Zeeb <bz@FreeBSD.org>2008-10-05 17:41:46 +0000
commit76e656c84123f769b172b9fff968ffcd4cb040d9 (patch)
tree2da563600668ea2b399796e6c7df2e7d1f8779c7
parent7244155be98815cac58bbaa93b0c6b6419300b5b (diff)
Notes
-rw-r--r--share/man/man4/enc.459
-rw-r--r--sys/net/if_enc.c85
-rw-r--r--sys/netipsec/ipsec.h11
-rw-r--r--sys/netipsec/ipsec_input.c23
-rw-r--r--sys/netipsec/ipsec_output.c26
-rw-r--r--sys/netipsec/xform.h3
-rw-r--r--sys/netipsec/xform_ipip.c16
7 files changed, 198 insertions, 25 deletions
diff --git a/share/man/man4/enc.4 b/share/man/man4/enc.4
index 3da2dfdcaf2b..4b05e574005f 100644
--- a/share/man/man4/enc.4
+++ b/share/man/man4/enc.4
@@ -31,7 +31,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd August 1, 2007
+.Dd November 28, 2007
.Dt ENC 4
.Os
.Sh NAME
@@ -56,10 +56,10 @@ framework.
.Pp
The
.Nm
-interface allows an administrator
-to see outgoing packets before they have been processed by
-.Xr ipsec 4 ,
-or incoming packets after they have been similarly processed, via
+interface allows an administrator to see incoming and outgoing packets
+before and after they will be or have been processed by
+.Xr ipsec 4
+via
.Xr tcpdump 1 .
.Pp
The
@@ -72,10 +72,55 @@ and all IPsec traffic could be seen by invoking
on the
.Dq Li enc0
interface.
+.Pp
+What can be seen with
+.Xr tcpdump 1
+and what will be passed on to the firewalls via the
+.Xr pfil 9
+framework can be independently controlled using the following
+.Xr sysctl 8
+variables:
+.Bl -column net.enc.out.ipsec_filter_mask 0x00000000 0x00000000
+.It Sy "Name Defaults Suggested"
+.It "net.enc.out.ipsec_bpf_mask" 0x00000003 0x00000001
+.It "net.enc.out.ipsec_filter_mask" 0x00000001 0x00000001
+.It "net.enc.in.ipsec_bpf_mask" 0x00000001 0x00000002
+.It "net.enc.in.ipsec_filter_mask" 0x00000001 0x00000002
+.El
+.Pp
+For the incoming path a value of
+.Li 0x1
+means
+.Dq Li before stripping off the outer header
+and
+.Li 0x2
+means
+.Dq Li after stripping off the outer header .
+For the outgoing path
+.Li 0x1
+means
+.Dq Li with only the inner header
+and
+.Li 0x2
+means
+.Dq Li with outer and inner headers .
+.Bd -literal
+incoming path |------|
+---- IPsec processing ---- (before) ---- (after) ----> | |
+ | Host |
+<--- IPsec processing ---- (after) ----- (before) ---- | |
+outgoing path |------|
+.Ed
+.Pp
+Most people will want to run with the suggested defaults for
+.Cm ipsec_filter_mask
+and rely on the security policy database for the outer headers.
.Sh EXAMPLES
-To see all outgoing packets before they have been processed via
+To see the packets the processed via
.Xr ipsec 4 ,
-or all incoming packets after they have been similarly processed:
+adjust the
+.Xr sysctl 8
+variables according to your need and run:
.Pp
.Dl "tcpdump -i enc0"
.Sh SEE ALSO
diff --git a/sys/net/if_enc.c b/sys/net/if_enc.c
index 496cc9d9c4ad..edb19949ae63 100644
--- a/sys/net/if_enc.c
+++ b/sys/net/if_enc.c
@@ -60,7 +60,9 @@
#include <netinet6/ip6_var.h>
#endif
+#include "opt_enc.h"
#include <netipsec/ipsec.h>
+#include <netipsec/xform.h>
#define ENCMTU (1024+512)
@@ -90,6 +92,32 @@ static void enc_clone_destroy(struct ifnet *);
IFC_SIMPLE_DECLARE(enc, 1);
+/*
+ * Sysctls.
+ */
+
+/*
+ * Before and after are relative to when we are stripping the
+ * outer IP header.
+ */
+SYSCTL_NODE(_net, OID_AUTO, enc, CTLFLAG_RW, 0, "enc sysctl");
+
+SYSCTL_NODE(_net_enc, OID_AUTO, in, CTLFLAG_RW, 0, "enc input sysctl");
+static int ipsec_filter_mask_in = ENC_BEFORE;
+SYSCTL_XINT(_net_enc_in, OID_AUTO, ipsec_filter_mask, CTLFLAG_RW,
+ &ipsec_filter_mask_in, 0, "IPsec input firewall filter mask");
+static int ipsec_bpf_mask_in = ENC_BEFORE;
+SYSCTL_XINT(_net_enc_in, OID_AUTO, ipsec_bpf_mask, CTLFLAG_RW,
+ &ipsec_bpf_mask_in, 0, "IPsec input bpf mask");
+
+SYSCTL_NODE(_net_enc, OID_AUTO, out, CTLFLAG_RW, 0, "enc output sysctl");
+static int ipsec_filter_mask_out = ENC_BEFORE;
+SYSCTL_XINT(_net_enc_out, OID_AUTO, ipsec_filter_mask, CTLFLAG_RW,
+ &ipsec_filter_mask_out, 0, "IPsec output firewall filter mask");
+static int ipsec_bpf_mask_out = ENC_BEFORE|ENC_AFTER;
+SYSCTL_XINT(_net_enc_out, OID_AUTO, ipsec_bpf_mask, CTLFLAG_RW,
+ &ipsec_bpf_mask_out, 0, "IPsec output bpf mask");
+
static void
enc_clone_destroy(struct ifnet *ifp)
{
@@ -194,16 +222,26 @@ enc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
}
int
-ipsec_filter(struct mbuf **mp, int dir)
+ipsec_filter(struct mbuf **mp, int dir, int flags)
{
int error, i;
struct ip *ip;
KASSERT(encif != NULL, ("%s: encif is null", __func__));
+ KASSERT(flags & (ENC_IN|ENC_OUT),
+ ("%s: invalid flags: %04x", __func__, flags));
if ((encif->if_drv_flags & IFF_DRV_RUNNING) == 0)
return (0);
+ if (flags & ENC_IN) {
+ if ((flags & ipsec_filter_mask_in) == 0)
+ return (0);
+ } else {
+ if ((flags & ipsec_filter_mask_out) == 0)
+ return (0);
+ }
+
/* Skip pfil(9) if no filters are loaded */
if (!(PFIL_HOOKED(&inet_pfil_hook)
#ifdef INET6
@@ -276,23 +314,48 @@ bad:
}
void
-ipsec_bpf(struct mbuf *m, struct secasvar *sav, int af)
+ipsec_bpf(struct mbuf *m, struct secasvar *sav, int af, int flags)
{
- int flags;
+ int mflags;
struct enchdr hdr;
KASSERT(encif != NULL, ("%s: encif is null", __func__));
- KASSERT(sav != NULL, ("%s: sav is null", __func__));
+ KASSERT(flags & (ENC_IN|ENC_OUT),
+ ("%s: invalid flags: %04x", __func__, flags));
if ((encif->if_drv_flags & IFF_DRV_RUNNING) == 0)
return;
+ if (flags & ENC_IN) {
+ if ((flags & ipsec_bpf_mask_in) == 0)
+ return;
+ } else {
+ if ((flags & ipsec_bpf_mask_out) == 0)
+ return;
+ }
+
if (bpf_peers_present(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;
+ mflags = 0;
+ hdr.spi = 0;
+ if (!sav) {
+ struct m_tag *mtag;
+ mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL);
+ if (mtag != NULL) {
+ struct tdb_ident *tdbi;
+ tdbi = (struct tdb_ident *) (mtag + 1);
+ if (tdbi->alg_enc != SADB_EALG_NONE)
+ mflags |= M_CONF;
+ if (tdbi->alg_auth != SADB_AALG_NONE)
+ mflags |= M_AUTH;
+ hdr.spi = tdbi->spi;
+ }
+ } else {
+ if (sav->alg_enc != SADB_EALG_NONE)
+ mflags |= M_CONF;
+ if (sav->alg_auth != SADB_AALG_NONE)
+ mflags |= M_AUTH;
+ hdr.spi = sav->spi;
+ }
/*
* We need to prepend the address family as a four byte
@@ -302,8 +365,8 @@ ipsec_bpf(struct mbuf *m, struct secasvar *sav, int af)
* to it).
*/
hdr.af = af;
- hdr.spi = sav->spi;
- hdr.flags = flags;
+ /* hdr.spi already set above */
+ hdr.flags = mflags;
bpf_mtap2(encif->if_bpf, &hdr, sizeof(hdr), m);
}
diff --git a/sys/netipsec/ipsec.h b/sys/netipsec/ipsec.h
index 3d8f4ccf232b..d49aefde20be 100644
--- a/sys/netipsec/ipsec.h
+++ b/sys/netipsec/ipsec.h
@@ -410,8 +410,15 @@ 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);
+
+#ifdef DEV_ENC
+#define ENC_BEFORE 0x0001
+#define ENC_AFTER 0x0002
+#define ENC_IN 0x0100
+#define ENC_OUT 0x0200
+extern int ipsec_filter(struct mbuf **, int, int);
+extern void ipsec_bpf(struct mbuf *, struct secasvar *, int, int);
+#endif
#endif /* _KERNEL */
#ifndef _KERNEL
diff --git a/sys/netipsec/ipsec_input.c b/sys/netipsec/ipsec_input.c
index b17a1c5edd83..cdc84770c956 100644
--- a/sys/netipsec/ipsec_input.c
+++ b/sys/netipsec/ipsec_input.c
@@ -449,6 +449,9 @@ ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav,
bcopy(&saidx->dst, &tdbi->dst, saidx->dst.sa.sa_len);
tdbi->proto = sproto;
tdbi->spi = sav->spi;
+ /* Cache those two for enc(4) in xform_ipip. */
+ tdbi->alg_auth = sav->alg_auth;
+ tdbi->alg_enc = sav->alg_enc;
m_tag_prepend(m, mtag);
} else if (mt != NULL) {
@@ -466,10 +469,10 @@ ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav,
* 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);
+ ipsec_bpf(m, sav, AF_INET, ENC_IN|ENC_BEFORE);
if (prot != IPPROTO_IPIP)
- if ((error = ipsec_filter(&m, PFIL_IN)) != 0)
+ if ((error = ipsec_filter(&m, PFIL_IN, ENC_IN|ENC_BEFORE)) != 0)
return (error);
#endif
@@ -711,6 +714,9 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, int proto
bcopy(&saidx->dst, &tdbi->dst, sizeof(union sockaddr_union));
tdbi->proto = sproto;
tdbi->spi = sav->spi;
+ /* Cache those two for enc(4) in xform_ipip. */
+ tdbi->alg_auth = sav->alg_auth;
+ tdbi->alg_enc = sav->alg_enc;
m_tag_prepend(m, mtag);
} else {
@@ -721,6 +727,19 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, int proto
key_sa_recordxfer(sav, m);
+#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_INET6, ENC_IN|ENC_BEFORE);
+
+ /* XXX-BZ does not make sense. */
+ if (prot != IPPROTO_IPIP)
+ if ((error = ipsec_filter(&m, PFIL_IN, ENC_IN|ENC_BEFORE)) != 0)
+ return (error);
+#endif
+
/* Retrieve new protocol */
m_copydata(m, protoff, sizeof(u_int8_t), (caddr_t) &nxt8);
diff --git a/sys/netipsec/ipsec_output.c b/sys/netipsec/ipsec_output.c
index e9b02bb98183..ef84a132d70d 100644
--- a/sys/netipsec/ipsec_output.c
+++ b/sys/netipsec/ipsec_output.c
@@ -375,8 +375,10 @@ ipsec4_process_packet(
encif->if_opackets++;
encif->if_obytes += m->m_pkthdr.len;
+ /* pass the mbuf to enc0 for bpf processing */
+ ipsec_bpf(m, sav, AF_INET, ENC_OUT|ENC_BEFORE);
/* pass the mbuf to enc0 for packet filtering */
- if ((error = ipsec_filter(&m, PFIL_OUT)) != 0)
+ if ((error = ipsec_filter(&m, PFIL_OUT, ENC_OUT|ENC_BEFORE)) != 0)
goto bad;
#endif
@@ -479,7 +481,10 @@ ipsec4_process_packet(
#ifdef DEV_ENC
/* pass the mbuf to enc0 for bpf processing */
- ipsec_bpf(m, sav, AF_INET);
+ ipsec_bpf(m, sav, AF_INET, ENC_OUT|ENC_AFTER);
+ /* pass the mbuf to enc0 for packet filtering */
+ if ((error = ipsec_filter(&m, PFIL_OUT, ENC_OUT|ENC_AFTER)) != 0)
+ goto bad;
#endif
/*
@@ -729,6 +734,14 @@ ipsec6_output_tunnel(struct ipsec_output_state *state, struct secpolicy *sp, int
return EJUSTRETURN;
}
+#ifdef DEV_ENC
+ /* pass the mbuf to enc0 for bpf processing */
+ ipsec_bpf(m, isr->sav, AF_INET6, ENC_OUT|ENC_BEFORE);
+ /* pass the mbuf to enc0 for packet filtering */
+ if ((error = ipsec_filter(&m, PFIL_OUT, ENC_OUT|ENC_BEFORE)) != 0)
+ goto bad;
+#endif
+
/*
* There may be the case that SA status will be changed when
* we are refering to one. So calling splsoftnet().
@@ -797,6 +810,15 @@ ipsec6_output_tunnel(struct ipsec_output_state *state, struct secpolicy *sp, int
goto bad;
}
ip6 = mtod(m, struct ip6_hdr *);
+
+#ifdef DEV_ENC
+ /* pass the mbuf to enc0 for bpf processing */
+ ipsec_bpf(m, isr->sav, AF_INET6, ENC_OUT|ENC_AFTER);
+ /* pass the mbuf to enc0 for packet filtering */
+ if ((error = ipsec_filter(&m, PFIL_OUT, ENC_OUT|ENC_AFTER)) != 0)
+ goto bad;
+#endif
+
error = (*isr->sav->tdb_xform->xf_output)(m, isr, NULL,
sizeof (struct ip6_hdr),
offsetof(struct ip6_hdr, ip6_nxt));
diff --git a/sys/netipsec/xform.h b/sys/netipsec/xform.h
index 58509c5304b8..92f7866a13e6 100644
--- a/sys/netipsec/xform.h
+++ b/sys/netipsec/xform.h
@@ -57,6 +57,9 @@ struct tdb_ident {
u_int32_t spi;
union sockaddr_union dst;
u_int8_t proto;
+ /* Cache those two for enc(4) in xform_ipip. */
+ u_int8_t alg_auth;
+ u_int8_t alg_enc;
};
/*
diff --git a/sys/netipsec/xform_ipip.c b/sys/netipsec/xform_ipip.c
index 80fafd252cdc..e0f54f5a36fc 100644
--- a/sys/netipsec/xform_ipip.c
+++ b/sys/netipsec/xform_ipip.c
@@ -348,8 +348,22 @@ _ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp)
ipipstat.ipips_ibytes += m->m_pkthdr.len - iphlen;
#ifdef DEV_ENC
+ switch (v >> 4) {
+#ifdef INET
+ case 4:
+ ipsec_bpf(m, NULL, AF_INET, ENC_IN|ENC_AFTER);
+ break;
+#endif
+#ifdef INET6
+ case 6:
+ ipsec_bpf(m, NULL, AF_INET6, ENC_IN|ENC_AFTER);
+ break;
+#endif
+ default:
+ panic("%s: bogus ip version %u", __func__, v>>4);
+ }
/* pass the mbuf to enc0 for packet filtering */
- if (ipsec_filter(&m, PFIL_IN) != 0)
+ if (ipsec_filter(&m, PFIL_IN, ENC_IN|ENC_AFTER) != 0)
return;
#endif