this is the diff from the "pf route-to issues" thread, but on it's own.
the summary of why i wanted to do this is: - route-to, reply-to, and dup-to do not work with pfsync this is because the information about where to route-to is stored in rules, and it is hard to have a ruleset synced 100% between firewalls. - i can make my boxes panic when i try to use it in certain situations yeah... - the configuration and syntax for route-to rules are confusing. the argument to route-to and co is an interace name with an optional ip address. there are several problems with this. one is that people tend to think about routing as sending packets to peers by their address, not by the interface they're reachable on. another is that we currently have no way to synchronise interface topology information between firewalls, so using an interface to say where packets go means we can't do failover of these states with pfsync. another is that a change in routing topology means a host may become reachable over a different interface. tying routing policy to interfaces gets in the way of failover and load balancing. this change does the following: - stores the route info in the state instead of the pf rule this allows route-to to keep working when the ruleset changes, and allows route-to info to be sent over pfsync. there's enough spare bits in pfsync messages that the protocol doesnt break. the caveat is that route-to becomes tied to pass rules that create state, like rdr-to and nat-to. - the argument to route-to etc is a destination ip address it's not limited to a next-hop address (thought a next-hop can be a destination address). this allows for the failover and load balancing referred to above. - deprecates the address@interface host syntax in pfctl because routing is done entirely by IPs, the interface is derived from the route lookup, not pf. this change does not affect some other stuff discussed in the thread: - it keeps the current semantic where when route-to changes which interface the packet is travelling over, it runs pf_test again. that's a separate change for broader discussion. id like to thank sashan@, bluhm@, and sthen@ for working through this stuff with me. i've got a lot out of it so far. ok? 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);