Index: net/if_loop.c =================================================================== RCS file: /cvs/src/sys/net/if_loop.c,v diff -u -p -r1.98 if_loop.c --- net/if_loop.c 29 Dec 2023 11:43:04 -0000 1.98 +++ net/if_loop.c 27 Jul 2024 10:49:49 -0000 @@ -261,10 +261,10 @@ looutput(struct ifnet *ifp, struct mbuf if ((m->m_flags & M_PKTHDR) == 0) panic("%s: no header mbuf", __func__); - if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) { + if (rt != NULL && !ISSET(rt->rt_flags, RTF_LOCAL)) { m_freem(m); - return (rt->rt_flags & RTF_BLACKHOLE ? 0 : - rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); + return (ISSET(rt->rt_flags, RTF_HOST) ? + EHOSTUNREACH : ENETUNREACH); } /* Index: netinet/ip_icmp.c =================================================================== RCS file: /cvs/src/sys/netinet/ip_icmp.c,v diff -u -p -r1.196 ip_icmp.c --- netinet/ip_icmp.c 14 Jul 2024 18:53:39 -0000 1.196 +++ netinet/ip_icmp.c 27 Jul 2024 10:49:49 -0000 @@ -684,7 +684,8 @@ icmp_reflect(struct mbuf *m, struct mbuf struct ip *ip = mtod(m, struct ip *); struct mbuf *opts = NULL; struct sockaddr_in sin; - struct rtentry *rt = NULL; + struct rtentry *rt; + struct in_addr ip_src = { INADDR_ANY }; int optlen = (ip->ip_hl << 2) - sizeof(struct ip); u_int rtableid; u_int8_t pfflags; @@ -701,10 +702,6 @@ icmp_reflect(struct mbuf *m, struct mbuf return (ELOOP); } rtableid = m->m_pkthdr.ph_rtableid; - pfflags = m->m_pkthdr.pf.flags; - m_resethdr(m); - m->m_pkthdr.ph_rtableid = rtableid; - m->m_pkthdr.pf.flags = pfflags & PF_TAG_GENERATED; /* * If the incoming packet was addressed directly to us, @@ -718,41 +715,80 @@ icmp_reflect(struct mbuf *m, struct mbuf sin.sin_addr = ip->ip_dst; rt = rtalloc(sintosa(&sin), 0, rtableid); - if (rtisvalid(rt) && - ISSET(rt->rt_flags, RTF_LOCAL|RTF_BROADCAST)) - ia = ifatoia(rt->rt_ifa); - } + if (rtisvalid(rt)) { + if (ISSET(rt->rt_flags, RTF_LOCAL)) + ip_src = ip->ip_dst; + else if (ISSET(rt->rt_flags, RTF_BROADCAST)) { + ia = ifatoia(rt->rt_ifa); + ip_src = ia->ia_addr.sin_addr; + } + } + rtfree(rt); + } else + ip_src = ia->ia_addr.sin_addr; /* * The following happens if the packet was not addressed to us. - * Use the new source address and do a route lookup. If it fails - * drop the packet as there is no path to the host. + * If we're directly connected use the closest address, otherwise + * try to use the sourceaddr from the routing table. */ - if (ia == NULL) { - rtfree(rt); - + if (ip_src.s_addr == INADDR_ANY) { memset(&sin, 0, sizeof(sin)); sin.sin_len = sizeof(sin); sin.sin_family = AF_INET; sin.sin_addr = ip->ip_src; - /* keep packet in the original virtual instance */ - rt = rtalloc(sintosa(&sin), RT_RESOLVE, rtableid); - if (rt == NULL) { - ipstat_inc(ips_noroute); - m_freem(m); - return (EHOSTUNREACH); + rt = rtalloc_mpath(sintosa(&sin), &ip->ip_dst.s_addr, rtableid); + if (rtisvalid(rt) && + ISSET(rt->rt_flags, RTF_LLINFO|RTF_HOST)) { + ia = ifatoia(rt->rt_ifa); + ip_src = ia->ia_addr.sin_addr; + } else { + struct sockaddr *sourceaddr; + struct ifaddr *ifa; + + sourceaddr = rtable_getsource(rtableid, AF_INET); + if (sourceaddr != NULL) { + ifa = ifa_ifwithaddr(sourceaddr, rtableid); + if (ifa != NULL && + ISSET(ifa->ifa_ifp->if_flags, IFF_UP)) + ip_src = satosin(sourceaddr)->sin_addr; + } } + rtfree(rt); + } - ia = ifatoia(rt->rt_ifa); + /* + * If the above didn't find an ip_src, get the IP of the + * interface the original packet was received on. If all this + * comes up with nothing, ip_output() will try and fill it + * in for us. + */ + if (ip_src.s_addr == INADDR_ANY) { + struct ifnet *ifp; + struct ifaddr *ifa; + + ifp = if_get(m->m_pkthdr.ph_ifidx); + if (ifp != NULL) { + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { + if (ifa->ifa_addr->sa_family != AF_INET) + continue; + + ip_src = satosin(ifa->ifa_addr)->sin_addr; + break; + } + } + if_put(ifp); } + pfflags = m->m_pkthdr.pf.flags; + + m_resethdr(m); + m->m_pkthdr.ph_rtableid = rtableid; + m->m_pkthdr.pf.flags = pfflags & PF_TAG_GENERATED; ip->ip_dst = ip->ip_src; + ip->ip_src = ip_src; ip->ip_ttl = MAXTTL; - - /* It is safe to dereference ``ia'' iff ``rt'' is valid. */ - ip->ip_src = ia->ia_addr.sin_addr; - rtfree(rt); if (optlen > 0) { u_char *cp; Index: netinet/ip_output.c =================================================================== RCS file: /cvs/src/sys/netinet/ip_output.c,v diff -u -p -r1.401 ip_output.c --- netinet/ip_output.c 2 Jul 2024 18:33:47 -0000 1.401 +++ netinet/ip_output.c 27 Jul 2024 10:49:49 -0000 @@ -398,6 +398,20 @@ sendit: } #endif /* IPSEC */ + if (ro && ro->ro_rt) { + struct rtentry *rt = ro->ro_rt; + + if (ISSET(rt->rt_flags, RTF_REJECT)) { + error = ISSET(rt->rt_flags, RTF_HOST) ? + EHOSTUNREACH : ENETUNREACH; + goto bad; + } + if (ISSET(rt->rt_flags, RTF_BLACKHOLE)) { + error = 0; + goto bad; + } + } + /* * Packet filter */ Index: netinet6/ip6_output.c =================================================================== RCS file: /cvs/src/sys/netinet6/ip6_output.c,v diff -u -p -r1.292 ip6_output.c --- netinet6/ip6_output.c 4 Jul 2024 12:50:08 -0000 1.292 +++ netinet6/ip6_output.c 27 Jul 2024 10:49:49 -0000 @@ -483,9 +483,20 @@ reroute: route6_cache(ro, &ip6->ip6_dst, NULL, m->m_pkthdr.ph_rtableid); } - if (rt && (rt->rt_flags & RTF_GATEWAY) && - !IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) - dst = satosin6(rt->rt_gateway); + if (rt != NULL) { + if (ISSET(rt->rt_flags, RTF_REJECT)) { + error = ISSET(rt->rt_flags, RTF_HOST) ? + EHOSTUNREACH : ENETUNREACH; + goto bad; + } + if (ISSET(rt->rt_flags, RTF_BLACKHOLE)) { + error = 0; + goto bad; + } + if (ISSET(rt->rt_flags, RTF_GATEWAY) && + !IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) + dst = satosin6(rt->rt_gateway); + } if (!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { /* Unicast */