SNOOP(7P) SNOOP(7P)
snoop - network monitoring protocol
#include <sys/types.h>
#include <net/raw.h>
s = socket(PF_RAW, SOCK_RAW, RAWPROTO_SNOOP);
The Snoop protocol provides promiscuous packet capture with filtering.
It treats packets as datagrams containing a link-layer header followed by
data. Snoop uses the Raw address format, assigning a unique port to a
socket bound to port zero, otherwise binding the specified port if it is
valid. Valid ports range from SNOOP_MINPORT to SNOOP_MAXPORT.
Snoop associates a set of SNOOP_MAXFILTERS packet filters with each
network interface. Each filter contains an array of mask bits, a
parallel array of bits to match against the masked packet's bits, the
filter's index in the interface's filter table, and a port identifying
the socket that added this filter. The user can set only sf_mask,
sf_match, and sf_port; all other members are set by the kernel.
struct snoopfilter {
u_long sf_mask[SNOOP_FILTERLEN];
u_long sf_match[SNOOP_FILTERLEN];
u_short sf_allocated:1,
sf_active:1,
sf_promisc:1,
sf_allmulti:1,
sf_index:SNOOP_MAXFILTSHIFT;
u_short sf_port;
};
The mask is applied to at most SNOOP_FILTERLEN long integers of the
packet. If the link-layer header size is not congruent with
RAW_ALIGNGRAIN, the mask and match arrays begin with RAW_HDRPAD(hdrsize)
bytes of padding, in order to preserve native addressability of packet
data. The RAW_HDR(addr, hdrtype) macro adjusts and coerces a
RAW_ALIGNGRAIN-congruent address into a pointer to the packet header
type. Use RAW_HDR to convert sf_mask and sf_match into appropriately
padded, typed pointers.
Call ioctl(2) on a bound Snoop socket with the SIOCADDSNOOP command and
the address of a snoopfilter, to add a filter. The SIOCDELSNOOP ioctl
command takes the address of an integer telling the index of a filter to
delete. The SIOCSNOOPLEN command takes the address of an integer telling
how many bytes of packet data to capture (the link-layer header is always
captured). By default, all received bytes of packet data are captured.
The SIOCSNOOPING command takes the address of an integer boolean telling
whether to start or stop capture.
Page 1
SNOOP(7P) SNOOP(7P)
The SIOCERRSNOOP ioctl command establishes an error filter. It takes the
address of an integer containing error flag bits (see below), and
designates the socket being operated on as the error snooper. There may
be at most one error snooper per network interface. Only packets
received with errors indicated by bits in the integer argument will be
captured.
Snoop applies filters to a non-erroneous packet in index order, matching
all filters against the packet. It then prepends the following header to
the alignment-padded, link-layer header:
struct snoopheader {
u_long snoop_seq;
u_short snoop_flags;
u_short snoop_packetlen;
struct timeval snoop_timestamp;
};
A snoopheader contains a reception sequence number, packet state flags,
length in bytes of the link-layer packet excluding frame check and
preamble, and a reception timestamp. The bits in snoop_flags describe
the packet's state as follows:
SN_PROMISC packet was not destined for this interface
SN_ERROR receive error specified by the following bits:
SNERR_FRAME packet received, but with framing error
SNERR_CHECKSUM packet received, but with CRC error
SNERR_TOOBIG packet received, truncated to fit buffer
SNERR_TOOSMALL packet not received, size less than minimum
SNERR_NOBUFS no packet received, out of buffers
SNERR_OVERFLOW no packet received, input silo overflow
SNERR_MEMORY no packet received, buffer memory error
The snoop_timestamp member contains the packet's reception time, with
precision limited by the operating system's clock tick parameter (see
times(2)).
Output on a Snoop socket, using write(2) or send(2), takes a buffer
address pointing at the link-layer packet to be transmitted. Output
buffers may need to begin with RAW_HDRPAD bytes of padding to ensure
addressability of structured data, but such padding is not passed to
write.
To capture all packets from an Ethernet network interface, first declare
an input buffer structure:
Page 2
SNOOP(7P) SNOOP(7P)
#include <sys/types.h>
#include <net/raw.h>
#include <netinet/if_ether.h>
#define ETHERHDRPAD RAW_HDRPAD(sizeof(struct ether_header))
struct etherpacket {
struct snoopheader snoop;
char pad[ETHERHDRPAD];
struct ether_header ether;
char data[ETHERMTU];
};
Then create a Snoop socket (error handling is omitted for clarity). Bind
it to the desired interface, e.g., ec0 (to bind to the primary interface,
zero sr_ifname):
int s;
struct sockaddr_raw sr;
s = socket(PF_RAW, SOCK_RAW, RAWPROTO_SNOOP);
sr.sr_family = AF_RAW;
sr.sr_port = 0;
strncpy(sr.sr_ifname, "ec0", sizeof sr.sr_ifname);
bind(s, &sr, sizeof sr);
Initialize a filter with no mask bits set, in order to match all packets.
Add it to the interface's filter set:
struct snoopfilter sf;
bzero((char *) &sf, sizeof sf);
ioctl(s, SIOCADDSNOOP, &sf);
Increase the socket's receive buffer size to a generous upper bound, to
cope with promiscuous reception of heavy traffic. Turn snooping on and
read captured packets:
struct etherpacket ep;
int cc = 60000, on = 1;
setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *) &cc, sizeof cc);
ioctl(s, SIOCSNOOPING, &on);
for (;;) {
cc = read(s, (char *) &ep, sizeof ep);
/* . . . */
}
Page 3
SNOOP(7P) SNOOP(7P)
To capture ARP packets from a specific Ethernet host, first declare an
appropriate input buffer structure:
#include <sys/types.h>
#include <net/raw.h>
#include <net/if_arp.h>
#include <netinet/if_ether.h>
#define ETHERHDRPAD RAW_HDRPAD(sizeof(struct ether_header))
struct arp_packet {
struct snoopheader snoop;
char pad[ETHERHDRPAD];
struct ether_header ether;
struct ether_arp arp;
};
Create and bind a Snoop socket as shown in the previous example. Then
initialize a filter to capture all ARP requests originating from a
remote_ether_addr:
struct snoopfilter sf;
struct ether_header *eh;
bzero((char *) &sf, sizeof sf);
eh = RAW_HDR(sf.sf_mask, struct ether_header);
memset(eh->ether_dhost, 0xff, sizeof eh->ether_dhost);
eh->ether_type = 0xffff;
eh = RAW_HDR(sf.sf_match, struct ether_header);
bcopy(remote_ether_addr, eh->ether_dhost, sizeof eh->ether_dhost);
eh->ether_type = htons(ETHERTYPE_ARP);
Finally, add the filter and start capturing packets:
struct arp_packet ap;
int cc, on = 1;
ioctl(s, SIOCADDSNOOP, &sf);
ioctl(s, SIOCSNOOPING, &on);
for (;;) {
cc = read(s, (char *) &ap, sizeof ap);
/* . . . */
}
A socket operation may fail with one of the following errors returned:
Page 4
SNOOP(7P) SNOOP(7P)
[EISCONN] when trying to establish a connection on a socket which
already has one, or when trying to send a datagram with
the destination address specified and the socket is
already connected;
[ENOBUFS] when the system runs out of memory for an internal data
structure or a send or receive buffer;
[EADDRINUSE] when an attempt is made to create a socket with a port
which has already been allocated;
[EADDRNOTAVAIL] when an attempt is made to bind an address naming a nonexistent
network interface to a Raw family socket.
[EOPNOTSUPP] when an ioctl operation not supported by the Snoop
protocol is attempted.
[EINVAL] when a Snoop ioctl argument is out of bounds or otherwise
invalid.
[EBUSY] when an error snooper is running and another process
attempts to set an error filter with SIOCERRSNOOP.
getsockopt(2), socket(2), intro(3), ethernet(7), raw(7F), drain(7P)
PPPPaaaaggggeeee 5555 [ Back ]
|