diff options
-rw-r--r-- | ChangeLog | 13 | ||||
-rw-r--r-- | doc/guide.html | 8 | ||||
-rw-r--r-- | doc/guide.tex | 4 | ||||
-rw-r--r-- | src/ejabberd.cfg.example | 7 | ||||
-rw-r--r-- | src/ejabberd_config.erl | 2 | ||||
-rw-r--r-- | src/ejabberd_s2s_out.erl | 111 | ||||
-rw-r--r-- | src/ejabberd_socket.erl | 6 |
7 files changed, 121 insertions, 30 deletions
@@ -1,3 +1,14 @@ +2008-12-26 Badlop <badlop@process-one.net> + + * src/ejabberd_config.erl: Option outgoing_s2s_options to define + s2s outgoing behaviour: IPv4, IPv6 and timeout (thanks to Stephan + Maka)(EJAB-665) + * src/ejabberd_s2s_out.erl: Likewise + * src/ejabberd_socket.erl: Likewise + * src/ejabberd.cfg.example: Likewise + * doc/guide.tex: Likewise + * doc/guide.html: Likewise + 2008-12-26 Evgeniy Khramtsov <ekhramtsov@process-one.net> * src/odbc/ejabberd_odbc.erl: get rid of SERIALIZABLE isolation @@ -10,7 +21,7 @@ 2008-12-24 Badlop <badlop@process-one.net> * src/aclocal.m4: Fixes in configure script: fix - disable-disable_zlib and disable-pam; in case of problems, PAM + disable-ejabberd_zlib and disable-pam; in case of problems, PAM verification aborts with error instead of warning. (EJAB-787) * src/configure.ac: Likewise * src/configure: Likewise diff --git a/doc/guide.html b/doc/guide.html index 2982f355d..6d143c335 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -745,6 +745,10 @@ use STARTTLS for s2s connections. file containing a SSL certificate. </DD><DT CLASS="dt-description"><B><TT>{domain_certfile, Domain, Path}</TT></B></DT><DD CLASS="dd-description"> Full path to the file containing the SSL certificate for a specific domain. +</DD><DT CLASS="dt-description"><B><TT>{outgoing_s2s_options, Methods, Timeout}</TT></B></DT><DD CLASS="dd-description"> +Specify which address families to try, in what order, and connect timeout in milliseconds. +By default it first tries connecting with IPv4, if that fails it tries using IPv6, +with a timeout of 10000 milliseconds. </DD><DT CLASS="dt-description"><B><TT>{s2s_default_policy, allow|deny}</TT></B></DT><DD CLASS="dd-description"> The default policy for incoming and outgoing s2s connections to other Jabber servers. The default value is <TT>allow</TT>. @@ -1032,6 +1036,10 @@ declarations of ACLs in the configuration file have the following syntax: </PRE></DD><DT CLASS="dt-description"><B><TT>{resource, <resource>}</TT></B></DT><DD CLASS="dd-description"> Matches any JID with a resource <TT><resource></TT>. Example: <PRE CLASS="verbatim">{acl, mucklres, {resource, "muckl"}}. +</PRE></DD><DT CLASS="dt-description"><B><TT>{shared_group, <groupname>}</TT></B></DT><DD CLASS="dd-description"> Matches any member of a Shared Roster Group with name <TT><groupname></TT> in the virtual host. Example: +<PRE CLASS="verbatim">{acl, techgroupmembers, {shared_group, "techteam"}}. +</PRE></DD><DT CLASS="dt-description"><B><TT>{shared_group, <groupname>, <server>}</TT></B></DT><DD CLASS="dd-description"> Matches any member of a Shared Roster Group with name <TT><groupname></TT> in the virtual host <TT><server></TT>. Example: +<PRE CLASS="verbatim">{acl, techgroupmembers, {shared_group, "techteam", "example.org"}}. </PRE></DD><DT CLASS="dt-description"><B><TT>{user_regexp, <regexp>}</TT></B></DT><DD CLASS="dd-description"> Matches any local user with a name that matches <TT><regexp></TT> on local virtual hosts. Example: <PRE CLASS="verbatim">{acl, tests, {user_regexp, "^test[0-9]*$"}}. diff --git a/doc/guide.tex b/doc/guide.tex index 9501c0cc5..afc63a3ff 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -870,6 +870,10 @@ There are some additional global options: file containing a SSL certificate. \titem{\{domain\_certfile, Domain, Path\}} \ind{options!domain\_certfile} Full path to the file containing the SSL certificate for a specific domain. + \titem{\{outgoing\_s2s\_options, Methods, Timeout\}} \ind{options!outgoing\_s2s\_options} + Specify which address families to try, in what order, and connect timeout in milliseconds. + By default it first tries connecting with IPv4, if that fails it tries using IPv6, + with a timeout of 10000 milliseconds. \titem{\{s2s\_default\_policy, allow|deny\}} The default policy for incoming and outgoing s2s connections to other Jabber servers. The default value is \term{allow}. diff --git a/src/ejabberd.cfg.example b/src/ejabberd.cfg.example index 6a6b52494..046db942b 100644 --- a/src/ejabberd.cfg.example +++ b/src/ejabberd.cfg.example @@ -186,6 +186,13 @@ %%{{s2s_host, "goodhost.org"}, allow}. %%{{s2s_host, "badhost.org"}, deny}. +%% +%% Outgoing S2S options +%% +%% Preferred address families (which to try first) and connect timeout +%% in milliseconds. +%% +%%{outgoing_s2s_options, [ipv4, ipv6], 10000}. %%% ============== %%% AUTHENTICATION diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl index 6ee0fa528..a5083424b 100644 --- a/src/ejabberd_config.erl +++ b/src/ejabberd_config.erl @@ -330,6 +330,8 @@ process_term(Term, State) -> add_option(language, Val, State); {outgoing_s2s_port, Port} -> add_option(outgoing_s2s_port, Port, State); + {outgoing_s2s_options, Methods, Timeout} -> + add_option(outgoing_s2s_options, {Methods, Timeout}, State); {s2s_use_starttls, Port} -> add_option(s2s_use_starttls, Port, State); {s2s_certfile, CertFile} -> diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index aa4c7ed96..5f5d905f8 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -119,6 +119,8 @@ -define(INVALID_XML_ERR, xml:element_to_string(?SERR_XML_NOT_WELL_FORMED)). +-define(SOCKET_DEFAULT_RESULT, {error, badarg}). + %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- @@ -206,7 +208,7 @@ open_socket(init, StateData) -> _ -> open_socket1(Addr, Port) end - end, {error, badarg}, AddrList) of + end, ?SOCKET_DEFAULT_RESULT, AddrList) of {ok, Socket} -> Version = if StateData#state.use_v10 -> @@ -239,34 +241,40 @@ open_socket(_, StateData) -> {next_state, open_socket, StateData}. %%---------------------------------------------------------------------- -open_socket1(Addr, Port) -> - ?DEBUG("s2s_out: connecting to ~s:~p~n", [Addr, Port]), - Res = case catch ejabberd_socket:connect( - Addr, Port, - [binary, {packet, 0}, - {active, false}]) of - {ok, _Socket} = R -> R; - {error, Reason1} -> - ?DEBUG("s2s_out: connect return ~p~n", [Reason1]), - catch ejabberd_socket:connect( - Addr, Port, - [binary, {packet, 0}, - {active, false}, inet6]); - {'EXIT', Reason1} -> - ?DEBUG("s2s_out: connect crashed ~p~n", [Reason1]), - catch ejabberd_socket:connect( - Addr, Port, - [binary, {packet, 0}, - {active, false}, inet6]) - end, - case Res of - {ok, Socket} -> - {ok, Socket}; - {error, Reason} -> - ?DEBUG("s2s_out: inet6 connect return ~p~n", [Reason]), - {error, Reason}; +%% IPv4 +open_socket1({_,_,_,_} = Addr, Port) -> + open_socket2(inet, Addr, Port); + +%% IPv6 +open_socket1({_,_,_,_,_,_,_,_} = Addr, Port) -> + open_socket2(inet6, Addr, Port); + +%% Hostname +open_socket1(Host, Port) -> + lists:foldl(fun(_Family, {ok, _Socket} = R) -> + R; + (Family, _) -> + Addrs = get_addrs(Host, Family), + lists:foldl(fun(_Addr, {ok, _Socket} = R) -> + R; + (Addr, _) -> + open_socket1(Addr, Port) + end, ?SOCKET_DEFAULT_RESULT, Addrs) + end, ?SOCKET_DEFAULT_RESULT, outgoing_s2s_families()). + +open_socket2(Type, Addr, Port) -> + ?DEBUG("s2s_out: connecting to ~p:~p~n", [Addr, Port]), + Timeout = outgoing_s2s_timeout(), + case (catch ejabberd_socket:connect(Addr, Port, + [binary, {packet, 0}, + {active, false}, Type], + Timeout)) of + {ok, _Socket} = R -> R; + {error, Reason} = R -> + ?DEBUG("s2s_out: connect return ~p~n", [Reason]), + R; {'EXIT', Reason} -> - ?DEBUG("s2s_out: inet6 connect crashed ~p~n", [Reason]), + ?DEBUG("s2s_out: connect crashed ~p~n", [Reason]), {error, Reason} end. @@ -1000,6 +1008,23 @@ test_get_addr_port(Server) -> end end, [], lists:seq(1, 100000)). +get_addrs(Host, Family) -> + Type = case Family of + inet4 -> a; + ipv4 -> a; + inet6 -> aaaa; + ipv6 -> aaaa + end, + case inet_res:getbyname(Host, Type) of + {ok, #hostent{h_addr_list = Addrs}} -> + ?DEBUG("~s of ~s resolved to: ~p~n", [Type, Host, Addrs]), + Addrs; + {error, Reason} -> + ?DEBUG("~s lookup of '~s' failed: ~p~n", [Type, Host, Reason]), + [] + end. + + outgoing_s2s_port() -> case ejabberd_config:get_local_option(outgoing_s2s_port) of Port when is_integer(Port) -> @@ -1008,6 +1033,36 @@ outgoing_s2s_port() -> 5269 end. +outgoing_s2s_families() -> + case ejabberd_config:get_local_option(outgoing_s2s_options) of + {Families, _} when is_list(Families) -> + Families; + undefined -> + %% DISCUSSION: Why prefer IPv4 first? + %% + %% IPv4 connectivity will be available for everyone for + %% many years to come. So, there's absolutely no benefit + %% in preferring IPv6 connections which are flaky at best + %% nowadays. + %% + %% On the other hand content providers hesitate putting up + %% AAAA records for their sites due to the mentioned + %% quality of current IPv6 connectivity. Making IPv6 the a + %% `fallback' may avoid these problems elegantly. + [ipv4, ipv6] + end. + +outgoing_s2s_timeout() -> + case ejabberd_config:get_local_option(outgoing_s2s_options) of + {_, Timeout} when is_integer(Timeout) -> + Timeout; + {_, infinity} -> + infinity; + undefined -> + %% 10 seconds + 10000 + end. + %% Human readable S2S logging: Log only new outgoing connections as INFO %% Do not log dialback log_s2s_out(false, _, _) -> ok; diff --git a/src/ejabberd_socket.erl b/src/ejabberd_socket.erl index ba706e4e8..01e1eddcb 100644 --- a/src/ejabberd_socket.erl +++ b/src/ejabberd_socket.erl @@ -30,6 +30,7 @@ %% API -export([start/4, connect/3, + connect/4, starttls/2, starttls/3, compress/1, @@ -94,7 +95,10 @@ start(Module, SockMod, Socket, Opts) -> end. connect(Addr, Port, Opts) -> - case gen_tcp:connect(Addr, Port, Opts) of + connect(Addr, Port, Opts, infinity). + +connect(Addr, Port, Opts, Timeout) -> + case gen_tcp:connect(Addr, Port, Opts, Timeout) of {ok, Socket} -> Receiver = ejabberd_receiver:start(Socket, gen_tcp, none), SocketData = #socket_state{sockmod = gen_tcp, |