]> granicus.if.org Git - ejabberd/commitdiff
Support IPv6 connections for PostgreSQL, MySQL and LDAP
authorEvgeniy Khramtsov <ekhramtsov@process-one.net>
Fri, 11 May 2018 13:43:49 +0000 (16:43 +0300)
committerEvgeniy Khramtsov <ekhramtsov@process-one.net>
Fri, 11 May 2018 13:43:49 +0000 (16:43 +0300)
Fixes #2411

rebar.config
src/eldap.erl

index 0eaecdb5e96bd535b8e79f2f383b086bd0e30ea2..f68a16a24739c1dcb087b2aa3cb42fad706633ab 100644 (file)
@@ -34,9 +34,9 @@
         {if_var_true, stun, {stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.0.22"}}}},
         {if_var_true, sip, {esip, ".*", {git, "https://github.com/processone/esip", {tag, "1.0.23"}}}},
         {if_var_true, mysql, {p1_mysql, ".*", {git, "https://github.com/processone/p1_mysql",
-                                               {tag, "1.0.5"}}}},
+                                               "36efcd96f61a"}}},
         {if_var_true, pgsql, {p1_pgsql, ".*", {git, "https://github.com/processone/p1_pgsql",
-                                               {tag, "1.1.5"}}}},
+                                               "dd37ea053eb3"}}},
         {if_var_true, sqlite, {sqlite3, ".*", {git, "https://github.com/processone/erlang-sqlite3",
                                                {tag, "1.1.6"}}}},
         {if_var_true, pam, {epam, ".*", {git, "https://github.com/processone/epam",
index 03651c5088e913729f3b9058839c7b617499bcc6..b086a3e8b929df8f691b0be58484dc12b65bbb1f 100644 (file)
@@ -88,7 +88,7 @@
 -export_type([filter/0]).
 
 -include("ELDAPv3.hrl").
-
+-include_lib("kernel/include/inet.hrl").
 -include("eldap.hrl").
 
 -define(LDAP_VERSION, 3).
@@ -1057,15 +1057,11 @@ connect_bind(S) ->
     ?DEBUG("Connecting to LDAP server at ~s:~p with options ~p",
           [Host, S#eldap.port, Opts]),
     HostS = binary_to_list(Host),
-    SocketData = case S#eldap.tls of
-                  tls ->
-                      SockMod = ssl, ssl:connect(HostS, S#eldap.port, Opts);
-                  %% starttls -> %% TODO: Implement STARTTLS;
-                  _ ->
-                      SockMod = gen_tcp,
-                      gen_tcp:connect(HostS, S#eldap.port, Opts)
-                end,
-    case SocketData of
+    SockMod = case S#eldap.tls of
+                 tls -> ssl;
+                 _ -> gen_tcp
+             end,
+    case connect(HostS, S#eldap.port, SockMod, Opts) of
       {ok, Socket} ->
          case bind_request(Socket, S#eldap{sockmod = SockMod}) of
            {ok, NewS} ->
@@ -1132,3 +1128,66 @@ format_error(SockMod, Reason) ->
        _ ->
            Txt
     end.
+
+%%--------------------------------------------------------------------
+%% Connecting stuff
+%%--------------------------------------------------------------------
+-define(CONNECT_TIMEOUT, timer:seconds(15)).
+-define(DNS_TIMEOUT, timer:seconds(5)).
+
+connect(Host, Port, Mod, Opts) ->
+    case lookup(Host) of
+       {ok, AddrsFamilies} ->
+           do_connect(AddrsFamilies, Port, Mod, Opts, {error, nxdomain});
+       {error, _} = Err ->
+           Err
+    end.
+
+do_connect([{IP, Family}|AddrsFamilies], Port, Mod, Opts, _Err) ->
+    case Mod:connect(IP, Port, [Family|Opts], ?CONNECT_TIMEOUT) of
+       {ok, Sock} ->
+           {ok, Sock};
+       {error, _} = Err ->
+           do_connect(AddrsFamilies, Port, Mod, Opts, Err)
+    end;
+do_connect([], _Port, _Mod, _Opts, Err) ->
+    Err.
+
+lookup(Host) ->
+    case inet:parse_address(Host) of
+       {ok, IP} ->
+           {ok, [{IP, get_addr_type(IP)}]};
+       {error, _} ->
+           do_lookup([{Host, Family} || Family <- [inet6, inet]],
+                     [], {error, nxdomain})
+    end.
+
+do_lookup([{Host, Family}|HostFamilies], AddrFamilies, Err) ->
+    case inet:gethostbyname(Host, Family, ?DNS_TIMEOUT) of
+       {ok, HostEntry} ->
+           Addrs = host_entry_to_addrs(HostEntry),
+           AddrFamilies1 = [{Addr, Family} || Addr <- Addrs],
+           do_lookup(HostFamilies,
+                     AddrFamilies ++ AddrFamilies1,
+                     Err);
+       {error, _} = Err1 ->
+           do_lookup(HostFamilies, AddrFamilies, Err1)
+    end;
+do_lookup([], [], Err) ->
+    Err;
+do_lookup([], AddrFamilies, _Err) ->
+    {ok, AddrFamilies}.
+
+host_entry_to_addrs(#hostent{h_addr_list = AddrList}) ->
+    lists:filter(
+      fun(Addr) ->
+             try get_addr_type(Addr) of
+                 _ -> true
+             catch _:badarg ->
+                     false
+             end
+      end, AddrList).
+
+get_addr_type({_, _, _, _}) -> inet;
+get_addr_type({_, _, _, _, _, _, _, _}) -> inet6;
+get_addr_type(_) -> erlang:error(badarg).