summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/net/if_bridge.c12
-rw-r--r--sys/net/if_ethersubr.c15
-rw-r--r--sys/netgraph/ng_ipfw.c6
-rw-r--r--sys/netgraph/ng_ipfw.h26
-rw-r--r--sys/netinet/in.h26
-rw-r--r--sys/netinet/ip_dummynet.h31
-rw-r--r--sys/netinet/ipfw/ip_dummynet.c52
-rw-r--r--sys/netinet/ipfw/ip_fw2.c87
-rw-r--r--sys/netinet/ipfw/ip_fw_dynamic.c4
-rw-r--r--sys/netinet/ipfw/ip_fw_log.c27
-rw-r--r--sys/netinet/ipfw/ip_fw_nat.c16
-rw-r--r--sys/netinet/ipfw/ip_fw_pfil.c475
-rw-r--r--sys/netinet/ipfw/ip_fw_private.h56
-rw-r--r--sys/netinet/ipfw/ip_fw_sockopt.c2
14 files changed, 342 insertions, 493 deletions
diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c
index b380ef0..d0d2242 100644
--- a/sys/net/if_bridge.c
+++ b/sys/net/if_bridge.c
@@ -3041,13 +3041,17 @@ bridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir)
/* XXX this section is also in if_ethersubr.c */
if (V_ip_fw_chk_ptr && pfil_ipfw != 0 && dir == PFIL_OUT && ifp != NULL) {
- struct dn_pkt_tag *dn_tag;
+ struct m_tag *mtag;
error = -1;
- dn_tag = ip_dn_claim_tag(*mp);
- if (dn_tag == NULL) {
+ mtag = m_tag_find(*mp, PACKET_TAG_DUMMYNET, NULL);
+ if (mtag == NULL) {
args.slot = 0;
} else {
+ struct dn_pkt_tag *dn_tag;
+
+ mtag->m_tag_id = PACKET_TAG_NONE;
+ dn_tag = (struct dn_pkt_tag *)(mtag + 1);
if (dn_tag->slot != 0 && V_fw_one_pass)
/* packet already partially processed */
goto ipfwpass;
@@ -3081,7 +3085,7 @@ bridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir)
* packet will return to us via bridge_dummynet().
*/
args.oif = ifp;
- ip_dn_io_ptr(mp, DN_TO_IFB_FWD, &args);
+ ip_dn_io_ptr(mp, DIR_FWD | PROTO_IFB, &args);
return (error);
}
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index 95554ca..5fd53e8 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -467,13 +467,16 @@ ether_ipfw_chk(struct mbuf **m0, struct ifnet *dst, int shared)
struct mbuf *m;
int i;
struct ip_fw_args args;
- struct dn_pkt_tag *dn_tag;
+ struct m_tag *mtag;
- dn_tag = ip_dn_claim_tag(*m0);
-
- if (dn_tag == NULL) {
+ mtag = m_tag_find(*m0, PACKET_TAG_DUMMYNET, NULL);
+ if (mtag == NULL) {
args.slot = 0;
} else {
+ struct dn_pkt_tag *dn_tag;
+
+ mtag->m_tag_id = PACKET_TAG_NONE;
+ dn_tag = (struct dn_pkt_tag *)(mtag + 1);
if (dn_tag->slot != 0 && V_fw_one_pass)
/* dummynet packet, already partially processed */
return (1);
@@ -532,6 +535,7 @@ ether_ipfw_chk(struct mbuf **m0, struct ifnet *dst, int shared)
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.
@@ -547,7 +551,8 @@ ether_ipfw_chk(struct mbuf **m0, struct ifnet *dst, int shared)
*/
*m0 = NULL ;
}
- ip_dn_io_ptr(&m, dst ? DN_TO_ETH_OUT: DN_TO_ETH_DEMUX, &args);
+ dir = PROTO_LAYER2 | (dst ? DIR_OUT : DIR_IN);
+ ip_dn_io_ptr(&m, dir, &args);
return 0;
}
/*
diff --git a/sys/netgraph/ng_ipfw.c b/sys/netgraph/ng_ipfw.c
index 974f48f..c02ca75 100644
--- a/sys/netgraph/ng_ipfw.c
+++ b/sys/netgraph/ng_ipfw.c
@@ -234,7 +234,7 @@ ng_ipfw_rcvdata(hook_p hook, item_p item)
};
switch (ngit->dir) {
- case NG_IPFW_OUT:
+ case DIR_OUT:
{
struct ip *ip;
@@ -249,7 +249,7 @@ ng_ipfw_rcvdata(hook_p hook, item_p item)
return ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL);
}
- case NG_IPFW_IN:
+ case DIR_IN:
ip_input(m);
return (0);
default:
@@ -298,7 +298,7 @@ ng_ipfw_input(struct mbuf **m0, int dir, struct ip_fw_args *fwa, int tee)
ngit->rule_id = fwa->rule_id;
ngit->chain_id = fwa->chain_id;
ngit->dir = dir;
- ngit->ifp = fwa->oif;
+// ngit->ifp = fwa->oif; /* XXX do we use it ? */
m_tag_prepend(m, &ngit->mt);
} else
diff --git a/sys/netgraph/ng_ipfw.h b/sys/netgraph/ng_ipfw.h
index 9fb4cf7..c463d6a 100644
--- a/sys/netgraph/ng_ipfw.h
+++ b/sys/netgraph/ng_ipfw.h
@@ -26,27 +26,7 @@
* $FreeBSD$
*/
+#ifndef _NG_IPFW_H
+#define _NG_IPFW_H
#define NG_IPFW_NODE_TYPE "ipfw"
-#define NGM_IPFW_COOKIE 1105988990
-
-#ifdef _KERNEL
-
-typedef int ng_ipfw_input_t(struct mbuf **, int, struct ip_fw_args *, int);
-extern ng_ipfw_input_t *ng_ipfw_input_p;
-#define NG_IPFW_LOADED (ng_ipfw_input_p != NULL)
-
-struct ng_ipfw_tag {
- struct m_tag mt; /* tag header */
- uint32_t slot; /* slot for next rule */
- uint32_t rulenum; /* matching rule number */
- uint32_t rule_id; /* matching rule id */
- uint32_t chain_id; /* ruleset id */
- struct ifnet *ifp; /* interface, for ip_output */
- int dir;
-#define NG_IPFW_OUT 0
-#define NG_IPFW_IN 1
-};
-
-#define TAGSIZ (sizeof(struct ng_ipfw_tag) - sizeof(struct m_tag))
-
-#endif /* _KERNEL */
+#endif /* _NG_IPFW_H */
diff --git a/sys/netinet/in.h b/sys/netinet/in.h
index e83d94b..4f47658 100644
--- a/sys/netinet/in.h
+++ b/sys/netinet/in.h
@@ -734,6 +734,32 @@ void in_ifdetach(struct ifnet *);
#define sintosa(sin) ((struct sockaddr *)(sin))
#define ifatoia(ifa) ((struct in_ifaddr *)(ifa))
+/*
+ * Historically, BSD keeps ip_len and ip_off in host format
+ * when doing layer 3 processing, and this often requires
+ * to translate the format back and forth.
+ * To make the process explicit, we define a couple of macros
+ * that also take into account the fact that at some point
+ * we may want to keep those fields always in net format.
+ */
+
+#if (BYTE_ORDER == BIG_ENDIAN) || defined(HAVE_NET_IPLEN)
+#define SET_NET_IPLEN(p) do {} while (0)
+#define SET_HOST_IPLEN(p) do {} while (0)
+#else
+#define SET_NET_IPLEN(p) do { \
+ struct ip *h_ip = (p); \
+ h_ip->ip_len = htons(h_ip->ip_len); \
+ h_ip->ip_off = htons(h_ip->ip_off); \
+ } while (0)
+
+#define SET_HOST_IPLEN(p) do { \
+ struct ip *h_ip = (p); \
+ h_ip->ip_len = ntohs(h_ip->ip_len); \
+ h_ip->ip_off = ntohs(h_ip->ip_off); \
+ } while (0)
+#endif /* !HAVE_NET_IPLEN */
+
#endif /* _KERNEL */
/* INET6 stuff */
diff --git a/sys/netinet/ip_dummynet.h b/sys/netinet/ip_dummynet.h
index 9d5223f..4d039ee 100644
--- a/sys/netinet/ip_dummynet.h
+++ b/sys/netinet/ip_dummynet.h
@@ -110,21 +110,19 @@ struct dn_heap {
* them that carries their dummynet state. This is used within
* the dummynet code as well as outside when checking for special
* processing requirements.
+ * Note that the first part is the reinject info and is common to
+ * other forms of packet reinjection.
*/
struct dn_pkt_tag {
+ /* first part, reinject info */
uint32_t slot; /* slot of next rule to use */
uint32_t rulenum; /* matching rule number */
uint32_t rule_id; /* matching rule id */
uint32_t chain_id; /* ruleset id */
+
+ /* second part, dummynet specific */
int dn_dir; /* action when packet comes out. */
-#define DN_TO_IP_OUT 1
-#define DN_TO_IP_IN 2
-/* Obsolete: #define DN_TO_BDG_FWD 3 */
-#define DN_TO_ETH_DEMUX 4
-#define DN_TO_ETH_OUT 5
-#define DN_TO_IP6_IN 6
-#define DN_TO_IP6_OUT 7
-#define DN_TO_IFB_FWD 8
+ /* see ip_fw_private.h */
dn_key output_time; /* when the pkt is due for delivery */
struct ifnet *ifp; /* interface, for ip_output */
@@ -377,21 +375,4 @@ struct dn_pipe_max {
SLIST_HEAD(dn_pipe_head, dn_pipe);
-#ifdef _KERNEL
-
-/*
- * Return the dummynet tag; if any.
- * Make sure that the dummynet tag is not reused by lower layers.
- */
-static __inline struct dn_pkt_tag *
-ip_dn_claim_tag(struct mbuf *m)
-{
- struct m_tag *mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
- if (mtag != NULL) {
- mtag->m_tag_id = PACKET_TAG_NONE;
- return ((struct dn_pkt_tag *)(mtag + 1));
- } else
- return (NULL);
-}
-#endif
#endif /* _IP_DUMMYNET_H */
diff --git a/sys/netinet/ipfw/ip_dummynet.c b/sys/netinet/ipfw/ip_dummynet.c
index 2b9b928..2142751 100644
--- a/sys/netinet/ipfw/ip_dummynet.c
+++ b/sys/netinet/ipfw/ip_dummynet.c
@@ -551,7 +551,6 @@ transmit_event(struct dn_pipe *pipe, struct mbuf **head, struct mbuf **tail)
}
#define div64(a, b) ((int64_t)(a) / (int64_t)(b))
-#define DN_TO_DROP 0xffff
/*
* Compute how many ticks we have to wait before being able to send
* a packet. This is computed as the "wire time" for the packet
@@ -589,7 +588,7 @@ compute_extra_bits(struct mbuf *pkt, struct dn_pipe *p)
if (index >= p->loss_level) {
struct dn_pkt_tag *dt = dn_tag_get(pkt);
if (dt)
- dt->dn_dir = DN_TO_DROP;
+ dt->dn_dir = DIR_DROP;
}
return extra_bits;
}
@@ -964,49 +963,48 @@ dummynet_task(void *context, int pending)
static void
dummynet_send(struct mbuf *m)
{
- struct dn_pkt_tag *pkt;
struct mbuf *n;
- struct ip *ip;
- int dst;
for (; m != NULL; m = n) {
+ struct ifnet *ifp;
+ int dst;
+
n = m->m_nextpkt;
m->m_nextpkt = NULL;
if (m_tag_first(m) == NULL) {
- pkt = NULL; /* probably unnecessary */
- dst = DN_TO_DROP;
+ dst = DIR_DROP;
} else {
- pkt = dn_tag_get(m);
+ struct dn_pkt_tag *pkt = dn_tag_get(m);
dst = pkt->dn_dir;
+ ifp = pkt->ifp;
}
switch (dst) {
- case DN_TO_IP_OUT:
+ case DIR_OUT:
ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL);
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);
+ case DIR_IN :
+ /* put header in network format for ip_input() */
+ SET_NET_IPLEN(mtod(m, struct ip *));
netisr_dispatch(NETISR_IP, m);
break;
#ifdef INET6
- case DN_TO_IP6_IN:
+ case DIR_IN | PROTO_IPV6:
netisr_dispatch(NETISR_IPV6, m);
break;
- case DN_TO_IP6_OUT:
+ case DIR_OUT | PROTO_IPV6:
ip6_output(m, NULL, NULL, IPV6_FORWARDING, NULL, NULL, NULL);
break;
#endif
- case DN_TO_IFB_FWD:
+ case DIR_FWD | PROTO_IFB: /* DN_TO_IFB_FWD: */
if (bridge_dn_p != NULL)
- ((*bridge_dn_p)(m, pkt->ifp));
+ ((*bridge_dn_p)(m, ifp));
else
printf("dummynet: if_bridge not loaded\n");
break;
- case DN_TO_ETH_DEMUX:
+ case DIR_IN | PROTO_LAYER2: /* DN_TO_ETH_DEMUX: */
/*
* The Ethernet code assumes the Ethernet header is
* contiguous in the first mbuf header.
@@ -1020,17 +1018,17 @@ dummynet_send(struct mbuf *m)
}
ether_demux(m->m_pkthdr.rcvif, m);
break;
- case DN_TO_ETH_OUT:
- ether_output_frame(pkt->ifp, m);
+ case DIR_OUT | PROTO_LAYER2: /* N_TO_ETH_OUT: */
+ ether_output_frame(ifp, m);
break;
- case DN_TO_DROP:
+ case DIR_DROP:
/* drop the packet after some time */
dn_free_pkt(m);
break;
default:
- printf("dummynet: bad switch %d!\n", pkt->dn_dir);
+ printf("dummynet: bad switch %d!\n", dst);
dn_free_pkt(m);
break;
}
@@ -1545,8 +1543,8 @@ dummynet_io(struct mbuf **m0, int dir, struct ip_fw_args *fwa)
}
}
done:
- if (head == m && dir != DN_TO_IFB_FWD && dir != DN_TO_ETH_DEMUX &&
- dir != DN_TO_ETH_OUT) { /* Fast io. */
+ if (head == m && (dir & PROTO_LAYER2) == 0 ) {
+ /* Fast io. */
io_pkt_fast++;
if (m->m_nextpkt != NULL)
printf("dummynet: fast io: pkt chain detected!\n");
@@ -1810,13 +1808,15 @@ config_pipe(struct dn_pipe *p)
pipe->idle_heap.size = pipe->idle_heap.elements = 0;
pipe->idle_heap.offset =
offsetof(struct dn_flow_queue, heap_pos);
- } else
+ } else {
/* Flush accumulated credit for all queues. */
- for (i = 0; i <= pipe->fs.rq_size; i++)
+ for (i = 0; i <= pipe->fs.rq_size; i++) {
for (q = pipe->fs.rq[i]; q; q = q->next) {
q->numbytes = p->burst +
(io_fast ? p->bandwidth : 0);
}
+ }
+ }
pipe->bandwidth = p->bandwidth;
pipe->burst = p->burst;
diff --git a/sys/netinet/ipfw/ip_fw2.c b/sys/netinet/ipfw/ip_fw2.c
index 719ed6c..bf10214 100644
--- a/sys/netinet/ipfw/ip_fw2.c
+++ b/sys/netinet/ipfw/ip_fw2.c
@@ -75,7 +75,6 @@ __FBSDID("$FreeBSD$");
#include <netinet/ip_fw.h>
#include <netinet/ipfw/ip_fw_private.h>
#include <netinet/ip_divert.h>
-#include <netinet/ip_dummynet.h>
#include <netinet/ip_carp.h>
#include <netinet/pim.h>
#include <netinet/tcp_var.h>
@@ -83,8 +82,6 @@ __FBSDID("$FreeBSD$");
#include <netinet/udp_var.h>
#include <netinet/sctp.h>
-#include <netgraph/ng_ipfw.h>
-
#include <netinet/ip6.h>
#include <netinet/icmp6.h>
#ifdef INET6
@@ -591,7 +588,7 @@ send_reject6(struct ip_fw_args *args, int code, u_int hlen, struct ip6_hdr *ip6)
* sends a reject message, consuming the mbuf passed as an argument.
*/
static void
-send_reject(struct ip_fw_args *args, int code, int ip_len, struct ip *ip)
+send_reject(struct ip_fw_args *args, int code, int iplen, struct ip *ip)
{
#if 0
@@ -607,8 +604,7 @@ send_reject(struct ip_fw_args *args, int code, int ip_len, struct ip *ip)
if (code != ICMP_REJECT_RST) { /* Send an ICMP unreach */
/* We need the IP header in host order for icmp_error(). */
if (args->eh != NULL) {
- ip->ip_len = ntohs(ip->ip_len);
- ip->ip_off = ntohs(ip->ip_off);
+ SET_HOST_IPLEN(ip);
}
icmp_error(args->m, ICMP_UNREACH, code, 0L, 0);
} else if (args->f_id.proto == IPPROTO_TCP) {
@@ -851,12 +847,12 @@ ipfw_chk(struct ip_fw_args *args)
* src_ip, dst_ip ip addresses, in NETWORK format.
* Only valid for IPv4 packets.
*/
- u_int8_t proto;
- u_int16_t src_port = 0, dst_port = 0; /* NOTE: host format */
+ uint8_t proto;
+ uint16_t src_port = 0, dst_port = 0; /* NOTE: host format */
struct in_addr src_ip, dst_ip; /* NOTE: network format */
- u_int16_t ip_len=0;
+ uint16_t iplen=0;
int pktlen;
- u_int16_t etype = 0; /* Host order stored ether type */
+ uint16_t etype = 0; /* Host order stored ether type */
/*
* dyn_dir = MATCH_UNKNOWN when rules unchecked,
@@ -1094,14 +1090,17 @@ do { \
proto = ip->ip_p;
src_ip = ip->ip_src;
dst_ip = ip->ip_dst;
- if (args->eh != NULL) { /* layer 2 packets are as on the wire */
- offset = ntohs(ip->ip_off) & IP_OFFMASK;
- ip_len = ntohs(ip->ip_len);
- } else {
+#ifndef HAVE_NET_IPLEN
+ if (args->eh == NULL) { /* on l3 these are in host format */
offset = ip->ip_off & IP_OFFMASK;
- ip_len = ip->ip_len;
+ iplen = ip->ip_len;
+ } else
+#endif /* !HAVE_NET_IPLEN */
+ { /* otherwise they are in net format */
+ offset = ntohs(ip->ip_off) & IP_OFFMASK;
+ iplen = ntohs(ip->ip_len);
}
- pktlen = ip_len < pktlen ? ip_len : pktlen;
+ pktlen = iplen < pktlen ? iplen : pktlen;
if (offset == 0) {
switch (proto) {
@@ -1144,6 +1143,7 @@ do { \
IPFW_RUNLOCK(chain);
return (IP_FW_PASS); /* accept */
}
+ /* XXX divert should be handled same as other tags */
mtag = m_tag_find(m, PACKET_TAG_DIVERT, NULL);
if (args->slot) {
/*
@@ -1355,27 +1355,29 @@ do { \
case O_IP_SRC_LOOKUP:
case O_IP_DST_LOOKUP:
if (is_ipv4) {
- uint32_t a =
+ uint32_t key =
(cmd->opcode == O_IP_DST_LOOKUP) ?
dst_ip.s_addr : src_ip.s_addr;
uint32_t v = 0;
if (cmdlen > F_INSN_SIZE(ipfw_insn_u32)) {
- /* generic lookup */
+ /* generic lookup. The key must be
+ * in 32bit big-endian format.
+ */
v = ((ipfw_insn_u32 *)cmd)->d[1];
if (v == 0)
- a = dst_ip.s_addr;
+ key = dst_ip.s_addr;
else if (v == 1)
- a = src_ip.s_addr;
+ key = src_ip.s_addr;
else if (offset != 0)
break;
else if (proto != IPPROTO_TCP &&
proto != IPPROTO_UDP)
break;
else if (v == 2)
- a = dst_port;
+ key = htonl(dst_port);
else if (v == 3)
- a = src_port;
+ key = htons(src_port);
else if (v == 4 || v == 5) {
check_uidgid(
(ipfw_insn_u32 *)cmd,
@@ -1384,14 +1386,15 @@ do { \
src_ip, src_port, &ucred_cache,
&ucred_lookup, args->inp);
if (v == 4 /* O_UID */)
- a = ucred_cache->cr_uid;
+ key = ucred_cache->cr_uid;
else if (v == 5 /* O_JAIL */)
- a = ucred_cache->cr_prison->pr_id;
+ key = ucred_cache->cr_prison->pr_id;
+ key = htonl(key);
} else
break;
}
- match = ipfw_lookup_table(chain, cmd->arg1, a,
- &v);
+ match = ipfw_lookup_table(chain,
+ cmd->arg1, key, &v);
if (!match)
break;
if (cmdlen == F_INSN_SIZE(ipfw_insn_u32))
@@ -1514,7 +1517,7 @@ do { \
int i;
if (cmd->opcode == O_IPLEN)
- x = ip_len;
+ x = iplen;
else if (cmd->opcode == O_IPTTL)
x = ip->ip_ttl;
else /* must be IPID */
@@ -1549,7 +1552,7 @@ do { \
int i;
tcp = TCP(ulp);
- x = ip_len -
+ x = iplen -
((ip->ip_hl + tcp->th_off) << 2);
if (cmdlen == 1) {
match = (cmd->arg1 == x);
@@ -2022,7 +2025,7 @@ do { \
is_icmp_query(ICMP(ulp))) &&
!(m->m_flags & (M_BCAST|M_MCAST)) &&
!IN_MULTICAST(ntohl(dst_ip.s_addr))) {
- send_reject(args, cmd->arg1, ip_len, ip);
+ send_reject(args, cmd->arg1, iplen, ip);
m = args->m;
}
/* FALLTHROUGH */
@@ -2124,8 +2127,13 @@ do { \
f->bcnt += pktlen;
l = 0; /* in any case exit inner loop */
- ip_off = (args->eh != NULL) ?
- ntohs(ip->ip_off) : ip->ip_off;
+#ifndef HAVE_NET_IPLEN
+ if (args->eh == NULL)
+ ip_off = ip->ip_off;
+ else
+#endif /* !HAVE_NET_IPLEN */
+ ip_off = ntohs(ip->ip_off);
+
/* if not fragmented, go to next rule */
if ((ip_off & (IP_MF | IP_OFFMASK)) == 0)
break;
@@ -2135,8 +2143,7 @@ do { \
* from layer2.
*/
if (args->eh != NULL) {
- ip->ip_len = ntohs(ip->ip_len);
- ip->ip_off = ntohs(ip->ip_off);
+ SET_HOST_IPLEN(ip);
}
args->m = m = ip_reass(m);
@@ -2153,9 +2160,10 @@ do { \
ip = mtod(m, struct ip *);
hlen = ip->ip_hl << 2;
- /* revert len & off for layer2 pkts */
- if (args->eh != NULL)
- ip->ip_len = htons(ip->ip_len);
+ /* revert len. & off to net format if needed */
+ if (args->eh != NULL) {
+ SET_NET_IPLEN(ip);
+ }
ip->ip_sum = 0;
if (hlen == sizeof(struct ip))
ip->ip_sum = in_cksum_hdr(ip);
@@ -2364,7 +2372,7 @@ vnet_ipfw_init(const void *unused)
*/
V_ip_fw_ctl_ptr = ipfw_ctl;
V_ip_fw_chk_ptr = ipfw_chk;
- error = ipfw_attach_hooks();
+ error = ipfw_attach_hooks(1);
return (error);
}
@@ -2384,10 +2392,7 @@ vnet_ipfw_uninit(const void *unused)
* Then grab, release and grab again the WLOCK so we make
* sure the update is propagated and nobody will be in.
*/
- ipfw_unhook();
-#ifdef INET6
- ipfw6_unhook();
-#endif
+ (void)ipfw_attach_hooks(0 /* detach */);
V_ip_fw_chk_ptr = NULL;
V_ip_fw_ctl_ptr = NULL;
IPFW_UH_WLOCK(chain);
diff --git a/sys/netinet/ipfw/ip_fw_dynamic.c b/sys/netinet/ipfw/ip_fw_dynamic.c
index a5f24a7..70a0147 100644
--- a/sys/netinet/ipfw/ip_fw_dynamic.c
+++ b/sys/netinet/ipfw/ip_fw_dynamic.c
@@ -1002,7 +1002,11 @@ ipfw_send_pkt(struct mbuf *replyto, struct ipfw_flow_id *id, u_int32_t seq,
h->ip_hl = sizeof(*h) >> 2;
h->ip_tos = IPTOS_LOWDELAY;
h->ip_off = 0;
+#ifdef HAVE_NET_IPLEN /* XXX do we handle layer2 ? */
+ h->ip_len = htons(len);
+#else
h->ip_len = len;
+#endif
h->ip_ttl = V_ip_defttl;
h->ip_sum = 0;
break;
diff --git a/sys/netinet/ipfw/ip_fw_log.c b/sys/netinet/ipfw/ip_fw_log.c
index e3515af..e2aa4d2 100644
--- a/sys/netinet/ipfw/ip_fw_log.c
+++ b/sys/netinet/ipfw/ip_fw_log.c
@@ -87,6 +87,12 @@ __FBSDID("$FreeBSD$");
#define SNPARGS(buf, len) buf + len, sizeof(buf) > len ? sizeof(buf) - len : 0
#define SNP(buf) buf, sizeof(buf)
+#ifdef WITHOUT_BPF
+void
+ipfw_log_bpf(int onoff)
+{
+}
+#else /* !WITHOUT_BPF */
static struct ifnet *log_if; /* hook to attach to bpf */
/* we use this dummy function for all ifnet callbacks */
@@ -128,6 +134,7 @@ ipfw_log_bpf(int onoff)
log_if = NULL;
}
}
+#endif /* !WITHOUT_BPF */
/*
* We enter here when we have a rule with O_LOG.
@@ -138,12 +145,12 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args,
struct mbuf *m, struct ifnet *oif, u_short offset, uint32_t tablearg,
struct ip *ip)
{
- struct ether_header *eh = args->eh;
char *action;
int limit_reached = 0;
char action2[40], proto[128], fragment[32];
if (V_fw_verbose == 0) {
+#ifndef WITHOUT_BPF
struct m_hdr mh;
if (log_if == NULL || log_if->if_bpf == NULL)
@@ -160,16 +167,15 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args,
mh.mh_data = "DDDDDDSSSSSS\x08\x00";
if (args->f_id.addr_type == 4) {
/* restore wire format */
- ip->ip_off = ntohs(ip->ip_off);
- ip->ip_len = ntohs(ip->ip_len);
+ SET_NET_IPLEN(ip);
}
}
BPF_MTAP(log_if, (struct mbuf *)&mh);
if (args->eh == NULL && args->f_id.addr_type == 4) {
/* restore host format */
- ip->ip_off = htons(ip->ip_off);
- ip->ip_len = htons(ip->ip_len);
+ SET_HOST_IPLEN(ip);
}
+#endif /* !WITHOUT_BPF */
return;
}
/* the old 'log' function */
@@ -404,12 +410,15 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args,
#endif
{
int ip_off, ip_len;
- if (eh != NULL) { /* layer 2 packets are as on the wire */
- ip_off = ntohs(ip->ip_off);
- ip_len = ntohs(ip->ip_len);
- } else {
+#ifndef HAVE_NET_IPLEN
+ if (args->eh == NULL) {
ip_off = ip->ip_off;
ip_len = ip->ip_len;
+ } else
+#endif /* !HAVE_NET_IPLEN */
+ {
+ ip_off = ntohs(ip->ip_off);
+ ip_len = ntohs(ip->ip_len);
}
if (ip_off & (IP_MF | IP_OFFMASK))
snprintf(SNPARGS(fragment, 0),
diff --git a/sys/netinet/ipfw/ip_fw_nat.c b/sys/netinet/ipfw/ip_fw_nat.c
index c0a8cb8..549d779 100644
--- a/sys/netinet/ipfw/ip_fw_nat.c
+++ b/sys/netinet/ipfw/ip_fw_nat.c
@@ -29,14 +29,11 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/condvar.h>
#include <sys/eventhandler.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/module.h>
-#include <sys/priv.h>
-#include <sys/proc.h>
#include <sys/rwlock.h>
#define IPFW_INTERNAL /* Access to protected data structures in ip_fw.h. */
@@ -223,8 +220,7 @@ ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m)
}
ip = mtod(mcl, struct ip *);
if (args->eh == NULL) {
- ip->ip_len = htons(ip->ip_len);
- ip->ip_off = htons(ip->ip_off);
+ SET_NET_IPLEN(ip);
}
/*
@@ -302,11 +298,11 @@ ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m)
struct udphdr *uh;
u_short cksum;
- ip->ip_len = ntohs(ip->ip_len);
+ /* XXX check if ip_len can stay in net format */
cksum = in_pseudo(
ip->ip_src.s_addr,
ip->ip_dst.s_addr,
- htons(ip->ip_p + ip->ip_len - (ip->ip_hl << 2))
+ htons(ip->ip_p + ntohs(ip->ip_len) - (ip->ip_hl << 2))
);
switch (ip->ip_p) {
@@ -333,14 +329,10 @@ ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m)
in_delayed_cksum(mcl);
mcl->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
}
- ip->ip_len = htons(ip->ip_len);
}
-
if (args->eh == NULL) {
- ip->ip_len = ntohs(ip->ip_len);
- ip->ip_off = ntohs(ip->ip_off);
+ SET_HOST_IPLEN(ip);
}
-
args->m = mcl;
return (IP_FW_NAT);
}
diff --git a/sys/netinet/ipfw/ip_fw_pfil.c b/sys/netinet/ipfw/ip_fw_pfil.c
index 35ee157..f59d341 100644
--- a/sys/netinet/ipfw/ip_fw_pfil.c
+++ b/sys/netinet/ipfw/ip_fw_pfil.c
@@ -46,9 +46,7 @@ __FBSDID("$FreeBSD$");
#include <sys/lock.h>
#include <sys/rwlock.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>
@@ -64,8 +62,6 @@ __FBSDID("$FreeBSD$");
#include <netinet/ip_divert.h>
#include <netinet/ip_dummynet.h>
-#include <netgraph/ng_ipfw.h>
-
#include <machine/in_cksum.h>
static VNET_DEFINE(int, fw_enable) = 1;
@@ -85,9 +81,7 @@ ip_divert_packet_t *ip_divert_ptr = NULL;
ng_ipfw_input_t *ng_ipfw_input_p = NULL;
/* Forward declarations. */
-static int ipfw_divert(struct mbuf **, int, int);
-#define DIV_DIR_IN 1
-#define DIV_DIR_OUT 0
+static void ipfw_divert(struct mbuf **, int, int);
#ifdef SYSCTL_NODE
SYSCTL_DECL(_net_inet_ip_fw);
@@ -102,162 +96,32 @@ SYSCTL_VNET_PROC(_net_inet6_ip6_fw, OID_AUTO, enable,
#endif /* INET6 */
#endif /* SYSCTL_NODE */
-int
-ipfw_check_in(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
- struct inpcb *inp)
-{
- struct ip_fw_args args;
- struct ng_ipfw_tag *ng_tag;
- struct m_tag *dn_tag;
- int ipfw = 0;
- int divert;
- int tee;
-#ifdef IPFIREWALL_FORWARD
- struct m_tag *fwd_tag;
-#endif
-
- KASSERT(dir == PFIL_IN, ("ipfw_check_in wrong direction!"));
-
- bzero(&args, sizeof(args));
-
- ng_tag = (struct ng_ipfw_tag *)m_tag_locate(*m0, NGM_IPFW_COOKIE, 0,
- NULL);
- if (ng_tag != NULL) {
- KASSERT(ng_tag->dir == NG_IPFW_IN,
- ("ng_ipfw tag with wrong direction"));
- args.slot = ng_tag->slot;
- args.rulenum = ng_tag->rulenum;
- args.rule_id = ng_tag->rule_id;
- args.chain_id = ng_tag->chain_id;
- m_tag_delete(*m0, (struct m_tag *)ng_tag);
- }
-
-again:
- 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.slot = dt->slot;
- args.rulenum = dt->rulenum;
- args.rule_id = dt->rule_id;
- args.chain_id = dt->chain_id;
- m_tag_delete(*m0, dn_tag);
- }
-
- args.m = *m0;
- args.inp = inp;
- tee = 0;
-
- if (V_fw_one_pass == 0 || args.slot == 0) {
- ipfw = ipfw_chk(&args);
- *m0 = args.m;
- } else
- ipfw = IP_FW_PASS;
-
- KASSERT(*m0 != NULL || ipfw == IP_FW_DENY, ("%s: m0 is NULL",
- __func__));
-
- switch (ipfw) {
- case IP_FW_PASS:
- if (args.next_hop == NULL)
- goto pass;
-
-#ifdef IPFIREWALL_FORWARD
- 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
- break; /* not reached */
-
- case IP_FW_DENY:
- goto drop;
- break; /* not reached */
-
- case IP_FW_DUMMYNET:
- if (ip_dn_io_ptr == NULL)
- goto drop;
- if (mtod(*m0, struct ip *)->ip_v == 4)
- ip_dn_io_ptr(m0, DN_TO_IP_IN, &args);
- else if (mtod(*m0, struct ip *)->ip_v == 6)
- ip_dn_io_ptr(m0, DN_TO_IP6_IN, &args);
- if (*m0 != NULL)
- goto again;
- return 0; /* packet consumed */
-
- case IP_FW_TEE:
- tee = 1;
- /* fall through */
-
- case IP_FW_DIVERT:
- divert = ipfw_divert(m0, DIV_DIR_IN, tee);
- if (divert) {
- *m0 = NULL;
- return 0; /* packet consumed */
- } else {
- args.slot = 0;
- goto again; /* continue with packet */
- }
-
- case IP_FW_NGTEE:
- if (!NG_IPFW_LOADED)
- goto drop;
- (void)ng_ipfw_input_p(m0, NG_IPFW_IN, &args, 1);
- goto again; /* continue with packet */
-
- case IP_FW_NETGRAPH:
- if (!NG_IPFW_LOADED)
- goto drop;
- return ng_ipfw_input_p(m0, NG_IPFW_IN, &args, 0);
-
- case IP_FW_NAT:
- goto again; /* continue with packet */
-
- case IP_FW_REASS:
- goto again;
-
- default:
- KASSERT(0, ("%s: unknown retval", __func__));
- }
-
-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,
+/*
+ * The pfilter hook to pass packets to ipfw_chk and then to
+ * dummynet, divert, netgraph or other modules.
+ * The packet may be consumed.
+ */
+static int
+ipfw_check_hook(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
struct inpcb *inp)
{
struct ip_fw_args args;
struct ng_ipfw_tag *ng_tag;
struct m_tag *dn_tag;
- int ipfw = 0;
- int divert;
- int tee;
+ int ipfw;
+ int ret;
#ifdef IPFIREWALL_FORWARD
struct m_tag *fwd_tag;
#endif
- KASSERT(dir == PFIL_OUT, ("ipfw_check_out wrong direction!"));
-
+ /* convert dir to IPFW values */
+ dir = (dir == PFIL_IN) ? DIR_IN : DIR_OUT;
bzero(&args, sizeof(args));
ng_tag = (struct ng_ipfw_tag *)m_tag_locate(*m0, NGM_IPFW_COOKIE, 0,
NULL);
if (ng_tag != NULL) {
- KASSERT(ng_tag->dir == NG_IPFW_OUT,
+ KASSERT(ng_tag->dir == dir,
("ng_ipfw tag with wrong direction"));
args.slot = ng_tag->slot;
args.rulenum = ng_tag->rulenum;
@@ -280,9 +144,8 @@ again:
}
args.m = *m0;
- args.oif = ifp;
+ args.oif = dir == DIR_OUT ? ifp : NULL;
args.inp = inp;
- tee = 0;
if (V_fw_one_pass == 0 || args.slot == 0) {
ipfw = ipfw_chk(&args);
@@ -293,255 +156,209 @@ again:
KASSERT(*m0 != NULL || ipfw == IP_FW_DENY, ("%s: m0 is NULL",
__func__));
+ /* breaking out of the switch means drop */
+ ret = 0; /* default return value for pass */
switch (ipfw) {
case IP_FW_PASS:
+ /* next_hop may be set by ipfw_chk */
if (args.next_hop == NULL)
- goto pass;
-#ifdef IPFIREWALL_FORWARD
- /* Overwrite existing tag. */
- fwd_tag = m_tag_find(*m0, PACKET_TAG_IPFORWARD, NULL);
- if (fwd_tag == NULL) {
+ break; /* pass */
+#ifndef IPFIREWALL_FORWARD
+ ret = EACCES;
+#else
+ /* Incoming packets should not be tagged so we do not
+ * m_tag_find. Outgoing packets may be tagged, so we
+ * reuse the tag if present.
+ */
+ fwd_tag = (dir == DIR_IN) ? NULL :
+ m_tag_find(*m0, PACKET_TAG_IPFORWARD, NULL);
+ if (fwd_tag != NULL) {
+ m_tag_unlink(*m0, fwd_tag);
+ } else {
fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD,
sizeof(struct sockaddr_in), M_NOWAIT);
- if (fwd_tag == NULL)
- goto drop;
- } else
- m_tag_unlink(*m0, fwd_tag);
+ if (fwd_tag == NULL) {
+ ret = EACCES;
+ break; /* i.e. 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
- break; /* not reached */
+ break;
case IP_FW_DENY:
- goto drop;
- break; /* not reached */
+ ret = EACCES;
+ break; /* i.e. drop */
case IP_FW_DUMMYNET:
+ ret = EACCES;
if (ip_dn_io_ptr == NULL)
- break;
+ break; /* i.e. drop */
if (mtod(*m0, struct ip *)->ip_v == 4)
- ip_dn_io_ptr(m0, DN_TO_IP_OUT, &args);
+ ret = ip_dn_io_ptr(m0, dir, &args);
else if (mtod(*m0, struct ip *)->ip_v == 6)
- ip_dn_io_ptr(m0, DN_TO_IP6_OUT, &args);
+ ret = ip_dn_io_ptr(m0, dir | PROTO_IPV6, &args);
+ else
+ break; /* drop it */
+ /*
+ * XXX should read the return value.
+ * dummynet normally eats the packet and sets *m0=NULL
+ * unless the packet can be sent immediately. In this
+ * case args is updated and we should re-run the
+ * check without clearing args.
+ */
if (*m0 != NULL)
goto again;
- return 0; /* packet consumed */
-
break;
case IP_FW_TEE:
- tee = 1;
- /* fall through */
-
case IP_FW_DIVERT:
- divert = ipfw_divert(m0, DIV_DIR_OUT, tee);
- if (divert) {
- *m0 = NULL;
- return 0; /* packet consumed */
- } else {
+ if (ip_divert_ptr == NULL) {
+ ret = EACCES;
+ break; /* i.e. drop */
+ }
+ ipfw_divert(m0, dir, (ipfw == IP_FW_TEE) ? 1 : 0);
+ if (*m0) {
+ /* continue processing for this one. We set
+ * args.slot=0, but the divert tag is processed
+ * in ipfw_chk to jump to the right place.
+ */
args.slot = 0;
goto again; /* continue with packet */
}
+ break;
case IP_FW_NGTEE:
- if (!NG_IPFW_LOADED)
- goto drop;
- (void)ng_ipfw_input_p(m0, NG_IPFW_OUT, &args, 1);
- goto again; /* continue with packet */
-
case IP_FW_NETGRAPH:
- if (!NG_IPFW_LOADED)
- goto drop;
- return ng_ipfw_input_p(m0, NG_IPFW_OUT, &args, 0);
+ if (!NG_IPFW_LOADED) {
+ ret = EACCES;
+ break; /* i.e. drop */
+ }
+ ret = ng_ipfw_input_p(m0, dir, &args,
+ (ipfw == IP_FW_NGTEE) ? 1 : 0);
+ if (ipfw == IP_FW_NGTEE) /* ignore errors for NGTEE */
+ goto again; /* continue with packet */
+ break;
case IP_FW_NAT:
- goto again; /* continue with packet */
-
case IP_FW_REASS:
- goto again;
+ goto again; /* continue with packet */
default:
KASSERT(0, ("%s: unknown retval", __func__));
}
-drop:
- if (*m0)
- m_freem(*m0);
- *m0 = NULL;
- return (EACCES);
-pass:
- return 0; /* not filtered */
+ if (ret != 0) {
+ if (*m0)
+ m_freem(*m0);
+ *m0 = NULL;
+ }
+ return ret;
}
-static int
-ipfw_divert(struct mbuf **m, int incoming, int tee)
+static void
+ipfw_divert(struct mbuf **m0, int incoming, int tee)
{
/*
* ipfw_chk() has already tagged the packet with the divert tag.
* If tee is set, copy packet and return original.
* If not tee, consume packet and send it to divert socket.
*/
- struct mbuf *clone, *reass;
+ struct mbuf *clone;
struct ip *ip;
- int hlen;
-
- reass = NULL;
-
- /* Is divert module loaded? */
- if (ip_divert_ptr == NULL)
- goto nodivert;
/* 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;
+ if (tee == 0) {
+ clone = *m0; /* use the original mbuf */
+ *m0 = NULL;
+ } else {
+ clone = m_dup(*m0, M_DONTWAIT);
+ /* If we cannot duplicate the mbuf, we sacrifice the divert
+ * chain and continue with the tee-ed packet.
+ */
+ if (clone == NULL)
+ return;
+ }
/*
- * 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.
+ * Divert listeners can normally handle non-fragmented packets,
+ * but we can only reass in the non-tee case.
+ * This means that listeners on a tee rule may get fragments,
+ * and have to live with that.
+ * Note that we now have the 'reass' ipfw option so if we care
+ * we can do it before a 'tee'.
*/
ip = mtod(clone, struct ip *);
if (!tee && ip->ip_off & (IP_MF | IP_OFFMASK)) {
+ int hlen;
+ struct mbuf *reass;
- /* Reassemble packet. */
- reass = ip_reass(clone);
-
+ reass = ip_reass(clone); /* Reassemble packet. */
+ if (reass == NULL)
+ return;
+ /* if reass = NULL then it was consumed by ip_reass */
/*
* 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;
+ ip = mtod(reass, struct ip *);
+ hlen = ip->ip_hl << 2;
+ SET_NET_IPLEN(ip);
+ 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 {
/* Convert header to network byte order. */
- ip->ip_len = htons(ip->ip_len);
- ip->ip_off = htons(ip->ip_off);
+ SET_NET_IPLEN(ip);
}
/* Do the dirty job... */
- if (clone && ip_divert_ptr != NULL)
- ip_divert_ptr(clone, incoming);
-
-teeout:
- /*
- * For tee we leave the divert tag attached to original packet.
- * It will then continue rule evaluation after the tee rule.
- */
- if (tee)
- return 0;
-
- /* Packet diverted and consumed */
- return 1;
-
-nodivert:
- m_freem(*m);
- return 1;
-}
-
-static int
-ipfw_hook(void)
-{
- struct pfil_head *pfh_inet;
-
- pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
- if (pfh_inet == NULL)
- return ENOENT;
-
- (void)pfil_add_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK,
- pfh_inet);
- (void)pfil_add_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK,
- pfh_inet);
-
- return 0;
-}
-
-int
-ipfw_unhook(void)
-{
- struct pfil_head *pfh_inet;
-
- pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
- if (pfh_inet == NULL)
- return ENOENT;
-
- (void)pfil_remove_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK,
- pfh_inet);
- (void)pfil_remove_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK,
- pfh_inet);
-
- return 0;
+ ip_divert_ptr(clone, incoming);
}
-#ifdef INET6
+/*
+ * attach or detach hooks for a given protocol family
+ */
static int
-ipfw6_hook(void)
-{
- struct pfil_head *pfh_inet6;
-
- pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
- if (pfh_inet6 == NULL)
- return ENOENT;
-
- (void)pfil_add_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK,
- pfh_inet6);
- (void)pfil_add_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK,
- pfh_inet6);
-
- return 0;
-}
-
-int
-ipfw6_unhook(void)
+ipfw_hook(int onoff, int pf)
{
- struct pfil_head *pfh_inet6;
+ const int arg = PFIL_IN | PFIL_OUT | PFIL_WAITOK;
+ struct pfil_head *pfh;
- pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
- if (pfh_inet6 == NULL)
+ pfh = pfil_head_get(PFIL_TYPE_AF, pf);
+ if (pfh == NULL)
return ENOENT;
- (void)pfil_remove_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK,
- pfh_inet6);
- (void)pfil_remove_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK,
- pfh_inet6);
+ if (onoff)
+ (void)pfil_add_hook(ipfw_check_hook, NULL, arg, pfh);
+ else
+ (void)pfil_remove_hook(ipfw_check_hook, NULL, arg, pfh);
return 0;
}
-#endif /* INET6 */
int
-ipfw_attach_hooks(void)
+ipfw_attach_hooks(int arg)
{
int error = 0;
- if (V_fw_enable && ipfw_hook() != 0) {
+ if (arg == 0) /* detach */
+ ipfw_hook(0, AF_INET);
+ else if (V_fw_enable && ipfw_hook(1, AF_INET) != 0) {
error = ENOENT; /* see ip_fw_pfil.c::ipfw_hook() */
printf("ipfw_hook() error\n");
}
#ifdef INET6
- if (V_fw6_enable && ipfw6_hook() != 0) {
+ if (arg == 0) /* detach */
+ ipfw_hook(0, AF_INET6);
+ else if (V_fw6_enable && ipfw_hook(1, AF_INET6) != 0) {
error = ENOENT;
printf("ipfw6_hook() error\n");
}
@@ -555,13 +372,16 @@ ipfw_chg_hook(SYSCTL_HANDLER_ARGS)
int enable;
int oldenable;
int error;
+ int af;
if (arg1 == &VNET_NAME(fw_enable)) {
enable = V_fw_enable;
+ af = AF_INET;
}
#ifdef INET6
else if (arg1 == &VNET_NAME(fw6_enable)) {
enable = V_fw6_enable;
+ af = AF_INET6;
}
#endif
else
@@ -579,25 +399,14 @@ ipfw_chg_hook(SYSCTL_HANDLER_ARGS)
if (enable == oldenable)
return (0);
- if (arg1 == &VNET_NAME(fw_enable)) {
- if (enable)
- error = ipfw_hook();
- else
- error = ipfw_unhook();
- if (error)
- return (error);
+ error = ipfw_hook(enable, af);
+ if (error)
+ return (error);
+ if (af == AF_INET)
V_fw_enable = enable;
- }
#ifdef INET6
- else if (arg1 == &VNET_NAME(fw6_enable)) {
- if (enable)
- error = ipfw6_hook();
- else
- error = ipfw6_unhook();
- if (error)
- return (error);
+ else if (af == AF_INET6)
V_fw6_enable = enable;
- }
#endif
return (0);
diff --git a/sys/netinet/ipfw/ip_fw_private.h b/sys/netinet/ipfw/ip_fw_private.h
index da5db8e..780d16e 100644
--- a/sys/netinet/ipfw/ip_fw_private.h
+++ b/sys/netinet/ipfw/ip_fw_private.h
@@ -101,19 +101,33 @@ struct ip_fw_args {
MALLOC_DECLARE(M_IPFW);
/*
- * Function definitions.
+ * Hooks sometime need to know the direction of the packet
+ * (divert, dummynet, netgraph, ...)
+ * We use a generic definition here, with bit0-1 indicating the
+ * direction, bit 2 indicating layer2 or 3, bit 3-4 indicating the
+ * specific protocol
+ * indicating the protocol (if necessary)
*/
+enum {
+ DIR_MASK = 0x3,
+ DIR_OUT = 0,
+ DIR_IN = 1,
+ DIR_FWD = 2,
+ DIR_DROP = 3,
+ PROTO_LAYER2 = 0x4, /* set for layer 2 */
+ /* PROTO_DEFAULT = 0, */
+ PROTO_IPV4 = 0x08,
+ PROTO_IPV6 = 0x10,
+ PROTO_IFB = 0x0c, /* layer2 + ifbridge */
+ /* PROTO_OLDBDG = 0x14, unused, old bridge */
+};
-/* Firewall hooks */
-
-int ipfw_check_in(void *, struct mbuf **, struct ifnet *,
- int, struct inpcb *inp);
-int ipfw_check_out(void *, struct mbuf **, struct ifnet *,
- int, struct inpcb *inp);
+/*
+ * Function definitions.
+ */
-int ipfw_attach_hooks(void);
-int ipfw_unhook(void);
-int ipfw6_unhook(void);
+/* attach (arg = 1) or detach (arg = 0) hooks */
+int ipfw_attach_hooks(int);
#ifdef NOTYET
void ipfw_nat_destroy(void);
#endif
@@ -257,5 +271,27 @@ extern ipfw_nat_cfg_t *ipfw_nat_del_ptr;
extern ipfw_nat_cfg_t *ipfw_nat_get_cfg_ptr;
extern ipfw_nat_cfg_t *ipfw_nat_get_log_ptr;
+/* netgraph prototypes */
+#define NGM_IPFW_COOKIE 1105988990
+
+typedef int ng_ipfw_input_t(struct mbuf **, int, struct ip_fw_args *, int);
+extern ng_ipfw_input_t *ng_ipfw_input_p;
+#define NG_IPFW_LOADED (ng_ipfw_input_p != NULL)
+
+struct ng_ipfw_tag {
+ struct m_tag mt; /* tag header */
+ /* reinject info */
+ uint32_t slot; /* slot for next rule */
+ uint32_t rulenum; /* matching rule number */
+ uint32_t rule_id; /* matching rule id */
+ uint32_t chain_id; /* ruleset id */
+ int dir;
+
+// struct ifnet *ifp; /* interface, for ip_output */
+};
+
+#define TAGSIZ (sizeof(struct ng_ipfw_tag) - sizeof(struct m_tag))
+
+
#endif /* _KERNEL */
#endif /* _IPFW2_PRIVATE_H */
diff --git a/sys/netinet/ipfw/ip_fw_sockopt.c b/sys/netinet/ipfw/ip_fw_sockopt.c
index e14952a..40d6ed7 100644
--- a/sys/netinet/ipfw/ip_fw_sockopt.c
+++ b/sys/netinet/ipfw/ip_fw_sockopt.c
@@ -67,8 +67,6 @@ __FBSDID("$FreeBSD$");
#include <netinet/ipfw/ip_fw_private.h>
#include <netinet/ip_divert.h>
-#include <netgraph/ng_ipfw.h>
-
#ifdef MAC
#include <security/mac/mac_framework.h>
#endif
OpenPOWER on IntegriCloud