Skip to content

Instantly share code, notes, and snippets.

@linuxgemini
Last active September 26, 2021 02:22
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save linuxgemini/e43396a2674a943de0cc03f0eea1785a to your computer and use it in GitHub Desktop.
Save linuxgemini/e43396a2674a943de0cc03f0eea1785a to your computer and use it in GitHub Desktop.
%% Simple(?) WHOIS Client in Erlang
%% Copyright 2020 İlteriş Yağıztegin Eroğlu (linuxgemini) <new-iwhois@linuxgemini.space>
%% SPDX-License-Identifier: AGPL-3.0-or-later
-module(whois).
-export([query_iana/1,
query_ripe/1,
query_arin/1,
query_afrinic/1,
query_apnic/1,
query_lacnic/1,
query_radb/1,
query_host/2,
query_recursive/1]).
receive_data(Socket, SoFar) ->
receive
{tcp, Socket, Bin} ->
receive_data(Socket, [Bin|SoFar]);
{tcp_closed, Socket} ->
list_to_binary(lists:reverse(SoFar))
end.
string_clean(Str) ->
Final = try re:replace(Str, "\r\n", "\n", [global, caseless]) of
_ -> re:replace(Str, "\r\n", "\n", [global, caseless])
catch
_:_ -> ""
end,
FinalTwo = unicode:characters_to_list(Final),
FinalThree = string:trim(FinalTwo),
FinalThree.
remove_dupes(List) ->
Set = sets:from_list(List),
sets:to_list(Set).
merge_refs(L, S) -> lists:append(L, S).
remove(X, L) ->
[Y || Y <- L, Y =/= X].
regex_first_pass(S) ->
R = re:replace(S, "^whois:|^refer:|^ReferralServer:", "", [caseless]),
RTwo = re:replace(R, "Registrar WHOIS Server: ", "", [caseless]),
string_clean(unicode:characters_to_list(RTwo)).
regex_second_pass(S) ->
R = re:replace(S, "^whois:\/\/", "", [caseless]),
RTwo = re:replace(R, ":[0-9]+$", "", [caseless]),
string_clean(unicode:characters_to_list(RTwo)).
whois_string_clean(S) ->
R = regex_first_pass(S),
RTwo = regex_second_pass(R),
RThree = case re:run(RTwo, "^rwhois:\/\/", [caseless, {capture, none}]) of
match -> "";
nomatch -> RTwo
end,
RThree.
get_refer(S) ->
A = string_clean(S),
R = case re:run(A, "^whois:|^refer:|^ReferralServer:", [caseless, {capture, none}]) of
match -> whois_string_clean(A);
nomatch ->
case re:run(A, "^Registrar WHOIS Server: ", [caseless, {capture, none}]) of
match -> whois_string_clean(A);
nomatch -> ""
end
end,
RTwo = case re:run(R, "^#|^%|:", [caseless, global, {capture, none}]) of
match -> "";
nomatch -> R
end,
RTwo.
query_host(QueryString, Host) ->
{ok, Socket} = gen_tcp:connect(Host, 43,
[binary, {packet, 0}]),
%% I hate quirks
QS = case Host of
"whois.ripe.net" -> string:concat(QueryString, " -B");
"whois.arin.net" ->
case re:run(QueryString, "^AS[0-9]+", [caseless, {capture, none}]) of
match -> unicode:characters_to_list(re:replace(QueryString, "^AS", "a ", [caseless]));
nomatch -> QueryString
end;
"whois.afrinic.net" -> string:concat(QueryString, " -B");
_ -> QueryString
end,
ok = gen_tcp:send(Socket, string:concat(QS, "\r\n")),
Result = receive_data(Socket, []),
ResultTwo = binary_to_list(Result),
ResultThree = unicode:characters_to_list(ResultTwo),
string_clean(ResultThree).
query_host_print(QS, H) -> io:fwrite(string:concat(query_host(QS, H), "\n\n")).
just_print(R) -> io:fwrite(string:concat(R, "\n\n")).
get_proper_refs(R, H) ->
RefsRaw = lists:map(fun(X) -> get_refer(X) end, R),
RefProc = case item_exists("", RefsRaw) of
true -> ProcOne = remove("", RefsRaw),
remove([], ProcOne);
false -> remove([], RefsRaw)
end,
RefFinal = case RefProc == [] of
true -> merge_refs([], [H]);
false -> RefProc
end,
remove_dupes(RefFinal).
item_exists(I, L) -> lists:member(I, L).
query_recursive(QS, PrevRefs) ->
H = lists:nth(1, PrevRefs),
A = query_host(QS, H),
just_print(A),
Refs = get_proper_refs(string:split(A, "\n", all), H),
IsServerListed = item_exists(H, Refs),
case IsServerListed of
true -> ok;
false ->
AllRefs = merge_refs(Refs, remove_dupes(PrevRefs)),
query_recursive(QS, AllRefs)
end.
query_recursive(QS) ->
H = "whois.iana.org",
A = query_host(QS, H),
just_print(A),
Refs = get_proper_refs(string:split(A, "\n", all), H),
query_recursive(QS, merge_refs(remove_dupes(Refs), [H])).
query_iana(QS) -> query_host_print(QS, "whois.iana.org").
query_ripe(QS) -> query_host_print(QS, "whois.ripe.net").
query_arin(QS) -> query_host_print(QS, "whois.arin.net").
query_afrinic(QS) -> query_host_print(QS, "whois.afrinic.net").
query_apnic(QS) -> query_host_print(QS, "whois.apnic.net").
query_lacnic(QS) -> query_host_print(QS, "whois.lacnic.net").
query_radb(QS) -> query_host_print(QS, "whois.radb.net").
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment