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