[Git][debian-proftpd-team/proftpd-mod-proxy][upstream] New upstream version 0.9.5
Hilmar Preuße (@hilmar)
gitlab at salsa.debian.org
Wed Feb 26 13:42:15 GMT 2025
Hilmar Preuße pushed to branch upstream at Debian ProFTPD Team / proftpd-mod-proxy
Commits:
1cdea7e4 by Hilmar Preuße at 2025-02-26T12:14:24+01:00
New upstream version 0.9.5
- - - - -
19 changed files:
- .github/workflows/ci.yml
- .github/workflows/codeql.yml
- .github/workflows/regressions.yml
- include/proxy/tls.h
- lib/proxy/conn.c
- lib/proxy/ftp/conn.c
- lib/proxy/ftp/dirlist.c
- lib/proxy/ftp/xfer.c
- lib/proxy/reverse/db.c
- lib/proxy/session.c
- lib/proxy/ssh.c
- lib/proxy/ssh/crypto.c
- lib/proxy/ssh/msg.c
- lib/proxy/tls.c
- mod_proxy.c
- mod_proxy.h.in
- mod_proxy.html
- t/lib/ProFTPD/Tests/Modules/mod_proxy.pm
- t/lib/ProFTPD/Tests/Modules/mod_proxy/ssh.pm
Changes:
=====================================
.github/workflows/ci.yml
=====================================
@@ -7,6 +7,9 @@ on:
paths-ignore:
- '*.html'
- '*.md'
+ - 't/etc/**'
+ - 't/lib/**'
+ - 't/modules/**'
pull_request:
branches:
- master
@@ -18,6 +21,11 @@ jobs:
runs-on: ubuntu-latest
env:
+ # We need to avoid using NodeJS v20, because it doesn't work with
+ # older glibc versions. See:
+ # https://github.com/actions/checkout/issues/1809.
+ ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
+
CI: true
strategy:
@@ -27,8 +35,8 @@ jobs:
- gcc
container:
- almalinux:8
- - alpine:3.15
- - ubuntu:18.04
+ - alpine:3.18
+ - ubuntu:22.04
container: ${{ matrix.container }}
@@ -45,7 +53,7 @@ jobs:
path: proftpd/contrib/mod_proxy
- name: Whitespace check
- if: ${{ matrix.container == 'ubuntu:18.04' }}
+ if: ${{ matrix.container == 'ubuntu:22.04' }}
run: |
apt-get update -qq
apt-get install -y git
@@ -58,11 +66,11 @@ jobs:
fi
- name: Install Alpine packages
- if: ${{ matrix.container == 'alpine:3.15' }}
+ if: ${{ matrix.container == 'alpine:3.18' }}
run: |
apk update
# for builds
- apk add bash build-base clang compiler-rt-static gcc make zlib-dev
+ apk add bash build-base clang compiler-rt gcc make zlib-dev
# for unit tests
apk add check check-dev subunit subunit-dev
# for Redis support
@@ -95,7 +103,7 @@ jobs:
openssl version -a
- name: Install Ubuntu packages
- if: ${{ matrix.container == 'ubuntu:18.04' }}
+ if: ${{ matrix.container == 'ubuntu:22.04' }}
run: |
apt-get update -qq
# for builds
@@ -121,7 +129,7 @@ jobs:
openssl version -a
- name: Prepare code coverage
- if: ${{ matrix.container == 'ubuntu:18.04' }}
+ if: ${{ matrix.container == 'ubuntu:22.04' }}
run: |
lcov --directory proftpd --zerocounters
@@ -164,7 +172,7 @@ jobs:
env:
CC: ${{ matrix.compiler }}
# Note: Skip the unit tests on Alpine
- if: ${{ matrix.container != 'alpine:3.15' }}
+ if: ${{ matrix.container != 'alpine:3.18' }}
run: |
cd proftpd/contrib/mod_proxy
make TEST_VERBOSE=1 check
@@ -201,7 +209,7 @@ jobs:
CC: ${{ matrix.compiler }}
CFLAGS: -fsanitize=address,undefined
LDFLAGS: -fsanitize=address,undefined
- if: ${{ matrix.compiler == 'clang' && matrix.container == 'ubuntu:18.04' }}
+ if: ${{ matrix.compiler == 'clang' && matrix.container == 'ubuntu:22.04' }}
run: |
cd proftpd
make clean
@@ -212,7 +220,7 @@ jobs:
make TEST_VERBOSE=1 check
- name: Check HTML docs
- if: ${{ matrix.container == 'ubuntu:18.04' }}
+ if: ${{ matrix.container == 'ubuntu:22.04' }}
run: |
cd proftpd/contrib/mod_proxy
for f in $(/bin/ls *.html); do echo "Processing $f"; tidy -errors -omit -q $f; done || exit 0
=====================================
.github/workflows/codeql.yml
=====================================
@@ -8,6 +8,9 @@ on:
- '*.html'
- '**/*.md'
- '**/doc/*'
+ - 't/etc/**'
+ - 't/lib/**'
+ - 't/modules/**'
pull_request:
branches:
- master
@@ -34,12 +37,12 @@ jobs:
steps:
- name: Checkout ProFTPD
- uses: actions/checkout at v3
+ uses: actions/checkout at v4
with:
repository: proftpd/proftpd
- name: Checkout mod_proxy
- uses: actions/checkout at v3
+ uses: actions/checkout at v4
with:
path: contrib/mod_proxy
=====================================
.github/workflows/regressions.yml
=====================================
@@ -16,6 +16,11 @@ jobs:
runs-on: ubuntu-latest
env:
+ # We need to avoid using NodeJS v20, because it doesn't work with
+ # older glibc versions. See:
+ # https://github.com/actions/checkout/issues/1809.
+ ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
+
DEBIAN_FRONTEND: noninteractive
REDIS_HOST: redis
TZ: America/Los_Angeles
@@ -36,7 +41,7 @@ jobs:
compiler:
- gcc
container:
- - ubuntu:18.04
+ - ubuntu:22.04
container: ${{ matrix.container }}
=====================================
include/proxy/tls.h
=====================================
@@ -1,6 +1,6 @@
/*
* ProFTPD - mod_proxy TLS API
- * Copyright (c) 2015-2021 TJ Saunders
+ * Copyright (c) 2015-2024 TJ Saunders
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -39,7 +39,9 @@
# include <openssl/x509v3.h>
# include <openssl/rand.h>
# if OPENSSL_VERSION_NUMBER > 0x000907000L
-# include <openssl/engine.h>
+# if defined(PR_USE_OPENSSL_ENGINE)
+# include <openssl/engine.h>
+# endif /* PR_USE_OPENSSL_ENGINE */
# include <openssl/ocsp.h>
# endif
# ifdef PR_USE_OPENSSL_ECC
=====================================
lib/proxy/conn.c
=====================================
@@ -1,6 +1,6 @@
/*
* ProFTPD - mod_proxy conn implementation
- * Copyright (c) 2012-2023 TJ Saunders
+ * Copyright (c) 2012-2025 TJ Saunders
*
* This program is free software; you can redistribute it and/or modify
* 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,
const char *remote_ipstr = NULL;
unsigned int remote_port;
conn_t *server_conn, *ctrl_conn;
- int res;
+ int res, default_inet_family = 0, xerrno;
if (proxy_sess->connect_timeout > 0) {
const char *notes_key = "mod_proxy.proxy-connect-address";
@@ -750,8 +750,21 @@ conn_t *proxy_conn_get_server_conn(pool *p, struct proxy_session *proxy_sess,
}
bind_addr = proxy_sess->src_addr;
+
+ /* We need to set the default inet family to use for the local address of
+ * our socket. We do NOT want to just use the family of the local address of
+ * our control connection, since we could be listening on an IPv6 address
+ * and want to connect to a backend IPv4 address, or vice versa; see
+ * Issue #272.
+ */
if (bind_addr == NULL) {
- bind_addr = local_addr;
+ int remote_family;
+
+ remote_family = pr_netaddr_get_family(remote_addr);
+
+ pr_trace_msg(trace_channel, 9, "using %s family for socket local address",
+ remote_family == AF_INET ? "IPv4" : "IPv6");
+ default_inet_family = pr_inet_set_default_family(p, remote_family);
}
/* Note: IF mod_proxy is running on localhost, and the connection to be
@@ -760,7 +773,8 @@ conn_t *proxy_conn_get_server_conn(pool *p, struct proxy_session *proxy_sess,
* 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 &&
+ if (bind_addr != NULL &&
+ pr_netaddr_is_loopback(bind_addr) == TRUE &&
pr_netaddr_is_loopback(remote_addr) != TRUE) {
const char *local_name;
const pr_netaddr_t *new_local_addr;
@@ -802,9 +816,14 @@ conn_t *proxy_conn_get_server_conn(pool *p, struct proxy_session *proxy_sess,
}
server_conn = pr_inet_create_conn(p, -1, bind_addr, INPORT_ANY, FALSE);
- if (server_conn == NULL) {
- int xerrno = errno;
+ xerrno = errno;
+ /* Restore the previous default inet family if necessary. */
+ if (bind_addr == NULL) {
+ (void) pr_inet_set_default_family(p, default_inet_family);
+ }
+
+ if (server_conn == NULL) {
(void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
"error creating connection to %s: %s", pr_netaddr_get_ipstr(bind_addr),
strerror(xerrno));
@@ -821,7 +840,7 @@ conn_t *proxy_conn_get_server_conn(pool *p, struct proxy_session *proxy_sess,
res = pr_inet_connect_nowait(p, server_conn, remote_addr,
ntohs(pr_netaddr_get_port(remote_addr)));
if (res < 0) {
- int xerrno = errno;
+ xerrno = errno;
(void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
"error starting connect to %s#%u: %s", remote_ipstr, remote_port,
@@ -884,7 +903,7 @@ conn_t *proxy_conn_get_server_conn(pool *p, struct proxy_session *proxy_sess,
nstrm = proxy_netio_open(p, PR_NETIO_STRM_OTHR, server_conn->listen_fd,
nstrm_mode);
if (nstrm == NULL) {
- int xerrno = errno;
+ xerrno = errno;
(void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
"error opening stream to %s#%u: %s", remote_ipstr, remote_port,
@@ -908,7 +927,7 @@ conn_t *proxy_conn_get_server_conn(pool *p, struct proxy_session *proxy_sess,
switch (polled) {
case 1: {
/* Aborted, timed out. Note that we shouldn't reach here. */
- int xerrno = ETIMEDOUT;
+ xerrno = ETIMEDOUT;
(void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
"error connecting to %s#%u: %s", remote_ipstr, remote_port,
@@ -923,7 +942,7 @@ conn_t *proxy_conn_get_server_conn(pool *p, struct proxy_session *proxy_sess,
case -1: {
/* Error */
- int xerrno = nstrm->strm_errno;
+ xerrno = nstrm->strm_errno;
if (xerrno == 0) {
xerrno = errno;
@@ -957,7 +976,7 @@ conn_t *proxy_conn_get_server_conn(pool *p, struct proxy_session *proxy_sess,
res = pr_inet_get_conn_info(server_conn, server_conn->listen_fd);
if (res < 0) {
- int xerrno = errno;
+ xerrno = errno;
(void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
"error obtaining local socket info on fd %d: %s",
@@ -986,7 +1005,7 @@ conn_t *proxy_conn_get_server_conn(pool *p, struct proxy_session *proxy_sess,
ctrl_conn = proxy_inet_openrw(p, server_conn, NULL, PR_NETIO_STRM_CTRL, -1,
-1, -1, FALSE);
if (ctrl_conn == NULL) {
- int xerrno = errno;
+ xerrno = errno;
(void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
"unable to open control connection to %s#%u: %s", remote_ipstr,
=====================================
lib/proxy/ftp/conn.c
=====================================
@@ -1,6 +1,6 @@
/*
* ProFTPD - mod_proxy FTP connection routines
- * Copyright (c) 2013-2022 TJ Saunders
+ * Copyright (c) 2013-2025 TJ Saunders
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -134,7 +134,7 @@ conn_t *proxy_ftp_conn_accept(pool *p, conn_t *data_conn, conn_t *ctrl_conn,
conn_t *proxy_ftp_conn_connect(pool *p, const pr_netaddr_t *bind_addr,
const pr_netaddr_t *remote_addr, int frontend_data) {
conn_t *conn, *opened = NULL;
- int res, reverse_dns;
+ int default_inet_family = 0, remote_family, res, reverse_dns, xerrno;
if (p == NULL ||
remote_addr == NULL) {
@@ -142,8 +142,19 @@ conn_t *proxy_ftp_conn_connect(pool *p, const pr_netaddr_t *bind_addr,
return NULL;
}
+ remote_family = pr_netaddr_get_family(remote_addr);
+ pr_trace_msg(trace_channel, 9,
+ "using %s family for backend socket address %s",
+ remote_family == AF_INET ? "IPv4" : "IPv6",
+ pr_netaddr_get_ipstr(remote_addr));
+ default_inet_family = pr_inet_set_default_family(p, remote_family);
+
conn = pr_inet_create_conn(session.pool, -1, bind_addr, INPORT_ANY, TRUE);
+ xerrno = errno;
+
if (conn == NULL) {
+ pr_inet_set_default_family(p, default_inet_family);
+ errno = xerrno;
return NULL;
}
@@ -179,7 +190,7 @@ conn_t *proxy_ftp_conn_connect(pool *p, const pr_netaddr_t *bind_addr,
}
if (res < 0) {
- int xerrno = errno;
+ xerrno = errno;
(void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
"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,
pr_netaddr_set_reverse_dns(reverse_dns);
if (opened == NULL) {
- int xerrno = errno;
+ xerrno = errno;
if (frontend_data == FALSE) {
proxy_inet_close(session.pool, conn);
=====================================
lib/proxy/ftp/dirlist.c
=====================================
@@ -1,6 +1,6 @@
/*
* ProFTPD - mod_proxy FTP dirlist routines
- * Copyright (c) 2020-2021 TJ Saunders
+ * Copyright (c) 2020-2025 TJ Saunders
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -126,7 +126,7 @@ struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_dos(pool *p,
return NULL;
}
- pr_trace_msg(trace_channel, 19, "parsing Windows text: '%*s'",
+ pr_trace_msg(trace_channel, 19, "parsing Windows text: '%.*s'",
(int) textlen, text);
/* 24 is the minimum length of a well-formatted Windows directory listing
@@ -134,7 +134,7 @@ struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_dos(pool *p,
*/
if (textlen < 24) {
pr_trace_msg(trace_channel, 3,
- "error parsing Windows text (too short, need at least 24 bytes): '%*s'",
+ "error parsing Windows text (too short, need at least 24 bytes): '%.*s'",
(int) textlen, text);
errno = EINVAL;
return NULL;
@@ -148,7 +148,7 @@ struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_dos(pool *p,
if (strpbrk(buf, "0123456789-") == NULL) {
pr_trace_msg(trace_channel, 3,
- "unexpected Windows date format: '%*s'", (int) buflen, buf);
+ "unexpected Windows date format: '%.*s'", (int) buflen, buf);
errno = EINVAL;
return NULL;
}
@@ -156,7 +156,7 @@ struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_dos(pool *p,
ptr += buflen;
if (strncmp(ptr, " ", 2) != 0) {
pr_trace_msg(trace_channel, 3,
- "malformed Windows text (expected 2 spaces after date): '%*s'",
+ "malformed Windows text (expected 2 spaces after date): '%.*s'",
(int) textlen, text); errno = EINVAL;
return NULL;
}
@@ -167,7 +167,7 @@ struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_dos(pool *p,
buf = pstrndup(p, ptr, buflen);
if (strpbrk(buf, "AMP0123456789:") == NULL) {
- pr_trace_msg(trace_channel, 3, "unexpected Windows time format: '%*s'",
+ pr_trace_msg(trace_channel, 3, "unexpected Windows time format: '%.*s'",
(int) buflen, buf);
errno = EINVAL;
return NULL;
@@ -189,10 +189,10 @@ struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_dos(pool *p,
buf = pstrndup(p, text, buflen);
pr_trace_msg(trace_channel, 19,
- "parsing Windows-style timestamp: '%*s'", (int) buflen, buf);
+ "parsing Windows-style timestamp: '%.*s'", (int) buflen, buf);
if (strptime(buf, windows_ts_fmt, pdf->tm) == NULL) {
pr_trace_msg(trace_channel, 3,
- "unexpected Windows timestamp format: '%*s'", (int) buflen, buf);
+ "unexpected Windows timestamp format: '%.*s'", (int) buflen, buf);
errno = EINVAL;
return NULL;
}
@@ -202,7 +202,7 @@ struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_dos(pool *p,
/* We now expect at least 7 spaces. */
if (strncmp(ptr, " ", 7) != 0) {
pr_trace_msg(trace_channel, 3,
- "malformed Windows text (expected 7 spaces after timestamp): '%*s'",
+ "malformed Windows text (expected 7 spaces after timestamp): '%.*s'",
(int) textlen, text);
errno = EINVAL;
return NULL;
@@ -220,7 +220,7 @@ struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_dos(pool *p,
if (strncmp(ptr, " ", 10) != 0) {
pr_trace_msg(trace_channel, 3,
- "malformed Windows text (expected 10 spaces after dir): '%*s'",
+ "malformed Windows text (expected 10 spaces after dir): '%.*s'",
(int) textlen, text);
errno = EINVAL;
return NULL;
@@ -245,7 +245,7 @@ struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_dos(pool *p,
if (strpbrk(buf, "0123456789 ") == NULL) {
pr_trace_msg(trace_channel, 3,
- "malformed Windows text (expected filesize with '%*s'): '%*s'",
+ "malformed Windows text (expected filesize with '%.*s'): '%.*s'",
(int) buflen, buf, (int) textlen, text);
errno = EINVAL;
return NULL;
@@ -254,7 +254,7 @@ struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_dos(pool *p,
size_ptr = strpbrk(buf, "0123456789");
if (size_ptr == NULL) {
pr_trace_msg(trace_channel, 3,
- "malformed Windows text (expected filesize not found): '%*s'",
+ "malformed Windows text (expected filesize not found): '%.*s'",
(int) textlen, text);
errno = EINVAL;
return NULL;
@@ -265,7 +265,7 @@ struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_dos(pool *p,
if (pr_str_get_nbytes(size_ptr, NULL, &filesz) < 0) {
pr_trace_msg(trace_channel, 3,
- "malformed Windows text (unable to parse filesize: %s): '%*s'",
+ "malformed Windows text (unable to parse filesize: %s): '%.*s'",
strerror(errno), (int) textlen, text);
errno = EINVAL;
return NULL;
@@ -276,7 +276,7 @@ struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_dos(pool *p,
if (strncmp(ptr, " ", 1) != 0) {
pr_trace_msg(trace_channel, 3,
- "malformed Windows text (missing space after filesize): '%*s'",
+ "malformed Windows text (missing space after filesize): '%.*s'",
(int) textlen, text);
errno = EINVAL;
return NULL;
@@ -286,7 +286,7 @@ struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_dos(pool *p,
} else {
pr_trace_msg(trace_channel, 3,
- "malformed Windows text (unexpected spaces after timestamp): '%*s'",
+ "malformed Windows text (unexpected spaces after timestamp): '%.*s'",
(int) textlen, text);
errno = EINVAL;
return NULL;
@@ -519,7 +519,7 @@ static int get_unix_user(pool *p, char *buf, size_t buflen,
res = sscanf(buf, "%s", user);
if (res != 1) {
pr_trace_msg(trace_channel, 3,
- "malformed Unix text (unable to parse user): '%*s'", (int) buflen, buf);
+ "malformed Unix text (unable to parse user): '%.*s'", (int) buflen, buf);
errno = EINVAL;
return -1;
}
@@ -552,7 +552,7 @@ static int get_unix_group(pool *p, char *buf, size_t buflen,
res = sscanf(buf, "%s", group);
if (res != 1) {
pr_trace_msg(trace_channel, 3,
- "malformed Unix text (unable to parse group): '%*s'", (int) buflen, buf);
+ "malformed Unix text (unable to parse group): '%.*s'", (int) buflen, buf);
errno = EINVAL;
return -1;
}
@@ -574,7 +574,7 @@ static int get_unix_filesize(pool *p, char *buf, size_t buflen,
if (pr_str_get_nbytes(buf, NULL, &filesz) < 0) {
pr_trace_msg(trace_channel, 3,
- "malformed Unix text (unable to parse filesize: %s): '%*s'",
+ "malformed Unix text (unable to parse filesize: %s): '%.*s'",
strerror(errno), (int) buflen, buf);
errno = EINVAL;
return -1;
@@ -610,7 +610,7 @@ static int get_unix_timestamp(pool *p, char *buf, size_t buflen,
if (found_month == FALSE) {
pr_trace_msg(trace_channel, 3,
- "malformed Unix text (unable to month in '%*s')", (int) buflen, buf);
+ "malformed Unix text (unable to month in '%.*s')", (int) buflen, buf);
errno = EINVAL;
return -1;
}
@@ -620,7 +620,7 @@ static int get_unix_timestamp(pool *p, char *buf, size_t buflen,
if (strncmp(buf, " ", 1) != 0) {
pr_trace_msg(trace_channel, 3,
- "malformed Unix text (expected space after month): '%*s'",
+ "malformed Unix text (expected space after month): '%.*s'",
(int) buflen, buf);
errno = EINVAL;
return -1;
@@ -632,7 +632,7 @@ static int get_unix_timestamp(pool *p, char *buf, size_t buflen,
res = sscanf(buf, "%2d", &mday);
if (res != 1) {
pr_trace_msg(trace_channel, 3,
- "malformed Unix text (expected mday after month): '%*s'",
+ "malformed Unix text (expected mday after month): '%.*s'",
(int) buflen, buf);
errno = EINVAL;
return -1;
@@ -664,7 +664,7 @@ static int get_unix_timestamp(pool *p, char *buf, size_t buflen,
} else {
pr_trace_msg(trace_channel, 3,
- "malformed Unix text (expected year/hour/min after mday): '%*s'",
+ "malformed Unix text (expected year/hour/min after mday): '%.*s'",
(int) buflen, buf);
errno = EINVAL;
return -1;
@@ -689,7 +689,7 @@ struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_unix(pool *p,
return NULL;
}
- pr_trace_msg(trace_channel, 19, "parsing Unix text: '%*s'",
+ pr_trace_msg(trace_channel, 19, "parsing Unix text: '%.*s'",
(int) textlen, text);
/* 43 is the minimum length of a well-formatted Unix directory listing
@@ -697,7 +697,7 @@ struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_unix(pool *p,
*/
if (textlen < 43) {
pr_trace_msg(trace_channel, 3,
- "error parsing Unix text (too short, need at least 43 bytes): '%*s'",
+ "error parsing Unix text (too short, need at least 43 bytes): '%.*s'",
(int) textlen, text);
errno = EINVAL;
return NULL;
@@ -775,7 +775,7 @@ struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_unix(pool *p,
break;
default:
- pr_trace_msg(trace_channel, 3, "unknown Unix file type: '%*s'", 1, text);
+ pr_trace_msg(trace_channel, 3, "unknown Unix file type: '%.*s'", 1, text);
errno = EINVAL;
return NULL;
}
@@ -786,7 +786,7 @@ struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_unix(pool *p,
if (strpbrk(buf, "rwx-tTsS") == NULL) {
pr_trace_msg(trace_channel, 3,
- "malformed Unix text (expected permissions): '%*s'", (int) buflen, buf);
+ "malformed Unix text (expected permissions): '%.*s'", (int) buflen, buf);
errno = EINVAL;
return NULL;
}
@@ -800,7 +800,7 @@ struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_unix(pool *p,
ptr += buflen;
if (strncmp(ptr, " ", 1) != 0) {
pr_trace_msg(trace_channel, 3,
- "malformed Unix text (expected space after permissions): '%*s'",
+ "malformed Unix text (expected space after permissions): '%.*s'",
(int) textlen, text);
errno = EINVAL;
return NULL;
@@ -815,7 +815,7 @@ struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_unix(pool *p,
ptr2 = strchr(ptr, ' ');
if (ptr2 == NULL) {
pr_trace_msg(trace_channel, 3,
- "malformed Unix text (expected space after nlink): '%*s'",
+ "malformed Unix text (expected space after nlink): '%.*s'",
(int) textlen, text);
errno = EINVAL;
return NULL;
@@ -829,7 +829,7 @@ struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_unix(pool *p,
int xerrno = errno;
pr_trace_msg(trace_channel, 3,
- "malformed Unix text (expected nlink with '%*s'): '%*s'", (int) buflen,
+ "malformed Unix text (expected nlink with '%.*s'): '%.*s'", (int) buflen,
buf, (int) textlen, text);
errno = xerrno;
@@ -839,7 +839,7 @@ struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_unix(pool *p,
ptr += buflen;
if (strncmp(ptr, " ", 1) != 0) {
pr_trace_msg(trace_channel, 3,
- "malformed Unix text (expected space after nlink): '%*s'",
+ "malformed Unix text (expected space after nlink): '%.*s'",
(int) textlen, text);
errno = EINVAL;
return NULL;
@@ -853,7 +853,7 @@ struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_unix(pool *p,
int xerrno = errno;
pr_trace_msg(trace_channel, 3,
- "malformed Unix text (expected user with '%*s'): '%*s'", (int) buflen,
+ "malformed Unix text (expected user with '%.*s'): '%.*s'", (int) buflen,
buf, (int) textlen, text);
errno = xerrno;
@@ -863,7 +863,7 @@ struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_unix(pool *p,
ptr += buflen;
if (strncmp(ptr, " ", 1) != 0) {
pr_trace_msg(trace_channel, 3,
- "malformed Unix text (expected space after user): '%*s'",
+ "malformed Unix text (expected space after user): '%.*s'",
(int) textlen, text);
errno = EINVAL;
return NULL;
@@ -877,7 +877,7 @@ struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_unix(pool *p,
int xerrno = errno;
pr_trace_msg(trace_channel, 3,
- "malformed Unix text (expected group with '%*s'): '%*s'", (int) buflen,
+ "malformed Unix text (expected group with '%.*s'): '%.*s'", (int) buflen,
buf, (int) textlen, text);
errno = xerrno;
@@ -887,7 +887,7 @@ struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_unix(pool *p,
ptr += buflen;
if (strncmp(ptr, " ", 1) != 0) {
pr_trace_msg(trace_channel, 3,
- "malformed Unix text (expected space after group): '%*s'",
+ "malformed Unix text (expected space after group): '%.*s'",
(int) textlen, text);
errno = EINVAL;
return NULL;
@@ -904,7 +904,7 @@ struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_unix(pool *p,
ptr2 = strchr(ptr, ' ');
if (ptr2 == NULL) {
pr_trace_msg(trace_channel, 3,
- "malformed Unix text (expected space after filesize): '%*s'",
+ "malformed Unix text (expected space after filesize): '%.*s'",
(int) textlen, text);
errno = EINVAL;
return NULL;
@@ -916,8 +916,8 @@ struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_unix(pool *p,
int xerrno = errno;
pr_trace_msg(trace_channel, 3,
- "malformed Unix text (expected filesize with '%*s'): '%*s'", (int) buflen,
- buf, (int) textlen, text);
+ "malformed Unix text (expected filesize with '%.*s'): '%.*s'",
+ (int) buflen, buf, (int) textlen, text);
errno = xerrno;
return NULL;
@@ -926,7 +926,7 @@ struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_unix(pool *p,
ptr += buflen;
if (strncmp(ptr, " ", 1) != 0) {
pr_trace_msg(trace_channel, 3,
- "malformed Unix text (expected space after filesize): '%*s'",
+ "malformed Unix text (expected space after filesize): '%.*s'",
(int) textlen, text);
errno = EINVAL;
return NULL;
@@ -941,7 +941,7 @@ struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_unix(pool *p,
int xerrno = errno;
pr_trace_msg(trace_channel, 3,
- "malformed Unix text (expected timestamp with '%*s'): '%*s'",
+ "malformed Unix text (expected timestamp with '%.*s'): '%.*s'",
(int) buflen, buf, (int) textlen, text);
errno = xerrno;
@@ -951,7 +951,7 @@ struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_unix(pool *p,
ptr += buflen;
if (strncmp(ptr, " ", 1) != 0) {
pr_trace_msg(trace_channel, 3,
- "malformed Unix text (expected space after timestamp): '%*s'",
+ "malformed Unix text (expected space after timestamp): '%.*s'",
(int) textlen, text);
errno = EINVAL;
return NULL;
@@ -963,7 +963,7 @@ struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_unix(pool *p,
ptr2 = strchr(ptr, ' ');
if (ptr2 == NULL) {
pr_trace_msg(trace_channel, 3,
- "malformed Unix text (expected space after symlink source): '%*s'",
+ "malformed Unix text (expected space after symlink source): '%.*s'",
(int) textlen, text);
errno = EINVAL;
return NULL;
@@ -975,7 +975,7 @@ struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_unix(pool *p,
ptr = ptr2 + 1;
if (strncmp(ptr, "-> ", 3) != 0) {
pr_trace_msg(trace_channel, 3,
- "malformed Unix text (expected arrow after symlink source): '%*s'",
+ "malformed Unix text (expected arrow after symlink source): '%.*s'",
(int) textlen, text);
errno = EINVAL;
return NULL;
@@ -1372,7 +1372,7 @@ int proxy_ftp_dirlist_to_text(pool *p, char *buf, size_t buflen,
pdf = proxy_ftp_dirlist_fileinfo_from_text(tmp_pool, input_line,
input_linelen, tm, user_data, proxy_sess->dirlist_opts);
if (pdf == NULL) {
- pr_trace_msg(trace_channel, 3, "error parsing text '%*s': %s",
+ pr_trace_msg(trace_channel, 3, "error parsing text '%.*s': %s",
(int) input_linelen, input_line, strerror(errno));
continue;
}
@@ -1401,7 +1401,7 @@ int proxy_ftp_dirlist_to_text(pool *p, char *buf, size_t buflen,
output_line = proxy_ftp_dirlist_fileinfo_to_facts(tmp_pool, pdf,
&output_linelen);
- pr_trace_msg(trace_channel, 19, "emitting line: '%*s'",
+ pr_trace_msg(trace_channel, 19, "emitting line: '%.*s'",
(int) output_linelen, output_line);
/* XXX What to do if this will exceed capacity of output buffer? */
=====================================
lib/proxy/ftp/xfer.c
=====================================
@@ -1,6 +1,6 @@
/*
* ProFTPD - mod_proxy FTP data transfer routines
- * Copyright (c) 2013-2022 TJ Saunders
+ * Copyright (c) 2013-2025 TJ Saunders
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -550,24 +550,44 @@ const pr_netaddr_t *proxy_ftp_xfer_prepare_passive(int policy_id, cmd_rec *cmd,
remote_port = ntohs(pr_netaddr_get_port(remote_addr));
- /* Make sure that the given address matches the address to which we
- * originally connected.
+ /* See if the given address matches the address to which we originally
+ * connected.
*/
-
if (pr_netaddr_cmp(remote_addr,
proxy_sess->backend_ctrl_conn->remote_addr) != 0) {
- (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
- "Refused %s address %s (address mismatch with %s)",
- (char *) pasv_cmd->argv[0], pr_netaddr_get_ipstr(remote_addr),
- pr_netaddr_get_ipstr(proxy_sess->backend_ctrl_conn->remote_addr));
- xerrno = EPERM;
- pr_response_add_err(error_code, "%s: %s", (char *) cmd->argv[0],
- strerror(xerrno));
- pr_response_flush(&resp_err_list);
+ pr_trace_msg(trace_channel, 2,
+ "backend passive transfer address %s does not match backend control "
+ "connection address %s", pr_netaddr_get_ipstr(remote_addr),
+ pr_netaddr_get_ipstr(proxy_sess->backend_ctrl_conn->remote_addr));
- errno = xerrno;
- return NULL;
+ if (proxy_opts & PROXY_OPT_IGNORE_FOREIGN_ADDRESS) {
+ (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
+ "Ignoring %s address %s per IgnoreForeignAddress ProxyOption, using %s "
+ "instead", (char *) pasv_cmd->argv[0],
+ pr_netaddr_get_ipstr(remote_addr),
+ pr_netaddr_get_ipstr(proxy_sess->backend_ctrl_conn->remote_addr));
+
+ remote_addr = pr_netaddr_dup(proxy_sess->dataxfer_pool,
+ proxy_sess->backend_ctrl_conn->remote_addr);
+ pr_netaddr_set_port2((pr_netaddr_t *) remote_addr, remote_port);
+
+ } else {
+ if (!(proxy_opts & PROXY_OPT_ALLOW_FOREIGN_ADDRESS)) {
+ (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
+ "Refused %s address %s (address mismatch with %s)",
+ (char *) pasv_cmd->argv[0], pr_netaddr_get_ipstr(remote_addr),
+ pr_netaddr_get_ipstr(proxy_sess->backend_ctrl_conn->remote_addr));
+ xerrno = EPERM;
+
+ pr_response_add_err(error_code, "%s: %s", (char *) cmd->argv[0],
+ strerror(xerrno));
+ pr_response_flush(&resp_err_list);
+
+ errno = xerrno;
+ return NULL;
+ }
+ }
}
if (remote_port < 1024) {
=====================================
lib/proxy/reverse/db.c
=====================================
@@ -1,6 +1,6 @@
/*
* ProFTPD - mod_proxy reverse datastore implementation
- * Copyright (c) 2012-2021 TJ Saunders
+ * Copyright (c) 2012-2025 TJ Saunders
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -1507,10 +1507,21 @@ static const struct proxy_conn *reverse_db_policy_next_backend(pool *p,
if (proxy_reverse_policy_is_sticky(policy_id) != TRUE) {
if (conns == NULL &&
- default_backends != NULL &&
db_backends == NULL) {
- conns = default_backends->elts;
- nelts = default_backends->nelts;
+
+ if (default_backends != NULL) {
+ conns = default_backends->elts;
+ nelts = default_backends->nelts;
+
+ } else {
+ /* Prevent possible null pointer dereferences later due to missing
+ * default URIs for non-sticky ConnectPolicy configurations.
+ */
+ pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
+ "missing required default/global ProxyReverseServers");
+ errno = EPERM;
+ return NULL;
+ }
}
}
=====================================
lib/proxy/session.c
=====================================
@@ -1,6 +1,6 @@
/*
* ProFTPD - mod_proxy session routines
- * Copyright (c) 2012-2022 TJ Saunders
+ * Copyright (c) 2012-2024 TJ Saunders
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -299,8 +299,6 @@ int proxy_session_setup_env(pool *p, const char *user, int flags) {
strerror(xerrno));
}
- session.disable_id_switching = TRUE;
-
session.proc_prefix = pstrdup(session.pool, session.c->remote_name);
session.sf_flags = 0;
=====================================
lib/proxy/ssh.c
=====================================
@@ -44,6 +44,7 @@
#include "proxy/ssh/utf8.h"
#if defined(PR_USE_OPENSSL)
+#include <openssl/conf.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
=====================================
lib/proxy/ssh/crypto.c
=====================================
@@ -1,6 +1,6 @@
/*
* ProFTPD - mod_proxy SSH crypto
- * Copyright (c) 2021-2022 TJ Saunders
+ * Copyright (c) 2021-2024 TJ Saunders
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -36,6 +36,13 @@
#endif /* !OPENSSL_NO_DES */
#include <openssl/err.h>
+#if OPENSSL_VERSION_NUMBER > 0x000907000L && \
+ OPENSSL_VERSION_NUMBER < 0x10100000L && \
+ defined(PR_USE_OPENSSL_ENGINE)
+# include <openssl/engine.h>
+static const char *crypto_engine = NULL;
+#endif
+
struct proxy_ssh_cipher {
const char *name;
const char *openssl_name;
@@ -1401,8 +1408,9 @@ void proxy_ssh_crypto_free(int flags) {
pr_module_get("mod_tls.c") == NULL) {
#if OPENSSL_VERSION_NUMBER > 0x000907000L && \
- OPENSSL_VERSION_NUMBER < 0x10100000L
- if (crypto_engine) {
+ OPENSSL_VERSION_NUMBER < 0x10100000L && \
+ defined(PR_USE_OPENSSL_ENGINE)
+ if (crypto_engine != NULL) {
ENGINE_cleanup();
crypto_engine = NULL;
}
=====================================
lib/proxy/ssh/msg.c
=====================================
@@ -1,6 +1,6 @@
/*
* ProFTPD - mod_proxy SSH message format
- * Copyright (c) 2021-2022 TJ Saunders
+ * Copyright (c) 2021-2024 TJ Saunders
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -70,7 +70,7 @@ uint32_t proxy_ssh_msg_read_byte(pool *p, unsigned char **buf, uint32_t *buflen,
}
uint32_t proxy_ssh_msg_read_bool(pool *p, unsigned char **buf, uint32_t *buflen,
- int *bool) {
+ int *b) {
unsigned char byte = 0;
uint32_t len;
@@ -81,7 +81,7 @@ uint32_t proxy_ssh_msg_read_bool(pool *p, unsigned char **buf, uint32_t *buflen,
return 0;
}
- *bool = byte;
+ *b = byte;
return len;
}
@@ -355,8 +355,8 @@ uint32_t proxy_ssh_msg_write_byte(unsigned char **buf, uint32_t *buflen,
}
uint32_t proxy_ssh_msg_write_bool(unsigned char **buf, uint32_t *buflen,
- unsigned char bool) {
- return proxy_ssh_msg_write_byte(buf, buflen, bool == 0 ? 0 : 1);
+ unsigned char b) {
+ return proxy_ssh_msg_write_byte(buf, buflen, b == 0 ? 0 : 1);
}
uint32_t proxy_ssh_msg_write_data(unsigned char **buf, uint32_t *buflen,
=====================================
lib/proxy/tls.c
=====================================
@@ -1,6 +1,6 @@
/*
* ProFTPD - mod_proxy TLS implementation
- * Copyright (c) 2015-2022 TJ Saunders
+ * Copyright (c) 2015-2024 TJ Saunders
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -3641,7 +3641,8 @@ static void tls_tlsext_cb(SSL *ssl, int server, int type,
(void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
"[tls.tlsext] TLS %s extension \"%s\" (ID %d, %d %s)%.*s",
server ? "server" : "client", extension_name, type, tlsext_datalen,
- tlsext_datalen != 1 ? "bytes" : "byte", (int) ext_infolen, ext_info);
+ tlsext_datalen != 1 ? "bytes" : "byte", (int) ext_infolen,
+ ext_info != NULL ? ext_info : "");
if (bio != NULL) {
BIO_free(bio);
@@ -3766,7 +3767,8 @@ static void tls_tlsext_cb(SSL *ssl, int server, int type,
(void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
"[tls.tlsext] TLS %s extension \"%s\" (ID %d, %d %s)%.*s",
server ? "server" : "client", extension_name, type, tlsext_datalen,
- tlsext_datalen != 1 ? "bytes" : "byte", (int) ext_infolen, ext_info);
+ tlsext_datalen != 1 ? "bytes" : "byte", (int) ext_infolen,
+ ext_info != NULL ? ext_info : "");
if (bio != NULL) {
BIO_free(bio);
@@ -3878,7 +3880,8 @@ static void tls_tlsext_cb(SSL *ssl, int server, int type,
(void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
"[tls.tlsext] TLS %s extension \"%s\" (ID %d, %d %s)%.*s",
server ? "server" : "client", extension_name, type, tlsext_datalen,
- tlsext_datalen != 1 ? "bytes" : "byte", (int) ext_infolen, ext_info);
+ tlsext_datalen != 1 ? "bytes" : "byte", (int) ext_infolen,
+ ext_info != NULL ? ext_info : "");
if (bio != NULL) {
BIO_free(bio);
@@ -3932,7 +3935,8 @@ static void tls_tlsext_cb(SSL *ssl, int server, int type,
(void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
"[tls.tlsext] TLS %s extension \"%s\" (ID %d, %d %s)%.*s",
server ? "server" : "client", extension_name, type, tlsext_datalen,
- tlsext_datalen != 1 ? "bytes" : "byte", (int) ext_infolen, ext_info);
+ tlsext_datalen != 1 ? "bytes" : "byte", (int) ext_infolen,
+ ext_info != NULL ? ext_info : "");
if (bio != NULL) {
BIO_free(bio);
=====================================
mod_proxy.c
=====================================
@@ -1,6 +1,6 @@
/*
* ProFTPD - mod_proxy
- * Copyright (c) 2012-2023 TJ Saunders
+ * Copyright (c) 2012-2025 TJ Saunders
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -485,6 +485,8 @@ static void proxy_restrict_session(void) {
*/
PRIVS_REVOKE
+ session.disable_id_switching = TRUE;
+
if (proxy_chroot != NULL) {
(void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
"proxy session running as UID %lu, GID %lu, restricted to '%s'",
@@ -811,6 +813,12 @@ MODRET set_proxyoptions(cmd_rec *cmd) {
} else if (strcmp(cmd->argv[i], "IgnoreConfigPerms") == 0) {
opts |= PROXY_OPT_IGNORE_CONFIG_PERMS;
+ } else if (strcmp(cmd->argv[i], "AllowForeignAddress") == 0) {
+ opts |= PROXY_OPT_ALLOW_FOREIGN_ADDRESS;
+
+ } else if (strcmp(cmd->argv[i], "IgnoreForeignAddress") == 0) {
+ opts |= PROXY_OPT_IGNORE_FOREIGN_ADDRESS;
+
} else {
CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, ": unknown ProxyOption '",
(char *) cmd->argv[i], "'", NULL));
@@ -820,6 +828,13 @@ MODRET set_proxyoptions(cmd_rec *cmd) {
c->argv[0] = pcalloc(c->pool, sizeof(unsigned long));
*((unsigned long *) c->argv[0]) = opts;
+ if (pr_module_exists("mod_ifsession.c")) {
+ /* These are needed in case this directive is used with mod_ifsession
+ * configuration.
+ */
+ c->flags |= CF_MULTI;
+ }
+
return PR_HANDLED(cmd);
}
@@ -978,6 +993,13 @@ MODRET set_proxyreverseservers(cmd_rec *cmd) {
c->argv[1] = pstrdup(c->pool, uri);
}
+ if (pr_module_exists("mod_ifsession.c")) {
+ /* These are needed in case this directive is used with mod_ifsession
+ * configuration.
+ */
+ c->flags |= CF_MULTI;
+ }
+
return PR_HANDLED(cmd);
}
@@ -1254,6 +1276,13 @@ MODRET set_proxysftpoptions(cmd_rec *cmd) {
c->argv[0] = pcalloc(c->pool, sizeof(unsigned long));
*((unsigned long *) c->argv[0]) = opts;
+ if (pr_module_exists("mod_ifsession.c")) {
+ /* These are needed in case this directive is used with mod_ifsession
+ * configuration.
+ */
+ c->flags |= CF_MULTI;
+ }
+
return PR_HANDLED(cmd);
}
@@ -1784,7 +1813,7 @@ MODRET set_proxytlscertkeyfile(cmd_rec *cmd) {
/* usage: ProxyTLSCipherSuite [protocol] ciphers */
MODRET set_proxytlsciphersuite(cmd_rec *cmd) {
-#ifdef PR_USE_OPENSSL
+#if defined(PR_USE_OPENSSL)
config_rec *c = NULL;
char *ciphersuite = NULL;
int protocol = 0;
@@ -1880,6 +1909,13 @@ MODRET set_proxytlsciphersuite(cmd_rec *cmd) {
c->argv[1] = palloc(c->pool, sizeof(int));
*((int *) c->argv[1]) = protocol;
+ if (pr_module_exists("mod_ifsession.c")) {
+ /* These are needed in case this directive is used with mod_ifsession
+ * configuration.
+ */
+ c->flags |= CF_MULTI;
+ }
+
return PR_HANDLED(cmd);
#else
CONF_ERROR(cmd, "Missing required OpenSSL support (see --enable-openssl configure option)");
@@ -1929,7 +1965,7 @@ MODRET set_proxytlsengine(cmd_rec *cmd) {
/* usage: ProxyTLSOptions ... */
MODRET set_proxytlsoptions(cmd_rec *cmd) {
-#ifdef PR_USE_OPENSSL
+#if defined(PR_USE_OPENSSL)
config_rec *c = NULL;
register unsigned int i = 0;
unsigned long opts = 0UL;
@@ -1970,6 +2006,13 @@ MODRET set_proxytlsoptions(cmd_rec *cmd) {
c->argv[0] = pcalloc(c->pool, sizeof(unsigned long));
*((unsigned long *) c->argv[0]) = opts;
+ if (pr_module_exists("mod_ifsession.c")) {
+ /* These are needed in case this directive is used with mod_ifsession
+ * configuration.
+ */
+ c->flags |= CF_MULTI;
+ }
+
return PR_HANDLED(cmd);
#else
CONF_ERROR(cmd, "Missing required OpenSSL support (see --enable-openssl configure option)");
@@ -2409,10 +2452,16 @@ static int proxy_data_prepare_backend_conn(struct proxy_session *proxy_sess,
* response until we connect to the backend data address/port.
*/
+ /* Specify the specific address/interface to use as the source address for
+ * connections to the destination server.
+ */
+ bind_addr = proxy_sess->src_addr;
+
/* Check the family of the remote 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(bind_addr) != pr_netaddr_get_family(proxy_sess->backend_data_addr)) {
+ if (bind_addr != NULL &&
+ pr_netaddr_get_family(bind_addr) != pr_netaddr_get_family(proxy_sess->backend_data_addr)) {
/* 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
@@ -2456,10 +2505,6 @@ static int proxy_data_prepare_backend_conn(struct proxy_session *proxy_sess,
}
}
- /* Specify the specific address/interface to use as the source address for
- * connections to the destination server.
- */
- bind_addr = proxy_sess->src_addr;
if (bind_addr == NULL) {
bind_addr = local_addr;
}
@@ -2512,14 +2557,9 @@ static int proxy_data_prepare_backend_conn(struct proxy_session *proxy_sess,
backend_conn = proxy_ftp_conn_connect(cmd->pool, bind_addr,
proxy_sess->backend_data_addr, FALSE);
if (backend_conn == NULL) {
- xerrno = errno;
-
- pr_response_add_err(R_425, _("%s: %s"), (char *) cmd->argv[0],
- strerror(xerrno));
- pr_response_flush(&resp_err_list);
-
- errno = xerrno;
- return -1;
+ pr_trace_msg(trace_channel, 9,
+ "error connecting to backend server for passive data transfer: %s",
+ strerror(errno));
}
proxy_sess->backend_data_conn = backend_conn;
@@ -5566,8 +5606,38 @@ static int proxy_sess_init(void) {
* needed.
*/
proxy_sess = (struct proxy_session *) proxy_session_alloc(proxy_pool);
- if (pr_table_add(session.notes, "mod_proxy.proxy-session", proxy_sess,
- sizeof(struct proxy_session)) < 0) {
+ res = pr_table_add(session.notes, "mod_proxy.proxy-session", proxy_sess,
+ sizeof(struct proxy_session));
+
+ if (res < 0 &&
+ errno == ENOSPC) {
+ int nents, nmaxents;
+
+ nents = pr_table_count(session.notes);
+ nmaxents = nents * 2;
+
+ /* Attempt to handle the unusual case where the table is full, since
+ * we really need this note.
+ */
+ pr_trace_msg(trace_channel, 1,
+ "session notes table is full (%u), increasing entry limit to %u",
+ nents, nmaxents);
+
+ if (pr_table_ctl(session.notes, PR_TABLE_CTL_SET_MAX_ENTS,
+ &nmaxents) == 0) {
+ res = pr_table_add(session.notes, "mod_proxy.proxy-session", proxy_sess,
+ sizeof(struct proxy_session));
+
+ } else {
+ (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
+ "error increasing session notes max entries: %s", strerror(errno));
+
+ res = -1;
+ errno = ENOSPC;
+ }
+ }
+
+ if (res < 0) {
(void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
"error stashing proxy session note: %s", strerror(errno));
=====================================
mod_proxy.h.in
=====================================
@@ -1,6 +1,6 @@
/*
* ProFTPD - mod_proxy
- * Copyright (c) 2012-2024 TJ Saunders
+ * Copyright (c) 2012-2025 TJ Saunders
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -88,7 +88,7 @@
/* Define if you have the strnstr(3) function. */
#undef HAVE_STRNSTR
-#define MOD_PROXY_VERSION "mod_proxy/0.9.4"
+#define MOD_PROXY_VERSION "mod_proxy/0.9.5"
/* Make sure the version of proftpd is as necessary. */
#if PROFTPD_VERSION_NUMBER < 0x0001030706
@@ -103,6 +103,8 @@
#define PROXY_OPT_IGNORE_CONFIG_PERMS 0x0010
#define PROXY_OPT_USE_PROXY_PROTOCOL_V2 0x0020
#define PROXY_OPT_USE_PROXY_PROTOCOL_V2_TLVS 0x0040
+#define PROXY_OPT_ALLOW_FOREIGN_ADDRESS 0x0080
+#define PROXY_OPT_IGNORE_FOREIGN_ADDRESS 0x0100
/* mod_proxy datastores */
#define PROXY_DATASTORE_SQLITE 1
=====================================
mod_proxy.html
=====================================
@@ -492,6 +492,52 @@ behavior of <code>mod_proxy</code>. For example:
<p>
The currently implemented options are:
<ul>
+ <li><code>AllowForeignAddress</code><br>
+ <p>
+ The <a href="http://www.proftpd.org/docs/modules/mod_core.html#AllowForeignAddress"><code>AllowForeignAddress</code></a> directive controls the policy for
+ <i>frontend</i> data transfer requests from clients connecting to the proxy
+ server; it does <b>not</b> apply to <i>backend</i> data transfer requests.
+ For those, you will want to use this <code>AllowForeignAddress</code>
+ option:
+ <pre>
+ # Allow for cases where the backend server tells us to use a different IP
+ # address for data transfers than the IP address to which mod_proxy connected.
+ ProxyOptions AllowForeignAddress
+ </pre>
+
+ <p>
+ Note that the <code>IgnoreForeignAddress</code> option takes precedence
+ over this option.
+ </li>
+
+ <p>
+ <li><code>IgnoreForeignAddress</code><br>
+ <p>
+ Use this option to tell the <code>mod_proxy</code> module to <i>always</i>
+ use the same IP address for passive data transfers to the backend server as
+ used for the control connection, ignoring any different IP address that
+ the backend server may provide in its <code>PASV</code> response.
+
+ <p>
+ This option may be needed in cases where you see backend data transfers fail with errors logged such as:
+ <pre>
+ unable to connect to 172.16.1.2#8200: Network unreachable
+ unable to connect to 172.16.2.2#8200: Connection refused
+ </pre>
+ Example:
+ <pre>
+ # When the backend server tells us to use a different IP address for data
+ # transfers than the IP address to which mod_proxy connected, ignore that
+ # different IP address and use the original initial IP address.
+ ProxyOptions IgnoreForeignAddress
+ </pre>
+
+ <p>
+ Note that this option takes precedence over the
+ <code>AllowForeignAddress</code> option.
+ </li>
+
+ <p>
<li><code>ShowFeatures</code><br>
<p>
When reverse proxying, <code>mod_proxy</code> defaults to not responding to
@@ -2546,7 +2592,7 @@ development library/header files <b>must</b> be installed for building
<hr>
<font size=2><b><i>
-© Copyright 2015-2024 TJ Saunders<br>
+© Copyright 2015-2025 TJ Saunders<br>
All Rights Reserved<br>
</i></b></font>
=====================================
t/lib/ProFTPD/Tests/Modules/mod_proxy.pm
=====================================
@@ -4963,11 +4963,12 @@ sub proxy_reverse_eprt_ipv6 {
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
TraceLog => $log_file,
- Trace => 'DEFAULT:10 event:0 lock:0 scoreboard:0 signal:0 proxy:20 proxy.ftp.conn:20 proxy.ftp.ctrl:20 proxy.ftp.data:20 proxy.ftp.msg:20',
+ Trace => 'DEFAULT:10 event:0 lock:0 scoreboard:0 signal:0 proxy:20 proxy.conn:20 proxy.ftp.conn:20 proxy.ftp.ctrl:20 proxy.ftp.data:20 proxy.ftp.msg:20',
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
AuthOrder => 'mod_auth_file.c',
+ UseIPv6 => 'on',
SocketBindTight => 'on',
TimeoutIdle => $timeout_idle,
@@ -5036,19 +5037,16 @@ EOC
my ($resp_code, $resp_msg) = $client->eprt('|2|::ffff:127.0.0.1|4856|');
- my $expected;
-
- $expected = 200;
+ my $expected = 200;
$self->assert($expected == $resp_code,
- test_msg("Expected $expected, got $resp_code"));
+ test_msg("Expected response code $expected, got $resp_code"));
$expected = "EPRT command successful";
$self->assert($expected eq $resp_msg,
- test_msg("Expected '$expected', got '$resp_msg'"));
+ test_msg("Expected response message '$expected', got '$resp_msg'"));
$client->quit();
};
-
if ($@) {
$ex = $@;
}
@@ -23599,6 +23597,7 @@ sub proxy_forward_noproxyauth_login_ipv6_dst_addr {
ServerIdent => 'on "Forward Proxy Server"',
SocketBindTight => 'on',
+ UseIPv6 => 'on',
IfModules => {
'mod_proxy.c' => $proxy_config,
@@ -26121,6 +26120,7 @@ sub proxy_forward_eprt_ipv6 {
ServerIdent => 'on "Forward Proxy Server"',
SocketBindTight => 'on',
+ UseIPv6 => 'on',
IfModules => {
'mod_proxy.c' => $proxy_config,
=====================================
t/lib/ProFTPD/Tests/Modules/mod_proxy/ssh.pm
=====================================
@@ -612,7 +612,28 @@ sub list_tests {
}
}
- return testsuite_get_runnable_tests($TESTS);
+ my @tests = testsuite_get_runnable_tests($TESTS);
+
+ # These tests need to be skipped due to lack of support when using newer
+ # OpenSSL versions, i.e. 3.x or later.
+ my $skipped_tests = {
+ proxy_reverse_backend_ssh_cipher_3des_ctr => 1,
+ proxy_reverse_backend_ssh_cipher_arcfour128 => 1,
+ proxy_reverse_backend_ssh_cipher_arcfour256 => 1,
+ proxy_reverse_backend_ssh_cipher_blowfish_ctr => 1,
+ };
+
+ foreach my $key (keys(%$skipped_tests)) {
+ my $ntests = scalar(@tests);
+ for (my $i = 0; $i < $ntests; $i++) {
+ if ($tests[$i] eq $key) {
+ splice(@tests, $i, 1);
+ last;
+ }
+ }
+ }
+
+ return @tests;
}
sub set_up {
View it on GitLab: https://salsa.debian.org/debian-proftpd-team/proftpd-mod-proxy/-/commit/1cdea7e4fcccb42c1fb3df022a8b2a6fe1232ae5
--
View it on GitLab: https://salsa.debian.org/debian-proftpd-team/proftpd-mod-proxy/-/commit/1cdea7e4fcccb42c1fb3df022a8b2a6fe1232ae5
You're receiving this email because of your account on salsa.debian.org.
More information about the Pkg-proftpd-maintainers
mailing list