RawPing.Socket (raw_ping v0.3.1)

Copy Markdown View Source

Low-level socket operations for ICMP using Erlang's :socket API.

This module handles opening ICMP sockets, sending packets, and receiving replies with proper timeout handling.

Socket modes

Two kernel interfaces can carry ICMP echo:

  • :dgram — unprivileged ICMP datagram sockets (SOCK_DGRAM/IPPROTO_ICMP). Needs no capability. On Linux, availability is gated by net.ipv4.ping_group_range, which must include the running process's GID; many distributions ship this wide open. macOS permits it by default.

  • :raw — raw sockets (SOCK_RAW). Requires root or CAP_NET_RAW.

:auto (the default) tries :dgram first and falls back to :raw, so a process gets the least-privileged interface that works on the host.

The mode matters to callers because the two deliver different bytes: raw sockets include the IP header on receive, datagram sockets do not, and the kernel rewrites the ICMP identifier on the datagram path. open/1 returns the negotiated mode so parsing and reply matching can adapt. See RawPing.Packet.parse_echo_reply/2.

Summary

Functions

Close an ICMP socket.

Open an ICMP socket.

Receive an ICMP reply with timeout.

Send an ICMP packet to a destination IP.

Types

mode()

@type mode() :: :dgram | :raw

Functions

close(socket)

@spec close(:socket.socket()) :: :ok | {:error, term()}

Close an ICMP socket.

open(opts \\ [])

@spec open(keyword()) :: {:ok, :socket.socket(), mode()} | {:error, term()}

Open an ICMP socket.

Options

  • :mode - :auto (default), :dgram, or :raw

Returns {:ok, socket, mode} or {:error, reason}, where mode is the interface actually negotiated.

With :auto, no elevated privileges are needed as long as datagram ICMP is permitted for this process; otherwise it falls back to :raw, which requires root or CAP_NET_RAW.

recv(socket, timeout_ms)

@spec recv(:socket.socket(), non_neg_integer()) :: {:ok, binary()} | {:error, term()}

Receive an ICMP reply with timeout.

Returns {:ok, data} or {:error, :timeout} / {:error, reason}.

On :raw sockets data begins with the IP header. On :dgram sockets the kernel strips it and data is the ICMP message alone.

send(socket, packet, dest_ip)

@spec send(:socket.socket(), binary(), :inet.ip_address()) :: :ok | {:error, term()}

Send an ICMP packet to a destination IP.