This is an internal protocol between two trusted Dovecots.
#include "istream.h"
#include "md5.h"
#include "ostream.h"
+#include "istream-multiplex.h"
+#include "ostream-multiplex.h"
#include "iostream.h"
#include "iostream-ssl.h"
#include "iostream-proxy.h"
client->list_type = CLIENT_LIST_TYPE_NONE;
i_stream_unref(&client->input);
o_stream_unref(&client->output);
+ o_stream_unref(&client->multiplex_orig_output);
i_close_fd(&client->fd);
event_unref(&client->event);
event_unref(&client->event_auth);
static void client_start_tls(struct client *client)
{
+ bool add_multiplex_ostream = FALSE;
+
+ if (client->multiplex_output != NULL) {
+ /* restart multiplexing after TLS iostreams are set up */
+ client_multiplex_output_stop(client);
+ add_multiplex_ostream = TRUE;
+ }
client->connection_used_starttls = TRUE;
if (client_init_ssl(client) < 0) {
client_notify_disconnect(client,
}
login_refresh_proctitle();
+ if (add_multiplex_ostream)
+ client_multiplex_output_start(client);
client->v.starttls(client);
}
}
}
+void client_multiplex_output_start(struct client *client)
+{
+ if (client->v.iostream_change_pre != NULL)
+ client->v.iostream_change_pre(client);
+
+ client->multiplex_output =
+ o_stream_create_multiplex(client->output, LOGIN_MAX_OUTBUF_SIZE,
+ OSTREAM_MULTIPLEX_FORMAT_STREAM);
+ client->multiplex_orig_output = client->output;
+ client->output = client->multiplex_output;
+
+ if (client->v.iostream_change_post != NULL)
+ client->v.iostream_change_post(client);
+}
+
+void client_multiplex_output_stop(struct client *client)
+{
+ i_assert(client->multiplex_output != NULL);
+ i_assert(client->multiplex_orig_output != NULL);
+
+ if (client->v.iostream_change_pre != NULL)
+ client->v.iostream_change_pre(client);
+
+ i_assert(client->output == client->multiplex_output);
+ o_stream_unref(&client->output);
+ client->output = client->multiplex_orig_output;
+ client->multiplex_output = NULL;
+ client->multiplex_orig_output = NULL;
+
+ if (client->v.iostream_change_post != NULL)
+ client->v.iostream_change_post(client);
+}
+
static void
iostream_fd_proxy_finished(enum iostream_proxy_side side ATTR_UNUSED,
enum iostream_proxy_status status ATTR_UNUSED,
{
int fds[2];
- if (client->ssl_iostream == NULL) {
+ if (client->ssl_iostream == NULL && client->multiplex_output == NULL) {
/* Plaintext connection - We can send the fd directly to
the post-login process without any proxying. */
*fd_r = client->fd;
o_stream_set_no_error_handling(output, TRUE);
i_assert(client->io == NULL);
+ struct ostream *client_output = client->output;
+ if (client->multiplex_output != NULL) {
+ /* The post-login process takes over handling the multiplex
+ stream. */
+ i_assert(client_output == client->multiplex_output);
+ client_output = client->multiplex_orig_output;
+ }
client_ref(client);
client->iostream_fd_proxy =
iostream_proxy_create(input, output,
- client->input, client->output);
+ client->input, client_output);
i_stream_unref(&input);
o_stream_unref(&output);
int fd;
struct istream *input;
struct ostream *output;
+ /* If non-NULL, this is the multiplex ostream. It is usually the same
+ as the output pointer, but some plugins may make them different.
+ This isn't holding a reference, so it must not be unreferenced. */
+ struct ostream *multiplex_output;
+ struct ostream *multiplex_orig_output;
struct io *io;
struct iostream_proxy *iostream_fd_proxy;
struct timeout *to_auth_waiting;
int client_init_ssl(struct client *client);
void client_cmd_starttls(struct client *client);
+void client_multiplex_output_start(struct client *client);
+void client_multiplex_output_stop(struct client *client);
+
int client_get_plaintext_fd(struct client *client, int *fd_r, bool *close_fd_r);
unsigned int clients_get_count(void) ATTR_PURE;
#include "ioloop.h"
#include "istream.h"
#include "ostream.h"
+#include "iostream.h"
+#include "istream-multiplex.h"
#include "iostream-proxy.h"
#include "iostream-rawlog.h"
#include "iostream-ssl.h"
struct io *client_wait_io, *server_io;
struct istream *client_input, *server_input;
struct ostream *client_output, *server_output;
+ struct istream *multiplex_input, *multiplex_orig_input;
struct iostream_proxy *iostream_proxy;
struct ssl_iostream *server_ssl_iostream;
guid_128_t anvil_conn_guid;
ssl_iostream_destroy(&proxy->server_ssl_iostream);
io_remove(&proxy->server_io);
+ i_stream_destroy(&proxy->multiplex_orig_input);
+ proxy->multiplex_input = NULL;
i_stream_destroy(&proxy->server_input);
o_stream_destroy(&proxy->server_output);
if (proxy->server_fd != -1) {
proxy->detached = TRUE;
proxy->client_input = client->input;
proxy->client_output = client->output;
-
- o_stream_set_max_buffer_size(client->output, PROXY_MAX_OUTBUF_SIZE);
client->input = NULL;
client->output = NULL;
+ if (proxy->multiplex_orig_input != NULL &&
+ client->multiplex_output == proxy->client_output) {
+ /* both sides of the proxy want multiplexing and there are no
+ plugins hooking into the ostream. We can just step out of
+ the way and let the two sides multiplex directly. */
+ i_stream_unref(&proxy->server_input);
+ proxy->server_input = proxy->multiplex_orig_input;
+ proxy->multiplex_input = NULL;
+ proxy->multiplex_orig_input = NULL;
+
+ o_stream_unref(&proxy->client_output);
+ proxy->client_output = client->multiplex_orig_output;
+ client->multiplex_output = NULL;
+ client->multiplex_orig_output = NULL;
+ }
+ o_stream_set_max_buffer_size(proxy->client_output,
+ PROXY_MAX_OUTBUF_SIZE);
+
/* from now on, just do dummy proxying */
proxy->iostream_proxy =
iostream_proxy_create(proxy->client_input, proxy->client_output,
struct ssl_iostream_context *ssl_ctx;
struct ssl_iostream_settings ssl_set;
const char *error;
+ bool add_multiplex_istream = FALSE;
master_service_ssl_client_settings_to_iostream_set(
proxy->client->ssl_set, pool_datastack_create(), &ssl_set);
return -1;
}
+ if (proxy->multiplex_orig_input != NULL) {
+ /* restart multiplexing after TLS iostreams are set up */
+ i_assert(proxy->server_input == proxy->multiplex_input);
+ i_stream_unref(&proxy->server_input);
+ proxy->server_input = proxy->multiplex_orig_input;
+ proxy->multiplex_input = NULL;
+ proxy->multiplex_orig_input = NULL;
+ add_multiplex_istream = TRUE;
+ }
+
if (io_stream_create_ssl_client(ssl_ctx, proxy->host, &ssl_set,
proxy->event,
&proxy->server_input,
proxy->server_io = io_add_istream(proxy->server_input,
proxy_prelogin_input, proxy);
+ if (add_multiplex_istream)
+ login_proxy_multiplex_input_start(proxy);
return 0;
}
+void login_proxy_multiplex_input_start(struct login_proxy *proxy)
+{
+ struct istream *input = i_stream_create_multiplex(proxy->server_input,
+ LOGIN_MAX_INBUF_SIZE);
+ i_assert(proxy->multiplex_orig_input == NULL);
+ proxy->multiplex_orig_input = proxy->server_input;
+ proxy->multiplex_input = input;
+ proxy->server_input = input;
+
+ io_remove(&proxy->server_io);
+ proxy->server_io = io_add_istream(proxy->server_input,
+ proxy_prelogin_input, proxy);
+ /* caller needs to break out of the proxy_input() loop and get it
+ called again to update the istream. */
+ i_stream_set_input_pending(input, TRUE);
+}
+
static void proxy_kill_idle(struct login_proxy *proxy)
{
login_proxy_free_full(&proxy,
/* STARTTLS command was issued. */
int login_proxy_starttls(struct login_proxy *proxy);
+/* MULTIPLEX input was started. */
+void login_proxy_multiplex_input_start(struct login_proxy *proxy);
struct istream *login_proxy_get_istream(struct login_proxy *proxy);
struct ostream *login_proxy_get_ostream(struct login_proxy *proxy);