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鈥?03 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鈥?20 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.
|