summaryrefslogtreecommitdiffstats
path: root/sys/netinet/ip_fastfwd.c
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 /sys/netinet/ip_fastfwd.c
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)
Diffstat (limited to 'sys/netinet/ip_fastfwd.c')
-rw-r--r--sys/netinet/ip_fastfwd.c232
1 files changed, 32 insertions, 200 deletions
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
OpenPOWER on IntegriCloud