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: