Closed Bug 136913 Opened 23 years ago Closed 3 years ago

PR_Bind() to PR_IpAddrLoopback fails if IPv6 not available

Categories

(NSPR :: NSPR, defect, P1)

Sun
SunOS
defect

Tracking

(Not tracked)

RESOLVED WONTFIX

People

(Reporter: mcs, Unassigned)

References

(Blocks 1 open bug)

Details

Attachments

(1 file)

Calls to PR_Bind() with an IPv6 address based on PR_IpAddrLoopback fail on Solaris machines where IPv6 is not available. On a Solaris 2.6 machine (which does not support IPv6 at all), the error is PR_NETWORK_UNREACHABLE_ERROR. On a Solaris 8 machine that has no IPv6 interfaces configured, the error is PR_ADDRESS_NOT_AVAILABLE_ERROR. On a Solaris 8 machine that has IPv6 interfaces, it works fine. I will attach a program that demonstrates the problem. Perhaps this is not supposed to work. But then how can I write portable code that will work regardless of whether IPv6 is configured?
Attached file simple test program
I did some debugging inside NSPR. Two cases: *** Case 1: On a Solaris 8 machine without an IPv6 interface, the call stack looks like this: bind() // system call pt_Bind() PR_Bind() main() The problem is that bind() is called with a PR_AF_INET6 address. But shouldn't the code path be: bind() pt_Bind() Ipv6ToIpv4SocketBind() // conversion layer PR_Bind() main() ? I set a breakpoint in _pr_init_ipv6() and found that it sets _pr_ipv6_is_present to PR_TRUE. That seems wrong. But it looks like the socket() call made inside _pr_test_ipv6_socket() returns a valid socket. So maybe the IPv6 detection code does not work correctly? *** Case 2: Solaris 2.6 (libc/OS does not support IPv6) I don't have a NSPR build with source code available right now on a Solaris 2.6 machine, but truss shows that the bind() system call is never called. The stack probably looks like this: Ipv6ToIpv4SocketBind() // conversion layer PR_Bind() main() because there is code in Ipv6ToIpv4SocketBind() that checks the address and returns PR_NETWORK_UNREACHABLE_ERROR: if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) || PR_IsNetAddrType(addr, PR_IpAddrAny)) { _PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr); tmp_addrp = &tmp_ipv4addr; } else { PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0); return PR_FAILURE; } I think the basic question is whether it is safe to change NSPR to have a special case for PR_IpAddrLoopback addresses. Functions like Ipv6ToIpv4SocketConnect() already do. Note that if the IPv6 detection was fixed to improve the behavior in case 1, then I would run into this problem (case 2) on Solaris 8 anyway.
This is a known problem. It's time for me to resolve it. > But then how can I write portable code that will work > regardless of whether IPv6 is configured? Maybe you can try binding your IPv6 socket to ::1 (the IPv6 loopback address) first. If it fails, then try binding to ::ffff:127.0.0.1 (the IPv4 loopback address in IPv4-mapped IPv6 address format). (You would need the PR_ConvertIPv4AddrToIPv6 function.) It is not clear whether on an IPv4/IPv6 dual-stack system PR_Bind should automatically retry with ::ffff:127.0.0.1 if the bind to ::1 fails, and whether on an IPv4-only system PR_Bind should automatically convert ::1 to 127.0.0.1. What do you guys think?
Status: NEW → ASSIGNED
Priority: -- → P1
Target Milestone: --- → 4.2.1
I don't know. Is the IPv6 loopback separate from the IPv4 one? It seems like maybe it is on Solaris. So perhaps I just need to change my code to do something different.
Mark, The IPv6 loopback address is separate from the IPv4 one. By default, Solaris 8 systems have an IPv6 stack but not the IPv6 loopback address. NSPR's IPv6 detection code detects the ability to open an AF_INET6 socket. This is why NSPR considers Solaris 8 IPv6 enabled even though the IPv6 loopback address may not exist. On second thought, I think it is not a good idea to automatically convert ::1 to 127.0.0.1 or fall back on ::ffff:127.0.0.1. I think we should treat ::1 and 127.0.0.1 (or ::ffff:127.0.0.1) as two different addresses. That is, I want each application to decide whether they want 1. ::1 only; or 2. ::ffff:127.0.0.1 only; or 3. ::1 or ::ffff:127.0.0.1 when they want to bind an IPv6 NSPR socket to the "loopback address". This is actually what is currently implemented in NSPR.
On a dual-stack system, if you listen to ::1 I believe you would (also) get connections to 127.0.0.1. Could someone test this?
It doesn't work this way in NES 6.x. If I specify the listen address to be ::1 then it only listens on ::1, not 127.0.0.1 as well.
Ok, they're different addresses then. It's just ::0 and ::FFFF:0.0.0.0 that have the near equivalence.
Right now NSPR treats ::0 as a superset of ::ffff:0.0.0.0. NSPR treats ::1 as distinct from ::ffff:127.0.0.1 in PR_Bind but treats them as equivalent in PR_Connect and PR_SendTo on IPv4-only systems. Should we fix this inconsistency? Should PR_Connect and PR_SendTo treat ::1 and ::ffff:127.0.0.1 as different addresses too?
It would be good to fix the inconsistency.
I agree -- we should fix the inconsistency. The inconsistency is what led me to file this bug, because (being somewhat naive about the behavior of dual stack systems) I did not realize that the IPv6 loopback and the IPv4 loopback were entirely separate (I knew they were implemented as separate network interfaces on Solaris, so I should've realized). Is the IPv6 detection problem I described in case 1 a bug? In the particular code I am working on, it not longer matters as much to me because I have now seen the light and I don't expect a listen on ::1 to work on a machine where the IPv6 loopback is not present. But it seems like the IPv6 detection problem might cause other problems... but it could be "as designed."
Mark, Actually, "ifconfig -a" on a Solaris 8 system with the IPv6 loopback report both the IPv4 loopback and the IPv6 loopback on the same network interface (lo0): lo0: flags=1000849<UP,LOOPBACK,RUNNING,MULTICAST,IPv4> mtu 8232 index 1 inet 127.0.0.1 netmask ff000000 hme0: flags=1000843<UP,BROADCAST,RUNNING,MULTICAST,IPv4> mtu 1500 index 2 inet 10.169.36.144 netmask ffffff80 broadcast 10.169.36.255 lo0: flags=2000849<UP,LOOPBACK,RUNNING,MULTICAST,IPv6> mtu 8252 index 1 inet6 ::1/128 hme0: flags=2000841<UP,RUNNING,MULTICAST,IPv6> mtu 1500 index 2 inet6 fe80::a00:20ff:feae:460d/10 The IPv6 detection that you described in case 1, comment #2 is not a bug. NSPR is detecting whether the IPv6 socket extension is present.
Thanks for the clarifications Wan-Teh. I will leave it to you to close this bug (I am not sure if you want to open a different one to track the consistency issue with PR_Bind(), PR_Connect(), and PR_SendTo().
Blocks: IPv6
QA Contact: wtchang → nspr
The target milestone is already released. Resetting target milestone.
Target Milestone: 4.2.1 → ---
This assigned "P1" bug is 5 years old. Maybe it's not really P1?
Definitely not a P1. Maybe this should be closed as "Won't Fix?"

The bug assignee didn't login in Bugzilla in the last 7 months.
:KaiE, could you have a look please?
For more information, please visit auto_nag documentation.

Assignee: wtc → nobody
Status: ASSIGNED → NEW
Flags: needinfo?(kaie)
Status: NEW → RESOLVED
Closed: 3 years ago
Flags: needinfo?(kaie)
Resolution: --- → WONTFIX
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: