diff options
-rw-r--r-- | sys/net/if_enc.c | 85 | ||||
-rw-r--r-- | sys/netipsec/ipsec.h | 11 | ||||
-rw-r--r-- | sys/netipsec/ipsec_input.c | 23 | ||||
-rw-r--r-- | sys/netipsec/ipsec_output.c | 26 | ||||
-rw-r--r-- | sys/netipsec/xform.h | 3 | ||||
-rw-r--r-- | sys/netipsec/xform_ipip.c | 16 |
6 files changed, 146 insertions, 18 deletions
diff --git a/sys/net/if_enc.c b/sys/net/if_enc.c index e8d279c..3ab9081 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 @@ -269,23 +307,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 @@ -295,8 +358,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 1464014..6efacc6 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 cea8aff..63677ec 100644 --- a/sys/netipsec/ipsec_input.c +++ b/sys/netipsec/ipsec_input.c @@ -444,6 +444,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) { @@ -458,10 +461,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 @@ -703,6 +706,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 { @@ -713,6 +719,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 27ad224..ae7c08b 100644 --- a/sys/netipsec/ipsec_output.c +++ b/sys/netipsec/ipsec_output.c @@ -362,8 +362,10 @@ ipsec4_process_packet( sav = isr->sav; #ifdef DEV_ENC + /* 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 @@ -466,7 +468,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 /* @@ -710,6 +715,14 @@ ipsec6_output_tunnel(struct ipsec_output_state *state, struct secpolicy *sp, int if (isr == NULL) goto bad; +#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(). @@ -778,6 +791,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 58509c5..92f7866 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 80fafd2..e0f54f5 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 |