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 <[email protected]>
> > ---
> > 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 [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to