ityonemo

ityonemo

Zing, basic Elixir ICMP ('ping') server using Zig NIF

This is a basic demonstration of how to write an ICMP (‘ping’) server using a NIF in about 100 lines of elixir and 100 lines of Zig.

This might be able to be deployed as a ‘real’ library. Would anyone be interested in using this? I am very happy to put more work into making this a quality release (modulo zig itself being still experimental) if people are interested, as there really isn’t a satisfactory ICMP solution in the BEAM (and the :socket library maintainers have suggested that ICMP is not going to happen)

Most Liked

hauleth

hauleth

To prove that it is possible:

defmodule GenICMP do
  @data <<0xdeadbeef::size(32)>>
  def ping(addr) do
    {:ok, s} = open()

    data = @data

    req_echo(s, addr, data: data)

    case recv_echo(s) do
      {:ok, %{data: ^data}} = resp -> resp
      {:ok, other} -> {:error, other}
      _ -> {:error, :invalid_resp}
    end
  end

  def open, do: :socket.open(:inet, :dgram, :icmp)

  def req_echo(socket, addr, opts \\ []) do
    data = Keyword.get(opts, :data, @data)
    id = Keyword.get(opts, :id, 0)
    seq = Keyword.get(opts, :seq, 0)

    sum = checksum(<<8, 0, 0::size(16), id, seq, data::binary>>)

    msg = <<8, 0, sum::binary, id, seq, data::binary>>

    :socket.sendto(socket, msg, %{family: :inet, port: 1, addr: addr})
  end

  def recv_echo(socket, timeout \\ 5000) do
    {:ok, data} = :socket.recv(socket, 0, [], timeout)

    <<_::size(160), pong::binary>> = data

    case pong do
      <<0, 0, _::size(16), id, seq, data::binary>> ->
        {:ok, %{
          id: id, seq: seq, data: data
        }}
      _ -> {:error, pong}
    end
  end

  defp checksum(bin), do: checksum(bin, 0)

  defp checksum(<<x::integer-size(16), rest::binary>>, sum), do: checksum(rest, sum + x)
  defp checksum(<<x>>, sum), do: checksum(<<>>, sum + x)
  defp checksum(<<>>, sum) do
    <<x::size(16), y::size(16)>> = <<sum::size(32)>>

    res = :erlang.bnot(x + y)

    <<res::big-size(16)>>
  end
end

API is simple:

GenICMP.ping({127, 0, 0, 1})

Tested on macOS, but should work on Linux as well. I am not sure about BSDs.

EDIT:

Just in case, this project seems as a good example of how to use Zigler to write Erlang NIFs, and it is great. However sending ICMP echo requests via socket is absolutely possible.

hauleth

hauleth

I have implemented ICMP, but ICMPv6 is still not done, if you want then I would be glad for PR. It uses slightly different API from what You are using as I wanted something “more basic” so users could build larger functionalities on top of this.

ityonemo

ityonemo

Lol, I tried this two months ago and support for the :icmp mode wasn’t there!! I think I was on 22.2, and I asked Peter dimitrov at codebeam and he said they weren’t going to do icmp :smiley:

Last Post!

the_wildgoose

the_wildgoose

Hi, could I persuade you to explain the code a little more here please?

I see the line referenced
decode(<<4:4, IHL:4, Rest/binary>>)
But I’m really not clear why that can’t match an unfortunate (or carefully constructed) ping response

Phrasing the question another way, is there a tight binary match for an IPv4 header that couldn’t match the ICMP body response (on Linux)?

I wonder why you don’t check the OS during init and then match on that? (Stash it in the state perhaps?)

Agreed that the continue handling is very neat!

Where Next?

Popular in Discussions Top

PragTob
Hey everyone, this has been on my mind for some time and I’d love your input on it! TLDR: I feel like maps are superioer for storing and...
New
rower687
Hi all, I’ve been reading a lot about the “let it crash” term and how supervising processes and the whole messaging passing make an elixi...
New
boundedvariable
I am going through the kafka architecture. All the features what the kafka is providing are already in Erlang. I would like hear your opi...
New
pdgonzalez872
If this has been asked here before, please point me to where it was asked as I didn’t find it when I searched the forum. Maybe a mailing ...
New
PragTob
Hello everyone, I know we had quite some threads (read through lots of them) about background job processing but it remains a hotly deba...
New
tomekowal
Hey guys! I want to create a toy project that shows a chart of temperature over time and updates every 5 seconds. I feel LiveView is per...
New
opsb
We’re considering our architecture from a viewpoint of scaling our traffic heavily over the next 6 months. Our current deployment is runn...
New

Other popular topics Top

hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 44139 214
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New

We're in Beta

About us Mission Statement