EHOSTDOWN prevents firefox from retrying other addresses for making a connection

RESOLVED FIXED in 4.9.1

Status

NSPR
NSPR
P2
normal
RESOLVED FIXED
13 years ago
6 years ago

People

(Reporter: jinmei, Assigned: Phoenix)

Tracking

other
4.9.1
All
FreeBSD

Firefox Tracking Flags

(Not tracked)

Details

Attachments

(1 attachment)

(Reporter)

Description

13 years ago
User-Agent:       Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041210 Firefox/1.0
Build Identifier: Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041210 Firefox/1.0

Suppose that an web server has both IPv4 and IPv6 connectivity
(e.g., this is the case for www.kame.net).  When I tried to make an
HTTP connection to the server with my firefox 1.0 running on FreeBSD
5.3R and the attempt to make a connection over IPv6 failed with an
error of EHOSTDOWN, firefox gave up trying the IPv4 address of the
server, and I failed to get access to the web page even if I had IPv4
reachability to the server.


Reproducible: Always
Steps to Reproduce:
1. get an FreeBSD box to reproduce the problem.  Version 5.3 is
   preferred, but I believe you can also reproduce it on 4.x.
   Global IPv4 reachability should be necessary for the following
   steps, but there is no need for IPv6 connectivity.
2. install firefox from the FreeBSD ports collection
3. temporarily configure an IPv6 address on the FreeBSD box as
   follows:
   # ifconfig IFname inet6 2001:db8::1 prefixlen 64 alias
   (IFname should be replaced with a real interface name like "fxp0")
4. add the following (dummy) entries to /etc/hosts of the FreeBSD box:

   2001:db8::2 www.kame.net
   203.178.141.194 www.kame.net

5. invoke firefox, and try to visit http://www.kame.net/

Actual Results:  
firefox will first try to connect to the IPv6 address.  After trying
IPv6 neighbor discovery, the attempt of connect(2) will fail with an
error of EHOSTDOWN.  Then firefox will stop trying to make a
connection.


Expected Results:  
It should then try the IPv4 address (203.178.141.194), since it has
IPv4 connectivity (based on the above assumption).


The following patch to mozilla/nsprpub/pr/src/md/unix/unix_errors.c
seems to fix the problem.  I don't know why EHOSTDOWN is ignored in
this context, but as shown in this report, there are at least some
cases where EHOSTDOWN should not be regarded as a fatal error.  I also
believe a similar problem can happen for multiple IPv4 addresses.

