Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Raw sockets in Haskell

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?

like image 527
Andres Avatar asked Apr 19 '12 13:04

Andres


People also ask

What is the purpose of raw socket?

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.

How do you code a raw socket?

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.


1 Answers

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))
like image 129
Andres Avatar answered Sep 24 '22 18:09

Andres