bring in several cleanups tested in ipfw3-head branch, namely:
r201011 - move most of ng_ipfw.h into ip_fw_private.h, as this code is ipfw-specific. This removes a dependency on ng_ipfw.h from some files. - move many equivalent definitions of direction (IN, OUT) for reinjected packets into ip_fw_private.h - document the structure of the packet tags used for dummynet and netgraph; r201049 - merge some common code to attach/detach hooks into a single function. r201055 - remove some duplicated code in ip_fw_pfil. The input and output processing uses almost exactly the same code so there is no need to use two separate hooks. ip_fw_pfil.o goes from 2096 to 1382 bytes of .text r201057 (see the svn log for full details) - macros to make the conversion of ip_len and ip_off between host and network format more explicit r201113 (the remaining parts) - readability fixes -- put braces around some large for() blocks, localize variables so the compiler does not think they are uninitialized, do not insist on precise allocation size if we have more than we need. r201119 - when doing a lookup, keys must be in big endian format because this is what the radix code expects (this fixes a bug in the recently-introduced 'lookup' option) No ABI changes in this commit. MFC after: 1 week
This commit is contained in:
parent
6cc7b9f5d9
commit
830c6e2b97
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=201122
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
/*
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
/*
|
||||
* 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_IN, ("ipfw_check_in 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_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,
|
||||
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_OUT, ("ipfw_check_out 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_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 @@ ipfw_check_out(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
|
||||
}
|
||||
|
||||
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 @@ ipfw_check_out(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
|
||||
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;
|
||||
ip_divert_ptr(clone, incoming);
|
||||
}
|
||||
|
||||
/*
|
||||
* attach or detach hooks for a given protocol family
|
||||
*/
|
||||
static int
|
||||
ipfw_hook(void)
|
||||
ipfw_hook(int onoff, int pf)
|
||||
{
|
||||
struct pfil_head *pfh_inet;
|
||||
const int arg = PFIL_IN | PFIL_OUT | PFIL_WAITOK;
|
||||
struct pfil_head *pfh;
|
||||
|
||||
pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
|
||||
if (pfh_inet == NULL)
|
||||
pfh = pfil_head_get(PFIL_TYPE_AF, pf);
|
||||
if (pfh == 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);
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#ifdef INET6
|
||||
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)
|
||||
{
|
||||
struct pfil_head *pfh_inet6;
|
||||
|
||||
pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
|
||||
if (pfh_inet6 == 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);
|
||||
|
||||
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);
|
||||
|
@ -100,20 +100,34 @@ struct ip_fw_args {
|
||||
|
||||
MALLOC_DECLARE(M_IPFW);
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
};
|
||||
|
||||
/*
|
||||
* Function definitions.
|
||||
*/
|
||||
|
||||
/* 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);
|
||||
|
||||
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 */
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user