On Wed, Sep 16, 2020 at 06:22:00PM +0900, YASUOKA Masahiko wrote:
> Let me continue this separetely.
Yes, let's get your diff in for release and then work out the other
approach.
> Make pfctl check if the rtable really exists when parsing the config.
The diff is a bit hard to read (nothing you can do), but after applying
the code reads good in principal.
> 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 16 Sep 2020 09:11:21 -0000
> @@ -392,7 +392,9 @@ int invalid_redirect(struct node_host *
> u_int16_t parseicmpspec(char *, sa_family_t);
> int kw_casecmp(const void *, const void *);
> int map_tos(char *string, int *);
> +int get_domainid(u_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 +1219,10 @@ antispoof_opt : LABEL label {
> yyerror("invalid rtable id");
> YYERROR;
> }
> + else if (rtable_exists($2) != 1) {
Using the function verb would reads a bit clearer/more intuitive, i.e.
else if (!rtable_exists($2)) {
> + yyerror("rtable %lld does not exist", $2);
> + YYERROR;
> + }
> antispoof_opts.rtableid = $2;
> }
> ;
> @@ -2001,6 +2007,10 @@ filter_opt : USER uids {
> yyerror("invalid rtable id");
> YYERROR;
> }
> + else if (rtable_exists($2) != 1) {
Same here.
> + yyerror("rtable %lld does not exist", $2);
> + YYERROR;
> + }
> filter_opts.rtableid = $2;
> }
> | DIVERTTO STRING PORT portplain {
> @@ -5868,15 +5878,15 @@ map_tos(char *s, int *val)
> }
>
> int
> -rdomain_exists(u_int rdomain)
> +get_domainid(u_int rdomain)
> {
> size_t len;
> struct rt_tableinfo info;
> int mib[6];
> - static u_int found[RT_TABLEID_MAX+1];
> + static u_int domainid[RT_TABLEID_MAX+1];
>
> - if (found[rdomain] == 1)
> - return 1;
> + if (domainid[rdomain] != 0)
> + return domainid[rdomain];
>
> mib[0] = CTL_NET;
> mib[1] = PF_ROUTE;
> @@ -5887,17 +5897,37 @@ rdomain_exists(u_int rdomain)
>
> len = sizeof(info);
> if (sysctl(mib, 6, &info, &len, NULL, 0) == -1) {
> - if (errno == ENOENT) {
> + if (errno == ENOENT)
> /* table nonexistent */
> - return 0;
> - }
> - err(1, "%s", __func__);
> - }
> - if (info.rti_domainid == rdomain) {
> - found[rdomain] = 1;
> + domainid[rdomain] = RT_TABLEID_MAX;
This does not look correct, RT_TABLEID_MAX (255) is the biggest *valid*
id, so you cannot use it to denote a nonexistent routing table.
$ doas ifconfig lo255 rdomain 255
$ netstat -R | grep 255
Rdomain 255
Interface: lo255
Routing table: 255
Perhaps use `static int domainid[RT_TABLEID_MAX+1]' and `-1' to reflect
ENOENT?
> + else
> + err(1, "%s", __func__);
> + } else
> + domainid[rdomain] = info.rti_domainid;
> +
> + return domainid[rdomain];
> +}
> +
> +int
> +rdomain_exists(u_int rdomain)
> +{
> + int domainid;
> +
> + domainid = get_domainid(rdomain);
> + if (domainid == rdomain)
> return 1;
> - }
> /* rdomain is a table, but not an rdomain */
> + return 0;
> +}
> +
> +int
> +rtable_exists(u_int rtable)
> +{
> + int domainid;
> +
> + domainid = get_domainid(rtable);
> + if (domainid < RT_TABLEID_MAX)
As per above, RT_TABLEID_MAX is valid.
> + return 1;
> return 0;
> }