/** * http_ftp_initiate_passive_data: * @self: HttpProxy instance * * This function is called to initiate a passive data connection to the FTP * server. If it returns FALSE an active connection might still be * attempted. (however it is currently unimplemented). * * It currently creates the ZAttach object only does not start the actual * connection, it is done somewhat later in the http_ftp_complete_data() * function. **/ static gboolean http_ftp_initiate_passive_data(HttpProxy *self) { gchar response_msg[1024]; gint status; gchar *start, *end; gint i; gint ftp_pasv_endpoint[6]; gchar ip[16]; ZSockAddr *peer; ZAttachParams params; if (!http_ftp_communicate(self, "PASV", NULL, &status, response_msg, sizeof(response_msg))) return FALSE; if (status != 227) return FALSE; start = strchr(response_msg, '('); if (!start) { /* hmm no '(' in PASV response */ return FALSE; } start++; for (i = 0; i < 6; i++) { ftp_pasv_endpoint[i] = strtol(start, &end, 10); if ((i < 5 && *end != ',') || (i == 5 && *end != ')')) { g_string_sprintf(self->error_info, "Response to PASV is invalid; response='%s'", response_msg); return FALSE; } start = end + 1; } g_snprintf(ip, sizeof(ip), "%d.%d.%d.%d", ftp_pasv_endpoint[0], ftp_pasv_endpoint[1], ftp_pasv_endpoint[2], ftp_pasv_endpoint[3]); peer = z_sockaddr_inet_new(ip, 256 * ftp_pasv_endpoint[4] + ftp_pasv_endpoint[5]); memset(¶ms, 0, sizeof(params)); params.timeout = 30000; self->ftp_data_attach = z_attach_new(&self->super, ZD_PROTO_TCP, NULL, peer, ¶ms, NULL, NULL, NULL); z_sockaddr_unref(peer); /* attach not started yet */ return TRUE; }
/** * z_dispatch_bind_unref: * @self: this * * Decrement reference count for @self and free if that reaches zero. * **/ void z_dispatch_bind_unref(ZDispatchBind *self) { if (self && z_refcount_dec(&self->ref_cnt)) { if (self->type == ZD_BIND_SOCKADDR) z_sockaddr_unref(self->sa.addr); g_free(self); } }
/** * z_dispatch_chain_unref: * @self this * * Decrement the chain's reference counter, destroy it when the counter * reaches zero. */ static inline void z_dispatch_chain_unref(ZDispatchChain *self) { z_dispatch_chain_lock(self); if (z_decref(&self->ref_cnt) == 0) { z_dispatch_chain_unlock(self); if (self->accept_queue) g_async_queue_unref(self->accept_queue); z_dispatch_bind_unref(self->registered_key); z_sockaddr_unref(self->bound_addr); g_free(self->session_id); g_free(self); } else z_dispatch_chain_unlock(self); }
/** * z_dispatch_accept: * @fdstream Socket stream * @client Address of remote endpoint * @dest Address of original destination * @user_data this * * Internal callback, called when a new incoming connection is established. * Creates and initialises a new ZConnection, and dispatches it to the chain * either synchronously by z_dispatch_connection or asynchronously by pushing * it to the chain's accept queue. * * Note: this function runs in the main thread. * * Returns: TRUE */ static gboolean z_dispatch_accept(ZStream *fdstream, ZSockAddr *client, ZSockAddr *dest, gpointer user_data) { ZConnection *conn = NULL; ZDispatchChain *chain = (ZDispatchChain *) user_data; z_enter(); if (fdstream == NULL) { z_dispatch_connection(chain, NULL); z_return(TRUE); } if (chain->params.common.transparent) { ZSockAddr *listen_addr = NULL; gboolean non_transparent = FALSE; GList *p; switch (chain->registered_key->type) { case ZD_BIND_SOCKADDR: listen_addr = chain->registered_key->sa.addr; non_transparent = z_sockaddr_equal(listen_addr, dest); break; case ZD_BIND_IFACE: case ZD_BIND_IFACE_GROUP: /* NOTE: we are running in the main thread just like the * code that manipulates chain->listeners, thus we don't need to * lock here. This is even true for threaded listeners as * z_dispatch_accept runs in the main thread in that case too. */ for (p = chain->listeners; p; p = p->next) { ZListener *l = ((ZListenerEntry *) p->data)->listener; if (z_sockaddr_equal(l->local, dest)) { non_transparent = TRUE; listen_addr = l->local; break; } } break; } if (non_transparent) { gchar buf1[MAX_SOCKADDR_STRING], buf2[MAX_SOCKADDR_STRING]; /*LOG This message indicates that Listener/Receiver was configured to be accept transparent connections, but it was connected directly. Configure it either non-transparent or deny direct access to it and set up the appropriate TPROXY rule. @see: Listener @see: Receiver */ z_log(chain->session_id, CORE_ERROR, 1, "Transparent listener connected directly, dropping connection; local='%s', client_local='%s'", z_sockaddr_format(listen_addr, buf1, sizeof(buf1)), z_sockaddr_format(dest, buf2, sizeof(buf2))); z_stream_close(fdstream, NULL); z_stream_unref(fdstream); z_sockaddr_unref(client); z_sockaddr_unref(dest); z_return(TRUE); } } conn = z_connection_new(); conn->remote = client; conn->dest = dest; conn->local = z_sockaddr_ref(conn->dest); conn->dispatch_bind = z_dispatch_bind_ref(chain->registered_key); conn->protocol = chain->registered_key->protocol; conn->stream = fdstream; if (chain->threaded) g_async_queue_push(chain->accept_queue, conn); else z_dispatch_connection(chain, conn); z_return(TRUE); }