Skip to content

Instantly share code, notes, and snippets.

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

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

Select an option

Save msantos/559809 to your computer and use it in GitHub Desktop.
dumpetag: parse payloads using epcap
-module(dumpetag).
-include("epcap_net.hrl").
-export([start/0, start/1]).
-export([filename/1]).
-record(state, {
c % monitored connections
}).
-define(TMPDIR, "/tmp/").
start() ->
start([{filter, "tcp and port 80"},
{interface, "eth0"},
{chroot, "priv/tmp"}]).
start(Arg) ->
epcap:start(Arg),
loop(#state{
c = orddict:new()
}).
loop(State) ->
receive
[{pkthdr, _}, {packet, Packet}] ->
P = epcap_net:decapsulate(Packet),
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:info_report([{error, Error}])
end.
% closed connections
match([ #ether{},
#ipv4{
saddr = Saddr,
daddr = Daddr
},
#tcp{
sport = Sport,
dport = Dport,
rst = RST,
fin = FIN
},
_Payload],
#state{
c = Connections
} = State) when RST =:= 1; FIN =:= 1 ->
Info = make_key({{Saddr, Sport}, {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 = Sport,
dport = Dport,
syn = 0,
rst = 0,
fin = 0,
ack = 1
},
Payload],
#state{
c = Connections
} = State) ->
Info = make_key({{Saddr, Sport}, {Daddr, Dport}}),
case orddict:find(Info, Connections) of
{ok, Pid} ->
Pid ! {data, Payload},
State;
error ->
{Pid, _Ref} = spawn_monitor(fun() -> dumper() end),
State#state{c = orddict:store(Info, Pid, Connections)}
end;
match(_, State) ->
State.
% canononical representation of the TCP connection
make_key({{_IP, 80}, _} = Key) ->
Key;
make_key({K2, {_IP, 80} = K1}) ->
{K1, K2}.
dumper() ->
dumper([]).
dumper(Payload) ->
receive
{data, Data} ->
dumper([Data|Payload]);
eof ->
filer(Payload)
after
5000 ->
filer(Payload)
end.
filer(Data) ->
Payload = list_to_binary(lists:reverse(Data)),
Name = filename(Payload),
file:write_file(Name, Payload, [append]).
filename(Payload) ->
{match, [Name]} = re:run(Payload, "ETag: \"([a-zA-Z0-9-]+)\"", [{capture, [1], list}]),
?TMPDIR ++ "etag-" ++ Name.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment