Re: [PATCH v4 nft] Set/print standard chain prios with textual names

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Jul 10, 2018 at 12:10:22PM +0200, Pablo Neira Ayuso wrote:
> Hi,
> 
> On Mon, Jul 09, 2018 at 04:44:53PM +0200, Máté Eckl wrote:
> [...]
> > Example:
> > nft> add table ip x
> > nft> add chain ip x y { type filter hook prerouting priority raw; }
> > nft> add chain ip x z { type filter hook prerouting priority mangle + 1; }
> 
> Nice stuff.
> 
> > nft> add chain ip x w { type filter hook prerouting priority dstnat - 5; }
> 
> I'd suggest prenat instead of dstnat, probably? I understand this is
> leaking the definition we have in the kernel, but this is expected to
> be used by non-programmers, so I wonder if we can offer a better tag
> for this.

Destination nat (dnat/dstnat) is a well-known expression among sysadmins and
netadmins so I think this is better than prenat which just seems to be a new
word for the same thing.

> > nft> add chain ip x r { type filter hook prerouting priority filter + 10; }
> > nft> add chain ip x t { type filter hook prerouting priority security; }
> > nft> add chain ip x q { type filter hook prerouting priority srcnat + 11; }
> 
> I'd suggest postnat instead of srcnat.

Same as for dstnat.

> BTW, srcnat only makes sense from postrouting, I think it would it be
> possible to reject things that make no sense from there, like srcnat
> with prerouting as in the example above.

I'll look after this.

