summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorandre <andre@FreeBSD.org>2004-08-17 22:05:54 +0000
committerandre <andre@FreeBSD.org>2004-08-17 22:05:54 +0000
commite4a34b65ad08ea7247d310eed0ec0fab9a4d7516 (patch)
treefd3ce94d6b888f16cc620389a55920396fd4a781
parent494133eeee0d46d7cd7dcd3df49b57fc74f1123b (diff)
downloadFreeBSD-src-e4a34b65ad08ea7247d310eed0ec0fab9a4d7516.zip
FreeBSD-src-e4a34b65ad08ea7247d310eed0ec0fab9a4d7516.tar.gz
Convert ipfw to use PFIL_HOOKS. This is change is transparent to userland
and preserves the ipfw ABI. The ipfw core packet inspection and filtering functions have not been changed, only how ipfw is invoked is different. However there are many changes how ipfw is and its add-on's are handled: In general ipfw is now called through the PFIL_HOOKS and most associated magic, that was in ip_input() or ip_output() previously, is now done in ipfw_check_[in|out]() in the ipfw PFIL handler. IPDIVERT is entirely handled within the ipfw PFIL handlers. A packet to be diverted is checked if it is fragmented, if yes, ip_reass() gets in for reassembly. If not, or all fragments arrived and the packet is complete, divert_packet is called directly. For 'tee' no reassembly attempt is made and a copy of the packet is sent to the divert socket unmodified. The original packet continues its way through ip_input/output(). ipfw 'forward' is done via m_tag's. The ipfw PFIL handlers tag the packet with the new destination sockaddr_in. A check if the new destination is a local IP address is made and the m_flags are set appropriately. ip_input() and ip_output() have some more work to do here. For ip_input() the m_flags are checked and a packet for us is directly sent to the 'ours' section for further processing. Destination changes on the input path are only tagged and the 'srcrt' flag to ip_forward() is set to disable destination checks and ICMP replies at this stage. The tag is going to be handled on output. ip_output() again checks for m_flags and the 'ours' tag. If found, the packet will be dropped back to the IP netisr where it is going to be picked up by ip_input() again and the directly sent to the 'ours' section. When only the destination changes, the route's 'dst' is overwritten with the new destination from the forward m_tag. Then it jumps back at the route lookup again and skips the firewall check because it has been marked with M_SKIP_FIREWALL. ipfw 'forward' has to be compiled into the kernel with 'option IPFIREWALL_FORWARD' to enable it. DUMMYNET is entirely handled within the ipfw PFIL handlers. A packet for a dummynet pipe or queue is directly sent to dummynet_io(). Dummynet will then inject it back into ip_input/ip_output() after it has served its time. Dummynet packets are tagged and will continue from the next rule when they hit the ipfw PFIL handlers again after re-injection. BRIDGING and IPFW_ETHER are not changed yet and use ipfw_chk() directly as they did before. Later this will be changed to dedicated ETHER PFIL_HOOKS. More detailed changes to the code: conf/files Add netinet/ip_fw_pfil.c. conf/options Add IPFIREWALL_FORWARD option. modules/ipfw/Makefile Add ip_fw_pfil.c. net/bridge.c Disable PFIL_HOOKS if ipfw for bridging is active. Bridging ipfw is still directly invoked to handle layer2 headers and packets would get a double ipfw when run through PFIL_HOOKS as well. netinet/ip_divert.c Removed divert_clone() function. It is no longer used. netinet/ip_dummynet.[ch] Neither the route 'ro' nor the destination 'dst' need to be stored while in dummynet transit. Structure members and associated macros are removed. netinet/ip_fastfwd.c Removed all direct ipfw handling code and replace it with the new 'ipfw forward' handling code. netinet/ip_fw.h Removed 'ro' and 'dst' from struct ip_fw_args. netinet/ip_fw2.c (Re)moved some global variables and the module handling. netinet/ip_fw_pfil.c New file containing the ipfw PFIL handlers and module initialization. netinet/ip_input.c Removed all direct ipfw handling code and replace it with the new 'ipfw forward' handling code. ip_forward() does not longer require the 'next_hop' struct sockaddr_in argument. Disable early checks if 'srcrt' is set. netinet/ip_output.c Removed all direct ipfw handling code and replace it with the new 'ipfw forward' handling code. netinet/ip_var.h Add ip_reass() as general function. (Used from ipfw PFIL handlers for IPDIVERT.) netinet/raw_ip.c Directly check if ipfw and dummynet control pointers are active. netinet/tcp_input.c Rework the 'ipfw forward' to local code to work with the new way of forward tags. netinet/tcp_sack.c Remove include 'opt_ipfw.h' which is not needed here. sys/mbuf.h Remove m_claim_next() macro which was exclusively for ipfw 'forward' and is no longer needed. Approved by: re (scottl)
-rw-r--r--sys/conf/files1
-rw-r--r--sys/conf/options1
-rw-r--r--sys/modules/ipfw/Makefile2
-rw-r--r--sys/net/bridge.c2
-rw-r--r--sys/netgraph/ng_bridge.c2
-rw-r--r--sys/netinet/ip_divert.c21
-rw-r--r--sys/netinet/ip_dummynet.c42
-rw-r--r--sys/netinet/ip_dummynet.h2
-rw-r--r--sys/netinet/ip_fastfwd.c232
-rw-r--r--sys/netinet/ip_fw.h22
-rw-r--r--sys/netinet/ip_fw2.c65
-rw-r--r--sys/netinet/ip_fw_pfil.c402
-rw-r--r--sys/netinet/ip_input.c282
-rw-r--r--sys/netinet/ip_output.c349
-rw-r--r--sys/netinet/ip_var.h2
-rw-r--r--sys/netinet/raw_ip.c12
-rw-r--r--sys/netinet/tcp_input.c26
-rw-r--r--sys/netinet/tcp_reass.c26
-rw-r--r--sys/netinet/tcp_sack.c1
-rw-r--r--sys/sys/mbuf.h15
20 files changed, 655 insertions, 852 deletions
diff --git a/sys/conf/files b/sys/conf/files
index 3c702c1..dfeee93 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1484,6 +1484,7 @@ netinet/ip_encap.c optional inet
netinet/ip_encap.c optional inet6
netinet/ip_fastfwd.c optional inet
netinet/ip_fw2.c optional ipfirewall
+netinet/ip_fw_pfil.c optional ipfirewall
netinet/ip_icmp.c optional inet
netinet/ip_input.c optional inet
netinet/ip_mroute.c optional mrouting
diff --git a/sys/conf/options b/sys/conf/options
index 222f706..b6ff58c 100644
--- a/sys/conf/options
+++ b/sys/conf/options
@@ -347,6 +347,7 @@ IPFIREWALL opt_ipfw.h
IPFIREWALL_VERBOSE opt_ipfw.h
IPFIREWALL_VERBOSE_LIMIT opt_ipfw.h
IPFIREWALL_DEFAULT_TO_ACCEPT opt_ipfw.h
+IPFIREWALL_FORWARD opt_ipfw.h
IPV6FIREWALL opt_ip6fw.h
IPV6FIREWALL_VERBOSE opt_ip6fw.h
IPV6FIREWALL_VERBOSE_LIMIT opt_ip6fw.h
diff --git a/sys/modules/ipfw/Makefile b/sys/modules/ipfw/Makefile
index cd5b7f0..cd5a6f7 100644
--- a/sys/modules/ipfw/Makefile
+++ b/sys/modules/ipfw/Makefile
@@ -3,7 +3,7 @@
.PATH: ${.CURDIR}/../../netinet
KMOD= ipfw
-SRCS= ip_fw2.c
+SRCS= ip_fw2.c ip_fw_pfil.c
CFLAGS+= -DIPFIREWALL
#
diff --git a/sys/net/bridge.c b/sys/net/bridge.c
index 1f113ba..59e5905 100644
--- a/sys/net/bridge.c
+++ b/sys/net/bridge.c
@@ -1003,6 +1003,7 @@ bdg_forward(struct mbuf *m0, struct ifnet *dst)
* NetBSD-style generic packet filter, pfil(9), hooks.
* Enables ipf(8) in bridging.
*/
+ if (!IPFW_LOADED) { /* XXX: Prevent ipfw from being run twice. */
if (inet_pfil_hook.ph_busy_count >= 0 &&
m0->m_pkthdr.len >= sizeof(struct ip) &&
ntohs(save_eh.ether_type) == ETHERTYPE_IP) {
@@ -1029,6 +1030,7 @@ bdg_forward(struct mbuf *m0, struct ifnet *dst)
ip->ip_len = htons(ip->ip_len);
ip->ip_off = htons(ip->ip_off);
}
+ } /* XXX: Prevent ipfw from being run twice. */
#endif /* PFIL_HOOKS */
/*
diff --git a/sys/netgraph/ng_bridge.c b/sys/netgraph/ng_bridge.c
index 0dcb30f..de6d754 100644
--- a/sys/netgraph/ng_bridge.c
+++ b/sys/netgraph/ng_bridge.c
@@ -629,9 +629,11 @@ ng_bridge_rcvdata(hook_p hook, item_p item)
}
/* Run packet through ipfw processing, if enabled */
+#if 0
if (priv->conf.ipfw[linkNum] && fw_enable && ip_fw_chk_ptr != NULL) {
/* XXX not implemented yet */
}
+#endif
/*
* If unicast and destination host known, deliver to host's link,
diff --git a/sys/netinet/ip_divert.c b/sys/netinet/ip_divert.c
index afd455e..106aa56 100644
--- a/sys/netinet/ip_divert.c
+++ b/sys/netinet/ip_divert.c
@@ -373,27 +373,6 @@ cantsend:
return error;
}
-/*
- * Return a copy of the specified packet, but without
- * the divert tag. This is used when packets are ``tee'd''
- * and we want the cloned copy to not have divert processing.
- */
-struct mbuf *
-divert_clone(struct mbuf *m)
-{
- struct mbuf *clone;
- struct m_tag *mtag;
-
- clone = m_dup(m, M_DONTWAIT);
- if (clone != NULL) {
- /* strip divert tag from copy */
- mtag = m_tag_find(clone, PACKET_TAG_DIVERT, NULL);
- if (mtag != NULL)
- m_tag_delete(clone, mtag);
- }
- return clone;
-}
-
static int
div_attach(struct socket *so, int proto, struct thread *td)
{
diff --git a/sys/netinet/ip_dummynet.c b/sys/netinet/ip_dummynet.c
index 40e17d4..6c419ed 100644
--- a/sys/netinet/ip_dummynet.c
+++ b/sys/netinet/ip_dummynet.c
@@ -179,7 +179,6 @@ static struct mtx dummynet_mtx;
static int config_pipe(struct dn_pipe *p);
static int ip_dn_ctl(struct sockopt *sopt);
-static void rt_unref(struct rtentry *, const char *);
static void dummynet(void *);
static void dummynet_flush(void);
void dummynet_drain(void);
@@ -188,19 +187,6 @@ static void dn_rule_delete(void *);
int if_tx_rdy(struct ifnet *ifp);
-static void
-rt_unref(struct rtentry *rt, const char *where)
-{
- if (rt == NULL)
- return ;
- RT_LOCK(rt);
- if (rt->rt_refcnt <= 0) {
- printf("dummynet: warning, refcnt now %ld, decreasing (%s)\n",
- rt->rt_refcnt, where);
- }
- RTFREE_LOCKED(rt);
-}
-
/*
* Heap management functions.
*
@@ -446,6 +432,7 @@ transmit_event(struct dn_pipe *pipe)
{
struct mbuf *m ;
struct dn_pkt_tag *pkt ;
+ struct ip *ip;
DUMMYNET_LOCK_ASSERT();
@@ -468,6 +455,9 @@ transmit_event(struct dn_pipe *pipe)
break ;
case DN_TO_IP_IN :
+ ip = mtod(m, struct ip *);
+ ip->ip_len = htons(ip->ip_len);
+ ip->ip_off = htons(ip->ip_off);
ip_input(m) ;
break ;
@@ -1127,8 +1117,6 @@ locate_flowset(int pipe_nr, struct ip_fw *rule)
* ifp the 'ifp' parameter from the caller.
* NULL in ip_input, destination interface in ip_output,
* real_dst in bdg_forward
- * ro route parameter (only used in ip_output, NULL otherwise)
- * dst destination address, only used by ip_output
* rule matching rule, in case of multiple passes
* flags flags from the caller, only used in ip_output
*
@@ -1214,23 +1202,8 @@ dummynet_io(struct mbuf *m, int pipe_nr, int dir, struct ip_fw_args *fwa)
pkt->dn_dir = dir ;
pkt->ifp = fwa->oif;
- if (dir == DN_TO_IP_OUT) {
- /*
- * We need to copy *ro because for ICMP pkts (and maybe others)
- * the caller passed a pointer into the stack; dst might also be
- * a pointer into *ro so it needs to be updated.
- */
- pkt->ro = *(fwa->ro);
- if (pkt->ro.ro_rt) {
- RT_LOCK(pkt->ro.ro_rt);
- RT_ADDREF(pkt->ro.ro_rt) ;
- RT_UNLOCK(pkt->ro.ro_rt);
- }
- if (fwa->dst == (struct sockaddr_in *)&fwa->ro->ro_dst) /* dst points into ro */
- fwa->dst = (struct sockaddr_in *)&(pkt->ro.ro_dst) ;
- pkt->dn_dst = fwa->dst;
+ if (dir == DN_TO_IP_OUT)
pkt->flags = fwa->flags;
- }
if (q->head == NULL)
q->head = m;
else
@@ -1327,7 +1300,6 @@ dropit:
* Doing this would probably save us the initial bzero of dn_pkt
*/
#define DN_FREE_PKT(_m) do { \
- rt_unref(dn_tag_get(_m)->ro.ro_rt, __func__); \
m_freem(_m); \
} while (0)
@@ -2091,6 +2063,6 @@ static moduledata_t dummynet_mod = {
dummynet_modevent,
NULL
};
-DECLARE_MODULE(dummynet, dummynet_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
-MODULE_DEPEND(dummynet, ipfw, 1, 1, 1);
+DECLARE_MODULE(dummynet, dummynet_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
+MODULE_DEPEND(dummynet, ipfw, 2, 2, 2);
MODULE_VERSION(dummynet, 1);
diff --git a/sys/netinet/ip_dummynet.h b/sys/netinet/ip_dummynet.h
index 28e85a9..f241dcd 100644
--- a/sys/netinet/ip_dummynet.h
+++ b/sys/netinet/ip_dummynet.h
@@ -127,8 +127,6 @@ struct dn_pkt_tag {
dn_key output_time; /* when the pkt is due for delivery */
struct ifnet *ifp; /* interface, for ip_output */
- struct sockaddr_in *dn_dst ;
- struct route ro; /* route, for ip_output. MUST COPY */
int flags ; /* flags, for ip_output (IPv6 ?) */
};
#endif /* _KERNEL */
diff --git a/sys/netinet/ip_fastfwd.c b/sys/netinet/ip_fastfwd.c
index 78e46dd..bc7c359 100644
--- a/sys/netinet/ip_fastfwd.c
+++ b/sys/netinet/ip_fastfwd.c
@@ -76,9 +76,6 @@
*/
#include "opt_ipfw.h"
-#include "opt_ipdn.h"
-#include "opt_ipdivert.h"
-#include "opt_ipfilter.h"
#include "opt_ipstealth.h"
#include "opt_pfil_hooks.h"
@@ -107,10 +104,6 @@
#include <machine/in_cksum.h>
-#include <netinet/ip_fw.h>
-#include <netinet/ip_divert.h>
-#include <netinet/ip_dummynet.h>
-
static int ipfastforward_active = 0;
SYSCTL_INT(_net_inet_ip, OID_AUTO, fastforwarding, CTLFLAG_RW,
&ipfastforward_active, 0, "Enable fast IP forwarding");
@@ -163,20 +156,18 @@ ip_fastforward(struct mbuf *m)
{
struct ip *ip;
struct mbuf *m0 = NULL;
-#ifdef IPDIVERT
- struct ip *tip;
- struct mbuf *clone = NULL;
-#endif
struct route ro;
struct sockaddr_in *dst = NULL;
struct in_ifaddr *ia = NULL;
struct ifaddr *ifa = NULL;
struct ifnet *ifp;
- struct ip_fw_args args;
struct in_addr odest, dest;
u_short sum, ip_len;
int error = 0;
- int hlen, ipfw, mtu;
+ int hlen, mtu;
+#ifdef IPFIREWALL_FORWARD
+ struct m_tag *fwd_tag;
+#endif
/*
* Are we active and forwarding packets?
@@ -375,92 +366,6 @@ ip_fastforward(struct mbuf *m)
ip = mtod(m, struct ip *); /* m may have changed by pfil hook */
dest.s_addr = ip->ip_dst.s_addr;
-#endif
-
- /*
- * Run through ipfw for input packets
- */
- if (fw_enable && IPFW_LOADED) {
- bzero(&args, sizeof(args));
- args.m = m;
-
- ipfw = ip_fw_chk_ptr(&args);
- m = args.m;
-
- M_ASSERTVALID(m);
- M_ASSERTPKTHDR(m);
-
- /*
- * Packet denied, drop it
- */
- if ((ipfw & IP_FW_PORT_DENY_FLAG) || m == NULL)
- goto drop;
- /*
- * Send packet to the appropriate pipe
- */
- if (DUMMYNET_LOADED && (ipfw & IP_FW_PORT_DYNT_FLAG) != 0) {
- ip_dn_io_ptr(m, ipfw & 0xffff, DN_TO_IP_IN, &args);
- return 1;
- }
-#ifdef IPDIVERT
- /*
- * Divert packet
- */
- if (ipfw != 0 && (ipfw & IP_FW_PORT_DYNT_FLAG) == 0) {
- /*
- * See if this is a fragment
- */
- if (ip->ip_off & (IP_MF | IP_OFFMASK))
- goto droptoours;
- /*
- * Tee packet
- */
- if ((ipfw & IP_FW_PORT_TEE_FLAG) != 0)
- clone = divert_clone(m);
- else
- clone = m;
- if (clone == NULL)
- goto passin;
-
- /*
- * Delayed checksums are not compatible
- */
- if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
- in_delayed_cksum(m);
- m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
- }
- /*
- * Restore packet header fields to original values
- */
- tip = mtod(m, struct ip *);
- tip->ip_len = htons(tip->ip_len);
- tip->ip_off = htons(tip->ip_off);
- /*
- * Deliver packet to divert input routine
- */
- divert_packet(m, 0);
- /*
- * If this was not tee, we are done
- */
- m = clone;
- if ((ipfw & IP_FW_PORT_TEE_FLAG) == 0)
- return 1;
- /* Continue if it was tee */
- goto passin;
- }
-#endif
- if (ipfw == 0 && args.next_hop != NULL) {
- dest.s_addr = args.next_hop->sin_addr.s_addr;
- goto passin;
- }
- /*
- * Let through or not?
- */
- if (ipfw != 0)
- goto drop;
- }
-passin:
- ip = mtod(m, struct ip *); /* if m changed during fw processing */
/*
* Destination address changed?
@@ -475,6 +380,15 @@ passin:
* Go on with new destination address
*/
}
+#ifdef IPFIREWALL_FORWARD
+ if (m->m_flags & M_FASTFWD_OURS) {
+ /*
+ * ipfw changed it for a local address on this host.
+ */
+ goto forwardlocal;
+ }
+#endif /* IPFIREWALL_FORWARD */
+#endif /* PFIL_HOOKS */
/*
* Step 4: decrement TTL and look up route
@@ -528,123 +442,32 @@ passin:
ip = mtod(m, struct ip *);
dest.s_addr = ip->ip_dst.s_addr;
-#endif
- if (fw_enable && IPFW_LOADED && !args.next_hop) {
- bzero(&args, sizeof(args));
- args.m = m;
- args.oif = ifp;
-
- ipfw = ip_fw_chk_ptr(&args);
- m = args.m;
-
- M_ASSERTVALID(m);
- M_ASSERTPKTHDR(m);
-
- if ((ipfw & IP_FW_PORT_DENY_FLAG) || m == NULL)
- goto drop;
-
- if (DUMMYNET_LOADED && (ipfw & IP_FW_PORT_DYNT_FLAG) != 0) {
- /*
- * XXX note: if the ifp or rt entry are deleted
- * while a pkt is in dummynet, we are in trouble!
- */
- args.ro = &ro; /* dummynet does not save it */
- args.dst = dst;
-
- ip_dn_io_ptr(m, ipfw & 0xffff, DN_TO_IP_OUT, &args);
- goto consumed;
- }
-#ifdef IPDIVERT
- if (ipfw != 0 && (ipfw & IP_FW_PORT_DYNT_FLAG) == 0) {
- /*
- * See if this is a fragment
- */
- if (ip->ip_off & (IP_MF | IP_OFFMASK))
- goto droptoours;
- /*
- * Tee packet
- */
- if ((ipfw & IP_FW_PORT_TEE_FLAG) != 0)
- clone = divert_clone(m);
- else
- clone = m;
- if (clone == NULL)
- goto passout;
-
- /*
- * Delayed checksums are not compatible with divert
- */
- if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
- in_delayed_cksum(m);
- m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
- }
- /*
- * Restore packet header fields to original values
- */
- tip = mtod(m, struct ip *);
- tip->ip_len = htons(tip->ip_len);
- tip->ip_off = htons(tip->ip_off);
- /*
- * Deliver packet to divert input routine
- */
- divert_packet(m, 0);
- /*
- * If this was not tee, we are done
- */
- m = clone;
- if ((ipfw & IP_FW_PORT_TEE_FLAG) == 0) {
- goto consumed;
- }
- /* Continue if it was tee */
- goto passout;
- }
-#endif
- if (ipfw == 0 && args.next_hop != NULL) {
- dest.s_addr = args.next_hop->sin_addr.s_addr;
- goto passout;
- }
- /*
- * Let through or not?
- */
- if (ipfw != 0)
- goto drop;
- }
-passout:
- ip = mtod(m, struct ip *);
/*
* Destination address changed?
*/
+#ifndef IPFIREWALL_FORWARD
if (odest.s_addr != dest.s_addr) {
+#else
+ fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL);
+ if (odest.s_addr != dest.s_addr || fwd_tag != NULL) {
+#endif /* IPFIREWALL_FORWARD */
/*
* Is it now for a local address on this host?
*/
+#ifndef IPFIREWALL_FORWARD
if (in_localip(dest)) {
+#else
+ if (in_localip(dest) || m->m_flags & M_FASTFWD_OURS) {
+#endif /* IPFIREWALL_FORWARD */
forwardlocal:
- if (args.next_hop) {
- struct m_tag *mtag = m_tag_get(
- PACKET_TAG_IPFORWARD,
- sizeof(struct sockaddr_in *),
- M_NOWAIT);
- if (mtag == NULL) {
- goto drop;
- }
- *(struct sockaddr_in **)(mtag+1) =
- args.next_hop;
- m_tag_prepend(m, mtag);
- }
-#ifdef IPDIVERT
-droptoours: /* Used for DIVERT */
-#endif
/* for ip_input */
m->m_flags |= M_FASTFWD_OURS;
-
- /* ip still points to the real packet */
ip->ip_len = htons(ip->ip_len);
ip->ip_off = htons(ip->ip_off);
/*
- * Return packet for processing by ip_input
+ * Return packet for processing by ip_input()
*/
if (ro.ro_rt)
RTFREE(ro.ro_rt);
@@ -653,11 +476,20 @@ droptoours: /* Used for DIVERT */
/*
* Redo route lookup with new destination address
*/
+#ifdef IPFIREWALL_FORWARD
+ if (fwd_tag) {
+ if (!in_localip(ip->ip_src) && !in_localaddr(ip->ip_dst))
+ dest.s_addr = ((struct sockaddr_in *)(fwd_tag+1))->sin_addr.s_addr;
+ //bcopy((fwd_tag+1), dst, sizeof(struct sockaddr_in));
+ m_tag_delete(m, fwd_tag);
+ }
+#endif /* IPFIREWALL_FORWARD */
RTFREE(ro.ro_rt);
if ((dst = ip_findroute(&ro, dest, m)) == NULL)
return 1; /* icmp unreach already sent */
ifp = ro.ro_rt->rt_ifp;
}
+#endif /* PFIL_HOOKS */
/*
* Step 6: send off the packet
diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h
index fa17599..add5289 100644
--- a/sys/netinet/ip_fw.h
+++ b/sys/netinet/ip_fw.h
@@ -28,6 +28,7 @@
#ifndef _IPFW2_H
#define _IPFW2_H
#define IPFW2 1
+
/*
* The kernel representation of ipfw rules is made of a list of
* 'instructions' (for all practical purposes equivalent to BPF
@@ -420,8 +421,6 @@ struct ip_fw_args {
struct ip_fw *rule; /* matching rule */
struct ether_header *eh; /* for bridged packets */
- struct route *ro; /* for dummynet */
- struct sockaddr_in *dst; /* for dummynet */
int flags; /* for dummynet */
struct ipfw_flow_id f_id; /* grabbed from IP header */
@@ -436,15 +435,24 @@ struct ip_fw_args {
struct sockopt;
struct dn_flow_set;
+int ipfw_check_in(void *, struct mbuf **, struct ifnet *, int);
+int ipfw_check_out(void *, struct mbuf **, struct ifnet *, int);
+
+int ipfw_chk(struct ip_fw_args *);
+
+int ipfw_init(void);
+void ipfw_destroy(void);
+
void flush_pipe_ptrs(struct dn_flow_set *match); /* used by dummynet */
-typedef int ip_fw_chk_t (struct ip_fw_args *args);
-typedef int ip_fw_ctl_t (struct sockopt *);
-extern ip_fw_chk_t *ip_fw_chk_ptr;
+typedef int ip_fw_ctl_t(struct sockopt *);
extern ip_fw_ctl_t *ip_fw_ctl_ptr;
extern int fw_one_pass;
-extern int fw_enable;
+
+/* For kernel ipfw_ether and ipfw_bridge. */
+typedef int ip_fw_chk_t(struct ip_fw_args *args);
+extern ip_fw_chk_t *ip_fw_chk_ptr;
#define IPFW_LOADED (ip_fw_chk_ptr != NULL)
-#endif /* _KERNEL */
+#endif /* _KERNEL */
#endif /* _IPFW2_H */
diff --git a/sys/netinet/ip_fw2.c b/sys/netinet/ip_fw2.c
index 7559db7..c1ae851 100644
--- a/sys/netinet/ip_fw2.c
+++ b/sys/netinet/ip_fw2.c
@@ -156,9 +156,6 @@ static int autoinc_step = 100; /* bounded to 1..1000 in add_rule() */
#ifdef SYSCTL_NODE
SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall");
-SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, enable,
- CTLFLAG_RW | CTLFLAG_SECURE3,
- &fw_enable, 0, "Enable ipfw");
SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, autoinc_step, CTLFLAG_RW,
&autoinc_step, 0, "Rule number autincrement step");
SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, one_pass,
@@ -276,10 +273,6 @@ SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_keepalive, CTLFLAG_RW,
#endif /* SYSCTL_NODE */
-static ip_fw_chk_t ipfw_chk;
-
-ip_dn_ruledel_t *ip_dn_ruledel_ptr = NULL; /* hook into dummynet */
-
/*
* This macro maps an ip pointer into a layer3 header pointer of type T
*/
@@ -1653,7 +1646,7 @@ check_uidgid(ipfw_insn_u32 *insn,
* 16 bits as a dummynet pipe number instead of diverting
*/
-static int
+int
ipfw_chk(struct ip_fw_args *args)
{
/*
@@ -3348,7 +3341,7 @@ done:
callout_reset(&ipfw_timeout, dyn_keepalive_period*hz, ipfw_tick, NULL);
}
-static int
+int
ipfw_init(void)
{
struct ip_fw default_rule;
@@ -3384,7 +3377,13 @@ ipfw_init(void)
ip_fw_default_rule = layer3_chain.rules;
printf("ipfw2 initialized, divert %s, "
- "rule-based forwarding enabled, default to %s, logging ",
+ "rule-based forwarding "
+#ifdef IPFIREWALL_FORWARD
+ "enabled, "
+#else
+ "disabled, "
+#endif
+ "default to %s, logging ",
#ifdef IPDIVERT
"enabled",
#else
@@ -3406,22 +3405,23 @@ ipfw_init(void)
printf("limited to %d packets/entry by default\n",
verbose_limit);
- ip_fw_chk_ptr = ipfw_chk;
+ init_tables();
ip_fw_ctl_ptr = ipfw_ctl;
+ ip_fw_chk_ptr = ipfw_chk;
callout_reset(&ipfw_timeout, hz, ipfw_tick, NULL);
return (0);
}
-static void
+void
ipfw_destroy(void)
{
struct ip_fw *reap;
- IPFW_LOCK(&layer3_chain);
- callout_stop(&ipfw_timeout);
ip_fw_chk_ptr = NULL;
ip_fw_ctl_ptr = NULL;
+ IPFW_LOCK(&layer3_chain);
+ callout_stop(&ipfw_timeout);
layer3_chain.reap = NULL;
free_chain(&layer3_chain, 1 /* kill default rule */);
reap = layer3_chain.reap, layer3_chain.reap = NULL;
@@ -3434,41 +3434,4 @@ ipfw_destroy(void)
printf("IP firewall unloaded\n");
}
-static int
-ipfw_modevent(module_t mod, int type, void *unused)
-{
- int err = 0;
-
- switch (type) {
- case MOD_LOAD:
- if (IPFW_LOADED) {
- printf("IP firewall already loaded\n");
- err = EEXIST;
- } else {
- err = ipfw_init();
- }
- break;
-
- case MOD_UNLOAD:
- ipfw_destroy();
- err = 0;
- break;
- default:
- return EOPNOTSUPP;
- break;
- }
- return err;
-}
-
-static moduledata_t ipfwmod = {
- "ipfw",
- ipfw_modevent,
- 0
-};
-DECLARE_MODULE(ipfw, ipfwmod, SI_SUB_PSEUDO, SI_ORDER_ANY);
-MODULE_VERSION(ipfw, 1);
-
-/* Must be run after route_init(). */
-SYSINIT(ipfw, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY, init_tables, 0)
-
#endif /* IPFW2 */
diff --git a/sys/netinet/ip_fw_pfil.c b/sys/netinet/ip_fw_pfil.c
new file mode 100644
index 0000000..9056ab6
--- /dev/null
+++ b/sys/netinet/ip_fw_pfil.c
@@ -0,0 +1,402 @@
+/*
+ * Copyright (c) 2004 Andre Oppermann, Internet Business Solutions AG
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#if !defined(KLD_MODULE)
+#include "opt_ipfw.h"
+#include "opt_ipdn.h"
+#include "opt_ipdivert.h"
+#include "opt_inet.h"
+#ifndef INET
+#error IPFIREWALL requires INET.
+#endif /* INET */
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/module.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sysctl.h>
+#include <sys/ucred.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/pfil.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip_fw.h>
+#include <netinet/ip_divert.h>
+#include <netinet/ip_dummynet.h>
+
+#include <machine/in_cksum.h>
+
+static int ipfw_pfil_hooked = 0;
+
+/* Dummynet hooks. */
+ip_dn_ruledel_t *ip_dn_ruledel_ptr = NULL;
+
+#define DIV_DIR_IN 1
+#define DIV_DIR_OUT 0
+
+static int ipfw_divert(struct mbuf **, int, int);
+
+int
+ipfw_check_in(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir)
+{
+ struct ip_fw_args args;
+ struct m_tag *dn_tag;
+ int ipfw = 0;
+ int divert;
+#ifdef IPFIREWALL_FORWARD
+ struct m_tag *fwd_tag;
+#endif
+
+ KASSERT(dir == PFIL_IN, ("ipfw_check_in wrong direction!"));
+
+ bzero(&args, sizeof(args));
+
+ dn_tag = m_tag_find(*m0, PACKET_TAG_DUMMYNET, NULL);
+ if (dn_tag != NULL){
+ struct dn_pkt_tag *dt;
+
+ dt = (struct dn_pkt_tag *)(dn_tag+1);
+ args.rule = dt->rule;
+
+ m_tag_delete(*m0, dn_tag);
+ }
+
+ args.m = *m0;
+ ipfw = ipfw_chk(&args);
+ *m0 = args.m;
+
+ if ((ipfw & IP_FW_PORT_DENY_FLAG) || *m0 == NULL)
+ goto drop;
+
+ if (ipfw == 0 && args.next_hop == NULL)
+ goto pass;
+
+ if (DUMMYNET_LOADED && (ipfw & IP_FW_PORT_DYNT_FLAG) != 0) {
+ ip_dn_io_ptr(*m0, ipfw & 0xffff, DN_TO_IP_IN, &args);
+ *m0 = NULL;
+ return 0; /* packet consumed */
+ }
+
+ if (ipfw != 0 && (ipfw & IP_FW_PORT_DYNT_FLAG) == 0) {
+ if ((ipfw & IP_FW_PORT_TEE_FLAG) != 0)
+ divert = ipfw_divert(m0, DIV_DIR_IN, 1);
+ else
+ divert = ipfw_divert(m0, DIV_DIR_IN, 0);
+
+ /* tee should continue again with the firewall. */
+ if (divert) {
+ *m0 = NULL;
+ return 0; /* packet consumed */
+ } else
+ goto pass; /* continue with packet */
+ }
+
+#ifdef IPFIREWALL_FORWARD
+ if (ipfw == 0 && args.next_hop != NULL) {
+ fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD,
+ sizeof(struct sockaddr_in), M_NOWAIT);
+ if (fwd_tag == NULL)
+ goto drop;
+ bcopy(args.next_hop, (fwd_tag+1), sizeof(struct sockaddr_in));
+ m_tag_prepend(*m0, fwd_tag);
+
+ if (in_localip(args.next_hop->sin_addr))
+ (*m0)->m_flags |= M_FASTFWD_OURS;
+ goto pass;
+ }
+#endif
+
+drop:
+ if (*m0)
+ m_freem(*m0);
+ *m0 = NULL;
+ return (EACCES);
+pass:
+ return 0; /* not filtered */
+}
+
+int
+ipfw_check_out(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir)
+{
+ struct ip_fw_args args;
+ struct m_tag *dn_tag;
+ int ipfw = 0;
+ int divert;
+#ifdef IPFIREWALL_FORWARD
+ struct m_tag *fwd_tag;
+#endif
+
+ KASSERT(dir == PFIL_OUT, ("ipfw_check_out wrong direction!"));
+
+ bzero(&args, sizeof(args));
+
+ dn_tag = m_tag_find(*m0, PACKET_TAG_DUMMYNET, NULL);
+ if (dn_tag != NULL) {
+ struct dn_pkt_tag *dt;
+
+ dt = (struct dn_pkt_tag *)(dn_tag+1);
+ args.rule = dt->rule;
+
+ m_tag_delete(*m0, dn_tag);
+ }
+
+ args.m = *m0;
+ args.oif = ifp;
+ ipfw = ipfw_chk(&args);
+ *m0 = args.m;
+
+ if ((ipfw & IP_FW_PORT_DENY_FLAG) || *m0 == NULL)
+ goto drop;
+
+ if (ipfw == 0 && args.next_hop == NULL)
+ goto pass;
+
+ if (DUMMYNET_LOADED && (ipfw & IP_FW_PORT_DYNT_FLAG) != 0) {
+ ip_dn_io_ptr(*m0, ipfw & 0xffff, DN_TO_IP_OUT, &args);
+ *m0 = NULL;
+ return 0; /* packet consumed */
+ }
+
+ if (ipfw != 0 && (ipfw & IP_FW_PORT_DYNT_FLAG) == 0) {
+ if ((ipfw & IP_FW_PORT_TEE_FLAG) != 0)
+ divert = ipfw_divert(m0, DIV_DIR_OUT, 1);
+ else
+ divert = ipfw_divert(m0, DIV_DIR_OUT, 0);
+
+ if (divert) {
+ *m0 = NULL;
+ return 0; /* packet consumed */
+ } else
+ goto pass; /* continue with packet */
+ }
+
+#ifdef IPFIREWALL_FORWARD
+ if (ipfw == 0 && args.next_hop != NULL) {
+ /* Overwrite existing tag. */
+ fwd_tag = m_tag_find(*m0, PACKET_TAG_IPFORWARD, NULL);
+ if (fwd_tag == NULL)
+ fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD,
+ sizeof(struct sockaddr_in), M_NOWAIT);
+ if (fwd_tag == NULL)
+ goto drop;
+ bcopy(args.next_hop, (fwd_tag+1), sizeof(struct sockaddr_in));
+ m_tag_prepend(*m0, fwd_tag);
+
+ if (in_localip(args.next_hop->sin_addr))
+ (*m0)->m_flags |= M_FASTFWD_OURS;
+ goto pass;
+ }
+#endif
+
+drop:
+ if (*m0)
+ m_freem(*m0);
+ *m0 = NULL;
+ return (EACCES);
+pass:
+ return 0; /* not filtered */
+}
+
+static int
+ipfw_divert(struct mbuf **m, int incoming, int tee)
+{
+ /*
+ * ipfw_chk() has already tagged the packet with the divert
+ * tag. For tee we need to remove the tag.
+ * If tee is set, copy packet and return original.
+ * If not tee, consume packet and send it to divert socket.
+ */
+#ifdef IPDIVERT
+ struct mbuf *clone, *reass;
+ struct m_tag *mtag;
+ struct ip *ip;
+ int hlen;
+
+ reass = NULL;
+
+ /* Cloning needed for tee? */
+ if (tee)
+ clone = m_dup(*m, M_DONTWAIT);
+ else
+ clone = *m;
+
+ /* In case m_dup was unable to allocate mbufs. */
+ if (clone == NULL)
+ goto teeout;
+
+ /*
+ * Divert listeners can only handle non-fragmented packets.
+ * However when tee is set we will *not* de-fragment the packets;
+ * Doing do would put the reassembly into double-jeopardy. On top
+ * of that someone doing a tee will probably want to get the packet
+ * in its original form.
+ */
+ ip = mtod(clone, struct ip *);
+ if (!tee && ip->ip_off & (IP_MF | IP_OFFMASK)) {
+
+ /* Reassemble packet. */
+ reass = ip_reass(clone);
+
+ /*
+ * IP header checksum fixup after reassembly and leave header
+ * in network byte order.
+ */
+ if (reass != NULL) {
+ ip = mtod(reass, struct ip *);
+ hlen = ip->ip_hl << 2;
+ ip->ip_len = htons(ip->ip_len);
+ ip->ip_off = htons(ip->ip_off);
+ ip->ip_sum = 0;
+ if (hlen == sizeof(struct ip))
+ ip->ip_sum = in_cksum_hdr(ip);
+ else
+ ip->ip_sum = in_cksum(reass, hlen);
+ clone = reass;
+ } else
+ clone = NULL;
+ } else {
+ /* Convert header to network byte order. */
+ ip->ip_len = htons(ip->ip_len);
+ ip->ip_off = htons(ip->ip_off);
+ }
+
+ /* Do the dirty job... */
+ if (clone)
+ divert_packet(clone, incoming);
+
+teeout:
+ if (tee) {
+ mtag = m_tag_find(*m, PACKET_TAG_DIVERT, NULL);
+ if (mtag != NULL)
+ m_tag_delete(*m, mtag);
+ return 0; /* continue with original packet. */
+ }
+
+ /* Packet diverted and consumed */
+ return 1;
+#else
+ m_freem(*m);
+ return 1;
+#endif /* ipdivert */
+}
+
+static int
+ipfw_hook(void)
+{
+ struct pfil_head *pfh_inet;
+
+ if (ipfw_pfil_hooked)
+ return EEXIST;
+
+ pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
+ if (pfh_inet == NULL)
+ return ENOENT;
+
+ pfil_add_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet);
+ pfil_add_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet);
+
+ return 0;
+}
+
+static int
+ipfw_unhook(void)
+{
+ struct pfil_head *pfh_inet;
+
+ if (!ipfw_pfil_hooked)
+ return ENOENT;
+
+ pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
+ if (pfh_inet == NULL)
+ return ENOENT;
+
+ pfil_remove_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet);
+ pfil_remove_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet);
+
+ return 0;
+}
+
+static int
+ipfw_modevent(module_t mod, int type, void *unused)
+{
+ int err = 0;
+
+ switch (type) {
+ case MOD_LOAD:
+ if (ipfw_pfil_hooked) {
+ printf("IP firewall already loaded\n");
+ err = EEXIST;
+ } else {
+ if ((err = ipfw_init()) != 0) {
+ printf("ipfw_init() error\n");
+ break;
+ }
+ if ((err = ipfw_hook()) != 0) {
+ printf("ipfw_hook() error\n");
+ break;
+ }
+ ipfw_pfil_hooked = 1;
+ }
+ break;
+
+ case MOD_UNLOAD:
+ if (ipfw_pfil_hooked) {
+ if ((err = ipfw_unhook()) > 0);
+ break;
+ ipfw_destroy();
+ ipfw_pfil_hooked = 0;
+ } else {
+ printf("IP firewall already unloaded\n");
+ }
+ break;
+
+ default:
+ return EOPNOTSUPP;
+ break;
+ }
+ return err;
+}
+
+static moduledata_t ipfwmod = {
+ "ipfw",
+ ipfw_modevent,
+ 0
+};
+DECLARE_MODULE(ipfw, ipfwmod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
+MODULE_VERSION(ipfw, 2);
diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c
index 0ae3c16..fc4ab6e 100644
--- a/sys/netinet/ip_input.c
+++ b/sys/netinet/ip_input.c
@@ -32,9 +32,6 @@
#include "opt_bootp.h"
#include "opt_ipfw.h"
-#include "opt_ipdn.h"
-#include "opt_ipdivert.h"
-#include "opt_ipfilter.h"
#include "opt_ipstealth.h"
#include "opt_ipsec.h"
#include "opt_mac.h"
@@ -72,8 +69,8 @@
#include <sys/socketvar.h>
+/* XXX: Temporary until ipfw_ether and ipfw_bridge are converted. */
#include <netinet/ip_fw.h>
-#include <netinet/ip_divert.h>
#include <netinet/ip_dummynet.h>
#ifdef IPSEC
@@ -208,15 +205,14 @@ SYSCTL_INT(_net_inet_ip, OID_AUTO, stealth, CTLFLAG_RW,
&ipstealth, 0, "");
#endif
-
-/* Firewall hooks */
-ip_fw_chk_t *ip_fw_chk_ptr;
-int fw_enable = 1 ;
+/*
+ * ipfw_ether and ipfw_bridge hooks.
+ * XXX: Temporary until those are converted to pfil_hooks as well.
+ */
+ip_fw_chk_t *ip_fw_chk_ptr = NULL;
+ip_dn_io_t *ip_dn_io_ptr = NULL;
int fw_one_pass = 1;
-/* Dummynet hooks */
-ip_dn_io_t *ip_dn_io_ptr;
-
/*
* XXX this is ugly -- the following two global variables are
* used to store packet state while it travels through the stack.
@@ -240,12 +236,9 @@ static struct ip_srcrt {
} ip_srcrt;
static void save_rte(u_char *, struct in_addr);
-static int ip_dooptions(struct mbuf *m, int,
- struct sockaddr_in *next_hop);
-static void ip_forward(struct mbuf *m, int srcrt,
- struct sockaddr_in *next_hop);
+static int ip_dooptions(struct mbuf *m, int);
+static void ip_forward(struct mbuf *m, int srcrt);
static void ip_freef(struct ipqhead *, struct ipq *);
-static struct mbuf *ip_reass(struct mbuf *);
/*
* IP initialization: fill in IP protocol switch table.
@@ -301,13 +294,8 @@ ip_input(struct mbuf *m)
struct ip *ip = NULL;
struct in_ifaddr *ia = NULL;
struct ifaddr *ifa;
- int i, checkif, hlen = 0;
+ int checkif, hlen = 0;
u_short sum;
- struct in_addr pkt_dst;
-#ifdef IPDIVERT
- u_int32_t divert_info; /* packet divert/tee info */
-#endif
- struct ip_fw_args args;
int dchg = 0; /* dest changed after fw */
#ifdef PFIL_HOOKS
struct in_addr odst; /* original dst address */
@@ -319,26 +307,20 @@ ip_input(struct mbuf *m)
int s, error;
#endif /* FAST_IPSEC */
- args.eh = NULL;
- args.oif = NULL;
-
M_ASSERTPKTHDR(m);
- args.next_hop = m_claim_next(m, PACKET_TAG_IPFORWARD);
- args.rule = ip_dn_claim_rule(m);
-
if (m->m_flags & M_FASTFWD_OURS) {
- /* ip_fastforward firewall changed dest to local */
+ /*
+ * ip_fastforward firewall changed dest to local.
+ * We expect ip_len and ip_off in host byte order.
+ */
m->m_flags &= ~M_FASTFWD_OURS; /* for reflected mbufs */
+ /* Set up some basic stuff */
+ ip = mtod(m, struct ip *);
+ hlen = ip->ip_hl << 2;
goto ours;
}
- if (args.rule) { /* dummynet already filtered us */
- ip = mtod(m, struct ip *);
- hlen = ip->ip_hl << 2;
- goto iphack ;
- }
-
ipstat.ips_total++;
if (m->m_pkthdr.len < sizeof(struct ip))
@@ -441,20 +423,6 @@ tooshort:
goto pass;
#endif
- /*
- * IpHack's section.
- * Right now when no processing on packet has done
- * and it is still fresh out of network we do our black
- * deals with it.
- * - Firewall: deny/allow/divert
- * - Xlate: translate packet's addr/port (NAT).
- * - Pipe: pass pkt through dummynet.
- * - Wrap: fake packet's addr/port <unimpl.>
- * - Encapsulate: put it in another IP and send out. <unimp.>
- */
-
-iphack:
-
#ifdef PFIL_HOOKS
/*
* Run through list of hooks for input packets.
@@ -469,50 +437,23 @@ iphack:
return;
if (m == NULL) /* consumed by filter */
return;
+
ip = mtod(m, struct ip *);
dchg = (odst.s_addr != ip->ip_dst.s_addr);
-#endif /* PFIL_HOOKS */
- if (fw_enable && IPFW_LOADED) {
- /*
- * If we've been forwarded from the output side, then
- * skip the firewall a second time
- */
- if (args.next_hop)
- goto ours;
+#ifdef IPFIREWALL_FORWARD
+ if (m->m_flags & M_FASTFWD_OURS) {
+ m->m_flags &= ~M_FASTFWD_OURS;
+ goto ours;
+ }
+ dchg = (m_tag_find(m, PACKET_TAG_IPFORWARD, NULL) != NULL);
+#endif /* IPFIREWALL_FORWARD */
- args.m = m;
- i = ip_fw_chk_ptr(&args);
- m = args.m;
+#endif /* PFIL_HOOKS */
- if ( (i & IP_FW_PORT_DENY_FLAG) || m == NULL) { /* drop */
- if (m)
- m_freem(m);
- return;
- }
- ip = mtod(m, struct ip *); /* just in case m changed */
- if (i == 0 && args.next_hop == NULL) /* common case */
- goto pass;
- if (DUMMYNET_LOADED && (i & IP_FW_PORT_DYNT_FLAG) != 0) {
- /* Send packet to the appropriate pipe */
- ip_dn_io_ptr(m, i&0xffff, DN_TO_IP_IN, &args);
- return;
- }
-#ifdef IPDIVERT
- if (i != 0 && (i & IP_FW_PORT_DYNT_FLAG) == 0) {
- /* Divert or tee packet */
- goto ours;
- }
-#endif
- if (i == 0 && args.next_hop != NULL)
- goto pass;
- /*
- * if we get here, the packet must be dropped
- */
- m_freem(m);
- return;
- }
+#if defined(FAST_IPSEC) && !defined(IPSEC_FILTERGIF)
pass:
+#endif
/*
* Process options and, if not destined for us,
@@ -520,8 +461,7 @@ pass:
* error was detected (causing an icmp message
* to be sent and the original packet to be freed).
*/
- ip_nhops = 0; /* for source routed packets */
- if (hlen > sizeof (struct ip) && ip_dooptions(m, 0, args.next_hop))
+ if (hlen > sizeof (struct ip) && ip_dooptions(m, 0))
return;
/* greedy RSVP, snatches any PATH packet of the RSVP protocol and no
@@ -544,12 +484,6 @@ pass:
goto ours;
/*
- * Cache the destination address of the packet; this may be
- * changed by use of 'ipfw fwd'.
- */
- pkt_dst = args.next_hop ? args.next_hop->sin_addr : ip->ip_dst;
-
- /*
* Enable a consistency check between the destination address
* and the arrival interface for a unicast packet (the RFC 1122
* strong ES model) if IP forwarding is disabled and the packet
@@ -566,18 +500,18 @@ pass:
checkif = ip_checkinterface && (ipforwarding == 0) &&
m->m_pkthdr.rcvif != NULL &&
((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) &&
- (args.next_hop == NULL) && (dchg == 0);
+ (dchg == 0);
/*
* Check for exact addresses in the hash bucket.
*/
- LIST_FOREACH(ia, INADDR_HASH(pkt_dst.s_addr), ia_hash) {
+ LIST_FOREACH(ia, INADDR_HASH(ip->ip_dst.s_addr), ia_hash) {
/*
* If the address matches, verify that the packet
* arrived via the correct interface if checking is
* enabled.
*/
- if (IA_SIN(ia)->sin_addr.s_addr == pkt_dst.s_addr &&
+ if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr &&
(!checkif || ia->ia_ifp == m->m_pkthdr.rcvif))
goto ours;
}
@@ -596,9 +530,9 @@ pass:
continue;
ia = ifatoia(ifa);
if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
- pkt_dst.s_addr)
+ ip->ip_dst.s_addr)
goto ours;
- if (ia->ia_netbroadcast.s_addr == pkt_dst.s_addr)
+ if (ia->ia_netbroadcast.s_addr == ip->ip_dst.s_addr)
goto ours;
#ifdef BOOTP_COMPAT
if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY)
@@ -706,7 +640,7 @@ pass:
goto bad;
}
#endif /* FAST_IPSEC */
- ip_forward(m, dchg, args.next_hop);
+ ip_forward(m, dchg);
}
return;
@@ -717,7 +651,7 @@ ours:
* if the packet is destined for us.
*/
if (ipstealth && hlen > sizeof (struct ip) &&
- ip_dooptions(m, 1, args.next_hop))
+ ip_dooptions(m, 1))
return;
#endif /* IPSTEALTH */
@@ -738,20 +672,6 @@ ours:
ip = mtod(m, struct ip *);
/* Get the header length of the reassembled packet */
hlen = ip->ip_hl << 2;
-#ifdef IPDIVERT
- /* Restore original checksum before diverting packet */
- if (divert_find_info(m) != 0) {
- ip->ip_len = htons(ip->ip_len);
- ip->ip_off = htons(ip->ip_off);
- ip->ip_sum = 0;
- if (hlen == sizeof(struct ip))
- ip->ip_sum = in_cksum_hdr(ip);
- else
- ip->ip_sum = in_cksum(m, hlen);
- ip->ip_off = ntohs(ip->ip_off);
- ip->ip_len = ntohs(ip->ip_len);
- }
-#endif
}
/*
@@ -760,46 +680,6 @@ ours:
*/
ip->ip_len -= hlen;
-#ifdef IPDIVERT
- /*
- * Divert or tee packet to the divert protocol if required.
- */
- divert_info = divert_find_info(m);
- if (divert_info != 0) {
- struct mbuf *clone;
-
- /* Clone packet if we're doing a 'tee' */
- if ((divert_info & IP_FW_PORT_TEE_FLAG) != 0)
- clone = divert_clone(m);
- else
- clone = NULL;
-
- /* Restore packet header fields to original values */
- ip->ip_len += hlen;
- ip->ip_len = htons(ip->ip_len);
- ip->ip_off = htons(ip->ip_off);
-
- /* Deliver packet to divert input routine */
- divert_packet(m, 1);
- ipstat.ips_delivered++;
-
- /* If 'tee', continue with original packet */
- if (clone == NULL)
- return;
- m = clone;
- ip = mtod(m, struct ip *);
- ip->ip_len += hlen;
- /*
- * Jump backwards to complete processing of the
- * packet. We do not need to clear args.next_hop
- * as that will not be used again and the cloned packet
- * doesn't contain a divert packet tag so we won't
- * re-entry this block.
- */
- goto pass;
- }
-#endif
-
#ifdef IPSEC
/*
* enforce IPsec policy checking if we are seeing last header.
@@ -856,15 +736,7 @@ DPRINTF(("ip_input: no SP, packet discarded\n"));/*XXX*/
* Switch out to protocol's input routine.
*/
ipstat.ips_delivered++;
- if (args.next_hop && ip->ip_p == IPPROTO_TCP) {
- /* attach next hop info for TCP */
- struct m_tag *mtag = m_tag_get(PACKET_TAG_IPFORWARD,
- sizeof(struct sockaddr_in *), M_NOWAIT);
- if (mtag == NULL)
- goto bad;
- *(struct sockaddr_in **)(mtag+1) = args.next_hop;
- m_tag_prepend(m, mtag);
- }
+
(*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen);
return;
bad:
@@ -1092,18 +964,6 @@ found:
inserted:
-#ifdef IPDIVERT
- if (ip->ip_off != 0) {
- /*
- * Strip any divert information; only the info
- * on the first fragment is used/kept.
- */
- struct m_tag *mtag = m_tag_find(m, PACKET_TAG_DIVERT, NULL);
- if (mtag)
- m_tag_delete(m, mtag);
- }
-#endif
-
/*
* Check for complete reassembly and perform frag per packet
* limiting.
@@ -1298,7 +1158,7 @@ ip_drain()
* 0 if the packet should be processed further.
*/
static int
-ip_dooptions(struct mbuf *m, int pass, struct sockaddr_in *next_hop)
+ip_dooptions(struct mbuf *m, int pass)
{
struct ip *ip = mtod(m, struct ip *);
u_char *cp;
@@ -1557,7 +1417,7 @@ dropit:
}
}
if (forward && ipforwarding) {
- ip_forward(m, 1, next_hop);
+ ip_forward(m, 1);
return (1);
}
return (0);
@@ -1737,35 +1597,25 @@ u_char inetctlerrmap[PRC_NCMDS] = {
* The srcrt parameter indicates whether the packet is being forwarded
* via a source route.
*/
-static void
-ip_forward(struct mbuf *m, int srcrt, struct sockaddr_in *next_hop)
+void
+ip_forward(struct mbuf *m, int srcrt)
{
struct ip *ip = mtod(m, struct ip *);
- struct in_ifaddr *ia;
+ struct in_ifaddr *ia = NULL;
int error, type = 0, code = 0;
struct mbuf *mcopy;
- n_long dest;
- struct in_addr pkt_dst;
- struct ifnet *destifp;
-#if defined(IPSEC) || defined(FAST_IPSEC)
- struct ifnet dummyifp;
-#endif
-
- /*
- * Cache the destination address of the packet; this may be
- * changed by use of 'ipfw fwd'.
- */
- pkt_dst = next_hop ? next_hop->sin_addr : ip->ip_dst;
+ struct in_addr dest;
+ struct ifnet *destifp, dummyifp;
#ifdef DIAGNOSTIC
if (ipprintfs)
printf("forward: src %lx dst %lx ttl %x\n",
- (u_long)ip->ip_src.s_addr, (u_long)pkt_dst.s_addr,
+ (u_long)ip->ip_src.s_addr, (u_long)ip->ip_dst.s_addr,
ip->ip_ttl);
#endif
- if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(pkt_dst) == 0) {
+ if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(ip->ip_dst) == 0) {
ipstat.ips_cantforward++;
m_freem(m);
return;
@@ -1782,7 +1632,7 @@ ip_forward(struct mbuf *m, int srcrt, struct sockaddr_in *next_hop)
}
#endif
- if ((ia = ip_rtaddr(pkt_dst)) == NULL) {
+ if (!srcrt && (ia = ip_rtaddr(ip->ip_dst)) == NULL) {
icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0);
return;
}
@@ -1837,8 +1687,8 @@ ip_forward(struct mbuf *m, int srcrt, struct sockaddr_in *next_hop)
* Also, don't send redirect if forwarding using a default route
* or a route modified by a redirect.
*/
- dest = 0;
- if (ipsendredirects && ia->ia_ifp == m->m_pkthdr.rcvif) {
+ dest.s_addr = 0;
+ if (!srcrt && ipsendredirects && ia->ia_ifp == m->m_pkthdr.rcvif) {
struct sockaddr_in *sin;
struct route ro;
struct rtentry *rt;
@@ -1847,29 +1697,28 @@ ip_forward(struct mbuf *m, int srcrt, struct sockaddr_in *next_hop)
sin = (struct sockaddr_in *)&ro.ro_dst;
sin->sin_family = AF_INET;
sin->sin_len = sizeof(*sin);
- sin->sin_addr = pkt_dst;
+ sin->sin_addr = ip->ip_dst;
rtalloc_ign(&ro, RTF_CLONING);
rt = ro.ro_rt;
if (rt && (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 &&
- satosin(rt_key(rt))->sin_addr.s_addr != 0 &&
- ipsendredirects && !srcrt && !next_hop) {
+ satosin(rt_key(rt))->sin_addr.s_addr != 0) {
#define RTA(rt) ((struct in_ifaddr *)(rt->rt_ifa))
u_long src = ntohl(ip->ip_src.s_addr);
if (RTA(rt) &&
(src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) {
if (rt->rt_flags & RTF_GATEWAY)
- dest = satosin(rt->rt_gateway)->sin_addr.s_addr;
+ dest.s_addr = satosin(rt->rt_gateway)->sin_addr.s_addr;
else
- dest = pkt_dst.s_addr;
+ dest.s_addr = ip->ip_dst.s_addr;
/* Router requirements says to only send host redirects */
type = ICMP_REDIRECT;
code = ICMP_REDIRECT_HOST;
#ifdef DIAGNOSTIC
if (ipprintfs)
- printf("redirect (%d) to %lx\n", code, (u_long)dest);
+ printf("redirect (%d) to %lx\n", code, (u_long)dest.s_addr);
#endif
}
}
@@ -1877,16 +1726,6 @@ ip_forward(struct mbuf *m, int srcrt, struct sockaddr_in *next_hop)
RTFREE(rt);
}
- if (next_hop) {
- struct m_tag *mtag = m_tag_get(PACKET_TAG_IPFORWARD,
- sizeof(struct sockaddr_in *), M_NOWAIT);
- if (mtag == NULL) {
- m_freem(m);
- return;
- }
- *(struct sockaddr_in **)(mtag+1) = next_hop;
- m_tag_prepend(m, mtag);
- }
error = ip_output(m, (struct mbuf *)0, NULL, IP_FORWARDING, 0, NULL);
if (error)
ipstat.ips_cantforward++;
@@ -1985,7 +1824,16 @@ ip_forward(struct mbuf *m, int srcrt, struct sockaddr_in *next_hop)
break;
} else
#endif /*IPSEC || FAST_IPSEC*/
- destifp = ia->ia_ifp;
+ /*
+ * When doing source routing 'ia' can be NULL. Fall back
+ * to the minimum guaranteed routeable packet size and use
+ * the same hack as IPSEC to setup a dummyifp for icmp.
+ */
+ if (ia == NULL) {
+ dummyifp.if_mtu = IP_MSS;
+ destifp = &dummyifp;
+ } else
+ destifp = ia->ia_ifp;
#if defined(IPSEC) || defined(FAST_IPSEC)
}
#endif /*IPSEC || FAST_IPSEC*/
@@ -2014,7 +1862,7 @@ ip_forward(struct mbuf *m, int srcrt, struct sockaddr_in *next_hop)
m_freem(mcopy);
return;
}
- icmp_error(mcopy, type, code, dest, destifp);
+ icmp_error(mcopy, type, code, dest.s_addr, destifp);
}
void
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index 4946153..c40c682 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -31,9 +31,6 @@
*/
#include "opt_ipfw.h"
-#include "opt_ipdn.h"
-#include "opt_ipdivert.h"
-#include "opt_ipfilter.h"
#include "opt_ipsec.h"
#include "opt_mac.h"
#include "opt_pfil_hooks.h"
@@ -51,6 +48,7 @@
#include <sys/sysctl.h>
#include <net/if.h>
+#include <net/netisr.h>
#include <net/route.h>
#include <netinet/in.h>
@@ -84,10 +82,6 @@ static MALLOC_DEFINE(M_IPMOPTS, "ip_moptions", "internet multicast options");
#include <netipsec/key.h>
#endif /*FAST_IPSEC*/
-#include <netinet/ip_fw.h>
-#include <netinet/ip_divert.h>
-#include <netinet/ip_dummynet.h>
-
#define print_ip(x, a, y) printf("%s %d.%d.%d.%d%s",\
x, (ntohl(a.s_addr)>>24)&0xFF,\
(ntohl(a.s_addr)>>16)&0xFF,\
@@ -133,49 +127,27 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro,
struct ifnet *ifp = NULL; /* keep compiler happy */
struct mbuf *m0;
int hlen = sizeof (struct ip);
- int len, off, error = 0;
+ int len, error = 0;
struct sockaddr_in *dst = NULL; /* keep compiler happy */
struct in_ifaddr *ia = NULL;
int isbroadcast, sw_csum;
- struct in_addr pkt_dst;
struct route iproute;
- struct m_tag *mtag, *dummytag;
+ struct in_addr odst;
+#ifdef IPFIREWALL_FORWARD
+ struct m_tag *fwd_tag = NULL;
+#endif
#ifdef IPSEC
struct secpolicy *sp = NULL;
#endif
#ifdef FAST_IPSEC
struct secpolicy *sp = NULL;
struct tdb_ident *tdbi;
+ struct m_tag *mtag;
int s;
#endif /* FAST_IPSEC */
- struct ip_fw_args args;
- int src_was_INADDR_ANY = 0; /* as the name says... */
-
- args.eh = NULL;
- args.rule = NULL;
M_ASSERTPKTHDR(m);
- args.next_hop = m_claim_next(m, PACKET_TAG_IPFORWARD);
- dummytag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
- if (dummytag != NULL) {
- struct dn_pkt_tag *dt = (struct dn_pkt_tag *)(dummytag+1);
- /*
- * Prevent lower layers from finding the tag
- * Cleanup and free is done below
- */
- m_tag_unlink(m, dummytag);
- /*
- * the packet was already tagged, so part of the
- * processing was already done, and we need to go down.
- * Get parameters from the header.
- */
- args.rule = dt->rule;
- ro = &(dt->ro);
- dst = dt->dn_dst;
- ifp = dt->ifp;
- }
-
if (ro == NULL) {
ro = &iproute;
bzero(ro, sizeof (*ro));
@@ -184,14 +156,6 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro,
if (inp != NULL)
INP_LOCK_ASSERT(inp);
- if (args.rule != NULL) { /* dummynet already saw us */
- ip = mtod(m, struct ip *);
- hlen = ip->ip_hl << 2 ;
- if (ro->ro_rt)
- ia = ifatoia(ro->ro_rt->rt_ifa);
- goto sendit;
- }
-
if (opt) {
len = 0;
m = ip_insertoptions(m, opt, &len);
@@ -199,7 +163,6 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro,
hlen = len;
}
ip = mtod(m, struct ip *);
- pkt_dst = args.next_hop ? args.next_hop->sin_addr : ip->ip_dst;
/*
* Fill in IP header. If we are not allowing fragmentation,
@@ -222,6 +185,7 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro,
}
dst = (struct sockaddr_in *)&ro->ro_dst;
+again:
/*
* If there is a cached route,
* check that it is to the same destination
@@ -231,15 +195,19 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro,
*/
if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
dst->sin_family != AF_INET ||
- dst->sin_addr.s_addr != pkt_dst.s_addr)) {
+ dst->sin_addr.s_addr != ip->ip_dst.s_addr)) {
RTFREE(ro->ro_rt);
ro->ro_rt = (struct rtentry *)0;
}
+#ifdef IPFIREWALL_FORWARD
+ if (ro->ro_rt == NULL && fwd_tag == NULL) {
+#else
if (ro->ro_rt == NULL) {
+#endif
bzero(dst, sizeof(*dst));
dst->sin_family = AF_INET;
dst->sin_len = sizeof(*dst);
- dst->sin_addr = pkt_dst;
+ dst->sin_addr = ip->ip_dst;
}
/*
* If routing to interface only,
@@ -287,7 +255,7 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro,
else
isbroadcast = in_broadcast(dst->sin_addr, ifp);
}
- if (IN_MULTICAST(ntohl(pkt_dst.s_addr))) {
+ if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
struct in_multi *inm;
m->m_flags |= M_MCAST;
@@ -329,7 +297,7 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro,
ip->ip_src = IA_SIN(ia)->sin_addr;
}
- IN_LOOKUP_MULTI(pkt_dst, ifp, inm);
+ IN_LOOKUP_MULTI(ip->ip_dst, ifp, inm);
if (inm != NULL &&
(imo == NULL || imo->imo_multicast_loop)) {
/*
@@ -395,7 +363,6 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro,
/* Interface may have no addresses. */
if (ia != NULL) {
ip->ip_src = IA_SIN(ia)->sin_addr;
- src_was_INADDR_ANY = 1;
}
}
#endif /* notdef */
@@ -693,250 +660,75 @@ skip_ipsec:
spd_done:
#endif /* FAST_IPSEC */
- /*
- * IpHack's section.
- * - Xlate: translate packet's addr/port (NAT).
- * - Firewall: deny/allow/etc.
- * - Wrap: fake packet's addr/port <unimpl.>
- * - Encapsulate: put it in another IP and send out. <unimp.>
- */
#ifdef PFIL_HOOKS
/*
* Run through list of hooks for output packets.
*/
+ odst.s_addr = ip->ip_dst.s_addr;
error = pfil_run_hooks(&inet_pfil_hook, &m, ifp, PFIL_OUT);
if (error != 0 || m == NULL)
goto done;
- ip = mtod(m, struct ip *);
-#endif /* PFIL_HOOKS */
-
- /*
- * Check with the firewall...
- * but not if we are already being fwd'd from a firewall.
- */
- if (fw_enable && IPFW_LOADED && !args.next_hop) {
- struct sockaddr_in *old = dst;
-
- args.m = m;
- args.next_hop = dst;
- args.oif = ifp;
- off = ip_fw_chk_ptr(&args);
- m = args.m;
- dst = args.next_hop;
-
- /*
- * On return we must do the following:
- * m == NULL -> drop the pkt (old interface, deprecated)
- * (off & IP_FW_PORT_DENY_FLAG) -> drop the pkt (new interface)
- * 1<=off<= 0xffff -> DIVERT
- * (off & IP_FW_PORT_DYNT_FLAG) -> send to a DUMMYNET pipe
- * (off & IP_FW_PORT_TEE_FLAG) -> TEE the packet
- * dst != old -> IPFIREWALL_FORWARD
- * off==0, dst==old -> accept
- * If some of the above modules are 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 ( (off & IP_FW_PORT_DENY_FLAG) || m == NULL) {
- if (m)
- m_freem(m);
- error = EACCES;
- goto done;
- }
- ip = mtod(m, struct ip *);
- if (off == 0 && dst == old) /* common case */
- goto pass;
- if (DUMMYNET_LOADED && (off & IP_FW_PORT_DYNT_FLAG) != 0) {
- /*
- * pass the pkt to dummynet. Need to include
- * pipe number, m, ifp, ro, dst 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!
- */
- args.ro = ro;
- args.dst = dst;
- args.flags = flags;
-
- error = ip_dn_io_ptr(m, off & 0xffff, DN_TO_IP_OUT,
- &args);
- goto done;
- }
-#ifdef IPDIVERT
- if (off != 0 && (off & IP_FW_PORT_DYNT_FLAG) == 0) {
- struct mbuf *clone;
-
- /* Clone packet if we're doing a 'tee' */
- if ((off & IP_FW_PORT_TEE_FLAG) != 0)
- clone = divert_clone(m);
- else
- clone = NULL;
-
- /* Restore packet header fields to original values */
- ip->ip_len = htons(ip->ip_len);
- ip->ip_off = htons(ip->ip_off);
-
- /* Deliver packet to divert input routine */
- divert_packet(m, 0);
-
- /* If 'tee', continue with original packet */
- if (clone != NULL) {
- m = clone;
- ip = mtod(m, struct ip *);
- goto pass;
- }
- goto done;
- }
-#endif
-
- /* IPFIREWALL_FORWARD */
- /*
- * Check dst to make sure it is directly reachable on the
- * interface we previously thought it was.
- * If it isn't (which may be likely in some situations) we have
- * to re-route it (ie, find a route for the next-hop and the
- * associated interface) and set them here. This is nested
- * forwarding which in most cases is undesirable, except where
- * such control is nigh impossible. So we do it here.
- * And I'm babbling.
- */
- if (off == 0 && old != dst) { /* FORWARD, dst has changed */
-#if 0
- /*
- * XXX To improve readability, this block should be
- * changed into a function call as below:
- */
- error = ip_ipforward(&m, &dst, &ifp);
- if (error)
- goto bad;
- if (m == NULL) /* ip_input consumed the mbuf */
- goto done;
-#else
- struct in_ifaddr *ia;
- /*
- * XXX sro_fwd below is static, and a pointer
- * to it gets passed to routines downstream.
- * This could have surprisingly bad results in
- * practice, because its content is overwritten
- * by subsequent packets.
- * XXX: Breaks on SMP and possibly preemption!
- */
- /* There must be a better way to do this next line... */
- static struct route sro_fwd;
- struct route *ro_fwd = &sro_fwd;
-
-#if 0
- print_ip("IPFIREWALL_FORWARD: New dst ip: ",
- dst->sin_addr, "\n");
-#endif
+ ip = mtod(m, struct ip *);
- /*
- * We need to figure out if we have been forwarded
- * to a local socket. If so, then we should somehow
- * "loop back" to ip_input, and get directed to the
- * PCB as if we had received this packet. This is
- * because it may be dificult to identify the packets
- * you want to forward until they are being output
- * and have selected an interface. (e.g. locally
- * initiated packets) If we used the loopback inteface,
- * we would not be able to control what happens
- * as the packet runs through ip_input() as
- * it is done through an ISR.
- */
- LIST_FOREACH(ia,
- INADDR_HASH(dst->sin_addr.s_addr), ia_hash) {
- /*
- * If the addr to forward to is one
- * of ours, we pretend to
- * be the destination for this packet.
- */
- if (IA_SIN(ia)->sin_addr.s_addr ==
- dst->sin_addr.s_addr)
- break;
- }
- if (ia) { /* tell ip_input "dont filter" */
- mtag = m_tag_get(
- PACKET_TAG_IPFORWARD,
- sizeof(struct sockaddr_in *), M_NOWAIT);
- if (mtag == NULL) {
- error = ENOBUFS;
- goto bad;
- }
- *(struct sockaddr_in **)(mtag+1) =
- args.next_hop;
- m_tag_prepend(m, mtag);
-
- if (m->m_pkthdr.rcvif == NULL)
- m->m_pkthdr.rcvif = ifunit("lo0");
- if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
- m->m_pkthdr.csum_flags |=
- CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
- m->m_pkthdr.csum_data = 0xffff;
- }
+ /* See if destination IP address was changed by packet filter. */
+ if (odst.s_addr != ip->ip_dst.s_addr) {
+ m->m_flags |= M_SKIP_FIREWALL;
+ if (in_localip(ip->ip_dst)) {
+ m->m_flags |= M_FASTFWD_OURS;
+ if (m->m_pkthdr.rcvif == NULL)
+ m->m_pkthdr.rcvif = ifunit("lo0");
+ if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
m->m_pkthdr.csum_flags |=
- CSUM_IP_CHECKED | CSUM_IP_VALID;
- ip->ip_len = htons(ip->ip_len);
- ip->ip_off = htons(ip->ip_off);
- ip_input(m);
- goto done;
+ CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
+ m->m_pkthdr.csum_data = 0xffff;
}
- /*
- * Some of the logic for this was
- * nicked from above.
- */
- bcopy(dst, &ro_fwd->ro_dst, sizeof(*dst));
-
- ro_fwd->ro_rt = 0;
- rtalloc_ign(ro_fwd, RTF_CLONING);
+ m->m_pkthdr.csum_flags |=
+ CSUM_IP_CHECKED | CSUM_IP_VALID;
- if (ro_fwd->ro_rt == NULL) {
- ipstat.ips_noroute++;
- error = EHOSTUNREACH;
- goto bad;
- }
-
- ia = ifatoia(ro_fwd->ro_rt->rt_ifa);
- ifp = ro_fwd->ro_rt->rt_ifp;
- ro_fwd->ro_rt->rt_rmx.rmx_pksent++;
- if (ro_fwd->ro_rt->rt_flags & RTF_GATEWAY)
- dst = (struct sockaddr_in *)
- ro_fwd->ro_rt->rt_gateway;
- if (ro_fwd->ro_rt->rt_flags & RTF_HOST)
- isbroadcast =
- (ro_fwd->ro_rt->rt_flags & RTF_BROADCAST);
- else
- isbroadcast = in_broadcast(dst->sin_addr, ifp);
- if (ro->ro_rt)
- RTFREE(ro->ro_rt);
- ro->ro_rt = ro_fwd->ro_rt;
- dst = (struct sockaddr_in *)&ro_fwd->ro_dst;
+ error = netisr_queue(NETISR_IP, m);
+ goto done;
+ } else
+ goto again;
+ }
-#endif /* ... block to be put into a function */
- /*
- * If we added a default src ip earlier,
- * which would have been gotten from the-then
- * interface, do it again, from the new one.
- */
- if (src_was_INADDR_ANY)
- ip->ip_src = IA_SIN(ia)->sin_addr;
- goto pass ;
+#ifdef IPFIREWALL_FORWARD
+ /* See if local, if yes, send it to netisr with IP_FASTFWD_OURS. */
+ if (m->m_flags & M_FASTFWD_OURS) {
+ if (m->m_pkthdr.rcvif == NULL)
+ m->m_pkthdr.rcvif = ifunit("lo0");
+ if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
+ m->m_pkthdr.csum_flags |=
+ CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
+ m->m_pkthdr.csum_data = 0xffff;
}
+ m->m_pkthdr.csum_flags |=
+ CSUM_IP_CHECKED | CSUM_IP_VALID;
- /*
- * 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;
+ error = netisr_queue(NETISR_IP, m);
+ goto done;
}
+ /* Or forward to some other address? */
+ fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL);
+ if (fwd_tag) {
+ if (!in_localip(ip->ip_src) && !in_localaddr(ip->ip_dst)) {
+ dst = (struct sockaddr_in *)&ro->ro_dst;
+ bcopy((fwd_tag+1), dst, sizeof(struct sockaddr_in));
+ m->m_flags |= M_SKIP_FIREWALL;
+ m_tag_delete(m, fwd_tag);
+ goto again;
+ } else {
+ m_tag_delete(m, fwd_tag);
+ /* Continue. */
+ }
+ }
+#endif
+#endif /* PFIL_HOOKS */
+
+#if 0
pass:
+#endif
/* 127/8 must not appear on wire - RFC1122. */
if ((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET ||
(ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) {
@@ -1037,13 +829,6 @@ pass:
done:
if (ro == &iproute && ro->ro_rt) {
RTFREE(ro->ro_rt);
- ro->ro_rt = NULL;
- }
- if (dummytag) {
- struct dn_pkt_tag *dt = (struct dn_pkt_tag *)(dummytag+1);
- if (dt->ro.ro_rt)
- RTFREE(dt->ro.ro_rt);
- m_tag_free(dummytag);
}
#ifdef IPSEC
if (sp != NULL) {
diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h
index 66da695b..f557225 100644
--- a/sys/netinet/ip_var.h
+++ b/sys/netinet/ip_var.h
@@ -168,6 +168,8 @@ extern int (*ip_mforward)(struct ip *, struct ifnet *, struct mbuf *,
int ip_output(struct mbuf *,
struct mbuf *, struct route *, int, struct ip_moptions *,
struct inpcb *);
+struct mbuf *
+ ip_reass(struct mbuf *);
struct in_ifaddr *
ip_rtaddr(struct in_addr);
void ip_savecontrol(struct inpcb *, struct mbuf **, struct ip *,
diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c
index 50e1961..f8796f1 100644
--- a/sys/netinet/raw_ip.c
+++ b/sys/netinet/raw_ip.c
@@ -78,8 +78,8 @@ struct inpcbhead ripcb;
struct inpcbinfo ripcbinfo;
/* control hooks for ipfw and dummynet */
-ip_fw_ctl_t *ip_fw_ctl_ptr;
-ip_dn_ctl_t *ip_dn_ctl_ptr;
+ip_fw_ctl_t *ip_fw_ctl_ptr = NULL;
+ip_dn_ctl_t *ip_dn_ctl_ptr = NULL;
/*
* hooks for multicast routing. They all default to NULL,
@@ -358,14 +358,14 @@ rip_ctloutput(struct socket *so, struct sockopt *sopt)
case IP_FW_GET:
case IP_FW_TABLE_GETSIZE:
case IP_FW_TABLE_LIST:
- if (IPFW_LOADED)
+ if (ip_fw_ctl_ptr != NULL)
error = ip_fw_ctl_ptr(sopt);
else
error = ENOPROTOOPT;
break;
case IP_DUMMYNET_GET:
- if (DUMMYNET_LOADED)
+ if (ip_dn_ctl_ptr != NULL)
error = ip_dn_ctl_ptr(sopt);
else
error = ENOPROTOOPT;
@@ -414,7 +414,7 @@ rip_ctloutput(struct socket *so, struct sockopt *sopt)
case IP_FW_TABLE_ADD:
case IP_FW_TABLE_DEL:
case IP_FW_TABLE_FLUSH:
- if (IPFW_LOADED)
+ if (ip_fw_ctl_ptr != NULL)
error = ip_fw_ctl_ptr(sopt);
else
error = ENOPROTOOPT;
@@ -423,7 +423,7 @@ rip_ctloutput(struct socket *so, struct sockopt *sopt)
case IP_DUMMYNET_CONFIGURE:
case IP_DUMMYNET_DEL:
case IP_DUMMYNET_FLUSH:
- if (DUMMYNET_LOADED)
+ if (ip_dn_ctl_ptr != NULL)
error = ip_dn_ctl_ptr(sopt);
else
error = ENOPROTOOPT ;
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 902044b..3b70e99 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -429,7 +429,9 @@ tcp_input(m, off0)
struct tcpopt to; /* options in this segment */
struct rmxp_tao tao; /* our TAO cache entry */
int headlocked = 0;
- struct sockaddr_in *next_hop = NULL;
+#ifdef IPFIREWALL_FORWARD
+ struct m_tag *fwd_tag;
+#endif
int rstreason; /* For badport_bandlim accounting purposes */
struct ip6_hdr *ip6 = NULL;
@@ -449,8 +451,6 @@ tcp_input(m, off0)
short ostate = 0;
#endif
- /* Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain. */
- next_hop = m_claim_next(m, PACKET_TAG_IPFORWARD);
#ifdef INET6
isipv6 = (mtod(m, struct ip *)->ip_v == 6) ? 1 : 0;
#endif
@@ -611,17 +611,24 @@ tcp_input(m, off0)
INP_INFO_WLOCK(&tcbinfo);
headlocked = 1;
findpcb:
- /* IPFIREWALL_FORWARD section */
- if (next_hop != NULL && isipv6 == 0) { /* IPv6 support is not yet */
+#ifdef IPFIREWALL_FORWARD
+ /* Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain. */
+ fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL);
+
+ if (fwd_tag != NULL && isipv6 == 0) { /* IPv6 support is not yet */
+ struct sockaddr_in *next_hop;
+
+ next_hop = (struct sockaddr_in *)(fwd_tag+1);
/*
* Transparently forwarded. Pretend to be the destination.
* already got one like this?
*/
- inp = in_pcblookup_hash(&tcbinfo, ip->ip_src, th->th_sport,
+ inp = in_pcblookup_hash(&tcbinfo,
+ ip->ip_src, th->th_sport,
ip->ip_dst, th->th_dport,
0, m->m_pkthdr.rcvif);
if (!inp) {
- /* It's new. Try find the ambushing socket. */
+ /* It's new. Try to find the ambushing socket. */
inp = in_pcblookup_hash(&tcbinfo,
ip->ip_src, th->th_sport,
next_hop->sin_addr,
@@ -630,7 +637,10 @@ findpcb:
th->th_dport,
1, m->m_pkthdr.rcvif);
}
+ /* Remove the tag from the packet. We don't need it anymore. */
+ m_tag_delete(m, fwd_tag);
} else {
+#endif /* IPFIREWALL_FORWARD */
if (isipv6) {
#ifdef INET6
inp = in6_pcblookup_hash(&tcbinfo,
@@ -643,7 +653,9 @@ findpcb:
ip->ip_src, th->th_sport,
ip->ip_dst, th->th_dport,
1, m->m_pkthdr.rcvif);
+#ifdef IPFIREWALL_FORWARD
}
+#endif /* IPFIREWALL_FORWARD */
#if defined(IPSEC) || defined(FAST_IPSEC)
#ifdef INET6
diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c
index 902044b..3b70e99 100644
--- a/sys/netinet/tcp_reass.c
+++ b/sys/netinet/tcp_reass.c
@@ -429,7 +429,9 @@ tcp_input(m, off0)
struct tcpopt to; /* options in this segment */
struct rmxp_tao tao; /* our TAO cache entry */
int headlocked = 0;
- struct sockaddr_in *next_hop = NULL;
+#ifdef IPFIREWALL_FORWARD
+ struct m_tag *fwd_tag;
+#endif
int rstreason; /* For badport_bandlim accounting purposes */
struct ip6_hdr *ip6 = NULL;
@@ -449,8 +451,6 @@ tcp_input(m, off0)
short ostate = 0;
#endif
- /* Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain. */
- next_hop = m_claim_next(m, PACKET_TAG_IPFORWARD);
#ifdef INET6
isipv6 = (mtod(m, struct ip *)->ip_v == 6) ? 1 : 0;
#endif
@@ -611,17 +611,24 @@ tcp_input(m, off0)
INP_INFO_WLOCK(&tcbinfo);
headlocked = 1;
findpcb:
- /* IPFIREWALL_FORWARD section */
- if (next_hop != NULL && isipv6 == 0) { /* IPv6 support is not yet */
+#ifdef IPFIREWALL_FORWARD
+ /* Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain. */
+ fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL);
+
+ if (fwd_tag != NULL && isipv6 == 0) { /* IPv6 support is not yet */
+ struct sockaddr_in *next_hop;
+
+ next_hop = (struct sockaddr_in *)(fwd_tag+1);
/*
* Transparently forwarded. Pretend to be the destination.
* already got one like this?
*/
- inp = in_pcblookup_hash(&tcbinfo, ip->ip_src, th->th_sport,
+ inp = in_pcblookup_hash(&tcbinfo,
+ ip->ip_src, th->th_sport,
ip->ip_dst, th->th_dport,
0, m->m_pkthdr.rcvif);
if (!inp) {
- /* It's new. Try find the ambushing socket. */
+ /* It's new. Try to find the ambushing socket. */
inp = in_pcblookup_hash(&tcbinfo,
ip->ip_src, th->th_sport,
next_hop->sin_addr,
@@ -630,7 +637,10 @@ findpcb:
th->th_dport,
1, m->m_pkthdr.rcvif);
}
+ /* Remove the tag from the packet. We don't need it anymore. */
+ m_tag_delete(m, fwd_tag);
} else {
+#endif /* IPFIREWALL_FORWARD */
if (isipv6) {
#ifdef INET6
inp = in6_pcblookup_hash(&tcbinfo,
@@ -643,7 +653,9 @@ findpcb:
ip->ip_src, th->th_sport,
ip->ip_dst, th->th_dport,
1, m->m_pkthdr.rcvif);
+#ifdef IPFIREWALL_FORWARD
}
+#endif /* IPFIREWALL_FORWARD */
#if defined(IPSEC) || defined(FAST_IPSEC)
#ifdef INET6
diff --git a/sys/netinet/tcp_sack.c b/sys/netinet/tcp_sack.c
index 52c1980..1cf44f2 100644
--- a/sys/netinet/tcp_sack.c
+++ b/sys/netinet/tcp_sack.c
@@ -96,7 +96,6 @@
* official policies, either expressed or implied, of the US Naval
* Research Laboratory (NRL).
*/
-#include "opt_ipfw.h" /* for ipfw_fwd */
#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_ipsec.h"
diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h
index a1fa6c8..ff799bc 100644
--- a/sys/sys/mbuf.h
+++ b/sys/sys/mbuf.h
@@ -737,21 +737,6 @@ m_tag_find(struct mbuf *m, int type, struct m_tag *start)
NULL : m_tag_locate(m, MTAG_ABI_COMPAT, type, start));
}
-/*
- * Obtain next_hop information associated with the mbuf, if any.
- * If a tag is present devalidate it also.
- */
-static __inline struct sockaddr_in *
-m_claim_next(struct mbuf *m, int type)
-{
- struct m_tag *mtag = m_tag_find(m, type, NULL);
- if (mtag) {
- struct sockaddr_in *sin = *(struct sockaddr_in **)(mtag + 1);
- mtag->m_tag_id = PACKET_TAG_NONE;
- return (sin);
- }
- return (NULL);
-}
#endif /* _KERNEL */
#endif /* !_SYS_MBUF_H_ */
OpenPOWER on IntegriCloud