SEND(4)

πŸ“¦ version 15.1, in freebsd 14.5, freebsd 15.1, nixpkgs unstable

πŸ’– SEND(4) β€” Kernel side support for Secure Neighbor Discovery (SeND) β€” from the Kernel Interfaces Manual πŸ’–

🌸 NAME 🌸

send β€” Kernel side support for Secure Neighbor Discovery (SeND). That's the name section, bestie, short and iconic πŸ’….

✨ SYNOPSIS ✨

Okay so here are the includes, exactly as they come:

#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet6/send.h>

int
socket(PF_INET6, SOCK_RAW, IPPROTO_SEND);

To load the driver as a module at boot time, place the following line in loader.conf(5):

send_load="YES"

πŸ¦‹ DESCRIPTION πŸ¦‹

So IPv6 nodes use the Neighbor Discovery Protocol (NDP) to discover other nodes on the link, to determine their link-layer addresses to find routers, and to maintain reachability information about the paths to active members. And ngl, NDP is vulnerable to various attacks [RFC3756] 😭. Secure Neighbor Discovery is a set of extensions to NDP that counter threats to NDP [RFC3971] β€” that's the whole point, periodt.

Kernel side support for SeND consists of a kernel module with hooks that divert relevant packets (Neighbor Solicitations, Neighbor Advertisements, Router Solicitations, Router Advertisements and Redirects) from the NDP stack, send them to user space on a dedicated socket and reinject them back for further processing. Hooks are triggered only if the send module is loaded β€” no module, no hooks, no cap.

The native SeND socket is similar to a raw IP socket, but with its own, internal pseudo-protocol (IPPROTO_SEND). Struct sockaddr_send is defined in <netinet6/send.h>. It defines the total length of the structure, the address family, packet's incoming or outgoing direction from the interface's point of view, and the interface index.

struct sockaddr_send {
        unsigned char           send_len;       /* total length */
        sa_family_t             send_family;    /* address family */
        int                     send_direction;
        int                     send_ifidx;
        char                    send_zero[8];
};

The address family is always AF_INET6. The send_direction variable denotes the direction of the packet from the interface's point of view and has either the value SND_IN or SND_OUT. The send_ifidx variable is the interface index of the receiving or sending interface. The send_zero variable is padding and must always be zero β€” like, do not touch it, bestie 🫢.

In case that no user space application is connected to the send socket, processing continues normally as if the module was not loaded. It's giving "nothing to see here" and honestly? Slay.

πŸ”₯ INPUT HOOK πŸ”₯

The input hook is named after the input path of the incoming or outgoing NDP packets, on the way from the wire, through the nd6 stack, to user space. Relevant packets are identified by adding an mbuf_tag (see mbuf_tags(9)) to the mbuf(9), if the send module is loaded. It is then passed on to the kernel-userland interface for either cryptographic protection or validation by the SeND application.

The hook takes an argument that describes the direction of the packet, both in case of incoming and outgoing packets.

  • SND_IN β€” the direction of the incoming packets that are usually protected by the SeND options and then sent to user space for cryptographic validation.
  • SND_OUT β€” the outgoing direction. It describes both reply and locally originated outgoing packets that are sent to user space for the addition of SeND options.

πŸ“₯ INCOMING PACKETS πŸ“₯

The incoming ND packet from the wire:

                                               kernelspace ( userspace
                                                           )
        incoming SeND/ND packet                            (
                   |                                       )
                   v                 ( SND_IN )            (
                  icmp6_input() -> send_input_hook ---> send socket ----+
                   :                                       )            |
                   :             #                 #       (            |
          normal   :             #                 #       )            v
        processing :             #     send.ko     #       (    SeND application
           path    :             #                 #       )            |
                   :             #                 #       (            |
                   v                                       )            |
          icmp6/nd6_??_input() <- protocol switch  <--- send socket <---+
                   |         structure (IPPPROTO_SEND)     )
                   |                ( SND_IN )             (
                   v                                       )
        continue normal ND processing                      (

πŸ“€ OUTGOING PACKETS πŸ“€

Outgoing ND packet (reply or locally triggered):

                                               kernelspace ( userspace
                                                           )
        nd6_na_input()                                     (
        +PACKET_TAG_ND_OUTGOING                            )
        |                                                  )
        |   outgoing packet                                (
        |          |                                       )
        |          v                                       (
        |   icmp6_redirect_output()                        )
        |   nd6_ns_output()                                (
        |   nd6_na_output()                                )
        |   +PACKET_TAG_ND_OUTGOING                        (
        |          |                                       )
        |          +-----------<- rip6_output() <----------)----- rtsol/rtadvd/..
        |          |              +PACKET_TAG_ND_OUTGOING  (
        |          v                                       )
        |       ip6_output()                               (
        |          |                                       )
        +-------->-+                                       (
                   |                                       )
                   v                ( SND_OUT )            (
               nd6_output_lle() -> send_input_hook ---> send socket ----+
        -PACKET_TAG_ND_OUTGOING                            )            |
                   :             #                 #       (            |
          normal   :             #                 #       )            v
        processing :             #     send.ko     #       (    SeND application
           path    :             #                 #       )            |
                   :             #                 #       (            |
                   v                                       )            |
           (*ifp->if_output)() <- protocol switch  <--- send socket <---+
                   |         structure (IPPPROTO_SEND)     )
                   |                ( SND_OUT )            (
                   v                                       )
        continue with normal packet output                 (

πŸ’€ ERRORS πŸ’€

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

  • [EEXIST] β€” Another user space SeND application is bound to the socket.
  • [ENOBUFS] β€” Shortage of space to receive the incoming (SeND-protected) or outgoing (SeND-validated) packet from the SeND application.
  • [ENOSYS] β€” A packet received from user space and passed to the NDP stack for further processing is neither Neighbor Solicitation, Neighbor Advertisement, Router Solicitation, Router Advertisement nor Redirect.
  • [ENOENT] β€” Occurs if interface output routines fail to send the packet out of the interface.

πŸŽ€ SEE ALSO πŸŽ€

⭐ HISTORY ⭐

The send module first appeared in FreeBSD 9.0. Vintage but make it iconic ✨.

πŸ‘‘ AUTHORS πŸ‘‘

Ana Kukec <anchie@FreeBSD.org>, University of Zagreb. We stan a legend 🫢.

🚨 BUGS 🚨

Due to the lack of NDP locking, it is currently not possible to unload the send module.

That's the warning, bestie β€” not me being dramatic, that's literally the bug note 😭.


okay bye bestie β€” this page is from Debian, dated September 19, 2010, and it's SEND(4), mwah πŸ’‹βœ¨

πŸ“¦ where this page comes from