diff --git a/apps/kolab_guam/src/kolab_guam_listener.erl b/apps/kolab_guam/src/kolab_guam_listener.erl index 7b7a283..c50b4b1 100644 --- a/apps/kolab_guam/src/kolab_guam_listener.erl +++ b/apps/kolab_guam/src/kolab_guam_listener.erl @@ -1,86 +1,95 @@ %% Copyright 2015 Kolab Systems AG (http://www.kolabsys.com) %% %% Aaron Seigo (Kolab Systems) %% %% 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 3 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, see . -module(kolab_guam_listener). -behaviour(supervisor). -define(DEFAULT_IMAP_PORT, 143). %% API -export([start_link/2, create_initial_listeners/1, cleanup/1]). %% gen_supervisor callbacks -export([init/1]). %% state record definition %%TODO: support reconfiguration requests %% public API start_link(Name, Config) -> supervisor:start_link(?MODULE, [Name, Config]). %% gen_server API init([Name, Config]) -> Host = proplists:get_value(host, Config, none), + NetIface = proplists:get_value(net_iface, Config, none), Port = proplists:get_value(port, Config, ?DEFAULT_IMAP_PORT), ImplicitTLS = proplists:get_value(implicit_tls, Config, false), TLSConfig = proplists:get_value(tls_config, Config, []), Rules = proplists:get_value(rules, Config, []), - Options = listen_options(Host, ImplicitTLS, TLSConfig), + Options = listen_options(NetIface, Host, ImplicitTLS, TLSConfig), lager:info("Starting listener \"~p\" on port ~B (~p) with ~B rules", [Name, Port, Options, length(Rules)]), { ok, ListenSocket } = listen(ImplicitTLS, Port, Options), spawn_link(?MODULE, cleanup, [ListenSocket]), %% setting up the initial listeners must be done async to allow the init to be done and the supervisor to be setup spawn_link(kolab_guam_listener, create_initial_listeners, [self()]), ImapConfig = imap_config(proplists:get_value(imap_server, Config, none)), lager:debug("ImapConfig is ~p", [ImapConfig]), {ok, { { simple_one_for_one, 60, 3600 }, [ { session, { kolab_guam_session, start_link, [self(), ListenSocket, ImapConfig, ImplicitTLS, TLSConfig, Rules] }, temporary, 1000, worker, [kolab_guam_session] } ] } }. imap_config(none) -> kolab_guam_sup:default_imap_server_config(); imap_config(Backend) -> kolab_guam_sup:imap_server_config(Backend). -listen_options(none, ImplicitTLS, TLSConfig) -> default_listen_options(ImplicitTLS, TLSConfig); -listen_options(Hostname, ImplicitTLS, TLSConfig) -> +listen_options(none, none, ImplicitTLS, TLSConfig) -> default_listen_options(ImplicitTLS, TLSConfig); +listen_options(none, Hostname, ImplicitTLS, TLSConfig) -> case inet:gethostbyname(Hostname) of { ok, { hostent, _HostName, _Unused, inet, _Ver, [IP] } } -> [ { ip, IP } | default_listen_options(ImplicitTLS, TLSConfig) ]; _ -> - listen_options(none, ImplicitTLS, TLSConfig) + listen_options(none, none, ImplicitTLS, TLSConfig) + end; +listen_options(Iface, Hostname, ImplicitTLS, TLSConfig) -> + { ok, Ifaces } = inet:getifaddrs(), + case proplists:get_value(Iface, Ifaces) of + undefined -> listen_options(none, Hostname, ImplicitTLS, TLSConfig); + Info -> Addr = proplists:get_value(addr, Info, none), + lager:info("YEAH! ~p", [Addr]), + listen_options(none, Addr, ImplicitTLS, TLSConfig) end. default_listen_options(true, TLSConfig) -> [ { reuseaddr, true }, {active, once } | TLSConfig ]; default_listen_options(_ImplicitTLS, _Config) -> [ { active, once }, { reuseaddr, true } ]. create_initial_listeners(PID) when is_pid(PID) -> lager:debug("Creating session pool for listener ~p", [PID]), [ supervisor:start_child(PID, []) || _ <- lists:seq(1, 20) ]. cleanup(Socket) -> process_flag(trap_exit, true), receive { 'EXIT', _PID, _ } -> ok; _ -> cleanup(Socket) end, gen_tcp:close(Socket). listen(true, Port, Options) -> ssl:listen(Port, Options); listen(_ImplicitTLS, Port, Options) -> gen_tcp:listen(Port, Options). %% private API diff --git a/docs/deployment.md b/docs/deployment.md index 33cd450..484d0ed 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -1,142 +1,154 @@ Deploying Guam ============== This document covers the deployment of Guam in a Kolab environment. Installation ------------ TBD Running Guam ------------ Guam includes a kolab_guam binary in the bin/ directory. This binary can be used to start, stop, restart, etc. Guam. For example, assumign kolab_guam is in your path: kolab_guam start # starts Guam in the background kolab_guam console # starts Guam in a foreground console kolab_guam ping # determine if the server is running or not kolab_guam attach # attaches to a running Guam and opens a console to it kolab_guam stop # stop Guam kolab_guam restart # restarts Guam The version of Guam packaged with Kolab comes with a systemd module file, which can be used to integrate with systemd managed operating systems. Configuration ------------- Guam's config is stored in releases//sys.config. The file contains configuration for the following aspect of Guam: * imap_servers: The IMAP servers to connet to * listeners: the ports Guam should be listening on These are all wrapped in a { kolab_guam, [ ... ] } entry in the file. ### imap_servers imap_servers can have one or more entries in it, one for each IMAP server that Guam may use. Each IMAP server can have the following aspects specified: * host: an IP address or hostname to connect to * port: the port to connet to * tls: false for no encryption, true for implicit SSL or starttls for the encryption to be started with STARTTLS on IMAP servers that advertise that capability (NOTE: starttls not included in v0.2) An IMAP server labeled "default" is required to exist for proper functionality. Example: { imap_servers, [ { default, [ { host, "192.168.56.101" }, { port, 993 }, { tls, true } ] }, { other_server, [ { host, "kolab.acmeinc.com" }, { port, 143 } { tls, false } ] }, If running Guam on the same server as the IMAP backend, it is recommended to set tls to false as encryption between Guam and the IMAP server is in that case is superfluous and therefore simply a waste of resources. ### listeners For each port that Guam should listen on one listener configuration must be present. This configuration also controls which rules are applied. Each listener is defined by a key, which is the name used in e.g. logging, and a value which contains the configuration specifics. Example: { listeners, [ { default, [ { host, "127.0.0.1" }, { port, 1936 }, { imap_server, default }, { rules, [ { filter_groupware, [] } ] }, { tls_config, [ { certfile, "/etc/ssl/sample.pem" } ] } ] + }, + { default, [ + { net_iface, "eth0" }, + { port, 1993 }, + { imap_server, default }, + { implicit_tls, true }, + { rules, [ { filter_groupware, [] } ] }, + { tls_config, [ { certfile, "/etc/ssl/sample.pem" } ] } + ] } } The host entry is optional, and is used to bind the connection to a specific -network interface. Leaving it empty will cause Guam to bind to the port accross +network interface by ip address. Alternatively, the net_iface may be defined and +guam will attempt to bind to an address on that network device. net_iface overrides +host, though host will be used as a fallback if net_iface does not produce a network +interface. Leaving host and net_iface empty will cause Guam to bind to the port accross all network interfaces available to it. -port defines the port it is listening on. +port defines the port the listener is active on. imap_server refers to the entry in the imap_servers block. If not provided, the default entry in the imap_servers configuration is used. rules contains the rules to apply to sessions with this listener. If not provided, then no rules are applied. The rules are a list containing pairs of rule names and rule configuration. In the above example, there is exactly one rule to be applied and it has no specific configuration. A more elaborate example might be: { rules, [ { filter_groupware, [] }, { deny_access, [ "badhost.com" ] }, { filter_users, [ "*@acme.com", { silent, true } ] } ] } Finally, there is the tls_config. This must be provided if STARTTLS is to be supported. (Implicit TLS is currently not supported by listeners.) The minimum configuration provides the path to a PEM bundle, however one can also define the path to cacerts, client certs, individuals key/cert files (e.g. not in a PEM bundle) as well as the cyphers to be used. See this for full details of all supported options: http://www.erlang.org/doc/man/ssl.html Logging ------- Logging is controlled with a top-level group in the group with the key "lager". A sample configuration would look like this: { lager, [ { handlers, [ { lager_console_backend, debug }, { lager_file_backend, [ { file, "log/error.log"}, { level, error } ] }, { lager_file_backend, [ { file, "log/console.log"}, { level, debug } ] } ] } ] } Each handler describes where the messages are routed (console, file, ...) and the message levels which are directed to those end points. The message levels used in egara include: info, warn, error and debug. See https://github.com/basho/lager for more details on lager configuration.