summaryrefslogtreecommitdiffstats
path: root/sys/netinet/ip_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet/ip_output.c')
-rw-r--r--sys/netinet/ip_output.c107
1 files changed, 89 insertions, 18 deletions
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index c9acdf3..32e3545 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -37,12 +37,12 @@
#define _IP_VHL
#include "opt_ipfw.h"
+#include "opt_ipdn.h"
#include "opt_ipdivert.h"
#include "opt_ipfilter.h"
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/protosw.h>
@@ -77,6 +77,10 @@ static MALLOC_DEFINE(M_IPMOPTS, "ip_moptions", "internet multicast options");
#include <netinet/ip_fw.h>
#endif
+#ifdef DUMMYNET
+#include <netinet/ip_dummynet.h>
+#endif
+
#ifdef IPFIREWALL_FORWARD_DEBUG
#define print_ip(a) printf("%ld.%ld.%ld.%ld",(ntohl(a.s_addr)>>24)&0xFF,\
(ntohl(a.s_addr)>>16)&0xFF,\
@@ -131,6 +135,41 @@ ip_output(m0, opt, ro, flags, imo)
int fwd_rewrite_src = 0;
#endif
+#ifndef IPDIVERT /* dummy variable for the firewall code to play with */
+ u_short ip_divert_cookie = 0 ;
+#endif
+#ifdef COMPAT_IPFW
+ struct ip_fw_chain *rule = NULL ;
+#endif
+
+#if defined(IPFIREWALL) && defined(DUMMYNET)
+ /*
+ * dummynet packet are prepended a vestigial mbuf with
+ * m_type = MT_DUMMYNET and m_data pointing to the matching
+ * rule.
+ */
+ if (m->m_type == MT_DUMMYNET) {
+ struct mbuf *tmp_m = m ;
+ /*
+ * the packet was already tagged, so part of the
+ * processing was already done, and we need to go down.
+ * opt, flags and imo have already been used, and now
+ * they are used to hold ifp and hlen and NULL, respectively.
+ */
+ rule = (struct ip_fw_chain *)(m->m_data) ;
+ m = m->m_next ;
+ free(tmp_m, M_IPFW);
+ ip = mtod(m, struct ip *);
+ dst = (struct sockaddr_in *)&ro->ro_dst;
+ ifp = (struct ifnet *)opt;
+ hlen = IP_VHL_HL(ip->ip_vhl) << 2 ;
+ opt = NULL ;
+ flags = 0 ; /* XXX is this correct ? */
+ goto sendit;
+ } else
+ rule = NULL ;
+#endif
+
#ifdef DIAGNOSTIC
if ((m->m_flags & M_PKTHDR) == 0)
panic("ip_output no HDR");
@@ -394,28 +433,52 @@ sendit:
* Check with the firewall...
*/
if (ip_fw_chk_ptr) {
-#ifdef IPFIREWALL_FORWARD
struct sockaddr_in *old = dst;
-#endif
-#ifdef IPDIVERT
- ip_divert_port = (*ip_fw_chk_ptr)(&ip,
- hlen, ifp, &ip_divert_cookie, &m, &dst);
- if (ip_divert_port) { /* Divert packet */
- (*inetsw[ip_protox[IPPROTO_DIVERT]].pr_input)(m, 0);
+
+ off = (*ip_fw_chk_ptr)(&ip,
+ hlen, ifp, &ip_divert_cookie, &m, &rule, &dst);
+ /*
+ * On return we must do the following:
+ * m == NULL -> drop the pkt
+ * 1<=off<= 0xffff -> DIVERT
+ * (off & 0x10000) -> send to a DUMMYNET pipe
+ * dst != old -> IPFIREWALL_FORWARD
+ * off==0, dst==old -> accept
+ * If some of the above modules is not compiled in, then
+ * we should't have to check the corresponding condition
+ * (because the ipfw control socket should not accept
+ * unsupported rules), but better play safe and drop
+ * packets in case of doubt.
+ */
+ if (!m) { /* firewall said to reject */
+ error = EACCES;
goto done;
}
-#else /* !IPDIVERT */
- u_int16_t dummy = 0;
- /* If ipfw says divert, we have to just drop packet */
- if ((*ip_fw_chk_ptr)(&ip, hlen, ifp, &dummy, &m, &dst)) {
- m_freem(m);
+ if (off == 0 && dst == old) /* common case */
+ goto pass ;
+#ifdef DUMMYNET
+ if (off & 0x10000) {
+ /*
+ * pass the pkt to dummynet. Need to include
+ * pipe number, m, ifp, ro, hlen because these are
+ * not recomputed in the next pass.
+ * All other parameters have been already used and
+ * so they are not needed anymore.
+ * XXX note: if the ifp or ro entry are deleted
+ * while a pkt is in dummynet, we are in trouble!
+ */
+ dummynet_io(off & 0xffff, DN_TO_IP_OUT, m,ifp,ro,hlen,rule);
goto done;
}
-#endif /* !IPDIVERT */
- if (!m) {
- error = EACCES;
+#endif
+#ifdef IPDIVERT
+ if (off > 0 && off < 0x10000) { /* Divert packet */
+ ip_divert_port = off & 0xffff ;
+ (*inetsw[ip_protox[IPPROTO_DIVERT]].pr_input)(m, 0);
goto done;
}
+#endif
+
#ifdef IPFIREWALL_FORWARD
/* Here we check dst to make sure it's directly reachable on the
* interface we previously thought it was.
@@ -426,7 +489,7 @@ sendit:
* such control is nigh impossible. So we do it here.
* And I'm babbling.
*/
- if (old != dst) {
+ if (off == 0 && old != dst) {
struct in_ifaddr *ia;
/* It's changed... */
@@ -515,12 +578,20 @@ sendit:
*/
if (fwd_rewrite_src)
ip->ip_src = IA_SIN(ia)->sin_addr;
+ goto pass ;
}
#endif /* IPFIREWALL_FORWARD */
+ /*
+ * if we get here, none of the above matches, and
+ * we have to drop the pkt
+ */
+ m_freem(m);
+ error = EACCES; /* not sure this is the right error msg */
+ goto done;
}
#endif /* COMPAT_IPFW */
-
+pass:
/*
* If small enough for interface, can just send directly.
*/
OpenPOWER on IntegriCloud