Skip to content

Instantly share code, notes, and snippets.

@msantos
Created August 31, 2010 21:44
Show Gist options
  • Select an option

  • Save msantos/559806 to your computer and use it in GitHub Desktop.

Select an option

Save msantos/559806 to your computer and use it in GitHub Desktop.
-module(pdump).
-include("epcap_net.hrl").
-export([start/0, start/1]).
-export([filename/1]).
-record(state, {
s, % PF_PACKET socket
c % monitored connections
}).
-define(TMPDIR, "/tmp/").
start() ->
start("eth0").
start(Dev) ->
{ok, Socket} = packet:socket(),
ok = packet:promiscuous(Socket, packet:ifindex(Socket, Dev)),
loop(#state{
s = Socket,
c = orddict:new()
}).
loop(#state{s = Socket} = State) ->
case procket:recvfrom(Socket, 65535) of
nodata ->
timer:sleep(10),
loop(State);
{ok, Data} ->
P = epcap_net:decapsulate(Data),
State1 = match(P, State),
loop(State1);
{'DOWN', Pid, process, _Object, _Info} ->
loop(State#state{
c = orddict:filter(
fun (_,V) when V == Pid -> false;
(_,_) -> true end,
State#state.c)
});
Error ->
error_logger:error_report(Error)
end.
% closed connections
match([ #ether{},
#ipv4{
saddr = Saddr,
daddr = Daddr
},
#tcp{
sport = 80,
dport = Dport,
rst = RST,
fin = FIN
},
_Payload ],
#state{
c = Connections
} = State) when RST =:= 1; FIN =:= 1 ->
Info = {{Saddr, 80}, {Daddr, Dport}},
case orddict:find(Info, Connections) of
{ok, Pid} ->
Pid ! eof,
State#state{
c = orddict:erase(Info, Connections)
};
error ->
State
end;
% connections in ESTABLISHED state
match([ #ether{},
#ipv4{
saddr = Saddr,
daddr = Daddr
},
#tcp{
sport = 80,
dport = Dport,
syn = 0,
rst = 0,
fin = 0,
ack = 1
},
Payload ],
#state{
c = Connections
} = State) ->
Info = {{Saddr, 80}, {Daddr, Dport}},
case orddict:find(Info, Connections) of
{ok, Pid} ->
Pid ! {data, Payload},
State;
error ->
Pid = spawn(fun() -> dumper(Info) end),
State#state{c = orddict:store(Info, Pid, Connections)}
end;
match(_, State) ->
State.
dumper(Info) ->
dumper(Info, []).
dumper(Info, Payload) ->
receive
{data, Data} ->
dumper(Info, [Data|Payload]);
eof ->
filer(Info, Payload)
after
5000 ->
error_logger:info_report([{timeout, Info}]),
filer(Info, Payload)
end.
filer(Info, Data) ->
Payload = list_to_binary(lists:reverse(Data)),
Name = filename(Info),
file:write_file(Name, Payload, [append]).
filename({{Saddr, Sport}, {Daddr, Dport}}) ->
?TMPDIR ++ "ip-" ++
inet_parse:ntoa(Saddr) ++ "-" ++ integer_to_list(Sport) ++ "_" ++
inet_parse:ntoa(Daddr) ++ "-" ++ integer_to_list(Dport).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment