On Sun, May 13, 2018 at 01:34:48AM +0200, Sebastian Benoit wrote:
> when you add a pf rule with a "on rdomain n" with nonexisting rdomain n,
> the load will fail with the error
> 
>   pfctl: DIOCADDRULE: Device busy
> 
> with no information which rule caused the problem and no indication that the
> problem is the rdomain <nonexisting>.
> 
> So lets check if the rdomain really exists when parsing the config.
> 
> Also parsing doesnot have to stop when this occurs, we can go on and
> stop before actually loading the config and that way parse the complete
> pf.conf and find more errors. Same goes for the rdomain range check, remove
> YYERROR there too.
> 
> ok?

OK bluhm@

> 
> /Benno
> 
> (benno_pfctl_rdomain_check.diff)
> 
> diff --git sbin/pfctl/parse.y sbin/pfctl/parse.y
> index fba07e2ea43..08797ebaabc 100644
> --- sbin/pfctl/parse.y
> +++ sbin/pfctl/parse.y
> @@ -30,6 +30,7 @@
>  #include <sys/types.h>
>  #include <sys/socket.h>
>  #include <sys/stat.h>
> +#include <sys/sysctl.h>
>  #include <net/if.h>
>  #include <netinet/in.h>
>  #include <netinet/ip.h>
> @@ -389,6 +390,7 @@ int        invalid_redirect(struct node_host *, 
> sa_family_t);
>  u_int16_t parseicmpspec(char *, sa_family_t);
>  int   kw_casecmp(const void *, const void *);
>  int   map_tos(char *string, int *);
> +int   rdomain_exists(u_int);
>  
>  TAILQ_HEAD(loadanchorshead, loadanchors)
>      loadanchorshead = TAILQ_HEAD_INITIALIZER(loadanchorshead);
> @@ -2561,10 +2563,11 @@ if_item               : STRING                        
> {
>                       $$->tail = $$;
>               }
>               | RDOMAIN NUMBER                {
> -                     if ($2 < 0 || $2 > RT_TABLEID_MAX) {
> -                             yyerror("rdomain outside range");
> -                             YYERROR;
> -                     }
> +                     if ($2 < 0 || $2 > RT_TABLEID_MAX)
> +                             yyerror("rdomain %lld outside range", $2);
> +                     if (rdomain_exists($2) != 1)
> +                             yyerror("rdomain %lld does not exist", $2);
> +
>                       $$ = calloc(1, sizeof(struct node_if));
>                       if ($$ == NULL)
>                               err(1, "if_item: calloc");
> @@ -5950,3 +5953,35 @@ map_tos(char *s, int *val)
>       }
>       return (0);
>  }
> +
> +int
> +rdomain_exists(u_int rdomain)
> +{
> +     size_t                   len;
> +     struct rt_tableinfo      info;
> +     int                      mib[6];
> +     static u_int             found[RT_TABLEID_MAX];
> +
> +     if (found[rdomain] == 1)
> +             return (1);
> +
> +     mib[0] = CTL_NET;
> +     mib[1] = PF_ROUTE;
> +     mib[2] = 0;
> +     mib[3] = 0;
> +     mib[4] = NET_RT_TABLE;
> +     mib[5] = rdomain;
> +
> +     len = sizeof(info);
> +     if (sysctl(mib, 6, &info, &len, NULL, 0) == -1) {
> +             if (errno == ENOENT)
> +                     /* table nonexistent */
> +                     return (0);
> +             err(1, "sysctl");
> +     }
> +     if (info.rti_domainid == rdomain) {
> +             found[rdomain] = 1;
> +             return (1);
> +     }
> +     return (0);
> +}

Reply via email to