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