05 October 2010

The magic of sockets

What I wanted to know, is how to use linux sockets to get what I want (either the whole IP packet, or just the payload, and so on) from what packets I want (like only packets with a specific protocol, and so on).
socket(domain, family, protocol);
This is the important function to use. There are two domains which interest me.

PF_PACKET
This family of sockets is used to retrieve the packets directly from the ethernet interface. Two types are defined:
- SOCK_RAW: retrieves the whole ethernet frame (including the ethernet header).
- SOCK_DGRAM: retrieves only the IP/IPv6 packet (without ethernet header).
The third parameter is the protocol.
- ETH_P_IP/ETH_P_IPV6: only IPv4/IPv6 packets are retrieved.
- ETH_P_ALL: all packets are retrieved. However, when using ETH_P_ALL, the outgoing packets are retrieved as well.

PF_INET
This family of sockets is used to retrieve IP packets from the kernel. Three types are defined here:
- SOCK_DGRAM: this is used to listen for UDP packets. Only UDP packets cand be received/send using this type of socket
- SOCK_STREAM: this is used to listen for TCP connections. Only TCP packets can be received/sent using this type of socket
- SOCK_RAW: This is (in my opinion) the most interesting type. This is used to retrieve whichever protocol you like. If you use this option, you must always specify the protocol (like IPPROTO_GRE for GRE tunnels). When sending packets using this type of socket, the socket will send the packet by adding an IP header over the payload, which has the protocol with which the socket was opened. If you use SOCK_RAW, you can actually create your own IP header and send the whole IP packet from the socket. In order to do this, you must use the setsockopt function to add the option IP_HDRINCL to the socket.

Another important domain is the PF_UNIX domain, but since I haven't had much work to do with it until now, I won't discuss it here.

Once you opened the socket, simply bind it to an interface. For PF_PACKET sockets, as far as I know, you must bind it to an interface, while the AF_INET sockets can be bound to IP addresses on the interfaces.