> More comments below.
> 
> > nft> add chain ip x h { type filter hook prerouting priority 15; }
> > nft>
> > nft> add flowtable ip x y { hook ingress priority filter + 5 ; devices = {enp0s31f6}; }
> > nft>
> > nft> add table arp x
> > nft> add chain arp x y { type filter hook input priority filter + 5; }
> > nft>
> > nft> list ruleset
> > table ip x {
> > 	flowtable y {
> > 		hook ingress priority filter + 5
> > 		devices = { enp0s31f6 }
> > 	}
> > 
> > 	chain y {
> > 		type filter hook prerouting priority raw; policy accept;
> > 	}
> > 
> > 	chain z {
> > 		type filter hook prerouting priority mangle + 1; policy accept;
> > 	}
> > 
> > 	chain w {
> > 		type filter hook prerouting priority dstnat - 5; policy accept;
> > 	}
> > 
> > 	chain r {
> > 		type filter hook prerouting priority filter + 10; policy accept;
> > 	}
> > 
> > 	chain t {
> > 		type filter hook prerouting priority security; policy accept;
> > 	}
> > 
> > 	chain q {
> > 		type filter hook prerouting priority 111; policy accept;
> > 	}
> > 
> > 	chain h {
> > 		type filter hook prerouting priority 15; policy accept;
> > 	}
> > }
> > table arp x {
> > 	chain y {
> > 		type filter hook input priority filter + 5; policy accept;
> > 	}
> > }
> > nft>
> > nft> add chain ip x h { type filter hook prerouting priority first; }
> > Error: 'first' is invalid for priority in this context.
> > add chain ip x h { type filter hook prerouting priority first; }
> >                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> > nft> add chain arp x y { type filter hook input priority raw; }
> > Error: 'raw' is invalid for priority in this context.
> > add chain arp x y { type filter hook input priority raw; }
> >                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> > nft> add flowtable ip x y { hook ingress priority magle; devices = {enp0s31f6}; }
> > Error: 'magle' is invalid for priority.
> > add flowtable ip x y { hook ingress priority magle; devices = {enp0s31f6}; }
> >                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> > 
> > Signed-off-by: Máté Eckl <ecklm94@xxxxxxxxx>
> > ---
> > v4:
> >  - fix snat and dnat conflict with existing tokens
> >  - remove static char array from chain_prio2str
> >  - make numerical priority printing available via -nnn nft flag
> >  - add docs about priority names
> >  - check compatibility of standard prio names and table family
> >  - handle flowtables
> > 
> >  doc/nft.xml        |  68 ++++++++++++++++++++++--
> >  include/rule.h     |   5 ++
> >  src/evaluate.c     |  56 ++++++++++++++++++++
> >  src/parser_bison.y |  36 ++++++++++---
> >  src/rule.c         | 129 ++++++++++++++++++++++++++++++++++++++++++---
> >  src/scanner.l      |   2 +
> >  6 files changed, 281 insertions(+), 15 deletions(-)
> > 
> > diff --git a/doc/nft.xml b/doc/nft.xml
> > index dc93a8c..01cc1d1 100644
> > --- a/doc/nft.xml
> > +++ b/doc/nft.xml
> > @@ -109,7 +109,7 @@ vi:ts=4 sw=4
> >  						Show data numerically. When used once (the default behaviour), skip
> >  						lookup of addresses to symbolic names. Use twice to also show Internet
> >  						services (port numbers) numerically. Use three times to also show
> > -						protocols and UIDs/GIDs numerically.
> > +						protocols, UIDs/GIDs and priorities numerically.
> >  					</para>
> >  				</listitem>
> >  			</varlistentry>
> > @@ -856,10 +856,68 @@ add table inet mytable
> >  			</itemizedlist>
> >  		</para>
> >  		<para>
> > -			The <literal>priority</literal> parameter accepts a signed integer value which specifies the order in which chains with same <literal>hook</literal> value are traversed. The ordering is ascending, i.e. lower priority values have precedence over higher ones.
> > +			The <literal>priority</literal> parameter accepts a signed integer value
> > +			or a standard priority name which specifies the order in which chains
> > +			with same <literal>hook</literal> value are traversed. The ordering is
> > +			ascending, i.e. lower priority values have precedence over higher ones.
> > +			<table frame="all">
> > +				<title>Standard priority names, values and families they are supported in</title>
> > +				<tgroup cols="3" align="left" colsep="1" rowsep="1">
> > +					<colspec colname="c1"/>
> > +					<colspec colname="c2" align="right"/>
> > +					<colspec colname="c3"/>
> > +					<thead>
> > +						<row>
> > +							<entry>Name</entry>
> > +							<entry>Value</entry>
> > +							<entry>Families</entry>
> > +						</row>
> > +					</thead>
> > +					<tbody>
> > +						<row>
> > +							<entry>raw</entry>
> > +							<entry>-300</entry>
> > +							<entry>ip, ip6, inet</entry>
> > +						</row>
> > +						<row>
> > +							<entry>mangle</entry>
> > +							<entry>-150</entry>
> > +							<entry>ip, ip6, inet</entry>
> > +						</row>
> > +						<row>
> > +							<entry>dstnat</entry>
> > +							<entry>-100</entry>
> > +							<entry>ip, ip6, inet, bridge</entry>
> > +						</row>
> > +						<row>
> > +							<entry>filter</entry>
> > +							<entry>0</entry>
> > +							<entry>ip, ip6, inet, arp, bridge, netdev</entry>
> > +						</row>
> > +						<row>
> > +							<entry>security</entry>
> > +							<entry>50</entry>
> > +							<entry>ip, ip6, inet</entry>
> > +						</row>
> > +						<row>
> > +							<entry>srcnat</entry>
> > +							<entry>100</entry>
> > +							<entry>ip, ip6, inet, bridge</entry>
> > +						</row>
> > +					</tbody>
> > +				</tgroup>
> > +			</table>
> > +			Basic arithmetic expressions (addition and substraction) can also
> > +			be achieved with these standard names to ease relative prioritizing,
> > +			eg. <literal>mangle - 5</literal> stands for <literal>-155</literal>.
> > +			Values will also be printid like this untill the value is not further
> > +			than 10 form the standard value.
> >  		</para>
> >  		<para>
> > -			Base chains also allow to set the chain's <literal>policy</literal>, i.e. what happens to packets not explicitly accepted or refused in contained rules. Supported policy values are <literal>accept</literal> (which is the default) or <literal>drop</literal>.
> > +			Base chains also allow to set the chain's <literal>policy</literal>, i.e.
> > +			what happens to packets not explicitly accepted or refused in contained
> > +			rules. Supported policy values are <literal>accept</literal> (which is
> > +			the default) or <literal>drop</literal>.
> >  		</para>
> >  	</refsect1>
> >  
> > @@ -1379,6 +1437,10 @@ table inet filter {
> >  			hybrid IPv4/IPv6 tables.
> >  
> >  			When no address family is specified, <literal>ip</literal> is used by default.
> > +
> > +			The <literal>priority</literal> can be a signed integer or <literal>filter</literal>
> > +			which stands for 0. Addition and substraction can be used to set relative priority
> > +			eg. filter + 5 equals to 5.
> >  		</para>
> >  
> >  		<variablelist>
> > diff --git a/include/rule.h b/include/rule.h
> > index 909ff36..cee9832 100644
> > --- a/include/rule.h
> > +++ b/include/rule.h
> > @@ -171,6 +171,7 @@ enum chain_flags {
> >   * @flags:	chain flags
> >   * @hookstr:	unified and human readable hook name (base chains)
> >   * @hooknum:	hook number (base chains)
> > + * @priostr:	hook priority for standard priority name use (base chains)
> >   * @priority:	hook priority (base chains)
> >   * @policy:	default chain policy (base chains)
> >   * @type:	chain type
> > @@ -185,6 +186,7 @@ struct chain {
> >  	uint32_t		flags;
> >  	const char		*hookstr;
> >  	unsigned int		hooknum;
> > +	const char		*priostr;
> >  	int			priority;
> >  	int			policy;
> >  	const char		*type;
> > @@ -193,6 +195,8 @@ struct chain {
> >  	struct list_head	rules;
> >  };
> >  
> > +#define STD_PRIO_BUFSIZE 100
> > +extern int std_prio_lookup(const char *std_prio_name, int family);
> >  extern const char *chain_type_name_lookup(const char *name);
> >  extern const char *chain_hookname_lookup(const char *name);
> >  extern struct chain *chain_alloc(const char *name);
> > @@ -357,6 +361,7 @@ struct flowtable {
> >  	struct location		location;
> >  	const char *		hookstr;
> >  	unsigned int		hooknum;
> > +	const char		*priostr;
> >  	int			priority;
> >  	const char		**dev_array;
> >  	struct expr		*dev_expr;
> > diff --git a/src/evaluate.c b/src/evaluate.c
> > index c4ee3cc..c6de5e7 100644
> > --- a/src/evaluate.c
> > +++ b/src/evaluate.c
> > @@ -17,6 +17,7 @@
> >  #include <linux/netfilter.h>
> >  #include <linux/netfilter_arp.h>
> >  #include <linux/netfilter/nf_tables.h>
> > +#include <linux/netfilter_ipv4.h>
> >  #include <netinet/ip_icmp.h>
> >  #include <netinet/icmp6.h>
> >  #include <net/ethernet.h>
> > @@ -2868,6 +2869,46 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set)
> >  	return 0;
> >  }
> >  
> > +static bool parse_evaluate_priority(const char *priostr, int *prioptr,
> > +				    int family) {
> > +	char *endptr = NULL, *numstart = NULL;
> > +	int priority;
> > +
> > +	priority = (int)strtol(priostr, &endptr, 10);
> > +	/* prio_spec */
> > +	if (priostr != endptr) {
> > +		*prioptr = priority;
> > +		return true;
> > +	}
> > +
> > +	/* STRING */
> > +	priority = std_prio_lookup(priostr, family);
> > +	if (priority != NF_IP_PRI_LAST) {
> > +		*prioptr = priority;
> > +		return true;
> > +	}
> > +
> > +	/* STRUNG PLUS NUM | STRING DASH NUM */
> > +	numstart = strchr(priostr, '+');
> > +	if (!numstart)
> > +		numstart = strchr(priostr, '-');
> > +	if (numstart) {
> > +		char prioname[STD_PRIO_BUFSIZE];
> > +
> > +		snprintf(prioname, numstart - priostr + 1, "%s", priostr);
> > +		priority = std_prio_lookup(prioname, family);
> > +		if (priority != NF_IP_PRI_LAST) {
> > +			priority += (int)strtol(numstart, &endptr, 10);
> > +			if (endptr == priostr + strlen(priostr)) {
> > +				*prioptr = priority;
> > +				return true;
> > +			}
> > +		}
> > +	}
> > +
> > +	return false;
> > +}
> > +
> >  static uint32_t str2hooknum(uint32_t family, const char *hook);
> >  
> >  static int flowtable_evaluate(struct eval_ctx *ctx, struct flowtable *ft)
> > @@ -2884,6 +2925,13 @@ static int flowtable_evaluate(struct eval_ctx *ctx, struct flowtable *ft)
> >  	if (ft->hooknum == NF_INET_NUMHOOKS)
> >  		return chain_error(ctx, ft, "invalid hook %s", ft->hookstr);
> >  
> > +	if (!ft->priostr)
> > +		return chain_error(ctx, ft,
> > +				   "flowtable priority must be specified.");
> > +	if (!parse_evaluate_priority(ft->priostr, &ft->priority, NFPROTO_NETDEV))
> > +		return chain_error(ctx, ft, "'%s' is invalid priority.",
> > +				   ft->priostr);
> > +
> >  	if (!ft->dev_expr)
> >  		return chain_error(ctx, ft, "Unbound flowtable not allowed (must specify devices)");
> >  
> > @@ -3038,6 +3086,14 @@ static int chain_evaluate(struct eval_ctx *ctx, struct chain *chain)
> >  					   chain->hookstr);
> >  	}
> >  
> > +	if (!chain->priostr)
> > +		return chain_error(ctx, chain, "chain priority must be specified.");
> > +	if (!parse_evaluate_priority(chain->priostr, &chain->priority,
> > +				     chain->handle.family))
> > +		return chain_error(ctx, chain,
> > +				   "'%s' is invalid priority in this context.",
> > +				   chain->priostr);
> > +
> >  	list_for_each_entry(rule, &chain->rules, list) {
> >  		handle_merge(&rule->handle, &chain->handle);
> >  		if (rule_evaluate(ctx, rule) < 0)
> > diff --git a/src/parser_bison.y b/src/parser_bison.y
> > index 98bfeba..2b7d7cc 100644
> > --- a/src/parser_bison.y
> > +++ b/src/parser_bison.y
> > @@ -182,6 +182,8 @@ int nft_lex(void *, void *, void *);
> >  %token AT			"@"
> >  %token VMAP			"vmap"
> >  
> > +%token PLUS			"+"
> > +
> >  %token INCLUDE			"include"
> >  %token DEFINE			"define"
> >  %token REDEFINE			"redefine"
> > @@ -522,6 +524,7 @@ int nft_lex(void *, void *, void *);
> >  %type <handle>			set_spec setid_spec set_identifier flowtable_identifier obj_spec objid_spec obj_identifier
> >  %destructor { handle_free(&$$); } set_spec setid_spec set_identifier obj_spec objid_spec obj_identifier
> >  %type <val>			family_spec family_spec_explicit chain_policy prio_spec
> > +%type <string>		str_prio_spec
> >  
> >  %type <string>			dev_spec quota_unit
> >  %destructor { xfree($$); }	dev_spec quota_unit
> > @@ -1633,7 +1636,7 @@ flowtable_block_alloc	:	/* empty */
> >  flowtable_block		:	/* empty */	{ $$ = $<flowtable>-1; }
> >  			|	flowtable_block	common_block
> >  			|	flowtable_block	stmt_separator
> > -			|	flowtable_block	HOOK		STRING	PRIORITY        prio_spec	stmt_separator
> > +			|	flowtable_block	HOOK		STRING	PRIORITY    str_prio_spec	stmt_separator
> >  			{
> >  				$$->hookstr	= chain_hookname_lookup($3);
> >  				if ($$->hookstr == NULL) {
> > @@ -1644,7 +1647,7 @@ flowtable_block		:	/* empty */	{ $$ = $<flowtable>-1; }
> >  				}
> >  				xfree($3);
> >  
> > -				$$->priority = $5;
> > +				$$->priostr = $5;
> >  			}
> >  			|	flowtable_block	DEVICES		'='	flowtable_expr	stmt_separator
> >  			{
> > @@ -1766,7 +1769,7 @@ type_identifier		:	STRING	{ $$ = $1; }
> >  			|	CLASSID { $$ = xstrdup("classid"); }
> >  			;
> >  
> > -hook_spec		:	TYPE		STRING		HOOK		STRING		dev_spec	PRIORITY	prio_spec
> > +hook_spec		:	TYPE		STRING		HOOK		STRING		dev_spec	PRIORITY	str_prio_spec
> >  			{
> >  				const char *chain_type = chain_type_name_lookup($2);
> >  
> > @@ -1789,13 +1792,34 @@ hook_spec		:	TYPE		STRING		HOOK		STRING		dev_spec	PRIORITY	prio_spec
> >  				xfree($4);
> >  
> >  				$<chain>0->dev		= $5;
> > -				$<chain>0->priority	= $7;
> > +				$<chain>0->priostr	= $7;
> >  				$<chain>0->flags	|= CHAIN_F_BASECHAIN;
> >  			}
> >  			;
> >  
> > -prio_spec		:	NUM			{ $$ = $1; }
> > -			|	DASH	NUM		{ $$ = -$2; }
> > +str_prio_spec	:	prio_spec
> > +			{
> > +				char buf[STD_PRIO_BUFSIZE];
> > +				snprintf(buf, STD_PRIO_BUFSIZE, "%d", (int)$1);
> > +				$$ = xstrdup(buf);
> > +			}
> > +			|	STRING	{ $$ = xstrdup($1); }
> > +			|	STRING PLUS NUM
> > +			{
> > +				char buf[STD_PRIO_BUFSIZE];
> > +				snprintf(buf, STD_PRIO_BUFSIZE, "%s+%d",$1, (int)$3);
> 
> Could you store the string plus offset instead of building this
> string that you need to parse again from the evaluation phase?
> 
> Probably you could reuse the existing priority integer field, then, if
> the label is non-NULL, then it means the priority integer becomes an
> offset.

This seems to be a good idea, I'll be on it.

> Thanks for working on this !
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux