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

ben-pr-p
In general I’ve been sticking to this community style guide GitHub - christopheradams/elixir_style_guide: A community driven style guide ...
New
und0ck3d
Hello everyone! A few days ago I’ve created a topic here about how people were creating CMSs with Elixir and Phoenix. I’ve been studying...
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
mikl
I wanted to capitalize a string, and tried using String.capitalize(). That generally works well, until you try to capitalize a word like...
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
marciol
Please, let me know if this kind of discussion already took place in another topic . Hi all, how do you consider if is better to build ...
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

Other popular topics Top

KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 36654 110
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 54006 488
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
AstonJ
Seen any cool LiveView demos, sample apps or examples? Please post them here! :003:
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New

We're in Beta

About us Mission Statement