%%% @copyright 2012-2020 Michael Santos %%% All rights reserved. %%% %%% Redistribution and use in source and binary forms, with or without %%% modification, are permitted provided that the following conditions %%% are met: %%% %%% Redistributions of source code must retain the above copyright %%% notice, this list of conditions and the following disclaimer. %%% %%% Redistributions in binary form must reproduce the above copyright %%% notice, this list of conditions and the following disclaimer in the %%% documentation and/or other materials provided with the distribution. %%% %%% Neither the name of the author nor the names of its contributors %%% may be used to endorse or promote products derived from this software %%% without specific prior written permission. %%% %%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS %%% "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT %%% LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS %%% FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE %%% COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, %%% INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, %%% BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; %%% LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER %%% CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT %%% LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN %%% ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE %%% POSSIBILITY OF SUCH DAMAGE. -module(epcap_compile). -export([ compile/1, compile/2 ]). -define(PCAP_NETMASK_UNKNOWN, 16#ffffffff). -define(DLT_EN10MB, 1). -on_load(on_load/0). on_load() -> erlang:load_nif(progname(), []). -spec pcap_compile( Filter :: iodata(), Optimize :: 0 | 1, Netmask :: non_neg_integer() | {byte(), byte(), byte(), byte()}, Linktype :: integer(), Snaplen :: integer() ) -> {ok, [binary()]} | {error, string()}. pcap_compile(_, _, _, _, _) -> erlang:nif_error(not_implemented). % @doc Compile a PCAP filter to a BPF program % % Filter is a string in pcap-filter(7) format. % % compile/1 defaults to: % % * optimization enabled % % * an unspecified netmask (filters specifying the broadcast % will return an error) % % * datalinktype set to ethernet (DLT_EN10MB) % % * a packet length of 65535 bytes % % * a limit of 8192 bytes for filters. Filters larger than this limit % will return `{error, enomem}'. A limit less than 0 disables the % length check. -spec compile(Filter :: iodata()) -> {ok, [binary()]} | {error, string()}. compile(Filter) -> compile(Filter, []). -type compile_options() :: [ {optimize, true | false} | {netmask, non_neg_integer()} | {dlt, integer()} | {snaplen, integer()} | {limit, integer()} ]. % @doc Compile a PCAP filter to a BPF program % % Filter is a string in pcap-filter(7) format. % % See pcap_compile(3PCAP) for documentation about each option. -spec compile(Filter :: iodata(), compile_options()) -> {ok, [binary()]} | {error, string()}. compile(Filter, Options) when is_binary(Filter); is_list(Filter) -> Optimize = bool(proplists:get_value(optimize, Options, true)), Netmask = mask(proplists:get_value(netmask, Options, ?PCAP_NETMASK_UNKNOWN)), Linktype = proplists:get_value(dlt, Options, ?DLT_EN10MB), Snaplen = proplists:get_value(snaplen, Options, 16#ffff), Limit = proplists:get_value(limit, Options, 8192), case iolist_size(Filter) < Limit orelse Limit < 0 of true -> pcap_compile(Filter, Optimize, Netmask, Linktype, Snaplen); false -> {error, enomem} end. bool(true) -> 1; bool(false) -> 0. mask(N) when is_integer(N) -> N; mask({A, B, C, D}) -> (A bsl 24) bor (B bsl 16) bor (C bsl 8) bor D. progname() -> case code:priv_dir(?MODULE) of {error, bad_name} -> filename:join([ filename:dirname(code:which(?MODULE)), "..", "priv", ?MODULE ]); Dir -> filename:join([Dir, ?MODULE]) end.