On Thu, Jan 28, 2021 at 10:54:30PM +1000, David Gwynne wrote:
> this is the diff from the "pf route-to issues" thread, but on it's own.

I think we should make progress and commit something.

>   the caveat is that route-to becomes tied to pass rules that create
>   state, like rdr-to and nat-to.

Maybe we should mention that in the man page.  But let's discuss
that separately.

>   that's a separate change for broader discussion.

Yes.  No more topics on top of uncomitted diffs.

> ok?

OK bluhm@

> Index: sbin/pfctl/parse.y
> ===================================================================
> RCS file: /cvs/src/sbin/pfctl/parse.y,v
> retrieving revision 1.708
> diff -u -p -r1.708 parse.y
> --- sbin/pfctl/parse.y        12 Jan 2021 00:10:34 -0000      1.708
> +++ sbin/pfctl/parse.y        28 Jan 2021 11:45:58 -0000
> @@ -276,6 +276,7 @@ struct filter_opts {
>       struct redirspec         nat;
>       struct redirspec         rdr;
>       struct redirspec         rroute;
> +     u_int8_t                 rt;
>  
>       /* scrub opts */
>       int                      nodf;
> @@ -284,15 +285,6 @@ struct filter_opts {
>       int                      randomid;
>       int                      max_mss;
>  
> -     /* route opts */
> -     struct {
> -             struct node_host        *host;
> -             u_int8_t                 rt;
> -             u_int8_t                 pool_opts;
> -             sa_family_t              af;
> -             struct pf_poolhashkey   *key;
> -     }                        route;
> -
>       struct {
>               u_int32_t       limit;
>               u_int32_t       seconds;
> @@ -372,7 +364,7 @@ void               expand_label(char *, size_t, cons
>                   struct node_port *, u_int8_t);
>  int           expand_divertspec(struct pf_rule *, struct divertspec *);
>  int           collapse_redirspec(struct pf_pool *, struct pf_rule *,
> -                 struct redirspec *rs, u_int8_t);
> +                 struct redirspec *rs, int);
>  int           apply_redirspec(struct pf_pool *, struct pf_rule *,
>                   struct redirspec *, int, struct node_port *);
>  void          expand_rule(struct pf_rule *, int, struct node_if *,
> @@ -518,7 +510,6 @@ int       parseport(char *, struct range *r, i
>  %type        <v.host>                ipspec xhost host dynaddr host_list
>  %type        <v.host>                table_host_list tablespec
>  %type        <v.host>                redir_host_list redirspec
> -%type        <v.host>                route_host route_host_list routespec
>  %type        <v.os>                  os xos os_list
>  %type        <v.port>                portspec port_list port_item
>  %type        <v.uid>                 uids uid_list uid_item
> @@ -975,7 +966,7 @@ anchorrule        : ANCHOR anchorname dir quick
>                               YYERROR;
>                       }
>  
> -                     if ($9.route.rt) {
> +                     if ($9.rt) {
>                               yyerror("cannot specify route handling "
>                                   "on anchors");
>                               YYERROR;
> @@ -1843,37 +1834,13 @@ pfrule                : action dir logquick interface 
>                       decide_address_family($7.src.host, &r.af);
>                       decide_address_family($7.dst.host, &r.af);
>  
> -                     if ($8.route.rt) {
> -                             if (!r.direction) {
> +                     if ($8.rt) {
> +                             if ($8.rt != PF_DUPTO && !r.direction) {
>                                       yyerror("direction must be explicit "
>                                           "with rules that specify routing");
>                                       YYERROR;
>                               }
> -                             r.rt = $8.route.rt;
> -                             r.route.opts = $8.route.pool_opts;
> -                             if ($8.route.key != NULL)
> -                                     memcpy(&r.route.key, $8.route.key,
> -                                         sizeof(struct pf_poolhashkey));
> -                     }
> -                     if (r.rt) {
> -                             decide_address_family($8.route.host, &r.af);
> -                             if ((r.route.opts & PF_POOL_TYPEMASK) ==
> -                                 PF_POOL_NONE && ($8.route.host->next != 
> NULL ||
> -                                 $8.route.host->addr.type == PF_ADDR_TABLE ||
> -                                 DYNIF_MULTIADDR($8.route.host->addr)))
> -                                     r.route.opts |= PF_POOL_ROUNDROBIN;
> -                             if ($8.route.host->next != NULL) {
> -                                     if (!PF_POOL_DYNTYPE(r.route.opts)) {
> -                                             yyerror("address pool option "
> -                                                 "not supported by type");
> -                                             YYERROR;
> -                                     }
> -                             }
> -                             /* fake redirspec */
> -                             if (($8.rroute.rdr = calloc(1,
> -                                 sizeof(*$8.rroute.rdr))) == NULL)
> -                                     err(1, "$8.rroute.rdr");
> -                             $8.rroute.rdr->host = $8.route.host;
> +                             r.rt = $8.rt;
>                       }
>  
>                       if (expand_divertspec(&r, &$8.divert))
> @@ -2137,30 +2104,14 @@ filter_opt    : USER uids {
>                           sizeof(filter_opts.nat.pool_opts));
>                       filter_opts.nat.pool_opts.staticport = 1;
>               }
> -             | ROUTETO routespec pool_opts {
> -                     filter_opts.route.host = $2;
> -                     filter_opts.route.rt = PF_ROUTETO;
> -                     filter_opts.route.pool_opts = $3.type | $3.opts;
> -                     memcpy(&filter_opts.rroute.pool_opts, &$3,
> -                         sizeof(filter_opts.rroute.pool_opts));
> -                     if ($3.key != NULL)
> -                             filter_opts.route.key = $3.key;
> +             | ROUTETO routespec {
> +                     filter_opts.rt = PF_ROUTETO;
>               }
> -             | REPLYTO routespec pool_opts {
> -                     filter_opts.route.host = $2;
> -                     filter_opts.route.rt = PF_REPLYTO;
> -                     filter_opts.route.pool_opts = $3.type | $3.opts;
> -                     if ($3.key != NULL)
> -                             filter_opts.route.key = $3.key;
> -             }
> -             | DUPTO routespec pool_opts {
> -                     filter_opts.route.host = $2;
> -                     filter_opts.route.rt = PF_DUPTO;
> -                     filter_opts.route.pool_opts = $3.type | $3.opts;
> -                     memcpy(&filter_opts.rroute.pool_opts, &$3,
> -                         sizeof(filter_opts.rroute.pool_opts));
> -                     if ($3.key != NULL)
> -                             filter_opts.route.key = $3.key;
> +             | REPLYTO routespec {
> +                     filter_opts.rt = PF_REPLYTO;
> +             }
> +             | DUPTO routespec {
> +                     filter_opts.rt = PF_DUPTO;
>               }
>               | not RECEIVEDON if_item {
>                       if (filter_opts.rcv) {
> @@ -3743,122 +3694,21 @@ pool_opt     : BITMASK       {
>               }
>               ;
>  
> -route_host   : STRING                        {
> -                     /* try to find @if0 address specs */
> -                     if (strrchr($1, '@') != NULL) {
> -                             if (($$ = host($1, pf->opts)) == NULL)  {
> -                                     yyerror("invalid host for route spec");
> -                                     YYERROR;
> -                             }
> -                             free($1);
> -                     } else {
> -                             $$ = calloc(1, sizeof(struct node_host));
> -                             if ($$ == NULL)
> -                                     err(1, "route_host: calloc");
> -                             $$->ifname = $1;
> -                             $$->addr.type = PF_ADDR_NONE;
> -                             set_ipmask($$, 128);
> -                             $$->next = NULL;
> -                             $$->tail = $$;
> -                     }
> -             }
> -             | STRING '/' STRING             {
> -                     char    *buf;
> -
> -                     if (asprintf(&buf, "%s/%s", $1, $3) == -1)
> -                             err(1, "host: asprintf");
> -                     free($1);
> -                     if (($$ = host(buf, pf->opts)) == NULL) {
> -                             /* error. "any" is handled elsewhere */
> -                             free(buf);
> -                             yyerror("could not parse host specification");
> -                             YYERROR;
> -                     }
> -                     free(buf);
> -             }
> -             | '<' STRING '>'        {
> -                     if (strlen($2) >= PF_TABLE_NAME_SIZE) {
> -                             yyerror("table name '%s' too long", $2);
> -                             free($2);
> -                             YYERROR;
> -                     }
> -                     $$ = calloc(1, sizeof(struct node_host));
> -                     if ($$ == NULL)
> -                             err(1, "host: calloc");
> -                     $$->addr.type = PF_ADDR_TABLE;
> -                     if (strlcpy($$->addr.v.tblname, $2,
> -                         sizeof($$->addr.v.tblname)) >=
> -                         sizeof($$->addr.v.tblname))
> -                             errx(1, "host: strlcpy");
> -                     free($2);
> -                     $$->next = NULL;
> -                     $$->tail = $$;
> -             }
> -             | dynaddr '/' NUMBER            {
> -                     struct node_host        *n;
> -
> -                     if ($3 < 0 || $3 > 128) {
> -                             yyerror("bit number too big");
> -                             YYERROR;
> -                     }
> -                     $$ = $1;
> -                     for (n = $1; n != NULL; n = n->next)
> -                             set_ipmask(n, $3);
> -             }
> -             | '(' STRING host ')'           {
> -                     struct node_host        *n;
> -
> -                     $$ = $3;
> -                     /* XXX check masks, only full mask should be allowed */
> -                     for (n = $3; n != NULL; n = n->next) {
> -                             if ($$->ifname) {
> -                                     yyerror("cannot specify interface twice 
> "
> -                                         "in route spec");
> -                                     YYERROR;
> -                             }
> -                             if (($$->ifname = strdup($2)) == NULL)
> -                                     errx(1, "host: strdup");
> -                     }
> -                     free($2);
> -             }
> -             ;
> -
> -route_host_list      : route_host optweight optnl            { 
> -                     if ($2 > 0) {
> -                             struct node_host        *n;
> -                             for (n = $1; n != NULL; n = n->next)
> -                                     n->weight = $2;
> -                     }
> -                     $$ = $1;
> -             }
> -             | route_host_list comma route_host optweight optnl {
> -                     if ($1->af == 0)
> -                             $1->af = $3->af;
> -                     if ($1->af != $3->af) {
> -                             yyerror("all pool addresses must be in the "
> -                                 "same address family");
> +routespec    : redirspec pool_opts {
> +                     struct redirection *redir;
> +                     if (filter_opts.rt != PF_NOPFROUTE) {
> +                             yyerror("cannot respecify "
> +                                 "route-to/reply-to/dup-to");
>                               YYERROR;
>                       }
> -                     $1->tail->next = $3;
> -                     $1->tail = $3->tail;
> -                     if ($4 > 0) {
> -                             struct node_host        *n;
> -                             for (n = $3; n != NULL; n = n->next)
> -                                     n->weight = $4;
> -                     }
> -                     $$ = $1;
> -             }
> -             ;
> -
> -routespec    : route_host optweight                  {
> -                     if ($2 > 0) {
> -                             struct node_host        *n;
> -                             for (n = $1; n != NULL; n = n->next)
> -                                     n->weight = $2;
> -                     }
> -                     $$ = $1;
> +                     redir = calloc(1, sizeof(*redir));
> +                     if (redir == NULL)
> +                             err(1, "routespec calloc");
> +                     redir->host = $1;
> +                     filter_opts.rroute.rdr = redir;
> +                     memcpy(&filter_opts.rroute.pool_opts, &$2,
> +                         sizeof(filter_opts.rroute.pool_opts));
>               }
> -             | '{' optnl route_host_list '}' { $$ = $3; }
>               ;
>  
>  timeout_spec : STRING NUMBER
> @@ -4478,7 +4328,7 @@ expand_divertspec(struct pf_rule *r, str
>  
>  int
>  collapse_redirspec(struct pf_pool *rpool, struct pf_rule *r,
> -    struct redirspec *rs, u_int8_t allow_if)
> +    struct redirspec *rs, int routing)
>  {
>       struct pf_opt_tbl *tbl = NULL;
>       struct node_host *h, *hprev = NULL;
> @@ -4494,6 +4344,15 @@ collapse_redirspec(struct pf_pool *rpool
>               r->naf = rs->af;
>  
>       for (h = rs->rdr->host; h != NULL; h = h->next) {
> +             if (routing) {
> +                     if (h->addr.type == PF_ADDR_DYNIFTL &&
> +                         h->addr.iflags != PFI_AFLAG_PEER) {
> +                             yyerror("route spec requires :peer with "
> +                                 "dynamic interface addresses");
> +                             return (1);
> +                     }
> +             }
> +
>               /* set rule address family if redirect spec has one */
>               if (rs->af && !r->af && !af) {
>                       /* swap address families for af-to */
> @@ -4515,7 +4374,7 @@ collapse_redirspec(struct pf_pool *rpool
>                       if (!r->af && af && af != h->af) {
>                               yyerror("%s spec contains addresses with "
>                                   "different address families",
> -                                 allow_if ? "routing" : "translation");
> +                                 routing ? "routing" : "translation");
>                               return (1);
>                       }
>               } else if (h->af) {     /* af-to case */
> @@ -4526,7 +4385,7 @@ collapse_redirspec(struct pf_pool *rpool
>                       if (rs->af && rs->af != h->af) {
>                               yyerror("%s spec contains addresses that "
>                                   "don't match target address family",
> -                                 allow_if ? "routing" : "translation");
> +                                 routing ? "routing" : "translation");
>                               return (1);
>                       }
>               }
> @@ -4541,8 +4400,9 @@ collapse_redirspec(struct pf_pool *rpool
>  
>               if (naddr == 0) {       /* the first host */
>                       rpool->addr = h->addr;
> -                     if (!allow_if && h->ifname) {
> -                             yyerror("@if not permitted for translation");
> +                     if (h->ifname) {
> +                             yyerror("@if not permitted for %s",
> +                                 routing ? "routing" : "translation");
>                               return (1);
>                       }
>                       if (h->ifname && strlcpy(rpool->ifname, h->ifname,
> @@ -4564,8 +4424,9 @@ collapse_redirspec(struct pf_pool *rpool
>                                   "not supported for translation or routing");
>                               return (1);
>                       }
> -                     if (!allow_if && h->ifname) {
> -                             yyerror("@if not permitted for translation");
> +                     if (h->ifname) {
> +                             yyerror("@if not permitted for %s",
> +                                 routing ? "routing" : "translation");
>                               return (1);
>                       }
>                       if (hprev) {
> @@ -4596,7 +4457,7 @@ collapse_redirspec(struct pf_pool *rpool
>               r->af = af;
>       if (!naddr) {
>               yyerror("af mismatch in %s spec",
> -                 allow_if ? "routing" : "translation");
> +                 routing ? "routing" : "translation");
>               return (1);
>       }
>       if (tbl) {
> @@ -5992,7 +5853,7 @@ filteropts_to_rule(struct pf_rule *r, st
>               yyerror("af-to can only be used with direction in");
>               return (1);
>       }
> -     if ((opts->marker & FOM_AFTO) && opts->route.rt) {
> +     if ((opts->marker & FOM_AFTO) && opts->rt) {
>               yyerror("af-to cannot be used together with "
>                   "route-to, reply-to, dup-to");
>               return (1);
> Index: sbin/pfctl/pfctl_parser.c
> ===================================================================
> RCS file: /cvs/src/sbin/pfctl/pfctl_parser.c,v
> retrieving revision 1.345
> diff -u -p -r1.345 pfctl_parser.c
> --- sbin/pfctl/pfctl_parser.c 12 Jan 2021 00:10:34 -0000      1.345
> +++ sbin/pfctl/pfctl_parser.c 28 Jan 2021 11:45:58 -0000
> @@ -1615,17 +1615,12 @@ host(const char *s, int opts)
>  {
>       struct node_host        *h = NULL, *n;
>       int                      mask = -1;
> -     char                    *p, *ps, *if_name;
> +     char                    *p, *ps;
>       const char              *errstr;
>  
>       if ((ps = strdup(s)) == NULL)
>               err(1, "%s: strdup", __func__);
>  
> -     if ((if_name = strrchr(ps, '@')) != NULL) {
> -             if_name[0] = '\0';
> -             if_name++;
> -     }
> -
>       if ((p = strchr(ps, '/')) != NULL) {
>               mask = strtonum(p+1, 0, 128, &errstr);
>               if (errstr) {
> @@ -1642,10 +1637,6 @@ host(const char *s, int opts)
>               goto error;
>       }
>  
> -     if (if_name && if_name[0])
> -             for (n = h; n != NULL; n = n->next)
> -                     if ((n->ifname = strdup(if_name)) == NULL)
> -                             err(1, "%s: strdup", __func__);
>       for (n = h; n != NULL; n = n->next) {
>               n->addr.type = PF_ADDR_ADDRMASK;
>               n->weight = 0;
> Index: share/man/man5/pf.conf.5
> ===================================================================
> RCS file: /cvs/src/share/man/man5/pf.conf.5,v
> retrieving revision 1.585
> diff -u -p -r1.585 pf.conf.5
> --- share/man/man5/pf.conf.5  7 Dec 2020 08:29:41 -0000       1.585
> +++ share/man/man5/pf.conf.5  28 Jan 2021 11:45:58 -0000
> @@ -1113,8 +1113,8 @@ the incoming connection arrived through 
>  .It Cm route-to
>  The
>  .Cm route-to
> -option routes the packet to the specified interface with an optional address
> -for the next hop.
> +option routes the packet to the specified destination address instead
> +of the destination address in the packet header.
>  When a
>  .Cm route-to
>  rule creates state, only packets that pass in the same direction as the
> @@ -2858,8 +2858,7 @@ ifspec         = ( [ "!" ] ( interface-n
>  interface-list = [ "!" ] ( interface-name | interface-group )
>                   [ [ "," ] interface-list ]
>  route          = ( "route-to" | "reply-to" | "dup-to" )
> -                 ( routehost | "{" routehost-list "}" )
> -                 [ pooltype ]
> +                 ( redirhost | "{" redirhost-list "}" )
>  af             = "inet" | "inet6"
>  
>  protospec      = "proto" ( proto-name | proto-number |
> @@ -2878,14 +2877,11 @@ host           = [ "!" ] ( address [ "we
>                   address [ "/" mask-bits ] [ "weight" number ] |
>                   "<" string ">" )
>  redirhost      = address [ "/" mask-bits ]
> -routehost      = host | host "@" interface-name |
> -                 "(" interface-name [ address [ "/" mask-bits ] ] ")"
>  address        = ( interface-name | interface-group |
>                   "(" ( interface-name | interface-group ) ")" |
>                   hostname | ipv4-dotted-quad | ipv6-coloned-hex )
>  host-list      = host [ [ "," ] host-list ]
>  redirhost-list = redirhost [ [ "," ] redirhost-list ]
> -routehost-list = routehost [ [ "," ] routehost-list ]
>  
>  port           = "port" ( unary-op | binary-op | "{" op-list "}" )
>  portspec       = "port" ( number | name ) [ ":" ( "*" | number | name ) ]
> Index: sys/net/if_pfsync.c
> ===================================================================
> RCS file: /cvs/src/sys/net/if_pfsync.c,v
> retrieving revision 1.281
> diff -u -p -r1.281 if_pfsync.c
> --- sys/net/if_pfsync.c       18 Jan 2021 18:29:19 -0000      1.281
> +++ sys/net/if_pfsync.c       28 Jan 2021 11:45:58 -0000
> @@ -613,6 +613,7 @@ pfsync_state_import(struct pfsync_state 
>  
>       /* copy to state */
>       st->rt_addr = sp->rt_addr;
> +     st->rt = sp->rt;
>       st->creation = getuptime() - ntohl(sp->creation);
>       st->expire = getuptime();
>       if (ntohl(sp->expire)) {
> @@ -643,7 +644,6 @@ pfsync_state_import(struct pfsync_state 
>  
>       st->rule.ptr = r;
>       st->anchor.ptr = NULL;
> -     st->rt_kif = NULL;
>  
>       st->pfsync_time = getuptime();
>       st->sync_state = PFSYNC_S_NONE;
> @@ -1860,7 +1860,7 @@ pfsync_undefer(struct pfsync_deferral *p
>       if (drop)
>               m_freem(pd->pd_m);
>       else {
> -             if (st->rule.ptr->rt == PF_ROUTETO) {
> +             if (st->rt == PF_ROUTETO) {
>                       if (pf_setup_pdesc(&pdesc, st->key[PF_SK_WIRE]->af,
>                           st->direction, st->kif, pd->pd_m, NULL) !=
>                           PF_PASS) {
> @@ -1869,11 +1869,11 @@ pfsync_undefer(struct pfsync_deferral *p
>                       }
>                       switch (st->key[PF_SK_WIRE]->af) {
>                       case AF_INET:
> -                             pf_route(&pdesc, st->rule.ptr, st);
> +                             pf_route(&pdesc, st);
>                               break;
>  #ifdef INET6
>                       case AF_INET6:
> -                             pf_route6(&pdesc, st->rule.ptr, st);
> +                             pf_route6(&pdesc, st);
>                               break;
>  #endif /* INET6 */
>                       default:
> Index: sys/net/pf.c
> ===================================================================
> RCS file: /cvs/src/sys/net/pf.c,v
> retrieving revision 1.1105
> diff -u -p -r1.1105 pf.c
> --- sys/net/pf.c      28 Jan 2021 09:37:20 -0000      1.1105
> +++ sys/net/pf.c      28 Jan 2021 11:45:58 -0000
> @@ -1180,6 +1180,7 @@ pf_state_export(struct pfsync_state *sp,
>  
>       /* copy from state */
>       strlcpy(sp->ifname, st->kif->pfik_name, sizeof(sp->ifname));
> +     sp->rt = st->rt;
>       sp->rt_addr = st->rt_addr;
>       sp->creation = htonl(getuptime() - st->creation);
>       expire = pf_state_expires(st);
> @@ -3430,16 +3431,13 @@ pf_set_rt_ifp(struct pf_state *s, struct
>       struct pf_rule *r = s->rule.ptr;
>       int     rv;
>  
> -     s->rt_kif = NULL;
>       if (!r->rt)
>               return (0);
>  
>       rv = pf_map_addr(af, r, saddr, &s->rt_addr, NULL, sns, 
>           &r->route, PF_SN_ROUTE);
> -     if (rv == 0) {
> -             s->rt_kif = r->route.kif;
> -             s->natrule.ptr = r;
> -     }
> +     if (rv == 0)
> +             s->rt = r->rt;
>  
>       return (rv);
>  }
> @@ -5963,15 +5961,13 @@ pf_rtlabel_match(struct pf_addr *addr, s
>  
>  /* pf_route() may change pd->m, adjust local copies after calling */
>  void
> -pf_route(struct pf_pdesc *pd, struct pf_rule *r, struct pf_state *s)
> +pf_route(struct pf_pdesc *pd, struct pf_state *s)
>  {
>       struct mbuf             *m0, *m1;
>       struct sockaddr_in      *dst, sin;
>       struct rtentry          *rt = NULL;
>       struct ip               *ip;
>       struct ifnet            *ifp = NULL;
> -     struct pf_addr           naddr;
> -     struct pf_src_node      *sns[PF_SN_MAX];
>       int                      error = 0;
>       unsigned int             rtableid;
>  
> @@ -5981,11 +5977,11 @@ pf_route(struct pf_pdesc *pd, struct pf_
>               return;
>       }
>  
> -     if (r->rt == PF_DUPTO) {
> +     if (s->rt == PF_DUPTO) {
>               if ((m0 = m_dup_pkt(pd->m, max_linkhdr, M_NOWAIT)) == NULL)
>                       return;
>       } else {
> -             if ((r->rt == PF_REPLYTO) == (r->direction == pd->dir))
> +             if ((s->rt == PF_REPLYTO) == (s->direction == pd->dir))
>                       return;
>               m0 = pd->m;
>               pd->m = NULL;
> @@ -5999,48 +5995,45 @@ pf_route(struct pf_pdesc *pd, struct pf_
>  
>       ip = mtod(m0, struct ip *);
>  
> -     memset(&sin, 0, sizeof(sin));
> -     dst = &sin;
> -     dst->sin_family = AF_INET;
> -     dst->sin_len = sizeof(*dst);
> -     dst->sin_addr = ip->ip_dst;
> -     rtableid = m0->m_pkthdr.ph_rtableid;
> -
>       if (pd->dir == PF_IN) {
>               if (ip->ip_ttl <= IPTTLDEC) {
> -                     if (r->rt != PF_DUPTO)
> +                     if (s->rt != PF_DUPTO) {
>                               pf_send_icmp(m0, ICMP_TIMXCEED,
>                                   ICMP_TIMXCEED_INTRANS, 0,
> -                                 pd->af, r, pd->rdomain);
> +                                 pd->af, s->rule.ptr, pd->rdomain);
> +                     }
>                       goto bad;
>               }
>               ip->ip_ttl -= IPTTLDEC;
>       }
>  
> -     if (s == NULL) {
> -             memset(sns, 0, sizeof(sns));
> -             if (pf_map_addr(AF_INET, r,
> -                 (struct pf_addr *)&ip->ip_src,
> -                 &naddr, NULL, sns, &r->route, PF_SN_ROUTE)) {
> -                     DPFPRINTF(LOG_ERR,
> -                         "%s: pf_map_addr() failed", __func__);
> -                     goto bad;
> -             }
> +     memset(&sin, 0, sizeof(sin));
> +     dst = &sin;
> +     dst->sin_family = AF_INET;
> +     dst->sin_len = sizeof(*dst);
> +     dst->sin_addr = s->rt_addr.v4;
> +     rtableid = m0->m_pkthdr.ph_rtableid;
>  
> -             if (!PF_AZERO(&naddr, AF_INET))
> -                     dst->sin_addr.s_addr = naddr.v4.s_addr;
> -             ifp = r->route.kif ?
> -                 r->route.kif->pfik_ifp : NULL;
> -     } else {
> -             if (!PF_AZERO(&s->rt_addr, AF_INET))
> -                     dst->sin_addr.s_addr =
> -                         s->rt_addr.v4.s_addr;
> -             ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL;
> +     rt = rtalloc(sintosa(dst), RT_RESOLVE, rtableid);
> +     if (!rtisvalid(rt)) {
> +             if (s->rt != PF_DUPTO) {
> +                     pf_send_icmp(m0, ICMP_UNREACH, ICMP_UNREACH_HOST,
> +                         0, pd->af, s->rule.ptr, pd->rdomain);
> +             }
> +             ipstat_inc(ips_noroute);
> +             goto bad;
>       }
> +
> +     ifp = if_get(rt->rt_ifidx);
>       if (ifp == NULL)
>               goto bad;
>  
> -     if (r->rt != PF_DUPTO && pd->kif->pfik_ifp != ifp) {
> +     /* A locally generated packet may have invalid source address. */
> +     if ((ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET &&
> +         (ifp->if_flags & IFF_LOOPBACK) == 0)
> +             ip->ip_src = ifatoia(rt->rt_ifa)->ia_addr.sin_addr;
> +
> +     if (s->rt != PF_DUPTO && pd->kif->pfik_ifp != ifp) {
>               if (pf_test(AF_INET, PF_OUT, ifp, &m0) != PF_PASS)
>                       goto bad;
>               else if (m0 == NULL)
> @@ -6053,20 +6046,6 @@ pf_route(struct pf_pdesc *pd, struct pf_
>               ip = mtod(m0, struct ip *);
>       }
>  
> -     rt = rtalloc(sintosa(dst), RT_RESOLVE, rtableid);
> -     if (!rtisvalid(rt)) {
> -             if (r->rt != PF_DUPTO) {
> -                     pf_send_icmp(m0, ICMP_UNREACH, ICMP_UNREACH_HOST,
> -                         0, pd->af, s->rule.ptr, pd->rdomain);
> -             }
> -             ipstat_inc(ips_noroute);
> -             goto bad;
> -     }
> -     /* A locally generated packet may have invalid source address. */
> -     if ((ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET &&
> -         (ifp->if_flags & IFF_LOOPBACK) == 0)
> -             ip->ip_src = ifatoia(rt->rt_ifa)->ia_addr.sin_addr;
> -
>       in_proto_cksum_out(m0, ifp);
>  
>       if (ntohs(ip->ip_len) <= ifp->if_mtu) {
> @@ -6087,9 +6066,9 @@ pf_route(struct pf_pdesc *pd, struct pf_
>        */
>       if (ip->ip_off & htons(IP_DF)) {
>               ipstat_inc(ips_cantfrag);
> -             if (r->rt != PF_DUPTO)
> +             if (s->rt != PF_DUPTO)
>                       pf_send_icmp(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG,
> -                         ifp->if_mtu, pd->af, r, pd->rdomain);
> +                         ifp->if_mtu, pd->af, s->rule.ptr, pd->rdomain);
>               goto bad;
>       }
>  
> @@ -6113,6 +6092,7 @@ pf_route(struct pf_pdesc *pd, struct pf_
>               ipstat_inc(ips_fragmented);
>  
>  done:
> +     if_put(ifp);
>       rtfree(rt);
>       return;
>  
> @@ -6124,15 +6104,13 @@ bad:
>  #ifdef INET6
>  /* pf_route6() may change pd->m, adjust local copies after calling */
>  void
> -pf_route6(struct pf_pdesc *pd, struct pf_rule *r, struct pf_state *s)
> +pf_route6(struct pf_pdesc *pd, struct pf_state *s)
>  {
>       struct mbuf             *m0;
>       struct sockaddr_in6     *dst, sin6;
>       struct rtentry          *rt = NULL;
>       struct ip6_hdr          *ip6;
>       struct ifnet            *ifp = NULL;
> -     struct pf_addr           naddr;
> -     struct pf_src_node      *sns[PF_SN_MAX];
>       struct m_tag            *mtag;
>       unsigned int             rtableid;
>  
> @@ -6142,11 +6120,11 @@ pf_route6(struct pf_pdesc *pd, struct pf
>               return;
>       }
>  
> -     if (r->rt == PF_DUPTO) {
> +     if (s->rt == PF_DUPTO) {
>               if ((m0 = m_dup_pkt(pd->m, max_linkhdr, M_NOWAIT)) == NULL)
>                       return;
>       } else {
> -             if ((r->rt == PF_REPLYTO) == (r->direction == pd->dir))
> +             if ((s->rt == PF_REPLYTO) == (s->direction == pd->dir))
>                       return;
>               m0 = pd->m;
>               pd->m = NULL;
> @@ -6159,74 +6137,59 @@ pf_route6(struct pf_pdesc *pd, struct pf
>       }
>       ip6 = mtod(m0, struct ip6_hdr *);
>  
> -     memset(&sin6, 0, sizeof(sin6));
> -     dst = &sin6;
> -     dst->sin6_family = AF_INET6;
> -     dst->sin6_len = sizeof(*dst);
> -     dst->sin6_addr = ip6->ip6_dst;
> -     rtableid = m0->m_pkthdr.ph_rtableid;
> -
>       if (pd->dir == PF_IN) {
>               if (ip6->ip6_hlim <= IPV6_HLIMDEC) {
> -                     if (r->rt != PF_DUPTO)
> +                     if (s->rt != PF_DUPTO) {
>                               pf_send_icmp(m0, ICMP6_TIME_EXCEEDED,
>                                   ICMP6_TIME_EXCEED_TRANSIT, 0,
> -                                 pd->af, r, pd->rdomain);
> +                                 pd->af, s->rule.ptr, pd->rdomain);
> +                     }
>                       goto bad;
>               }
>               ip6->ip6_hlim -= IPV6_HLIMDEC;
>       }
>  
> -     if (s == NULL) {
> -             memset(sns, 0, sizeof(sns));
> -             if (pf_map_addr(AF_INET6, r, (struct pf_addr *)&ip6->ip6_src,
> -                 &naddr, NULL, sns, &r->route, PF_SN_ROUTE)) {
> -                     DPFPRINTF(LOG_ERR,
> -                         "%s: pf_map_addr() failed", __func__);
> -                     goto bad;
> -             }
> -             if (!PF_AZERO(&naddr, AF_INET6))
> -                     pf_addrcpy((struct pf_addr *)&dst->sin6_addr,
> -                         &naddr, AF_INET6);
> -             ifp = r->route.kif ? r->route.kif->pfik_ifp : NULL;
> -     } else {
> -             if (!PF_AZERO(&s->rt_addr, AF_INET6))
> -                     pf_addrcpy((struct pf_addr *)&dst->sin6_addr,
> -                         &s->rt_addr, AF_INET6);
> -             ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL;
> -     }
> -     if (ifp == NULL)
> -             goto bad;
> -
> -     if (r->rt != PF_DUPTO && pd->kif->pfik_ifp != ifp) {
> -             if (pf_test(AF_INET6, PF_OUT, ifp, &m0) != PF_PASS)
> -                     goto bad;
> -             else if (m0 == NULL)
> -                     goto done;
> -             if (m0->m_len < sizeof(struct ip6_hdr)) {
> -                     DPFPRINTF(LOG_ERR,
> -                         "%s: m0->m_len < sizeof(struct ip6_hdr)", __func__);
> -                     goto bad;
> -             }
> -     }
> +     memset(&sin6, 0, sizeof(sin6));
> +     dst = &sin6;
> +     dst->sin6_family = AF_INET6;
> +     dst->sin6_len = sizeof(*dst);
> +     dst->sin6_addr = s->rt_addr.v6;
> +     rtableid = m0->m_pkthdr.ph_rtableid;
>  
>       if (IN6_IS_SCOPE_EMBED(&dst->sin6_addr))
>               dst->sin6_addr.s6_addr16[1] = htons(ifp->if_index);
>       rt = rtalloc(sin6tosa(dst), RT_RESOLVE, rtableid);
>       if (!rtisvalid(rt)) {
> -             if (r->rt != PF_DUPTO) {
> +             if (s->rt != PF_DUPTO) {
>                       pf_send_icmp(m0, ICMP6_DST_UNREACH,
>                           ICMP6_DST_UNREACH_NOROUTE, 0,
>                           pd->af, s->rule.ptr, pd->rdomain);
> -             }
> +             }
>               ip6stat_inc(ip6s_noroute);
>               goto bad;
>       }
> +
> +     ifp = if_get(rt->rt_ifidx);
> +     if (ifp == NULL)
> +             goto bad;
> +
>       /* A locally generated packet may have invalid source address. */
>       if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src) &&
>           (ifp->if_flags & IFF_LOOPBACK) == 0)
>               ip6->ip6_src = ifatoia6(rt->rt_ifa)->ia_addr.sin6_addr;
>  
> +     if (s->rt != PF_DUPTO && pd->kif->pfik_ifp != ifp) {
> +             if (pf_test(AF_INET6, PF_OUT, ifp, &m0) != PF_PASS)
> +                     goto bad;
> +             else if (m0 == NULL)
> +                     goto done;
> +             if (m0->m_len < sizeof(struct ip6_hdr)) {
> +                     DPFPRINTF(LOG_ERR,
> +                         "%s: m0->m_len < sizeof(struct ip6_hdr)", __func__);
> +                     goto bad;
> +             }
> +     }
> +
>       in6_proto_cksum_out(m0, ifp);
>  
>       /*
> @@ -6239,13 +6202,14 @@ pf_route6(struct pf_pdesc *pd, struct pf
>               ifp->if_output(ifp, m0, sin6tosa(dst), rt);
>       } else {
>               ip6stat_inc(ip6s_cantfrag);
> -             if (r->rt != PF_DUPTO)
> +             if (s->rt != PF_DUPTO)
>                       pf_send_icmp(m0, ICMP6_PACKET_TOO_BIG, 0,
> -                         ifp->if_mtu, pd->af, r, pd->rdomain);
> +                         ifp->if_mtu, pd->af, s->rule.ptr, pd->rdomain);
>               goto bad;
>       }
>  
>  done:
> +     if_put(ifp);
>       rtfree(rt);
>       return;
>  
> @@ -7286,14 +7250,14 @@ done:
>               pd.m = NULL;
>               break;
>       default:
> -             if (r->rt) {
> +             if (s && s->rt) {
>                       switch (pd.af) {
>                       case AF_INET:
> -                             pf_route(&pd, r, s);
> +                             pf_route(&pd, s);
>                               break;
>  #ifdef INET6
>                       case AF_INET6:
> -                             pf_route6(&pd, r, s);
> +                             pf_route6(&pd, s);
>                               break;
>  #endif /* INET6 */
>                       }
> Index: sys/net/pfvar.h
> ===================================================================
> RCS file: /cvs/src/sys/net/pfvar.h,v
> retrieving revision 1.498
> diff -u -p -r1.498 pfvar.h
> --- sys/net/pfvar.h   12 Jan 2021 00:10:34 -0000      1.498
> +++ sys/net/pfvar.h   28 Jan 2021 11:45:58 -0000
> @@ -762,7 +762,6 @@ struct pf_state {
>       struct pf_sn_head        src_nodes;
>       struct pf_state_key     *key[2];        /* addresses stack and wire  */
>       struct pfi_kif          *kif;
> -     struct pfi_kif          *rt_kif;
>       u_int64_t                packets[2];
>       u_int64_t                bytes[2];
>       int32_t                  creation;
> @@ -797,6 +796,7 @@ struct pf_state {
>       u_int16_t                if_index_out;
>       pf_refcnt_t              refcnt;
>       u_int16_t                delay;
> +     u_int8_t                 rt;
>  };
>  
>  /*
> @@ -852,7 +852,7 @@ struct pfsync_state {
>       u_int8_t         proto;
>       u_int8_t         direction;
>       u_int8_t         log;
> -     u_int8_t         pad0;
> +     u_int8_t         rt;
>       u_int8_t         timeout;
>       u_int8_t         sync_flags;
>       u_int8_t         updates;
> @@ -1798,8 +1798,8 @@ int     pf_state_key_attach(struct pf_state_
>  int  pf_translate(struct pf_pdesc *, struct pf_addr *, u_int16_t,
>           struct pf_addr *, u_int16_t, u_int16_t, int);
>  int  pf_translate_af(struct pf_pdesc *);
> -void pf_route(struct pf_pdesc *, struct pf_rule *, struct pf_state *);
> -void pf_route6(struct pf_pdesc *, struct pf_rule *, struct pf_state *);
> +void pf_route(struct pf_pdesc *, struct pf_state *);
> +void pf_route6(struct pf_pdesc *, struct pf_state *);
>  void pf_init_threshold(struct pf_threshold *, u_int32_t, u_int32_t);
>  int  pf_delay_pkt(struct mbuf *, u_int);
>  

Reply via email to