Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 4 Dec 2018 16:12:43 +0000 (UTC)
From:      "Andrey V. Elsukov" <ae@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r341472 - in head: sbin/ipfw sys/netinet sys/netpfil/ipfw
Message-ID:  <201812041612.wB4GCh78010128@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ae
Date: Tue Dec  4 16:12:43 2018
New Revision: 341472
URL: https://svnweb.freebsd.org/changeset/base/341472

Log:
  Add ability to request listing and deleting only for dynamic states.
  
  This can be useful, when net.inet.ip.fw.dyn_keep_states is enabled, but
  after rules reloading some state must be deleted. Added new flag '-D'
  for such purpose.
  
  Retire '-e' flag, since there can not be expired states in the meaning
  that this flag historically had.
  
  Also add "verbose" mode for listing of dynamic states, it can be enabled
  with '-v' flag and adds additional information to states list. This can
  be useful for debugging.
  
  Obtained from:	Yandex LLC
  MFC after:	2 months
  Sponsored by:	Yandex LLC

Modified:
  head/sbin/ipfw/ipfw.8
  head/sbin/ipfw/ipfw2.c
  head/sbin/ipfw/ipfw2.h
  head/sbin/ipfw/main.c
  head/sys/netinet/ip_fw.h
  head/sys/netpfil/ipfw/ip_fw_dynamic.c
  head/sys/netpfil/ipfw/ip_fw_sockopt.c

Modified: head/sbin/ipfw/ipfw.8
==============================================================================
--- head/sbin/ipfw/ipfw.8	Tue Dec  4 16:01:25 2018	(r341471)
+++ head/sbin/ipfw/ipfw.8	Tue Dec  4 16:12:43 2018	(r341472)
@@ -1,7 +1,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd November 13, 2018
+.Dd December 4, 2018
 .Dt IPFW 8
 .Os
 .Sh NAME
@@ -310,10 +310,9 @@ i.e., omitting the "ip from any to any" string
 when this does not carry any additional information.
 .It Fl d
 When listing, show dynamic rules in addition to static ones.
-.It Fl e
-When listing and
-.Fl d
-is specified, also show expired dynamic rules.
+.It Fl D
+When listing, show only dynamic states.
+When deleting, delete only dynamic states.
 .It Fl f
 Run without prompting for confirmation for commands that can cause problems if misused,
 i.e.,

