DRAIN(7P)                                                            DRAIN(7P)


NAME
     drain - capture unimplemented link-layer protocols

SYNOPSIS
     #include <sys/types.h>
     #include <net/raw.h>

     s = socket(PF_RAW, SOCK_RAW, RAWPROTO_DRAIN);

DESCRIPTION
     The Drain protocol provides non-promiscuous capture of packets having
     unimplemented link-layer protocol types, i.e., packets that the operating
     system normally receives and drops ``down the drain''.  It treats packets
     as datagrams containing a link-layer header followed by data.  Drain uses
     the Raw address format, interpreting ports as link-layer type codes (in
     host byte order) to match against unimplemented types in received
     packets.  Multiple sockets may bind to the same port on a network
     interface.

     Drain can map several link-layer type codes to a port.  There is one
     type-to-port mapping for each network interface; it is initialized to map
     zero to zero.  Call ioctl(2) with the SIOCDRAINMAP command and the
     address of the following structure, declared in <net/raw.h>, to set a
     mapping:

          struct drainmap {
               u_short   dm_minport;    /* lowest port in range */
               u_short   dm_maxport;    /* and highest port */
               u_short   dm_toport;     /* port mapped by range */
          };


     Drain input from Ethernet network interfaces is demultiplexed based on
     the ether_type member of the ether_header structure, declared in
     <netinet/if_ether.h> and documented in ethernet(7).

     If the link-layer header size is not congruent with RAW_ALIGNGRAIN, Drain
     input prepends RAW_HDRPAD(hdrsize) bytes of padding to received packets.
     Output on a Drain socket, using write(2) or send(2), takes a buffer
     address pointing at the link-layer packet to be transmitted, not at any
     prepended padding.

EXAMPLES
     To capture from an Ethernet network interface, first declare an input
     buffer structure with the required header padding:


          #include <sys/types.h>
          #include <net/raw.h>
          #include <netinet/if_ether.h>

          #define ETHERHDRPAD RAW_HDRPAD(sizeof(struct ether_header))

          struct etherpacket {
               char           pad[ETHERHDRPAD];
               struct ether_header ether;
               char           data[ETHERMTU];
          };


     To capture all Reverse ARP (RARP) packets, create a Drain socket and bind
     it to the RARP port on the primary network interface (error handling is
     omitted for clarity):

          #define   ETHERTYPE_RARP 0x8035

          int s;
          struct sockaddr_raw sr;

          s = socket(PF_RAW, SOCK_RAW, RAWPROTO_DRAIN);
          sr.sr_family = AF_RAW;
          sr.sr_port = ETHERTYPE_RARP;
          bzero(sr.sr_ifname, sizeof sr.sr_ifname);
          bind(s, &sr, sizeof sr);


     Alternatively, to capture all Ethernet packets with IEEE 802.3
     encapsulations, create and bind a socket to a port different from any
     valid ether_type:

          #define   IEEE802_3PORT  1

          int s;
          struct sockaddr_raw sr;

          s = socket(PF_RAW, SOCK_RAW, RAWPROTO_DRAIN);
          sr.sr_family = AF_RAW;
          sr.sr_port = IEEE802_3PORT;
          bzero(sr.sr_ifname, sizeof sr.sr_ifname);
          bind(s, &sr, sizeof sr);


     Map all Ethernet types corresponding to packet lengths, as specified by
     802.3, to the bound port:


          struct drainmap map;

          map.dm_minport = 1;
          map.dm_maxport = 1500;
          map.dm_toport = IEEE802_3PORT;
          ioctl(s, SIOCDRAINMAP, &map);


     Before reading, it may be desirable to increase the Drain socket's
     default receive buffer size.  The following code also shows how to
     transmit a link-layer packet:

          struct etherpacket ep;
          int cc = 10000;

          setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *) &cc, sizeof cc);
          for (;;) {
               cc = read(s, (char *) &ep, sizeof ep);
               /* . . . */
               write(s, (char *) &ep.ether, cc - sizeof ep.pad);
          }


DIAGNOSTICS
     A socket operation may fail with one of the following errors returned:

     [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 create a socket with a network
                    address for which no network interface exists.

     [EOPNOTSUPP]    when an ioctl operation not supported by the Drain
                     protocol is attempted.

SEE ALSO
     getsockopt(2), socket(2), intro(3), ethernet(7), raw(7F), snoop(7P)


                                                                        Page 3