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)
This commit is contained in:
parent
4c37803a89
commit
9b932e9e04
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=133920
@ -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
|
||||
|
@ -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
|
||||
|
@ -3,7 +3,7 @@
|
||||
.PATH: ${.CURDIR}/../../netinet
|
||||
|
||||
KMOD= ipfw
|
||||
SRCS= ip_fw2.c
|
||||
SRCS= ip_fw2.c ip_fw_pfil.c
|
||||
|
||||
CFLAGS+= -DIPFIREWALL
|
||||
#
|
||||
|
@ -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 */
|
||||
|
||||
/*
|
||||
|
@ -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,
|
||||
|
@ -373,27 +373,6 @@ div_output(struct socket *so, struct mbuf *m,
|
||||
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)
|
||||
{
|
||||
|
@ -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 @@ dummynet_io(struct mbuf *m, int pipe_nr, int dir, struct ip_fw_args *fwa)
|
||||
* 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);
|
||||
|
@ -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 */
|
||||
|
@ -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 @@ ip_fastforward(struct mbuf *m)
|
||||
* 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 @@ ip_fastforward(struct mbuf *m)
|
||||
|
||||
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 @@ ip_fastforward(struct mbuf *m)
|
||||
/*
|
||||
* 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
|
||||
|
@ -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;
|
||||
#define IPFW_LOADED (ip_fw_chk_ptr != NULL)
|
||||
#endif /* _KERNEL */
|
||||
|
||||
/* 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 /* _IPFW2_H */
|
||||
|
@ -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 @@ ipfw_tick(void * __unused unused)
|
||||
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 */
|
||||
|
402
sys/netinet/ip_fw_pfil.c
Normal file
402
sys/netinet/ip_fw_pfil.c
Normal file
@ -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);
|
@ -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 @@ ip_input(struct mbuf *m)
|
||||
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 @@ ip_input(struct mbuf *m)
|
||||
return;
|
||||
if (m == NULL) /* consumed by filter */
|
||||
return;
|
||||
|
||||
ip = mtod(m, struct ip *);
|
||||
dchg = (odst.s_addr != ip->ip_dst.s_addr);
|
||||
|
||||
#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 */
|
||||
|
||||
#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;
|
||||
|
||||
args.m = m;
|
||||
i = ip_fw_chk_ptr(&args);
|
||||
m = args.m;
|
||||
|
||||
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 @@ ip_input(struct mbuf *m)
|
||||
* 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
|
||||
@ -543,12 +483,6 @@ ip_input(struct mbuf *m)
|
||||
(m->m_flags & (M_MCAST|M_BCAST)) == 0)
|
||||
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
|
||||
@ -566,18 +500,18 @@ ip_input(struct mbuf *m)
|
||||
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 @@ ip_input(struct mbuf *m)
|
||||
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 @@ ip_input(struct mbuf *m)
|
||||
goto bad;
|
||||
}
|
||||
#endif /* FAST_IPSEC */
|
||||
ip_forward(m, dchg, args.next_hop);
|
||||
ip_forward(m, dchg);
|
||||
}
|
||||
return;
|
||||
|
||||
@ -717,7 +651,7 @@ ip_input(struct mbuf *m)
|
||||
* 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 @@ ip_input(struct mbuf *m)
|
||||
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 @@ ip_input(struct mbuf *m)
|
||||
*/
|
||||
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 @@ ip_reass(struct mbuf *m)
|
||||
|
||||
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 @@ ip_dooptions(struct mbuf *m, int pass, struct sockaddr_in *next_hop)
|
||||
}
|
||||
}
|
||||
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
|
||||
|
@ -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 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro,
|
||||
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
|
||||
|
||||
/*
|
||||
* 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));
|
||||
m->m_pkthdr.csum_flags |=
|
||||
CSUM_IP_CHECKED | CSUM_IP_VALID;
|
||||
|
||||
ro_fwd->ro_rt = 0;
|
||||
rtalloc_ign(ro_fwd, RTF_CLONING);
|
||||
|
||||
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;
|
||||
|
||||
#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 ;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
} else
|
||||
goto again;
|
||||
}
|
||||
|
||||
#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;
|
||||
|
||||
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 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro,
|
||||
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) {
|
||||
|
@ -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 *,
|
||||
|
@ -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 ;
|
||||
|
@ -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 @@ tcp_input(m, off0)
|
||||
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 @@ tcp_input(m, off0)
|
||||
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
|
||||
|
@ -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 @@ tcp_input(m, off0)
|
||||
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 @@ tcp_input(m, off0)
|
||||
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
|
||||
|
@ -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"
|
||||
|
@ -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_ */
|
||||
|
Loading…
Reference in New Issue
Block a user