1
- /* $OpenBSD: ip_icmp.c,v 1.200 2025/06/12 20:37:59 deraadt Exp $ */
1
+ /* $OpenBSD: ip_icmp.c,v 1.201 2025/06/20 05:08:07 dlg Exp $ */
2
2
/* $NetBSD: ip_icmp.c,v 1.19 1996/02/13 23:42:22 christos Exp $ */
3
3
4
4
/*
@@ -692,7 +692,8 @@ icmp_reflect(struct mbuf *m, struct mbuf **op, struct in_ifaddr *ia)
692
692
struct ip * ip = mtod (m , struct ip * );
693
693
struct mbuf * opts = NULL ;
694
694
struct sockaddr_in sin ;
695
- struct rtentry * rt = NULL ;
695
+ struct rtentry * rt ;
696
+ struct in_addr ip_src = { INADDR_ANY };
696
697
int optlen = (ip -> ip_hl << 2 ) - sizeof (struct ip );
697
698
u_int rtableid ;
698
699
u_int8_t pfflags ;
@@ -709,10 +710,6 @@ icmp_reflect(struct mbuf *m, struct mbuf **op, struct in_ifaddr *ia)
709
710
return (ELOOP );
710
711
}
711
712
rtableid = m -> m_pkthdr .ph_rtableid ;
712
- pfflags = m -> m_pkthdr .pf .flags ;
713
- m_resethdr (m );
714
- m -> m_pkthdr .ph_rtableid = rtableid ;
715
- m -> m_pkthdr .pf .flags = pfflags & PF_TAG_GENERATED ;
716
713
717
714
/*
718
715
* If the incoming packet was addressed directly to us,
@@ -726,42 +723,64 @@ icmp_reflect(struct mbuf *m, struct mbuf **op, struct in_ifaddr *ia)
726
723
sin .sin_addr = ip -> ip_dst ;
727
724
728
725
rt = rtalloc (sintosa (& sin ), 0 , rtableid );
729
- if (rtisvalid (rt ) &&
730
- ISSET (rt -> rt_flags , RTF_LOCAL |RTF_BROADCAST ))
731
- ia = ifatoia (rt -> rt_ifa );
732
- }
726
+ if (rtisvalid (rt )) {
727
+ if (ISSET (rt -> rt_flags , RTF_LOCAL ))
728
+ ip_src = ip -> ip_dst ;
729
+ else if (ISSET (rt -> rt_flags , RTF_BROADCAST )) {
730
+ ia = ifatoia (rt -> rt_ifa );
731
+ ip_src = ia -> ia_addr .sin_addr ;
732
+ }
733
+ }
734
+ rtfree (rt );
735
+ } else
736
+ ip_src = ia -> ia_addr .sin_addr ;
733
737
734
738
/*
735
739
* The following happens if the packet was not addressed to us.
736
- * Use the new source address and do a route lookup. If it fails
737
- * drop the packet as there is no path to the host .
740
+ * If we're directly connected use the closest address, otherwise
741
+ * try to use the sourceaddr from the routing table .
738
742
*/
739
- if (ia == NULL ) {
740
- rtfree (rt );
741
-
743
+ if (ip_src .s_addr == INADDR_ANY ) {
742
744
memset (& sin , 0 , sizeof (sin ));
743
745
sin .sin_len = sizeof (sin );
744
746
sin .sin_family = AF_INET ;
745
747
sin .sin_addr = ip -> ip_src ;
746
748
747
749
/* keep packet in the original virtual instance */
748
750
rt = rtalloc (sintosa (& sin ), RT_RESOLVE , rtableid );
749
- if (rt == NULL ) {
750
- ipstat_inc (ips_noroute );
751
- m_freem (m );
752
- return (EHOSTUNREACH );
751
+ if (rtisvalid (rt ) &&
752
+ ISSET (rt -> rt_flags , RTF_LLINFO |RTF_HOST )) {
753
+ ia = ifatoia (rt -> rt_ifa );
754
+ ip_src = ia -> ia_addr .sin_addr ;
755
+ } else {
756
+ struct sockaddr * sourceaddr ;
757
+ struct ifaddr * ifa ;
758
+
759
+ sourceaddr = rtable_getsource (rtableid , AF_INET );
760
+ if (sourceaddr != NULL ) {
761
+ ifa = ifa_ifwithaddr (sourceaddr , rtableid );
762
+ if (ifa != NULL &&
763
+ ISSET (ifa -> ifa_ifp -> if_flags , IFF_UP ))
764
+ ip_src = satosin (sourceaddr )-> sin_addr ;
765
+ }
753
766
}
754
-
755
- ia = ifatoia (rt -> rt_ifa );
767
+ rtfree (rt );
756
768
}
757
769
770
+ /*
771
+ * If the above didn't find an ip_src, ip_output() will try
772
+ * and fill it in for us.
773
+ */
774
+
775
+ pfflags = m -> m_pkthdr .pf .flags ;
776
+
777
+ m_resethdr (m );
778
+ m -> m_pkthdr .ph_rtableid = rtableid ;
779
+ m -> m_pkthdr .pf .flags = pfflags & PF_TAG_GENERATED ;
758
780
ip -> ip_dst = ip -> ip_src ;
781
+ ip -> ip_src = ip_src ;
759
782
ip -> ip_ttl = MAXTTL ;
760
783
761
- /* It is safe to dereference ``ia'' iff ``rt'' is valid. */
762
- ip -> ip_src = ia -> ia_addr .sin_addr ;
763
- rtfree (rt );
764
-
765
784
if (optlen > 0 ) {
766
785
u_char * cp ;
767
786
int opt , cnt ;
0 commit comments