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); }
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_connect_ipv6_test) { #ifdef PR_USE_IPV6 int 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, -1, NULL, INPORT_ANY, 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)); mark_point(); res = proxy_inet_connect(p, conn, addr, 80); fail_unless(res < 0, "Connected to 127.0.0.1#80 unexpectedly"); fail_unless(errno == ECONNREFUSED || errno == ENETUNREACH, "Expected ECONNREFUSED (%d) or ENETUNREACH (%d), got %s (%d)", ECONNREFUSED, ENETUNREACH, strerror(errno), errno); proxy_inet_close(p, conn); /* Try connecting to Google's DNS server. */ conn = pr_inet_create_conn(p, -1, NULL, INPORT_ANY, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); 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)); mark_point(); res = proxy_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); } mark_point(); proxy_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_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_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_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_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_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_close_test) { conn_t *conn; mark_point(); proxy_inet_close(NULL, NULL); conn = pr_inet_create_conn(p, -1, NULL, INPORT_ANY, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); mark_point(); conn->rfd = conn->wfd = 999; proxy_inet_close(NULL, conn); }
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); }
END_TEST START_TEST (inet_openrw_test) { conn_t *res, *conn; const pr_netaddr_t *addr; res = proxy_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); res = proxy_inet_openrw(p, NULL, NULL, PR_NETIO_STRM_CTRL, -1, -1, -1, FALSE); fail_unless(res == NULL, "Failed to handle null conn"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL, strerror(errno), errno); conn = pr_inet_create_conn(p, -2, NULL, INPORT_ANY, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); res = proxy_inet_openrw(p, conn, NULL, PR_NETIO_STRM_OTHR, -1, -1, -1, FALSE); fail_unless(res == NULL, "Failed to handle null addr"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL, strerror(errno), errno); proxy_inet_close(p, conn); 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 = proxy_inet_openrw(p, conn, addr, PR_NETIO_STRM_OTHR, -1, -1, -1, FALSE); fail_unless(res != NULL, "Failed to open rw conn: %s", strerror(errno)); proxy_inet_close(p, conn); }
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 */ }
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); }
END_TEST START_TEST (inet_connect_ipv4_test) { int res; conn_t *conn; const pr_netaddr_t *addr; mark_point(); res = proxy_inet_connect(NULL, NULL, NULL, 0); fail_unless(res < 0, "Failed to handle null pool"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL, strerror(errno), errno); mark_point(); res = proxy_inet_connect(p, NULL, NULL, 0); fail_unless(res < 0, "Failed to handle null conn"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL, strerror(errno), errno); conn = pr_inet_create_conn(p, -1, NULL, INPORT_ANY, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); mark_point(); res = proxy_inet_connect(p, conn, NULL, 0); fail_unless(res < 0, "Failed to handle null addr"); 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)); mark_point(); res = proxy_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); proxy_inet_close(p, conn); /* 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)); conn = pr_inet_create_conn(p, -1, NULL, INPORT_ANY, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); mark_point(); res = proxy_inet_connect(p, conn, addr, 53); fail_if(res < 0, "Failed to connect to 8.8.8.8#53: %s", strerror(errno)); mark_point(); proxy_inet_close(p, conn); /* Now start supplying in/out streams. */ conn = pr_inet_create_conn(p, -1, NULL, INPORT_ANY, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); conn->instrm = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_RD); fail_unless(conn->instrm != NULL, "Failed to open ctrl reading stream: %s", strerror(errno)); mark_point(); res = proxy_inet_connect(p, conn, addr, 53); fail_if(res < 0, "Failed to connect to 8.8.8.8#53: %s", strerror(errno)); mark_point(); proxy_inet_close(p, conn); conn = pr_inet_create_conn(p, -1, NULL, INPORT_ANY, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); conn->instrm = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, 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_OTHR, -1, PR_NETIO_IO_WR); fail_unless(conn->outstrm != NULL, "Failed to open othr writing stream: %s", strerror(errno)); mark_point(); res = proxy_inet_connect(p, conn, addr, 53); fail_if(res < 0, "Failed to connect to 8.8.8.8#53: %s", strerror(errno)); mark_point(); proxy_inet_close(p, conn); }
conn_t *proxy_conn_get_server_conn(pool *p, struct proxy_session *proxy_sess, pr_netaddr_t *remote_addr) { pr_netaddr_t *bind_addr = NULL, *local_addr = NULL; const char *remote_ipstr = NULL; unsigned int remote_port; conn_t *server_conn, *ctrl_conn; int res; if (proxy_sess->connect_timeout > 0) { const char *notes_key = "mod_proxy.proxy-connect-address"; proxy_sess->connect_timerno = pr_timer_add(proxy_sess->connect_timeout, -1, &proxy_module, proxy_conn_connect_timeout_cb, "ProxyTimeoutConnect"); (void) pr_table_remove(session.notes, notes_key, NULL); if (pr_table_add(session.notes, notes_key, remote_addr, sizeof(pr_netaddr_t)) < 0) { (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, "error stashing proxy connect address note: %s", strerror(errno)); } } remote_ipstr = pr_netaddr_get_ipstr(remote_addr); remote_port = ntohs(pr_netaddr_get_port(remote_addr)); /* Check the family of the retrieved address vs what we'll be using * to connect. If there's a mismatch, we need to get an addr with the * matching family. */ if (pr_netaddr_get_family(session.c->local_addr) == pr_netaddr_get_family(remote_addr)) { local_addr = session.c->local_addr; } else { /* In this scenario, the proxy has an IPv6 socket, but the remote/backend * server has an IPv4 (or IPv4-mapped IPv6) address. OR it's the proxy * which has an IPv4 socket, and the remote/backend server has an IPv6 * address. */ if (pr_netaddr_get_family(session.c->local_addr) == AF_INET) { char *ip_str; /* Convert the local address from an IPv4 to an IPv6 addr. */ ip_str = pcalloc(p, INET6_ADDRSTRLEN + 1); snprintf(ip_str, INET6_ADDRSTRLEN, "::ffff:%s", pr_netaddr_get_ipstr(session.c->local_addr)); local_addr = pr_netaddr_get_addr(p, ip_str, NULL); } else { local_addr = pr_netaddr_v6tov4(p, session.c->local_addr); if (local_addr == NULL) { pr_trace_msg(trace_channel, 4, "error converting IPv6 local address %s to IPv4 address: %s", pr_netaddr_get_ipstr(session.c->local_addr), strerror(errno)); } } if (local_addr == NULL) { local_addr = session.c->local_addr; } } bind_addr = proxy_sess->src_addr; if (bind_addr == NULL) { bind_addr = local_addr; } /* Note: IF mod_proxy is running on localhost, and the connection to be * made is to a public IP address, then this connect(2) attempt would most * likely fail with ENETUNREACH, since localhost is a loopback network, * and of course not reachable from a public IP. Thus we check for this * edge case (which happens often for development). */ if (pr_netaddr_is_loopback(bind_addr) == TRUE) { const char *local_name; pr_netaddr_t *local_addr; local_name = pr_netaddr_get_localaddr_str(p); local_addr = pr_netaddr_get_addr(p, local_name, NULL); if (local_addr != NULL) { pr_trace_msg(trace_channel, 14, "%s is a loopback address, and unable to reach %s; using %s instead", pr_netaddr_get_ipstr(bind_addr), remote_ipstr, pr_netaddr_get_ipstr(local_addr)); bind_addr = local_addr; } } server_conn = pr_inet_create_conn(p, -1, bind_addr, INPORT_ANY, FALSE); if (server_conn == NULL) { int xerrno = errno; (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, "error creating connection to %s: %s", pr_netaddr_get_ipstr(bind_addr), strerror(xerrno)); pr_timer_remove(proxy_sess->connect_timerno, &proxy_module); errno = xerrno; return NULL; } pr_trace_msg(trace_channel, 11, "connecting to backend address %s#%u from %s", remote_ipstr, remote_port, pr_netaddr_get_ipstr(bind_addr)); res = pr_inet_connect_nowait(p, server_conn, remote_addr, ntohs(pr_netaddr_get_port(remote_addr))); if (res < 0) { int xerrno = errno; (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, "error starting connect to %s#%u: %s", remote_ipstr, remote_port, strerror(xerrno)); pr_timer_remove(proxy_sess->connect_timerno, &proxy_module); errno = xerrno; return NULL; } if (res == 0) { pr_netio_stream_t *nstrm; int nstrm_mode = PR_NETIO_IO_RD; if (proxy_opts & PROXY_OPT_USE_PROXY_PROTOCOL) { /* Rather than waiting for the stream to be readable (because the * other end sent us something), wait for the stream to be writable * so that we can send something to the other end). */ nstrm_mode = PR_NETIO_IO_WR; } /* Not yet connected. */ nstrm = proxy_netio_open(p, PR_NETIO_STRM_OTHR, server_conn->listen_fd, nstrm_mode); if (nstrm == NULL) { int xerrno = errno; (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, "error opening stream to %s#%u: %s", remote_ipstr, remote_port, strerror(xerrno)); pr_timer_remove(proxy_sess->connect_timerno, &proxy_module); pr_inet_close(p, server_conn); errno = xerrno; return NULL; } proxy_netio_set_poll_interval(nstrm, 1); switch (proxy_netio_poll(nstrm)) { case 1: { /* Aborted, timed out. Note that we shouldn't reach here. */ pr_timer_remove(proxy_sess->connect_timerno, &proxy_module); proxy_netio_close(nstrm); pr_inet_close(p, server_conn); errno = ETIMEDOUT; return NULL; } case -1: { /* Error */ int xerrno = errno; (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, "error connecting to %s#%u: %s", remote_ipstr, remote_port, strerror(xerrno)); pr_timer_remove(proxy_sess->connect_timerno, &proxy_module); proxy_netio_close(nstrm); pr_inet_close(p, server_conn); errno = xerrno; return NULL; } default: { /* Connected */ server_conn->mode = CM_OPEN; pr_timer_remove(proxy_sess->connect_timerno, &proxy_module); pr_table_remove(session.notes, "mod_proxy.proxy-connect-addr", NULL); res = pr_inet_get_conn_info(server_conn, server_conn->listen_fd); if (res < 0) { int xerrno = errno; (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, "error obtaining local socket info on fd %d: %s", server_conn->listen_fd, strerror(xerrno)); proxy_netio_close(nstrm); pr_inet_close(p, server_conn); errno = xerrno; return NULL; } break; } } } pr_trace_msg(trace_channel, 5, "successfully connected to %s#%u from %s#%d", remote_ipstr, remote_port, pr_netaddr_get_ipstr(server_conn->local_addr), ntohs(pr_netaddr_get_port(server_conn->local_addr))); ctrl_conn = proxy_inet_openrw(p, server_conn, NULL, PR_NETIO_STRM_CTRL, -1, -1, -1, FALSE); if (ctrl_conn == NULL) { int xerrno = errno; (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, "unable to open control connection to %s#%u: %s", remote_ipstr, remote_port, strerror(xerrno)); pr_inet_close(p, server_conn); errno = xerrno; return NULL; } return ctrl_conn; }
static int init_inetd_bindings(void) { int res = 0; server_rec *serv = NULL; unsigned char *default_server = NULL, is_default = FALSE; /* We explicitly do NOT use the get_listening_conn() function here, since * inetd-run daemons will not a) handle restarts, and thus b) will not have * already-open connections to choose from. */ main_server->listen = pr_inet_create_conn(main_server->pool, STDIN_FILENO, NULL, INPORT_ANY, FALSE); if (main_server->listen == NULL) { return -1; } /* Note: Since we are being called via inetd/xinetd, any socket options * which may be attempted by listeners for this event may not work. */ pr_inet_generate_socket_event("core.ctrl-listen", main_server, main_server->addr, main_server->listen->listen_fd); /* Fill in all the important connection information. */ if (pr_inet_get_conn_info(main_server->listen, STDIN_FILENO) == -1) { int xerrno = errno; pr_log_pri(PR_LOG_WARNING, "fatal: unable to get connection info: %s", strerror(xerrno)); if (xerrno == ENOTSOCK) { pr_log_pri(PR_LOG_ERR, "(Running from command line? " "Use `ServerType standalone' in config file!)"); } exit(1); } default_server = get_param_ptr(main_server->conf, "DefaultServer", FALSE); if (default_server != NULL && *default_server == TRUE) { is_default = TRUE; } PR_CREATE_IPBIND(main_server, main_server->addr, main_server->ServerPort); PR_OPEN_IPBIND(main_server->addr, main_server->ServerPort, main_server->listen, is_default, TRUE, TRUE); PR_ADD_IPBINDS(main_server); /* Now attach the faked connection to all virtual servers. */ for (serv = main_server->next; serv; serv = serv->next) { /* Because this server is sharing the connection with the * main server, we need a cleanup handler to remove * the server's reference when the original connection's * pool is destroyed. */ serv->listen = main_server->listen; register_cleanup(serv->listen->pool, &serv->listen, server_cleanup_cb, server_cleanup_cb); is_default = FALSE; default_server = get_param_ptr(serv->conf, "DefaultServer", FALSE); if (default_server != NULL && *default_server == TRUE) { is_default = TRUE; } PR_CREATE_IPBIND(serv, serv->addr, serv->ServerPort); PR_OPEN_IPBIND(serv->addr, serv->ServerPort, serv->listen, is_default, FALSE, TRUE); PR_ADD_IPBINDS(serv); } return 0; }
END_TEST START_TEST (inet_listen_test) { int res; conn_t *conn; mark_point(); res = proxy_inet_listen(NULL, NULL, 0, 0); fail_unless(res < 0, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); mark_point(); res = proxy_inet_listen(p, NULL, 0, 0); fail_unless(res < 0, "Failed to handle null conn"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); conn = pr_inet_create_conn(p, -1, NULL, INPORT_ANY, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); mark_point(); res = proxy_inet_listen(p, conn, 5, 0); fail_unless(res == 0, "Failed to listen on conn: %s", strerror(errno)); mark_point(); proxy_inet_close(p, conn); /* Now start providing in/out streams. */ conn = pr_inet_create_conn(p, -1, NULL, INPORT_ANY, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); conn->instrm = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_RD); fail_unless(conn->instrm != NULL, "Failed to open ctrl reading stream: %s", strerror(errno)); mark_point(); res = proxy_inet_listen(p, conn, 5, 0); fail_unless(res == 0, "Failed to listen on conn: %s", strerror(errno)); mark_point(); proxy_inet_close(p, conn); conn = pr_inet_create_conn(p, -1, NULL, INPORT_ANY, FALSE); fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno)); conn->instrm = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, 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_OTHR, -1, PR_NETIO_IO_WR); fail_unless(conn->outstrm != NULL, "Failed to open othr writing stream: %s", strerror(errno)); mark_point(); res = proxy_inet_listen(p, conn, 5, 0); fail_unless(res == 0, "Failed to listen on conn: %s", strerror(errno)); mark_point(); proxy_inet_close(p, conn); }
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; }
conn_t *pr_ipbind_get_listening_conn(server_rec *server, pr_netaddr_t *addr, unsigned int port) { conn_t *l; pool *p; struct listener_rec *lr; if (listening_conn_list) { for (lr = (struct listener_rec *) listening_conn_list->xas_list; lr; lr = lr->next) { int use_elt = FALSE; pr_signals_handle(); if (addr != NULL && lr->addr != NULL) { const char *lr_ipstr = NULL; lr_ipstr = pr_netaddr_get_ipstr(lr->addr); /* Note: lr_ipstr should never be null. If it is, it means that * the lr->addr object never had its IP address resolved/stashed, * and in attempting to do, getnameinfo(3) failed for some reason. * * The IP address on which it's listening, if not available via * lr->addr, should thus be available via lr->conn->local_addr. */ if (lr_ipstr == NULL && lr->conn != NULL) { lr_ipstr = pr_netaddr_get_ipstr(lr->conn->local_addr); } if (lr_ipstr != NULL) { if (strcmp(pr_netaddr_get_ipstr(addr), lr_ipstr) == 0 && port == lr->port) { use_elt = TRUE; } } } else if (addr == NULL && port == lr->port) { use_elt = TRUE; } if (use_elt) { lr->claimed = TRUE; return lr->conn; } } } if (listening_conn_pool == NULL) { listening_conn_pool = make_sub_pool(permanent_pool); pr_pool_tag(listening_conn_pool, "Listening Connection Pool"); listening_conn_list = xaset_create(listening_conn_pool, NULL); } p = make_sub_pool(listening_conn_pool); pr_pool_tag(p, "Listening conn subpool"); l = pr_inet_create_conn(p, -1, addr, port, FALSE); if (l == NULL) { return NULL; } /* Inform any interested listeners that this socket was opened. */ pr_inet_generate_socket_event("core.ctrl-listen", server, l->local_addr, l->listen_fd); lr = pcalloc(p, sizeof(struct listener_rec)); lr->pool = p; lr->conn = l; lr->addr = pr_netaddr_dup(p, addr); if (lr->addr == NULL && errno != EINVAL) { return NULL; } lr->port = port; lr->claimed = TRUE; xaset_insert(listening_conn_list, (xasetmember_t *) lr); return l; }
static int data_active_open(char *reason, off_t size) { conn_t *c; int bind_port, rev; pr_netaddr_t *bind_addr; unsigned char *root_revoke = NULL; 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); } /* Default source port to which to bind for the active transfer, as * per RFC959. */ bind_port = session.c->local_port-1; /* A RootRevoke value of 0 indicates 'false', 1 indicates 'true', and * 2 indicates 'NonCompliantActiveTransfer'. We change the source port for * a RootRevoke value of 2. */ root_revoke = get_param_ptr(TOPLEVEL_CONF, "RootRevoke", FALSE); if (root_revoke != NULL && *root_revoke == 2) { bind_port = INPORT_ANY; } session.d = pr_inet_create_conn(session.pool, -1, bind_addr, bind_port, TRUE); /* Default remote address to which to connect for an active transfer, * if the client has not specified a different address via PORT/EPRT, * as per RFC 959. */ if (pr_netaddr_get_family(&session.data_addr) == AF_UNSPEC) { pr_log_debug(DEBUG6, "Client has not sent previous PORT/EPRT command, " "defaulting to %s#%u for active transfer", pr_netaddr_get_ipstr(session.c->remote_addr), session.c->remote_port); pr_netaddr_set_family(&session.data_addr, pr_netaddr_get_family(session.c->remote_addr)); pr_netaddr_set_sockaddr(&session.data_addr, pr_netaddr_get_sockaddr(session.c->remote_addr)); } /* 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, main_server->tcp_keepalive); } else { pr_inet_set_socket_opts(session.d->pool, session.d, 0, (main_server->tcp_sndbuf_override ? main_server->tcp_sndbuf_len : 0), main_server->tcp_keepalive); } /* 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_log_debug(DEBUG6, "Error connecting to %s#%u for active data transfer: %s", pr_netaddr_get_ipstr(&session.data_addr), session.data_port, strerror(session.d->xerrno)); pr_response_add_err(R_425, _("Unable to build data connection: %s"), strerror(session.d->xerrno)); errno = 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)); errno = session.d->xerrno; destroy_pool(session.d->pool); session.d = NULL; return -1; }