mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-22 16:20:52 +01:00
136 lines
4.4 KiB
Erlang
136 lines
4.4 KiB
Erlang
%%%----------------------------------------------------------------------
|
|
%%% File : win32_dns.erl
|
|
%%% Author : Geoff Cant
|
|
%%% Purpose : Get name servers in a Windows machine
|
|
%%% Created : 5 Mar 2009 by Geoff Cant
|
|
%%%
|
|
%%%
|
|
%%% ejabberd, Copyright (C) 2002-2024 ProcessOne
|
|
%%%
|
|
%%% This program is free software; you can redistribute it and/or
|
|
%%% modify it under the terms of the GNU General Public License as
|
|
%%% published by the Free Software Foundation; either version 2 of the
|
|
%%% License, or (at your option) any later version.
|
|
%%%
|
|
%%% This program is distributed in the hope that it will be useful,
|
|
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
%%% General Public License for more details.
|
|
%%%
|
|
%%% You should have received a copy of the GNU General Public License along
|
|
%%% with this program; if not, write to the Free Software Foundation, Inc.,
|
|
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
%%%
|
|
%%%----------------------------------------------------------------------
|
|
|
|
-module(win32_dns).
|
|
-export([get_nameservers/0]).
|
|
|
|
-include("logger.hrl").
|
|
|
|
-define(IF_KEY, "\\hklm\\system\\CurrentControlSet\\Services\\TcpIp\\Parameters\\Interfaces").
|
|
-define(TOP_KEY, "\\hklm\\system\\CurrentControlSet\\Services\\TcpIp\\Parameters").
|
|
|
|
get_nameservers() ->
|
|
{_, Config} = pick_config(),
|
|
IPTs = get_value(["NameServer"], Config),
|
|
lists:filter(fun(IPTuple) -> is_good_ns(IPTuple) end, IPTs).
|
|
|
|
is_good_ns(Addr) ->
|
|
element(1,
|
|
inet_res:nnslookup("a.root-servers.net", in, a, [{Addr,53}],
|
|
timer:seconds(5)))
|
|
=:= ok.
|
|
|
|
reg() ->
|
|
{ok, R} = win32reg:open([read]),
|
|
R.
|
|
|
|
interfaces(R) ->
|
|
ok = win32reg:change_key(R, ?IF_KEY),
|
|
{ok, I} = win32reg:sub_keys(R),
|
|
I.
|
|
config_keys(R, Key) ->
|
|
ok = win32reg:change_key(R, Key),
|
|
[ {K,
|
|
case win32reg:value(R, K) of
|
|
{ok, V} -> try_translate(K, V);
|
|
_ -> undefined
|
|
end
|
|
} || K <- ["Domain", "DhcpDomain",
|
|
"NameServer", "DhcpNameServer", "SearchList"]].
|
|
|
|
try_translate(K, V) ->
|
|
try translate(K, V) of
|
|
Res ->
|
|
Res
|
|
catch
|
|
A:B ->
|
|
?ERROR_MSG("Error '~p' translating Win32 registry~n"
|
|
"K: ~p~nV: ~p~nError: ~p", [A, K, V, B]),
|
|
undefined
|
|
end.
|
|
|
|
translate(NS, V) when NS =:= "NameServer"; NS =:= "DhcpNameServer" ->
|
|
%% The IPs may be separated by commas ',' or by spaces " "
|
|
%% The parts of an IP are separated by dots '.'
|
|
IPsStrings = [string:tokens(IP, ".") || IP <- string:tokens(V, " ,")],
|
|
[ list_to_tuple([list_to_integer(String) || String <- IpStrings])
|
|
|| IpStrings <- IPsStrings];
|
|
translate(_, V) -> V.
|
|
|
|
interface_configs(R) ->
|
|
[{If, config_keys(R, ?IF_KEY ++ "\\" ++ If)}
|
|
|| If <- interfaces(R)].
|
|
|
|
sort_configs(Configs) ->
|
|
lists:sort(fun ({_, A}, {_, B}) ->
|
|
ANS = proplists:get_value("NameServer", A),
|
|
BNS = proplists:get_value("NameServer", B),
|
|
if ANS =/= undefined, BNS =:= undefined -> false;
|
|
true -> count_undef(A) < count_undef(B)
|
|
end
|
|
end,
|
|
Configs).
|
|
|
|
count_undef(L) when is_list(L) ->
|
|
lists:foldl(fun ({_K, undefined}, Acc) -> Acc +1;
|
|
({_K, []}, Acc) -> Acc +1;
|
|
(_, Acc) -> Acc
|
|
end, 0, L).
|
|
|
|
all_configs() ->
|
|
R = reg(),
|
|
TopConfig = config_keys(R, ?TOP_KEY),
|
|
Configs = [{top, TopConfig}
|
|
| interface_configs(R)],
|
|
win32reg:close(R),
|
|
{TopConfig, Configs}.
|
|
|
|
pick_config() ->
|
|
{TopConfig, Configs} = all_configs(),
|
|
NSConfigs = [{If, C} || {If, C} <- Configs,
|
|
get_value(["DhcpNameServer","NameServer"], C)
|
|
=/= undefined],
|
|
case get_value(["DhcpNameServer","NameServer"],
|
|
TopConfig) of
|
|
%% No top level nameserver to pick interface with
|
|
undefined ->
|
|
hd(sort_configs(NSConfigs));
|
|
%% Top level has a nameserver - use this to select an interface.
|
|
NS ->
|
|
Cs = [ {If, C}
|
|
|| {If, C} <- Configs,
|
|
lists:member(NS,
|
|
[get_value(["NameServer"], C),
|
|
get_value(["DhcpNameServer"], C)])],
|
|
hd(sort_configs(Cs))
|
|
end.
|
|
|
|
get_value([], _Config) -> undefined;
|
|
get_value([K|Keys], Config) ->
|
|
case proplists:get_value(K, Config) of
|
|
undefined -> get_value(Keys, Config);
|
|
V -> V
|
|
end.
|