Ticket #11 (new defect)
Network.listenOn (PortNumber n) Sometimes Picks IPv6
| Reported by: | tibbe | Owned by: | bos |
|---|---|---|---|
| Priority: | major | Milestone: | |
| Component: | network | Version: | |
| Keywords: | Cc: | pho@…, cjs@… |
Description
When I run the following program on a NetBSD system, it listens on *.4444 for IPv6, not IPv4. This could certainly happen on other operating systems as well, though I've not tested others. Whether it happens or not could even vary from release to release.
import IO
import Network
main = do
s <- listenOn (PortNumber 4444)
(h, hostName, portNum) <- Network.accept s
putStrLn $ "Connection from " ++ hostName ++ ":" ++ show portNum
hPutStrLn h "Bye!"
hClose h
I've verified that telnet 127.0.0.1 4444 produces a "connection refused" message, but telnet ::1 4444 connects and displays "Bye!"
I'd go so far to say that this is a bug. At best, one could argue that this behaviour is not entirely intuitive.
I propose that we (re-?)define PortID's PortNumber constructor to refer only to IPv4 protocol ports, and add a new PortNumber6 constructor for IPv6 ports.
Another option would be to do force PortNumber always to bind to IPv4, but not add PortNumber6. I prefer this less because we should be encouraging the use of IPv6, and because having PortNumber6 serves as obvious documentation for what PortNumber and PortNumber6 do.
A third option would be to attempt to listen on both IPv4 and IPv6, when both are available, but this sort of thing is fraught with many problems, the details of which are much more than I'd want to get into in this bug report.
I saw exactly the same problem on FreeBSD.
I propose that we (re-?)define PortID's PortNumber constructor to refer only to IPv4 protocol ports, and add a new PortNumber6 constructor for IPv6 ports.
That sounds highly reasonable. I prefer that way.
This sounds like a peculiarity of the BSD networking stack. On Linux, the code correctly chooses a wildcard address that responds to both IPv4 and IPv6 traffic.
I'd strongly suggest that a BSD user dig into the platform-specific problem. Suggesting an API change without any investigation of the underlying issue is not the right approach.
Actually, the linux code incorrectly binds to both; this opens up a security problem, though I can't remember the exact details right now. This is exactly the reason for the default sysctl setting of "net.inet6.ip6.v6only = 1", IIRC.
Here is a document discussing the security issues with IPv4-mapped addresses:
ftp://ftp.itojun.org/pub/paper/draft-itojun-v6ops-v4mapped-harmful-01.txt
I'd say we definitely don't want to have to force people to enable this just to use Network, which is in the end supposed to make life simpler for basic networking.
The Linux behaviour does not appear to me to be incorrect, and the document to which you refer is concerned with threats due to the use of IPv4-mapped addresses on the wire.
The code in the Network module uses the Network.Socket code for its implementation. There are currently several knobs for controlling getAddrInfo that it does not use. Perhaps if you read up on a few of them and try them out, you might find a behaviour that you could then propose as more desirable.
