RawPing (raw_ping v0.2.0)

Copy Markdown View Source

Pure Erlang/OTP ICMP ping library using the modern :socket API.

No NIFs, no external dependencies. Requires Elixir 1.17+ (OTP 25+).

Usage

# Single ping
{:ok, rtt_ms} = RawPing.ping("8.8.8.8")
{:ok, rtt_ms} = RawPing.ping({8, 8, 8, 8})

# With options
{:ok, rtt_ms} = RawPing.ping("8.8.8.8", timeout: 2000)

# Multiple pings with stats
{:ok, stats} = RawPing.ping_stats("8.8.8.8", count: 5)
# => {:ok, %{min: 10.5, max: 15.2, avg: 12.3, success_rate: 1.0, ...}}

# Batch ping multiple hosts
results = RawPing.ping_batch(["8.8.8.8", "1.1.1.1", "192.168.1.1"])
# => %{"8.8.8.8" => {:ok, 12.5}, "1.1.1.1" => {:ok, 8.2}, ...}

Privileges

Raw ICMP sockets typically require elevated privileges. Options:

  • Run as root/sudo
  • Set CAP_NET_RAW capability on the BEAM: setcap cap_net_raw+ep /path/to/beam.smp
  • Use a setuid wrapper

How It Works

Uses Erlang's :socket module to open a raw ICMP socket, builds ICMP echo request packets manually, sends them, and parses the echo replies to calculate round-trip time.

Summary

Functions

Ping a host and return the round-trip time in milliseconds.

Ping multiple hosts concurrently.

Ping a host multiple times and return statistics.

Types

ip_address()

@type ip_address() :: String.t() | :inet.ip_address() | [integer()]

ping_result()

@type ping_result() :: {:ok, float()} | {:error, term()}

ping_stats()

@type ping_stats() :: %{
  min: float() | nil,
  max: float() | nil,
  avg: float() | nil,
  success_rate: float(),
  success_count: non_neg_integer(),
  failure_count: non_neg_integer(),
  rtts: [float()]
}

Functions

ping(host, opts \\ [])

@spec ping(
  ip_address(),
  keyword()
) :: ping_result()

Ping a host and return the round-trip time in milliseconds.

Options

  • :timeout - Timeout in milliseconds (default: 5000)
  • :payload_size - Size of ICMP payload in bytes (default: 56)

Examples

{:ok, rtt} = RawPing.ping("8.8.8.8")
{:ok, rtt} = RawPing.ping({8, 8, 8, 8}, timeout: 1000)
{:error, :timeout} = RawPing.ping("10.255.255.1", timeout: 100)

ping_batch(hosts, opts \\ [])

@spec ping_batch(
  [ip_address()],
  keyword()
) :: %{required(String.t()) => ping_result()}

Ping multiple hosts concurrently.

Returns a map of host => result.

Options

  • :timeout - Timeout per ping in milliseconds (default: 5000)
  • :max_concurrency - Maximum concurrent pings (default: 50)

Examples

results = RawPing.ping_batch(["8.8.8.8", "1.1.1.1"])
# %{"8.8.8.8" => {:ok, 12.5}, "1.1.1.1" => {:ok, 8.2}}

ping_stats(host, opts \\ [])

@spec ping_stats(
  ip_address(),
  keyword()
) :: {:ok, ping_stats()} | {:error, term()}

Ping a host multiple times and return statistics.

Options

  • :count - Number of pings to send (default: 1)
  • :timeout - Timeout per ping in milliseconds (default: 5000)
  • :payload_size - Size of ICMP payload in bytes (default: 56)

Examples

{:ok, stats} = RawPing.ping_stats("8.8.8.8", count: 5)
# %{min: 10.2, max: 15.8, avg: 12.5, success_rate: 1.0, ...}