Hi,

When pf rule with a "on rdomain n" with nonexisting rdomain n causes

  /etc/pf.conf:XXX: rdomain n does not exist

error.  But with a "rtable n" with nonexisting rtable n will cause

  pfctl: DIOCADDRULE: Device busy

error.  It is hard to find the cause by this error message.

  /etc/pf.conf:XXX: rtable n does not exist

is better.  

ok?


Make pfctl check if the rtable really exists when parsing the config.

Index: sbin/pfctl/parse.y
===================================================================
RCS file: /cvs/src/sbin/pfctl/parse.y,v
retrieving revision 1.701
diff -u -p -r1.701 parse.y
--- sbin/pfctl/parse.y  28 Jan 2020 15:40:35 -0000      1.701
+++ sbin/pfctl/parse.y  14 Sep 2020 04:54:39 -0000
@@ -393,6 +393,7 @@ u_int16_t parseicmpspec(char *, sa_famil
 int     kw_casecmp(const void *, const void *);
 int     map_tos(char *string, int *);
 int     rdomain_exists(u_int);
+int     rtable_exists(u_int);
 int     filteropts_to_rule(struct pf_rule *, struct filter_opts *);
 
 TAILQ_HEAD(loadanchorshead, loadanchors)
@@ -1217,6 +1218,10 @@ antispoof_opt    : LABEL label   {
                                yyerror("invalid rtable id");
                                YYERROR;
                        }
+                       else if (rtable_exists($2) != 1) {
+                               yyerror("rtable %lld does not exist", $2);
+                               YYERROR;
+                       }
                        antispoof_opts.rtableid = $2;
                }
                ;
@@ -2001,6 +2006,10 @@ filter_opt       : USER uids {
                                yyerror("invalid rtable id");
                                YYERROR;
                        }
+                       else if (rtable_exists($2) != 1) {
+                               yyerror("rtable %lld does not exist", $2);
+                               YYERROR;
+                       }
                        filter_opts.rtableid = $2;
                }
                | DIVERTTO STRING PORT portplain {
@@ -5899,6 +5908,36 @@ rdomain_exists(u_int rdomain)
        }
        /* rdomain is a table, but not an rdomain */
        return 0;
+}
+
+int
+rtable_exists(u_int rtable)
+{
+       size_t                   len;
+       struct rt_tableinfo      info;
+       int                      mib[6];
+       static u_int             found[RT_TABLEID_MAX+1];
+
+       if (found[rtable] == 1)
+               return 1;
+
+       mib[0] = CTL_NET;
+       mib[1] = PF_ROUTE;
+       mib[2] = 0;
+       mib[3] = 0;
+       mib[4] = NET_RT_TABLE;
+       mib[5] = rtable;
+
+       len = sizeof(info);
+       if (sysctl(mib, 6, &info, &len, NULL, 0) == -1) {
+               if (errno == ENOENT) {
+                       /* table nonexistent */
+                       return 0;
+               }
+               err(1, "%s", __func__);
+       }
+       found[rtable] = 1;
+       return 1;
 }
 
 int

Reply via email to