diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -8648,14 +8648,13 @@ struct mbuf *m0, *m1, *md; struct sockaddr_in dst; struct ip *ip; - struct ifnet *ifp; + struct ifnet *ifp = NULL; int error = 0; uint16_t ip_len, ip_off; uint16_t tmp; int r_dir; - KASSERT(m && *m && r && oifp && pd->act.rt_kif, - ("%s: invalid parameters", __func__)); + KASSERT(m && *m && r && oifp, ("%s: invalid parameters", __func__)); SDT_PROBE4(pf, ip, route_to, entry, *m, pd, s, oifp); @@ -8678,12 +8677,8 @@ goto bad_locked; } - if ((ifp = pd->act.rt_kif->pfik_ifp) == NULL) { - m0 = *m; - *m = NULL; - SDT_PROBE1(pf, ip, route_to, drop, __LINE__); - goto bad_locked; - } + if (pd->act.rt_kif != NULL) + ifp = pd->act.rt_kif->pfik_ifp; if (pd->act.rt == PF_DUPTO) { if ((pd->pf_mtag->flags & PF_MTAG_FLAG_DUPLICATED)) { @@ -8733,9 +8728,31 @@ s->orig_kif = oifp->if_pf_kif; } + if (ifp == NULL && (pd->af != pd->naf)) { + /* We're in the AFTO case. Do a route lookup. */ + struct nhop_object *nh; + nh = fib4_lookup(M_GETFIB(*m), ip->ip_dst, 0, NHR_NONE, 0); + if (nh) { + ifp = nh->nh_ifp; + + /* Use the gateway if needed. */ + if (nh->nh_flags & NHF_GATEWAY) + dst.sin_addr = nh->gw4_sa.sin_addr; + else + dst.sin_addr = ip->ip_dst; + } + } + PF_STATE_UNLOCK(s); } + if (ifp == NULL) { + m0 = *m; + *m = NULL; + SDT_PROBE1(pf, ip, route_to, drop, __LINE__); + goto bad; + } + if (pd->dir == PF_IN) { if (pf_test(AF_INET, PF_OUT, PFIL_FWD, ifp, &m0, inp, &pd->act) != PF_PASS) { @@ -8887,8 +8904,7 @@ struct ifnet *ifp = NULL; int r_dir; - KASSERT(m && *m && r && oifp && pd->act.rt_kif, - ("%s: invalid parameters", __func__)); + KASSERT(m && *m && r && oifp, ("%s: invalid parameters", __func__)); SDT_PROBE4(pf, ip6, route_to, entry, *m, pd, s, oifp); @@ -8911,12 +8927,8 @@ goto bad_locked; } - if ((ifp = pd->act.rt_kif->pfik_ifp) == NULL) { - m0 = *m; - *m = NULL; - SDT_PROBE1(pf, ip6, route_to, drop, __LINE__); - goto bad_locked; - } + if (pd->act.rt_kif != NULL) + ifp = pd->act.rt_kif->pfik_ifp; if (pd->act.rt == PF_DUPTO) { if ((pd->pf_mtag->flags & PF_MTAG_FLAG_DUPLICATED)) { @@ -8965,9 +8977,32 @@ s->kif = pd->act.rt_kif; s->orig_kif = oifp->if_pf_kif; } + + if (ifp == NULL && (pd->af != pd->naf)) { + struct nhop_object *nh; + nh = fib6_lookup(M_GETFIB(*m), &ip6->ip6_dst, 0, NHR_NONE, 0); + if (nh) { + ifp = nh->nh_ifp; + + /* Use the gateway if needed. */ + if (nh->nh_flags & NHF_GATEWAY) + bcopy(&dst.sin6_addr, &nh->gw6_sa.sin6_addr, + sizeof(dst.sin6_addr)); + else + dst.sin6_addr = ip6->ip6_dst; + } + } + PF_STATE_UNLOCK(s); } + if (ifp == NULL) { + m0 = *m; + *m = NULL; + SDT_PROBE1(pf, ip6, route_to, drop, __LINE__); + goto bad; + } + if (pd->dir == PF_IN) { if (pf_test(AF_INET6, PF_OUT, PFIL_FWD | PF_PFIL_NOREFRAGMENT, ifp, &m0, inp, &pd->act) != PF_PASS) {