Index: sys/netinet/ip_fastfwd.c =================================================================== --- sys/netinet/ip_fastfwd.c +++ sys/netinet/ip_fastfwd.c @@ -136,6 +136,10 @@ mcopy->m_pkthdr.len = mcopy->m_len; m_copydata(m, 0, mcopy->m_len, mtod(mcopy, caddr_t)); + /* + * XXX A lot of this should be a pre-condition of whether to send + * a redirect in first place and not how to send it. + */ if (nh != NULL && ((nh->nh_flags & (NHF_REDIRECT|NHF_DEFAULT)) == 0)) { struct in_ifaddr *nh_ia = (struct in_ifaddr *)(nh->nh_ifa); @@ -198,7 +202,7 @@ { struct ip *ip; struct mbuf *m0 = NULL; - struct nhop_object *nh = NULL; + struct nhop_object *nh = NULL, *onh; struct route ro; struct sockaddr_in *dst; const struct sockaddr *gw; @@ -435,12 +439,33 @@ gw = (const struct sockaddr *)dst; /* - * Handle redirect case. + * Handle redirect case. Only send a redirect if: + * (a) redirects are not disabled, + * (b) packet goes out the same interface (partially flawed in case + * of ROUTE_MPATH and having multiple addresses of the same subnet + * on multiple interfaces but good enough as an abstraction), + * (c) we know how to reach the sender and the source address is + * directly connected to us [RFC792, p13], + * (d) the forwarding route was not created by a redirect, + * (e) the packet does not do IP source routing or having any other + * IP options (this case was handled already by ip_input() calling + * ip_dooptions() [RFC792, p13], + * (f) the resulting forwarding destination is not "This host on this + * network" [RFC1122, Section 3.2.1.3]. */ redest.s_addr = 0; + onh = fib4_lookup(M_GETFIB(m), ip->ip_src, 0, NHR_NONE, m->m_pkthdr.flowid); if (V_ipsendredirects && (nh->nh_ifp == m->m_pkthdr.rcvif) && - gw->sa_family == AF_INET) + onh != NULL && (onh->nh_flags & NHF_GATEWAY) == 0 && + (nh->nh_flags & NHF_REDIRECT) == 0 && + gw->sa_family == AF_INET) { mcopy = ip_redir_alloc(m, nh, ip, &redest.s_addr); + if (mcopy != NULL && redest.s_addr == 0) { + /* Do not redirect to 0.0.0.0. */ + m_freem(mcopy); + mcopy = NULL; + } + } /* * Check if packet fits MTU or if hardware will fragment for us Index: sys/netinet/ip_input.c =================================================================== --- sys/netinet/ip_input.c +++ sys/netinet/ip_input.c @@ -560,8 +560,9 @@ /* * Try to forward the packet, but if we fail continue. - * ip_tryforward() does not generate redirects, so fall - * through to normal processing if redirects are required. + * ip_tryforward() may generate redirects these days. + * XXX the logic below falling through to normal processing + * if redirects are required should be revisited as well. * ip_tryforward() does inbound and outbound packet firewall * processing. If firewall has decided that destination becomes * our local address, it sets M_FASTFWD_OURS flag. In this @@ -574,6 +575,10 @@ IPSEC_CAPS(ipv4, m, IPSEC_CAP_OPERABLE) == 0) #endif ) { + /* + * ip_dooptions() was run so we can ignore the source route (or + * any IP options case) case for redirects in ip_tryforward(). + */ if ((m = ip_tryforward(m)) == NULL) return; if (m->m_flags & M_FASTFWD_OURS) {