Skip to content

Commit

Permalink
Begin receiving packets upon opening the device
Browse files Browse the repository at this point in the history
Simplify the interface by immediately receiving packets when the device
is opened. By default, all packets are sniffed. A filter can be applied
when the device is opened or changed later using filter/3.

Remove the loop/1 function. This also prevents multiple threads being
spawned to handle the same pcap descriptor.
  • Loading branch information
msantos committed Aug 23, 2012
1 parent 941bda3 commit 39db696
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 30 deletions.
53 changes: 26 additions & 27 deletions README.md
Expand Up @@ -66,41 +66,30 @@ SMP erlang must be enabled (erl -smp -pa ebin).
Option = {promisc, boolean()} Option = {promisc, boolean()}
| {snaplen, integer()} | {snaplen, integer()}
| {to_ms, integer()} | {to_ms, integer()}
| {filter, binary() | string()}
| FilterOpts

Open a network interface and begin receiving packets.


Dev is the name of the network device. If an empty binary (<<>>) Dev is the name of the network device. If an empty binary (<<>>)
is passed in, pcap will select a default interface. is passed in, pcap will select a default interface.


If an error occurs, the PCAP string describing the error is If an error occurs, the PCAP string describing the error is
returned to the caller. returned to the caller.


open/1 and open/2 defaults to: open/1 and open/2 default to:


* promiscuous mode disabled * promiscuous mode disabled


* a snaplen (packet length) of 65535 bytes * a snaplen (packet length) of 65535 bytes


* timeout set to 500 ms * timeout set to 500 ms


close(Socket) -> ok * no filter (all packets are received)


Closes the pcap descriptor. For filter options, see filter/3.


filter(Socket, Filter, Options) -> ok | {error, Error} Packets are returned as messages to the caller:

Types Socket = resource()
Error = enomem | pcap_error_string()
Options = [ Option ]
Option = {optimize, boolean()}
| {netmask, integer()}

Compile a PCAP filter and apply it to the PCAP descriptor.

loop(Socket) -> ok | {error, posix()}

Types Socket = resource()

Begin sniffing the network. Packets are returned as messages to
the caller:


{ewpcap, Ref, DatalinkType, Time, Length, Packet} {ewpcap, Ref, DatalinkType, Time, Length, Packet}


Expand All @@ -118,6 +107,21 @@ SMP erlang must be enabled (erl -smp -pa ebin).


The Packet is a binary holding the captured data. The Packet is a binary holding the captured data.


close(Socket) -> ok

Closes the pcap descriptor.

filter(Socket, Filter) -> ok | {error, Error}
filter(Socket, Filter, Options) -> ok | {error, Error}

Types Socket = resource()
Error = enomem | pcap_error_string()
Options = [ Option ]
Option = {optimize, boolean()}
| {netmask, integer()}

Compile a PCAP filter and apply it to the PCAP descriptor.

read(Socket) -> {ok, Packet} read(Socket) -> {ok, Packet}
read(Socket, Timeout) -> {ok, Packet} | {error, eagain} read(Socket, Timeout) -> {ok, Packet} | {error, eagain}


Expand Down Expand Up @@ -168,12 +172,7 @@ SMP erlang must be enabled (erl -smp -pa ebin).


% icmp_resend:start("eth0"). % icmp_resend:start("eth0").
start(Dev) -> start(Dev) ->
{ok, Socket} = ewpcap:open(Dev), {ok, Socket} = ewpcap:open(Dev, [{filter, "icmp"}]),
ok = ewpcap:filter(Socket, "icmp"),

% begin reading from the network
ok = ewpcap:loop(Socket),

resend(Socket). resend(Socket).


resend(Socket) -> resend(Socket) ->
Expand All @@ -183,10 +182,10 @@ SMP erlang must be enabled (erl -smp -pa ebin).


## TODO ## TODO


* rename loop/1

* ewpcap, epcap, epcap\_compile ... confusing! * ewpcap, epcap, epcap\_compile ... confusing!


* pcap\_sendpacket may block * pcap\_sendpacket may block


* pcap\_findalldevices blocks

* re-write as a port driver? * re-write as a port driver?
1 change: 0 additions & 1 deletion c_src/ewpcap.c
Expand Up @@ -303,7 +303,6 @@ nif_pcap_close(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])


pcap_breakloop(ep->p); pcap_breakloop(ep->p);
pcap_close(ep->p); pcap_close(ep->p);
/* XXX safe? pcap_loop may still be running */
ep->p = NULL; ep->p = NULL;


return atom_ok; return atom_ok;
Expand Down
25 changes: 23 additions & 2 deletions src/ewpcap.erl
Expand Up @@ -35,7 +35,6 @@
open/0, open/1, open/2, open/0, open/1, open/2,
close/1, close/1,
filter/2, filter/3, filter/2, filter/3,
loop/1,
read/1, read/2, read/1, read/2,
write/2, write/2,
getifaddrs/0 getifaddrs/0
Expand Down Expand Up @@ -94,8 +93,30 @@ open(Dev, Options) when is_list(Options) ->
Snaplen = proplists:get_value(snaplen, Options, 16#ffff), Snaplen = proplists:get_value(snaplen, Options, 16#ffff),
Promisc = bool(proplists:get_value(promisc, Options, false)), Promisc = bool(proplists:get_value(promisc, Options, false)),
To_ms = proplists:get_value(to_ms, Options, 500), To_ms = proplists:get_value(to_ms, Options, 500),
Filter = proplists:get_value(filter, Options, <<>>),


pcap_open_live(Dev, Snaplen, Promisc, To_ms). case pcap_open_live(Dev, Snaplen, Promisc, To_ms) of
{ok, Socket} ->
open_1(Socket, Options, Filter);
Error ->
Error
end.

open_1(Socket, _Options, <<>>) ->
open_2(Socket);
open_1(Socket, Options, Filter) ->
case filter(Socket, Filter, Options) of
ok ->
open_2(Socket);
Error ->
Error
end.

open_2(Socket) ->
case loop(Socket) of
ok -> {ok, Socket};
Error -> Error
end.


close(#ewpcap_resource{res = Res}) -> close(#ewpcap_resource{res = Res}) ->
pcap_close(Res). pcap_close(Res).
Expand Down

0 comments on commit 39db696

Please sign in to comment.