Subject: kern/15735: ipip recursion.
To: None <gnats-bugs@gnats.netbsd.org>
From: None <seanb@qnx.com>
List: netbsd-bugs
Date: 02/25/2002 12:28:32
>Number:         15735
>Category:       kern
>Synopsis:       ipip recursion.
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Mon Feb 25 12:28:01 PST 2002
>Closed-Date:
>Last-Modified:
>Originator:     Sean Boudreau
>Release:        1-5
>Organization:
QNX
>Environment:
NetBSD fili 1.5.1 NetBSD 1.5.1 (ker.xtang)
>Description:
If ipip's route is deleted out from under it,
ip_output()can re-calculate specific route to
itself.
>How-To-Repeat:
On 'fresh' system.

#ifconfig ex0 10.25
#route add default 10.7.0.36
#ifconfig ipip0 11.1 11.2
#route delete default
#ping 11.2
<boom>
>Fix:
Add check for recursion in ipip_output().  Also notice
I'm failing the SIOCSIFADDR immediately with EHOSTUNREACH
if the route can't be calculated.  This seems to make more
sense than letting it succeed but in a non usable state
due to 0 mtu and getting EMSGSIZE some time later from
ip_output() (what does EMSGSIZE have to do with a failed
route?).

Index: netinet/ip_ipip.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/ip_ipip.c,v
retrieving revision 1.10
diff -c -r1.10 ip_ipip.c
*** ip_ipip.c   2000/04/19 06:30:55     1.10
--- ip_ipip.c   2002/02/25 19:58:23
***************
*** 80,86 ****
  int   ipip_output __P((struct ifnet *, struct mbuf *, struct sockaddr *,
            struct rtentry *));
  int   ipip_ioctl __P((struct ifnet *, u_long, caddr_t));
! void  ipip_compute_route __P((struct ipip_softc *));

  extern struct protosw ipip_protosw;

--- 80,86 ----
  int   ipip_output __P((struct ifnet *, struct mbuf *, struct sockaddr *,
            struct rtentry *));
  int   ipip_ioctl __P((struct ifnet *, u_long, caddr_t));
! static struct rtentry *       ipip_compute_route __P((struct ipip_softc *));

  extern struct protosw ipip_protosw;

***************
*** 217,231 ****
  }

  int
! ipip_output(ifp, m0, dst, rt)
        struct ifnet *ifp;
        struct mbuf *m0;
        struct sockaddr *dst;
!       struct rtentry *rt;
  {
        struct ipip_softc *sc = ifp->if_softc;
        struct ip *nip, *ip;
        int error;

        if (dst->sa_family != AF_INET) {
                IF_DROP(&ifp->if_snd);
--- 217,232 ----
  }

  int
! ipip_output(ifp, m0, dst, rt0)
        struct ifnet *ifp;
        struct mbuf *m0;
        struct sockaddr *dst;
!       struct rtentry *rt0;
  {
        struct ipip_softc *sc = ifp->if_softc;
        struct ip *nip, *ip;
        int error;
+       struct rtentry *rt;

        if (dst->sa_family != AF_INET) {
                IF_DROP(&ifp->if_snd);
***************
*** 233,238 ****
--- 234,263 ----
                return (EAFNOSUPPORT);
        }

+       if ((rt = sc->sc_route.ro_rt) != NULL && rt->rt_ifp->if_output == ipip_output) {
+               /* ip_output() calculated specific route to ourselves. Undo and retry */
+               RTFREE(rt);
+               sc->sc_route.ro_rt = NULL;
+       }
+
+       if (sc->sc_route.ro_rt == NULL) {
+               if ((rt = ipip_compute_route(sc)) == NULL) {
+                       IF_DROP(&ifp->if_snd);
+                       m_freem(m0);
+                       return (EHOSTUNREACH);
+               }
+
+               /* Reset our mtu */
+               ifp->if_mtu = rt->rt_ifp->if_mtu - ifp->if_hdrlen;
+
+               if (ifp->if_mtu < m0->m_pkthdr.len) {
+                       IF_DROP(&ifp->if_snd);
+                       m_freem(m0);
+                       return (EMSGSIZE);
+               }
+       }
+
+
        ip = mtod(m0, struct ip *);

        /* Add the new IP header. */
***************
*** 296,312 ****
                if (!in_nullhost(sc->sc_src) && !in_nullhost(sc->sc_dst)) {
                        struct rtentry *rt;

-                       ipip_compute_route(sc);
                        /*
                         * Now that we know the route to use, fill in the
                         * MTU.
                         */
!                       rt = sc->sc_route.ro_rt;
!                       if (rt != NULL) {
                                ifp->if_mtu = rt->rt_ifp->if_mtu -
                                              ifp->if_hdrlen;
                                ifp->if_flags |= IFF_UP;
                        }
                }
                break;

--- 321,338 ----
                if (!in_nullhost(sc->sc_src) && !in_nullhost(sc->sc_dst)) {
                        struct rtentry *rt;

                        /*
                         * Now that we know the route to use, fill in the
                         * MTU.
                         */
!                       if ((rt = ipip_compute_route(sc)) != NULL) {
                                ifp->if_mtu = rt->rt_ifp->if_mtu -
                                              ifp->if_hdrlen;
                                ifp->if_flags |= IFF_UP;
                        }
+                       else {
+                               error = EHOSTUNREACH;
+                       }
                }
                break;

***************
*** 318,326 ****
                        if (sc->sc_route.ro_rt == NULL) {
                                struct rtentry *rt;

!                               ipip_compute_route(sc);
!                               rt = sc->sc_route.ro_rt;
!                               if (rt != NULL)
                                        ifp->if_mtu = rt->rt_ifp->if_mtu -
                                                      ifp->if_hdrlen;
                                else
--- 344,350 ----
                        if (sc->sc_route.ro_rt == NULL) {
                                struct rtentry *rt;

!                               if ((rt = ipip_compute_route(sc)) != NULL)
                                        ifp->if_mtu = rt->rt_ifp->if_mtu -
                                                      ifp->if_hdrlen;
                                else
***************
*** 370,376 ****
   * Compute a less-specific route to the destination such that ip_output()
   * will not loop the packet back to ipip_output().
   */
! void
  ipip_compute_route(sc)
        struct ipip_softc *sc;
  {
--- 394,400 ----
   * Compute a less-specific route to the destination such that ip_output()
   * will not loop the packet back to ipip_output().
   */
! static struct rtentry *
  ipip_compute_route(sc)
        struct ipip_softc *sc;
  {
***************
*** 403,406 ****
--- 427,431 ----
         * the route and find the one for the ipip interface.
         */
        ((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->sc_dst;
+       return (ro->ro_rt);
  }

>Release-Note:
>Audit-Trail:
>Unformatted: