aboutsummaryrefslogtreecommitdiff
path: root/src/win32_dns.erl
blob: 79725cbab9d1a19dc00aa075c7bf9c00603234c7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
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.