Skip to content

Instantly share code, notes, and snippets.

@jedisct1
Created October 17, 2012 06:14
Show Gist options
  • Save jedisct1/3903954 to your computer and use it in GitHub Desktop.
Save jedisct1/3903954 to your computer and use it in GitHub Desktop.
massresolver
-module(massresolver).
-export([init/1, worker_init/0, get_best_pid/1, collector_init/1, run/1]).
get_best_pid(Group) ->
Members = pg2:get_members(Group),
Members1 = lists:map(fun(Pid) ->
[{message_queue_len, Messages}] =
erlang:process_info(Pid, [message_queue_len]),
{Pid, Messages}
end, Members),
case lists:keysort(2, Members1) of
[{Pid, _} | _] ->
Pid;
[] -> {error, empty_process_group}
end.
collector_loop(OutDevice) ->
receive
{ ok, Domain, TTL } ->
io:format(OutDevice, "~B ~s~n", [TTL, Domain]),
collector_loop(OutDevice)
end.
collector_init(OutDevice) ->
register(collector, self()),
collector_loop(OutDevice).
parse_section(Section, _) ->
Domain = inet_dns:rr(Section, domain),
TTL = inet_dns:rr(Section, ttl),
whereis(collector) ! { ok, Domain, TTL },
ok.
resolve(Domain) ->
ResolverIPs = [{4,2,2,1}, {4,2,2,2}, {4,2,2,3}, {127,0,0,1}],
ResolverIP = lists:nth(random:uniform(length(ResolverIPs)), ResolverIPs),
Resolver = {ResolverIP, 53},
Res = inet_res:resolve(Domain, in, a, [{udp_payload_size, 65000}, {timeout,5000}, {recurse, true}, {inet6, false}, {nameservers, [Resolver]}]),
case Res of
{ok, DNSMSG} ->
Sections = inet_dns:msg(DNSMSG, anlist),
lists:foldl(fun parse_section/2, none, Sections),
true;
{error, {nxdomain, _}} ->
false;
{error, timeout} ->
resolve(Domain)
end.
worker_loop() ->
receive
Domain ->
resolve(Domain),
worker_loop()
end.
worker_init() ->
pg2:join(resolvers, self()),
worker_loop().
spawn_workers(0) ->
ok;
spawn_workers(N) ->
spawn(?MODULE, worker_init, []),
spawn_workers(N - 1).
spawn_collector(OutDevice) ->
spawn(?MODULE, collector_init, [OutDevice]).
init(Workers, OutFile) ->
pg2:create(resolvers),
spawn_workers(Workers),
{ok, OutDevice} = file:open(OutFile, [write]),
spawn_collector(OutDevice).
init(OutFile) ->
init(1000, OutFile).
parse(InDevice) ->
case io:get_line(InDevice, "") of
eof -> file:close(InDevice);
Line ->
Domain = string:strip(Line, both, $\n),
massresolver:get_best_pid(resolvers) ! Domain,
parse(InDevice)
end.
run(InFile) ->
{ok, InDevice} = file:open(InFile, [read]),
parse(InDevice).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment