Introduce new link-layer PFIL hook V_link_pfil_hook.
Merge ether_ipfw_chk() and part of bridge_pfil() into unified ipfw_check_frame() function called by PFIL. This change was suggested by rwatson? @ DevSummit. Remove ipfw headers from ether/bridge code since they are unneeded now. Note this thange introduce some (temporary) performance penalty since PFIL read lock has to be acquired for every link-level packet. MFC after: 3 weeks
This commit is contained in:
parent
599115bdcb
commit
1fbae66b6e
@ -100,7 +100,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/proc.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/rwlock.h>
|
||||
|
||||
#include <net/bpf.h>
|
||||
#include <net/if.h>
|
||||
@ -131,8 +130,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <net/if_vlan_var.h>
|
||||
|
||||
#include <net/route.h>
|
||||
#include <netinet/ip_fw.h>
|
||||
#include <netinet/ipfw/ip_fw_private.h>
|
||||
|
||||
/*
|
||||
* Size of the route hash table. Must be a power of two.
|
||||
@ -2981,7 +2978,6 @@ bridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir)
|
||||
{
|
||||
int snap, error, i, hlen;
|
||||
struct ether_header *eh1, eh2;
|
||||
struct ip_fw_args args;
|
||||
struct ip *ip;
|
||||
struct llc llc1;
|
||||
u_int16_t ether_type;
|
||||
@ -3055,6 +3051,16 @@ bridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir)
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Run the packet through pfil before stripping link headers */
|
||||
if (PFIL_HOOKED(&V_link_pfil_hook) && pfil_ipfw != 0 &&
|
||||
dir == PFIL_OUT && ifp != NULL) {
|
||||
|
||||
error = pfil_run_hooks(&V_link_pfil_hook, mp, ifp, dir, NULL);
|
||||
|
||||
if (*mp == NULL || error != 0) /* packet consumed by filter */
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* Strip off the Ethernet header and keep a copy. */
|
||||
m_copydata(*mp, 0, ETHER_HDR_LEN, (caddr_t) &eh2);
|
||||
m_adj(*mp, ETHER_HDR_LEN);
|
||||
@ -3085,63 +3091,6 @@ bridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir)
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* XXX this section is also in if_ethersubr.c */
|
||||
// XXX PFIL_OUT or DIR_OUT ?
|
||||
if (V_ip_fw_chk_ptr && pfil_ipfw != 0 &&
|
||||
dir == PFIL_OUT && ifp != NULL) {
|
||||
struct m_tag *mtag;
|
||||
|
||||
error = -1;
|
||||
/* fetch the start point from existing tags, if any */
|
||||
mtag = m_tag_locate(*mp, MTAG_IPFW_RULE, 0, NULL);
|
||||
if (mtag == NULL) {
|
||||
args.rule.slot = 0;
|
||||
} else {
|
||||
struct ipfw_rule_ref *r;
|
||||
|
||||
/* XXX can we free the tag after use ? */
|
||||
mtag->m_tag_id = PACKET_TAG_NONE;
|
||||
r = (struct ipfw_rule_ref *)(mtag + 1);
|
||||
/* packet already partially processed ? */
|
||||
if (r->info & IPFW_ONEPASS)
|
||||
goto ipfwpass;
|
||||
args.rule = *r;
|
||||
}
|
||||
|
||||
args.m = *mp;
|
||||
args.oif = ifp;
|
||||
args.next_hop = NULL;
|
||||
args.next_hop6 = NULL;
|
||||
args.eh = &eh2;
|
||||
args.inp = NULL; /* used by ipfw uid/gid/jail rules */
|
||||
i = V_ip_fw_chk_ptr(&args);
|
||||
*mp = args.m;
|
||||
|
||||
if (*mp == NULL)
|
||||
return (error);
|
||||
|
||||
if (ip_dn_io_ptr && (i == IP_FW_DUMMYNET)) {
|
||||
|
||||
/* put the Ethernet header back on */
|
||||
M_PREPEND(*mp, ETHER_HDR_LEN, M_DONTWAIT);
|
||||
if (*mp == NULL)
|
||||
return (error);
|
||||
bcopy(&eh2, mtod(*mp, caddr_t), ETHER_HDR_LEN);
|
||||
|
||||
/*
|
||||
* Pass the pkt to dummynet, which consumes it. The
|
||||
* packet will return to us via bridge_dummynet().
|
||||
*/
|
||||
args.oif = ifp;
|
||||
ip_dn_io_ptr(mp, DIR_FWD | PROTO_IFB, &args);
|
||||
return (error);
|
||||
}
|
||||
|
||||
if (i != IP_FW_PASS) /* drop */
|
||||
goto bad;
|
||||
}
|
||||
|
||||
ipfwpass:
|
||||
error = 0;
|
||||
|
||||
/*
|
||||
|
@ -45,7 +45,6 @@
|
||||
#include <sys/module.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/random.h>
|
||||
#include <sys/rwlock.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/sysctl.h>
|
||||
@ -63,6 +62,7 @@
|
||||
#include <net/if_vlan_var.h>
|
||||
#include <net/if_llatbl.h>
|
||||
#include <net/pf_mtag.h>
|
||||
#include <net/pfil.h>
|
||||
#include <net/vnet.h>
|
||||
|
||||
#if defined(INET) || defined(INET6)
|
||||
@ -71,8 +71,6 @@
|
||||
#include <netinet/if_ether.h>
|
||||
#include <netinet/ip_carp.h>
|
||||
#include <netinet/ip_var.h>
|
||||
#include <netinet/ip_fw.h>
|
||||
#include <netinet/ipfw/ip_fw_private.h>
|
||||
#endif
|
||||
#ifdef INET6
|
||||
#include <netinet6/nd6.h>
|
||||
@ -106,6 +104,8 @@ CTASSERT(sizeof (struct ether_header) == ETHER_ADDR_LEN * 2 + 2);
|
||||
CTASSERT(sizeof (struct ether_addr) == ETHER_ADDR_LEN);
|
||||
#endif
|
||||
|
||||
VNET_DEFINE(struct pfil_head, link_pfil_hook); /* Packet filter hooks */
|
||||
|
||||
/* netgraph node hooks for ng_ether(4) */
|
||||
void (*ng_ether_input_p)(struct ifnet *ifp, struct mbuf **mp);
|
||||
void (*ng_ether_input_orphan_p)(struct ifnet *ifp, struct mbuf *m);
|
||||
@ -141,14 +141,6 @@ static MALLOC_DEFINE(M_ARPCOM, "arpcom", "802.* interface internals");
|
||||
|
||||
#define senderr(e) do { error = (e); goto bad;} while (0)
|
||||
|
||||
#if defined(INET) || defined(INET6)
|
||||
int
|
||||
ether_ipfw_chk(struct mbuf **m0, struct ifnet *dst, int shared);
|
||||
static VNET_DEFINE(int, ether_ipfw);
|
||||
#define V_ether_ipfw VNET(ether_ipfw)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Ethernet output routine.
|
||||
* Encapsulate a packet of type family for the local net.
|
||||
@ -427,18 +419,17 @@ bad: if (m != NULL)
|
||||
int
|
||||
ether_output_frame(struct ifnet *ifp, struct mbuf *m)
|
||||
{
|
||||
#if defined(INET) || defined(INET6)
|
||||
int i;
|
||||
|
||||
if (V_ip_fw_chk_ptr && V_ether_ipfw != 0) {
|
||||
if (ether_ipfw_chk(&m, ifp, 0) == 0) {
|
||||
if (m) {
|
||||
m_freem(m);
|
||||
return EACCES; /* pkt dropped */
|
||||
} else
|
||||
return 0; /* consumed e.g. in a pipe */
|
||||
}
|
||||
if (PFIL_HOOKED(&V_link_pfil_hook)) {
|
||||
i = pfil_run_hooks(&V_link_pfil_hook, &m, ifp, PFIL_OUT, NULL);
|
||||
|
||||
if (i != 0)
|
||||
return (EACCES);
|
||||
|
||||
if (m == NULL)
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Queue message on interface, update output statistics if
|
||||
@ -448,113 +439,6 @@ ether_output_frame(struct ifnet *ifp, struct mbuf *m)
|
||||
}
|
||||
|
||||
#if defined(INET) || defined(INET6)
|
||||
/*
|
||||
* ipfw processing for ethernet packets (in and out).
|
||||
* The second parameter is NULL from ether_demux, and ifp from
|
||||
* ether_output_frame.
|
||||
*/
|
||||
int
|
||||
ether_ipfw_chk(struct mbuf **m0, struct ifnet *dst, int shared)
|
||||
{
|
||||
struct ether_header *eh;
|
||||
struct ether_header save_eh;
|
||||
struct mbuf *m;
|
||||
int i;
|
||||
struct ip_fw_args args;
|
||||
struct m_tag *mtag;
|
||||
|
||||
/* fetch start point from rule, if any */
|
||||
mtag = m_tag_locate(*m0, MTAG_IPFW_RULE, 0, NULL);
|
||||
if (mtag == NULL) {
|
||||
args.rule.slot = 0;
|
||||
} else {
|
||||
/* dummynet packet, already partially processed */
|
||||
struct ipfw_rule_ref *r;
|
||||
|
||||
/* XXX can we free it after use ? */
|
||||
mtag->m_tag_id = PACKET_TAG_NONE;
|
||||
r = (struct ipfw_rule_ref *)(mtag + 1);
|
||||
if (r->info & IPFW_ONEPASS)
|
||||
return (1);
|
||||
args.rule = *r;
|
||||
}
|
||||
|
||||
/*
|
||||
* I need some amt of data to be contiguous, and in case others need
|
||||
* the packet (shared==1) also better be in the first mbuf.
|
||||
*/
|
||||
m = *m0;
|
||||
i = min( m->m_pkthdr.len, max_protohdr);
|
||||
if ( shared || m->m_len < i) {
|
||||
m = m_pullup(m, i);
|
||||
if (m == NULL) {
|
||||
*m0 = m;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
eh = mtod(m, struct ether_header *);
|
||||
save_eh = *eh; /* save copy for restore below */
|
||||
m_adj(m, ETHER_HDR_LEN); /* strip ethernet header */
|
||||
|
||||
args.m = m; /* the packet we are looking at */
|
||||
args.oif = dst; /* destination, if any */
|
||||
args.next_hop = NULL; /* we do not support forward yet */
|
||||
args.next_hop6 = NULL; /* we do not support forward yet */
|
||||
args.eh = &save_eh; /* MAC header for bridged/MAC packets */
|
||||
args.inp = NULL; /* used by ipfw uid/gid/jail rules */
|
||||
i = V_ip_fw_chk_ptr(&args);
|
||||
m = args.m;
|
||||
if (m != NULL) {
|
||||
/*
|
||||
* Restore Ethernet header, as needed, in case the
|
||||
* mbuf chain was replaced by ipfw.
|
||||
*/
|
||||
M_PREPEND(m, ETHER_HDR_LEN, M_DONTWAIT);
|
||||
if (m == NULL) {
|
||||
*m0 = m;
|
||||
return 0;
|
||||
}
|
||||
if (eh != mtod(m, struct ether_header *))
|
||||
bcopy(&save_eh, mtod(m, struct ether_header *),
|
||||
ETHER_HDR_LEN);
|
||||
}
|
||||
*m0 = m;
|
||||
|
||||
if (i == IP_FW_DENY) /* drop */
|
||||
return 0;
|
||||
|
||||
KASSERT(m != NULL, ("ether_ipfw_chk: m is NULL"));
|
||||
|
||||
if (i == IP_FW_PASS) /* a PASS rule. */
|
||||
return 1;
|
||||
|
||||
if (ip_dn_io_ptr && (i == IP_FW_DUMMYNET)) {
|
||||
int dir;
|
||||
/*
|
||||
* Pass the pkt to dummynet, which consumes it.
|
||||
* If shared, make a copy and keep the original.
|
||||
*/
|
||||
if (shared) {
|
||||
m = m_copypacket(m, M_DONTWAIT);
|
||||
if (m == NULL)
|
||||
return 0;
|
||||
} else {
|
||||
/*
|
||||
* Pass the original to dummynet and
|
||||
* nothing back to the caller
|
||||
*/
|
||||
*m0 = NULL ;
|
||||
}
|
||||
dir = PROTO_LAYER2 | (dst ? DIR_OUT : DIR_IN);
|
||||
ip_dn_io_ptr(&m, dir, &args);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* XXX at some point add support for divert/forward actions.
|
||||
* If none of the above matches, we have to drop the pkt.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -787,6 +671,35 @@ ether_init(__unused void *arg)
|
||||
}
|
||||
SYSINIT(ether, SI_SUB_INIT_IF, SI_ORDER_ANY, ether_init, NULL);
|
||||
|
||||
static void
|
||||
vnet_ether_init(__unused void *arg)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Initialize packet filter hooks. */
|
||||
V_link_pfil_hook.ph_type = PFIL_TYPE_AF;
|
||||
V_link_pfil_hook.ph_af = AF_LINK;
|
||||
if ((i = pfil_head_register(&V_link_pfil_hook)) != 0)
|
||||
printf("%s: WARNING: unable to register pfil link hook, "
|
||||
"error %d\n", __func__, i);
|
||||
}
|
||||
VNET_SYSINIT(vnet_ether_init, SI_SUB_PROTO_IF, SI_ORDER_ANY,
|
||||
vnet_ether_init, NULL);
|
||||
|
||||
static void
|
||||
vnet_ether_destroy(__unused void *arg)
|
||||
{
|
||||
int i;
|
||||
|
||||
if ((i = pfil_head_unregister(&V_link_pfil_hook)) != 0)
|
||||
printf("%s: WARNING: unable to unregister pfil link hook, "
|
||||
"error %d\n", __func__, i);
|
||||
}
|
||||
VNET_SYSUNINIT(vnet_ether_uninit, SI_SUB_PROTO_IF, SI_ORDER_ANY,
|
||||
vnet_ether_destroy, NULL);
|
||||
|
||||
|
||||
|
||||
static void
|
||||
ether_input(struct ifnet *ifp, struct mbuf *m)
|
||||
{
|
||||
@ -807,7 +720,7 @@ void
|
||||
ether_demux(struct ifnet *ifp, struct mbuf *m)
|
||||
{
|
||||
struct ether_header *eh;
|
||||
int isr;
|
||||
int i, isr;
|
||||
u_short ether_type;
|
||||
#if defined(NETATALK)
|
||||
struct llc *l;
|
||||
@ -815,19 +728,14 @@ ether_demux(struct ifnet *ifp, struct mbuf *m)
|
||||
|
||||
KASSERT(ifp != NULL, ("%s: NULL interface pointer", __func__));
|
||||
|
||||
#if defined(INET) || defined(INET6)
|
||||
/*
|
||||
* Allow dummynet and/or ipfw to claim the frame.
|
||||
* Do not do this for PROMISC frames in case we are re-entered.
|
||||
*/
|
||||
if (V_ip_fw_chk_ptr && V_ether_ipfw != 0 && !(m->m_flags & M_PROMISC)) {
|
||||
if (ether_ipfw_chk(&m, NULL, 0) == 0) {
|
||||
if (m)
|
||||
m_freem(m); /* dropped; free mbuf chain */
|
||||
return; /* consumed */
|
||||
}
|
||||
/* Do not grab PROMISC frames in case we are re-entered. */
|
||||
if (PFIL_HOOKED(&V_link_pfil_hook) && !(m->m_flags & M_PROMISC)) {
|
||||
i = pfil_run_hooks(&V_link_pfil_hook, &m, ifp, PFIL_IN, NULL);
|
||||
|
||||
if (i != 0 || m == NULL)
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
eh = mtod(m, struct ether_header *);
|
||||
ether_type = ntohs(eh->ether_type);
|
||||
|
||||
@ -1056,10 +964,6 @@ ether_reassign(struct ifnet *ifp, struct vnet *new_vnet, char *unused __unused)
|
||||
|
||||
SYSCTL_DECL(_net_link);
|
||||
SYSCTL_NODE(_net_link, IFT_ETHER, ether, CTLFLAG_RW, 0, "Ethernet");
|
||||
#if defined(INET) || defined(INET6)
|
||||
SYSCTL_VNET_INT(_net_link_ether, OID_AUTO, ipfw, CTLFLAG_RW,
|
||||
&VNET_NAME(ether_ipfw), 0, "Pass ether pkts through firewall");
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/*
|
||||
|
@ -99,6 +99,9 @@ TAILQ_HEAD(ifaddrhead, ifaddr); /* instantiation is preserved in the list */
|
||||
TAILQ_HEAD(ifmultihead, ifmultiaddr);
|
||||
TAILQ_HEAD(ifgrouphead, ifg_group);
|
||||
|
||||
VNET_DECLARE(struct pfil_head, link_pfil_hook); /* packet filter hooks */
|
||||
#define V_link_pfil_hook VNET(link_pfil_hook)
|
||||
|
||||
/*
|
||||
* Structure defining a queue for a network interface.
|
||||
*/
|
||||
|
@ -292,9 +292,7 @@ enum {
|
||||
struct ip_fw_args;
|
||||
typedef int (*ip_fw_chk_ptr_t)(struct ip_fw_args *args);
|
||||
typedef int (*ip_fw_ctl_ptr_t)(struct sockopt *);
|
||||
VNET_DECLARE(ip_fw_chk_ptr_t, ip_fw_chk_ptr);
|
||||
VNET_DECLARE(ip_fw_ctl_ptr_t, ip_fw_ctl_ptr);
|
||||
#define V_ip_fw_chk_ptr VNET(ip_fw_chk_ptr)
|
||||
#define V_ip_fw_ctl_ptr VNET(ip_fw_ctl_ptr)
|
||||
|
||||
/* Divert hooks. */
|
||||
|
@ -2645,10 +2645,9 @@ vnet_ipfw_init(const void *unused)
|
||||
V_ipfw_vnet_ready = 1; /* Open for business */
|
||||
|
||||
/*
|
||||
* Hook the sockopt handler, and the layer2 (V_ip_fw_chk_ptr)
|
||||
* and pfil hooks for ipv4 and ipv6. Even if the latter two fail
|
||||
* we still keep the module alive because the sockopt and
|
||||
* layer2 paths are still useful.
|
||||
* Hook the sockopt handler and pfil hooks for ipv4 and ipv6.
|
||||
* Even if the latter two fail we still keep the module alive
|
||||
* because the sockopt and layer2 paths are still useful.
|
||||
* ipfw[6]_hook return 0 on success, ENOENT on failure,
|
||||
* so we can ignore the exact return value and just set a flag.
|
||||
*
|
||||
@ -2659,7 +2658,6 @@ vnet_ipfw_init(const void *unused)
|
||||
* is checked on each packet because there are no pfil hooks.
|
||||
*/
|
||||
V_ip_fw_ctl_ptr = ipfw_ctl;
|
||||
V_ip_fw_chk_ptr = ipfw_chk;
|
||||
error = ipfw_attach_hooks(1);
|
||||
return (error);
|
||||
}
|
||||
@ -2681,7 +2679,6 @@ vnet_ipfw_uninit(const void *unused)
|
||||
* sure the update is propagated and nobody will be in.
|
||||
*/
|
||||
(void)ipfw_attach_hooks(0 /* detach */);
|
||||
V_ip_fw_chk_ptr = NULL;
|
||||
V_ip_fw_ctl_ptr = NULL;
|
||||
IPFW_UH_WLOCK(chain);
|
||||
IPFW_UH_WUNLOCK(chain);
|
||||
|
@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/route.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <net/pfil.h>
|
||||
#include <net/vnet.h>
|
||||
|
||||
@ -72,10 +73,17 @@ static VNET_DEFINE(int, fw6_enable) = 1;
|
||||
#define V_fw6_enable VNET(fw6_enable)
|
||||
#endif
|
||||
|
||||
static VNET_DEFINE(int, fwlink_enable) = 0;
|
||||
#define V_fwlink_enable VNET(fwlink_enable)
|
||||
|
||||
int ipfw_chg_hook(SYSCTL_HANDLER_ARGS);
|
||||
|
||||
/* Forward declarations. */
|
||||
static int ipfw_divert(struct mbuf **, int, struct ipfw_rule_ref *, int);
|
||||
static int ipfw_check_packet(void *, struct mbuf **, struct ifnet *, int,
|
||||
struct inpcb *);
|
||||
static int ipfw_check_frame(void *, struct mbuf **, struct ifnet *, int,
|
||||
struct inpcb *);
|
||||
|
||||
#ifdef SYSCTL_NODE
|
||||
|
||||
@ -92,6 +100,11 @@ SYSCTL_VNET_PROC(_net_inet6_ip6_fw, OID_AUTO, enable,
|
||||
ipfw_chg_hook, "I", "Enable ipfw+6");
|
||||
#endif /* INET6 */
|
||||
|
||||
SYSCTL_DECL(_net_link_ether);
|
||||
SYSCTL_VNET_PROC(_net_link_ether, OID_AUTO, ipfw,
|
||||
CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE3, &VNET_NAME(fwlink_enable), 0,
|
||||
ipfw_chg_hook, "I", "Pass ether pkts through firewall");
|
||||
|
||||
SYSEND
|
||||
|
||||
#endif /* SYSCTL_NODE */
|
||||
@ -101,8 +114,8 @@ SYSEND
|
||||
* dummynet, divert, netgraph or other modules.
|
||||
* The packet may be consumed.
|
||||
*/
|
||||
int
|
||||
ipfw_check_hook(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
|
||||
static int
|
||||
ipfw_check_packet(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
|
||||
struct inpcb *inp)
|
||||
{
|
||||
struct ip_fw_args args;
|
||||
@ -278,6 +291,111 @@ ipfw_check_hook(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* ipfw processing for ethernet packets (in and out).
|
||||
* Inteface is NULL from ether_demux, and ifp from
|
||||
* ether_output_frame.
|
||||
*/
|
||||
static int
|
||||
ipfw_check_frame(void *arg, struct mbuf **m0, struct ifnet *dst, int dir,
|
||||
struct inpcb *inp)
|
||||
{
|
||||
struct ether_header *eh;
|
||||
struct ether_header save_eh;
|
||||
struct mbuf *m;
|
||||
int i, ret;
|
||||
struct ip_fw_args args;
|
||||
struct m_tag *mtag;
|
||||
|
||||
/* fetch start point from rule, if any */
|
||||
mtag = m_tag_locate(*m0, MTAG_IPFW_RULE, 0, NULL);
|
||||
if (mtag == NULL) {
|
||||
args.rule.slot = 0;
|
||||
} else {
|
||||
/* dummynet packet, already partially processed */
|
||||
struct ipfw_rule_ref *r;
|
||||
|
||||
/* XXX can we free it after use ? */
|
||||
mtag->m_tag_id = PACKET_TAG_NONE;
|
||||
r = (struct ipfw_rule_ref *)(mtag + 1);
|
||||
if (r->info & IPFW_ONEPASS)
|
||||
return (0);
|
||||
args.rule = *r;
|
||||
}
|
||||
|
||||
/* I need some amt of data to be contiguous */
|
||||
m = *m0;
|
||||
i = min(m->m_pkthdr.len, max_protohdr);
|
||||
if (m->m_len < i) {
|
||||
m = m_pullup(m, i);
|
||||
if (m == NULL) {
|
||||
*m0 = m;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
eh = mtod(m, struct ether_header *);
|
||||
save_eh = *eh; /* save copy for restore below */
|
||||
m_adj(m, ETHER_HDR_LEN); /* strip ethernet header */
|
||||
|
||||
args.m = m; /* the packet we are looking at */
|
||||
args.oif = dst; /* destination, if any */
|
||||
args.next_hop = NULL; /* we do not support forward yet */
|
||||
args.next_hop6 = NULL; /* we do not support forward yet */
|
||||
args.eh = &save_eh; /* MAC header for bridged/MAC packets */
|
||||
args.inp = NULL; /* used by ipfw uid/gid/jail rules */
|
||||
i = ipfw_chk(&args);
|
||||
m = args.m;
|
||||
if (m != NULL) {
|
||||
/*
|
||||
* Restore Ethernet header, as needed, in case the
|
||||
* mbuf chain was replaced by ipfw.
|
||||
*/
|
||||
M_PREPEND(m, ETHER_HDR_LEN, M_DONTWAIT);
|
||||
if (m == NULL) {
|
||||
*m0 = NULL;
|
||||
return (0);
|
||||
}
|
||||
if (eh != mtod(m, struct ether_header *))
|
||||
bcopy(&save_eh, mtod(m, struct ether_header *),
|
||||
ETHER_HDR_LEN);
|
||||
}
|
||||
*m0 = m;
|
||||
|
||||
ret = 0;
|
||||
/* Check result of ipfw_chk() */
|
||||
switch (i) {
|
||||
case IP_FW_PASS:
|
||||
break;
|
||||
|
||||
case IP_FW_DENY:
|
||||
ret = EACCES;
|
||||
break; /* i.e. drop */
|
||||
|
||||
case IP_FW_DUMMYNET:
|
||||
ret = EACCES;
|
||||
int dir;
|
||||
|
||||
if (ip_dn_io_ptr == NULL)
|
||||
break; /* i.e. drop */
|
||||
|
||||
*m0 = NULL;
|
||||
dir = PROTO_LAYER2 | (dst ? DIR_OUT : DIR_IN);
|
||||
ip_dn_io_ptr(&m, dir, &args);
|
||||
return 0;
|
||||
|
||||
default:
|
||||
KASSERT(0, ("%s: unknown retval", __func__));
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
if (*m0)
|
||||
FREE_PKT(*m0);
|
||||
*m0 = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* do the divert, return 1 on error 0 on success */
|
||||
static int
|
||||
ipfw_divert(struct mbuf **m0, int incoming, struct ipfw_rule_ref *rule,
|
||||
@ -379,13 +497,16 @@ static int
|
||||
ipfw_hook(int onoff, int pf)
|
||||
{
|
||||
struct pfil_head *pfh;
|
||||
void *hook_func;
|
||||
|
||||
pfh = pfil_head_get(PFIL_TYPE_AF, pf);
|
||||
if (pfh == NULL)
|
||||
return ENOENT;
|
||||
|
||||
hook_func = (pf == AF_LINK) ? ipfw_check_frame : ipfw_check_packet;
|
||||
|
||||
(void) (onoff ? pfil_add_hook : pfil_remove_hook)
|
||||
(ipfw_check_hook, NULL, PFIL_IN | PFIL_OUT | PFIL_WAITOK, pfh);
|
||||
(hook_func, NULL, PFIL_IN | PFIL_OUT | PFIL_WAITOK, pfh);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -409,51 +530,58 @@ ipfw_attach_hooks(int arg)
|
||||
printf("ipfw6_hook() error\n");
|
||||
}
|
||||
#endif
|
||||
if (arg == 0) /* detach */
|
||||
ipfw_hook(0, AF_LINK);
|
||||
else if (V_fwlink_enable && ipfw_hook(1, AF_LINK) != 0) {
|
||||
error = ENOENT;
|
||||
printf("ipfw_link_hook() error\n");
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
int
|
||||
ipfw_chg_hook(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
int enable;
|
||||
int oldenable;
|
||||
int *enable;
|
||||
int newval;
|
||||
int error;
|
||||
int af;
|
||||
|
||||
if (arg1 == &VNET_NAME(fw_enable)) {
|
||||
enable = V_fw_enable;
|
||||
enable = &V_fw_enable;
|
||||
af = AF_INET;
|
||||
}
|
||||
#ifdef INET6
|
||||
else if (arg1 == &VNET_NAME(fw6_enable)) {
|
||||
enable = V_fw6_enable;
|
||||
enable = &V_fw6_enable;
|
||||
af = AF_INET6;
|
||||
}
|
||||
#endif
|
||||
else if (arg1 == &VNET_NAME(fwlink_enable)) {
|
||||
enable = &V_fwlink_enable;
|
||||
af = AF_LINK;
|
||||
}
|
||||
else
|
||||
return (EINVAL);
|
||||
|
||||
oldenable = enable;
|
||||
newval = *enable;
|
||||
|
||||
error = sysctl_handle_int(oidp, &enable, 0, req);
|
||||
/* Handle sysctl change */
|
||||
error = sysctl_handle_int(oidp, &newval, 0, req);
|
||||
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
enable = (enable) ? 1 : 0;
|
||||
/* Formalize new value */
|
||||
newval = (newval) ? 1 : 0;
|
||||
|
||||
if (enable == oldenable)
|
||||
if (*enable == newval)
|
||||
return (0);
|
||||
|
||||
error = ipfw_hook(enable, af);
|
||||
error = ipfw_hook(newval, af);
|
||||
if (error)
|
||||
return (error);
|
||||
if (af == AF_INET)
|
||||
V_fw_enable = enable;
|
||||
#ifdef INET6
|
||||
else if (af == AF_INET6)
|
||||
V_fw6_enable = enable;
|
||||
#endif
|
||||
*enable = newval;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
@ -270,10 +270,6 @@ int ipfw_ctl(struct sockopt *sopt);
|
||||
int ipfw_chk(struct ip_fw_args *args);
|
||||
void ipfw_reap_rules(struct ip_fw *head);
|
||||
|
||||
/* In ip_fw_pfil */
|
||||
int ipfw_check_hook(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
|
||||
struct inpcb *inp);
|
||||
|
||||
/* In ip_fw_table.c */
|
||||
struct radix_node;
|
||||
int ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
|
||||
|
Loading…
Reference in New Issue
Block a user