Tables under different anchors may have the same name, but pfctl warns
about such scenarios upon table creation to avoid mixups.  Unique and
descriptive names are highly recommended (for sanity).

        # pfctl -T replace -t t1
        1 table created.
        no changes.
        # pfctl -T replace -t t1 -a a1
        pfctl: warning: namespace collision with <t1> global table.
        1 table created.
        no changes.

Adding a table to yet another anchor will only ever warn about the one
in the main anchor:


        # pfctl -T replace -t t1 -a a2
        pfctl: warning: namespace collision with <t1> global table.
        1 table created.
        no changes.

Adding equally named tables in non-main anchors only will never produce
warnings:

        # pfctl -T add -t t2 -a a1
        1 table created.
        0/0 addresses added.
        # pfctl -T add -t t2 -a a2
        1 table created.
        0/0 addresses added.

Things to improve:

- spot all collisions
- warn on dry runs (`-n') as well
- name offending anchors

For this the anchor name must be passed in, but this is impossible to
do from pfctl's main() upon processing `-f file', where it's done now
since the file may contain table definitions.

This diff moves the call to process_tabledefs() inside the parser where
it's only called when tables actually occur.  This way both table and
anchor name is known and warn_namespace_collision()'s `filter == NULL'
semantic can be dropped to further simplify the function.

Besides new warnings on standard error, there's no functional change as
ruleset production/manipulation is not effected; regress passes.

        # ./obj/pfctl -T replace -t t3
        1 table created.
        no changes.
        # ./obj/pfctl -T replace -t t3 -a a1
        pfctl: warning: table <t3> already defined in anchor "/"
        1 table created.
        no changes.
        # ./obj/pfctl -T replace -t t3 -a a2 -n
        pfctl: warning: table <t3> already defined in anchor "/"
        pfctl: warning: table <t3> already defined in anchor "a1"
        1 table created (dummy).

The main anchor is denoted as "/" as it keeps the logic around warnx(3)
simple while still allowing to copy/paste it as is.

Since it's not just about collisions with the "global" tables (those in
the main anchor), I renamed the function to warn_duplicate_tables() at
no cost/blame churn since signature and callers are touched anyway.

Feedback? Objections? OK?

Index: pfctl.h
===================================================================
RCS file: /cvs/src/sbin/pfctl/pfctl.h,v
retrieving revision 1.57
diff -u -p -r1.57 pfctl.h
--- pfctl.h     6 Sep 2018 15:07:33 -0000       1.57
+++ pfctl.h     29 Dec 2018 15:59:11 -0000
@@ -79,7 +79,7 @@ void   pfctl_clear_tables(const char *, i
 void    pfctl_show_tables(const char *, int);
 int     pfctl_command_tables(int, char *[], char *, const char *, char *,
            const char *, int);
-void    warn_namespace_collision(const char *);
+void    warn_duplicate_tables(const char *, const char *);
 void    pfctl_show_ifaces(const char *, int);
 FILE   *pfctl_fopen(const char *, const char *);
 
Index: pfctl.c
===================================================================
RCS file: /cvs/src/sbin/pfctl/pfctl.c,v
retrieving revision 1.361
diff -u -p -r1.361 pfctl.c
--- pfctl.c     27 Dec 2018 16:33:44 -0000      1.361
+++ pfctl.c     29 Dec 2018 15:59:11 -0000
@@ -2690,8 +2690,6 @@ main(int argc, char *argv[])
                if (pfctl_rules(dev, rulesopt, opts, optimize,
                    anchorname, NULL))
                        error = 1;
-               else if (!(opts & PF_OPT_NOACTION))
-                       warn_namespace_collision(NULL);
        }
 
        if (opts & PF_OPT_ENABLE)
Index: parse.y
===================================================================
RCS file: /cvs/src/sbin/pfctl/parse.y,v
retrieving revision 1.688
diff -u -p -r1.688 parse.y
--- parse.y     15 Nov 2018 03:22:01 -0000      1.688
+++ parse.y     29 Dec 2018 15:59:28 -0000
@@ -4075,6 +4075,7 @@ process_tabledef(char *name, struct tabl
        if (pf->opts & PF_OPT_VERBOSE)
                print_tabledef(name, opts->flags, opts->init_addr,
                    &opts->init_nodes);
+       warn_duplicate_tables(name, pf->anchor->path);
        if (!(pf->opts & PF_OPT_NOACTION) &&
            pfctl_define_table(name, opts->flags, opts->init_addr,
            pf->anchor->path, &ab, pf->anchor->ruleset.tticket)) {
Index: pfctl_table.c
===================================================================
RCS file: /cvs/src/sbin/pfctl/pfctl_table.c,v
retrieving revision 1.78
diff -u -p -r1.78 pfctl_table.c
--- pfctl_table.c       15 Oct 2018 21:15:35 -0000      1.78
+++ pfctl_table.c       29 Dec 2018 15:59:21 -0000
@@ -94,7 +94,8 @@ static const char     *istats_text[2][2][2] 
                        goto _error;                                    \
                }                                                       \
                if (nadd) {                                             \
-                       warn_namespace_collision(table.pfrt_name);      \
+                       warn_duplicate_tables(table.pfrt_name,          \
+                           table.pfrt_anchor);                         \
                        xprintf(opts, "%d table created", nadd);        \
                        if (opts & PF_OPT_NOACTION)                     \
                                return (0);                             \
@@ -537,12 +538,10 @@ pfctl_define_table(char *name, int flags
 }
 
 void
-warn_namespace_collision(const char *filter)
+warn_duplicate_tables(const char *tablename, const char *anchorname)
 {
        struct pfr_buffer b;
        struct pfr_table *t;
-       const char *name = NULL, *lastcoll;
-       int coll = 0;
 
        bzero(&b, sizeof(b));
        b.pfrb_type = PFRB_TABLES;
@@ -558,22 +557,13 @@ warn_namespace_collision(const char *fil
        PFRB_FOREACH(t, &b) {
                if (!(t->pfrt_flags & PFR_TFLAG_ACTIVE))
                        continue;
-               if (filter != NULL && strcmp(filter, t->pfrt_name))
+               if (!strcmp(anchorname, t->pfrt_anchor))
                        continue;
-               if (!t->pfrt_anchor[0])
-                       name = t->pfrt_name;
-               else if (name != NULL && !strcmp(name, t->pfrt_name)) {
-                       coll++;
-                       lastcoll = name;
-                       name = NULL;
-               }
+               if (!strcmp(tablename, t->pfrt_name))
+                       warnx("warning: table <%s> already defined"
+                           " in anchor \"%s\"", tablename,
+                           t->pfrt_anchor[0] ? t->pfrt_anchor : "/");
        }
-       if (coll == 1)
-               warnx("warning: namespace collision with <%s> global table.",
-                   lastcoll);
-       else if (coll > 1)
-               warnx("warning: namespace collisions with %d global tables.",
-                   coll);
        pfr_buf_clear(&b);
 }
 
===================================================================
Stats: --- 21 lines 671 chars
Stats: +++ 10 lines 470 chars
Stats: -11 lines
Stats: -201 chars

Reply via email to