Modified: head/sbin/ipfw/ipfw2.c
==============================================================================
--- head/sbin/ipfw/ipfw2.c	Tue Dec  4 16:01:25 2018	(r341471)
+++ head/sbin/ipfw/ipfw2.c	Tue Dec  4 16:12:43 2018	(r341472)
@@ -2247,10 +2247,9 @@ show_dyn_state(struct cmdline_opts *co, struct format_
 	uint16_t rulenum;
 	char buf[INET6_ADDRSTRLEN];
 
-	if (!co->do_expired) {
-		if (!d->expire && !(d->dyn_type == O_LIMIT_PARENT))
-			return;
-	}
+	if (d->expire == 0 && d->dyn_type != O_LIMIT_PARENT)
+		return;
+
 	bcopy(&d->rule, &rulenum, sizeof(rulenum));
 	bprintf(bp, "%05d", rulenum);
 	if (fo->pcwidth > 0 || fo->bcwidth > 0) {
@@ -2292,6 +2291,33 @@ show_dyn_state(struct cmdline_opts *co, struct format_
 	if (d->kidx != 0)
 		bprintf(bp, " :%s", object_search_ctlv(fo->tstate,
 		    d->kidx, IPFW_TLV_STATE_NAME));
+
+#define	BOTH_SYN	(TH_SYN | (TH_SYN << 8))
+#define	BOTH_FIN	(TH_FIN | (TH_FIN << 8))
+	if (co->verbose) {
+		bprintf(bp, " state 0x%08x%s", d->state,
+		    d->state ? " ": ",");
+		if (d->state & IPFW_DYN_ORPHANED)
+			bprintf(bp, "ORPHANED,");
+		if ((d->state & BOTH_SYN) == BOTH_SYN)
+			bprintf(bp, "BOTH_SYN,");
+		else {
+			if (d->state & TH_SYN)
+				bprintf(bp, "F_SYN,");
+			if (d->state & (TH_SYN << 8))
+				bprintf(bp, "R_SYN,");
+		}
+		if ((d->state & BOTH_FIN) == BOTH_FIN)
+			bprintf(bp, "BOTH_FIN,");
+		else {
+			if (d->state & TH_FIN)
+				bprintf(bp, "F_FIN,");
+			if (d->state & (TH_FIN << 8))
+				bprintf(bp, "R_FIN,");
+		}
+		bprintf(bp, " f_ack 0x%x, r_ack 0x%x", d->ack_fwd,
+		    d->ack_rev);
+	}
 }
 
 static int
@@ -2695,7 +2721,8 @@ ipfw_list(int ac, char *av[], int show_counters)
 	cfg = NULL;
 	sfo.show_counters = show_counters;
 	sfo.show_time = co.do_time;
-	sfo.flags = IPFW_CFG_GET_STATIC;
+	if (co.do_dynamic != 2)
+		sfo.flags |= IPFW_CFG_GET_STATIC;
 	if (co.do_dynamic != 0)
 		sfo.flags |= IPFW_CFG_GET_STATES;
 	if ((sfo.show_counters | sfo.show_time) != 0)
@@ -2740,17 +2767,15 @@ ipfw_show_config(struct cmdline_opts *co, struct forma
 	fo->set_mask = cfg->set_mask;
 
 	ctlv = (ipfw_obj_ctlv *)(cfg + 1);
+	if (ctlv->head.type == IPFW_TLV_TBLNAME_LIST) {
+		object_sort_ctlv(ctlv);
+		fo->tstate = ctlv;
+		readsz += ctlv->head.length;
+		ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + ctlv->head.length);
+	}
 
 	if (cfg->flags & IPFW_CFG_GET_STATIC) {
 		/* We've requested static rules */
-		if (ctlv->head.type == IPFW_TLV_TBLNAME_LIST) {
-			object_sort_ctlv(ctlv);
-			fo->tstate = ctlv;
-			readsz += ctlv->head.length;
-			ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv +
-			    ctlv->head.length);
-		}
-
 		if (ctlv->head.type == IPFW_TLV_RULE_LIST) {
 			rbase = (ipfw_obj_tlv *)(ctlv + 1);
 			rcnt = ctlv->count;
@@ -2777,10 +2802,12 @@ ipfw_show_config(struct cmdline_opts *co, struct forma
 	if (ac == 0) {
 		fo->first = 0;
 		fo->last = IPFW_DEFAULT_RULE;
-		list_static_range(co, fo, &bp, rbase, rcnt);
+		if (cfg->flags & IPFW_CFG_GET_STATIC)
+			list_static_range(co, fo, &bp, rbase, rcnt);
 
 		if (co->do_dynamic && dynsz > 0) {
-			printf("## Dynamic rules (%d %zu):\n", fo->dcnt, dynsz);
+			printf("## Dynamic rules (%d %zu):\n", fo->dcnt,
+			    dynsz);
 			list_dyn_range(co, fo, &bp, dynbase, dynsz);
 		}
 
@@ -2800,6 +2827,9 @@ ipfw_show_config(struct cmdline_opts *co, struct forma
 			continue;
 		}
 
+		if ((cfg->flags & IPFW_CFG_GET_STATIC) == 0)
+			continue;
+
 		if (list_static_range(co, fo, &bp, rbase, rcnt) == 0) {
 			/* give precedence to other error(s) */
 			if (exitval == EX_OK)
@@ -3313,6 +3343,8 @@ ipfw_delete(char *av[])
 					rt.flags |= IPFW_RCFLAG_SET;
 				}
 			}
+			if (co.do_dynamic == 2)
+				rt.flags |= IPFW_RCFLAG_DYNAMIC;
 			i = do_range_cmd(IP_FW_XDEL, &rt);
 			if (i != 0) {
 				exitval = EX_UNAVAILABLE;
@@ -3320,7 +3352,8 @@ ipfw_delete(char *av[])
 					continue;
 				warn("rule %u: setsockopt(IP_FW_XDEL)",
 				    rt.start_rule);
-			} else if (rt.new_set == 0 && do_set == 0) {
+			} else if (rt.new_set == 0 && do_set == 0 &&
+			    co.do_dynamic != 2) {
 				exitval = EX_UNAVAILABLE;
 				if (co.do_quiet)
 					continue;

Modified: head/sbin/ipfw/ipfw2.h
==============================================================================
--- head/sbin/ipfw/ipfw2.h	Tue Dec  4 16:01:25 2018	(r341471)
+++ head/sbin/ipfw/ipfw2.h	Tue Dec  4 16:12:43 2018	(r341472)
@@ -37,8 +37,6 @@ struct cmdline_opts {
 	int	do_quiet;	/* Be quiet in add and flush */
 	int	do_pipe;	/* this cmd refers to a pipe/queue/sched */
 	int	do_nat; 	/* this cmd refers to a nat config */
-	int	do_dynamic;	/* display dynamic rules */
-	int	do_expired;	/* display expired dynamic rules */
 	int	do_compact;	/* show rules in compact mode */
 	int	do_force;	/* do not ask for confirmation */
 	int	show_sets;	/* display the set each rule belongs to */
@@ -48,6 +46,8 @@ struct cmdline_opts {
 
 	/* The options below can have multiple values. */
 
+	int	do_dynamic;	/* 1 - display dynamic rules */
+				/* 2 - display/delete only dynamic rules */
 	int	do_sort;	/* field to sort results (0 = no) */
 		/* valid fields are 1 and above */
 

Modified: head/sbin/ipfw/main.c
==============================================================================
--- head/sbin/ipfw/main.c	Tue Dec  4 16:01:25 2018	(r341471)
+++ head/sbin/ipfw/main.c	Tue Dec  4 16:12:43 2018	(r341472)
@@ -262,7 +262,7 @@ ipfw_main(int oldac, char **oldav)
 	save_av = av;
 
 	optind = optreset = 1;	/* restart getopt() */
-	while ((ch = getopt(ac, av, "abcdefhinNp:qs:STtv")) != -1)
+	while ((ch = getopt(ac, av, "abcdDefhinNp:qs:STtv")) != -1)
 		switch (ch) {
 		case 'a':
 			do_acct = 1;
@@ -281,8 +281,12 @@ ipfw_main(int oldac, char **oldav)
 			co.do_dynamic = 1;
 			break;
 
+		case 'D':
+			co.do_dynamic = 2;
+			break;
+
 		case 'e':
-			co.do_expired = 1;
+			/* nop for compatibility */
 			break;
 
 		case 'f':

Modified: head/sys/netinet/ip_fw.h
==============================================================================
--- head/sys/netinet/ip_fw.h	Tue Dec  4 16:01:25 2018	(r341471)
+++ head/sys/netinet/ip_fw.h	Tue Dec  4 16:12:43 2018	(r341472)
@@ -708,6 +708,7 @@ struct _ipfw_dyn_rule {
 	u_int32_t	state;		/* state of this rule (typically a
 					 * combination of TCP flags)
 					 */
+#define	IPFW_DYN_ORPHANED	0x40000	/* state's parent rule was deleted */
 	u_int32_t	ack_fwd;	/* most recent ACKs in forward	*/
 	u_int32_t	ack_rev;	/* and reverse directions (used	*/
 					/* to generate keepalives)	*/
@@ -938,9 +939,10 @@ typedef struct _ipfw_range_tlv {
 #define	IPFW_RCFLAG_RANGE	0x01	/* rule range is set		*/
 #define	IPFW_RCFLAG_ALL		0x02	/* match ALL rules		*/
 #define	IPFW_RCFLAG_SET		0x04	/* match rules in given set	*/
+#define	IPFW_RCFLAG_DYNAMIC	0x08	/* match only dynamic states	*/
 /* User-settable flags */
 #define	IPFW_RCFLAG_USER	(IPFW_RCFLAG_RANGE | IPFW_RCFLAG_ALL | \
-	IPFW_RCFLAG_SET)
+	IPFW_RCFLAG_SET | IPFW_RCFLAG_DYNAMIC)
 /* Internally used flags */
 #define	IPFW_RCFLAG_DEFAULT	0x0100	/* Do not skip defaul rule	*/
 

Modified: head/sys/netpfil/ipfw/ip_fw_dynamic.c
==============================================================================
--- head/sys/netpfil/ipfw/ip_fw_dynamic.c	Tue Dec  4 16:01:25 2018	(r341471)
+++ head/sys/netpfil/ipfw/ip_fw_dynamic.c	Tue Dec  4 16:12:43 2018	(r341472)
@@ -2110,7 +2110,11 @@ dyn_free_states(struct ip_fw_chain *chain)
 }
 
 /*
- * Returns 1 when state is matched by specified range, otherwise returns 0.
+ * Returns:
+ * 0 when state is not matched by specified range;
+ * 1 when state is matched by specified range;
+ * 2 when state is matched by specified range and requested deletion of
+ *   dynamic states.
  */
 static int
 dyn_match_range(uint16_t rulenum, uint8_t set, const ipfw_range_tlv *rt)
@@ -2118,13 +2122,18 @@ dyn_match_range(uint16_t rulenum, uint8_t set, const i
 
 	MPASS(rt != NULL);
 	/* flush all states */
-	if (rt->flags & IPFW_RCFLAG_ALL)
+	if (rt->flags & IPFW_RCFLAG_ALL) {
+		if (rt->flags & IPFW_RCFLAG_DYNAMIC)
+			return (2); /* forced */
 		return (1);
+	}
 	if ((rt->flags & IPFW_RCFLAG_SET) != 0 && set != rt->set)
 		return (0);
 	if ((rt->flags & IPFW_RCFLAG_RANGE) != 0 &&
 	    (rulenum < rt->start_rule || rulenum > rt->end_rule))
 		return (0);
+	if (rt->flags & IPFW_RCFLAG_DYNAMIC)
+		return (2);
 	return (1);
 }
 
@@ -2194,7 +2203,7 @@ dyn_match_ipv4_state(struct ip_fw_chain *ch, struct dy
 		    s->limit->set, rt));
 
 	ret = dyn_match_range(s->data->rulenum, s->data->set, rt);
-	if (ret == 0 || V_dyn_keep_states == 0)
+	if (ret == 0 || V_dyn_keep_states == 0 || ret > 1)
 		return (ret);
 
 	rule = s->data->parent;
@@ -2217,7 +2226,7 @@ dyn_match_ipv6_state(struct ip_fw_chain *ch, struct dy
 		    s->limit->set, rt));
 
 	ret = dyn_match_range(s->data->rulenum, s->data->set, rt);
-	if (ret == 0 || V_dyn_keep_states == 0)
+	if (ret == 0 || V_dyn_keep_states == 0 || ret > 1)
 		return (ret);
 
 	rule = s->data->parent;
@@ -2939,9 +2948,12 @@ dyn_export_data(const struct dyn_data *data, uint16_t 
 	memcpy((char *)&dst->rule + sizeof(data->rulenum), &data->set,
 	    sizeof(data->set));
 
+	dst->state = data->state;
+	if (data->flags & DYN_REFERENCED)
+		dst->state |= IPFW_DYN_ORPHANED;
+
 	/* unused fields */
 	dst->parent = NULL;
-	dst->state = data->state;
 	dst->ack_fwd = data->ack_fwd;
 	dst->ack_rev = data->ack_rev;
 	dst->count = 0;

Modified: head/sys/netpfil/ipfw/ip_fw_sockopt.c
==============================================================================
--- head/sys/netpfil/ipfw/ip_fw_sockopt.c	Tue Dec  4 16:01:25 2018	(r341471)
+++ head/sys/netpfil/ipfw/ip_fw_sockopt.c	Tue Dec  4 16:12:43 2018	(r341472)
@@ -1033,6 +1033,16 @@ delete_range(struct ip_fw_chain *chain, ipfw_range_tlv
 		end = ipfw_find_rule(chain, rt->end_rule, UINT32_MAX);
 	}
 
+	if (rt->flags & IPFW_RCFLAG_DYNAMIC) {
+		/*
+		 * Requested deleting only for dynamic states.
+		 */
+		*ndel = 0;
+		ipfw_expire_dyn_states(chain, rt);
+		IPFW_UH_WUNLOCK(chain);
+		return (0);
+	}
+
 	/* Allocate new map of the same size */
 	map = get_map(chain, 0, 1 /* locked */);
 	if (map == NULL) {
@@ -2402,7 +2412,6 @@ dump_config(struct ip_fw_chain *chain, ip_fw3_opheader
 		da.bmask = bmask = malloc(
 		    sizeof(uint32_t) * IPFW_TABLES_MAX * 2 / 32, M_TEMP,
 		    M_WAITOK | M_ZERO);
-
 	IPFW_UH_RLOCK(chain);
 
 	/*



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201812041612.wB4GCh78010128>