static void proxy_wait_connect(struct login_proxy *proxy) { errno = net_geterror(proxy->server_fd); if (errno != 0) { proxy_fail_connect(proxy); if (!proxy_try_reconnect(proxy)) { proxy_log_connect_error(proxy); login_proxy_free(&proxy); } return; } proxy->connected = TRUE; proxy->num_waiting_connections_updated = TRUE; proxy->state_rec->last_success = ioloop_timeval; i_assert(proxy->state_rec->num_waiting_connections > 0); proxy->state_rec->num_waiting_connections--; proxy->state_rec->num_proxying_connections++; proxy->state_rec->num_disconnects_since_ts = 0; if ((proxy->ssl_flags & PROXY_SSL_FLAG_YES) != 0 && (proxy->ssl_flags & PROXY_SSL_FLAG_STARTTLS) == 0) { if (login_proxy_starttls(proxy) < 0) { login_proxy_free(&proxy); return; } } else { io_remove(&proxy->server_io); proxy_plain_connected(proxy); } }
static int login_proxy_connect(struct login_proxy *proxy) { struct login_proxy_record *rec; rec = login_proxy_state_get(proxy_state, &proxy->ip, proxy->port); if (timeval_cmp(&rec->last_failure, &rec->last_success) > 0 && rec->last_failure.tv_sec - rec->last_success.tv_sec > PROXY_IMMEDIATE_FAILURE_SECS && rec->num_waiting_connections != 0) { /* the server is down. fail immediately */ i_error("proxy(%s): Host %s:%u is down", proxy->client->virtual_user, proxy->host, proxy->port); login_proxy_free(&proxy); return -1; } proxy->server_fd = net_connect_ip(&proxy->ip, proxy->port, NULL); if (proxy->server_fd == -1) { proxy_log_connect_error(proxy); login_proxy_free(&proxy); return -1; } proxy->server_io = io_add(proxy->server_fd, IO_WRITE, proxy_wait_connect, proxy); if (proxy->connect_timeout_msecs != 0) { proxy->to = timeout_add(proxy->connect_timeout_msecs, proxy_connect_timeout, proxy); } proxy->state_rec = rec; proxy->state_rec->num_waiting_connections++; return 0; }
static void proxy_connect_timeout(struct login_proxy *proxy) { errno = ETIMEDOUT; proxy_log_connect_error(proxy); if (!proxy->connected) proxy_fail_connect(proxy); login_proxy_free(&proxy); }
static int login_proxy_connect(struct login_proxy *proxy) { struct login_proxy_record *rec = proxy->state_rec; if (rec->last_success.tv_sec == 0) { /* first connect to this IP. don't start immediately failing the check below. */ rec->last_success.tv_sec = ioloop_timeval.tv_sec - 1; } if (timeval_cmp(&rec->last_failure, &rec->last_success) > 0 && rec->last_failure.tv_sec - rec->last_success.tv_sec > PROXY_IMMEDIATE_FAILURE_SECS && rec->num_waiting_connections != 0) { /* the server is down. fail immediately */ i_error("proxy(%s): Host %s:%u is down", proxy->client->virtual_user, proxy->host, proxy->port); login_proxy_free(&proxy); return -1; } proxy->server_fd = net_connect_ip(&proxy->ip, proxy->port, proxy->source_ip.family == 0 ? NULL : &proxy->source_ip); if (proxy->server_fd == -1) { proxy_log_connect_error(proxy); login_proxy_free(&proxy); return -1; } proxy->server_io = io_add(proxy->server_fd, IO_WRITE, proxy_wait_connect, proxy); if (proxy->connect_timeout_msecs != 0) { proxy->to = timeout_add(proxy->connect_timeout_msecs, proxy_connect_timeout, proxy); } proxy->num_waiting_connections_updated = FALSE; proxy->state_rec = rec; proxy->state_rec->num_waiting_connections++; return 0; }
void client_proxy_failed(struct client *client, bool send_line) { if (send_line) { client_proxy_error(client, PROXY_FAILURE_MSG); } login_proxy_free(&client->login_proxy); proxy_free_password(client); i_free_and_null(client->proxy_user); i_free_and_null(client->proxy_master_user); /* call this last - it may destroy the client */ client_auth_failed(client); }
int login_proxy_new(struct client *client, const struct login_proxy_settings *set, proxy_callback_t *callback) { struct login_proxy *proxy; i_assert(client->login_proxy == NULL); if (set->host == NULL || *set->host == '\0') { client_log_err(client, t_strdup_printf( "proxy(%s): host not given", client->virtual_user)); return -1; } if (client->proxy_ttl <= 1) { client_log_err(client, t_strdup_printf( "proxy(%s): TTL reached zero - " "proxies appear to be looping?", client->virtual_user)); return -1; } proxy = i_new(struct login_proxy, 1); proxy->client = client; proxy->client_fd = -1; proxy->server_fd = -1; proxy->created = ioloop_timeval; proxy->ip = set->ip; proxy->source_ip = set->source_ip; proxy->host = i_strdup(set->host); proxy->port = set->port; proxy->connect_timeout_msecs = set->connect_timeout_msecs; proxy->notify_refresh_secs = set->notify_refresh_secs; proxy->ssl_flags = set->ssl_flags; proxy->state_rec = login_proxy_state_get(proxy_state, &proxy->ip, proxy->port); client_ref(client); if (login_proxy_connect(proxy) < 0) { login_proxy_free(&proxy); return -1; } DLLIST_PREPEND(&login_proxies_pending, proxy); proxy->callback = callback; client->login_proxy = proxy; return 0; }
void client_destroy(struct client *client, const char *reason) { if (client->destroyed) return; client->destroyed = TRUE; if (!client->login_success && reason != NULL) { reason = t_strconcat(reason, " ", client_get_extra_disconnect_reason(client), NULL); } if (reason != NULL) client_log(client, reason); if (last_client == client) last_client = client->prev; DLLIST_REMOVE(&clients, client); if (client->input != NULL) i_stream_close(client->input); if (client->output != NULL) o_stream_close(client->output); if (client->master_tag != 0) { i_assert(client->auth_request == NULL); i_assert(client->authenticating); i_assert(client->refcount > 1); client->authenticating = FALSE; master_auth_request_abort(master_auth, client->master_tag); client->refcount--; } else if (client->auth_request != NULL) { i_assert(client->authenticating); sasl_server_auth_abort(client); } else { i_assert(!client->authenticating); } if (client->io != NULL) io_remove(&client->io); if (client->to_disconnect != NULL) timeout_remove(&client->to_disconnect); if (client->to_auth_waiting != NULL) timeout_remove(&client->to_auth_waiting); if (client->auth_response != NULL) str_free(&client->auth_response); if (client->fd != -1) { net_disconnect(client->fd); client->fd = -1; } if (client->proxy_password != NULL) { safe_memset(client->proxy_password, 0, strlen(client->proxy_password)); i_free_and_null(client->proxy_password); } if (client->proxy_sasl_client != NULL) dsasl_client_free(&client->proxy_sasl_client); if (client->login_proxy != NULL) login_proxy_free(&client->login_proxy); if (client->v.destroy != NULL) client->v.destroy(client); if (client_unref(&client) && initial_service_count == 1) { /* as soon as this connection is done with proxying (or whatever), the process will die. there's no need for authentication anymore, so close the connection. do this only with initial service_count=1, in case there are other clients with pending authentications */ auth_client_disconnect(auth_client, "unnecessary connection"); } login_client_destroyed(); login_refresh_proctitle(); }
static void proxy_reconnect_timeout(struct login_proxy *proxy) { timeout_remove(&proxy->to); if (login_proxy_connect(proxy) < 0) login_proxy_free(&proxy); }