Raw sockets in Haskell

haskell, networking, sockets, unix

Solution

Network.Pcap can be used to send and receive raw data.

import qualified Data.ByteString.Char8 as B
import Network.Pcap

main = do
    -- open device
    dev <- openLive "lo" 65535 False 0
    setFilter dev "ether proto 0xFFFF" True 0

    -- send
    sendPacketBS dev (B.pack "\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\255\255Hello, World!")

    -- receive
    loopBS dev (-1) (\_ packet -> putStrLn (show packet))

Problem

There is a raw socket type provided in Network.Socket, but near binding sockets there is a comment "Currently only Unix domain sockets and the Internet families are supported". How can I use raw sockets in haskell? What I am trying to achieve, as working Python code: ``` import binascii import socket # Create raw socket. ethType = b'FFFF' # 2 bytes, has to be >= 0x0600. FFFF is "unavailable" by IEEE. sock = socket.socket(socket.AF_PACKET, socket.SOCK_RAW) sock.bind( ('lo', int(ethType,16)) ) # Create packet. srcMac = b'000000000000' # 6 bytes destMac = b'000000000000' # 6 bytes header = binascii.a2b_hex( destMac + srcMac + ethType ) # 14 bytes message = b'Hello, World!' sock.send(header + message) # Receive such packets while True: print (sock.recv(65535)) ``` EDIT1: In Haskell, I use `sock <- socket AF_PACKET Raw 0xFFFF` to create a socket, but `bindSocket` requires a `SockAddr` as an argument, for which available constructors are ``` SockAddrInet PortNumber HostAddress SockAddrInet6 PortNumber FlowInfo HostAddress6 ScopeID SockAddrUnix String ``` but none of these seems right. EDIT2: Thanks to a comment by Yuras I got receiving packets to work: ``` import Network.Socket sock <- socket AF_PACKET Raw 0xFFFF recv sock 0xFFFF ``` EDIT3: Trying to send a packet from a socket without binding it results in an exception: ``` sock <- socket AF_PACKET Raw 0xFFFF send sock "\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\255\255" *** Exception: send: does not exist (No such device or address) ``` This makes sense, because the kernel would not have any clue on which interface to actually transmit the packet. Is there any way to bind a (raw) socket to an interface in Haskell?

Original source