lpeterse / haskell-socket

A Haskell binding to the POSIX sockets API
MIT License
47 stars 10 forks source link

Interfacing with mapped Ipv4 doesn't work #58

Closed matheus23 closed 6 years ago

matheus23 commented 6 years ago

I currently seem to have issues working with mapped Ipv4 both on my local Computer running ArchLinux and my VPS running ubuntu 16.04.4 lts.

I'm having issues like not getting any Ipv4 addresses mapped into Ipv6 when running getAddressInfo:

> getAddressInfo (Just "haskell.org") (Just "80") aiV4Mapped :: IO [AddressInfo Inet6 Stream TCP]
[ AddressInfo 
    { addressInfoFlags = AddressInfoFlags 8
    , socketAddress = SocketAddressInet6 
        { inet6Address = Inet6Address 2001:4800:7817:0104:be76:4eff:fe04:f608
        , inet6Port = Inet6Port 80
        , inet6FlowInfo = Inet6FlowInfo 0
        , inet6ScopeId = Inet6ScopeId 0
        }
    , canonicalName = Nothing
    }
]
> getAddressInfo (Just "haskell.org") (Just "80") aiAll :: IO [AddressInfo Inet6 Stream TCP]     
[ AddressInfo 
    { addressInfoFlags = AddressInfoFlags 16
    , socketAddress = SocketAddressInet6 
        { inet6Address = Inet6Address 2001:4800:7817:0104:be76:4eff:fe04:f608
        , inet6Port = Inet6Port 80
        , inet6FlowInfo = Inet6FlowInfo 0
        , inet6ScopeId = Inet6ScopeId 0
        }
    , canonicalName = Nothing
    }
]
> getAddressInfo (Just "haskell.org") (Just "80") aiAll :: IO [AddressInfo Inet Stream TCP]      
[ AddressInfo 
    { addressInfoFlags = AddressInfoFlags 16
    , socketAddress = SocketAddressInet 
        {inetAddress = InetAddress 23.253.242.70
        , inetPort = InetPort 80
        }
    , canonicalName = Nothing
    }
]

As you can see, I can only get ipv4 address info when issuing the getAddressInfo command with the Inet family. I would have expected an ipv6 address ::ffff:23.253.242.70 to be listed in the first call.

I'm also having issues with receiving udp packets from real (non-ipv4-mapped) on my Inet6 socket bound to inet6Any, which seems really weird to me. Its hard to prove this to you with logs, but I double-checked that they did actually come in at my machine via inspection with wireshark. I'm really confused.

Also, all of the above seems to work fine with the "network" haskell package:

> getAddrInfo (Just defaultHints { addrSocketType = Stream, addrFlags = [AI_V4MAPPED] }) (Just "haskell.org") (Just "80")       
[ AddrInfo 
    { addrFlags = [AI_V4MAPPED]
    , addrFamily = AF_INET6
    , addrSocketType = Stream
    , addrProtocol = 6
    , addrAddress = [2001:4800:7817:104:be76:4eff:fe04:f608]:80
    , addrCanonName = Nothing
    }
, AddrInfo 
    { addrFlags = [AI_V4MAPPED]
    , addrFamily = AF_INET
    , addrSocketType = Stream
    , addrProtocol = 6
    , addrAddress = 23.253.242.70:80
    , addrCanonName = Nothing
    }
]

My workaround would be using the "network" package, but I would really miss API of socket!

lpeterse commented 6 years ago

Hi,

you need to specify AI_V4MAPPED and AI_ALL. Otherwise you'll only get mapped IPv4 addresses when no IPv6 addresses could be found.

Quote from man getaddrinfo:

If hints.ai_flags specifies the AI_V4MAPPED flag, and hints.ai_family
was specified as AF_INET6, and no matching IPv6 addresses could be
found, then return IPv4-mapped IPv6 addresses in the list pointed to
by res.  If both AI_V4MAPPED and AI_ALL are specified in
hints.ai_flags, then return both IPv6 and IPv4-mapped IPv6 addresses
in the list pointed to by res.  AI_ALL is ignored if AI_V4MAPPED is
not also specified.

Just tested on my machine:

getAddressInfo (Just "haskell.org") (Just "80") (aiV4Mapped `mappend` aiAll) :: IO [AddressInfo Inet6 Stream TCP]
[AddressInfo {
addressInfoFlags = AddressInfoFlags 24,
socketAddress = SocketAddressInet6 {inet6Address = Inet6Address 0000:0000:0000:0000:0000:ffff:17fd:f246, inet6Port = Inet6Port 80, inet6FlowInfo = Inet6FlowInfo 0, inet6ScopeId = Inet6ScopeId 0},
canonicalName = Nothing},
AddressInfo {
addressInfoFlags = AddressInfoFlags 24,
socketAddress = SocketAddressInet6 {inet6Address = Inet6Address 2001:4800:7817:0104:be76:4eff:fe04:f608, inet6Port = Inet6Port 80, inet6FlowInfo = Inet6FlowInfo 0, inet6ScopeId = Inet6ScopeId 0},
canonicalName = Nothing}]

I need to think a little about the second part of your question..

matheus23 commented 6 years ago

Thank you! It works with aiAll and aiV4Mapped! :+1:

Yes. That second part seems to be an issue for me still...

A little more context, this is how I build my local socket for receiving:

bindLocalSocket :: IO (Socket Inet6 Datagram UDP)
bindLocalSocket = do
  local <- socket :: IO (Socket Inet6 Datagram UDP)
  setSocketOption local (V6Only False)
  bind local (SocketAddressInet6 inet6Any 7075 0 0)
  return local

I have tried different settings for V6Only, none seem to work. I'll read my man setsockopt now, good idea for that!

matheus23 commented 6 years ago

Oh I'm sorry! The second issue is fixed for me. I was accidentally using the wrong socket for sending packets which resulted in upd packets coming in on the wrong port being filtered by my firewall. Whoops!

Thank you for your help :)