[ Team LiB ] Previous Section Next Section

28.4 Raw Socket Input

The first question that we must answer regarding raw socket input is: Which received IP datagrams does the kernel pass to raw sockets? The following rules apply:

  • Received UDP packets and received TCP packets are never passed to a raw socket. If a process wants to read IP datagrams containing UDP or TCP packets, the packets must be read at the datalink layer, as described in Chapter 29.

  • Most ICMP packets are passed to a raw socket after the kernel has finished processing the ICMP message. Berkeley-derived implementations pass all received ICMP packets to a raw socket other than echo request, timestamp request, and address mask request (pp. 302–303 of TCPv2). These three ICMP messages are processed entirely by the kernel.

  • All IGMP packets are passed to a raw socket after the kernel has finished processing the IGMP message.

  • All IP datagrams with a protocol field that the kernel does not understand are passed to a raw socket. The only kernel processing done on these packets is the minimal verification of some IP header fields: the IP version, IPv4 header checksum, header length, and destination IP address (pp. 213–220 of TCPv2).

  • If the datagram arrives in fragments, nothing is passed to a raw socket until all fragments have arrived and have been reassembled.

When the kernel has an IP datagram to pass to the raw sockets, all raw sockets for all processes are examined, looking for all matching sockets. A copy of the IP datagram is delivered to each matching socket. The following tests are performed for each raw socket and only if all three tests are true is the datagram delivered to the socket:

  • If a nonzero protocol is specified when the raw socket is created (the third argument to socket), then the received datagram's protocol field must match this value or the datagram is not delivered to this socket.

  • If a local IP address is bound to the raw socket by bind, then the destination IP address of the received datagram must match this bound address or the datagram is not delivered to this socket.

  • If a foreign IP address was specified for the raw socket by connect, then the source IP address of the received datagram must match this connected address or the datagram is not delivered to this socket.

Notice that if a raw socket is created with a protocol of 0, and neither bind nor connect is called, then that socket receives a copy of every raw datagram the kernel passes to raw sockets.

Whenever a received datagram is passed to a raw IPv4 socket, the entire datagram, including the IP header, is passed to the process. For a raw IPv6 socket, only the payload (i.e., no IPv6 header or any extension headers) is passed to the socket (e.g., Figures 28.11 and 28.22).

In the IPv4 header passed to the application, ip_len, ip_off, and ip_id are host byte ordered, and ip_len contains only the IP payload length (with the IP header length subtracted), but the remaining fields are network byte ordered. Under Linux, all fields are left in network byte order.

As previously mentioned, the raw socket interface is defined to provide an identical interface to the one a protocol would have if it was resident in the kernel, so the contents of the fields are dependent on the OS kernel.

We mentioned in the previous section that all fields in a datagram received on a raw IPv6 socket are left in network byte order.

ICMPv6 Type Filtering

A raw ICMPv4 socket receives most ICMPv4 messages received by the kernel. But ICMPv6 is a superset of ICMPv4, including the functionality of ARP and IGMP (Section 2.2). Therefore, a raw ICMPv6 socket can potentially receive many more packets compared to a raw ICMPv4 socket. But most applications using a raw socket are interested in only a small subset of all ICMP messages.

To reduce the number of packets passed from the kernel to the application across a raw ICMPv6 socket, an application-specified filter is provided. A filter is declared with a datatype of struct icmp6_filter, which is defined by including <netinet/icmp6.h>. The current filter for a raw ICMPv6 socket is set and fetched using setsockopt and getsockopt with a level of IPPROTO_ICMPv6 and an optname of ICMP6_FILTER.

Six macros operate on the icmp6_filter structure.

#include <netinet/icmp6.h>

void ICMP6_FILTER_SETPASSALL (struct icmp6_filter *filt);

void ICMP6_FILTER_SETBLOCKALL (struct icmp6_filter *filt);

void ICMP6_FILTER_SETPASS (int msgtype, struct icmp6_filter *filt);

void ICMP6_FILTER_SETBLOCK (int msgtype, struct icmp6_filter *filt);

int ICMP6_FILTER_WILLPASS (int msgtype, const struct icmp6_filter *filt);

int ICMP6_FILTER_WILLBLOCK (int msgtype, const struct icmp6_filter *filt);

Both return: 1 if filter will pass (block) message type, 0 otherwise

The filt argument to all the macros is a pointer to an icmp6_filter variable that is modified by the first four macros and examined by the final two macros. The msgtype argument is a value between 0 and 255 and specifies the ICMP message type.

The SETPASSALL macro specifies that all message types are to be passed to the application, while the SETBLOCKALL macros specifies that no message types are to be passed. By default, when an ICMPv6 raw socket is created, all ICMPv6 message types are passed to the application.

The SETPASS macro enables one specific message type to be passed to the application while the SETBLOCK macro blocks one specific message type. The WILLPASS macro returns 1 if the specified message type is passed by the filter, or 0 otherwise; the WILLBLOCK macro returns 1 if the specified message type is blocked by the filter, or 0 otherwise.

As an example, consider the following application, which wants to receive only ICMPv6 router advertisements:


struct icmp6_filter myfilt;

fd = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);

ICMP6_FILTER_SETBLOCKALL (&myfilt);
ICMP6_FILTER_SETPASS (ND_ROUTER_ADVERT, &myfilt);
Setsockopt (fd, IPPROTO_ICMPV6, ICMP6_FILTER. &myfilt, sizeof (myfilt));

We first block all message types (since the default is to pass all message types) and then pass only router advertisements. Despite our use of the filter, the application must be prepared to receive all types of ICMPv6 packets since any ICMPv6 packets that arrive between the socket and the setsockopt will be added to the receive queue. The ICMP6_FILTER option is simply an optimization.

    [ Team LiB ] Previous Section Next Section