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?
The raw socket interface provides direct access to lower layer protocols, such as the Internet Protocol (IP) and Internet Control Message Protocol (ICMP or ICMPv6). You can use raw sockets to test new protocol implementations.
Raw tcp socketsint s = socket (AF_INET, SOCK_RAW, IPPROTO_TCP); The above function call creates a raw socket of protocol TCP. This means that we have to provide the TCP header along with the data. The kernel or the network stack of Linux shall provide the IP header.
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))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With