Various cleanup done in ipfw3-head branch including:
- use a uniform mtag format for all packets that exit and re-enter the firewall in the middle of a rulechain. On reentry, all tags containing reinject info are renamed to MTAG_IPFW_RULE so the processing is simpler. - make ipfw and dummynet use ip_len and ip_off in network format everywhere. Conversion is done only once instead of tracking the format in every place. - use a macro FREE_PKT to dispose of mbufs. This eases portability. On passing i also removed a few typos, staticise or localise variables, remove useless declarations and other minor things. Overall the code shrinks a bit and is hopefully more readable. I have tested functionality for all but ng_ipfw and if_bridge/if_ethersubr. For ng_ipfw i am actually waiting for feedback from glebius@ because we might have some small changes to make. For if_bridge and if_ethersubr feedback would be welcome (there are still some redundant parts in these two modules that I would like to remove, but first i need to check functionality).
This commit is contained in:
parent
290dac20e6
commit
7173b6e554
@ -3040,25 +3040,26 @@ 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) {
|
||||
// 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;
|
||||
mtag = m_tag_find(*mp, PACKET_TAG_DUMMYNET, NULL);
|
||||
/* fetch the start point from existing tags, if any */
|
||||
mtag = m_tag_locate(*mp, MTAG_IPFW_RULE, 0, NULL);
|
||||
if (mtag == NULL) {
|
||||
args.slot = 0;
|
||||
args.rule.slot = 0;
|
||||
} else {
|
||||
struct dn_pkt_tag *dn_tag;
|
||||
|
||||
/* XXX can we free the tag after use ? */
|
||||
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 */
|
||||
/* packet already partially processed ? */
|
||||
if (dn_tag->rule.slot != 0 && V_fw_one_pass)
|
||||
goto ipfwpass;
|
||||
args.slot = dn_tag->slot; /* next rule to use */
|
||||
args.chain_id = dn_tag->chain_id;
|
||||
args.rulenum = dn_tag->rulenum;
|
||||
args.rule_id = dn_tag->rule_id;
|
||||
args.rule = dn_tag->rule;
|
||||
}
|
||||
|
||||
args.m = *mp;
|
||||
|
@ -469,21 +469,20 @@ ether_ipfw_chk(struct mbuf **m0, struct ifnet *dst, int shared)
|
||||
struct ip_fw_args args;
|
||||
struct m_tag *mtag;
|
||||
|
||||
mtag = m_tag_find(*m0, PACKET_TAG_DUMMYNET, NULL);
|
||||
/* fetch start point from rule, if any */
|
||||
mtag = m_tag_locate(*m0, MTAG_IPFW_RULE, 0, NULL);
|
||||
if (mtag == NULL) {
|
||||
args.slot = 0;
|
||||
args.rule.slot = 0;
|
||||
} else {
|
||||
struct dn_pkt_tag *dn_tag;
|
||||
|
||||
/* XXX can we free it after use ? */
|
||||
mtag->m_tag_id = PACKET_TAG_NONE;
|
||||
dn_tag = (struct dn_pkt_tag *)(mtag + 1);
|
||||
if (dn_tag->slot != 0 && V_fw_one_pass)
|
||||
if (dn_tag->rule.slot != 0 && V_fw_one_pass)
|
||||
/* dummynet packet, already partially processed */
|
||||
return (1);
|
||||
args.slot = dn_tag->slot; /* matching rule to restart */
|
||||
args.rulenum = dn_tag->rulenum;
|
||||
args.rule_id = dn_tag->rule_id;
|
||||
args.chain_id = dn_tag->chain_id;
|
||||
args.rule = dn_tag->rule;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -221,21 +221,23 @@ ng_ipfw_findhook1(node_p node, u_int16_t rulenum)
|
||||
static int
|
||||
ng_ipfw_rcvdata(hook_p hook, item_p item)
|
||||
{
|
||||
struct ng_ipfw_tag *ngit;
|
||||
struct ipfw_rule_ref *tag;
|
||||
struct mbuf *m;
|
||||
|
||||
NGI_GET_M(item, m);
|
||||
NG_FREE_ITEM(item);
|
||||
|
||||
if ((ngit = (struct ng_ipfw_tag *)m_tag_locate(m, NGM_IPFW_COOKIE, 0,
|
||||
NULL)) == NULL) {
|
||||
tag = (struct ipfw_rule_ref *)
|
||||
m_tag_locate(m, MTAG_IPFW_RULE, 0, NULL);
|
||||
if (tag == NULL) {
|
||||
NG_FREE_M(m);
|
||||
return (EINVAL); /* XXX: find smth better */
|
||||
};
|
||||
|
||||
switch (ngit->dir) {
|
||||
case DIR_OUT:
|
||||
{
|
||||
if (tag->info & IPFW_INFO_IN) {
|
||||
ip_input(m);
|
||||
return (0);
|
||||
} else {
|
||||
struct ip *ip;
|
||||
|
||||
if (m->m_len < sizeof(struct ip) &&
|
||||
@ -244,27 +246,16 @@ ng_ipfw_rcvdata(hook_p hook, item_p item)
|
||||
|
||||
ip = mtod(m, struct ip *);
|
||||
|
||||
ip->ip_len = ntohs(ip->ip_len);
|
||||
ip->ip_off = ntohs(ip->ip_off);
|
||||
SET_HOST_IPLEN(ip);
|
||||
|
||||
return ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL);
|
||||
}
|
||||
case DIR_IN:
|
||||
ip_input(m);
|
||||
return (0);
|
||||
default:
|
||||
panic("ng_ipfw_rcvdata: bad dir %u", ngit->dir);
|
||||
}
|
||||
|
||||
/* not reached */
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ng_ipfw_input(struct mbuf **m0, int dir, struct ip_fw_args *fwa, int tee)
|
||||
{
|
||||
struct mbuf *m;
|
||||
struct ng_ipfw_tag *ngit;
|
||||
struct ip *ip;
|
||||
hook_p hook;
|
||||
int error = 0;
|
||||
@ -273,7 +264,7 @@ ng_ipfw_input(struct mbuf **m0, int dir, struct ip_fw_args *fwa, int tee)
|
||||
* Node must be loaded and corresponding hook must be present.
|
||||
*/
|
||||
if (fw_node == NULL ||
|
||||
(hook = ng_ipfw_findhook1(fw_node, fwa->cookie)) == NULL) {
|
||||
(hook = ng_ipfw_findhook1(fw_node, fwa->rule.info)) == NULL) {
|
||||
if (tee == 0)
|
||||
m_freem(*m0);
|
||||
return (ESRCH); /* no hook associated with this rule */
|
||||
@ -285,21 +276,21 @@ ng_ipfw_input(struct mbuf **m0, int dir, struct ip_fw_args *fwa, int tee)
|
||||
* a copy of a packet and forward it into netgraph without a tag.
|
||||
*/
|
||||
if (tee == 0) {
|
||||
struct m_tag *tag;
|
||||
struct ipfw_rule_ref *r;
|
||||
m = *m0;
|
||||
*m0 = NULL; /* it belongs now to netgraph */
|
||||
|
||||
if ((ngit = (struct ng_ipfw_tag *)m_tag_alloc(NGM_IPFW_COOKIE,
|
||||
0, TAGSIZ, M_NOWAIT|M_ZERO)) == NULL) {
|
||||
tag = m_tag_alloc(MTAG_IPFW_RULE, 0, sizeof(*r),
|
||||
M_NOWAIT|M_ZERO);
|
||||
if (tag == NULL) {
|
||||
m_freem(m);
|
||||
return (ENOMEM);
|
||||
}
|
||||
ngit->slot = fwa->slot;
|
||||
ngit->rulenum = fwa->rulenum;
|
||||
ngit->rule_id = fwa->rule_id;
|
||||
ngit->chain_id = fwa->chain_id;
|
||||
ngit->dir = dir;
|
||||
// ngit->ifp = fwa->oif; /* XXX do we use it ? */
|
||||
m_tag_prepend(m, &ngit->mt);
|
||||
r = (struct ipfw_rule_ref *)(tag + 1);
|
||||
*r = fwa->rule;
|
||||
r->info = dir ? IPFW_INFO_IN : IPFW_INFO_OUT;
|
||||
m_tag_prepend(m, tag);
|
||||
|
||||
} else
|
||||
if ((m = m_dup(*m0, M_DONTWAIT)) == NULL)
|
||||
@ -310,8 +301,6 @@ ng_ipfw_input(struct mbuf **m0, int dir, struct ip_fw_args *fwa, int tee)
|
||||
return (EINVAL);
|
||||
|
||||
ip = mtod(m, struct ip *);
|
||||
ip->ip_len = htons(ip->ip_len);
|
||||
ip->ip_off = htons(ip->ip_off);
|
||||
|
||||
NG_SEND_DATA_ONLY(error, hook, m);
|
||||
|
||||
|
@ -52,19 +52,12 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/priv.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/protosw.h>
|
||||
#include <sys/rwlock.h>
|
||||
#include <sys/signalvar.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/sx.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
#include <vm/uma.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/netisr.h>
|
||||
#include <net/route.h>
|
||||
#include <net/vnet.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
@ -72,7 +65,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/in_var.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_divert.h>
|
||||
#include <netinet/ip_var.h>
|
||||
#include <netinet/ip_fw.h>
|
||||
#include <netinet/ipfw/ip_fw_private.h>
|
||||
@ -194,7 +186,7 @@ div_destroy(void)
|
||||
* IPPROTO_DIVERT is not in the real IP protocol number space; this
|
||||
* function should never be called. Just in case, drop any packets.
|
||||
*/
|
||||
void
|
||||
static void
|
||||
div_input(struct mbuf *m, int off)
|
||||
{
|
||||
|
||||
@ -218,9 +210,8 @@ divert_packet(struct mbuf *m, int incoming)
|
||||
struct sockaddr_in divsrc;
|
||||
struct m_tag *mtag;
|
||||
|
||||
mtag = m_tag_find(m, PACKET_TAG_DIVERT, NULL);
|
||||
mtag = m_tag_locate(m, MTAG_IPFW_RULE, 0, NULL);
|
||||
if (mtag == NULL) {
|
||||
printf("%s: no divert tag\n", __func__);
|
||||
m_freem(m);
|
||||
return;
|
||||
}
|
||||
@ -245,14 +236,15 @@ divert_packet(struct mbuf *m, int incoming)
|
||||
ip->ip_len = htons(ip->ip_len);
|
||||
}
|
||||
#endif
|
||||
bzero(&divsrc, sizeof(divsrc));
|
||||
divsrc.sin_len = sizeof(divsrc);
|
||||
divsrc.sin_family = AF_INET;
|
||||
/* record matching rule, in host format */
|
||||
divsrc.sin_port = ((struct ipfw_rule_ref *)(mtag+1))->rulenum;
|
||||
/*
|
||||
* Record receive interface address, if any.
|
||||
* But only for incoming packets.
|
||||
*/
|
||||
bzero(&divsrc, sizeof(divsrc));
|
||||
divsrc.sin_len = sizeof(divsrc);
|
||||
divsrc.sin_family = AF_INET;
|
||||
divsrc.sin_port = divert_cookie(mtag); /* record matching rule */
|
||||
if (incoming) {
|
||||
struct ifaddr *ifa;
|
||||
struct ifnet *ifp;
|
||||
@ -300,7 +292,7 @@ divert_packet(struct mbuf *m, int incoming)
|
||||
|
||||
/* Put packet on socket queue, if any */
|
||||
sa = NULL;
|
||||
nport = htons((u_int16_t)divert_info(mtag));
|
||||
nport = htons((u_int16_t)(((struct ipfw_rule_ref *)(mtag+1))->info));
|
||||
INP_INFO_RLOCK(&V_divcbinfo);
|
||||
LIST_FOREACH(inp, &V_divcb, inp_list) {
|
||||
/* XXX why does only one socket match? */
|
||||
@ -339,7 +331,7 @@ div_output(struct socket *so, struct mbuf *m, struct sockaddr_in *sin,
|
||||
struct mbuf *control)
|
||||
{
|
||||
struct m_tag *mtag;
|
||||
struct divert_tag *dt;
|
||||
struct ipfw_rule_ref *dt;
|
||||
int error = 0;
|
||||
struct mbuf *options;
|
||||
|
||||
@ -354,23 +346,31 @@ div_output(struct socket *so, struct mbuf *m, struct sockaddr_in *sin,
|
||||
if (control)
|
||||
m_freem(control); /* XXX */
|
||||
|
||||
if ((mtag = m_tag_find(m, PACKET_TAG_DIVERT, NULL)) == NULL) {
|
||||
mtag = m_tag_get(PACKET_TAG_DIVERT, sizeof(struct divert_tag),
|
||||
M_NOWAIT | M_ZERO);
|
||||
mtag = m_tag_locate(m, MTAG_IPFW_RULE, 0, NULL);
|
||||
if (mtag == NULL) {
|
||||
/* this should be normal */
|
||||
mtag = m_tag_alloc(MTAG_IPFW_RULE, 0,
|
||||
sizeof(struct ipfw_rule_ref), M_NOWAIT | M_ZERO);
|
||||
if (mtag == NULL) {
|
||||
error = ENOBUFS;
|
||||
goto cantsend;
|
||||
}
|
||||
dt = (struct divert_tag *)(mtag+1);
|
||||
m_tag_prepend(m, mtag);
|
||||
} else
|
||||
dt = (struct divert_tag *)(mtag+1);
|
||||
}
|
||||
dt = (struct ipfw_rule_ref *)(mtag+1);
|
||||
|
||||
/* Loopback avoidance and state recovery */
|
||||
if (sin) {
|
||||
int i;
|
||||
|
||||
dt->cookie = sin->sin_port;
|
||||
/* set the starting point. We provide a non-zero slot,
|
||||
* but a non_matching chain_id to skip that info and use
|
||||
* the rulenum/rule_id.
|
||||
*/
|
||||
dt->slot = 1; /* dummy, chain_id is invalid */
|
||||
dt->chain_id = 0;
|
||||
dt->rulenum = sin->sin_port+1; /* host format ? */
|
||||
dt->rule_id = 0;
|
||||
/*
|
||||
* Find receive interface with the given name, stuffed
|
||||
* (if it exists) in the sin_zero[] field.
|
||||
@ -388,7 +388,7 @@ div_output(struct socket *so, struct mbuf *m, struct sockaddr_in *sin,
|
||||
struct ip *const ip = mtod(m, struct ip *);
|
||||
struct inpcb *inp;
|
||||
|
||||
dt->info |= IP_FW_DIVERT_OUTPUT_FLAG;
|
||||
dt->info |= IPFW_IS_DIVERT | IPFW_INFO_OUT;
|
||||
INP_INFO_WLOCK(&V_divcbinfo);
|
||||
inp = sotoinpcb(so);
|
||||
INP_RLOCK(inp);
|
||||
@ -454,7 +454,7 @@ div_output(struct socket *so, struct mbuf *m, struct sockaddr_in *sin,
|
||||
m_freem(options);
|
||||
}
|
||||
} else {
|
||||
dt->info |= IP_FW_DIVERT_LOOPBACK_FLAG;
|
||||
dt->info |= IPFW_IS_DIVERT | IPFW_INFO_IN;
|
||||
if (m->m_pkthdr.rcvif == NULL) {
|
||||
/*
|
||||
* No luck with the name, check by IP address.
|
||||
@ -588,7 +588,7 @@ div_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
|
||||
return div_output(so, m, (struct sockaddr_in *)nam, control);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
div_ctlinput(int cmd, struct sockaddr *sa, void *vip)
|
||||
{
|
||||
struct in_addr faddr;
|
||||
@ -801,5 +801,5 @@ static moduledata_t ipdivertmod = {
|
||||
};
|
||||
|
||||
DECLARE_MODULE(ipdivert, ipdivertmod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
|
||||
MODULE_DEPEND(dummynet, ipfw, 2, 2, 2);
|
||||
MODULE_DEPEND(ipdivert, ipfw, 2, 2, 2);
|
||||
MODULE_VERSION(ipdivert, 1);
|
||||
|
@ -36,53 +36,20 @@
|
||||
#define _NETINET_IP_DIVERT_H_
|
||||
|
||||
/*
|
||||
* Sysctl declaration.
|
||||
* divert has no custom kernel-userland API.
|
||||
*
|
||||
* All communication occurs through a sockaddr_in socket where
|
||||
*
|
||||
* kernel-->userland
|
||||
* sin_port = matching rule, host format;
|
||||
* sin_addr = IN: first address of the incoming interface;
|
||||
* OUT: INADDR_ANY
|
||||
* sin_zero = if fits, the interface name (max 7 bytes + NUL)
|
||||
*
|
||||
* userland->kernel
|
||||
* sin_port = restart-rule - 1, host order
|
||||
* (we restart at sin_port + 1)
|
||||
* sin_addr = IN: address of the incoming interface;
|
||||
* OUT: INADDR_ANY
|
||||
*/
|
||||
#ifdef SYSCTL_DECL
|
||||
SYSCTL_DECL(_net_inet_divert);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Divert socket definitions.
|
||||
*/
|
||||
struct divert_tag {
|
||||
u_int32_t info; /* port & flags */
|
||||
u_int16_t cookie; /* ipfw rule number */
|
||||
};
|
||||
|
||||
/*
|
||||
* Return the divert cookie associated with the mbuf; if any.
|
||||
*/
|
||||
static __inline u_int16_t
|
||||
divert_cookie(struct m_tag *mtag)
|
||||
{
|
||||
return ((struct divert_tag *)(mtag+1))->cookie;
|
||||
}
|
||||
static __inline u_int16_t
|
||||
divert_find_cookie(struct mbuf *m)
|
||||
{
|
||||
struct m_tag *mtag = m_tag_find(m, PACKET_TAG_DIVERT, NULL);
|
||||
return mtag ? divert_cookie(mtag) : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the divert info associated with the mbuf; if any.
|
||||
*/
|
||||
static __inline u_int32_t
|
||||
divert_info(struct m_tag *mtag)
|
||||
{
|
||||
return ((struct divert_tag *)(mtag+1))->info;
|
||||
}
|
||||
static __inline u_int32_t
|
||||
divert_find_info(struct mbuf *m)
|
||||
{
|
||||
struct m_tag *mtag = m_tag_find(m, PACKET_TAG_DIVERT, NULL);
|
||||
return mtag ? divert_info(mtag) : 0;
|
||||
}
|
||||
|
||||
typedef void ip_divert_packet_t(struct mbuf *m, int incoming);
|
||||
extern ip_divert_packet_t *ip_divert_ptr;
|
||||
|
||||
extern void div_input(struct mbuf *, int);
|
||||
extern void div_ctlinput(int, struct sockaddr *, void *);
|
||||
#endif /* _NETINET_IP_DIVERT_H_ */
|
||||
|
@ -114,11 +114,7 @@ struct dn_heap {
|
||||
* 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 */
|
||||
struct ipfw_rule_ref rule; /* matching rule */
|
||||
|
||||
/* second part, dummynet specific */
|
||||
int dn_dir; /* action when packet comes out. */
|
||||
|
@ -462,15 +462,10 @@ heap_free(struct dn_heap *h)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Dispose a packet in dummynet. Use an inline functions so if we
|
||||
* Dispose a list of packet. Use an inline functions so if we
|
||||
* need to free extra state associated to a packet, this is a
|
||||
* central point to do it.
|
||||
*/
|
||||
static __inline void *dn_free_pkt(struct mbuf *m)
|
||||
{
|
||||
m_freem(m);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static __inline void dn_free_pkts(struct mbuf *mnext)
|
||||
{
|
||||
@ -478,7 +473,7 @@ static __inline void dn_free_pkts(struct mbuf *mnext)
|
||||
|
||||
while ((m = mnext) != NULL) {
|
||||
mnext = m->m_nextpkt;
|
||||
dn_free_pkt(m);
|
||||
FREE_PKT(m);
|
||||
}
|
||||
}
|
||||
|
||||
@ -968,24 +963,31 @@ dummynet_send(struct mbuf *m)
|
||||
for (; m != NULL; m = n) {
|
||||
struct ifnet *ifp;
|
||||
int dst;
|
||||
struct m_tag *tag;
|
||||
|
||||
n = m->m_nextpkt;
|
||||
m->m_nextpkt = NULL;
|
||||
if (m_tag_first(m) == NULL) {
|
||||
tag = m_tag_first(m);
|
||||
if (tag == NULL) {
|
||||
dst = DIR_DROP;
|
||||
} else {
|
||||
struct dn_pkt_tag *pkt = dn_tag_get(m);
|
||||
/* extract the dummynet info, rename the tag */
|
||||
dst = pkt->dn_dir;
|
||||
ifp = pkt->ifp;
|
||||
/* rename the tag so it carries reinject info */
|
||||
tag->m_tag_cookie = MTAG_IPFW_RULE;
|
||||
tag->m_tag_id = 0;
|
||||
}
|
||||
|
||||
switch (dst) {
|
||||
case DIR_OUT:
|
||||
SET_HOST_IPLEN(mtod(m, struct ip *));
|
||||
ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL);
|
||||
break ;
|
||||
case DIR_IN :
|
||||
/* put header in network format for ip_input() */
|
||||
SET_NET_IPLEN(mtod(m, struct ip *));
|
||||
//SET_NET_IPLEN(mtod(m, struct ip *));
|
||||
netisr_dispatch(NETISR_IP, m);
|
||||
break;
|
||||
#ifdef INET6
|
||||
@ -994,6 +996,7 @@ dummynet_send(struct mbuf *m)
|
||||
break;
|
||||
|
||||
case DIR_OUT | PROTO_IPV6:
|
||||
SET_HOST_IPLEN(mtod(m, struct ip *));
|
||||
ip6_output(m, NULL, NULL, IPV6_FORWARDING, NULL, NULL, NULL);
|
||||
break;
|
||||
#endif
|
||||
@ -1024,12 +1027,12 @@ dummynet_send(struct mbuf *m)
|
||||
|
||||
case DIR_DROP:
|
||||
/* drop the packet after some time */
|
||||
dn_free_pkt(m);
|
||||
FREE_PKT(m);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("dummynet: bad switch %d!\n", dst);
|
||||
dn_free_pkt(m);
|
||||
FREE_PKT(m);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1362,7 +1365,7 @@ dummynet_io(struct mbuf **m0, int dir, struct ip_fw_args *fwa)
|
||||
struct dn_pipe *pipe;
|
||||
uint64_t len = m->m_pkthdr.len;
|
||||
struct dn_flow_queue *q = NULL;
|
||||
int is_pipe = fwa->cookie & 0x8000000 ? 0 : 1;
|
||||
int is_pipe = fwa->rule.info & IPFW_IS_PIPE;
|
||||
|
||||
KASSERT(m->m_nextpkt == NULL,
|
||||
("dummynet_io: mbuf queue passed to dummynet"));
|
||||
@ -1371,16 +1374,13 @@ dummynet_io(struct mbuf **m0, int dir, struct ip_fw_args *fwa)
|
||||
io_pkt++;
|
||||
/*
|
||||
* This is a dummynet rule, so we expect an O_PIPE or O_QUEUE rule.
|
||||
*
|
||||
* XXXGL: probably the pipe->fs and fs->pipe logic here
|
||||
* below can be simplified.
|
||||
*/
|
||||
if (is_pipe) {
|
||||
pipe = locate_pipe(fwa->cookie & 0xffff);
|
||||
pipe = locate_pipe(fwa->rule.info & IPFW_INFO_MASK);
|
||||
if (pipe != NULL)
|
||||
fs = &(pipe->fs);
|
||||
} else
|
||||
fs = locate_flowset(fwa->cookie & 0xffff);
|
||||
fs = locate_flowset(fwa->rule.info & IPFW_INFO_MASK);
|
||||
|
||||
if (fs == NULL)
|
||||
goto dropit; /* This queue/pipe does not exist! */
|
||||
@ -1426,12 +1426,9 @@ dummynet_io(struct mbuf **m0, int dir, struct ip_fw_args *fwa)
|
||||
* Ok, i can handle the pkt now...
|
||||
* Build and enqueue packet + parameters.
|
||||
*/
|
||||
pkt->slot = fwa->slot;
|
||||
pkt->rulenum = fwa->rulenum;
|
||||
pkt->rule_id = fwa->rule_id;
|
||||
pkt->chain_id = fwa->chain_id;
|
||||
pkt->rule = fwa->rule;
|
||||
pkt->rule.info &= IPFW_ONEPASS; /* only keep this info */
|
||||
pkt->dn_dir = dir;
|
||||
|
||||
pkt->ifp = fwa->oif;
|
||||
|
||||
if (q->head == NULL)
|
||||
@ -1562,7 +1559,8 @@ dropit:
|
||||
if (q)
|
||||
q->drops++;
|
||||
DUMMYNET_UNLOCK();
|
||||
*m0 = dn_free_pkt(m);
|
||||
FREE_PKT(m);
|
||||
*m0 = NULL;
|
||||
return ((fs && (fs->flags_fs & DN_NOERROR)) ? 0 : ENOBUFS);
|
||||
}
|
||||
|
||||
|
@ -74,7 +74,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <netinet/ip_icmp.h>
|
||||
#include <netinet/ip_fw.h>
|
||||
#include <netinet/ipfw/ip_fw_private.h>
|
||||
#include <netinet/ip_divert.h>
|
||||
#include <netinet/ip_carp.h>
|
||||
#include <netinet/pim.h>
|
||||
#include <netinet/tcp_var.h>
|
||||
@ -560,7 +559,7 @@ send_reject6(struct ip_fw_args *args, int code, u_int hlen, struct ip6_hdr *ip6)
|
||||
ip6_output(m0, NULL, NULL, 0, NULL, NULL,
|
||||
NULL);
|
||||
}
|
||||
m_freem(m);
|
||||
FREE_PKT(m);
|
||||
} else if (code != ICMP6_UNREACH_RST) { /* Send an ICMPv6 unreach. */
|
||||
#if 0
|
||||
/*
|
||||
@ -576,7 +575,7 @@ send_reject6(struct ip_fw_args *args, int code, u_int hlen, struct ip6_hdr *ip6)
|
||||
#endif
|
||||
icmp6_error(m, ICMP6_DST_UNREACH, code, 0);
|
||||
} else
|
||||
m_freem(m);
|
||||
FREE_PKT(m);
|
||||
|
||||
args->m = NULL;
|
||||
}
|
||||
@ -603,9 +602,7 @@ send_reject(struct ip_fw_args *args, int code, int iplen, struct ip *ip)
|
||||
#endif
|
||||
if (code != ICMP_REJECT_RST) { /* Send an ICMP unreach */
|
||||
/* We need the IP header in host order for icmp_error(). */
|
||||
if (args->eh != NULL) {
|
||||
SET_HOST_IPLEN(ip);
|
||||
}
|
||||
SET_HOST_IPLEN(ip);
|
||||
icmp_error(args->m, ICMP_UNREACH, code, 0L, 0);
|
||||
} else if (args->f_id.proto == IPPROTO_TCP) {
|
||||
struct tcphdr *const tcp =
|
||||
@ -618,9 +615,9 @@ send_reject(struct ip_fw_args *args, int code, int iplen, struct ip *ip)
|
||||
if (m != NULL)
|
||||
ip_output(m, NULL, NULL, 0, NULL, NULL);
|
||||
}
|
||||
m_freem(args->m);
|
||||
FREE_PKT(args->m);
|
||||
} else
|
||||
m_freem(args->m);
|
||||
FREE_PKT(args->m);
|
||||
args->m = NULL;
|
||||
}
|
||||
|
||||
@ -709,16 +706,18 @@ check_uidgid(ipfw_insn_u32 *insn, int proto, struct ifnet *oif,
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function to write the matching rule into args
|
||||
* Helper function to set args with info on the rule after the matching
|
||||
* one. slot is precise, whereas we guess rule_id as they are
|
||||
* assigned sequentially.
|
||||
*/
|
||||
static inline void
|
||||
set_match(struct ip_fw_args *args, int slot,
|
||||
struct ip_fw_chain *chain)
|
||||
{
|
||||
args->chain_id = chain->id;
|
||||
args->slot = slot + 1; /* we use 0 as a marker */
|
||||
args->rule_id = chain->map[slot]->id;
|
||||
args->rulenum = chain->map[slot]->rulenum;
|
||||
args->rule.chain_id = chain->id;
|
||||
args->rule.slot = slot + 1; /* we use 0 as a marker */
|
||||
args->rule.rule_id = 1 + chain->map[slot]->id;
|
||||
args->rule.rulenum = chain->map[slot]->rulenum;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -743,7 +742,7 @@ set_match(struct ip_fw_args *args, int slot,
|
||||
* args->rule Pointer to the last matching rule (in/out)
|
||||
* args->next_hop Socket we are forwarding to (out).
|
||||
* args->f_id Addresses grabbed from the packet (out)
|
||||
* args->cookie a cookie depending on rule action
|
||||
* args->rule.info a cookie depending on rule action
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
@ -753,6 +752,8 @@ set_match(struct ip_fw_args *args, int slot,
|
||||
* IP_FW_TEE tee packet, port in m_tag
|
||||
* IP_FW_DUMMYNET to dummynet, pipe in args->cookie
|
||||
* IP_FW_NETGRAPH into netgraph, cookie args->cookie
|
||||
* args->rule contains the matching rule,
|
||||
* args->rule.info has additional information.
|
||||
*
|
||||
*/
|
||||
int
|
||||
@ -796,14 +797,6 @@ ipfw_chk(struct ip_fw_args *args)
|
||||
struct ucred *ucred_cache = NULL;
|
||||
int ucred_lookup = 0;
|
||||
|
||||
/*
|
||||
* divinput_flags If non-zero, set to the IP_FW_DIVERT_*_FLAG
|
||||
* associated with a packet input on a divert socket. This
|
||||
* will allow to distinguish traffic and its direction when
|
||||
* it originates from a divert socket.
|
||||
*/
|
||||
u_int divinput_flags = 0;
|
||||
|
||||
/*
|
||||
* oif | args->oif If NULL, ipfw_chk has been called on the
|
||||
* inbound path (ether_input, ip_input).
|
||||
@ -862,7 +855,6 @@ ipfw_chk(struct ip_fw_args *args)
|
||||
int dyn_dir = MATCH_UNKNOWN;
|
||||
ipfw_dyn_rule *q = NULL;
|
||||
struct ip_fw_chain *chain = &V_layer3_chain;
|
||||
struct m_tag *mtag;
|
||||
|
||||
/*
|
||||
* We store in ulp a pointer to the upper layer protocol header.
|
||||
@ -1090,16 +1082,8 @@ do { \
|
||||
proto = ip->ip_p;
|
||||
src_ip = ip->ip_src;
|
||||
dst_ip = ip->ip_dst;
|
||||
#ifndef HAVE_NET_IPLEN
|
||||
if (args->eh == NULL) { /* on l3 these are in host format */
|
||||
offset = ip->ip_off & IP_OFFMASK;
|
||||
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);
|
||||
}
|
||||
offset = ntohs(ip->ip_off) & IP_OFFMASK;
|
||||
iplen = ntohs(ip->ip_len);
|
||||
pktlen = iplen < pktlen ? iplen : pktlen;
|
||||
|
||||
if (offset == 0) {
|
||||
@ -1143,44 +1127,20 @@ 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) {
|
||||
if (args->rule.slot) {
|
||||
/*
|
||||
* Packet has already been tagged as a result of a previous
|
||||
* match on rule args->rule aka args->rule_id (PIPE, QUEUE,
|
||||
* REASS, NETGRAPH and similar, never a skipto).
|
||||
* REASS, NETGRAPH, DIVERT/TEE...)
|
||||
* Validate the slot and continue from the next one
|
||||
* if still present, otherwise do a lookup.
|
||||
*/
|
||||
if (V_fw_one_pass) {
|
||||
IPFW_RUNLOCK(chain);
|
||||
return (IP_FW_PASS);
|
||||
}
|
||||
f_pos = (args->chain_id == chain->id) ?
|
||||
args->slot /* already incremented */ :
|
||||
ipfw_find_rule(chain, args->rulenum, args->rule_id+1);
|
||||
f_pos = (args->rule.chain_id == chain->id) ?
|
||||
args->rule.slot :
|
||||
ipfw_find_rule(chain, args->rule.rulenum,
|
||||
args->rule.rule_id);
|
||||
} else {
|
||||
/*
|
||||
* Find the starting rule. It can be either the first
|
||||
* one, or the one after divert_rule if asked so.
|
||||
*/
|
||||
int skipto = mtag ? divert_cookie(mtag) : 0;
|
||||
|
||||
f_pos = 0;
|
||||
if (args->eh == NULL && skipto != 0) {
|
||||
if (skipto >= IPFW_DEFAULT_RULE) {
|
||||
IPFW_RUNLOCK(chain);
|
||||
return (IP_FW_DENY); /* invalid */
|
||||
}
|
||||
f_pos = ipfw_find_rule(chain, skipto+1, 0);
|
||||
}
|
||||
}
|
||||
/* reset divert rule to avoid confusion later */
|
||||
if (mtag) {
|
||||
divinput_flags = divert_info(mtag) &
|
||||
(IP_FW_DIVERT_OUTPUT_FLAG | IP_FW_DIVERT_LOOPBACK_FLAG);
|
||||
m_tag_delete(m, mtag);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1332,10 +1292,15 @@ do { \
|
||||
break;
|
||||
|
||||
case O_DIVERTED:
|
||||
match = (cmd->arg1 & 1 && divinput_flags &
|
||||
IP_FW_DIVERT_LOOPBACK_FLAG) ||
|
||||
(cmd->arg1 & 2 && divinput_flags &
|
||||
IP_FW_DIVERT_OUTPUT_FLAG);
|
||||
{
|
||||
/* For diverted packets, args->rule.info
|
||||
* contains the divert port (in host format)
|
||||
* reason and direction.
|
||||
*/
|
||||
uint32_t i = args->rule.info;
|
||||
match = (i&IPFW_IS_MASK) == IPFW_IS_DIVERT &&
|
||||
cmd->arg1 & ((i & IPFW_INFO_IN) ? 1 : 2);
|
||||
}
|
||||
break;
|
||||
|
||||
case O_PROTO:
|
||||
@ -1755,6 +1720,7 @@ do { \
|
||||
break;
|
||||
|
||||
case O_TAG: {
|
||||
struct m_tag *mtag;
|
||||
uint32_t tag = (cmd->arg1 == IP_FW_TABLEARG) ?
|
||||
tablearg : cmd->arg1;
|
||||
|
||||
@ -1771,12 +1737,13 @@ do { \
|
||||
if (cmd->len & F_NOT) { /* `untag' action */
|
||||
if (mtag != NULL)
|
||||
m_tag_delete(m, mtag);
|
||||
match = 0;
|
||||
} else if (mtag == NULL) {
|
||||
if ((mtag = m_tag_alloc(MTAG_IPFW,
|
||||
tag, 0, M_NOWAIT)) != NULL)
|
||||
m_tag_prepend(m, mtag);
|
||||
match = 1;
|
||||
}
|
||||
match = (cmd->len & F_NOT) ? 0: 1;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1786,6 +1753,7 @@ do { \
|
||||
break;
|
||||
|
||||
case O_TAGGED: {
|
||||
struct m_tag *mtag;
|
||||
uint32_t tag = (cmd->arg1 == IP_FW_TABLEARG) ?
|
||||
tablearg : cmd->arg1;
|
||||
|
||||
@ -1926,10 +1894,12 @@ do { \
|
||||
case O_PIPE:
|
||||
case O_QUEUE:
|
||||
set_match(args, f_pos, chain);
|
||||
args->cookie = (cmd->arg1 == IP_FW_TABLEARG) ?
|
||||
args->rule.info = (cmd->arg1 == IP_FW_TABLEARG) ?
|
||||
tablearg : cmd->arg1;
|
||||
if (cmd->opcode == O_QUEUE)
|
||||
args->cookie |= 0x80000000;
|
||||
if (cmd->opcode == O_PIPE)
|
||||
args->rule.info |= IPFW_IS_PIPE;
|
||||
if (V_fw_one_pass)
|
||||
args->rule.info |= IPFW_ONEPASS;
|
||||
retval = IP_FW_DUMMYNET;
|
||||
l = 0; /* exit inner loop */
|
||||
done = 1; /* exit outer loop */
|
||||
@ -1942,23 +1912,11 @@ do { \
|
||||
/* otherwise this is terminal */
|
||||
l = 0; /* exit inner loop */
|
||||
done = 1; /* exit outer loop */
|
||||
mtag = m_tag_get(PACKET_TAG_DIVERT,
|
||||
sizeof(struct divert_tag),
|
||||
M_NOWAIT);
|
||||
if (mtag == NULL) {
|
||||
retval = IP_FW_DENY;
|
||||
} else {
|
||||
struct divert_tag *dt;
|
||||
dt = (struct divert_tag *)(mtag+1);
|
||||
dt->cookie = f->rulenum;
|
||||
if (cmd->arg1 == IP_FW_TABLEARG)
|
||||
dt->info = tablearg;
|
||||
else
|
||||
dt->info = cmd->arg1;
|
||||
m_tag_prepend(m, mtag);
|
||||
retval = (cmd->opcode == O_DIVERT) ?
|
||||
retval = (cmd->opcode == O_DIVERT) ?
|
||||
IP_FW_DIVERT : IP_FW_TEE;
|
||||
}
|
||||
set_match(args, f_pos, chain);
|
||||
args->rule.info = (cmd->arg1 == IP_FW_TABLEARG) ?
|
||||
tablearg : cmd->arg1;
|
||||
break;
|
||||
|
||||
case O_COUNT:
|
||||
@ -2074,7 +2032,7 @@ do { \
|
||||
case O_NETGRAPH:
|
||||
case O_NGTEE:
|
||||
set_match(args, f_pos, chain);
|
||||
args->cookie = (cmd->arg1 == IP_FW_TABLEARG) ?
|
||||
args->rule.info = (cmd->arg1 == IP_FW_TABLEARG) ?
|
||||
tablearg : cmd->arg1;
|
||||
retval = (cmd->opcode == O_NETGRAPH) ?
|
||||
IP_FW_NETGRAPH : IP_FW_NGTEE;
|
||||
@ -2126,12 +2084,6 @@ do { \
|
||||
f->pcnt++;
|
||||
f->bcnt += pktlen;
|
||||
l = 0; /* in any case exit inner loop */
|
||||
|
||||
#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 */
|
||||
@ -2139,19 +2091,14 @@ do { \
|
||||
break;
|
||||
/*
|
||||
* ip_reass() expects len & off in host
|
||||
* byte order: fix them in case we come
|
||||
* from layer2.
|
||||
* byte order.
|
||||
*/
|
||||
if (args->eh != NULL) {
|
||||
SET_HOST_IPLEN(ip);
|
||||
}
|
||||
SET_HOST_IPLEN(ip);
|
||||
|
||||
args->m = m = ip_reass(m);
|
||||
|
||||
/*
|
||||
* IP header checksum fixup after
|
||||
* reassembly and leave header
|
||||
* in network byte order.
|
||||
* do IP header checksum fixup.
|
||||
*/
|
||||
if (m == NULL) { /* fragment got swallowed */
|
||||
retval = IP_FW_DENY;
|
||||
@ -2160,10 +2107,7 @@ do { \
|
||||
|
||||
ip = mtod(m, struct ip *);
|
||||
hlen = ip->ip_hl << 2;
|
||||
/* revert len. & off to net format if needed */
|
||||
if (args->eh != NULL) {
|
||||
SET_NET_IPLEN(ip);
|
||||
}
|
||||
SET_NET_IPLEN(ip);
|
||||
ip->ip_sum = 0;
|
||||
if (hlen == sizeof(struct ip))
|
||||
ip->ip_sum = in_cksum_hdr(ip);
|
||||
|
@ -917,7 +917,7 @@ ipfw_send_pkt(struct mbuf *replyto, struct ipfw_flow_id *id, u_int32_t seq,
|
||||
#endif
|
||||
default:
|
||||
/* XXX: log me?!? */
|
||||
m_freem(m);
|
||||
FREE_PKT(m);
|
||||
return (NULL);
|
||||
}
|
||||
dir = ((flags & (TH_SYN | TH_RST)) == TH_SYN);
|
||||
@ -1002,11 +1002,7 @@ 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;
|
||||
|
@ -165,16 +165,8 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args,
|
||||
* more info in the header
|
||||
*/
|
||||
mh.mh_data = "DDDDDDSSSSSS\x08\x00";
|
||||
if (args->f_id.addr_type == 4) {
|
||||
/* restore wire format */
|
||||
SET_NET_IPLEN(ip);
|
||||
}
|
||||
}
|
||||
BPF_MTAP(log_if, (struct mbuf *)&mh);
|
||||
if (args->eh == NULL && args->f_id.addr_type == 4) {
|
||||
/* restore host format */
|
||||
SET_HOST_IPLEN(ip);
|
||||
}
|
||||
#endif /* !WITHOUT_BPF */
|
||||
return;
|
||||
}
|
||||
@ -409,23 +401,15 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args,
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
int ip_off, ip_len;
|
||||
#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))
|
||||
int ipoff, iplen;
|
||||
ipoff = ntohs(ip->ip_off);
|
||||
iplen = ntohs(ip->ip_len);
|
||||
if (ipoff & (IP_MF | IP_OFFMASK))
|
||||
snprintf(SNPARGS(fragment, 0),
|
||||
" (frag %d:%d@%d%s)",
|
||||
ntohs(ip->ip_id), ip_len - (ip->ip_hl << 2),
|
||||
ntohs(ip->ip_id), iplen - (ip->ip_hl << 2),
|
||||
offset << 3,
|
||||
(ip_off & IP_MF) ? "+" : "");
|
||||
(ipoff & IP_MF) ? "+" : "");
|
||||
}
|
||||
}
|
||||
if (oif || m->m_pkthdr.rcvif)
|
||||
|
@ -219,9 +219,6 @@ ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m)
|
||||
return (IP_FW_DENY);
|
||||
}
|
||||
ip = mtod(mcl, struct ip *);
|
||||
if (args->eh == NULL) {
|
||||
SET_NET_IPLEN(ip);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX - Libalias checksum offload 'duct tape':
|
||||
@ -330,9 +327,6 @@ ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m)
|
||||
mcl->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
|
||||
}
|
||||
}
|
||||
if (args->eh == NULL) {
|
||||
SET_HOST_IPLEN(ip);
|
||||
}
|
||||
args->m = mcl;
|
||||
return (IP_FW_NAT);
|
||||
}
|
||||
|
@ -59,7 +59,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <netinet/ip_var.h>
|
||||
#include <netinet/ip_fw.h>
|
||||
#include <netinet/ipfw/ip_fw_private.h>
|
||||
#include <netinet/ip_divert.h>
|
||||
#include <netinet/ip_dummynet.h>
|
||||
#include <netgraph/ng_ipfw.h>
|
||||
|
||||
@ -76,13 +75,13 @@ static VNET_DEFINE(int, fw6_enable) = 1;
|
||||
int ipfw_chg_hook(SYSCTL_HANDLER_ARGS);
|
||||
|
||||
/* Divert hooks. */
|
||||
ip_divert_packet_t *ip_divert_ptr = NULL;
|
||||
void (*ip_divert_ptr)(struct mbuf *m, int incoming);
|
||||
|
||||
/* ng_ipfw hooks. */
|
||||
ng_ipfw_input_t *ng_ipfw_input_p = NULL;
|
||||
|
||||
/* Forward declarations. */
|
||||
static void ipfw_divert(struct mbuf **, int, int);
|
||||
static int ipfw_divert(struct mbuf **, int, struct ipfw_rule_ref *, int);
|
||||
|
||||
#ifdef SYSCTL_NODE
|
||||
SYSCTL_DECL(_net_inet_ip_fw);
|
||||
@ -107,52 +106,38 @@ 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;
|
||||
struct m_tag *tag;
|
||||
int ipfw;
|
||||
int ret;
|
||||
#ifdef IPFIREWALL_FORWARD
|
||||
struct m_tag *fwd_tag;
|
||||
#endif
|
||||
|
||||
/* all the processing now uses ip_len in net format */
|
||||
SET_NET_IPLEN(mtod(*m0, struct ip *));
|
||||
|
||||
/* 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 == dir,
|
||||
("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);
|
||||
/*
|
||||
* extract and remove the tag if present. If we are left
|
||||
* with onepass, optimize the outgoing path.
|
||||
*/
|
||||
tag = m_tag_locate(*m0, MTAG_IPFW_RULE, 0, NULL);
|
||||
if (tag != NULL) {
|
||||
args.rule = *((struct ipfw_rule_ref *)(tag+1));
|
||||
m_tag_delete(*m0, tag);
|
||||
if (args.rule.info & IPFW_ONEPASS) {
|
||||
SET_HOST_IPLEN(mtod(*m0, struct ip *));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
args.m = *m0;
|
||||
args.oif = dir == DIR_OUT ? ifp : NULL;
|
||||
args.inp = inp;
|
||||
|
||||
if (V_fw_one_pass == 0 || args.slot == 0) {
|
||||
ipfw = ipfw_chk(&args);
|
||||
*m0 = args.m;
|
||||
} else
|
||||
ipfw = IP_FW_PASS;
|
||||
ipfw = ipfw_chk(&args);
|
||||
*m0 = args.m;
|
||||
|
||||
KASSERT(*m0 != NULL || ipfw == IP_FW_DENY, ("%s: m0 is NULL",
|
||||
__func__));
|
||||
@ -167,6 +152,9 @@ again:
|
||||
#ifndef IPFIREWALL_FORWARD
|
||||
ret = EACCES;
|
||||
#else
|
||||
{
|
||||
struct m_tag *fwd_tag;
|
||||
|
||||
/* 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.
|
||||
@ -188,6 +176,7 @@ again:
|
||||
|
||||
if (in_localip(args.next_hop->sin_addr))
|
||||
(*m0)->m_flags |= M_FASTFWD_OURS;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
@ -222,15 +211,11 @@ again:
|
||||
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 */
|
||||
}
|
||||
ret = ipfw_divert(m0, dir, &args.rule,
|
||||
(ipfw == IP_FW_TEE) ? 1 : 0);
|
||||
/* continue processing for the original packet (tee). */
|
||||
if (*m0)
|
||||
goto again;
|
||||
break;
|
||||
|
||||
case IP_FW_NGTEE:
|
||||
@ -255,14 +240,18 @@ again:
|
||||
|
||||
if (ret != 0) {
|
||||
if (*m0)
|
||||
m_freem(*m0);
|
||||
FREE_PKT(*m0);
|
||||
*m0 = NULL;
|
||||
}
|
||||
if (*m0)
|
||||
SET_HOST_IPLEN(mtod(*m0, struct ip *));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
ipfw_divert(struct mbuf **m0, int incoming, int tee)
|
||||
/* do the divert, return 1 on error 0 on success */
|
||||
static int
|
||||
ipfw_divert(struct mbuf **m0, int incoming, struct ipfw_rule_ref *rule,
|
||||
int tee)
|
||||
{
|
||||
/*
|
||||
* ipfw_chk() has already tagged the packet with the divert tag.
|
||||
@ -271,6 +260,7 @@ ipfw_divert(struct mbuf **m0, int incoming, int tee)
|
||||
*/
|
||||
struct mbuf *clone;
|
||||
struct ip *ip;
|
||||
struct m_tag *tag;
|
||||
|
||||
/* Cloning needed for tee? */
|
||||
if (tee == 0) {
|
||||
@ -282,7 +272,7 @@ ipfw_divert(struct mbuf **m0, int incoming, int tee)
|
||||
* chain and continue with the tee-ed packet.
|
||||
*/
|
||||
if (clone == NULL)
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -294,13 +284,14 @@ ipfw_divert(struct mbuf **m0, int incoming, int tee)
|
||||
* we can do it before a 'tee'.
|
||||
*/
|
||||
ip = mtod(clone, struct ip *);
|
||||
if (!tee && ip->ip_off & (IP_MF | IP_OFFMASK)) {
|
||||
if (!tee && ntohs(ip->ip_off) & (IP_MF | IP_OFFMASK)) {
|
||||
int hlen;
|
||||
struct mbuf *reass;
|
||||
|
||||
SET_HOST_IPLEN(ip); /* ip_reass wants host order */
|
||||
reass = ip_reass(clone); /* Reassemble packet. */
|
||||
if (reass == NULL)
|
||||
return;
|
||||
return 0; /* not an error */
|
||||
/* if reass = NULL then it was consumed by ip_reass */
|
||||
/*
|
||||
* IP header checksum fixup after reassembly and leave header
|
||||
@ -315,13 +306,20 @@ ipfw_divert(struct mbuf **m0, int incoming, int tee)
|
||||
else
|
||||
ip->ip_sum = in_cksum(reass, hlen);
|
||||
clone = reass;
|
||||
} else {
|
||||
/* Convert header to network byte order. */
|
||||
SET_NET_IPLEN(ip);
|
||||
}
|
||||
/* attach a tag to the packet with the reinject info */
|
||||
tag = m_tag_alloc(MTAG_IPFW_RULE, 0,
|
||||
sizeof(struct ipfw_rule_ref), M_NOWAIT);
|
||||
if (tag == NULL) {
|
||||
FREE_PKT(clone);
|
||||
return 1;
|
||||
}
|
||||
*((struct ipfw_rule_ref *)(tag+1)) = *rule;
|
||||
m_tag_prepend(clone, tag);
|
||||
|
||||
/* Do the dirty job... */
|
||||
ip_divert_ptr(clone, incoming);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -330,17 +328,14 @@ ipfw_divert(struct mbuf **m0, int incoming, int tee)
|
||||
static int
|
||||
ipfw_hook(int onoff, int pf)
|
||||
{
|
||||
const int arg = PFIL_IN | PFIL_OUT | PFIL_WAITOK;
|
||||
struct pfil_head *pfh;
|
||||
|
||||
pfh = pfil_head_get(PFIL_TYPE_AF, pf);
|
||||
if (pfh == NULL)
|
||||
return ENOENT;
|
||||
|
||||
if (onoff)
|
||||
(void)pfil_add_hook(ipfw_check_hook, NULL, arg, pfh);
|
||||
else
|
||||
(void)pfil_remove_hook(ipfw_check_hook, NULL, arg, pfh);
|
||||
(void) (onoff ? pfil_add_hook : pfil_remove_hook)
|
||||
(ipfw_check_hook, NULL, PFIL_IN | PFIL_OUT | PFIL_WAITOK, pfh);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -36,6 +36,7 @@
|
||||
#ifdef _KERNEL
|
||||
|
||||
#define MTAG_IPFW 1148380143 /* IPFW-tagged cookie */
|
||||
#define MTAG_IPFW_RULE 1262273568 /* rule reference */
|
||||
|
||||
/* Return values from ipfw_chk() */
|
||||
enum {
|
||||
@ -50,10 +51,6 @@ enum {
|
||||
IP_FW_REASS,
|
||||
};
|
||||
|
||||
/* flags for divert mtag */
|
||||
#define IP_FW_DIVERT_LOOPBACK_FLAG 0x00080000
|
||||
#define IP_FW_DIVERT_OUTPUT_FLAG 0x00100000
|
||||
|
||||
/*
|
||||
* Structure for collecting parameters to dummynet for ip6_output forwarding
|
||||
*/
|
||||
@ -69,6 +66,39 @@ struct _ip6dn_args {
|
||||
struct route_in6 ro_pmtu_or;
|
||||
};
|
||||
|
||||
/*
|
||||
* Reference to an ipfw rule that can be carried outside critical sections.
|
||||
* A rule is identified by rulenum:rule_id which is ordered.
|
||||
* In version chain_id the rule can be found in slot 'slot', so
|
||||
* we don't need a lookup if chain_id == chain->id.
|
||||
*
|
||||
* On exit from the firewall this structure refers to the rule after
|
||||
* the matching one (slot points to the new rule; rulenum:rule_id-1
|
||||
* is the matching rule), and additional info (e.g. info often contains
|
||||
* the insn argument or tablearg in the low 16 bits, in host format).
|
||||
* On entry, the structure is valid if slot>0, and refers to the starting
|
||||
* rules. 'info' contains the reason for reinject, e.g. divert port,
|
||||
* divert direction, and so on.
|
||||
*/
|
||||
struct ipfw_rule_ref {
|
||||
uint32_t slot; /* slot for matching rule */
|
||||
uint32_t rulenum; /* matching rule number */
|
||||
uint32_t rule_id; /* matching rule id */
|
||||
uint32_t chain_id; /* ruleset id */
|
||||
uint32_t info; /* see below */
|
||||
};
|
||||
|
||||
enum {
|
||||
IPFW_INFO_MASK = 0x0000ffff,
|
||||
IPFW_INFO_OUT = 0x00000000, /* outgoing, just for convenience */
|
||||
IPFW_INFO_IN = 0x80000000, /* incoming, overloads dir */
|
||||
IPFW_ONEPASS = 0x40000000, /* One-pass, do not reinject */
|
||||
IPFW_IS_MASK = 0x30000000, /* which source ? */
|
||||
IPFW_IS_DIVERT = 0x20000000,
|
||||
IPFW_IS_DUMMYNET =0x10000000,
|
||||
IPFW_IS_PIPE = 0x08000000, /* pip1=1, queue = 0 */
|
||||
};
|
||||
|
||||
/*
|
||||
* Arguments for calling ipfw_chk() and dummynet_io(). We put them
|
||||
* all into a structure because this way it is easier and more
|
||||
@ -79,19 +109,19 @@ struct ip_fw_args {
|
||||
struct ifnet *oif; /* output interface */
|
||||
struct sockaddr_in *next_hop; /* forward address */
|
||||
|
||||
/* chain_id validates 'slot', the location of the pointer to
|
||||
* a matching rule.
|
||||
* If invalid, we can lookup the rule using rule_id and rulenum
|
||||
/*
|
||||
* On return, it points to the matching rule.
|
||||
* On entry, rule.slot > 0 means the info is valid and
|
||||
* contains the the starting rule for an ipfw search.
|
||||
* If chain_id == chain->id && slot >0 then jump to that slot.
|
||||
* Otherwise, we locate the first rule >= rulenum:rule_id
|
||||
*/
|
||||
uint32_t slot; /* slot for matching rule */
|
||||
uint32_t rulenum; /* matching rule number */
|
||||
uint32_t rule_id; /* matching rule id */
|
||||
uint32_t chain_id; /* ruleset id */
|
||||
struct ipfw_rule_ref rule; /* match/restart info */
|
||||
|
||||
struct ether_header *eh; /* for bridged packets */
|
||||
|
||||
struct ipfw_flow_id f_id; /* grabbed from IP header */
|
||||
uint32_t cookie; /* a cookie depending on rule action */
|
||||
//uint32_t cookie; /* a cookie depending on rule action */
|
||||
struct inpcb *inp;
|
||||
|
||||
struct _ip6dn_args dummypar; /* dummynet->ip6_output */
|
||||
@ -122,6 +152,9 @@ enum {
|
||||
/* PROTO_OLDBDG = 0x14, unused, old bridge */
|
||||
};
|
||||
|
||||
/* wrapper for freeing a packet, in case we need to do more work */
|
||||
#define FREE_PKT(m) m_freem(m)
|
||||
|
||||
/*
|
||||
* Function definitions.
|
||||
*/
|
||||
@ -256,6 +289,9 @@ int ipfw_del_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
|
||||
int ipfw_count_table(struct ip_fw_chain *ch, uint32_t tbl, uint32_t *cnt);
|
||||
int ipfw_dump_table(struct ip_fw_chain *ch, ipfw_table *tbl);
|
||||
|
||||
/* hooks for divert */
|
||||
extern void (*ip_divert_ptr)(struct mbuf *m, int incoming);
|
||||
|
||||
/* In ip_fw_nat.c */
|
||||
|
||||
extern struct cfg_nat *(*lookup_nat_ptr)(struct nat_list *, int);
|
||||
@ -277,18 +313,6 @@ 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))
|
||||
|
||||
|
||||
|
@ -65,7 +65,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip_fw.h>
|
||||
#include <netinet/ipfw/ip_fw_private.h>
|
||||
#include <netinet/ip_divert.h>
|
||||
|
||||
#ifdef MAC
|
||||
#include <security/mac/mac_framework.h>
|
||||
@ -304,6 +303,8 @@ del_entry(struct ip_fw_chain *chain, u_int32_t arg)
|
||||
n++;
|
||||
}
|
||||
}
|
||||
if (n == 0 && arg == 0)
|
||||
break; /* special case, flush on empty ruleset */
|
||||
/* allocate the map, if needed */
|
||||
if (n > 0)
|
||||
map = get_map(chain, -n, 1 /* locked */);
|
||||
|
Loading…
x
Reference in New Issue
Block a user