One more note: if this patch makes sense, we'll probably need to
similar fixes under other mozilla/nsprpub/pr/src/md/*.  For example,
we'll need to add WSAEHOSTDOWN in addition to WSAEHOSTUNREACH for
win32.

--- unix_errors.c.orig	Fri Dec  3 21:29:37 2004
+++ unix_errors.c	Fri Dec  3 21:30:03 2004
@@ -109,6 +109,7 @@
             prError = PR_FILE_TOO_BIG_ERROR;
             break;
         case EHOSTUNREACH:
+	case EHOSTDOWN:
             prError = PR_HOST_UNREACHABLE_ERROR;
             break;
         case EINPROGRESS:

Comment 1

13 years ago
Darin, it may be better to fix this in the Networking
Library (Necko).  You recently fixed a similar problem
with EACCESS (when there is a firewall involved).
Rather than checking for the errors for which we should
retry other addresses, perhaps we should check for the
errors for which we should not retry other addresses?
Just a thought.
Assignee: wtchang → darin
Status: UNCONFIRMED → NEW
Ever confirmed: true

Updated

12 years ago
Assignee: darin → wtchang
QA Contact: wtchang → nspr
(Assignee)

Comment 2

6 years ago
Created attachment 600894 [details] [diff] [review]
Patch matching current source

Seems, issue still actual
Attachment #600894 - Flags: review?(ted.mielczarek)

Comment 3

6 years ago
Comment on attachment 600894 [details] [diff] [review]
Patch matching current source

r=wtc.
Attachment #600894 - Flags: review+

Comment 4

6 years ago
An alernative fix would be to add a new NSPR error code PR_HOST_DOWN_ERROR
(there is an PR_NETWORK_DOWN_ERROR) and map EHOSTDOWN to PR_HOST_DOWN_ERROR.

I found the relevant code in Necko.  The source file is
netwerk/base/src/nsSocketTransport2.cpp.

static nsresult
ErrorAccordingToNSPR(PRErrorCode errorCode)
{
    nsresult rv = NS_ERROR_FAILURE;
    switch (errorCode) {
    case PR_WOULD_BLOCK_ERROR:
        rv = NS_BASE_STREAM_WOULD_BLOCK;
        break;
    case PR_CONNECT_ABORTED_ERROR:
    case PR_CONNECT_RESET_ERROR:
        rv = NS_ERROR_NET_RESET;
        break;
    case PR_END_OF_FILE_ERROR: // XXX document this correlation
        rv = NS_ERROR_NET_INTERRUPT;
        break;
    case PR_CONNECT_REFUSED_ERROR:
    case PR_NETWORK_UNREACHABLE_ERROR: // XXX need new nsresult for this!
    case PR_HOST_UNREACHABLE_ERROR:    // XXX and this!
    case PR_ADDRESS_NOT_AVAILABLE_ERROR:
    // Treat EACCES as a soft error since (at least on Linux) connect() returns
    // EACCES when an IPv6 connection is blocked by a firewall. See bug 270784.
    case PR_ADDRESS_NOT_SUPPORTED_ERROR:
    case PR_NO_ACCESS_RIGHTS_ERROR:
        rv = NS_ERROR_CONNECTION_REFUSED;
        break;
    case PR_IO_TIMEOUT_ERROR:
    case PR_CONNECT_TIMEOUT_ERROR:
        rv = NS_ERROR_NET_TIMEOUT;
        break;
    default:
        if (IsNSSErrorCode(errorCode))
            rv = GetXPCOMFromNSSError(errorCode);
        break;
    }
    SOCKET_LOG(("ErrorAccordingToNSPR [in=%d out=%x]\n", errorCode, rv));
    return rv;
}

...

bool
nsSocketTransport::RecoverFromError()
{
    NS_ASSERTION(NS_FAILED(mCondition), "there should be something wrong");

    SOCKET_LOG(("nsSocketTransport::RecoverFromError [this=%x state=%x cond=%x]\n",
        this, mState, mCondition));

    // can only recover from errors in these states
    if (mState != STATE_RESOLVING && mState != STATE_CONNECTING)
        return false;

    nsresult rv;

    // OK to check this outside mLock
    NS_ASSERTION(!mFDconnected, "socket should not be connected");

    // can only recover from these errors
    if (mCondition != NS_ERROR_CONNECTION_REFUSED &&
        mCondition != NS_ERROR_PROXY_CONNECTION_REFUSED &&
        mCondition != NS_ERROR_NET_TIMEOUT &&
        mCondition != NS_ERROR_UNKNOWN_HOST &&
        mCondition != NS_ERROR_UNKNOWN_PROXY_HOST)
        return false;
    ...
}

We would need to add the new NSPR error code PR_HOST_DOWN_ERROR
to the switch statement in ErrorAccordingToNSPR.

Patch checked in on the NSPR trunk (NSPR 4.9.1).

Checking in unix_errors.c;
/cvsroot/mozilla/nsprpub/pr/src/md/unix/unix_errors.c,v  <--  unix_errors.c
new revision: 3.29; previous revision: 3.28
done
Status: NEW → RESOLVED
Last Resolved: 6 years ago
Priority: -- → P2
Hardware: x86 → All
Resolution: --- → FIXED
Target Milestone: --- → 4.9.1
Honza, just want to make sure you know about this in case it affects happy eyeballs.
Attachment #600894 - Flags: review?(ted.mielczarek)
Assignee: wtc → pppx
You need to log in before you can comment on or make changes to this bug.