From a56fb0bdc6d914fa3d2ffb6cbad301f5215dff7a Mon Sep 17 00:00:00 2001 From: Michael Santos Date: Fri, 17 Sep 2010 15:26:12 -0400 Subject: [PATCH] Try to figure out the default interface Use a dumb algorithm (whether an interface has a self-assigned IP address) to determine the default network device. Really should check the routing table instead for the interface associated with the default route. --- README | 23 +++++++++++++++++------ src/perv.erl | 39 ++++++++++++++++++++++++++++++++------- 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/README b/README index 2c1893f..65c1f1d 100644 --- a/README +++ b/README @@ -25,11 +25,26 @@ HOW TO USE IT perv:start() -> ok perv:start(Options) -> ok - Types Options = list() + Types Options = [EpcapArgs | Keyword] + EpcapArgs = list() + Keyword = [exclude] See epcap documentation for options. - Files are written to priv/files/. + perv will try to find the default interface to snoop (and will + probably get it wrong if there is more than one network interface). To + exclude the local host from packet dumps, use: + + > perv:start(exclude). + + To override the defaults, manually specify the device using the + epcap options, e.g.: + + > perv:start([ + {interface, "eth0"}, + {filter, "tcp and src port 80 and not host 10.11.11.11"}]). + + Content is written to priv/files/. A trace file containing the HTTP response is written to priv/tmp. The trace file can be unpacked by using pervon:content/3. @@ -99,9 +114,5 @@ TODO * pervon:content/3 should return a list of tuples containing the name, file type and file contents, rather than writing them directly to disk -* since the interface being snooped is known, grab the device's IP - address using inet:ifget/2. Provide an option for including/excluding - the user's address. - * add option to enable/disable debug messages and tracing diff --git a/src/perv.erl b/src/perv.erl index 3ae4af5..f668b66 100644 --- a/src/perv.erl +++ b/src/perv.erl @@ -37,6 +37,8 @@ -define(SERVER, ?MODULE). -export([start/0, start/1, stop/0]). +-export([dev/0]). +-export([getip/1]). -export([start_link/0, start_link/1]). -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). @@ -46,15 +48,14 @@ }). -define(EPCAP_DEFAULT_ARG, [{filter, "tcp and src port 80"}, - {interface, "wlan0"}, {promiscuous, true}, {chroot, "priv/tmp"}]). start() -> start_link(). -start(EpcapArg) -> - start_link(EpcapArg). +start(Options) -> + start_link(Options). stop() -> gen_server:call(?SERVER, [stop]). @@ -62,11 +63,20 @@ stop() -> start_link() -> start_link([]). -start_link(EpcapArg) -> - gen_server:start_link({local, ?SERVER}, ?MODULE, [EpcapArg], []). +start_link(Options) -> + gen_server:start_link({local, ?SERVER}, ?MODULE, [Options], []). -init([EpcapArg]) -> - epcap:start(EpcapArg ++ ?EPCAP_DEFAULT_ARG), +init([Options]) -> + {Dev, Address} = dev(), + + EpcapArgs = case Options of + exclude -> + [{filter, "tcp and src port 80 and not host " ++ inet_parse:ntoa(Address)}]; + Opt when is_list(Opt) -> + Options + end, + + epcap:start(EpcapArgs ++ [{interface, Dev}] ++ ?EPCAP_DEFAULT_ARG), {ok, #state{c = dict:new()}}. @@ -199,3 +209,18 @@ buf(Pid, SeqNo, Payload, PayloadSize) when PayloadSize < byte_size(Payload) -> pervon:buf(Pid, SeqNo, <>). +% Try to autostupidly figure out the local host's network device. +% Guaranteed to annoy. +dev() -> + {ok, Devs} = inet:getiflist(), + Ifs = [ {N, getip(N)} || N <- Devs ], + hd(lists:filter( + fun ({_, {127,_,_,_}}) -> false; + ({_, {169,_,_,_}}) -> false; + ({_, {_,_,_,_}}) -> true + end, Ifs)). + +getip(Dev) -> + {ok, Addr} = inet:ifget(Dev, [addr]), + proplists:get_value(addr, Addr). +