Skip to content

Commit 0270bfb

Browse files
committed
Issue #285: Make sure that the address family for the remote/backend data connection address matches that of the control address.
Mismatches in address families will cause `connect(2)`, for backend passive data transfers, to yield `EINVAL` due to the socket fd using one address family, and the socket _address_ using a different address family. Subtle.
1 parent ff2ae9c commit 0270bfb

File tree

3 files changed

+31
-20
lines changed

3 files changed

+31
-20
lines changed

lib/proxy/conn.c

+15-15
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* ProFTPD - mod_proxy conn implementation
3-
* Copyright (c) 2012-2024 TJ Saunders
3+
* Copyright (c) 2012-2025 TJ Saunders
44
*
55
* This program is free software; you can redistribute it and/or modify
66
* it under the terms of the GNU General Public License as published by
@@ -677,7 +677,7 @@ conn_t *proxy_conn_get_server_conn(pool *p, struct proxy_session *proxy_sess,
677677
const char *remote_ipstr = NULL;
678678
unsigned int remote_port;
679679
conn_t *server_conn, *ctrl_conn;
680-
int res, default_inet_family = 0;
680+
int res, default_inet_family = 0, xerrno;
681681

682682
if (proxy_sess->connect_timeout > 0) {
683683
const char *notes_key = "mod_proxy.proxy-connect-address";
@@ -816,9 +816,14 @@ conn_t *proxy_conn_get_server_conn(pool *p, struct proxy_session *proxy_sess,
816816
}
817817

818818
server_conn = pr_inet_create_conn(p, -1, bind_addr, INPORT_ANY, FALSE);
819-
if (server_conn == NULL) {
820-
int xerrno = errno;
819+
xerrno = errno;
820+
821+
/* Restore the previous default inet family if necessary. */
822+
if (bind_addr == NULL) {
823+
(void) pr_inet_set_default_family(p, default_inet_family);
824+
}
821825

826+
if (server_conn == NULL) {
822827
(void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
823828
"error creating connection to %s: %s", pr_netaddr_get_ipstr(bind_addr),
824829
strerror(xerrno));
@@ -828,19 +833,14 @@ conn_t *proxy_conn_get_server_conn(pool *p, struct proxy_session *proxy_sess,
828833
return NULL;
829834
}
830835

831-
/* Restore the previous default inet family if necessary. */
832-
if (bind_addr == NULL) {
833-
(void) pr_inet_set_default_family(p, default_inet_family);
834-
}
835-
836836
pr_trace_msg(trace_channel, 12,
837837
"connecting to backend address %s#%u from %s#%u", remote_ipstr, remote_port,
838838
pr_netaddr_get_ipstr(server_conn->local_addr), server_conn->local_port);
839839

840840
res = pr_inet_connect_nowait(p, server_conn, remote_addr,
841841
ntohs(pr_netaddr_get_port(remote_addr)));
842842
if (res < 0) {
843-
int xerrno = errno;
843+
xerrno = errno;
844844

845845
(void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
846846
"error starting connect to %s#%u: %s", remote_ipstr, remote_port,
@@ -903,7 +903,7 @@ conn_t *proxy_conn_get_server_conn(pool *p, struct proxy_session *proxy_sess,
903903
nstrm = proxy_netio_open(p, PR_NETIO_STRM_OTHR, server_conn->listen_fd,
904904
nstrm_mode);
905905
if (nstrm == NULL) {
906-
int xerrno = errno;
906+
xerrno = errno;
907907

908908
(void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
909909
"error opening stream to %s#%u: %s", remote_ipstr, remote_port,
@@ -927,7 +927,7 @@ conn_t *proxy_conn_get_server_conn(pool *p, struct proxy_session *proxy_sess,
927927
switch (polled) {
928928
case 1: {
929929
/* Aborted, timed out. Note that we shouldn't reach here. */
930-
int xerrno = ETIMEDOUT;
930+
xerrno = ETIMEDOUT;
931931

932932
(void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
933933
"error connecting to %s#%u: %s", remote_ipstr, remote_port,
@@ -942,7 +942,7 @@ conn_t *proxy_conn_get_server_conn(pool *p, struct proxy_session *proxy_sess,
942942

943943
case -1: {
944944
/* Error */
945-
int xerrno = nstrm->strm_errno;
945+
xerrno = nstrm->strm_errno;
946946

947947
if (xerrno == 0) {
948948
xerrno = errno;
@@ -976,7 +976,7 @@ conn_t *proxy_conn_get_server_conn(pool *p, struct proxy_session *proxy_sess,
976976

977977
res = pr_inet_get_conn_info(server_conn, server_conn->listen_fd);
978978
if (res < 0) {
979-
int xerrno = errno;
979+
xerrno = errno;
980980

981981
(void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
982982
"error obtaining local socket info on fd %d: %s",
@@ -1005,7 +1005,7 @@ conn_t *proxy_conn_get_server_conn(pool *p, struct proxy_session *proxy_sess,
10051005
ctrl_conn = proxy_inet_openrw(p, server_conn, NULL, PR_NETIO_STRM_CTRL, -1,
10061006
-1, -1, FALSE);
10071007
if (ctrl_conn == NULL) {
1008-
int xerrno = errno;
1008+
xerrno = errno;
10091009

10101010
(void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
10111011
"unable to open control connection to %s#%u: %s", remote_ipstr,

lib/proxy/ftp/conn.c

+15-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* ProFTPD - mod_proxy FTP connection routines
3-
* Copyright (c) 2013-2022 TJ Saunders
3+
* Copyright (c) 2013-2025 TJ Saunders
44
*
55
* This program is free software; you can redistribute it and/or modify
66
* it under the terms of the GNU General Public License as published by
@@ -134,16 +134,27 @@ conn_t *proxy_ftp_conn_accept(pool *p, conn_t *data_conn, conn_t *ctrl_conn,
134134
conn_t *proxy_ftp_conn_connect(pool *p, const pr_netaddr_t *bind_addr,
135135
const pr_netaddr_t *remote_addr, int frontend_data) {
136136
conn_t *conn, *opened = NULL;
137-
int res, reverse_dns;
137+
int default_inet_family = 0, remote_family, res, reverse_dns, xerrno;
138138

139139
if (p == NULL ||
140140
remote_addr == NULL) {
141141
errno = EINVAL;
142142
return NULL;
143143
}
144144

145+
remote_family = pr_netaddr_get_family(remote_addr);
146+
pr_trace_msg(trace_channel, 9,
147+
"using %s family for backend socket address %s",
148+
remote_family == AF_INET ? "IPv4" : "IPv6",
149+
pr_netaddr_get_ipstr(remote_addr));
150+
default_inet_family = pr_inet_set_default_family(p, remote_family);
151+
145152
conn = pr_inet_create_conn(session.pool, -1, bind_addr, INPORT_ANY, TRUE);
153+
xerrno = errno;
154+
146155
if (conn == NULL) {
156+
pr_inet_set_default_family(p, default_inet_family);
157+
errno = xerrno;
147158
return NULL;
148159
}
149160

@@ -179,7 +190,7 @@ conn_t *proxy_ftp_conn_connect(pool *p, const pr_netaddr_t *bind_addr,
179190
}
180191

181192
if (res < 0) {
182-
int xerrno = errno;
193+
xerrno = errno;
183194

184195
(void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
185196
"unable to connect to %s#%u: %s\n", pr_netaddr_get_ipstr(remote_addr),
@@ -208,7 +219,7 @@ conn_t *proxy_ftp_conn_connect(pool *p, const pr_netaddr_t *bind_addr,
208219
pr_netaddr_set_reverse_dns(reverse_dns);
209220

210221
if (opened == NULL) {
211-
int xerrno = errno;
222+
xerrno = errno;
212223

213224
if (frontend_data == FALSE) {
214225
proxy_inet_close(session.pool, conn);

lib/proxy/ftp/xfer.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -570,7 +570,7 @@ const pr_netaddr_t *proxy_ftp_xfer_prepare_passive(int policy_id, cmd_rec *cmd,
570570

571571
remote_addr = pr_netaddr_dup(proxy_sess->dataxfer_pool,
572572
proxy_sess->backend_ctrl_conn->remote_addr);
573-
pr_netaddr_set_port2(remote_addr, remote_port);
573+
pr_netaddr_set_port2((pr_netaddr_t *) remote_addr, remote_port);
574574

575575
} else {
576576
if (!(proxy_opts & PROXY_OPT_ALLOW_FOREIGN_ADDRESS)) {

0 commit comments

Comments
 (0)