Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/netinet Pick source address for ICMP errors a bit more i...



details:   https://anonhg.NetBSD.org/src/rev/99296dee0174
branches:  trunk
changeset: 481288:99296dee0174
user:      sommerfeld <sommerfeld%NetBSD.org@localhost>
date:      Tue Jan 25 17:07:56 2000 +0000

description:
Pick source address for ICMP errors a bit more intelligently when
there are multiple addresses on the interface.

>From Marc Horowitz <marc%netbsd.org@localhost>, who left this sitting for too long.

diffstat:

 sys/netinet/ip_icmp.c |  85 ++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 71 insertions(+), 14 deletions(-)

diffs (145 lines):

diff -r 86e85e93f316 -r 99296dee0174 sys/netinet/ip_icmp.c
--- a/sys/netinet/ip_icmp.c     Tue Jan 25 17:02:43 2000 +0000
+++ b/sys/netinet/ip_icmp.c     Tue Jan 25 17:07:56 2000 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ip_icmp.c,v 1.38 1999/07/09 22:57:18 thorpej Exp $     */
+/*     $NetBSD: ip_icmp.c,v 1.39 2000/01/25 17:07:56 sommerfeld Exp $  */
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -125,6 +125,7 @@
 #include <netinet/ip.h>
 #include <netinet/ip_icmp.h>
 #include <netinet/ip_var.h>
+#include <netinet/in_pcb.h>
 #include <netinet/icmp_var.h>
 
 #ifdef IPSEC
@@ -535,6 +536,7 @@
        register struct ip *ip = mtod(m, struct ip *);
        register struct in_ifaddr *ia;
        register struct ifaddr *ifa;
+       struct sockaddr_in *sin = 0;
        struct in_addr t;
        struct mbuf *opts = 0;
        int optlen = (ip->ip_hl << 2) - sizeof(struct ip);
@@ -548,51 +550,106 @@
        t = ip->ip_dst;
        ip->ip_dst = ip->ip_src;
        /*
-        * If the incoming packet was addressed directly to us,
-        * use dst as the src for the reply.  Otherwise (broadcast
-        * or anonymous), use the address which corresponds
-        * to the incoming interface.
+        * If the incoming packet was addressed directly to us, use
+        * dst as the src for the reply.  Otherwise (broadcast or
+        * anonymous), use an address which corresponds to the
+        * incoming interface, with a preference for the address which
+        * corresponds to the route to the destination of the ICMP.
         */
+
+       /* Look for packet addressed to us */
        INADDR_TO_IA(t, ia);
+
+       /* look for packet sent to broadcast address */
        if (ia == NULL && (m->m_pkthdr.rcvif->if_flags & IFF_BROADCAST)) {
                for (ifa = m->m_pkthdr.rcvif->if_addrlist.tqh_first;  
                    ifa != NULL; ifa = ifa->ifa_list.tqe_next) {
                        if (ifa->ifa_addr->sa_family != AF_INET)
                                continue;
-                       ia = ifatoia(ifa);
-                       if (in_hosteq(t, ia->ia_broadaddr.sin_addr))
+                       if (in_hosteq(t,ifatoia(ifa)->ia_broadaddr.sin_addr)) {
+                               ia = ifatoia(ifa);
                                break;
+                       }
                }
        }
 
+       if (ia)
+               sin = &ia->ia_addr;
+
        icmpdst.sin_addr = t;
-       if (ia == (struct in_ifaddr *)0)
-               ia = ifatoia(ifaof_ifpforaddr(sintosa(&icmpdst),
-                   m->m_pkthdr.rcvif));
+
+       /* if the packet is addressed somewhere else, compute the
+          source address for packets routed back to the source, and
+          use that, if it's an address on the interface which
+          received the packet */
+       if (sin == (struct sockaddr_in *)0) {
+               struct sockaddr_in sin_dst;
+               struct route icmproute;
+               int errornum;
+
+               sin_dst.sin_family = AF_INET;
+               sin_dst.sin_len = sizeof(struct sockaddr_in);
+               sin_dst.sin_addr = ip->ip_dst;
+               bzero(&icmproute, sizeof(icmproute));
+               errornum = 0;
+               sin = in_selectsrc(&sin_dst, &icmproute, 0, NULL, &errornum);
+               /* errornum is never used */
+               if (icmproute.ro_rt)
+                       RTFREE(icmproute.ro_rt);
+               /* check to make sure sin is a source address on rcvif */
+               if (sin) {
+                       t = sin->sin_addr;
+                       sin = (struct sockaddr_in *)0;
+                       INADDR_TO_IA(t, ia);
+                       while (ia) {
+                               if (ia->ia_ifp == m->m_pkthdr.rcvif) {
+                                       sin = &ia->ia_addr;
+                                       break;
+                               }
+                               NEXT_IA_WITH_SAME_ADDR(ia);
+                       }
+               }
+       }
+
+       /* if it was not addressed to us, but the route doesn't go out
+          the source interface, pick an address on the source
+          interface.  This can happen when routing is asymmetric, or
+          when the incoming packet was encapsulated */
+       if (sin == (struct sockaddr_in *)0) {
+               for (ifa = m->m_pkthdr.rcvif->if_addrlist.tqh_first;  
+                    ifa != NULL; ifa = ifa->ifa_list.tqe_next) {
+                       if (ifa->ifa_addr->sa_family != AF_INET)
+                               continue;
+                       sin = &(ifatoia(ifa)->ia_addr);
+                       break;
+               }
+       }
+
        /*
         * The following happens if the packet was not addressed to us,
         * and was received on an interface with no IP address:
         * We find the first AF_INET address on the first non-loopback
         * interface.
         */
-       if (ia == (struct in_ifaddr *)0)
+       if (sin == (struct sockaddr_in *)0)
                for (ia = in_ifaddr.tqh_first; ia != NULL;
                    ia = ia->ia_list.tqe_next) {
                        if (ia->ia_ifp->if_flags & IFF_LOOPBACK)
                                continue;
+                       sin = &ia->ia_addr;
                        break;
                }
+
        /*
         * If we still didn't find an address, punt.  We could have an
         * interface up (and receiving packets) with no address.
         */
-       if (ia == (struct in_ifaddr *)0) {
+       if (sin == (struct sockaddr_in *)0) {
                m_freem(m);
                goto done;
        }
 
-       t = ia->ia_addr.sin_addr;
-       ip->ip_src = t;
+       ip->ip_src = sin->sin_addr;
        ip->ip_ttl = MAXTTL;
 
        if (optlen > 0) {



Home | Main Index | Thread Index | Old Index