END_TEST START_TEST (listen_test) { conn_t *res; const pr_netaddr_t *bind_addr = NULL; res = proxy_ftp_conn_listen(NULL, NULL, FALSE); fail_unless(res == NULL, "Failed to handle null pool"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL, strerror(errno), errno); res = proxy_ftp_conn_listen(p, NULL, FALSE); fail_unless(res == NULL, "Failed to handle null bind address"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL, strerror(errno), errno); bind_addr = pr_netaddr_get_addr(p, "127.0.0.1", NULL); fail_unless(bind_addr != NULL, "Failed to address for 127.0.0.1: %s", strerror(errno)); pr_netaddr_set_port((pr_netaddr_t *) bind_addr, htons(0)); mark_point(); res = proxy_ftp_conn_listen(p, bind_addr, FALSE); fail_unless(res != NULL, "Failed to listen: %s", strerror(errno)); pr_inet_close(p, res); mark_point(); res = proxy_ftp_conn_listen(p, bind_addr, TRUE); fail_unless(res != NULL, "Failed to listen: %s", strerror(errno)); pr_inet_close(p, res); }
END_TEST START_TEST (inet_create_conn_test) { int sockfd = -2, port = INPORT_ANY; conn_t *conn, *conn2; conn = pr_inet_create_conn(NULL, sockfd, NULL, port, FALSE); fail_unless(conn == NULL, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Failed to set errno to EINVAL (%d), got '%s' (%d)", EINVAL, strerror(errno), errno); conn = pr_inet_create_conn(p, sockfd, NULL, port, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); fail_unless(conn->listen_fd == sockfd, "Expected listen_fd %d, got %d", sockfd, conn->listen_fd); pr_inet_close(p, conn); sockfd = -1; conn = pr_inet_create_conn(p, sockfd, NULL, port, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); fail_unless(conn->listen_fd != sockfd, "Expected listen_fd other than %d, got %d", sockfd, conn->listen_fd); /* Create another conn, with the same port, make sure it fails. */ conn2 = pr_inet_create_conn(p, sockfd, NULL, conn->local_port, FALSE); if (conn2 == NULL) { fail_unless(errno == EADDRINUSE, "Expected EADDRINUSE (%d), got %s (%d)", EADDRINUSE, strerror(errno), errno); pr_inet_close(p, conn2); } pr_inet_close(p, conn); }
int proxy_session_free(pool *p, struct proxy_session *proxy_sess) { conn_t *conn; if (proxy_sess == NULL) { errno = EINVAL; return -1; } /* Close any open connections. */ conn = proxy_sess->frontend_data_conn; if (conn != NULL) { pr_inet_close(p, conn); proxy_sess->frontend_data_conn = session.d = NULL; } conn = proxy_sess->backend_ctrl_conn; if (conn != NULL) { pr_inet_close(p, conn); proxy_sess->backend_ctrl_conn = NULL; } conn = proxy_sess->backend_data_conn; if (conn != NULL) { pr_inet_close(p, conn); proxy_sess->backend_data_conn = NULL; } destroy_pool(proxy_sess->pool); return 0; }
END_TEST START_TEST (inet_create_conn_test) { int sockfd = -2, port = INPORT_ANY; conn_t *conn; conn = pr_inet_create_conn(NULL, sockfd, NULL, port, FALSE); fail_unless(conn == NULL, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Failed to set errno to EINVAL (%d), got '%s' (%d)", EINVAL, strerror(errno), errno); conn = pr_inet_create_conn(p, sockfd, NULL, port, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); fail_unless(conn->listen_fd == sockfd, "Expected listen_fd %d, got %d", sockfd, conn->listen_fd); pr_inet_close(p, conn); sockfd = -1; conn = pr_inet_create_conn(p, sockfd, NULL, port, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); fail_unless(conn->listen_fd != sockfd, "Expected listen_fd other than %d, got %d", sockfd, conn->listen_fd); pr_inet_close(p, conn); }
END_TEST START_TEST (inet_connect_ipv4_test) { int sockfd = -1, port = INPORT_ANY, res; conn_t *conn; const pr_netaddr_t *addr; res = pr_inet_connect(NULL, NULL, NULL, port); fail_unless(res < 0, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); conn = pr_inet_create_conn(p, sockfd, NULL, port, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); res = pr_inet_connect(p, conn, NULL, 80); fail_unless(res < 0, "Failed to handle null address"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); addr = pr_netaddr_get_addr(p, "127.0.0.1", NULL); fail_unless(addr != NULL, "Failed to resolve '127.0.0.1': %s", strerror(errno)); res = pr_inet_connect(p, conn, addr, 80); fail_unless(res < 0, "Connected to 127.0.0.1#80 unexpectedly"); fail_unless(errno == ECONNREFUSED, "Expected ECONNREFUSED (%d), got %s (%d)", ECONNREFUSED, strerror(errno), errno); /* Try connecting to Google's DNS server. */ addr = pr_netaddr_get_addr(p, "8.8.8.8", NULL); fail_unless(addr != NULL, "Failed to resolve '8.8.8.8': %s", strerror(errno)); res = pr_inet_connect(p, conn, addr, 53); if (res < 0) { /* Note: We get EINVAL here because the socket already tried (and failed) * to connect to a different address. Interestingly, trying to connect(2) * using that same fd to a different address yields EINVAL. */ fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); } pr_inet_close(p, conn); conn = pr_inet_create_conn(p, sockfd, NULL, port, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); res = pr_inet_connect(p, conn, addr, 53); fail_if(res < 0, "Failed to connect to 8.8.8.8#53: %s", strerror(errno)); res = pr_inet_connect(p, conn, addr, 53); fail_unless(res < 0, "Failed to connect to 8.8.8.8#53: %s", strerror(errno)); fail_unless(errno == EISCONN, "Expected EISCONN (%d), got %s (%d)", EISCONN, strerror(errno), errno); pr_inet_close(p, conn); }
END_TEST START_TEST (inet_openrw_test) { int sockfd = -1, port = INPORT_ANY; conn_t *conn, *res; pr_netaddr_t *addr; res = pr_inet_openrw(NULL, NULL, NULL, PR_NETIO_STRM_CTRL, -1, -1, -1, FALSE); fail_unless(res == NULL, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); conn = pr_inet_create_conn(p, sockfd, NULL, port, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); res = pr_inet_openrw(p, conn, NULL, PR_NETIO_STRM_CTRL, -1, -1, -1, FALSE); fail_unless(res == NULL, "Opened rw conn unexpectedly"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); addr = pr_netaddr_get_addr(p, "127.0.0.1", NULL); fail_unless(addr != NULL, "Failed to resolve 127.0.0.1: %s", strerror(errno)); res = pr_inet_openrw(p, conn, addr, PR_NETIO_STRM_CTRL, -1, -1, -1, FALSE); fail_unless(res != NULL, "Failed to open rw conn: %s", strerror(errno)); (void) pr_inet_close(p, res); res = pr_inet_openrw(p, conn, addr, PR_NETIO_STRM_CTRL, -1, -1, -1, TRUE); fail_unless(res != NULL, "Failed to open rw conn: %s", strerror(errno)); }
END_TEST START_TEST (inet_set_block_test) { int sockfd = -1, port = INPORT_ANY, res; conn_t *conn; res = pr_inet_set_block(NULL, NULL); fail_unless(res < 0, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected errno EINVAL (%d), got '%s' (%d)", EINVAL, strerror(errno), errno); res = pr_inet_set_nonblock(NULL, NULL); fail_unless(res < 0, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected errno EINVAL (%d), got '%s' (%d)", EINVAL, strerror(errno), errno); conn = pr_inet_create_conn(p, sockfd, NULL, port, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); res = pr_inet_set_nonblock(p, conn); fail_unless(res < 0, "Failed to handle bad socket"); fail_unless(errno == EBADF, "Expected EBADF (%d), got %s (%d)", EBADF, strerror(errno), errno); res = pr_inet_set_block(p, conn); fail_unless(res < 0, "Failed to handle bad socket"); fail_unless(errno == EBADF, "Expected EBADF (%d), got %s (%d)", EBADF, strerror(errno), errno); pr_inet_close(p, conn); }
END_TEST START_TEST (inet_connect_nowait_test) { int sockfd = -1, port = INPORT_ANY, res; conn_t *conn; pr_netaddr_t *addr; res = pr_inet_connect_nowait(NULL, NULL, NULL, port); fail_unless(res < 0, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); conn = pr_inet_create_conn(p, sockfd, NULL, port, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); res = pr_inet_connect_nowait(p, conn, NULL, 80); fail_unless(res < 0, "Failed to handle null connection"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); addr = pr_netaddr_get_addr(p, "127.0.0.1", NULL); fail_unless(addr != NULL, "Failed to resolve '127.0.0.1': %s", strerror(errno)); res = pr_inet_connect_nowait(p, conn, addr, 80); fail_unless(res < 0, "Connected to 127.0.0.1#80 unexpectedly"); pr_inet_close(p, conn); }
END_TEST START_TEST (inet_set_socket_opts_test) { int sockfd = -1, port = INPORT_ANY, res; conn_t *conn; struct tcp_keepalive keepalive; res = pr_inet_set_socket_opts(NULL, NULL, 1, 2, NULL); fail_unless(res < 0, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); conn = pr_inet_create_conn(p, sockfd, NULL, port, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); res = pr_inet_set_socket_opts(p, conn, 1, 2, NULL); fail_unless(res == 0, "Failed to set socket opts: %s", strerror(errno)); res = pr_inet_set_socket_opts(p, conn, INT_MAX, INT_MAX, NULL); fail_unless(res == 0, "Failed to set socket opts: %s", strerror(errno)); keepalive.keepalive_enabled = 1; keepalive.keepalive_idle = 1; keepalive.keepalive_count = 2; keepalive.keepalive_intvl = 3; res = pr_inet_set_socket_opts(p, conn, 1, 2, &keepalive); fail_unless(res == 0, "Failed to set socket opts: %s", strerror(errno)); pr_inet_close(p, conn); }
END_TEST START_TEST (inet_conn_info_test) { int sockfd = -1, port = INPORT_ANY, res; conn_t *conn; res = pr_inet_get_conn_info(NULL, -1); fail_unless(res < 0, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); conn = pr_inet_create_conn(p, sockfd, NULL, port, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); res = pr_inet_get_conn_info(conn, -1); fail_unless(res < 0, "Failed to handle bad file descriptor"); fail_unless(errno == EBADF, "Expected EBADF (%d), got %s (%d)", EBADF, strerror(errno), errno); res = pr_inet_get_conn_info(conn, 1); fail_unless(res < 0, "Failed to handle bad file descriptor"); fail_unless(errno == ENOTSOCK, "Expected ENOTSOCK (%d), got %s (%d)", ENOTSOCK, strerror(errno), errno); pr_inet_close(p, conn); }
END_TEST START_TEST (inet_set_proto_opts_ipv6_test) { #ifdef PR_USE_IPV6 int fd, sockfd = -1, port = INPORT_ANY, res; conn_t *conn; unsigned char use_ipv6; use_ipv6 = pr_netaddr_use_ipv6(); pr_netaddr_enable_ipv6(); pr_inet_set_default_family(p, AF_INET6); conn = pr_inet_create_conn(p, sockfd, NULL, port, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); mark_point(); res = pr_inet_set_proto_opts(p, conn, 1, 1, 1, 1); fail_unless(res == 0, "Failed to set proto opts: %s", strerror(errno)); mark_point(); fd = conn->rfd; conn->rfd = 8; res = pr_inet_set_proto_opts(p, conn, 1, 1, 1, 1); fail_unless(res == 0, "Failed to set proto opts: %s", strerror(errno)); conn->rfd = fd; mark_point(); fd = conn->wfd; conn->wfd = 9; res = pr_inet_set_proto_opts(p, conn, 1, 1, 1, 1); fail_unless(res == 0, "Failed to set proto opts: %s", strerror(errno)); conn->wfd = fd; mark_point(); fd = conn->listen_fd; conn->listen_fd = 10; res = pr_inet_set_proto_opts(p, conn, 1, 1, 1, 1); fail_unless(res == 0, "Failed to set proto opts: %s", strerror(errno)); conn->listen_fd = fd; pr_inet_close(p, conn); pr_inet_set_default_family(p, AF_INET); if (use_ipv6 == FALSE) { pr_netaddr_disable_ipv6(); } #endif /* PR_USE_IPV6 */ }
END_TEST START_TEST (inet_listen_test) { int fd, mode, sockfd = -1, port = INPORT_ANY, res; conn_t *conn; res = pr_inet_listen(NULL, NULL, 5, 0); fail_unless(res < 0, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); res = pr_inet_resetlisten(NULL, NULL); fail_unless(res < 0, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); conn = pr_inet_create_conn(p, sockfd, NULL, port, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); fd = conn->listen_fd; conn->listen_fd = 777; res = pr_inet_listen(p, conn, 5, 0); fail_unless(res < 0, "Succeeded in listening on conn unexpectedly"); fail_unless(errno == EBADF, "Expected EBADF (%d), got %s (%d)", EBADF, strerror(errno), errno); mode = conn->mode; res = pr_inet_resetlisten(p, conn); fail_unless(res < 0, "Succeeded in resetting listening on conn unexpectedly"); fail_unless(errno == EBADF, "Expected EBADF (%d), got %s (%d)", EBADF, strerror(errno), errno); conn->listen_fd = fd; conn->mode = mode; res = pr_inet_listen(p, conn, 5, 0); fail_unless(res == 0, "Failed to listen on conn: %s", strerror(errno)); res = pr_inet_resetlisten(p, conn); fail_unless(res == 0, "Failed to reset listen mode: %s", strerror(errno)); res = pr_inet_listen(p, conn, 5, 0); fail_unless(res < 0, "Failed to handle already-listening socket"); fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM, strerror(errno), errno); pr_inet_close(p, conn); }
END_TEST START_TEST (trace_msg_test) { int res; char *channel, msg[16384]; res = pr_trace_msg(NULL, -1, NULL); fail_unless(res < 0, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); channel = "testsuite"; res = pr_trace_msg(channel, -1, NULL); fail_unless(res < 0, "Failed to handle bad level"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); res = pr_trace_msg(channel, 1, NULL); fail_unless(res < 0, "Failed to handle null message"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); pr_trace_set_levels(channel, 1, 10); memset(msg, 'A', sizeof(msg)-1); msg[sizeof(msg)-1] = '\0'; pr_trace_msg(channel, 5, "%s", msg); session.c = pr_inet_create_conn(p, -1, NULL, INPORT_ANY, FALSE); fail_unless(session.c != NULL, "Failed to create conn: %s", strerror(errno)); session.c->local_addr = session.c->remote_addr = pr_netaddr_get_addr(p, "127.0.0.1", NULL); res = pr_trace_set_options(PR_TRACE_OPT_LOG_CONN_IPS|PR_TRACE_OPT_USE_TIMESTAMP_MILLIS); fail_unless(res == 0, "Failed to set options: %s", strerror(errno)); pr_trace_msg(channel, 5, "%s", "alef bet vet?"); res = pr_trace_set_options(0); fail_unless(res == 0, "Failed to set options: %s", strerror(errno)); pr_trace_msg(channel, 5, "%s", "alef bet vet?"); pr_inet_close(p, session.c); session.c = NULL; pr_trace_set_levels(channel, 0, 0); }
END_TEST START_TEST (inet_set_proto_nodelay_test) { int fd, sockfd = -1, port = INPORT_ANY, res; conn_t *conn; res = pr_inet_set_proto_nodelay(NULL, NULL, 1); fail_unless(res < 0, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); conn = pr_inet_create_conn(p, sockfd, NULL, port, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); res = pr_inet_set_proto_nodelay(p, conn, 1); fail_unless(res == 0, "Failed to enable nodelay: %s", strerror(errno)); res = pr_inet_set_proto_nodelay(p, conn, 0); fail_unless(res == 0, "Failed to disable nodelay: %s", strerror(errno)); fd = conn->rfd; conn->rfd = 8; res = pr_inet_set_proto_nodelay(p, conn, 0); fail_unless(res == 0, "Failed to disable nodelay: %s", strerror(errno)); conn->rfd = fd; fd = conn->rfd; conn->rfd = -2; res = pr_inet_set_proto_nodelay(p, conn, 0); fail_unless(res == 0, "Failed to disable nodelay: %s", strerror(errno)); conn->rfd = fd; fd = conn->wfd; conn->rfd = 9; res = pr_inet_set_proto_nodelay(p, conn, 0); fail_unless(res == 0, "Failed to disable nodelay: %s", strerror(errno)); conn->wfd = fd; fd = conn->wfd; conn->rfd = -3; res = pr_inet_set_proto_nodelay(p, conn, 0); fail_unless(res == 0, "Failed to disable nodelay: %s", strerror(errno)); conn->wfd = fd; pr_inet_close(p, conn); }
END_TEST START_TEST (inet_connect_nowait_test) { int sockfd = -1, port = INPORT_ANY, res; conn_t *conn; const pr_netaddr_t *addr; res = pr_inet_connect_nowait(NULL, NULL, NULL, port); fail_unless(res < 0, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); conn = pr_inet_create_conn(p, sockfd, NULL, port, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); res = pr_inet_connect_nowait(p, conn, NULL, 80); fail_unless(res < 0, "Failed to handle null address"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); addr = pr_netaddr_get_addr(p, "127.0.0.1", NULL); fail_unless(addr != NULL, "Failed to resolve '127.0.0.1': %s", strerror(errno)); res = pr_inet_connect_nowait(p, conn, addr, 80); fail_unless(res != -1, "Connected to 127.0.0.1#80 unexpectedly"); /* Try connecting to Google's DNS server. */ addr = pr_netaddr_get_addr(p, "8.8.8.8", NULL); fail_unless(addr != NULL, "Failed to resolve '8.8.8.8': %s", strerror(errno)); res = pr_inet_connect_nowait(p, conn, addr, 53); if (res < 0 && errno != ECONNREFUSED) { fail_unless(res != -1, "Failed to connect to 8.8.8.8#53: %s", strerror(errno)); } pr_inet_close(p, conn); /* Restore the default family to AF_INET, for other tests. */ pr_inet_set_default_family(p, AF_INET); }
END_TEST START_TEST (inet_set_socket_opts_test) { int sockfd = -1, port = INPORT_ANY, res; conn_t *conn; res = pr_inet_set_socket_opts(NULL, NULL, 1, 2, NULL); fail_unless(res < 0, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); conn = pr_inet_create_conn(p, sockfd, NULL, port, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); res = pr_inet_set_socket_opts(p, conn, 1, 2, NULL); fail_unless(res == 0, "Failed to set socket opts: %s", strerror(errno)); pr_inet_close(p, conn); }
END_TEST START_TEST (inet_set_proto_opts_test) { int fd, sockfd = -1, port = INPORT_ANY, res; conn_t *conn; mark_point(); res = pr_inet_set_proto_opts(NULL, NULL, 1, 1, 1, 1); fail_unless(res < 0, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); conn = pr_inet_create_conn(p, sockfd, NULL, port, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); mark_point(); res = pr_inet_set_proto_opts(p, conn, 1, 1, 1, 1); fail_unless(res == 0, "Failed to set proto opts: %s", strerror(errno)); mark_point(); fd = conn->rfd; conn->rfd = 8; res = pr_inet_set_proto_opts(p, conn, 1, 1, 1, 1); fail_unless(res == 0, "Failed to set proto opts: %s", strerror(errno)); conn->rfd = fd; mark_point(); fd = conn->wfd; conn->wfd = 9; res = pr_inet_set_proto_opts(p, conn, 1, 1, 1, 1); fail_unless(res == 0, "Failed to set proto opts: %s", strerror(errno)); conn->wfd = fd; mark_point(); fd = conn->listen_fd; conn->listen_fd = 10; res = pr_inet_set_proto_opts(p, conn, 1, 1, 1, 1); fail_unless(res == 0, "Failed to set proto opts: %s", strerror(errno)); conn->listen_fd = fd; pr_inet_close(p, conn); }
END_TEST START_TEST (inet_set_async_test) { int fd, sockfd = -1, port = INPORT_ANY, res; conn_t *conn; res = pr_inet_set_async(NULL, NULL); fail_unless(res < 0, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected errno EINVAL (%d), got '%s' (%d)", EINVAL, strerror(errno), errno); conn = pr_inet_create_conn(p, sockfd, NULL, port, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); res = pr_inet_set_async(p, conn); fail_unless(res == 0, "Failed to set conn %p async: %s", conn, strerror(errno)); fd = conn->rfd; conn->rfd = 77; res = pr_inet_set_async(p, conn); fail_unless(res == 0, "Failed to set conn %p async: %s", conn, strerror(errno)); conn->rfd = fd; fd = conn->wfd; conn->wfd = 78; res = pr_inet_set_async(p, conn); fail_unless(res == 0, "Failed to set conn %p async: %s", conn, strerror(errno)); conn->wfd = fd; fd = conn->listen_fd; conn->listen_fd = 79; res = pr_inet_set_async(p, conn); fail_unless(res == 0, "Failed to set conn %p async: %s", conn, strerror(errno)); conn->listen_fd = fd; pr_inet_close(p, conn); }
END_TEST START_TEST (inet_accept_nowait_test) { int sockfd = -1, port = INPORT_ANY, res; conn_t *conn; res = pr_inet_accept_nowait(NULL, NULL); fail_unless(res < 0, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); conn = pr_inet_create_conn(p, sockfd, NULL, port, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); res = pr_inet_accept_nowait(p, conn); fail_unless(res < 0, "Accepted connection unexpectedly"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); pr_inet_close(p, conn); }
static void tear_down(void) { pr_response_register_handler(NULL); if (session.c != NULL) { pr_inet_close(p, session.c); session.c = NULL; } pr_unregister_netio(PR_NETIO_STRM_CTRL); if (getenv("TEST_VERBOSE") != NULL) { pr_trace_set_levels("netio", 0, 0); pr_trace_set_levels("response", 0, 0); } (void) unlink(display_test_file); if (p) { destroy_pool(p); p = session.pool = permanent_pool = NULL; } }
static int data_pasv_open(char *reason, off_t size) { conn_t *c; int rev; if (!reason && session.xfer.filename) reason = session.xfer.filename; /* Set the "stalled" timer, if any, to prevent the connection * open from taking too long */ if (timeout_stalled) { pr_timer_add(timeout_stalled, PR_TIMER_STALLED, NULL, stalled_timeout_cb, "TimeoutStalled"); } /* We save the state of our current disposition for doing reverse * lookups, and then set it to what the configuration wants it to * be. */ rev = pr_netaddr_set_reverse_dns(ServerUseReverseDNS); /* Protocol and socket options should be set before handshaking. */ if (session.xfer.direction == PR_NETIO_IO_RD) { pr_inet_set_socket_opts(session.d->pool, session.d, (main_server->tcp_rcvbuf_override ? main_server->tcp_rcvbuf_len : 0), 0); } else { pr_inet_set_socket_opts(session.d->pool, session.d, 0, (main_server->tcp_sndbuf_override ? main_server->tcp_sndbuf_len : 0)); } c = pr_inet_accept(session.pool, session.d, session.c, -1, -1, TRUE); pr_netaddr_set_reverse_dns(rev); if (c && c->mode != CM_ERROR) { pr_inet_close(session.pool, session.d); pr_inet_set_nonblock(session.pool, c); session.d = c; pr_log_debug(DEBUG4, "passive data connection opened - local : %s:%d", pr_netaddr_get_ipstr(session.d->local_addr), session.d->local_port); pr_log_debug(DEBUG4, "passive data connection opened - remote : %s:%d", pr_netaddr_get_ipstr(session.d->remote_addr), session.d->remote_port); if (session.xfer.xfer_type != STOR_UNIQUE) { if (size) { pr_response_send(R_150, _("Opening %s mode data connection for %s " "(%" PR_LU " bytes)"), MODE_STRING, reason, (pr_off_t) size); } else { pr_response_send(R_150, _("Opening %s mode data connection for %s"), MODE_STRING, reason); } } else { /* Format of 150 responses for STOU is explicitly dictated by * RFC 1123: * * 4.1.2.9 STOU Command: RFC-959 Section 4.1.3 * * The STOU command stores into a uniquely named file. When it * receives an STOU command, a Server-FTP MUST return the * actual file name in the "125 Transfer Starting" or the "150 * Opening Data Connection" message that precedes the transfer * (the 250 reply code mentioned in RFC-959 is incorrect). The * exact format of these messages is hereby defined to be as * follows: * * 125 FILE: pppp * 150 FILE: pppp * * where pppp represents the unique pathname of the file that * will be written. */ pr_response_send(R_150, "FILE: %s", reason); } return 0; } /* Check for error conditions. */ if (c && c->mode == CM_ERROR) pr_log_pri(PR_LOG_ERR, "Error: unable to accept an incoming data " "connection (%s)", strerror(c->xerrno)); pr_response_add_err(R_425, _("Unable to build data connection: %s"), strerror(session.d->xerrno)); destroy_pool(session.d->pool); session.d = NULL; return -1; }
static int forward_connect(pool *p, struct proxy_session *proxy_sess, pr_response_t **resp, unsigned int *resp_nlines) { conn_t *server_conn = NULL; int banner_ok = TRUE, use_tls, xerrno = 0; pr_netaddr_t *dst_addr; array_header *other_addrs = NULL; dst_addr = proxy_sess->dst_addr; other_addrs = proxy_sess->other_addrs; server_conn = proxy_conn_get_server_conn(p, proxy_sess, dst_addr); if (server_conn == NULL) { xerrno = errno; if (other_addrs != NULL) { register unsigned int i; /* Try the other IP addresses for the requested name (if any) as well. */ for (i = 0; i < other_addrs->nelts; i++) { dst_addr = ((pr_netaddr_t **) other_addrs->elts)[i]; pr_trace_msg(trace_channel, 8, "attempting to connect to other address #%u (%s) for requested " "URI '%.100s'", i+1, pr_netaddr_get_ipstr(dst_addr), proxy_conn_get_uri(proxy_sess->dst_pconn)); server_conn = proxy_conn_get_server_conn(p, proxy_sess, dst_addr); if (server_conn != NULL) { proxy_sess->dst_addr = dst_addr; break; } } } if (server_conn == NULL) { xerrno = errno; /* EINVALs lead to strange-looking error responses; change them to * EPERM. */ if (xerrno == EINVAL) { xerrno = EPERM; } } errno = xerrno; return -1; } /* XXX Support/send a CLNT command of our own? Configurable via e.g. * "UserAgent" string? */ proxy_sess->frontend_ctrl_conn = session.c; proxy_sess->backend_ctrl_conn = server_conn; /* Read the response from the backend server. */ *resp = proxy_ftp_ctrl_recv_resp(p, proxy_sess->backend_ctrl_conn, resp_nlines); if (*resp == NULL) { xerrno = errno; pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, "unable to read banner from server %s:%u: %s", pr_netaddr_get_ipstr(proxy_sess->backend_ctrl_conn->remote_addr), ntohs(pr_netaddr_get_port(proxy_sess->backend_ctrl_conn->remote_addr)), strerror(xerrno)); errno = EPERM; return -1; } if ((*resp)->num[0] != '2') { banner_ok = FALSE; } (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, "received banner from backend %s:%u%s: %s %s", pr_netaddr_get_ipstr(proxy_sess->backend_ctrl_conn->remote_addr), ntohs(pr_netaddr_get_port(proxy_sess->backend_ctrl_conn->remote_addr)), banner_ok ? "" : ", DISCONNECTING", (*resp)->num, (*resp)->msg); if (banner_ok == FALSE) { pr_inet_close(p, proxy_sess->backend_ctrl_conn); proxy_sess->backend_ctrl_conn = NULL; errno = EPERM; return -1; } /* Get the features supported by the backend server */ if (proxy_ftp_sess_get_feat(p, proxy_sess) < 0) { if (errno != EPERM) { (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, "unable to determine features of backend server: %s", strerror(errno)); } } use_tls = proxy_tls_use_tls(); if (use_tls != PROXY_TLS_ENGINE_OFF) { if (proxy_ftp_sess_send_auth_tls(p, proxy_sess) < 0) { xerrno = errno; (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, "error enabling TLS on control connection to backend server: %s", strerror(xerrno)); pr_inet_close(p, proxy_sess->backend_ctrl_conn); proxy_sess->backend_ctrl_conn = NULL; *resp = NULL; errno = xerrno; return -1; } } if (proxy_netio_postopen(server_conn->instrm) < 0) { xerrno = errno; (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, "postopen error for backend control connection input stream: %s", strerror(xerrno)); proxy_inet_close(session.pool, server_conn); proxy_sess->backend_ctrl_conn = NULL; *resp = NULL; errno = xerrno; return -1; } if (proxy_netio_postopen(server_conn->outstrm) < 0) { xerrno = errno; (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, "postopen error for backend control connection output stream: %s", strerror(xerrno)); proxy_inet_close(session.pool, server_conn); proxy_sess->backend_ctrl_conn = NULL; *resp = NULL; errno = xerrno; return -1; } if (use_tls != PROXY_TLS_ENGINE_OFF) { if (proxy_sess_state & PROXY_SESS_STATE_BACKEND_HAS_CTRL_TLS) { /* NOTE: should this be a fatal error? */ (void) proxy_ftp_sess_send_pbsz_prot(p, proxy_sess); } } (void) proxy_ftp_sess_send_host(p, proxy_sess); proxy_sess_state |= PROXY_SESS_STATE_CONNECTED; return 0; }
char *pr_ident_lookup(pool *p, conn_t *c) { char *ret = "UNKNOWN"; pool *tmp_pool = NULL; conn_t *ident_conn = NULL, *ident_io = NULL; char buf[256] = {'\0'}, *tok = NULL, *tmp = NULL; int timerno, i = 0; int ident_port = pr_inet_getservport(p, "ident", "tcp"); tmp_pool = make_sub_pool(p); ident_timeout = 0; nstrm = NULL; if (ident_port == -1) { destroy_pool(tmp_pool); return pstrdup(p, ret); } /* Set up our timer before going any further. */ timerno = pr_timer_add(PR_TUNABLE_TIMEOUTIDENT, -1, NULL, (callback_t) ident_timeout_cb, "ident lookup"); if (timerno <= 0) { destroy_pool(tmp_pool); return pstrdup(p, ret); } ident_conn = pr_inet_create_connection(tmp_pool, NULL, -1, c->local_addr, INPORT_ANY, FALSE); pr_inet_set_nonblock(tmp_pool, ident_conn); i = pr_inet_connect_nowait(tmp_pool, ident_conn, c->remote_addr, ident_port); if (i < 0) { int xerrno = errno; pr_timer_remove(timerno, ANY_MODULE); pr_inet_close(tmp_pool, ident_conn); pr_trace_msg(trace_channel, 5, "connection to %s, port %d failed: %s", pr_netaddr_get_ipstr(c->remote_addr), ident_port, strerror(xerrno)); destroy_pool(tmp_pool); errno = xerrno; return pstrdup(p, ret); } if (!i) { /* Not yet connected. */ nstrm = pr_netio_open(p, PR_NETIO_STRM_OTHR, ident_conn->listen_fd, PR_NETIO_IO_RD); pr_netio_set_poll_interval(nstrm, 1); switch (pr_netio_poll(nstrm)) { /* Aborted, timed out */ case 1: { if (ident_timeout) { pr_timer_remove(timerno, ANY_MODULE); pr_netio_close(nstrm); pr_inet_close(tmp_pool, ident_conn); pr_trace_msg(trace_channel, 5, "lookup timed out, returning '%s'", ret); destroy_pool(tmp_pool); return pstrdup(p, ret); } break; } /* Error. */ case -1: { int xerrno = errno; pr_timer_remove(timerno, ANY_MODULE); pr_netio_close(nstrm); pr_inet_close(tmp_pool, ident_conn); pr_trace_msg(trace_channel, 6, "lookup failed (%s), returning '%s'", strerror(xerrno), ret); destroy_pool(tmp_pool); errno = xerrno; return pstrdup(p, ret); } /* Connected. */ default: { ident_conn->mode = CM_OPEN; if (pr_inet_get_conn_info(ident_conn, ident_conn->listen_fd) < 0) { int xerrno = errno; pr_timer_remove(timerno, ANY_MODULE); pr_netio_close(nstrm); pr_inet_close(tmp_pool, ident_conn); pr_trace_msg(trace_channel, 2, "lookup timed out (%s), returning '%s'", strerror(xerrno), ret); destroy_pool(tmp_pool); errno = xerrno; return pstrdup(p, ret); } break; } } } ident_io = pr_inet_openrw(tmp_pool, ident_conn, NULL, PR_NETIO_STRM_OTHR, -1, -1, -1, FALSE); if (ident_io == NULL) { int xerrno = errno; pr_timer_remove(timerno, ANY_MODULE); pr_inet_close(tmp_pool, ident_conn); pr_trace_msg(trace_channel, 3, "failed opening read/write connection: %s", strerror(xerrno)); destroy_pool(tmp_pool); errno = xerrno; return pstrdup(p, ret); } nstrm = ident_io->instrm; pr_inet_set_nonblock(tmp_pool, ident_io); pr_netio_set_poll_interval(ident_io->instrm, 1); pr_netio_set_poll_interval(ident_io->outstrm, 1); pr_netio_printf(ident_io->outstrm, "%d, %d\r\n", c->remote_port, c->local_port); /* If the timer fires while in netio_gets(), netio_gets() will simply return * either a partial string, or NULL. This works because ident_timeout_cb * aborts the stream from which we are reading. netio_set_poll_interval() is * used to make sure significant delays don't occur on systems that * automatically restart syscalls after the SIGALRM signal. */ pr_trace_msg(trace_channel, 4, "reading response from remote ident server"); if (pr_netio_gets(buf, sizeof(buf), ident_io->instrm)) { strip_end(buf, "\r\n"); pr_trace_msg(trace_channel, 6, "received '%s' from remote ident server", buf); tmp = buf; tok = get_token(&tmp, ":"); if (tok && (tok = get_token(&tmp, ":"))) { while (*tok && isspace((int) *tok)) { pr_signals_handle(); tok++; } strip_end(tok, " \t"); if (strcasecmp(tok, "ERROR") == 0) { if (tmp) { while (*tmp && isspace((int) *tmp)) { pr_signals_handle(); tmp++; } strip_end(tmp, " \t"); if (strcasecmp(tmp, "HIDDEN-USER") == 0) ret = "HIDDEN-USER"; } } else if (strcasecmp(tok, "USERID") == 0) { if (tmp && (tok = get_token(&tmp, ":"))) { if (tmp) { while (*tmp && isspace((int) *tmp)) { pr_signals_handle(); tmp++; } strip_end(tmp, " \t"); ret = tmp; } } } } } pr_timer_remove(timerno, ANY_MODULE); pr_inet_close(tmp_pool, ident_io); pr_inet_close(tmp_pool, ident_conn); destroy_pool(tmp_pool); return pstrdup(p, ret); }
END_TEST START_TEST (inet_connect_ipv6_test) { #ifdef PR_USE_IPV6 int sockfd = -1, port = INPORT_ANY, res; conn_t *conn; const pr_netaddr_t *addr; unsigned char use_ipv6; use_ipv6 = pr_netaddr_use_ipv6(); pr_netaddr_enable_ipv6(); pr_inet_set_default_family(p, AF_INET6); conn = pr_inet_create_conn(p, sockfd, NULL, port, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); addr = pr_netaddr_get_addr(p, "::1", NULL); fail_unless(addr != NULL, "Failed to resolve '::1': %s", strerror(errno)); res = pr_inet_connect(p, conn, addr, 80); fail_unless(res < 0, "Connected to ::1#80 unexpectedly"); fail_unless(errno == ECONNREFUSED || errno == ENETUNREACH, "Expected ECONNREFUSED (%d) or ENETUNREACH (%d), got %s (%d)", ECONNREFUSED, ENETUNREACH, strerror(errno), errno); /* Try connecting to Google's DNS server. */ addr = pr_netaddr_get_addr(p, "2001:4860:4860::8888", NULL); fail_unless(addr != NULL, "Failed to resolve '2001:4860:4860::8888': %s", strerror(errno)); res = pr_inet_connect(p, conn, addr, 53); if (res < 0) { /* Note: We get EINVAL here because the socket already tried (and failed) * to connect to a different address. Interestingly, trying to connect(2) * using that same fd to a different address yields EINVAL. */ fail_unless(errno == EINVAL || errno == ENETUNREACH, "Expected EINVAL (%d) or ENETUNREACH (%d), got %s (%d)", EINVAL, ENETUNREACH, strerror(errno), errno); } pr_inet_close(p, conn); conn = pr_inet_create_conn(p, sockfd, NULL, port, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); res = pr_inet_connect(p, conn, addr, 53); if (res < 0) { /* This could be expected, e.g. if there's no route. */ fail_unless(errno == EHOSTUNREACH || errno == ENETUNREACH, "Expected EHOSTUNREACH (%d) or ENETUNREACH (%d), got %s (%d)", EHOSTUNREACH, ENETUNREACH, strerror(errno), errno); } res = pr_inet_connect(p, conn, addr, 53); fail_unless(res < 0, "Failed to connect to 2001:4860:4860::8888#53: %s", strerror(errno)); fail_unless(errno == EISCONN || errno == EHOSTUNREACH || errno == ENETUNREACH, "Expected EISCONN (%d) or EHOSTUNREACH (%d) or ENETUNREACH (%d), " "got %s (%d)", EISCONN, EHOSTUNREACH, ENETUNREACH, strerror(errno), errno); pr_inet_close(p, conn); pr_inet_set_default_family(p, AF_INET); if (use_ipv6 == FALSE) { pr_netaddr_disable_ipv6(); } #endif /* PR_USE_IPV6 */ }
static void sess_cleanup(int flags) { /* Clear the scoreboard entry. */ if (ServerType == SERVER_STANDALONE) { /* For standalone daemons, we only clear the scoreboard slot if we are * an exiting child process. */ if (!is_master) { if (pr_scoreboard_entry_del(TRUE) < 0 && errno != EINVAL && errno != ENOENT) { pr_log_debug(DEBUG1, "error deleting scoreboard entry: %s", strerror(errno)); } } } else if (ServerType == SERVER_INETD) { /* For inetd-spawned daemons, we always clear the scoreboard slot. */ if (pr_scoreboard_entry_del(TRUE) < 0 && errno != EINVAL && errno != ENOENT) { pr_log_debug(DEBUG1, "error deleting scoreboard entry: %s", strerror(errno)); } } /* If session.user is set, we have a valid login. */ if (session.user && session.wtmp_log) { const char *sess_ttyname; sess_ttyname = pr_session_get_ttyname(session.pool); log_wtmp(sess_ttyname, "", pr_netaddr_get_sess_remote_name(), pr_netaddr_get_sess_remote_addr()); } /* These are necessary in order that cleanups associated with these pools * (and their subpools) are properly run. */ if (session.d) { pr_inet_close(session.pool, session.d); session.d = NULL; } if (session.c) { pr_inet_close(session.pool, session.c); session.c = NULL; } /* Run all the exit handlers */ pr_event_generate("core.exit", NULL); if (!is_master || (ServerType == SERVER_INETD && !(flags & PR_SESS_END_FL_SYNTAX_CHECK))) { pr_log_pri(PR_LOG_INFO, "%s session closed.", pr_session_get_protocol(PR_SESS_PROTO_FL_LOGOUT)); } log_closesyslog(); }
int pr_ipbind_close(pr_netaddr_t *addr, unsigned int port, unsigned char close_namebinds) { int res = 0; register unsigned int i = 0; if (addr) { pr_ipbind_t *ipbind = NULL; unsigned char have_ipbind = FALSE; i = ipbind_hash_addr(addr); if (ipbind_table[i] == NULL) { pr_log_pri(PR_LOG_NOTICE, "notice: no ipbind found for %s:%d", pr_netaddr_get_ipstr(addr), port); errno = ENOENT; return -1; } for (ipbind = ipbind_table[i]; ipbind; ipbind = ipbind->ib_next) { if (pr_netaddr_cmp(ipbind->ib_addr, addr) == 0 && (!ipbind->ib_port || ipbind->ib_port == port)) { have_ipbind = TRUE; break; } } if (!have_ipbind) { pr_log_pri(PR_LOG_NOTICE, "notice: no ipbind found for %s:%d", pr_netaddr_get_ipstr(addr), port); errno = ENOENT; return -1; } /* If already closed, exit now. */ if (!ipbind->ib_isactive) { errno = EPERM; return -1; } /* Close the ipbinding's listen connection, if present. The trick * here is determining whether this binding's listen member is * _the_ listening socket for the master daemon, or whether it's * been created for SocketBindTight, and can be closed. * * Actually, it's not that hard. It's only _the_ listening socket * for the master daemon in inetd mode, in which case virtual servers * can't be shutdown via ftpdctl, anyway. */ if (SocketBindTight && ipbind->ib_listener != NULL) { pr_inet_close(ipbind->ib_server->pool, ipbind->ib_listener); ipbind->ib_listener = ipbind->ib_server->listen = NULL; } /* Mark this ipbind as inactive. For SocketBindTight sockets, the * closing of the listening connection will suffice, from the clients' * point of view. However, this covers the non-SocketBindTight case, * and will prevent this binding from returning its server_rec pointer * on future lookup requests via pr_ipbind_get_server(). */ ipbind->ib_isactive = FALSE; if (close_namebinds && ipbind->ib_namebinds) { register unsigned int j = 0; pr_namebind_t **namebinds = NULL; namebinds = (pr_namebind_t **) ipbind->ib_namebinds->elts; for (j = 0; j < ipbind->ib_namebinds->nelts; j++) { pr_namebind_t *nb = namebinds[j]; PR_CLOSE_NAMEBIND(nb->nb_name, nb->nb_server->addr, nb->nb_server->ServerPort); } } } else { /* A NULL addr has a special meaning: close _all_ ipbinds in the * list. */ for (i = 0; i < PR_BINDINGS_TABLE_SIZE; i++) { pr_ipbind_t *ipbind = NULL; for (ipbind = ipbind_table[i]; ipbind; ipbind = ipbind->ib_next) { if (SocketBindTight && ipbind->ib_listener != NULL) { pr_inet_close(main_server->pool, ipbind->ib_listener); ipbind->ib_listener = ipbind->ib_server->listen = NULL; } /* Note: do not need to check if this ipbind was previously closed, * for the NULL addr is a request to shut down all ipbinds, * regardless of their current state. */ ipbind->ib_isactive = FALSE; if (close_namebinds && ipbind->ib_namebinds) { register unsigned int j = 0; pr_namebind_t **namebinds = NULL; namebinds = (pr_namebind_t **) ipbind->ib_namebinds->elts; for (j = 0; j < ipbind->ib_namebinds->nelts; j++) { pr_namebind_t *nb = namebinds[j]; PR_CLOSE_NAMEBIND(nb->nb_name, nb->nb_server->addr, nb->nb_server->ServerPort); } } } } } return 0; }
static int data_active_open(char *reason, off_t size) { conn_t *c; int rev; pr_netaddr_t *bind_addr; if (!reason && session.xfer.filename) reason = session.xfer.filename; if (pr_netaddr_get_family(session.c->local_addr) == pr_netaddr_get_family(session.c->remote_addr)) { bind_addr = session.c->local_addr; } else { /* In this scenario, the server has an IPv6 socket, but the remote client * is an IPv4 (or IPv4-mapped IPv6) peer. */ bind_addr = pr_netaddr_v6tov4(session.xfer.p, session.c->local_addr); } session.d = pr_inet_create_conn(session.pool, -1, bind_addr, session.c->local_port-1, TRUE); /* Set the "stalled" timer, if any, to prevent the connection * open from taking too long */ if (timeout_stalled) { pr_timer_add(timeout_stalled, PR_TIMER_STALLED, NULL, stalled_timeout_cb, "TimeoutStalled"); } rev = pr_netaddr_set_reverse_dns(ServerUseReverseDNS); /* Protocol and socket options should be set before handshaking. */ if (session.xfer.direction == PR_NETIO_IO_RD) { pr_inet_set_socket_opts(session.d->pool, session.d, (main_server->tcp_rcvbuf_override ? main_server->tcp_rcvbuf_len : 0), 0); } else { pr_inet_set_socket_opts(session.d->pool, session.d, 0, (main_server->tcp_sndbuf_override ? main_server->tcp_sndbuf_len : 0)); } /* Make sure that the necessary socket options are set on the socket prior * to the call to connect(2). */ pr_inet_set_proto_opts(session.pool, session.d, main_server->tcp_mss_len, 0, IPTOS_THROUGHPUT, 1); pr_inet_generate_socket_event("core.data-connect", main_server, session.d->local_addr, session.d->listen_fd); if (pr_inet_connect(session.d->pool, session.d, &session.data_addr, session.data_port) == -1) { pr_response_add_err(R_425, _("Unable to build data connection: %s"), strerror(session.d->xerrno)); destroy_pool(session.d->pool); session.d = NULL; return -1; } c = pr_inet_openrw(session.pool, session.d, NULL, PR_NETIO_STRM_DATA, session.d->listen_fd, -1, -1, TRUE); pr_netaddr_set_reverse_dns(rev); if (c) { pr_log_debug(DEBUG4, "active data connection opened - local : %s:%d", pr_netaddr_get_ipstr(session.d->local_addr), session.d->local_port); pr_log_debug(DEBUG4, "active data connection opened - remote : %s:%d", pr_netaddr_get_ipstr(session.d->remote_addr), session.d->remote_port); if (session.xfer.xfer_type != STOR_UNIQUE) { if (size) pr_response_send(R_150, _("Opening %s mode data connection for %s " "(%" PR_LU " bytes)"), MODE_STRING, reason, (pr_off_t) size); else pr_response_send(R_150, _("Opening %s mode data connection for %s"), MODE_STRING, reason); } else { /* Format of 150 responses for STOU is explicitly dictated by * RFC 1123: * * 4.1.2.9 STOU Command: RFC-959 Section 4.1.3 * * The STOU command stores into a uniquely named file. When it * receives an STOU command, a Server-FTP MUST return the * actual file name in the "125 Transfer Starting" or the "150 * Opening Data Connection" message that precedes the transfer * (the 250 reply code mentioned in RFC-959 is incorrect). The * exact format of these messages is hereby defined to be as * follows: * * 125 FILE: pppp * 150 FILE: pppp * * where pppp represents the unique pathname of the file that * will be written. */ pr_response_send(R_150, "FILE: %s", reason); } pr_inet_close(session.pool, session.d); pr_inet_set_nonblock(session.pool, session.d); session.d = c; return 0; } pr_response_add_err(R_425, _("Unable to build data connection: %s"), strerror(session.d->xerrno)); destroy_pool(session.d->pool); session.d = NULL; return -1; }
END_TEST START_TEST (inet_copy_conn_test) { int fd = -1, sockfd = -1, port = INPORT_ANY; conn_t *conn, *conn2; const char *name; conn = pr_inet_copy_conn(NULL, NULL); fail_unless(conn == NULL, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); conn = pr_inet_copy_conn(p, NULL); fail_unless(conn == NULL, "Failed to handle null conn argument"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); conn = pr_inet_create_conn(p, sockfd, NULL, port, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); conn2 = pr_inet_copy_conn(p, conn); fail_unless(conn2 != NULL, "Failed to copy conn: %s", strerror(errno)); pr_inet_close(p, conn); pr_inet_close(p, conn2); conn = pr_inet_create_conn(p, sockfd, NULL, port, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); name = "127.0.0.1"; conn->remote_addr = pr_netaddr_get_addr(p, name, NULL); fail_unless(conn->remote_addr != NULL, "Failed to resolve '%s': %s", name, strerror(errno)); conn->remote_name = pstrdup(p, name); conn->instrm = pr_netio_open(p, PR_NETIO_STRM_CTRL, fd, PR_NETIO_IO_RD); fail_unless(conn->instrm != NULL, "Failed to open ctrl reading stream: %s", strerror(errno)); conn->outstrm = pr_netio_open(p, PR_NETIO_STRM_CTRL, fd, PR_NETIO_IO_WR); fail_unless(conn->instrm != NULL, "Failed to open ctrl writing stream: %s", strerror(errno)); conn2 = pr_inet_copy_conn(p, conn); fail_unless(conn2 != NULL, "Failed to copy conn: %s", strerror(errno)); mark_point(); pr_inet_lingering_close(NULL, NULL, 0L); pr_inet_lingering_close(p, conn, 0L); pr_inet_close(p, conn2); conn = pr_inet_create_conn(p, sockfd, NULL, port, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); conn->instrm = pr_netio_open(p, PR_NETIO_STRM_CTRL, fd, PR_NETIO_IO_RD); fail_unless(conn->instrm != NULL, "Failed to open ctrl reading stream: %s", strerror(errno)); conn->outstrm = pr_netio_open(p, PR_NETIO_STRM_CTRL, fd, PR_NETIO_IO_WR); fail_unless(conn->instrm != NULL, "Failed to open ctrl writing stream: %s", strerror(errno)); mark_point(); pr_inet_lingering_abort(NULL, NULL, 0L); pr_inet_lingering_abort(p, conn, 0L); }
int main(int argc, char *argv[]) { pool *p; const char *remote_name; pr_netaddr_t *remote_addr; conn_t *client_conn, *ctrl_conn, *data_conn; unsigned int connect_timeout, remote_port; struct proxy_ftp_client *ftp; int res, timerno; char buf[1024]; /* Seed the random number generator. */ /* XXX Use random(3) in the future? */ srand((unsigned int) (time(NULL) * getpid())); init_pools(); init_privs(); init_log(); init_regexp(); init_inet(); init_netio(); init_netaddr(); init_fs(); init_class(); init_config(); init_stash(); pr_log_setdebuglevel(10); log_stderr(TRUE); pr_trace_use_stderr(TRUE); pr_trace_set_levels("DEFAULT", 1, 20); p = make_sub_pool(permanent_pool); pr_pool_tag(p, "FTP Client Pool"); remote_name = "ftp.proftpd.org"; remote_addr = pr_netaddr_get_addr(p, remote_name, NULL); if (remote_addr == NULL) { fprintf(stderr, "Failed to get addr for '%s': %s\n", remote_name, strerror(errno)); destroy_pool(p); return 1; } fprintf(stdout, "Resolved name '%s' to IP address '%s'\n", remote_name, pr_netaddr_get_ipstr(remote_addr)); remote_port = 21; connect_timeout = 5; ftp = proxy_ftp_connect(p, remote_addr, remote_port, connect_timeout, NULL); if (ftp == NULL) { fprintf(stderr, "Error connecting to FTP server: %s\n", strerror(errno)); destroy_pool(p); return 1; } fprintf(stdout, "Successfully connected to %s:%d from %s:%d\n", remote_name, remote_port, pr_netaddr_get_ipstr(client_conn->local_addr), ntohs(pr_netaddr_get_port(client_conn->local_addr))); res = proxy_ftp_disconnect(ftp); if (res < 0) { fprintf(stderr, "Error disconnecting from FTP server: %s\n", strerror(errno)); destroy_pool(p); return 1; } ctrl_conn = pr_inet_openrw(p, client_conn, NULL, PR_NETIO_STRM_OTHR, -1, -1, -1, FALSE); if (ctrl_conn == NULL) { fprintf(stderr, "Error opening control connection: %s\n", strerror(errno)); pr_inet_close(p, client_conn); destroy_pool(p); return 1; } fprintf(stdout, "Reading response from %s:%d\n", remote_name, remote_port); /* Read the response */ memset(buf, '\0', sizeof(buf)); /* XXX We need to write our own version of netio_telnet_gets(), with * the buffering to handle reassembly of a full FTP response out of * multiple TCP packets. Not sure why the existing netio_telnet_gets() * is not sufficient. But we don't need the handling of Telnet codes * in our reading. But DO generate the 'core.ctrl-read' event, so that * any event listeners get a chance to process the data we've received. * (Or maybe use 'mod_proxy.server-read', and differentiate between * client and server reads/writes?) */ if (pr_netio_read(ctrl_conn->instrm, buf, sizeof(buf)-1, 5) < 0) { fprintf(stderr, "Error reading response from server: %s\n", strerror(errno)); } else { fprintf(stdout, "Response: \"%s\"\n", buf); } /* Disconnect */ res = pr_netio_printf(ctrl_conn->outstrm, "%s\r\n", C_QUIT); if (res < 0) { fprintf(stderr, "Error writing command to server: %s", strerror(errno)); } pr_inet_close(p, ctrl_conn); pr_inet_close(p, client_conn); destroy_pool(p); return 0; }
END_TEST START_TEST (connect_test) { conn_t *res; const pr_netaddr_t *remote_addr = NULL; res = proxy_ftp_conn_connect(NULL, NULL, NULL, FALSE); fail_unless(res == NULL, "Failed to handle null pool"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL, strerror(errno), errno); res = proxy_ftp_conn_connect(p, NULL, NULL, FALSE); fail_unless(res == NULL, "Failed to handle null remote addr"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL, strerror(errno), errno); remote_addr = pr_netaddr_get_addr(p, "127.0.0.1", NULL); fail_unless(remote_addr != NULL, "Failed to address for 127.0.0.1: %s", strerror(errno)); pr_netaddr_set_port((pr_netaddr_t *) remote_addr, htons(6555)); session.xfer.direction = PR_NETIO_IO_RD; mark_point(); res = proxy_ftp_conn_connect(p, NULL, remote_addr, FALSE); fail_unless(res == NULL, "Failed to handle bad address family"); fail_unless(errno == ECONNREFUSED, "Expected ECONNREFUSED (%d), got %s (%d)", ECONNREFUSED, strerror(errno), errno); mark_point(); res = proxy_ftp_conn_connect(p, NULL, remote_addr, TRUE); fail_unless(res == NULL, "Failed to handle bad address family"); fail_unless(errno == ECONNREFUSED, "Expected ECONNREFUSED (%d), got %s (%d)", ECONNREFUSED, strerror(errno), errno); session.xfer.direction = PR_NETIO_IO_WR; mark_point(); res = proxy_ftp_conn_connect(p, NULL, remote_addr, FALSE); fail_unless(res == NULL, "Failed to handle bad address family"); fail_unless(errno == ECONNREFUSED, "Expected ECONNREFUSED (%d), got %s (%d)", ECONNREFUSED, strerror(errno), errno); mark_point(); res = proxy_ftp_conn_connect(p, NULL, remote_addr, TRUE); fail_unless(res == NULL, "Failed to handle bad address family"); fail_unless(errno == ECONNREFUSED, "Expected ECONNREFUSED (%d), got %s (%d)", ECONNREFUSED, strerror(errno), errno); /* Try connecting to Google's DNS server. */ remote_addr = pr_netaddr_get_addr(p, "8.8.8.8", NULL); fail_unless(remote_addr != NULL, "Failed to resolve '8.8.8.8': %s", strerror(errno)); pr_netaddr_set_port((pr_netaddr_t *) remote_addr, htons(53)); mark_point(); res = proxy_ftp_conn_connect(p, NULL, remote_addr, FALSE); fail_unless(res != NULL, "Failed to connect: %s", strerror(errno)); pr_inet_close(p, res); mark_point(); res = proxy_ftp_conn_connect(p, NULL, remote_addr, TRUE); fail_unless(res != NULL, "Failed to connect: %s", strerror(errno)); pr_inet_close(p, res); }