diff --git a/ChangeLog b/ChangeLog index e23272baa..4a07966d0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2009-03-05 Badlop + * src/ejabberd_app.erl: In a Windows machine, explicitly add the + nameservers, as it seems Erlang does not do itself (EJAB-860) + * src/win32_dns.erl: Get name servers from Windows registy (thanks + to Geoff Cant) + * doc/guide.tex: Require OpenSSL 0.9.8f or higher (EJAB-877) * doc/guide.html: Likewise diff --git a/src/ejabberd_app.erl b/src/ejabberd_app.erl index 41e7444d8..d109a2082 100644 --- a/src/ejabberd_app.erl +++ b/src/ejabberd_app.erl @@ -63,6 +63,7 @@ start(normal, _Args) -> %eprof:start(), %eprof:profile([self()]), %fprof:trace(start, "/tmp/fprof"), + maybe_add_nameservers(), start_modules(), ejabberd_listener:start_listeners(), ?INFO_MSG("ejabberd ~s is started in the node ~p", [?VERSION, node()]), @@ -180,3 +181,16 @@ get_log_path() -> Path end end. + + +%% If ejabberd is running on some Windows machine, get nameservers and add to Erlang +maybe_add_nameservers() -> + case os:type() of + {win32, _} -> add_windows_nameservers(); + _ -> ok + end. + +add_windows_nameservers() -> + IPTs = win32_dns_test:get_nameservers(), + ?INFO_MSG("Adding machine's DNS IPs to Erlang system:~n~p", [IPTs]), + lists:foreach(fun(IPT) -> inet_db:add_ns(IPT) end, IPTs). diff --git a/src/win32_dns.erl b/src/win32_dns.erl new file mode 100644 index 000000000..79725cbab --- /dev/null +++ b/src/win32_dns.erl @@ -0,0 +1,122 @@ +%%%---------------------------------------------------------------------- +%%% 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-2009 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., 59 Temple Place, Suite 330, Boston, MA +%%% 02111-1307 USA +%%% +%%%---------------------------------------------------------------------- + +-module(win32_dns). +-export([get_nameservers/0]). + +-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, any, [{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} -> translate(K, V); + _ -> undefined + end + } || K <- ["Domain", "DhcpDomain", + "NameServer", "DhcpNameServer", "SearchList"]]. + +translate(NS, V) when NS =:= "NameServer"; NS =:= "DhcpNameServer" -> + 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.