An Erlang port interface to libpcap.
epcap includes a small example program called sniff.
$ rebar3 compile
To compile the examples:
$ mkdir -p ebin
$ erlc +debug_info -I _build/default/lib -o ebin examples/*.erl
# Allow your user to epcap with root privs
sudo visudo
youruser ALL = NOPASSWD: /path/to/epcap/priv/epcap
# And if requiretty is enabled, disable it by using one of these
Defaults!/path/to/epcap/priv/epcap !requiretty
Defaults:youruser !requiretty
rebar3 shell
% Start the sniffer process
sniff:start_link().
% Use your interface, or leave it out and trust in pcap
sniff:start([{interface, "eth0"}]).
% To change the filter
sniff:start([{filter, "icmp or (tcp and port 80)"},{interface, "eth0"}]).
% To stop sniffing
sniff:stop().
In case you want to compile epcap with PF_RING support, just specify the path to the libpfring and modified libpcap libraries via shell variable PFRING.
PFRING=/home/user/pfring rebar3 do clean, compile
To complete the configuration you need to set up the cluster_id option. The value of the cluster_id option is integer and should be in range between 0 and 255.
epcap:start_link([{interface, "lo"}, {cluster_id, 2}]).
You can also specify the option cpu_affinity to set up CPU affinity for epcap port:
epcap:start_link([{interface, "lo"}, {cluster_id, 2}, {cpu_affinity, "1,3,5-7"}]).
Setting the RESTRICT_PROCESS environment variable controls which
mode of process restriction is used. The available modes are:
-
seccomp: linux
-
pledge: openbsd (default)
-
capsicum: freebsd (default)
-
rlimit: all (default: linux)
-
null: all
For example, to force using the seccomp process restriction on linux:
RESTRICT_PROCESS=rlimit rebar3 do clean, compile
The null mode disables process restrictions and can be used for debugging.
RESTRICT_PROCESS=null rebar3 do clean, compile
epcap:start([{exec, "sudo strace -f -s 4096 -o rlimit.trace"}, {filter, "port 9997"}]).
RESTRICT_PROCESS=seccomp rebar3 do clean, compile
epcap:start([{exec, "sudo strace -f -s 4096 -o seccomp.trace"}, {filter, "port 9997"}]).
=INFO REPORT==== 27-Oct-2013::11:47:43 ===
pcap: [{time,"2013-10-27 11:47:43"},
{caplen,653},
{len,653},
{datalink,en10mb}]
ether: [{source_macaddr,"F0:BD:4F:AA:BB:CC"},
{destination_macaddr,"B3:4B:19:00:11:22"}]
ipv6: [{protocol,tcp},
{source_address,"2607:F8B0:400B:80B::1000"},
{destination_address,"2002:26F:92:AE::123"}]
tcp: [{source_port,80},
{destination_port,47980},
{flags,[ack,psh]},
{seq,686139900},
{ack,725208397},
{win,224}]
payload_size: 567
payload: "HTTP/1.0 301 Moved Permanently..Location: http://www.google.ca/..Content-Type: text/html; charset=UTF-8..Date: Sun, 27 Oct 2013 15:47:49 GMT..Expires: Tue, 26 Nov 2013 15:47:49 GMT..Cache-Control: public, max-age=2592000..Server: gws..Content-Length: 218..X-XSS-Protection: 1; mode=block..X-Frame-Options: SAMEORIGIN..Alternate-Protocol: 80:quic....<HTML><HEAD><meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">.<TITLE>301 Moved</TITLE></HEAD><BODY>.<H1>301 Moved</H1>.The document has moved.<A HREF=\"http://www.google.ca/\">here</A>...</BODY></HTML>.."
And a screenshot of the number of packets epcap is processing on a production system:
-
return error atoms/tuples instead of using errx
-
add support for retrieving packet statistics using pcap_stats(3PCAP)
