svn commit: r201516 - in user/luigi/ipfw3-head/sys/netinet: . ipfw
Luigi Rizzo
luigi at FreeBSD.org
Mon Jan 4 16:03:26 UTC 2010
Author: luigi
Date: Mon Jan 4 16:03:26 2010
New Revision: 201516
URL: http://svn.freebsd.org/changeset/base/201516
Log:
The main purpose of this commit is to fix 'divert', 'diverted' and
operation with one_pass=0 which was not completed in the previous
commits (in this branch).
In detail:
=== ip_fw_private.h ===
+ introduce enum constants to define the input and output info in
struct ipfw_rule_ref, so the same format can be used by different
clients.
+ remember to rename the file, as it exports kernel APIs,
not private stuff;
=== ip_fw_pfil.c ===
+ put the conversion of ip+len and ip_off in the right place
(was not correct for reinjected packets);
+ optimize the path for net.inet.ip.fw.onepass=1
=== ip_fw2.c ===
+ complete the implementation of 'diverted'
+ localize a variable;
=== ip_divert.c ===
+ use MTAG_IPFW_RULE tags for divert;
+ extract the rule and divert port directly from the tag;
+ store the return info in the 'info' field;
Modified:
user/luigi/ipfw3-head/sys/netinet/ip_divert.c
user/luigi/ipfw3-head/sys/netinet/ip_divert.h
user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c
user/luigi/ipfw3-head/sys/netinet/ipfw/ip_fw2.c
user/luigi/ipfw3-head/sys/netinet/ipfw/ip_fw_pfil.c
user/luigi/ipfw3-head/sys/netinet/ipfw/ip_fw_private.h
Modified: user/luigi/ipfw3-head/sys/netinet/ip_divert.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ip_divert.c Mon Jan 4 15:58:36 2010 (r201515)
+++ user/luigi/ipfw3-head/sys/netinet/ip_divert.c Mon Jan 4 16:03:26 2010 (r201516)
@@ -218,7 +218,7 @@ divert_packet(struct mbuf *m, int incomi
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) {
m_freem(m);
return;
@@ -244,14 +244,15 @@ divert_packet(struct mbuf *m, int incomi
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;
@@ -299,7 +300,7 @@ divert_packet(struct mbuf *m, int incomi
/* 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? */
@@ -395,7 +396,7 @@ div_output(struct socket *so, struct mbu
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);
@@ -461,7 +462,7 @@ div_output(struct socket *so, struct mbu
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.
Modified: user/luigi/ipfw3-head/sys/netinet/ip_divert.h
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ip_divert.h Mon Jan 4 15:58:36 2010 (r201515)
+++ user/luigi/ipfw3-head/sys/netinet/ip_divert.h Mon Jan 4 16:03:26 2010 (r201516)
@@ -55,15 +55,6 @@ divert_cookie(struct m_tag *mtag)
return ((struct ipfw_rule_ref *)(mtag+1))->rulenum;
}
-/*
- * Return the divert info associated with the mbuf; if any.
- */
-static __inline u_int32_t
-divert_info(struct m_tag *mtag)
-{
- return ((struct ipfw_rule_ref *)(mtag+1))->info;
-}
-
typedef void ip_divert_packet_t(struct mbuf *m, int incoming);
extern ip_divert_packet_t *ip_divert_ptr;
Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c Mon Jan 4 15:58:36 2010 (r201515)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c Mon Jan 4 16:03:26 2010 (r201516)
@@ -1370,7 +1370,7 @@ dummynet_io(struct mbuf **m0, int dir, s
struct dn_pipe *pipe;
uint64_t len = m->m_pkthdr.len;
struct dn_flow_queue *q = NULL;
- int is_pipe = fwa->rule.info & 0x8000000 ? 0 : 1;
+ int is_pipe = fwa->rule.info & IPFW_IS_PIPE;
KASSERT(m->m_nextpkt == NULL,
("dummynet_io: mbuf queue passed to dummynet"));
@@ -1379,16 +1379,13 @@ dummynet_io(struct mbuf **m0, int dir, s
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->rule.info & 0xffff);
+ pipe = locate_pipe(fwa->rule.info & IPFW_INFO_MASK);
if (pipe != NULL)
fs = &(pipe->fs);
} else
- fs = locate_flowset(fwa->rule.info & 0xffff);
+ fs = locate_flowset(fwa->rule.info & IPFW_INFO_MASK);
if (fs == NULL)
goto dropit; /* This queue/pipe does not exist! */
@@ -1435,6 +1432,7 @@ dummynet_io(struct mbuf **m0, int dir, s
* Build and enqueue packet + parameters.
*/
pkt->rule = fwa->rule;
+ pkt->rule.info &= IPFW_ONEPASS; /* only keep this info */
pkt->dn_dir = dir;
pkt->ifp = fwa->oif;
Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_fw2.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_fw2.c Mon Jan 4 15:58:36 2010 (r201515)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_fw2.c Mon Jan 4 16:03:26 2010 (r201516)
@@ -799,14 +799,6 @@ ipfw_chk(struct ip_fw_args *args)
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).
* If non-NULL, ipfw_chk has been called on the outbound path
@@ -864,7 +856,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.
@@ -1152,10 +1143,6 @@ do { \
} else {
f_pos = 0;
}
-#if 0 // XXX to be fixed
- divinput_flags = divert_info(mtag) &
- (IP_FW_DIVERT_OUTPUT_FLAG | IP_FW_DIVERT_LOOPBACK_FLAG);
-#endif
/*
* Now scan the rules, and parse microinstructions for each rule.
@@ -1306,10 +1293,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:
@@ -1729,6 +1721,7 @@ do { \
break;
case O_TAG: {
+ struct m_tag *mtag;
uint32_t tag = (cmd->arg1 == IP_FW_TABLEARG) ?
tablearg : cmd->arg1;
@@ -1761,6 +1754,7 @@ do { \
break;
case O_TAGGED: {
+ struct m_tag *mtag;
uint32_t tag = (cmd->arg1 == IP_FW_TABLEARG) ?
tablearg : cmd->arg1;
@@ -1903,8 +1897,10 @@ do { \
set_match(args, f_pos, chain);
args->rule.info = (cmd->arg1 == IP_FW_TABLEARG) ?
tablearg : cmd->arg1;
- if (cmd->opcode == O_QUEUE)
- args->rule.info |= 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 */
@@ -1917,6 +1913,8 @@ do { \
/* otherwise this is terminal */
l = 0; /* exit inner loop */
done = 1; /* exit outer loop */
+ 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;
Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_fw_pfil.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_fw_pfil.c Mon Jan 4 15:58:36 2010 (r201515)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_fw_pfil.c Mon Jan 4 16:03:26 2010 (r201516)
@@ -110,33 +110,35 @@ ipfw_check_hook(void *arg, struct mbuf *
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));
again:
+ /*
+ * 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;
- /* all the processing now uses ip_len in net format */
- SET_NET_IPLEN(mtod(*m0, struct ip *));
-
- if (V_fw_one_pass == 0 || args.rule.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__));
@@ -151,6 +153,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.
@@ -172,6 +177,7 @@ again:
if (in_localip(args.next_hop->sin_addr))
(*m0)->m_flags |= M_FASTFWD_OURS;
+ }
#endif
break;
Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_fw_private.h
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_fw_private.h Mon Jan 4 15:58:36 2010 (r201515)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_fw_private.h Mon Jan 4 16:03:26 2010 (r201516)
@@ -51,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
*/
@@ -75,13 +71,32 @@ struct _ip6dn_args {
* 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; /* reason for reinject */
+ 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 */
};
/*
More information about the svn-src-user
mailing list