Subject: Re: IPsec, NAT, and Firewalling
To: Dave Burgess <burgess@neonramp.com>
From: None <itojun@iijlab.net>
List: current-users
Date: 01/23/2001 13:55:40
try the following diff. it should make ipfilter look only at
packet on the wire (not the IPsec-decapsulated ones).
itojun
? netinet/tcp_subr.c-
Index: netinet/ip_input.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/ip_input.c,v
retrieving revision 1.126
diff -u -r1.126 ip_input.c
--- netinet/ip_input.c 2000/12/28 21:40:59 1.126
+++ netinet/ip_input.c 2001/01/23 04:54:04
@@ -471,12 +471,23 @@
* Note that filters must _never_ set this flag, as another filter
* in the list may have previously cleared it.
*/
- if (pfil_run_hooks(&inet_pfil_hook, &m, m->m_pkthdr.rcvif,
- PFIL_IN) != 0)
+ /*
+ * let ipfilter look at packet on the wire,
+ * not the decapsulated packet.
+ */
+#ifdef IPSEC
+ if (!ipsec_gethist(m, NULL))
+#else
+ if (1)
+#endif
+ {
+ if (pfil_run_hooks(&inet_pfil_hook, &m, m->m_pkthdr.rcvif,
+ PFIL_IN) != 0)
return;
- if (m == NULL)
- return;
- ip = mtod(m, struct ip *);
+ if (m == NULL)
+ return;
+ ip = mtod(m, struct ip *);
+ }
#endif /* PFIL_HOOKS */
#ifdef ALTQ
Index: netinet/ip_output.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/ip_output.c,v
retrieving revision 1.81
diff -u -r1.81 ip_output.c
--- netinet/ip_output.c 2001/01/13 07:19:33 1.81
+++ netinet/ip_output.c 2001/01/23 04:54:04
@@ -430,19 +430,6 @@
HTONS(ip->ip_len);
HTONS(ip->ip_off);
-#ifdef PFIL_HOOKS
- /*
- * Run through list of hooks for output packets.
- */
- if ((error = pfil_run_hooks(&inet_pfil_hook, &m, ifp,
- PFIL_OUT)) != 0)
- goto done;
- if (m == NULL)
- goto done;
-
- ip = mtod(m, struct ip *);
-#endif /* PFIL_HOOKS */
-
#ifdef IPSEC
/* get SP for this packet */
if (so == NULL)
@@ -562,6 +549,19 @@
skip_ipsec:
#endif /*IPSEC*/
+#ifdef PFIL_HOOKS
+ /*
+ * Run through list of hooks for output packets.
+ */
+ if ((error = pfil_run_hooks(&inet_pfil_hook, &m, ifp,
+ PFIL_OUT)) != 0)
+ goto done;
+ if (m == NULL)
+ goto done;
+
+ ip = mtod(m, struct ip *);
+#endif /* PFIL_HOOKS */
+
/*
* If small enough for mtu of path, can just send directly.
*/
@@ -577,6 +577,10 @@
#endif
ip->ip_sum = 0;
ip->ip_sum = in_cksum(m, hlen);
+#ifdef IPSEC
+ /* clean ipsec history once it goes out of the node */
+ ipsec_delaux(m);
+#endif
error = (*ifp->if_output)(ifp, m, sintosa(dst), ro->ro_rt);
goto done;
}
@@ -703,6 +707,10 @@
ia->ia_ifa.ifa_data.ifad_outbytes +=
ntohs(ip->ip_len);
}
+#endif
+#ifdef IPSEC
+ /* clean ipsec history once it goes out of the node */
+ ipsec_delaux(m);
#endif
error = (*ifp->if_output)(ifp, m, sintosa(dst),
ro->ro_rt);
Index: netinet6/ah_input.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet6/ah_input.c,v
retrieving revision 1.23
diff -u -r1.23 ah_input.c
--- netinet6/ah_input.c 2000/12/09 01:29:50 1.23
+++ netinet6/ah_input.c 2001/01/23 04:54:05
@@ -456,6 +456,8 @@
#endif
key_sa_recordxfer(sav, m);
+ ipsec_addhist(m, IPPROTO_AH, spi);
+ ipsec_addhist(m, IPPROTO_IPV4, 0);
s = splimp();
if (IF_QFULL(&ipintrq)) {
@@ -538,6 +540,7 @@
/* forget about IP hdr checksum, the check has already been passed */
key_sa_recordxfer(sav, m);
+ ipsec_addhist(m, IPPROTO_AH, spi);
if (nxt != IPPROTO_DONE)
(*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt);
@@ -915,6 +918,8 @@
#endif
key_sa_recordxfer(sav, m);
+ ipsec_addhist(m, IPPROTO_AH, spi);
+ ipsec_addhist(m, IPPROTO_IPV6, 0);
s = splimp();
if (IF_QFULL(&ip6intrq)) {
@@ -993,6 +998,7 @@
ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz);
key_sa_recordxfer(sav, m);
+ ipsec_addhist(m, IPPROTO_AH, spi);
}
*offp = off;
Index: netinet6/esp_input.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet6/esp_input.c,v
retrieving revision 1.13
diff -u -r1.13 esp_input.c
--- netinet6/esp_input.c 2000/12/09 01:29:50 1.13
+++ netinet6/esp_input.c 2001/01/23 04:54:05
@@ -382,6 +382,8 @@
#endif
key_sa_recordxfer(sav, m);
+ ipsec_addhist(m, IPPROTO_ESP, spi);
+ ipsec_addhist(m, IPPROTO_IPV4, 0);
s = splimp();
if (IF_QFULL(&ipintrq)) {
@@ -419,6 +421,7 @@
ip->ip_p = nxt;
key_sa_recordxfer(sav, m);
+ ipsec_addhist(m, IPPROTO_ESP, spi);
if (nxt != IPPROTO_DONE)
(*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt);
@@ -793,6 +796,8 @@
#endif
key_sa_recordxfer(sav, m);
+ ipsec_addhist(m, IPPROTO_ESP, spi);
+ ipsec_addhist(m, IPPROTO_IPV6, 0);
s = splimp();
if (IF_QFULL(&ip6intrq)) {
@@ -896,6 +901,7 @@
ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz);
key_sa_recordxfer(sav, m);
+ ipsec_addhist(m, IPPROTO_ESP, spi);
}
*offp = off;
Index: netinet6/ip6_output.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet6/ip6_output.c,v
retrieving revision 1.27
diff -u -r1.27 ip6_output.c
--- netinet6/ip6_output.c 2000/11/11 00:52:39 1.27
+++ netinet6/ip6_output.c 2001/01/23 04:54:06
@@ -862,6 +862,10 @@
m->m_pkthdr.len;
}
#endif
+#ifdef IPSEC
+ /* clean ipsec history once it goes out of the node */
+ ipsec_delaux(m);
+#endif
#ifdef OLDIP6OUTPUT
error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst,
ro->ro_rt);
@@ -991,6 +995,10 @@
ia6->ia_ifa.ifa_data.ifad_outbytes +=
m->m_pkthdr.len;
}
+#endif
+#ifdef IPSEC
+ /* clean ipsec history once it goes out of the node */
+ ipsec_delaux(m);
#endif
#ifdef OLDIP6OUTPUT
error = (*ifp->if_output)(ifp, m,
Index: netinet6/ipcomp_input.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet6/ipcomp_input.c,v
retrieving revision 1.14
diff -u -r1.14 ipcomp_input.c
--- netinet6/ipcomp_input.c 2000/10/02 03:55:43 1.14
+++ netinet6/ipcomp_input.c 2001/01/23 04:54:06
@@ -209,6 +209,7 @@
if (sav) {
key_sa_recordxfer(sav, m);
+ ipsec_addhist(m, IPPROTO_IPCOMP, (u_int32_t)cpi);
key_freesav(sav);
sav = NULL;
}
@@ -320,6 +321,7 @@
if (sav) {
key_sa_recordxfer(sav, m);
+ ipsec_addhist(m, IPPROTO_IPCOMP, (u_int32_t)cpi);
key_freesav(sav);
sav = NULL;
}
Index: netinet6/ipsec.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet6/ipsec.c,v
retrieving revision 1.31
diff -u -r1.31 ipsec.c
--- netinet6/ipsec.c 2000/11/10 01:10:36 1.31
+++ netinet6/ipsec.c 2001/01/23 04:54:08
@@ -156,6 +156,9 @@
#ifdef INET6
static int ipsec6_encapsulate __P((struct mbuf *, struct secasvar *));
#endif
+static struct mbuf *ipsec_addaux __P((struct mbuf *));
+static struct mbuf *ipsec_findaux __P((struct mbuf *));
+static void ipsec_optaux __P((struct mbuf *, struct mbuf *));
/*
* For OUTBOUND packet having a socket. Searching SPD for packet,
@@ -3266,27 +3269,74 @@
return(NULL);
}
-void
-ipsec_setsocket(m, so)
+static struct mbuf *
+ipsec_addaux(m)
struct mbuf *m;
- struct socket *so;
{
struct mbuf *n;
n = m_aux_find(m, AF_INET, IPPROTO_ESP);
- if (so && !n)
+ if (!n) {
n = m_aux_add(m, AF_INET, IPPROTO_ESP);
- if (n) {
- if (so) {
- *mtod(n, struct socket **) = so;
- /*
- * XXX think again about it when we put decryption
- * histrory into aux mbuf
- */
- n->m_len = sizeof(struct socket *);
- } else
- m_aux_delete(m, n);
+ n->m_len = sizeof(struct socket *);
+ bzero(mtod(n, void *), n->m_len);
}
+ return n;
+}
+
+static struct mbuf *
+ipsec_findaux(m)
+ struct mbuf *m;
+{
+ struct mbuf *n;
+
+ n = m_aux_find(m, AF_INET, IPPROTO_ESP);
+#ifdef DIAGNOSTIC
+ if (n && n->m_len < sizeof(struct socket *))
+ panic("invalid ipsec m_aux");
+#endif
+ return n;
+}
+
+void
+ipsec_delaux(m)
+ struct mbuf *m;
+{
+ struct mbuf *n;
+
+ n = m_aux_find(m, AF_INET, IPPROTO_ESP);
+ if (n)
+ m_aux_delete(m, n);
+}
+
+/* if the aux buffer is unnecessary, nuke it. */
+static void
+ipsec_optaux(m, n)
+ struct mbuf *m;
+ struct mbuf *n;
+{
+
+ if (!n)
+ return;
+ if (n->m_len == sizeof(struct socket *) && !*mtod(n, struct socket **))
+ ipsec_delaux(m);
+}
+
+void
+ipsec_setsocket(m, so)
+ struct mbuf *m;
+ struct socket *so;
+{
+ struct mbuf *n;
+
+ /* if so == NULL, don't insist on getting the aux mbuf */
+ if (so)
+ n = ipsec_addaux(m);
+ else
+ n = ipsec_findaux(m);
+ if (n && n->m_len >= sizeof(struct socket *))
+ *mtod(n, struct socket **) = so;
+ ipsec_optaux(m, n);
}
struct socket *
@@ -3295,11 +3345,65 @@
{
struct mbuf *n;
- n = m_aux_find(m, AF_INET, IPPROTO_ESP);
+ n = ipsec_findaux(m);
if (n && n->m_len >= sizeof(struct socket *))
return *mtod(n, struct socket **);
else
return NULL;
+}
+
+void
+ipsec_addhist(m, proto, spi)
+ struct mbuf *m;
+ int proto;
+ u_int32_t spi;
+{
+ struct mbuf *n;
+ struct ipsec_history *p;
+
+ n = ipsec_addaux(m);
+ if (n && M_TRAILINGSPACE(n) > sizeof(*p)) {
+ p = (struct ipsec_history *)(mtod(n, caddr_t) + n->m_len);
+ n->m_len += sizeof(*p);
+ bzero(p, sizeof(*p));
+ p->ih_proto = proto;
+ p->ih_spi = spi;
+ }
+}
+
+struct ipsec_history *
+ipsec_gethist(m, lenp)
+ struct mbuf *m;
+ int *lenp;
+{
+ struct mbuf *n;
+ int l;
+
+ n = ipsec_findaux(m);
+ if (!n)
+ return NULL;
+ l = n->m_len;
+ if (sizeof(struct socket *) > l)
+ return NULL;
+ if ((l - sizeof(struct socket *)) % sizeof(struct ipsec_history))
+ return NULL;
+ /* XXX does it make more sense to divide by sizeof(ipsec_history)? */
+ if (lenp)
+ *lenp = l - sizeof(struct socket *);
+ return (struct ipsec_history *)
+ (mtod(n, caddr_t) + sizeof(struct socket *));
+}
+
+void
+ipsec_clearhist(m)
+ struct mbuf *m;
+{
+ struct mbuf *n;
+
+ n = ipsec_findaux(m);
+ if ((n) && n->m_len > sizeof(struct socket *))
+ n->m_len = sizeof(struct socket *);
+ ipsec_optaux(m, n);
}
/*
Index: netinet6/ipsec.h
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet6/ipsec.h,v
retrieving revision 1.18
diff -u -r1.18 ipsec.h
--- netinet6/ipsec.h 2001/01/04 11:48:44 1.18
+++ netinet6/ipsec.h 2001/01/23 04:54:08
@@ -261,6 +261,11 @@
struct sockaddr *dst;
};
+struct ipsec_history {
+ int ih_proto;
+ u_int32_t ih_spi;
+};
+
extern int ipsec_debug;
#ifdef INET
@@ -366,8 +371,12 @@
struct secasvar *));
#endif
extern struct mbuf *ipsec_copypkt __P((struct mbuf *));
+extern void ipsec_delaux __P((struct mbuf *));
extern void ipsec_setsocket __P((struct mbuf *, struct socket *));
extern struct socket *ipsec_getsocket __P((struct mbuf *));
+extern void ipsec_addhist __P((struct mbuf *, int, u_int32_t));
+extern struct ipsec_history *ipsec_gethist __P((struct mbuf *, int *));
+extern void ipsec_clearhist __P((struct mbuf *));
extern int ipsec_sysctl __P((int *, u_int, void *, size_t *, void *, size_t));
extern int ipsec6_sysctl __P((int *, u_int, void *, size_t *, void *, size_t));