Skip to content

msantos/gen_icmp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

185 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Package Version Hex Docs

gen_icmp aspires to be a simple interface for using ICMP and ICMPv6 sockets in Erlang, just like gen_tcp and gen_udp do for their protocol types; incidentally messing up Google searches for whomever someday writes a proper gen_icmp module.

gen_icmp uses procket to get a raw socket and abuses gen_udp for the socket handling. gen_icmp should work on Linux and BSDs.

For a simple example of sending a ping, also see:

https://github.com/msantos/procket/blob/master/src/icmp.erl

COMPILING

rebar3 do clean, compile, ct

Also see the README for procket for additional setup (the procket executable needs superuser privileges).

DOCUMENTATION

https://hexdocs.pm/gen_icmp/

EXAMPLE

Simple ping interface

1> gen_icmp:ping("www.google.com").
[{ok,"www.google.com",
     {173,194,64,99},
     {173,194,64,99},
     18411,0,50,
     <<" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO">>}]

2> gen_icmp:ping(["www.google.com", {192,168,213,4}, "193.180.168.20", {192,0,32,10}]).
[{error,timeout,"193.180.168.20",{193,180,168,20}},
 {error,unreach_host,
        {192,168,213,4},
        {192,168,213,4},
        {192,168,213,54},
        {18411,2,undefined},
        <<69,0,0,84,0,0,64,0,64,1,15,29,192,168,213,54,192,168,
          213,4,...>>},
 {ok,{192,0,32,10},
     {192,0,32,10},
     {192,0,32,10},
     {18411,1,103},
     <<" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO">>},
 {ok,"www.google.com",
     {173,194,77,99},
     {173,194,77,99},
     {18411,0,50},
     <<" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO">>}]

IPv6

1> gen_icmp:ping("google.com", [inet6]).
[{ok,"google.com",
     {9735,63664,16395,2054,0,0,0,4098},
     {9735,63664,16395,2054,0,0,0,4098},
     {18411,0,64,62},
     <<" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO">>}]

2> tracert:host("google.com", [inet6]).

Re-using the ICMP ping socket

Keeping the ICMP socket around between runs is more efficient:

{ok, Socket} = gen_icmp:open(),
P1 = gen_icmp:ping(Socket, [{10,1,1,1}, "www.google.com"], []),
P2 = gen_icmp:ping(Socket, [{10,2,2,2}, "www.yahoo.com"], []),
gen_icmp:close(Socket).

Working with ICMP sockets

{ok, Socket} = gen_icmp:open().

% By default, the ICMP socket is in passive mode
ok = gen_icmp:setopts(Socket, [{active, true}]),

% ICMP host unreachable, empty payload (should contain an IPv4 header
% and the first 8 bytes of the packet data)
Packet = gen_icmp:packet([{type, 3}, {code, 0}], <<0:160, 0:64>>).

gen_icmp:send(Socket, {127,0,0,1}, Packet),

% Put the socket back into passive mode
ok = gen_icmp:setopts(Socket, [{active, false}]).

Setting Up an ICMP Ping Tunnel

ptun is an example of using gen_icmp to tunnel TCP over ICMP.

To compile ptun:

make eg

Host1 (1.1.1.1) listens for TCP on port 8787 and forwards the data over ICMP:

erl -noshell -pa ebin deps/*/ebin -eval 'ptun:server({2,2,2,2},8787)' -s erlang halt

Host2 (2.2.2.2) receives ICMP echo requests and opens a TCP connection to 127.0.0.1:22:

erl -noshell -pa ebin deps/*/ebin -eval 'ptun:client({1,1,1,1},22)' -s erlang halt

To use the proxy on host1:

ssh -p 8787 127.0.0.1

Traceroute

  • ICMP traceroute

    1> Path = tracert:host({8,8,8,8}).
    [{{216,239,46,191},
     36149,
     {icmp,<<11,0,111,150,0,0,0,0,69,128,0,84,0,0,64,...>>}},
     {{216,239,47,189},
     51459,
     {icmp,<<11,0,111,150,0,0,0,0,69,128,0,84,0,0,...>>}},
     {{8,8,8,8},
     34946,
     {icmp,<<0,0,170,0,219,104,0,0,32,33,34,35,36,...>>}}]
    
    2> tracert:path(Path).
    [{{216,239,46,191},62815,timxceed_intrans},
     {{216,239,47,189},44244,timxceed_intrans},
     {{8,8,8,8},34825,echoreply}]
  • UDP traceroute

    1> Path = tracert:host({8,8,8,8}, [{protocol, udp}]).
  • IPv6 traceroute

    1> Path = tracert:host("google.com", [inet6]).

Packages

 
 
 

Contributors

Languages