#endif
/* Define if you have the sqlite3.h header. */
#undef HAVE_SQLITE3_H
#if !defined(HAVE_SQLITE3_H)
# error "SQLite library/headers required"
#endif
/* Define if you have the random(3) function. */
#undef HAVE_RANDOM
/* Define if you have the sqlite3_stmt_readonly() function. */
#undef HAVE_SQLITE3_STMT_READONLY
/* Define if you have the sqlite3_trace() function. */
#undef HAVE_SQLITE3_TRACE
/* Define if you have the sqlite3_trace_v2() function. */
#undef HAVE_SQLITE3_TRACE_V2
/* Define if you have the srandom(3) function. */
#undef HAVE_SRANDOM
/* Define if you have the strnstr(3) function. */
#undef HAVE_STRNSTR
#define MOD_PROXY_VERSION "mod_proxy/0.8"
/* Make sure the version of proftpd is as necessary. */
#if PROFTPD_VERSION_NUMBER < 0x0001030706
# error "ProFTPD 1.3.7a or later required"
#endif
/* mod_proxy option flags */
#define PROXY_OPT_USE_PROXY_PROTOCOL_V1 0x0001
#define PROXY_OPT_SHOW_FEATURES 0x0002
#define PROXY_OPT_USE_REVERSE_PROXY_AUTH 0x0004
#define PROXY_OPT_USE_DIRECT_DATA_TRANSFERS 0x0008
#define PROXY_OPT_IGNORE_CONFIG_PERMS 0x0010
#define PROXY_OPT_USE_PROXY_PROTOCOL_V2 0x0020
/* mod_proxy datastores */
#define PROXY_DATASTORE_SQLITE 1
#define PROXY_DATASTORE_REDIS 2
/* Miscellaneous */
extern int proxy_logfd;
extern module proxy_module;
extern pool *proxy_pool;
extern unsigned long proxy_opts;
extern unsigned int proxy_sess_state;
extern int proxy_datastore;
extern void *proxy_datastore_data;
extern size_t proxy_datastore_datasz;
/* mod_proxy session state flags */
#define PROXY_SESS_STATE_PROXY_AUTHENTICATED 0x0001
#define PROXY_SESS_STATE_CONNECTED 0x0002
#define PROXY_SESS_STATE_BACKEND_AUTHENTICATED 0x0004
#define PROXY_SESS_STATE_BACKEND_HAS_CTRL_TLS 0x0008
#define PROXY_SESS_STATE_BACKEND_HAS_DATA_TLS 0x0010
#ifndef PROXY_DEFAULT_RETRY_COUNT
# define PROXY_DEFAULT_RETRY_COUNT 5
#endif
#endif /* MOD_PROXY_H */
proftpd-mod_proxy-0.8/mod_proxy.html 0000664 0000000 0000000 00000216312 14020740307 0017765 0 ustar 00root root 0000000 0000000
ProFTPD module mod_proxy
ProFTPD module mod_proxy
The purpose of the mod_proxy
module is to provide FTP proxying
capabilities in proftpd
, both reverse (or "gateway")
proxying and forward proxying.
Installation instructions are discussed here.
Note that mod_proxy
requires ProFTPD 1.3.6rc2 or later.
Detailed notes on best practices for using this module are
here.
This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/).
This product includes cryptographic software written by Eric Young (eay@cryptsoft.com).
The most current version of mod_proxy
can be found at:
https://github.com/Castaglia/proftpd-mod_proxy.git
Author
Please contact TJ Saunders <tj at castaglia.org> with any
questions, concerns, or suggestions regarding this module.
Thanks
2015-08-24: Thanks to Michael Toth <mtoth at queldor.net>
for helping test multiple iterations of mod_proxy
with IIS
servers.
Directives
Syntax: ProxyDataTransferPolicy client|active|passive|pasv|epsv|port|eprt
Default: ProxyDataTransferPolicy client
Context: server config, <VirtualHost>
, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc1 and later
The ProxyDataTransferPolicy
directive configures the data
transfer policy that mod_proxy
uses when performing
data transfers (e.g. file uploads/downloads, directory listings) with
the backend/destination server.
The currently supported policies are:
client
This policy indicates that mod_proxy
will use whatever
the connected client uses. Thus if the client sends PORT
,
mod_proxy
will send PORT
to the
backend/destination server.
This is the recommended policy in most cases.
active
Regardless of the commands sent by the client, mod_proxy
will use only active data transfers (i.e. using
PORT
commands) with the backend/destination server.
passive
Regardless of the commands sent by the client, mod_proxy
will use only passive data transfers (i.e. using
PASV
commands) with the backend/destination server.
PASV
Regardless of the commands sent by the client, mod_proxy
will use only PASV
commands with the backend/destination
server.
PORT
Regardless of the commands sent by the client, mod_proxy
will use only PORT
commands with the backend/destination
server.
EPSV
Regardless of the commands sent by the client, mod_proxy
will use only EPSV
commands with the backend/destination
server.
EPRT
Regardless of the commands sent by the client, mod_proxy
will use only EPRT
commands with the backend/destination
server.
Syntax: ProxyDatastore type [info]
Default: ProxyDatastore SQLite
Context: server config
Module: mod_proxy
Compatibility: 1.3.6rc1 and later
The ProxyDatastore
directive configures the type of
datastore that mod_proxy
uses for persistence. The currently
supported datastore types are:
Note that the Redis type also requires the info
parameter, namely a prefix for all of the Redis keys. This prefix must
be different/unique among all of your mod_proxy
servers using
that Redis server/cluster; the prefix is used to keep all of the data
for this server separate from all other servers. For example:
<IfModule mod_proxy.c>
...
<IfModule mod_redis.c>
# Use our IP address as our prefix
ProxyDatastore Redis 1.2.3.4.
</IfModule>
</IfModule>
Syntax: ProxyDirectoryListPolicy client|"LIST" [opt1 ...]
Default: ProxyDirectoryListPolicy client
Context: server config, <VirtualHost>
, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc1 and later
The ProxyDirectoryListPolicy
directive configures the directory
list policy that mod_proxy
uses when performing
directory lists with the backend/destination server.
The currently supported policies are:
client
This policy indicates that mod_proxy
will use whatever
the connected client uses. Thus if the client sends MLSD
,
mod_proxy
will send MLSD
to the
backend/destination server.
This is the recommended policy in most cases.
LIST
This policy instructs mod_proxy
to use the LIST
command with the backend/destination server, regardless of the command
used by the client. The mod_proxy
module then handles any
reformatting of the LIST
response into the response needed
by the client. For example, if the client sends MLSD
but the
backend/destination server does not support this command,
mod_proxy
will send LIST
instead, and translate
the backend format into the client-requested format.
The current implementation of this policy handles LIST-<MLSD
translations only.
You may also provide options; the currently implemented
options are:
UseSlink
Use this option to have mod_proxy
use the broken
"OS.unix=slink" syntax, preferred by FTP clients such as FileZilla, for
indicating symlinks, rather than the more correct "OS.unix=symlink"
syntax. See
Bug#3318 for
a more detailed discussion.
Syntax: ProxyEngine on|off
Default: None
Context: server config, <VirtualHost>
, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc1 and later
The ProxyEngine
directive toggles the support for proxying by
mod_proxy
. This is usually used inside a
<VirtualHost>
section to enable proxying of FTP sessions for
a particular virtual host. By default mod_proxy
is disabled for
both the main server and all configured virtual hosts.
Syntax: ProxyForwardEnabled on|off
Default: None
Context: <Class>
Module: mod_proxy
Compatibility: 1.3.6rc2 and later
The ProxyForwardEnabled
directive determines whether a client
can use mod_proxy
for forward proxying, based on that client's
class.
By default, mod_proxy
rejects any forward proxy request from
any client, with the exception of clients connecting from
RFC 1918 addresses:
192.168.0.0/16
172.16.0.0/12
10.0.0.0/8
This is done as a security measure: open/unrestricted proxy servers are
dangerous both to your network and to the Internet at large. Thus to make
it possible for clients to use your server for forward proxying, they must
be explicitly enabled to do so.
Example:
<Class forward-proxy>
From 1.2.3.4/12
# Allow clients from this class to use FTP forward proxying
ProxyForwardEnabled on
</Class>
See also: ProxyForwardTo
Syntax: ProxyForwardMethod method
Default: None
Context: server config, <VirtualHost>
, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc1 and later
The ProxyForwardMethod
directive configures the method
that clients can use for requesting forward proxying. Some methods require
that the client authenticate to the proxy first, and then separately
authenticate to the destination server; these methods differ on just when
the client specifies the destination server. Other methods do not require
proxy authentication. There are many variations on a theme with these methods.
The currently supported methods are:
proxyuser,user@host
This method indicates that proxy authentication is required. The
client first authenticates to the proxy via USER/PASS
commands:
USER proxy-user
PASS proxy-passwd
Then the client authenticates again, this time including the
address (and optionally port) of the destination server as part of the
second USER
command:
USER real-user@ftp.example.com
PASS real-passwd
The mod_proxy
module will remove the destination address
portion of the second USER
command before proxying it to
the destination server.
proxyuser@host,user
This method indicates that proxy authentication is required. The
client first authenticates to the proxy via USER/PASS
commands;
note that the destination address (and optionally port) is included as part
of the first USER
command:
USER proxy-user@ftp.example.com
PASS proxy-passwd
Then the client authenticates again, this time sending the
USER/PASS
commands to authenticate to the destination server:
USER real-user
PASS real-passwd
user@host
This methods indicates that no proxy authentication is used. The
client indicates the destination address (and optionally port) of the
server as part of the USER
command:
USER real-user@ftp.example.com
PASS real-passwd
The mod_proxy
module will remove the destination address
portion of the USER
command before proxying it to the
destination server.
Configuring the FTP client's proxy settings to match the above methods varies
greatly, depending on the FTP client.
Syntax: ProxyForwardTo [!]pattern [flags]
Default: None
Context: server config, <VirtualHost>
, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc1 and later
The ProxyForwardTo
directive is used to restrict which
hosts/domains can be requested for forward proxying. The destination host/port
for forward proxying must match the configured pattern
regular expression, or the forward proxying request will fail.
The optional flags parameter, if present, modifies how the given
pattern will be evaludated. The supported flags are:
- nocase|NC (no case)
This makes the pattern case-insensitive, i.e. there is
no difference between 'A-Z' and 'a-z' when pattern is matched
against the path
ProxyForwardTo
limits the destination hosts to which
clients can request forward proxying; by contrast,
ProxyForwardEnabled
controls
forward proxying based on where clients connect from.
Syntax: ProxyLog path|"none"
Default: None
Context: server config, <VirtualHost>
, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc1 and later
The ProxyLog
directive is used to specify a log file for
mod_proxy
's reporting on a per-server basis. The path
parameter given must be the full path to the file to use for logging.
Note that this path must not be to a world-writable directory and,
unless AllowLogSymlinks
is explicitly set to on
(generally a bad idea), the path must not be a symbolic link.
Syntax: ProxyOptions opt1 ...
Default: None
Context: server config, <VirtualHost>
, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc1 and later
The ProxyOptions
directive is used to configure various optional
behavior of mod_proxy
. For example:
ProxyOptions UseProxyProtocolV1
The currently implemented options are:
ShowFeatures
When reverse proxying, mod_proxy
defaults to not responding to
the FTP FEAT
command, which is used to determine the supported
features/capabilities of the FTP server; this is done to prevent leaking
of information about internal FTP servers to the outside world. However,
some clients rely on the FEAT
data. For such clients/use
cases, use this option to tell mod_proxy
to proxy the
FEAT
command/response to the backend server.
UseDirectDataTransfers
The mod_proxy
module will, by default, proxy all data transfers
through the proxy server. Some sites may wish to have the FTP data
transfers occur directly between the frontend client and the backend server,
to avoid the latency/overhead of the proxying. Use this option to
enable these direct data transfers (akin to Direct Server
Return, or DSR), for both forward and reverse proxy roles:
# Enable data transfers directly from frontend client to/from backend server
ProxyOptions UseDirectDataTransfers
UseProxyProtocolV1
When mod_proxy
connects to the backend/destination server,
use the PROXY
V1 protocol, sending the human-readable PROXY
command to the destination server. This allows backend servers to implement
access controls/logging, based on the IP address of the connecting client.
The mod_proxy_protocol
ProFTPD module can be used to handle the PROXY
command on
the receiving side, i.e. when using proftpd
as the
backend/destination server.
Note: do not use this option unless the backend server
does support the PROXY
V1 protocol. Otherwise, the
PROXY
protocol message will only confuse the backend server,
possibly leading to connection/login failures.
UseProxyProtocolV2
When mod_proxy
connects to the backend/destination server,
use the PROXY
V2 protocol, sending a binary-encoded "PROXY" command
to the destination server. This allows backend servers to implement
access controls/logging, based on the IP address of the connecting client.
The mod_proxy_protocol
ProFTPD module can be used to handle the "PROXY" command on the receiving
side, i.e. when using proftpd
as the
backend/destination server.
Note: do not use this option unless the backend server
does support the PROXY
V2 protocol. Otherwise, the
"PROXY" protocol message will only confuse the backend server, possibly
leading to connection/login failures.
UseReverseProxyAuth
When reverse proxying, mod_proxy
delegates user authentication
to the selected backend server. However, there are some sites which need
to centralize user authentication in the proxy; use this option to require
proxy authentication for such cases. Note that this option
only pertains to reverse proxy connections; proxy authentication
when forward proxying is determined by the ProxyForwardMethod
directive.
Syntax: ProxyRetryCount count
Default: ProxyRetryCount 5
Context: server config, <VirtualHost>
, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc1 and later
The ProxyRetryCount
directive configures the number of times
mod_proxy
will attempt to connect to the backend/destination
server. The default is 5 attempts.
Syntax: ProxyReverseConnectPolicy policy
Default: None
Context: server config, <VirtualHost>
, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc1 and later
The ProxyReverseConnectPolicy
directive configures the
policy that mod_proxy
will use for selecting the backend
server when reverse proxying.
The currently supported policies are:
LeastConns
Select the backend server with the lowest number of proxied connections.
LeastResponseTime
Select the backend server with the least response time; this is determined
based on the connect time to the backend server, and its number of
current connections.
PerGroup
Select a backend server based on the primary group of the authenticated
USER
name used by the connecting client; any future
connections using that same USER
name will be routed to the
same backend server.
Note: use of this ProxyReverseConnectPolicy
also
requires use of the UseReverseProxyAuth
ProxyOption
, as authenticating the given USER
name is required for discovering the primary group of that user.
PerHost
Select a backend server based on the IP address of the connecting client;
any future connections from that IP address will be routed to the same
backend server.
PerUser
Select a backend server based on the USER
name used by the
connecting client; any future connections using that same USER
name will be routed to the same backend server.
Random
Randomly select any of the backend servers.
RoundRobin
Select the next backend server in the list.
Shuffle
Similar to the Random
policy, except the selection happens
from the not-yet-chosed backend servers. This means that all
backend servers will eventually be used evenly, just in a random order.
Syntax: ProxyReverseServers servers
Default: None
Context: server config, <VirtualHost>
, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc1 and later
The ProxyReverseServers
directive configures the list of servers
to be used as the backend servers for reverse proxying.
Each server must be configured as a URL. Only the "ftp" and
"ftps" schemes are currently supported. If not specified, the port will be
21. IPv6 addresses must be enclosed within square brackets. Thus, for
example, the following are all valid URLs:
ftp://ftp1.example.com:2121
ftp://1.2.3.4
ftp://[::ffff:6.7.8.9]:2121
ftps://ftp2.example.com
ftps://ftp3.example.com:990
And using them all in the configuration would look like:
ProxyReverseServers ftp://ftp1.example.com:2121 ftps://1.2.3.4 ftp://[::ffff:6.7.8.9]:2121
The backend servers can also be discovered via DNS SRV
or TXT
records, using SRV/TXT
URL scheme variants, e.g.:
# Discover backend addresses via DNS SRV records
ftp+srv://_ftp._tcp.castaglia.org
# Discover backend addresses via DNS TXT records (which must be an FTP URL)
ftp+txt://castaglia.org
These SRV/TXT
URL scheme variations also apply to FTPS URLs.
Note that any explicit port numbers provided in URLs using these
SRV/TXT
scheme variants will be ignored; the actual port
numbers to use will be discovered from the SRV
and TXT
DNS records.
The backend servers can also be contained in a list in a JSON file,
e.g.:
[
"ftp://ftp1.example.com:2121",
"ftp://[::ffff:6.7.8.9]:2121"
]
You then only need to configure the path to that JSON file:
ProxyReverseServers file:/path/to/backends.json
Note that mod_proxy
has strict requirements for the
permissions on ProxyReverseServers
files. The configured file
must not be world-writable, since that would allow any user
on the system to modify the file, directing proxied connections anywhere else.
If a world-writable ProxyReverseServers
file is found, you will
see the following error message logged:
unable to use world-writable ProxyReverseServers '/opt/proxy/reverse.json' (perms 0666): Operation not permitted
In addition, the directory containing the
ProxyReverseServers
file cannot be world-writable, either. Even
if the file itself is not world-writable, being in a world-writable directory
means that any user on the system can delete that file, and write a new
file. When a world-writable directory is found, the following error is logged:
unable to use ProxyReverseServers '/opt/proxy/reverse.json' from world-writable directory '/opt/proxy' (perms 0777): Operation not permitted
The backend servers can also be provided from an external SQL database,
queried by mod_proxy
via SQLNamedQuery
. For example,
assuming a schema such as this:
CREATE TABLE proxy_user_servers (
user_name TEXT,
url TEXT
);
CREATE INDEX proxy_user_servers_name_idx ON proxy_user_servers (user_name);
where url contains URLs, e.g. "ftp://1.2.3.4:21". Then you
would configure mod_proxy
to query for those per-user backend URLs
using ProxyReverseServers
like this:
<IfModule mod_sql.c>
...
SQLNamedQuery get-user-servers SELECT "url FROM proxy_user_servers WHERE user_name = %{0}"
</IfModule>
ProxyRole reverse
ProxyReverseConnectPolicy PerUser
ProxyReverseServers sql:/get-user-servers
Given that mod_proxy
uses SQLite, does that mean that the table
used for storing these per-user URLs must be SQLite? No. The
use of SQLNamedQuery
means that any database, supported
by mod_sql
, can be used.
Syntax: ProxyRole role
Default: None
Context: server config, <VirtualHost>
, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc1 and later
The ProxyRole
directive configures whether mod_proxy
will perform forward or reverse proxying. The list of supported roles
are thus:
Note that the ProxyRole
directive is required
for mod_proxy
to function. If this directive is not configured,
connections to mod_proxy
will fail.
Syntax: ProxySourceAddress address
Default: None
Context: server config, <VirtualHost>
, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc1 and later
The ProxySourceAddress
directive configures the address
(or device name) of a network interface on the host machine, to
be used when connecting to the backend/destination server. This directive
is most useful on a multi-homed (or DMZ) host; frontend connections can
be received on one network interface, and the backend connections can use
a different network interface. Imagine e.g. separate WAN/LAN interfaces
on a proxying host.
Syntax: ProxyTables table-info
Default: None
Context: server config
Module: mod_proxy
Compatibility: 1.3.6rc1 and later
The ProxyTables
directive is used to specify a directory that
mod_proxy
will use for storing its database files; these files
are used for tracking the various load balancing/healthcheck statistics used
for proxying.
Note that the ProxyTables
directive is required
for mod_proxy
to function. If this directive is not configured,
connections to mod_proxy
will fail.
Syntax: ProxyTimeoutConnect timeout
Default: ProxyTimeoutConnect 5sec
Context: server config, <VirtualHost>
, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc1 and later
The ProxyTimeoutConnect
directive configures the amount of time
that mod_proxy
will wait for the backend/destination server to
accept a TCP connection, before giving up.
Note that if there are many different backend/destination servers to try
(due to e.g. ProxyRetryCount
), and if those
backend servers are slow, the connecting client might itself see connection
timeouts to mod_proxy
. To guard against such slow backend
servers, a more aggressively short timeout can be used:
ProxyTimeoutConnect 1sec
Syntax: ProxyTimeoutLinger timeout
Default: ProxyTimeoutLinger 3sec
Context: server config, <VirtualHost>
, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc1 and later
The ProxyTimeoutLinger
directive configures the amount of time
that mod_proxy
will wait (lingering), after receiving
all of the data on the data transfer connection to the backend server, for the
explicit "end of transfer" response from the backend server, before giving up.
Syntax: ProxyTLSCACertificateFile path
Default: None
Context: server config, <VirtualHost>
, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc2 and later
The ProxyTLSCACertificateFile
directive configures one file where
you can assemble the certificates of Certification Authorities (CA) which will
be used to verify the servers' certificates. Such a file is merely the
concatenation of the various PEM-encoded CA certificates. This directive can
be used in addition to, or as an alternative for,
ProxyTLSCACertificatePath
.
Example:
ProxyTLSCACertificateFile /etc/ftpd/cacerts.pem
Note that the location of CA certificates is required for
mod_proxy
's TLS support; verification of server certificates
is required for secure connections to backend/destination servers. For
this reason, mod_proxy
ships with its own default
ProxyTLSCACertificateFile
, which is generated using libcurl
's mk-ca-bundle.pl
script:
$ lib/mk-ca-bundle.pl -u cacerts.pem
Syntax: ProxyTLSCACertificatePath directory
Default: None
Context: server config, <VirtualHost>
, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc2 and later
The ProxyTLSCACertificatePath
directive sets the directory for the
certificates of Certification Authorities (CAs); these are used to verify the
server certificates presented. This directive may be used in addition to, or
as alternative for, ProxyTLSCACertificateFile
.
The files in the configured directory have to be PEM-encoded, and are accessed
through hash filenames. This means one cannot simply place the CA certificates
there: one also has to create symbolic links named hash-value.N. The
c_rehash
utility that comes with OpenSSL can be used to create
the necessary symlinks.
Example:
ProxyTLSCACertificatePath /etc/ftpd/cacerts/
Syntax: ProxyTLSCACertificateFile path
Default: None
Context: server config, <VirtualHost>
, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc2 and later
The ProxyTLSCARevocationFile
directive configures one file that can
contain the Certificate Revocation Lists (CRL) of Certification Authorities
(CA); these CRLs are used during the verification of server certificates. Such
a file is merely the concatenation of the various PEM-encoded CRL files. This
directive can be used in addition to, or as an alternative for,
ProxyTLSCARevocationPath
.
Example:
ProxyTLSCARevocationFile /etc/ftpd/cacrls.pem
Syntax: ProxyTLSCARevocationPath directory
Default: None
Context: server config, <VirtualHost>
, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc2 and later
The ProxyTLSCARevocationPath
directive sets the directory for the
Certificate Revocation Lists (CRL) of Certification Authorities (CAs); these
are used during the verification of server certificates. This directive may
be used in addition to, or as alternative for,
ProxyTLSCARevocationFile
.
The files in the configured directory have to be PEM-encoded, and are accessed
through hash filenames. This means one cannot simply place the CRLs there:
one also has to create symbolic links named hash-value.N. The
c_rehash
utility that comes with OpenSSL can be used to create
the necessary symlinks.
Example:
ProxyTLSCARevocationPath /etc/ftpd/cacrls/
Syntax: ProxyTLSCertificateFile path
Default: None
Context: server config, <VirtualHost>
, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc2 and later
The ProxyTLSCertificateFile
directive points to the PEM-encoded
file containing the client certificate file, and optionally also
the corresponding private key. Note that this directive is only
needed for backend/target FTPS servers which require client authentication.
Example:
ProxyTLSCertificateFile /etc/ftpd/client-cert.pem
Syntax: ProxyTLSCertificateKeyFile path
Default: None
Context: server config, <VirtualHost>
, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc2 and later
The ProxyTLSCertificateKeyFile
directive points to the PEM-encoded
file containing the client certificate file, and optionally also
The ProxyTLSCertificateKeyFile
directive points to the PEM-encoded
private key file for the client certificate indicated by
ProxyTLSCertificateFile
. If the private key is not combined with
the certificate in the ProxyTLSCertificateFile
, use this additional
directive to point to the file with the standalone private key. When
ProxyTLSCertificateFile
is used and the file contains both the
certificate and the private key, this directive need not be used. However,
this practice is strongly discouraged. Instead we recommend you to separate
the certificate and the private key.
Syntax: ProxyTLSCipherSuite [protocol] cipher-list
Default: ProxyTLSCipherSuite DEFAULT:!ADH:!EXPORT:!DES
Context: server config, <VirtualHost>
, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc2 and later
The ProxyTLSCipherSuite
directive configures the list of
acceptable SSL/TLS ciphersuites to use for backend SSL/TLS connections. The
syntax is that of the OpenSSL ciphers
command, e.g.:
$ openssl ciphers -v <cipher-list>
may be used to list all of the ciphers and the order described by a specific
<cipher-list>.
If the SSL library supports TLSv1.3 (e.g. OpenSSL-1.1.1 and later), the
protocol specifier "TLSv1.3" can be used to configure the cipher
suites for that protocol:
# Configure TLSv1.3 ciphersuites
ProxyTLSCipherSuite TLSv1.3 TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256
Syntax: ProxyTLSEngine on|off|auto
Default: ProxyTLSEngine auto
Context: server config, <VirtualHost>
, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc2 and later
The ProxyTLSEngine
directive configures the use of SSL/TLS for
backend FTP connections. The supported values are:
- on
Use of SSL/TLS is required; backend servers which do not support
SSL/TLS or which fail the SSL/TLS handshake will cause the proxied
session to be closed.
- off
Use of SSL/TLS is disabled; backend servers which do support SSL/TLS
will be ignored, and only FTP will be used.
- auto
Use of SSL/TLS will be automatically used if the backend server
supports SSL/TLS (via AUTH TLS
in its FEAT
response). If the SSL/TLS handshake fails, the backend connection will
proceed using plain FTP.
Note: this is the default behavior in mod_proxy
.
Syntax: ProxyTLSOptions options
Default: None
Context: server config, <VirtualHost>
, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc2 and later
The ProxyTLSOptions
directive is used to configure various
optional SSL/TLS behavior of mod_proxy
.
Example:
ProxyTLSOptions EnableDiags
The currently implemented options are:
AllowWeakSecurity
Sets the cryptographic security level to "zero", meaning that any/all
ciphers and key sizes are permitted. This option allows for the best
interoperability with any FTPS server, but is
not recommended. Use only when necessary.
EnableDiags
Sets callbacks in the OpenSSL library such that a lot of
SSL/TLS protcol information is logged to the
ProxyLog
file. This option is
very useful when debugging strange interactions with FTPS servers.
NoSessionCache
By default, when using SSL/TLS, mod_proxy
will cache
the negotiated SSL sessions in its local database, for reuse in enabling
SSL session resumption in future connections to those hosts. Use this
option to disable use of session caching if/when needed.
NoSessionTickets
By default, when using SSL/TLS, mod_proxy
will cache
any session tickets
offered by the server in its local database, for reuse in enabling
SSL session resumption in future connections to those hosts. Use this
option to disable use of session tickets if/when needed.
Syntax: ProxyTLSPreSharedKey identity key-info
Default: None
Context: server config, <VirtualHost>
, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc2 and later
The ProxyTLSPreSharedKey
directive is used to configure a
pre-shared key (PSK), for use in
TLS-PSK ciphersuites. Each
PSK has an identity (a string/name used by clients to request the use
of that PSK), and the actual key data. The key data may be encoded in different
ways; the ProxyTLSPreSharedKey
directive requires that the data be
hex-encoded, as indicated in the key-info parameter.
The key-info parameter is comprised of the type of encoding used for
the key data, and the full path to the key file. Only "hex" encoding is
supported right now. Thus an example ProxyTLSPreSharedKey
directive would be:
ProxyTLSPreSharedKey MyPSK hex:/path/to/psk.key
The configured file cannot be world-readable or world-writable; the
mod_proxy
module will skip/ignore such insecure permissions.
To generate this shared key (which is just a randomly generated bit of data),
you can use:
$ openssl rand 160 -out /path/to/identity.key -hex
Note that ProxyTLSPreSharedKey
requires at least 20 bytes of key
data. Having generated the random key data, tell mod_proxy
to use
it via:
ProxyTLSPreSharedKey identity hex:/path/to/identity.key
Syntax: ProxyTLSProtocol protocols
Default: ProxyTLSProtocol TLSv1 TLSv1.1 TLSv1.2
Context: server config, <VirtualHost>
, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc2 and later
The ProxyTLSProtocol
directive is used to configure the SSL/TLS
protocol versions that mod_proxy
should use when establishing
SSL/TLS sessions to backend servers.
The allowed protocols are:
SSLv3 |
Use only SSLv3 |
TLSv1 |
Use only TLSv1 |
TLSv1.1 |
Use only TLSv1.1 |
TLSv1.2 |
Use only TLSv1.2 |
To support both SSLv3 and TLSv1, simply list both parameters for the
ProxyTLSProtocol
directive, e.g.:
ProxyTLSProtocol SSLv3 TLSv1
The ProxyTLSProtocol
directive can also be used in a different
manner, to add or subtract protocol support. For example,
to enable all protocols except SSLv3, you can use:
ProxyTLSProtocol ALL -SSLv3
Using the directive in this manner requires that "ALL" be the first
parameter, and that all protocols have either a +
(add) or -
(subtract) prefix. "ALL" will
always be expanded to all of the supported SSL/TLS protocols known by
mod_proxy
and supported by OpenSSL
.
Syntax: ProxyTLSTimeoutHandshake timeout
Default: ProxyTLSTimeoutHandshake 30sec
Context: server config, <VirtualHost>
, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc2 and later
The ProxyTLSTimeoutHandshake
directive configures the maximum
number of seconds for mod_proxy
to complete an SSL/TLS handshake.
If set to zero, mod_proxy
will wait forever for a handshake to
complete. The default is 30 seconds.
Syntax: ProxyTLSTransferProtectionPolicy client|required|clear
Default: ProxyTLSTransferProtectionPolicy required
Context: server config, <VirtualHost>
, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc1 and later
The ProxyTLSTransferProtectionPolicy
directive configures the data
transfer protection policy, when using SSL/TLS, that
mod_proxy
uses when performing data transfers (e.g. file
uploads/downloads, directory listings) with the backend/destination server.
The currently supported policies are:
client
This policy indicates that mod_proxy
will use whatever
the connected client uses. Thus if the client sends PROT C
,
mod_proxy
will send PROT C
to the
backend/destination server.
required
Regardless of the commands sent by the client, mod_proxy
will use only protected TLS data transfers (i.e. using
PROT P
commands) with the backend/destination server.
This is the recommended policy in most cases.
clear
Regardless of the commands sent by the client, mod_proxy
will use only clear (i.e. unprotected) data
transfers (i.e. using PROT C
commands) with the
backend/destination server.
Syntax: ProxyTLSVerifyServer on|off
Default: ProxyTLSVerifyServer on
Context: server config, <VirtualHost>
, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc2 and later
The ProxyTLSVerifyServer
directive configures how
mod_proxy
handles certificates presented by servers. If
off, the module will accept any server certificate and
establish an SSL/TLS session, but will not verify the certificate. If
on, the module will verify a server's certificate and, furthermore,
will fail all SSL handshake attempts unless the server presents a valid
certificate.
Benefits of Proxying
The benefits of using a module like mod_proxy
depend mostly
on the type of proxying, forward or reverse, that mod_proxy
is configured to perform. There are some benefit, however, that the module
can bring, regardless of the type of proxying:
- Add ProFTPD's FTPS support (via
mod_tls
) for FTP servers which do not support FTPS
- Add ProFTPD's FTPS support for FTP clients which do not support FTPS
- Add ProFTPD's IPv6 support for FTP clients/servers which do not support it
- Add ProFTPD's logging power (
TransferLog
, ExtendedLog
, etc) for FTP servers which do not provide such versatile logging
- Use ProFTPD's monitoring capabilities (e.g.
mod_snmp
) for FTP servers which do not have such features
When using mod_proxy
for proxying, all data transfers
(e.g. file uploads/downloads, directory listings, etc) pass through
mod_proxy
; data transfers do not occur directly between
the "frontend" clients and the "backend" servers. This happens so that
clients are completely unaware of the network structure for the
backend servers; this is especially important when reverse proxying, where
it means that the client sees mod_proxy
as the real FTP
server.
Forward Proxying
One of the most common benefits of a forward proxy is having controlled access,
by clients within an internal LAN, to outside servers. FTP makes this sort
of thing notoriously difficult for firewalls/routers due to its multi-TCP
connection nature; this, in turn, makes proxying of FTP more difficult. But
mod_proxy
makes this possible; it understands FTP, and thus
provides the access control needed for such use cases.
When using mod_proxy
as a forward proxy, FTP clients which can
only perform active data transfers can use mod_proxy
as a way
to use passive data transfers with the destination FTP server.
Similarly, FTP clients which do not support IPv6 can proxy through
mod_proxy
to reach a destination FTP server with an IPv6 address;
mod_proxy
handles IPv4 and IPv6 addresses transparently.
Reverse Proxying
Just as mod_proxy
can aid naive/legacy FTP clients via forward
proxying, mod_proxy
can similarly front legacy FTP servers.
For example, mod_proxy
can sit in front of FTP servers which
do not handle IPv6 addresses, and provide this functionality transparently
to IPv6-capable FTP clients.
When performing reverse proxying, mod_proxy
can also perform
load balancing in various ways. The common methods of "round robin" and
"least connections" are implemented; mod_proxy
also provides
"sticky session" load balancing of clients as well.
Handling of Proxied Sessions
Once a proxied session has authenticated with the backend/destination server,
the mod_proxy
module automatically chroots itself to a
subdirectory of the ProxyTables
directory, after which all root privileges are permanently dropped.
Forward Proxy Configuration
Before discussing example forward proxy configurations for
mod_proxy
, it is very important to understand the consequences
of providing forward proxy capabilities.
Important Security Considerations
A forward proxy can be used by any client to have the proxy
connect to any arbitrary host, while hiding the client's true identity.
Malicious behavior, hacking or denial-of-service attempts, etc will
appear to be coming from your proxy; this is dangerous for your
network, and for the Internet at large. Think of the damage that has been
done, and continues to happen, due to open/unrestricted proxies/relays
such as open DNS or SMTP/email proxies.
This is the reason that mod_proxy
does not allow just any
client to use its forward proxy capabilities by default; instead, only
clients connecting from the LAN are allowed by default. Allowing trusted
outside clients is done using the
ProxyForwardEnabled
directive.
Even allowing internal clients to use your forward proxy can be troublesome,
depending on the destination hosts selected by the clients. To ensure that
your clients are using the forward proxy to connect only to the hosts allowed,
you can use the ProxyForwardTo
directive to configure a regular expression-based whitelist of allowed
destination/target hosts; this is strongly recommended.
With all that said, here's an example mod_proxy
configuration
for supporting forward proxying:
<IfModule mod_proxy.c>
ProxyEngine on
ProxyLog /path/to/proxy.log
ProxyTables /var/ftp/proxy
ProxyRole forward
ProxyForwardMethod user@host
ProxyForwardTo ^ftp\.example\.com\:21$ [NC]
</IfModule>
If the configured ProxyForwardTo
pattern is not met,
the following will be logged in the ProxyLog
:
mod_proxy/0.7[16151]: host/port 'server.example.org:2121' did not match ProxyForwardTo ^ftp\.example\.com\:21$, rejecting
Reverse Proxy Configuration
Reverse proxies (also known as "gateways") are often used to provide access
to FTP resources, located with internal networks, to the outside world. The
reverse proxy can perform load balancing, provide functionality that the
internal servers may not be able to do, and even perform things like caching.
Access control for reverse proxies is less critical than for forward proxies
because clients can only reach, via the reverse proxy, the backend servers
that the reverse proxy has been configured to use; the clients do not
get to choose arbitrary hosts for the reverse proxy to use.
Here's an example mod_proxy
configuration for supporting reverse
proxying:
<IfModule mod_proxy.c>
ProxyEngine on
ProxyLog /path/to/proxy.log
ProxyTables /var/ftp/proxy
ProxyRole reverse
ProxyReverseConnectPolicy RoundRobin
ProxyReverseServers ftp://ftp-backend1.example.com:2121 ftp://ftp-backend2.example.com:2121 ...
</IfModule>
Here's an example mod_proxy
configuration for reverse proxying,
with lookup of per-user backend servers:
<IfModule mod_proxy.c>
ProxyEngine on
ProxyLog /path/to/proxy.log
ProxyTables /var/ftp/proxy
ProxyRole reverse
ProxyReverseConnectPolicy PerUser
# We need to provide a pool of backend servers as a fallback
ProxyReverseServers ftp://ftp-backend1.example.com:2121 ftp://ftp-backend2.example.com:2121 ...
# Look up per-user backend servers from user-specific JSON files
ProxyReverseServers file:/var/ftp/proxy/backends/%U.json
</IfModule>
Similarly, you can use a per-group lookup for the backend servers when
reverse proxying:
<IfModule mod_proxy.c>
ProxyEngine on
ProxyLog /path/to/proxy.log
ProxyTables /var/ftp/proxy
ProxyRole reverse
ProxyReverseConnectPolicy PerGroup
ProxyOptions UseReverseProxyAuth
# We need to provide a pool of backend servers as a fallback
ProxyReverseServers ftp://ftp-backend1.example.com:2121 ftp://ftp-backend2.example.com:2121 ...
# Look up per-group backend servers from group-specific JSON files
ProxyReverseServers file:/var/ftp/proxy/backends/%g.json
</IfModule>
In order to support FTP over SSL/TLS (FTPS) connections from clients
when reverse proxying, simply include your normal mod_tls
configuration with the same <VirtualHost>
configuration
with your mod_proxy
configuration.
For FTPS support to the backend servers, your reverse proxy
configuration would look something like this:
<IfModule mod_proxy.c>
ProxyEngine on
ProxyLog /path/to/proxy.log
ProxyTables /var/ftp/proxy
ProxyRole reverse
ProxyReverseConnectPolicy RoundRobin
ProxyReverseServers ftp://ftp-backend1.example.com:2121 ftp://ftp-backend2.example.com:2121 ...
# Use FTPS when supported/available by the backend server
ProxyTLSEngine auto
# List of trusted root CAs
ProxyTLSCACertificateFile /etc/ftpd/cacerts.pem
</IfModule>
In fact, mod_proxy
comes with a default
ProxyTLSCACertificateFile
(comprised of the root CAs that most
browsers use/trust), and the default ProxyTLSEngine
value is auto. This means that, by default, mod_proxy
will try to use FTPS for backend connections automatically (assuming that
ProFTPD is built with OpenSSL support using the --enable-openssl
configure option).
Load Balancing versus Session Stickiness
For reverse proxy configurations, there is a choice between
load balancing and sticky session
ProxyReverseConnectPolicy
parameters; these parameters determine
the selection of the backend server that will handle the incoming connection.
Which should you use, and why?
All of the balancing policies are able to select the backend server
when the FTP client connects to the proxy, before sending any commands.
Most of the "sticky" policies, on the other hand, require more knowledge about
the user (e.g. USER
name, HOST
name, SSL
session ID) before the backend server can be determined, thus backend
server selection is delayed until that information is obtained.
Balancing is best when all of your backend severs are identical with
regard to the content they have, and when it does not matter which
server handles a particular client. Maybe all of your backend servers use a
shared filesystem via NFS or similar, thus directory listings will be the same
for a user no matter which backend server is used, and uploading files to one
server means that those files can be downloaded/seen by the other servers.
Balancing policies are also best when all of your backend servers have similar
processing power (memory, CPU, network, disk), so that all backend servers
are equally capable of providing the same service to the connecting client.
The balancing policies are:
LeastConns
Random
RoundRobin
Shuffle
Stickiness is best when your backend servers are not identical,
and some users/clients should only ever go to the same set of backend
servers. Thus the user/client needs to be "sticky" to a given backend
server.
The sticky policies are:
Implicit FTPS Support
The mod_proxy
module includes support for using implicit FTPS with backend servers,
both when forward and reverse proxying.
In order to use implicit FTPS for a reverse proxy server, the URI syntax
must be used in a ProxyReverseServers
directive; the scheme
must be "ftps" and the port must be explicitly specified as 990,
thus:
ProxyReverseServers ftps://ftp.example.com:990
When forward proxying, the client must request the destination server and
specify a port of 990, e.g.:
USER user@ftp.example.com:990
SFTP/SCP Support
The mod_proxy
module only works for FTP/FTPS sessions; it does
not currently support/handle SFTP/SCP sessions.
Logging
The mod_proxy
module supports different forms of logging. The
main module logging is done via the
ProxyLog
directive. For debugging
purposes, the module also uses trace logging, via the module-specific channels:
- proxy
- proxy.conn
- proxy.db
- proxy.forward
- proxy.ftp.conn
- proxy.ftp.ctrl
- proxy.ftp.data
- proxy.ftp.dirlist
- proxy.ftp.msg
- proxy.ftp.sess
- proxy.ftp.xfer
- proxy.inet
- proxy.netio
- proxy.random
- proxy.reverse
- proxy.reverse.db
- proxy.reverse.redis
- proxy.session
- proxy.tls
- proxy.tls.db
- proxy.tls.redis
- proxy.uri
Thus for trace logging, to aid in debugging, you would use the following in
your proftpd.conf
:
TraceLog /path/to/proxy-trace.log
Trace proxy:20
This trace logging can generate large files; it is intended for debugging
use only, and should be removed from any production configuration.
Logging Notes
The following is a list of notes, logging variables that can be used in
custom LogFormats
and/or custom SQL statements:
%{note.mod_proxy.backend-ip}
: IP address of the backend/proxied server
%{note.mod_proxy.backend-port}
: Port of the backend/proxied server
%{note.mod_proxy.backend-url}
: URL to the backend/proxied server
Suggested Future Features
The following lists the features I hope to add to mod_proxy
,
according to need, demand, inclination, and time:
MODE Z
support
- SFTP/SCP support
See the GitHub issues page for current bugs and feature requests, and to report issues.
Frequently Asked Questions
Question: I have heard a lot about both "round robin"
and "least conns" for load balancing. Which is better for FTP connections?
Answer: There is not an easy answer to this, because
it really comes down to the type of traffic that your FTP servers will see.
If your FTP sessions tend to be long-lived (e.g. on the
order of minutes to hours), then using ProxyReverseConnectPolicy
LeastConns
will tend to provide the best distribution of those sessions
across your pool of backend servers. The assumption here is that new
connections arrive infrequently relative to the number of existing
connections.
On the other hand, if your FTP sessions tend to be shorter
(e.g. minutes at most), then using ProxyReverseConnectPolicy
RoundRobin
might provide a more even distribution of connections
across your pool of backend servers.
Question: I am using:
ProxyReverseConnectPolicy PerHost
and would like to configure different pools of backend servers for different
incoming clients. How do I do this?
Answer: The best way to achieve this would be
to use classes
and mod_ifsession
's <IfClass>
sections. For
example:
<Class proxied-clients>
</Class>
ProxyRole reverse
ProxyReverseConnectPolicy PerHost
<IfClass proxied-clients>
ProxyReverseServers ftp://ftp-special1.example.com:2121 ftp://ftp-special2.example.com:2121 ...
</IfClass>
# Don't forget to configure the backend server pool for clients coming
# from other networks!
<IfClass !proxied-clients>
ProxyReverseServers ftp://ftp-backend1.example.com:2121 ftp://ftp-backend2.example.com:2121 ...
</IfClass>
Question: Does mod_proxy
support SSL/TLS
connections, i.e. FTPS?
Answer: Short answer: yes.
The long answer is the mod_proxy
supports FTPS connections
both on the frontend, from connecting clients, and on
the backend, to backend servers. This means that all of the following
flows are supported:
client --- FTPS ---> proxy --- FTP ---> server
client --- FTP ---> proxy --- FTPS ---> server
client --- FTPS ---> proxy --- FTPS ---> server
Thus mod_proxy
's FTPS support is suited for reverse proxy
configurations, where mod_proxy
can be used to provide SSL/TLS
capabilities to old/legacy FTP servers which do not implement it. The
mod_proxy
module is also suited for forward proxy
configurations, where the FTPS support can be used to provide SSL/TLS
capabilities to old/legacy FTP clients which do not implement it.
Question: I want to use mod_proxy
for
reverse proxying. I want to centralize all of my user authentication in
mod_proxy
, and I want to use different user
credentials when logging in to the backend servers. Can mod_proxy
do all of this?
Answer: Yes.
There are a couple of key parts of your mod_proxy
configuration
to pay attention to, for achieving the above.
<IfModule mod_proxy.c>
ProxyEngine on
ProxyLog /path/to/proxy.log
ProxyTables /var/ftp/proxy
ProxyRole reverse
# Make sure to authenticate in the proxy itself
ProxyOptions UseReverseProxyAuth
ProxyReverseConnectPolicy ...
# Include the username/passwords to use for the backend servers
# in the URLs.
ProxyReverseServers ftp://user1:password1@ftp-backend1.example.com:2121 ftp://user2:password2@ftp-backend2.example.com:2121 ...
</IfModule>
When a URL uses the "username:password" syntax for including the credentials
to use for that connection, mod_proxy
will use those URI
credentials when logging in to that backend server.
Question: I have configured mod_proxy
to
block the LIST
command for one group of users, like so:
<Limit LIST>
DenyGroup somegroup
</Limit>
But this <Limit>
is not working. Is this a bug?
Answer: No, it is not a bug. It is, unfortunately,
expected behavior.
The <Limit>
mechanism works on the authenticated
user/group names. And in many cases, it is not mod_proxy
which authenticates the user, it is the backend server. Thus it is the
backend server which knows the groups to which the authenticated user belongs;
mod_proxy
only knows that the USER
name was
successfully authenticated by the backend user. Thus group-based
limits cannot be honored.
However, if proxy auth is enabled, then group-based limits will
work. This means using either the following when forward proxying:
ProxyRole forward
# Either of these two methods result in proxy auth
ProxyForwardMethod proxyuser,user@host
ProxyForwardMethod proxyuser@host,user
or this, when reverse proxying:
ProxyRole reverse
ProxyOptions UseReverseProxyAuth
Question: Can mod_proxy
be configured
as a reverse proxy, and to select the backend server based on the client
certificate used by the frontend FTPS client?
Answer: Yes, but it requires the use of a custom SQL
query.
The idea here is to define a SQL query which looks up the backend server to
use, based on information in the frontend FTPS client certificate. Since the
mod_proxy
module already uses SQLite, you should
be able to use the mod_sql_sqlite
module if needed. The SQL
table schema might look like:
CREATE TABLE proxy_backends (
common_name TEXT PRIMARY KEY,
url TEXT
);
<IfModule mod_tls.c>
...
# Tell mod_tls to export environment variables containing various
# certificate fields, for use by e.g. mod_sql.
TLSOptions StdEnvVars
...
</IfModule>
<IfModule mod_sql.c>
...
# Use the TLS_CLIENT_S_DN_CN environment variable (for the CommonName of
# the Subject section of the frontend FTPS client certificate) provided
# by mod_tls in our selection.
SQLNamedQuery get-user-servers SELECT "url FROM proxy_backends WHERE common_name = '%{env:TLS_CLIENT_S_DN_CN}'"
...
</IfModule>
<IfModule mod_proxy.c>
...
ProxyRole reverse
ProxyReverseConnectPolicy PerUser
# Use a named SQL query to lookup the backend server to use. Note that
# the name used here is the name of our SQLNamedQuery defined above.
ProxyReverseServers sql:/get-user-servers
...
</IfModule>
Note that the mod_tls
module provides many other environment
variables for other fields of the certificate; using a field other than
CommonName is also quite doable, depending on your needs.
To install mod_proxy
, go to the third-party module area in
the proftpd source code and unpack the mod_proxy
source tarball:
$ cd proftpd-dir/contrib/
$ tar zxvf /path/to/mod_proxy-version.tar.gz
after unpacking the latest proftpd-1.3.x source code. For including
mod_proxy
as a statically linked module:
$ ./configure --with-modules=mod_proxy:...
To build mod_proxy
as a DSO module:
$ ./configure --enable-dso --with-shared=mod_proxy:...
Then follow the usual steps:
$ make
$ make install
Note: mod_proxy
uses the
SQLite
library; thus the
sqlite3
development library/headers must be installed for
building mod_proxy
.
It is highly recommended that SQLite 3.8.5 or later be used. Problems
have been reported with mod_proxy
when SQLite 3.6.20 is used;
these problems disappeared once SQLite was upgraded to a newer version.
© Copyright 2015-2020 TJ Saunders
All Rights Reserved
proftpd-mod_proxy-0.8/t/ 0000775 0000000 0000000 00000000000 14020740307 0015315 5 ustar 00root root 0000000 0000000 proftpd-mod_proxy-0.8/t/Makefile.in 0000664 0000000 0000000 00000005516 14020740307 0017371 0 ustar 00root root 0000000 0000000 CC=@CC@
@SET_MAKE@
top_builddir=../../..
top_srcdir=../../..
module_srcdir=..
srcdir=@srcdir@
VPATH=@srcdir@
include $(top_srcdir)/Make.rules
# Necessary redefinitions
INCLUDES=-I. -I.. -I$(module_srcdir)/include -I../../.. -I../../../include @INCLUDES@
CPPFLAGS= $(ADDL_CPPFLAGS) -DHAVE_CONFIG_H $(DEFAULT_PATHS) $(PLATFORM) $(INCLUDES)
LDFLAGS=-L$(top_srcdir)/lib @LIBDIRS@
EXEEXT=@EXEEXT@
TEST_API_DEPS=\
$(top_srcdir)/src/pool.o \
$(top_srcdir)/src/privs.o \
$(top_srcdir)/src/str.o \
$(top_srcdir)/src/sets.o \
$(top_srcdir)/src/table.o \
$(top_srcdir)/src/event.o \
$(top_srcdir)/src/timers.o \
$(top_srcdir)/src/stash.o \
$(top_srcdir)/src/modules.o \
$(top_srcdir)/src/cmd.o \
$(top_srcdir)/src/configdb.o \
$(top_srcdir)/src/parser.o \
$(top_srcdir)/src/regexp.o \
$(top_srcdir)/src/fsio.o \
$(top_srcdir)/src/netio.o \
$(top_srcdir)/src/inet.o \
$(top_srcdir)/src/netaddr.o \
$(top_srcdir)/src/response.o \
$(top_srcdir)/src/auth.o \
$(top_srcdir)/src/env.o \
$(top_srcdir)/src/trace.o \
$(top_srcdir)/src/support.o \
$(top_srcdir)/src/json.o \
$(top_srcdir)/src/redis.o \
$(top_srcdir)/src/error.o \
$(module_srcdir)/lib/proxy/random.o \
$(module_srcdir)/lib/proxy/db.o \
$(module_srcdir)/lib/proxy/dns.o \
$(module_srcdir)/lib/proxy/uri.o \
$(module_srcdir)/lib/proxy/conn.o \
$(module_srcdir)/lib/proxy/netio.o \
$(module_srcdir)/lib/proxy/inet.o \
$(module_srcdir)/lib/proxy/str.o \
$(module_srcdir)/lib/proxy/tls.o \
$(module_srcdir)/lib/proxy/tls/db.o \
$(module_srcdir)/lib/proxy/tls/redis.o \
$(module_srcdir)/lib/proxy/session.o \
$(module_srcdir)/lib/proxy/reverse.o \
$(module_srcdir)/lib/proxy/reverse/db.o \
$(module_srcdir)/lib/proxy/reverse/redis.o \
$(module_srcdir)/lib/proxy/forward.o \
$(module_srcdir)/lib/proxy/ftp/conn.o \
$(module_srcdir)/lib/proxy/ftp/ctrl.o \
$(module_srcdir)/lib/proxy/ftp/data.o \
$(module_srcdir)/lib/proxy/ftp/dirlist.o \
$(module_srcdir)/lib/proxy/ftp/facts.o \
$(module_srcdir)/lib/proxy/ftp/msg.o \
$(module_srcdir)/lib/proxy/ftp/sess.o \
$(module_srcdir)/lib/proxy/ftp/xfer.o
TEST_API_LIBS="-lcheck -lm @MODULE_LIBS@"
TEST_API_OBJS=\
api/random.o \
api/db.o \
api/dns.o \
api/uri.o \
api/conn.o \
api/netio.o \
api/inet.o \
api/str.o \
api/tls.o \
api/reverse.o \
api/forward.o \
api/session.o \
api/ftp/msg.o \
api/ftp/conn.o \
api/ftp/ctrl.o \
api/ftp/data.o \
api/ftp/dirlist.o \
api/ftp/facts.o \
api/ftp/sess.o \
api/ftp/xfer.o \
api/stubs.o \
api/tests.o
dummy:
api/.c.o:
$(CC) $(CPPFLAGS) $(CFLAGS) -c $<
api-tests$(EXEEXT): $(TEST_API_OBJS) $(TEST_API_DEPS)
$(LIBTOOL) --mode=link --tag=CC $(CC) $(LDFLAGS) -o $@ $(TEST_API_DEPS) $(TEST_API_OBJS) $(TEST_API_LIBS) $(LIBS)
./$@
clean:
$(LIBTOOL) --mode=clean $(RM) *.o api/*.o api/*/*.o api-tests$(EXEEXT) api-tests.log
proftpd-mod_proxy-0.8/t/api/ 0000775 0000000 0000000 00000000000 14020740307 0016066 5 ustar 00root root 0000000 0000000 proftpd-mod_proxy-0.8/t/api/conn.c 0000664 0000000 0000000 00000065002 14020740307 0017172 0 ustar 00root root 0000000 0000000 /*
* ProFTPD - mod_proxy testsuite
* Copyright (c) 2013-2020 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
*
* As a special exemption, TJ Saunders and other respective copyright holders
* give permission to link this program with OpenSSL, and distribute the
* resulting executable, without including the source code for OpenSSL in the
* source distribution.
*/
/* Conn API tests */
#include "tests.h"
static pool *p = NULL;
static void set_up(void) {
if (p == NULL) {
p = permanent_pool = make_sub_pool(NULL);
session.c = NULL;
session.notes = NULL;
}
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("proxy.conn", 1, 20);
}
}
static void tear_down(void) {
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("proxy.conn", 0, 0);
}
if (p) {
destroy_pool(p);
p = permanent_pool = NULL;
session.c = NULL;
session.notes = NULL;
}
}
START_TEST (conn_create_test) {
const struct proxy_conn *pconn;
const char *url;
pconn = proxy_conn_create(NULL, NULL, 0);
fail_unless(pconn == NULL, "Failed to handle null arguments");
fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
mark_point();
url = "ftp://127.0.0.1:21";
pconn = proxy_conn_create(NULL, url, 0);
fail_unless(pconn == NULL, "Failed to handle null pool argument");
fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
mark_point();
pconn = proxy_conn_create(p, NULL, 0);
fail_unless(pconn == NULL, "Failed to handle null URL argument");
fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
/* We're already testing URL parsing elsewhere, so we only need to
* supply well-formed URLs in these tests.
*/
mark_point();
url = "http://127.0.0.1:80";
pconn = proxy_conn_create(p, url, 0);
fail_unless(pconn == NULL, "Failed to handle unsupported protocol/scheme");
fail_unless(errno == EPERM, "Failed to set errno to EPERM");
mark_point();
url = "ftp://foo.bar.baz";
pconn = proxy_conn_create(p, url, 0);
fail_unless(pconn == NULL, "Failed to handle unresolvable host");
fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
mark_point();
url = "ftp://127.0.0.1:21";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
proxy_conn_free(pconn);
}
END_TEST
START_TEST (conn_get_addr_test) {
const struct proxy_conn *pconn;
const char *ipstr, *url;
const pr_netaddr_t *pconn_addr;
array_header *other_addrs = NULL;
pconn_addr = proxy_conn_get_addr(NULL, NULL);
fail_unless(pconn_addr == NULL, "Failed to handle null argument");
fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
url = "ftp://127.0.0.1:21";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
pconn_addr = proxy_conn_get_addr(pconn, &other_addrs);
fail_if(pconn_addr == NULL, "Failed to get address for pconn");
ipstr = pr_netaddr_get_ipstr(pconn_addr);
fail_unless(strcmp(ipstr, "127.0.0.1") == 0,
"Expected IP address '127.0.0.1', got '%s'", ipstr);
proxy_conn_free(pconn);
}
END_TEST
START_TEST (conn_get_host_test) {
const char *host, *url, *expected;
const struct proxy_conn *pconn;
host = proxy_conn_get_host(NULL);
fail_unless(host == NULL, "Got host from null pconn unexpectedly");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
url = "ftp://127.0.0.1:21";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
host = proxy_conn_get_host(pconn);
fail_unless(host != NULL, "Failed to get host from conn: %s",
strerror(errno));
expected = "127.0.0.1";
fail_unless(strcmp(host, expected) == 0, "Expected host '%s', got '%s'",
expected, host);
proxy_conn_free(pconn);
}
END_TEST
START_TEST (conn_get_port_test) {
int port;
const char *url;
const struct proxy_conn *pconn;
port = proxy_conn_get_port(NULL);
fail_unless(port < 0, "Got port from null pconn unexpectedly");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
url = "ftp://127.0.0.1:21";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
port = proxy_conn_get_port(pconn);
fail_unless(port == 21, "Expected port 21, got %d", port);
proxy_conn_free(pconn);
}
END_TEST
START_TEST (conn_get_hostport_test) {
const struct proxy_conn *pconn;
const char *hostport, *url;
hostport = proxy_conn_get_hostport(NULL);
fail_unless(hostport == NULL, "Failed to handle null argument");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
url = "ftp://127.0.0.1:21";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
hostport = proxy_conn_get_hostport(pconn);
fail_if(hostport == NULL, "Failed to get host/port for pconn");
fail_unless(strcmp(hostport, "127.0.0.1:21") == 0,
"Expected host/port '127.0.0.1:21', got '%s'", hostport);
/* Implicit/assumed ports */
proxy_conn_free(pconn);
url = "ftp://127.0.0.1";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
hostport = proxy_conn_get_hostport(pconn);
fail_if(hostport == NULL, "Failed to get host/port for pconn");
fail_unless(strcmp(hostport, "127.0.0.1:21") == 0,
"Expected host/port '127.0.0.1:21', got '%s'", hostport);
proxy_conn_free(pconn);
}
END_TEST
START_TEST (conn_get_uri_test) {
const struct proxy_conn *pconn;
const char *pconn_url, *url;
pconn_url = proxy_conn_get_uri(NULL);
fail_unless(pconn_url == NULL, "Failed to handle null argument");
fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
url = "ftp://127.0.0.1:21";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
pconn_url = proxy_conn_get_uri(pconn);
fail_if(pconn_url == NULL, "Failed to get URL for pconn");
fail_unless(strcmp(pconn_url, url) == 0,
"Expected URL '%s', got '%s'", url, pconn_url);
proxy_conn_free(pconn);
}
END_TEST
START_TEST (conn_get_username_test) {
const char *username, *url, *expected;
const struct proxy_conn *pconn;
username = proxy_conn_get_username(NULL);
fail_unless(username == NULL, "Got username from null pconn unexpectedly");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
url = "ftp://127.0.0.1:21";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
username = proxy_conn_get_username(pconn);
fail_unless(username == NULL, "Got username unexpectedly");
proxy_conn_free(pconn);
url = "ftp://user:passwd@127.0.0.1:2121";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
username = proxy_conn_get_username(pconn);
fail_unless(username != NULL, "Expected username from conn");
expected = "user";
fail_unless(strcmp(username, expected) == 0,
"Expected username '%s', got '%s'", expected, username);
proxy_conn_free(pconn);
}
END_TEST
START_TEST (conn_get_password_test) {
const char *passwd, *url, *expected;
const struct proxy_conn *pconn;
passwd = proxy_conn_get_password(NULL);
fail_unless(passwd == NULL, "Got password from null pconn unexpectedly");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
url = "ftp://127.0.0.1:21";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
passwd = proxy_conn_get_password(pconn);
fail_unless(passwd == NULL, "Got password unexpectedly");
proxy_conn_free(pconn);
url = "ftp://user:passwd@127.0.0.1:2121";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
passwd = proxy_conn_get_password(pconn);
fail_unless(passwd != NULL, "Expected password from conn");
expected = "passwd";
fail_unless(strcmp(passwd, expected) == 0,
"Expected password '%s', got '%s'", expected, passwd);
proxy_conn_free(pconn);
url = "ftp://user:@127.0.0.1:2121";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
passwd = proxy_conn_get_password(pconn);
fail_unless(passwd != NULL, "Expected password from conn");
expected = "";
fail_unless(strcmp(passwd, expected) == 0,
"Expected password '%s', got '%s'", expected, passwd);
proxy_conn_free(pconn);
}
END_TEST
START_TEST (conn_get_tls_test) {
int tls;
const char *url;
const struct proxy_conn *pconn;
mark_point();
tls = proxy_conn_get_tls(NULL);
fail_unless(tls < 0, "Got TLS from null pconn unexpectedly");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
mark_point();
url = "ftp://127.0.0.1:21";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
mark_point();
tls = proxy_conn_get_tls(pconn);
fail_unless(tls == PROXY_TLS_ENGINE_AUTO, "Expected TLS auto, got %d", tls);
proxy_conn_free(pconn);
mark_point();
url = "ftp+srv://127.0.0.1:21";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
mark_point();
tls = proxy_conn_get_tls(pconn);
fail_unless(tls == PROXY_TLS_ENGINE_AUTO, "Expected TLS auto, got %d", tls);
proxy_conn_free(pconn);
mark_point();
url = "ftp+txt://127.0.0.1:21";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
mark_point();
tls = proxy_conn_get_tls(pconn);
fail_unless(tls == PROXY_TLS_ENGINE_AUTO, "Expected TLS auto, got %d", tls);
proxy_conn_free(pconn);
mark_point();
url = "ftps://127.0.0.1:21";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
tls = proxy_conn_get_tls(pconn);
fail_unless(tls == PROXY_TLS_ENGINE_ON, "Expected TLS on, got %d", tls);
proxy_conn_free(pconn);
mark_point();
url = "ftps+srv://127.0.0.1:21";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
tls = proxy_conn_get_tls(pconn);
fail_unless(tls == PROXY_TLS_ENGINE_ON, "Expected TLS on, got %d", tls);
proxy_conn_free(pconn);
mark_point();
url = "ftps+txt://127.0.0.1:21";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
tls = proxy_conn_get_tls(pconn);
fail_unless(tls == PROXY_TLS_ENGINE_ON, "Expected TLS on, got %d", tls);
proxy_conn_free(pconn);
mark_point();
url = "ftps://127.0.0.1:990";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
tls = proxy_conn_get_tls(pconn);
fail_unless(tls == PROXY_TLS_ENGINE_IMPLICIT,
"Expected TLS implicit, got %d", tls);
proxy_conn_free(pconn);
mark_point();
url = "ftps+srv://127.0.0.1:990";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
tls = proxy_conn_get_tls(pconn);
fail_unless(tls == PROXY_TLS_ENGINE_ON, "Expected TLS on, got %d", tls);
proxy_conn_free(pconn);
mark_point();
url = "ftps+txt://127.0.0.1:990";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
tls = proxy_conn_get_tls(pconn);
fail_unless(tls == PROXY_TLS_ENGINE_ON, "Expected TLS on, got %d", tls);
proxy_conn_free(pconn);
}
END_TEST
START_TEST (conn_use_dns_srv_test) {
int use_dns_srv;
const char *url;
const struct proxy_conn *pconn;
mark_point();
use_dns_srv = proxy_conn_use_dns_srv(NULL);
fail_unless(use_dns_srv < 0, "Got DNS SRV from null pconn unexpectedly");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
mark_point();
url = "ftp://127.0.0.1:21";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
mark_point();
use_dns_srv = proxy_conn_use_dns_srv(pconn);
fail_unless(use_dns_srv == FALSE, "Expected DNS SRV = false, got %d",
use_dns_srv);
proxy_conn_free(pconn);
mark_point();
url = "ftp+srv://127.0.0.1:21";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
mark_point();
use_dns_srv = proxy_conn_use_dns_srv(pconn);
fail_unless(use_dns_srv == TRUE, "Expected DNS SRV = true, got %d",
use_dns_srv);
proxy_conn_free(pconn);
mark_point();
url = "ftps://127.0.0.1:21";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
use_dns_srv = proxy_conn_use_dns_srv(pconn);
fail_unless(use_dns_srv == FALSE, "Expected DNS SRV = false, got %d",
use_dns_srv);
proxy_conn_free(pconn);
mark_point();
url = "ftps+srv://127.0.0.1:21";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
use_dns_srv = proxy_conn_use_dns_srv(pconn);
fail_unless(use_dns_srv == TRUE, "Expected DNS SRV = true, got %d",
use_dns_srv);
proxy_conn_free(pconn);
}
END_TEST
START_TEST (conn_use_dns_txt_test) {
int use_dns_txt;
const char *url;
const struct proxy_conn *pconn;
mark_point();
use_dns_txt = proxy_conn_use_dns_txt(NULL);
fail_unless(use_dns_txt < 0, "Got DNS TXT from null pconn unexpectedly");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
mark_point();
url = "ftp://127.0.0.1:21";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
mark_point();
use_dns_txt = proxy_conn_use_dns_txt(pconn);
fail_unless(use_dns_txt == FALSE, "Expected DNS TXT = false, got %d",
use_dns_txt);
proxy_conn_free(pconn);
mark_point();
url = "ftp+txt://127.0.0.1:21";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
mark_point();
use_dns_txt = proxy_conn_use_dns_txt(pconn);
fail_unless(use_dns_txt == TRUE, "Expected DNS TXT = true, got %d",
use_dns_txt);
proxy_conn_free(pconn);
mark_point();
url = "ftps://127.0.0.1:21";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
use_dns_txt = proxy_conn_use_dns_txt(pconn);
fail_unless(use_dns_txt == FALSE, "Expected DNS TXT = false, got %d",
use_dns_txt);
proxy_conn_free(pconn);
mark_point();
url = "ftps+txt://127.0.0.1:21";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
use_dns_txt = proxy_conn_use_dns_txt(pconn);
fail_unless(use_dns_txt == TRUE, "Expected DNS TXT = true, got %d",
use_dns_txt);
proxy_conn_free(pconn);
}
END_TEST
START_TEST (conn_get_dns_ttl_test) {
int res;
const char *url;
const struct proxy_conn *pconn;
mark_point();
res = proxy_conn_get_dns_ttl(NULL);
fail_unless(res < 0, "Failed to handle null argument");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
mark_point();
url = "ftp://www.google.com";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
res = proxy_conn_get_dns_ttl(pconn);
fail_unless(res < 0, "Failed to handle non-TTL URL");
fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
strerror(errno), errno);
proxy_conn_free(pconn);
mark_point();
url = "ftp+srv://127.0.0.1";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
res = proxy_conn_get_dns_ttl(pconn);
fail_unless(res < 0, "Failed to handle SRV URL");
fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
strerror(errno), errno);
proxy_conn_free(pconn);
url = "ftps+txt://127.0.0.1:21";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
res = proxy_conn_get_dns_ttl(pconn);
fail_unless(res < 0, "Failed to handle TXT URL");
fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
strerror(errno), errno);
proxy_conn_free(pconn);
}
END_TEST
START_TEST (conn_get_server_conn_test) {
/* XXX TODO */
}
END_TEST
START_TEST (conn_clear_username_test) {
const char *username, *url, *expected;
const struct proxy_conn *pconn;
mark_point();
proxy_conn_clear_username(NULL);
url = "ftp://127.0.0.1:21";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
username = proxy_conn_get_username(pconn);
fail_unless(username == NULL, "Got username unexpectedly");
mark_point();
proxy_conn_clear_username(pconn);
proxy_conn_free(pconn);
url = "ftp://user:passwd@127.0.0.1:2121";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
username = proxy_conn_get_username(pconn);
fail_unless(username != NULL, "Expected username from conn");
expected = "user";
fail_unless(strcmp(username, expected) == 0,
"Expected username '%s', got '%s'", expected, username);
mark_point();
proxy_conn_clear_username(pconn);
username = proxy_conn_get_username(pconn);
fail_unless(username == NULL, "Expected null username, got '%s'", username);
proxy_conn_free(pconn);
}
END_TEST
START_TEST (conn_clear_password_test) {
const char *passwd, *url, *expected;
const struct proxy_conn *pconn;
mark_point();
proxy_conn_clear_password(NULL);
url = "ftp://127.0.0.1:21";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
passwd = proxy_conn_get_password(pconn);
fail_unless(passwd == NULL, "Got password unexpectedly");
mark_point();
proxy_conn_clear_password(pconn);
proxy_conn_free(pconn);
url = "ftp://user:passwd@127.0.0.1:2121";
pconn = proxy_conn_create(p, url, 0);
fail_if(pconn == NULL, "Failed to create pconn for URL '%s' as expected",
url);
passwd = proxy_conn_get_password(pconn);
fail_unless(passwd != NULL, "Expected password from conn");
expected = "passwd";
fail_unless(strcmp(passwd, expected) == 0,
"Expected password '%s', got '%s'", expected, passwd);
mark_point();
proxy_conn_clear_password(pconn);
passwd = proxy_conn_get_password(pconn);
fail_unless(passwd == NULL, "Expected null password, got '%s'", passwd);
proxy_conn_free(pconn);
}
END_TEST
START_TEST (conn_timeout_cb_test) {
int res;
struct proxy_session *proxy_sess;
const pr_netaddr_t *addr;
session.notes = pr_table_alloc(p, 0);
proxy_sess = (struct proxy_session *) proxy_session_alloc(p);
fail_unless(proxy_sess != NULL, "Failed to allocate proxy session: %s",
strerror(errno));
pr_table_add(session.notes, "mod_proxy.proxy-session", proxy_sess,
sizeof(struct proxy_session));
addr = pr_netaddr_get_addr(p, "1.2.3.4", NULL);
fail_unless(addr != NULL, "Failed to resolve '1.2.3.4': %s", strerror(errno));
pr_table_add(session.notes, "mod_proxy.proxy-connect-address", addr,
sizeof(pr_netaddr_t));
proxy_sess->connect_timeout = 1;
res = proxy_conn_connect_timeout_cb(0, 0, 0, NULL);
fail_unless(res == 0, "Failed to handle timeout: %s", strerror(errno));
proxy_sess->connect_timeout = 2;
res = proxy_conn_connect_timeout_cb(0, 0, 0, NULL);
fail_unless(res == 0, "Failed to handle timeout: %s", strerror(errno));
session.notes = NULL;
proxy_session_free(p, proxy_sess);
}
END_TEST
START_TEST (conn_send_proxy_v1_test) {
int res;
conn_t *conn;
res = proxy_conn_send_proxy_v1(NULL, NULL);
fail_unless(res < 0, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
res = proxy_conn_send_proxy_v1(p, NULL);
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);
session.c = pr_inet_create_conn(p, -1, NULL, INPORT_ANY, FALSE);
session.c->local_addr = session.c->remote_addr = pr_netaddr_get_addr(p,
"127.0.0.1", FALSE);
mark_point();
res = proxy_conn_send_proxy_v1(p, conn);
fail_unless(res < 0, "Failed to handle invalid conn");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
session.c->local_addr = session.c->remote_addr = pr_netaddr_get_addr(p,
"::1", FALSE);
mark_point();
res = proxy_conn_send_proxy_v1(p, conn);
fail_unless(res < 0, "Failed to handle invalid conn");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
session.c->local_addr = pr_netaddr_get_addr(p, "::1", FALSE);
session.c->remote_addr = pr_netaddr_get_addr(p, "127.0.0.1", FALSE);
mark_point();
res = proxy_conn_send_proxy_v1(p, conn);
fail_unless(res < 0, "Failed to handle invalid conn");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
session.c->remote_addr = pr_netaddr_get_addr(p, "::1", FALSE);
session.c->local_addr = pr_netaddr_get_addr(p, "127.0.0.1", FALSE);
mark_point();
res = proxy_conn_send_proxy_v1(p, conn);
fail_unless(res < 0, "Failed to handle invalid conn");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
conn->remote_addr = pr_netaddr_get_addr(p, "127.0.0.1", FALSE);
mark_point();
res = proxy_conn_send_proxy_v1(p, conn);
fail_unless(res < 0, "Failed to handle invalid conn");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
pr_inet_close(p, conn);
pr_inet_close(p, session.c);
session.c = NULL;
}
END_TEST
START_TEST (conn_send_proxy_v2_test) {
int res;
conn_t *conn;
res = proxy_conn_send_proxy_v2(NULL, NULL);
fail_unless(res < 0, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
res = proxy_conn_send_proxy_v2(p, NULL);
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);
session.c = pr_inet_create_conn(p, -1, NULL, INPORT_ANY, FALSE);
session.c->local_addr = session.c->remote_addr = pr_netaddr_get_addr(p,
"127.0.0.1", FALSE);
mark_point();
res = proxy_conn_send_proxy_v2(p, conn);
fail_unless(res < 0, "Failed to handle invalid conn");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
session.c->local_addr = session.c->remote_addr = pr_netaddr_get_addr(p,
"::1", FALSE);
mark_point();
res = proxy_conn_send_proxy_v2(p, conn);
fail_unless(res < 0, "Failed to handle invalid conn");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
session.c->local_addr = pr_netaddr_get_addr(p, "::1", FALSE);
session.c->remote_addr = pr_netaddr_get_addr(p, "127.0.0.1", FALSE);
mark_point();
res = proxy_conn_send_proxy_v2(p, conn);
fail_unless(res < 0, "Failed to handle invalid conn");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
session.c->remote_addr = pr_netaddr_get_addr(p, "::1", FALSE);
session.c->local_addr = pr_netaddr_get_addr(p, "127.0.0.1", FALSE);
mark_point();
res = proxy_conn_send_proxy_v2(p, conn);
fail_unless(res < 0, "Failed to handle invalid conn");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
conn->remote_addr = pr_netaddr_get_addr(p, "127.0.0.1", FALSE);
mark_point();
res = proxy_conn_send_proxy_v2(p, conn);
fail_unless(res < 0, "Failed to handle invalid conn");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
pr_inet_close(p, conn);
pr_inet_close(p, session.c);
session.c = NULL;
}
END_TEST
Suite *tests_get_conn_suite(void) {
Suite *suite;
TCase *testcase;
suite = suite_create("conn");
testcase = tcase_create("base");
tcase_add_checked_fixture(testcase, set_up, tear_down);
tcase_add_test(testcase, conn_create_test);
tcase_add_test(testcase, conn_get_addr_test);
tcase_add_test(testcase, conn_get_host_test);
tcase_add_test(testcase, conn_get_port_test);
tcase_add_test(testcase, conn_get_hostport_test);
tcase_add_test(testcase, conn_get_uri_test);
tcase_add_test(testcase, conn_get_username_test);
tcase_add_test(testcase, conn_get_password_test);
tcase_add_test(testcase, conn_get_tls_test);
tcase_add_test(testcase, conn_use_dns_srv_test);
tcase_add_test(testcase, conn_use_dns_txt_test);
tcase_add_test(testcase, conn_get_dns_ttl_test);
tcase_add_test(testcase, conn_get_server_conn_test);
tcase_add_test(testcase, conn_clear_username_test);
tcase_add_test(testcase, conn_clear_password_test);
tcase_add_test(testcase, conn_timeout_cb_test);
tcase_add_test(testcase, conn_send_proxy_v1_test);
tcase_add_test(testcase, conn_send_proxy_v2_test);
suite_add_tcase(suite, testcase);
return suite;
}
proftpd-mod_proxy-0.8/t/api/db.c 0000664 0000000 0000000 00000051275 14020740307 0016631 0 ustar 00root root 0000000 0000000 /*
* ProFTPD - mod_proxy testsuite
* Copyright (c) 2015-2017 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
*
* As a special exemption, TJ Saunders and other respective copyright holders
* give permission to link this program with OpenSSL, and distribute the
* resulting executable, without including the source code for OpenSSL in the
* source distribution.
*/
/* Database API tests. */
#include "tests.h"
static pool *p = NULL;
static const char *db_test_table = "/tmp/prt-mod_proxy-db.dat";
static void set_up(void) {
(void) unlink(db_test_table);
if (p == NULL) {
p = permanent_pool = make_sub_pool(NULL);
session.c = NULL;
session.notes = NULL;
}
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("proxy.db", 1, 20);
}
mark_point();
proxy_db_init(p);
}
static void tear_down(void) {
proxy_db_free();
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("proxy.db", 0, 0);
}
if (p) {
destroy_pool(p);
p = permanent_pool = NULL;
session.c = NULL;
session.notes = NULL;
}
(void) unlink(db_test_table);
}
START_TEST (db_close_test) {
int res;
res = proxy_db_close(NULL, NULL);
fail_unless(res < 0, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Failed to set errno to EINVAL, got %s (%d)",
strerror(errno), errno);
res = proxy_db_close(p, NULL);
fail_unless(res < 0, "Failed to handle null dbh");
fail_unless(errno == EINVAL, "Failed to set errno to EINVAL, got %s (%d)",
strerror(errno), errno);
}
END_TEST
START_TEST (db_open_test) {
int res;
const char *table_path, *schema_name;
struct proxy_dbh *dbh;
dbh = proxy_db_open(NULL, NULL, NULL);
fail_unless(dbh == NULL, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Failed to set errno to EINVAL, got %s (%d)",
strerror(errno), errno);
dbh = proxy_db_open(p, NULL, NULL);
fail_unless(dbh == NULL, "Failed to handle null table path");
fail_unless(errno == EINVAL, "Failed to set errno to EINVAL, got %s (%d)",
strerror(errno), errno);
(void) unlink(db_test_table);
table_path = db_test_table;
schema_name = "proxy_test";
dbh = proxy_db_open(p, table_path, NULL);
fail_unless(dbh == NULL, "Failed to handle null schema name");
fail_unless(errno == EINVAL, "Failed to set errno to EINVAL, got %s (%d)",
strerror(errno), errno);
dbh = proxy_db_open(p, table_path, schema_name);
fail_unless(dbh != NULL, "Failed to open table '%s': %s", table_path,
strerror(errno));
res = proxy_db_close(p, dbh);
fail_unless(res == 0, "Failed to close table '%s': %s", table_path,
strerror(errno));
(void) unlink(db_test_table);
}
END_TEST
START_TEST (db_open_with_version_test) {
int res, flags = 0;
struct proxy_dbh *dbh;
const char *table_path, *schema_name;
unsigned int schema_version;
dbh = proxy_db_open_with_version(NULL, NULL, NULL, 0, 0);
fail_unless(dbh == NULL, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Failed to set errno to EINVAL, got %s (%d)",
strerror(errno), errno);
(void) unlink(db_test_table);
table_path = db_test_table;
schema_name = "proxy_test";
schema_version = 0;
mark_point();
dbh = proxy_db_open_with_version(p, table_path, schema_name, schema_version,
flags);
fail_unless(dbh != NULL,
"Failed to open table '%s', schema '%s', version %u: %s", table_path,
schema_name, schema_version, strerror(errno));
res = proxy_db_close(p, dbh);
fail_unless(res == 0, "Failed to close database: %s", strerror(errno));
flags |= PROXY_DB_OPEN_FL_INTEGRITY_CHECK;
mark_point();
dbh = proxy_db_open_with_version(p, table_path, schema_name, schema_version,
flags);
fail_unless(dbh != NULL,
"Failed to open table '%s', schema '%s', version %u: %s", table_path,
schema_name, schema_version, strerror(errno));
res = proxy_db_close(p, dbh);
fail_unless(res == 0, "Failed to close database: %s", strerror(errno));
if (getenv("TRAVIS") == NULL) {
/* Enable the vacuuming for these tests. */
flags |= PROXY_DB_OPEN_FL_VACUUM;
mark_point();
dbh = proxy_db_open_with_version(p, table_path, schema_name, schema_version,
flags);
fail_unless(dbh != NULL,
"Failed to open table '%s', schema '%s', version %u: %s", table_path,
schema_name, schema_version, strerror(errno));
res = proxy_db_close(p, dbh);
fail_unless(res == 0, "Failed to close database: %s", strerror(errno));
flags &= ~PROXY_DB_OPEN_FL_VACUUM;
}
flags &= ~PROXY_DB_OPEN_FL_INTEGRITY_CHECK;
mark_point();
schema_version = 76;
flags |= PROXY_DB_OPEN_FL_SCHEMA_VERSION_CHECK|PROXY_DB_OPEN_FL_ERROR_ON_SCHEMA_VERSION_SKEW;
dbh = proxy_db_open_with_version(p, table_path, schema_name, schema_version,
flags);
fail_unless(dbh == NULL, "Opened table with version skew unexpectedly");
fail_unless(errno == EPERM, "Expected EPERM (%d), got '%s' (%d)", EPERM,
strerror(errno), errno);
mark_point();
flags &= ~PROXY_DB_OPEN_FL_ERROR_ON_SCHEMA_VERSION_SKEW;
dbh = proxy_db_open_with_version(p, table_path, schema_name, schema_version,
flags);
fail_unless(dbh != NULL,
"Failed to open table '%s', schema '%s', version %u: %s", table_path,
schema_name, schema_version, strerror(errno));
res = proxy_db_close(p, dbh);
fail_unless(res == 0, "Failed to close database: %s", strerror(errno));
mark_point();
schema_version = 76;
dbh = proxy_db_open_with_version(p, table_path, schema_name, schema_version,
flags);
fail_unless(dbh != NULL,
"Failed to open table '%s', schema '%s', version %u: %s", table_path,
schema_name, schema_version, strerror(errno));
res = proxy_db_close(p, dbh);
fail_unless(res == 0, "Failed to close databas: %s", strerror(errno));
mark_point();
schema_version = 99;
dbh = proxy_db_open_with_version(p, table_path, schema_name, schema_version,
flags);
fail_unless(dbh != NULL,
"Failed to open table '%s', schema '%s', version %u: %s", table_path,
schema_name, schema_version, strerror(errno));
res = proxy_db_close(p, dbh);
fail_unless(res == 0, "Failed to close database: %s", strerror(errno));
(void) unlink(db_test_table);
}
END_TEST
START_TEST (db_exec_stmt_test) {
int res;
const char *table_path, *schema_name, *stmt, *errstr;
struct proxy_dbh *dbh;
res = proxy_db_exec_stmt(NULL, NULL, NULL, NULL);
fail_unless(res < 0, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
res = proxy_db_exec_stmt(p, NULL, NULL, NULL);
fail_unless(res < 0, "Failed to handle null dbh");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
(void) unlink(db_test_table);
table_path = db_test_table;
schema_name = "proxy_test";
dbh = proxy_db_open(p, table_path, schema_name);
fail_unless(dbh != NULL, "Failed to open table '%s': %s", table_path,
strerror(errno));
res = proxy_db_exec_stmt(p, dbh, NULL, NULL);
fail_unless(res < 0, "Failed to handle null statement");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
stmt = "SELECT COUNT(*) FROM foo;";
errstr = NULL;
res = proxy_db_exec_stmt(p, dbh, stmt, &errstr);
fail_unless(res < 0, "Failed to execute statement '%s'", stmt);
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
res = proxy_db_close(p, dbh);
fail_unless(res == 0, "Failed to close database: %s", strerror(errno));
(void) unlink(db_test_table);
}
END_TEST
static int create_table(pool *stmt_pool, struct proxy_dbh *dbh,
const char *table_name) {
int res;
const char *stmt, *errstr = NULL;
stmt = pstrcat(stmt_pool, "CREATE TABLE ", table_name,
" (id INTEGER, name TEXT);", NULL);
res = proxy_db_exec_stmt(stmt_pool, dbh, stmt, &errstr);
return res;
}
START_TEST (db_prepare_stmt_test) {
int res;
const char *table_path, *schema_name, *stmt;
struct proxy_dbh *dbh;
res = proxy_db_prepare_stmt(NULL, NULL, NULL);
fail_unless(res < 0, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
res = proxy_db_prepare_stmt(p, NULL, NULL);
fail_unless(res < 0, "Failed to handle null dbh");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
(void) unlink(db_test_table);
table_path = db_test_table;
schema_name = "proxy_test";
dbh = proxy_db_open(p, table_path, schema_name);
fail_unless(dbh != NULL, "Failed to open table '%s': %s", table_path,
strerror(errno));
res = proxy_db_prepare_stmt(p, dbh, NULL);
fail_unless(res < 0, "Failed to handle null statement");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
stmt = "foo bar baz?";
res = proxy_db_prepare_stmt(p, dbh, stmt);
fail_unless(res < 0, "Prepared invalid statement '%s' unexpectedly", stmt);
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
res = create_table(p, dbh, "foo");
fail_unless(res == 0, "Failed to create table 'foo': %s", strerror(errno));
stmt = "SELECT COUNT(*) FROM foo;";
res = proxy_db_prepare_stmt(p, dbh, stmt);
fail_unless(res == 0, "Failed to prepare statement '%s': %s", stmt,
strerror(errno));
res = proxy_db_prepare_stmt(p, dbh, stmt);
fail_unless(res == 0, "Failed to prepare statement '%s': %s", stmt,
strerror(errno));
res = create_table(p, dbh, "bar");
fail_unless(res == 0, "Failed to create table 'bar': %s", strerror(errno));
stmt = "SELECT COUNT(*) FROM bar;";
res = proxy_db_prepare_stmt(p, dbh, stmt);
fail_unless(res == 0, "Failed to prepare statement '%s': %s", stmt,
strerror(errno));
res = proxy_db_close(p, dbh);
fail_unless(res == 0, "Failed to close database: %s", strerror(errno));
(void) unlink(db_test_table);
}
END_TEST
START_TEST (db_finish_stmt_test) {
int res;
const char *table_path, *schema_name, *stmt;
struct proxy_dbh *dbh;
res = proxy_db_finish_stmt(NULL, 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);
res = proxy_db_finish_stmt(p, NULL, NULL);
fail_unless(res < 0, "Failed to handle null dbh");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
(void) unlink(db_test_table);
table_path = db_test_table;
schema_name = "proxy_test";
dbh = proxy_db_open(p, table_path, schema_name);
fail_unless(dbh != NULL, "Failed to open table '%s': %s", table_path,
strerror(errno));
res = proxy_db_finish_stmt(p, dbh, NULL);
fail_unless(res < 0, "Failed to handle null statement");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
stmt = "SELECT COUNT(*) FROM foo";
res = proxy_db_finish_stmt(p, dbh, stmt);
fail_unless(res < 0, "Failed to handle unprepared statement");
fail_unless(errno == ENOENT, "Expected ENOENT (%d), got '%s' (%d)", ENOENT,
strerror(errno), errno);
res = create_table(p, dbh, "foo");
fail_unless(res == 0, "Failed to create table 'foo': %s", strerror(errno));
res = proxy_db_prepare_stmt(p, dbh, stmt);
fail_unless(res == 0, "Failed to prepare statement '%s': %s", stmt,
strerror(errno));
res = proxy_db_finish_stmt(p, dbh, stmt);
fail_unless(res == 0, "Failed to finish statement '%s': %s", stmt,
strerror(errno));
res = proxy_db_finish_stmt(p, dbh, stmt);
fail_unless(res < 0, "Failed to handle unprepared statement");
fail_unless(errno == ENOENT, "Expected ENOENT (%d), got '%s' (%d)", ENOENT,
strerror(errno), errno);
res = proxy_db_close(p, dbh);
fail_unless(res == 0, "Failed to close database: %s", strerror(errno));
(void) unlink(db_test_table);
}
END_TEST
START_TEST (db_bind_stmt_test) {
int res;
const char *table_path, *schema_name, *stmt;
struct proxy_dbh *dbh;
int idx, int_val;
long long_val;
char *text_val;
res = proxy_db_bind_stmt(NULL, NULL, NULL, -1, -1, NULL);
fail_unless(res < 0, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
res = proxy_db_bind_stmt(p, NULL, NULL, -1, -1, NULL);
fail_unless(res < 0, "Failed to handle null dbh");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
(void) unlink(db_test_table);
table_path = db_test_table;
schema_name = "proxy_test";
dbh = proxy_db_open(p, table_path, schema_name);
fail_unless(dbh != NULL, "Failed to open table '%s': %s", table_path,
strerror(errno));
res = proxy_db_bind_stmt(p, dbh, NULL, -1, -1, NULL);
fail_unless(res < 0, "Failed to handle null statement");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
stmt = "SELECT COUNT(*) FROM table";
idx = -1;
res = proxy_db_bind_stmt(p, dbh, stmt, idx, PROXY_DB_BIND_TYPE_INT, NULL);
fail_unless(res < 0, "Failed to handle invalid index %d", idx);
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
idx = 1;
res = proxy_db_bind_stmt(p, dbh, stmt, idx, PROXY_DB_BIND_TYPE_INT, NULL);
fail_unless(res < 0, "Failed to handle unprepared statement");
fail_unless(errno == ENOENT, "Expected ENOENT (%d), got '%s' (%d)", ENOENT,
strerror(errno), errno);
res = create_table(p, dbh, "foo");
fail_unless(res == 0, "Failed to create table 'foo': %s", strerror(errno));
stmt = "SELECT COUNT(*) FROM foo;";
res = proxy_db_prepare_stmt(p, dbh, stmt);
fail_unless(res == 0, "Failed to prepare statement '%s': %s", stmt,
strerror(errno));
res = proxy_db_bind_stmt(p, dbh, stmt, idx, PROXY_DB_BIND_TYPE_INT, NULL);
fail_unless(res < 0, "Failed to handle missing INT value");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
int_val = 7;
res = proxy_db_bind_stmt(p, dbh, stmt, idx, PROXY_DB_BIND_TYPE_INT, &int_val);
fail_unless(res < 0, "Failed to handle invalid index value");
fail_unless(errno == EPERM, "Expected EPERM (%d), got '%s' (%d)", EPERM,
strerror(errno), errno);
res = proxy_db_bind_stmt(p, dbh, stmt, idx, PROXY_DB_BIND_TYPE_LONG, NULL);
fail_unless(res < 0, "Failed to handle missing LONG value");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
long_val = 7;
res = proxy_db_bind_stmt(p, dbh, stmt, idx, PROXY_DB_BIND_TYPE_LONG,
&long_val);
fail_unless(res < 0, "Failed to handle invalid index value");
fail_unless(errno == EPERM, "Expected EPERM (%d), got '%s' (%d)", EPERM,
strerror(errno), errno);
res = proxy_db_bind_stmt(p, dbh, stmt, idx, PROXY_DB_BIND_TYPE_TEXT, NULL);
fail_unless(res < 0, "Failed to handle missing TEXT value");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
text_val = "testing";
res = proxy_db_bind_stmt(p, dbh, stmt, idx, PROXY_DB_BIND_TYPE_TEXT,
text_val);
fail_unless(res < 0, "Failed to handle invalid index value");
fail_unless(errno == EPERM, "Expected EPERM (%d), got '%s' (%d)", EPERM,
strerror(errno), errno);
res = proxy_db_bind_stmt(p, dbh, stmt, idx, PROXY_DB_BIND_TYPE_NULL, NULL);
fail_unless(res < 0, "Failed to handle invalid NULL value");
fail_unless(errno == EPERM, "Expected EPERM (%d), got '%s' (%d)", EPERM,
strerror(errno), errno);
stmt = "SELECT COUNT(*) FROM foo WHERE id = ?;";
res = proxy_db_prepare_stmt(p, dbh, stmt);
fail_unless(res == 0, "Failed to prepare statement '%s': %s", stmt,
strerror(errno));
int_val = 7;
res = proxy_db_bind_stmt(p, dbh, stmt, idx, PROXY_DB_BIND_TYPE_INT, &int_val);
fail_unless(res == 0, "Failed to bind INT value: %s", strerror(errno));
res = proxy_db_close(p, dbh);
fail_unless(res == 0, "Failed to close database: %s", strerror(errno));
(void) unlink(db_test_table);
}
END_TEST
START_TEST (db_exec_prepared_stmt_test) {
int res;
array_header *results;
const char *table_path, *schema_name, *stmt, *errstr = NULL;
struct proxy_dbh *dbh;
results = proxy_db_exec_prepared_stmt(NULL, NULL, NULL, NULL);
fail_unless(results == NULL, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
results = proxy_db_exec_prepared_stmt(p, NULL, NULL, NULL);
fail_unless(results == NULL, "Failed to handle null dbh");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
(void) unlink(db_test_table);
table_path = db_test_table;
schema_name = "proxy_test";
dbh = proxy_db_open(p, table_path, schema_name);
fail_unless(dbh != NULL, "Failed to open table '%s': %s", table_path,
strerror(errno));
results = proxy_db_exec_prepared_stmt(p, dbh, NULL, NULL);
fail_unless(results == NULL, "Failed to handle null statement");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
stmt = "SELECT COUNT(*) FROM foo;";
results = proxy_db_exec_prepared_stmt(p, dbh, stmt, &errstr);
fail_unless(results == NULL, "Failed to handle unprepared statement");
fail_unless(errno == ENOENT, "Expected ENOENT (%d), got '%s' (%d)", ENOENT,
strerror(errno), errno);
res = create_table(p, dbh, "foo");
fail_unless(res == 0, "Failed to create table 'foo': %s", strerror(errno));
res = proxy_db_prepare_stmt(p, dbh, stmt);
fail_unless(res == 0, "Failed to prepare statement '%s': %s", stmt,
strerror(errno));
results = proxy_db_exec_prepared_stmt(p, dbh, stmt, &errstr);
fail_unless(results != NULL,
"Failed to execute prepared statement '%s': %s (%s)", stmt, errstr,
strerror(errno));
res = proxy_db_close(p, dbh);
fail_unless(res == 0, "Failed to close database: %s", strerror(errno));
(void) unlink(db_test_table);
}
END_TEST
START_TEST (db_reindex_test) {
int res;
const char *table_path, *schema_name, *index_name, *errstr = NULL;
struct proxy_dbh *dbh;
res = proxy_db_reindex(NULL, NULL, NULL, NULL);
fail_unless(res < 0, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
res = proxy_db_reindex(p, NULL, NULL, NULL);
fail_unless(res < 0, "Failed to handle null dbh");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
(void) unlink(db_test_table);
table_path = db_test_table;
schema_name = "proxy_test";
dbh = proxy_db_open(p, table_path, schema_name);
fail_unless(dbh != NULL, "Failed to open table '%s': %s", table_path,
strerror(errno));
res = proxy_db_reindex(p, dbh, NULL, NULL);
fail_unless(res < 0, "Failed to handle null index name");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
index_name = "test_idx";
res = proxy_db_reindex(p, dbh, index_name, &errstr);
fail_unless(res < 0, "Failed to handle invalid index");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
fail_unless(errstr != NULL, "Failed to provide error string");
res = proxy_db_close(p, dbh);
fail_unless(res == 0, "Failed to close database: %s", strerror(errno));
(void) unlink(db_test_table);
}
END_TEST
Suite *tests_get_db_suite(void) {
Suite *suite;
TCase *testcase;
suite = suite_create("db");
testcase = tcase_create("base");
tcase_add_checked_fixture(testcase, set_up, tear_down);
tcase_add_test(testcase, db_close_test);
tcase_add_test(testcase, db_open_test);
tcase_add_test(testcase, db_open_with_version_test);
tcase_add_test(testcase, db_exec_stmt_test);
tcase_add_test(testcase, db_prepare_stmt_test);
tcase_add_test(testcase, db_finish_stmt_test);
tcase_add_test(testcase, db_bind_stmt_test);
tcase_add_test(testcase, db_exec_prepared_stmt_test);
tcase_add_test(testcase, db_reindex_test);
suite_add_tcase(suite, testcase);
return suite;
}
proftpd-mod_proxy-0.8/t/api/dns.c 0000664 0000000 0000000 00000017444 14020740307 0017030 0 ustar 00root root 0000000 0000000 /*
* ProFTPD - mod_proxy testsuite
* Copyright (c) 2020 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
*
* As a special exemption, TJ Saunders and other respective copyright holders
* give permission to link this program with OpenSSL, and distribute the
* resulting executable, without including the source code for OpenSSL in the
* source distribution.
*/
/* DNS API tests */
#include "tests.h"
static pool *p = NULL;
static void set_up(void) {
if (p == NULL) {
p = permanent_pool = make_sub_pool(NULL);
}
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("proxy.dns", 1, 20);
}
}
static void tear_down(void) {
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("proxy.dns", 0, 0);
}
if (p != NULL) {
destroy_pool(p);
p = permanent_pool = NULL;
}
}
START_TEST (dns_resolve_einval_test) {
int res;
const char *name = NULL;
proxy_dns_type_e dns_type = PROXY_DNS_UNKNOWN;
array_header *resp = NULL;
mark_point();
res = proxy_dns_resolve(NULL, NULL, dns_type, NULL, NULL);
fail_unless(res < 0, "Failed to handle null pool argument");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
mark_point();
res = proxy_dns_resolve(p, NULL, dns_type, NULL, NULL);
fail_unless(res < 0, "Failed to handle null name argument");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
mark_point();
name = "www.google.com";
res = proxy_dns_resolve(p, name, dns_type, NULL, NULL);
fail_unless(res < 0, "Failed to handle null resp argument");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
mark_point();
res = proxy_dns_resolve(p, name, dns_type, &resp, NULL);
fail_unless(res < 0, "Failed to handle UNKNOWN type argument");
fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
strerror(errno), errno);
}
END_TEST
START_TEST (dns_resolve_bad_response_test) {
int res;
const char *name;
proxy_dns_type_e dns_type;
array_header *resp = NULL;
/* SRV */
dns_type = PROXY_DNS_SRV;
mark_point();
name = "foobarbaz";
res = proxy_dns_resolve(p, name, dns_type, &resp, NULL);
fail_unless(res < 0, "Failed to handle no SRV records for '%s'", name);
fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
strerror(errno), errno);
fail_unless(resp == NULL, "Expected null responses");
mark_point();
name = " ";
res = proxy_dns_resolve(p, name, dns_type, &resp, NULL);
fail_unless(res < 0, "Failed to handle no SRV records for '%s'", name);
fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
strerror(errno), errno);
fail_unless(resp == NULL, "Expected null responses");
mark_point();
name = ".";
res = proxy_dns_resolve(p, name, dns_type, &resp, NULL);
fail_unless(res < 0, "Failed to handle no SRV records for '%s'", name);
fail_unless(errno == ENOENT || errno == EPERM,
"Expected EPERM (%d) or ENOENT (%d), got %s (%d)", EPERM, ENOENT,
strerror(errno), errno);
fail_unless(resp == NULL, "Expected null responses");
/* TXT */
dns_type = PROXY_DNS_TXT;
mark_point();
name = "foobarbaz";
res = proxy_dns_resolve(p, name, dns_type, &resp, NULL);
fail_unless(res < 0, "Failed to handle no TXT records for '%s'", name);
fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
strerror(errno), errno);
fail_unless(resp == NULL, "Expected null responses");
mark_point();
name = " ";
res = proxy_dns_resolve(p, name, dns_type, &resp, NULL);
fail_unless(res < 0, "Failed to handle no TXT records for '%s'", name);
fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
strerror(errno), errno);
fail_unless(resp == NULL, "Expected null responses");
mark_point();
name = ".";
res = proxy_dns_resolve(p, name, dns_type, &resp, NULL);
fail_unless(res < 0, "Failed to handle no TXT records for '%s'", name);
fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
strerror(errno), errno);
fail_unless(resp == NULL, "Expected null responses");
mark_point();
name = "+";
res = proxy_dns_resolve(p, name, dns_type, &resp, NULL);
fail_unless(res < 0, "Failed to handle no TXT records for '%s'", name);
fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
strerror(errno), errno);
fail_unless(resp == NULL, "Expected null responses");
}
END_TEST
START_TEST (dns_resolve_type_srv_test) {
int res;
const char *name = NULL;
proxy_dns_type_e dns_type = PROXY_DNS_SRV;
array_header *resp = NULL;
uint32_t ttl = 0;
mark_point();
name = "_ftps._tcp.castaglia.org";
res = proxy_dns_resolve(p, name, dns_type, &resp, &ttl);
fail_unless(res < 0, "Failed to handle no SRV records for '%s'", name);
fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
strerror(errno), errno);
fail_unless(resp == NULL, "Expected null responses");
mark_point();
name = "_imap._tcp.gmail.com";
res = proxy_dns_resolve(p, name, dns_type, &resp, &ttl);
fail_unless(res < 0, "Failed to handle explicit 'no service' for '%s'", name);
fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
strerror(errno), errno);
fail_unless(resp == NULL, "Expected null responses");
mark_point();
name = "_imaps._tcp.gmail.com";
res = proxy_dns_resolve(p, name, dns_type, &resp, &ttl);
fail_unless(res > 0, "Failed to resolve SRV records for '%s': %s", name,
strerror(errno));
fail_unless(resp != NULL, "Expected non-null responses");
mark_point();
name = "_ldap._tcp.ru.ac.za";
res = proxy_dns_resolve(p, name, dns_type, &resp, &ttl);
fail_unless(res > 0, "Failed to resolve SRV records for '%s': %s", name,
strerror(errno));
fail_unless(resp != NULL, "Expected non-null responses");
}
END_TEST
START_TEST (dns_resolve_type_txt_test) {
int res;
const char *name = NULL;
proxy_dns_type_e dns_type = PROXY_DNS_TXT;
array_header *resp = NULL;
uint32_t ttl = 0;
mark_point();
name = "google.com";
res = proxy_dns_resolve(p, name, dns_type, &resp, &ttl);
fail_unless(res > 0, "Failed to resolve TXT records for '%s': %s", name,
strerror(errno));
fail_unless(resp != NULL, "Expected non-null responses");
mark_point();
name = "amazon.com";
res = proxy_dns_resolve(p, name, dns_type, &resp, &ttl);
fail_unless(res > 0, "Failed to resolve TXT records for '%s': %s", name,
strerror(errno));
fail_unless(resp != NULL, "Expected non-null responses");
}
END_TEST
Suite *tests_get_dns_suite(void) {
Suite *suite;
TCase *testcase;
suite = suite_create("dns");
testcase = tcase_create("base");
tcase_add_checked_fixture(testcase, set_up, tear_down);
tcase_add_test(testcase, dns_resolve_einval_test);
tcase_add_test(testcase, dns_resolve_bad_response_test);
tcase_add_test(testcase, dns_resolve_type_srv_test);
tcase_add_test(testcase, dns_resolve_type_txt_test);
/* Allow a longer timeout on these tests, as they depend on external DNS
* latency.
*/
tcase_set_timeout(testcase, 30);
suite_add_tcase(suite, testcase);
return suite;
}
proftpd-mod_proxy-0.8/t/api/forward.c 0000664 0000000 0000000 00000052235 14020740307 0017705 0 ustar 00root root 0000000 0000000 /*
* ProFTPD - mod_proxy testsuite
* Copyright (c) 2016-2017 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
*
* As a special exemption, TJ Saunders and other respective copyright holders
* give permission to link this program with OpenSSL, and distribute the
* resulting executable, without including the source code for OpenSSL in the
* source distribution.
*/
/* Forward-proxy API tests */
#include "tests.h"
extern xaset_t *server_list;
static pool *p = NULL;
static const char *test_dir = "/tmp/mod_proxy-test-forward";
static void create_main_server(void) {
server_rec *s;
s = pr_parser_server_ctxt_open("127.0.0.1");
s->ServerName = "Test Server";
main_server = s;
}
static int create_test_dir(void) {
int res;
mode_t perms;
perms = 0770;
res = mkdir(test_dir, perms);
fail_unless(res == 0, "Failed to create tmp directory '%s': %s", test_dir,
strerror(errno));
res = chmod(test_dir, perms);
fail_unless(res == 0, "Failed to set perms %04o on directory '%s': %s",
perms, test_dir, strerror(errno));
return 0;
}
static void test_cleanup(pool *cleanup_pool) {
(void) tests_rmpath(cleanup_pool, test_dir);
}
static void set_up(void) {
if (p == NULL) {
p = permanent_pool = proxy_pool = session.pool = make_sub_pool(NULL);
server_list = NULL;
session.c = NULL;
session.notes = NULL;
}
test_cleanup(p);
init_config();
init_fs();
init_netaddr();
init_netio();
init_inet();
server_list = xaset_create(p, NULL);
pr_parser_prepare(p, &server_list);
create_main_server();
(void) create_test_dir();
proxy_db_init(p);
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("netio", 1, 20);
pr_trace_set_levels("proxy.db", 1, 20);
pr_trace_set_levels("proxy.forward", 1, 20);
pr_trace_set_levels("proxy.tls", 1, 20);
pr_trace_set_levels("proxy.uri", 1, 20);
pr_trace_set_levels("proxy.ftp.ctrl", 1, 20);
pr_trace_set_levels("proxy.ftp.sess", 1, 20);
}
}
static void tear_down(void) {
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("netio", 0, 0);
pr_trace_set_levels("proxy.db", 0, 0);
pr_trace_set_levels("proxy.forward", 0, 0);
pr_trace_set_levels("proxy.tls", 0, 0);
pr_trace_set_levels("proxy.uri", 0, 0);
pr_trace_set_levels("proxy.ftp.ctrl", 0, 0);
pr_trace_set_levels("proxy.ftp.sess", 0, 0);
}
proxy_db_free();
pr_parser_cleanup();
pr_inet_clear();
test_cleanup(p);
if (p) {
destroy_pool(p);
p = permanent_pool = proxy_pool = session.pool = NULL;
main_server = NULL;
server_list = NULL;
session.c = NULL;
session.notes = NULL;
}
}
START_TEST (forward_free_test) {
int res;
res = proxy_forward_free(NULL);
fail_unless(res == 0, "Failed to free Forward API resources: %s",
strerror(errno));
}
END_TEST
START_TEST (forward_init_test) {
int res;
res = proxy_forward_init(NULL, NULL);
fail_unless(res == 0, "Failed to init Forward API resources: %s",
strerror(errno));
}
END_TEST
START_TEST (forward_sess_free_test) {
int res;
res = proxy_forward_sess_free(NULL, NULL);
fail_unless(res == 0, "Failed to free Forward API session resources: %s",
strerror(errno));
}
END_TEST
START_TEST (forward_sess_init_test) {
int res;
session.c = pr_inet_create_conn(p, -1, NULL, INPORT_ANY, FALSE);
fail_unless(session.c != NULL,
"Failed to open session control conn: %s", strerror(errno));
session.c->local_addr = session.c->remote_addr = pr_netaddr_get_addr(p,
"127.0.0.1", NULL);
fail_unless(session.c->remote_addr != NULL, "Failed to get address: %s",
strerror(errno));
mark_point();
res = proxy_forward_sess_init(p, test_dir, NULL);
fail_unless(res < 0,
"Initialized Forward API session resources unexpectedly");
fail_unless(errno == EPERM, "Expected EPERM (%d), got '%s' (%d)", EPERM,
strerror(errno), errno);
/* Make the connections look like they're from an RFC1918 address. */
session.c->local_addr = session.c->remote_addr = pr_netaddr_get_addr(p,
"192.168.0.1", NULL);
fail_unless(session.c->remote_addr != NULL, "Failed to get address: %s",
strerror(errno));
mark_point();
res = proxy_forward_sess_init(p, test_dir, NULL);
fail_unless(res == 0, "Failed to init Forward API session resources: %s",
strerror(errno));
res = proxy_forward_sess_free(p, NULL);
fail_unless(res == 0, "Failed to free Forward API session resources: %s",
strerror(errno));
}
END_TEST
START_TEST (forward_get_method_test) {
int res;
const char *method;
res = proxy_forward_get_method(NULL);
fail_unless(res < 0, "Failed to handle null argument");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
method = "foo";
res = proxy_forward_get_method(method);
fail_unless(res < 0, "Failed to handle unsupported method '%s'", method);
fail_unless(errno == ENOENT, "Expected ENOENT (%d), got '%s' (%d)", ENOENT,
strerror(errno), errno);
method = "proxyuser,user@host";
res = proxy_forward_get_method(method);
fail_unless(res == PROXY_FORWARD_METHOD_USER_WITH_PROXY_AUTH,
"Failed to handle method '%s'", method);
method = "user@host";
res = proxy_forward_get_method(method);
fail_unless(res == PROXY_FORWARD_METHOD_USER_NO_PROXY_AUTH,
"Failed to handle method '%s'", method);
method = "proxyuser@host,user";
res = proxy_forward_get_method(method);
fail_unless(res == PROXY_FORWARD_METHOD_PROXY_USER_WITH_PROXY_AUTH,
"Failed to handle method '%s'", method);
}
END_TEST
START_TEST (forward_use_proxy_auth_test) {
int res;
res = proxy_forward_use_proxy_auth();
fail_unless(res == TRUE, "Expected true, got %d", res);
}
END_TEST
START_TEST (forward_have_authenticated_test) {
int res;
cmd_rec *cmd = NULL;
res = proxy_forward_have_authenticated(cmd);
fail_unless(res == FALSE, "Expected false, got %d", res);
}
END_TEST
static int forward_sess_init(int method_id) {
session.c = pr_inet_create_conn(p, -1, NULL, INPORT_ANY, FALSE);
if (session.c == NULL) {
return -1;
}
/* Make the connections look like they're from an RFC1918 address. */
session.c->local_addr = session.c->remote_addr = pr_netaddr_get_addr(p,
"192.168.0.1", NULL);
if (session.c->remote_addr == NULL) {
return -1;
}
pr_netaddr_set_port((pr_netaddr_t *) session.c->local_addr, htons(7777));
if (method_id > 0) {
config_rec *c;
c = add_config_param("ProxyForwardMethod", 1, NULL);
c->argv[0] = palloc(c->pool, sizeof(int));
*((int *) c->argv[0]) = method_id;
}
return proxy_forward_sess_init(p, test_dir, NULL);
}
static struct proxy_session *forward_get_proxy_sess(void) {
struct proxy_session *proxy_sess;
proxy_sess = (struct proxy_session *) proxy_session_alloc(p);
proxy_sess->src_addr = pr_netaddr_get_addr(p, "127.0.0.1", NULL);
return proxy_sess;
}
START_TEST (forward_handle_user_noproxyauth_test) {
int res, successful = FALSE, block_responses = FALSE;
cmd_rec *cmd;
struct proxy_session *proxy_sess;
res = forward_sess_init(PROXY_FORWARD_METHOD_USER_NO_PROXY_AUTH);
fail_unless(res == 0, "Failed to init Forward API session resources: %s",
strerror(errno));
proxy_sess = forward_get_proxy_sess();
/* No destination host in USER command. */
cmd = pr_cmd_alloc(p, 2, "USER", "test");
cmd->arg = pstrdup(p, "test");
mark_point();
res = proxy_forward_handle_user(cmd, proxy_sess, &successful,
&block_responses);
fail_unless(res < 0, "Handled USER command unexpectedly");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
/* Invalid host (no port) in USER command. */
cmd = pr_cmd_alloc(p, 2, "USER", "test@host");
cmd->arg = pstrdup(p, "test@host");
mark_point();
res = proxy_forward_handle_user(cmd, proxy_sess, &successful,
&block_responses);
fail_unless(res < 0, "Handled USER command unexpectedly");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
/* Valid host (no port) in USER command. */
cmd = pr_cmd_alloc(p, 2, "USER", "test@127.0.0.1");
cmd->arg = pstrdup(p, "test@127.0.0.1");
mark_point();
res = proxy_forward_handle_user(cmd, proxy_sess, &successful,
&block_responses);
fail_unless(res == 1, "Failed to handle USER command: %s", strerror(errno));
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
cmd = pr_cmd_alloc(p, 2, "USER", "test@192.168.0.1");
cmd->arg = pstrdup(p, "test@192.168.0.1:7777");
mark_point();
res = proxy_forward_handle_user(cmd, proxy_sess, &successful,
&block_responses);
fail_unless(res == 1, "Failed to handle USER command: %s", strerror(errno));
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
/* Destination host (WITH bad port syntax) in USER command. */
cmd = pr_cmd_alloc(p, 2, "USER", "test@host:foo");
cmd->arg = pstrdup(p, "test@host:foo");
mark_point();
res = proxy_forward_handle_user(cmd, proxy_sess, &successful,
&block_responses);
fail_unless(res < 0, "Handled USER command unexpectedly");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
/* Destination host (WITH invalid port) in USER command. */
cmd = pr_cmd_alloc(p, 2, "USER", "test@host:70000");
cmd->arg = pstrdup(p, "test@host:70000");
mark_point();
res = proxy_forward_handle_user(cmd, proxy_sess, &successful,
&block_responses);
fail_unless(res < 0, "Handled USER command unexpectedly");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
/* Destination host (WITH port) in USER command. */
cmd = pr_cmd_alloc(p, 2, "USER", "test@127.0.0.1:2121");
cmd->arg = pstrdup(p, "test@127.0.0.1:2121");
mark_point();
res = proxy_forward_handle_user(cmd, proxy_sess, &successful,
&block_responses);
fail_unless(res == 1, "Failed to handle USER command: %s", strerror(errno));
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
/* Valid external host (with port) in USER command. */
cmd = pr_cmd_alloc(p, 2, "USER", "anonymous@ftp.cisco.com:21");
cmd->arg = pstrdup(p, "anonymous@ftp.cisco.com");
mark_point();
res = proxy_forward_handle_user(cmd, proxy_sess, &successful,
&block_responses);
fail_unless(res == 1, "Failed to handle USER command: %s", strerror(errno));
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
res = proxy_forward_sess_free(p, NULL);
fail_unless(res == 0, "Failed to free Forward API session resources: %s",
strerror(errno));
proxy_session_free(p, proxy_sess);
}
END_TEST
START_TEST (forward_handle_user_userwithproxyauth_test) {
int res, successful = FALSE, block_responses = FALSE;
cmd_rec *cmd;
struct proxy_session *proxy_sess;
res = forward_sess_init(PROXY_FORWARD_METHOD_USER_WITH_PROXY_AUTH);
fail_unless(res == 0, "Failed to init Forward API session resources: %s",
strerror(errno));
proxy_sess = forward_get_proxy_sess();
cmd = pr_cmd_alloc(p, 2, "USER", "test@127.0.0.1");
cmd->arg = pstrdup(p, "test@127.0.0.1");
mark_point();
res = proxy_forward_handle_user(cmd, proxy_sess, &successful,
&block_responses);
fail_unless(res == 0, "Failed to handle USER command: %s", strerror(errno));
fail_unless(block_responses == FALSE, "Expected false, got %d",
block_responses);
proxy_sess_state |= PROXY_SESS_STATE_PROXY_AUTHENTICATED;
mark_point();
res = proxy_forward_handle_user(cmd, proxy_sess, &successful,
&block_responses);
fail_unless(res == 1, "Failed to handle USER command: %s", strerror(errno));
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
proxy_sess_state &= ~PROXY_SESS_STATE_PROXY_AUTHENTICATED;
res = proxy_forward_sess_free(p, NULL);
fail_unless(res == 0, "Failed to free Forward API session resources: %s",
strerror(errno));
proxy_session_free(p, proxy_sess);
}
END_TEST
START_TEST (forward_handle_user_proxyuserwithproxyauth_test) {
int res, successful = FALSE, block_responses = FALSE;
cmd_rec *cmd;
struct proxy_session *proxy_sess;
res = forward_sess_init(PROXY_FORWARD_METHOD_PROXY_USER_WITH_PROXY_AUTH);
fail_unless(res == 0, "Failed to init Forward API session resources: %s",
strerror(errno));
proxy_sess = forward_get_proxy_sess();
cmd = pr_cmd_alloc(p, 2, "USER", "test@127.0.0.1");
cmd->arg = pstrdup(p, "test@127.0.0.1");
mark_point();
res = proxy_forward_handle_user(cmd, proxy_sess, &successful,
&block_responses);
fail_unless(res == 0, "Failed to handle USER command: %s", strerror(errno));
fail_unless(block_responses == FALSE, "Expected false, got %d",
block_responses);
proxy_sess_state |= PROXY_SESS_STATE_PROXY_AUTHENTICATED;
mark_point();
res = proxy_forward_handle_user(cmd, proxy_sess, &successful,
&block_responses);
fail_unless(res == 1, "Failed to handle USER command: %s", strerror(errno));
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
proxy_sess_state &= ~PROXY_SESS_STATE_PROXY_AUTHENTICATED;
res = proxy_forward_sess_free(p, NULL);
fail_unless(res == 0, "Failed to free Forward API session resources: %s",
strerror(errno));
proxy_session_free(p, proxy_sess);
}
END_TEST
START_TEST (forward_handle_pass_noproxyauth_test) {
int res, successful = FALSE, block_responses = FALSE;
cmd_rec *cmd;
#ifdef PR_USE_OPENSSL
config_rec *c;
#endif /* PR_USE_OPENSSL */
struct proxy_session *proxy_sess;
/* Skip this test on travis, for now. It fails unexpectedly. */
if (getenv("TRAVIS_CI") != NULL) {
return;
}
res = forward_sess_init(PROXY_FORWARD_METHOD_USER_NO_PROXY_AUTH);
fail_unless(res == 0, "Failed to init Forward API session resources: %s",
strerror(errno));
proxy_sess = forward_get_proxy_sess();
/* No destination host in PASS command. */
cmd = pr_cmd_alloc(p, 2, "PASS", "test");
cmd->arg = pstrdup(p, "test");
mark_point();
res = proxy_forward_handle_pass(cmd, proxy_sess, &successful,
&block_responses);
fail_unless(res < 0, "Handled PASS command unexpectedly");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
/* XXX TODO: Use a file fd for the "backend control conn" fd (/dev/null?) */
/* Valid external host (with port) in USER command. */
cmd = pr_cmd_alloc(p, 2, "USER", "anonymous@ftp.cisco.com:21");
cmd->arg = pstrdup(p, "anonymous@ftp.cisco.com:21");
mark_point();
res = proxy_forward_handle_user(cmd, proxy_sess, &successful,
&block_responses);
fail_unless(res == 1, "Failed to handle USER command: %s", strerror(errno));
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
if (getenv("TRAVIS") == NULL) {
cmd = pr_cmd_alloc(p, 2, "PASS", "ftp@nospam.org");
cmd->arg = pstrdup(p, "ftp@nospam.org");
mark_point();
res = proxy_forward_handle_pass(cmd, proxy_sess, &successful,
&block_responses);
fail_unless(res == 1, "Failed to handle PASS command: %s", strerror(errno));
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
}
#ifdef PR_USE_OPENSSL
/* This time, try an FTPS-capable site. */
session.notes = pr_table_alloc(p, 0);
pr_table_add(session.notes, "mod_proxy.proxy-session", proxy_sess,
sizeof(struct proxy_session));
res = proxy_tls_init(p, test_dir, PROXY_DB_OPEN_FL_SKIP_VACUUM);
fail_unless(res == 0, "Failed to init TLS API resources: %s",
strerror(errno));
c = add_config_param("ProxyTLSEngine", 1, NULL);
c->argv[0] = palloc(c->pool, sizeof(int));
*((int *) c->argv[0]) = PROXY_TLS_ENGINE_AUTO;
c = add_config_param("ProxyTLSVerifyServer", 1, NULL);
c->argv[0] = palloc(c->pool, sizeof(int));
*((int *) c->argv[0]) = FALSE;
c = add_config_param("ProxyTLSOptions", 1, NULL);
c->argv[0] = palloc(c->pool, sizeof(unsigned long));
*((unsigned long *) c->argv[0]) = PROXY_TLS_OPT_ENABLE_DIAGS;
/* XXX if we want to successfully verify the Cisco cert, we'd need to include
* its CA certs as a test resource, and configure it here.
*/
res = proxy_tls_sess_init(p, PROXY_DB_OPEN_FL_SKIP_VACUUM);
fail_unless(res == 0, "Failed to init TLS API session resources: %s",
strerror(errno));
/* Valid external host (with port) in USER command. */
cmd = pr_cmd_alloc(p, 2, "USER", "anonymous@ftp.cisco.com:990");
cmd->arg = pstrdup(p, "anonymous@ftp.cisco.com:990");
if (getenv("TRAVIS") == NULL) {
mark_point();
res = proxy_forward_handle_user(cmd, proxy_sess, &successful,
&block_responses);
/* Once you've performed a TLS handshake with ftp.cisco.com, it does not
* accept anonymous logins. Fine.
*/
fail_if(res == 1, "Handled USER command unexpectedly");
fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
strerror(errno), errno);
}
mark_point();
res = proxy_tls_sess_free(p);
fail_unless(res == 0, "Failed to free TLS API session resources: %s",
strerror(errno));
mark_point();
res = proxy_tls_free(p);
fail_unless(res == 0, "Failed to free TLS API resources: %s",
strerror(errno));
mark_point();
(void) proxy_db_close(p, NULL);
#endif /* PR_USE_OPENSSL */
mark_point();
res = proxy_forward_sess_free(p, NULL);
fail_unless(res == 0, "Failed to free Forward API session resources: %s",
strerror(errno));
proxy_session_free(p, proxy_sess);
}
END_TEST
START_TEST (forward_handle_pass_userwithproxyauth_test) {
int res, successful = FALSE, block_responses = FALSE;
cmd_rec *cmd;
struct proxy_session *proxy_sess;
res = forward_sess_init(PROXY_FORWARD_METHOD_USER_WITH_PROXY_AUTH);
fail_unless(res == 0, "Failed to init Forward API session resources: %s",
strerror(errno));
proxy_sess = forward_get_proxy_sess();
/* No destination host in PASS command. */
cmd = pr_cmd_alloc(p, 2, "PASS", "test");
cmd->arg = pstrdup(p, "test");
mark_point();
res = proxy_forward_handle_pass(cmd, proxy_sess, &successful,
&block_responses);
fail_unless(res < 0, "Handled PASS command unexpectedly");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
/* XXX TODO: Use a file fd for the "backend control conn" fd (/dev/null?) */
res = proxy_forward_sess_free(p, NULL);
fail_unless(res == 0, "Failed to free Forward API session resources: %s",
strerror(errno));
proxy_session_free(p, proxy_sess);
}
END_TEST
START_TEST (forward_handle_pass_proxyuserwithproxyauth_test) {
int res, successful = FALSE, block_responses = FALSE;
cmd_rec *cmd;
struct proxy_session *proxy_sess;
res = forward_sess_init(PROXY_FORWARD_METHOD_PROXY_USER_WITH_PROXY_AUTH);
fail_unless(res == 0, "Failed to init Forward API session resources: %s",
strerror(errno));
proxy_sess = forward_get_proxy_sess();
/* No destination host in PASS command. */
cmd = pr_cmd_alloc(p, 2, "PASS", "test");
cmd->arg = pstrdup(p, "test");
mark_point();
res = proxy_forward_handle_pass(cmd, proxy_sess, &successful,
&block_responses);
fail_unless(res < 0, "Handled PASS command unexpectedly");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
/* XXX TODO: Use a file fd for the "backend control conn" fd (/dev/null?) */
res = proxy_forward_sess_free(p, NULL);
fail_unless(res == 0, "Failed to free Forward API session resources: %s",
strerror(errno));
proxy_session_free(p, proxy_sess);
}
END_TEST
Suite *tests_get_forward_suite(void) {
Suite *suite;
TCase *testcase;
suite = suite_create("forward");
testcase = tcase_create("base");
tcase_add_checked_fixture(testcase, set_up, tear_down);
tcase_add_test(testcase, forward_free_test);
tcase_add_test(testcase, forward_init_test);
tcase_add_test(testcase, forward_sess_free_test);
tcase_add_test(testcase, forward_sess_init_test);
tcase_add_test(testcase, forward_get_method_test);
tcase_add_test(testcase, forward_use_proxy_auth_test);
tcase_add_test(testcase, forward_have_authenticated_test);
tcase_add_test(testcase, forward_handle_user_noproxyauth_test);
tcase_add_test(testcase, forward_handle_user_userwithproxyauth_test);
tcase_add_test(testcase, forward_handle_user_proxyuserwithproxyauth_test);
tcase_add_test(testcase, forward_handle_pass_noproxyauth_test);
tcase_add_test(testcase, forward_handle_pass_userwithproxyauth_test);
tcase_add_test(testcase, forward_handle_pass_proxyuserwithproxyauth_test);
suite_add_tcase(suite, testcase);
return suite;
}
proftpd-mod_proxy-0.8/t/api/ftp/ 0000775 0000000 0000000 00000000000 14020740307 0016657 5 ustar 00root root 0000000 0000000 proftpd-mod_proxy-0.8/t/api/ftp/conn.c 0000664 0000000 0000000 00000022034 14020740307 0017761 0 ustar 00root root 0000000 0000000 /*
* ProFTPD - mod_proxy testsuite
* Copyright (c) 2016-2021 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
*
* As a special exemption, TJ Saunders and other respective copyright holders
* give permission to link this program with OpenSSL, and distribute the
* resulting executable, without including the source code for OpenSSL in the
* source distribution.
*/
/* FTP Connection API tests. */
#include "../tests.h"
static pool *p = NULL;
static void create_main_server(void) {
pool *main_pool;
xaset_t *servers;
main_pool = make_sub_pool(permanent_pool);
pr_pool_tag(main_pool, "testsuite#main_server pool");
servers = xaset_create(main_pool, NULL);
main_server = (server_rec *) pcalloc(main_pool, sizeof(server_rec));
xaset_insert(servers, (xasetmember_t *) main_server);
main_server->pool = main_pool;
main_server->set = servers;
main_server->sid = 1;
main_server->notes = pr_table_nalloc(main_pool, 0, 8);
main_server->conf = xaset_create(main_pool, NULL);
/* TCP KeepAlive is enabled by default, with the system defaults. */
main_server->tcp_keepalive = palloc(main_server->pool,
sizeof(struct tcp_keepalive));
main_server->tcp_keepalive->keepalive_enabled = TRUE;
main_server->tcp_keepalive->keepalive_idle = -1;
main_server->tcp_keepalive->keepalive_count = -1;
main_server->tcp_keepalive->keepalive_intvl = -1;
main_server->ServerName = "Test Server";
main_server->ServerPort = 21;
}
static void set_up(void) {
if (p == NULL) {
p = permanent_pool = session.pool = make_sub_pool(NULL);
session.c = NULL;
session.notes = NULL;
}
init_netaddr();
init_netio();
init_inet();
create_main_server();
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("netio", 1, 20);
pr_trace_set_levels("inet", 1, 20);
pr_trace_set_levels("proxy.ftp.conn", 1, 20);
}
pr_inet_set_default_family(p, AF_INET);
}
static void tear_down(void) {
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("netio", 0, 0);
pr_trace_set_levels("inet", 0, 0);
pr_trace_set_levels("proxy.ftp.conn", 0, 0);
}
pr_inet_set_default_family(p, 0);
pr_inet_clear();
if (p) {
destroy_pool(p);
p = permanent_pool = session.pool = NULL;
main_server = NULL;
session.c = NULL;
session.notes = NULL;
}
}
START_TEST (accept_test) {
conn_t *res, *ctrl_conn = NULL, *data_conn = NULL;
res = proxy_ftp_conn_accept(NULL, NULL, NULL, FALSE);
fail_unless(res == NULL, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
res = proxy_ftp_conn_accept(p, NULL, NULL, FALSE);
fail_unless(res == NULL, "Failed to handle null data conn");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
data_conn = pr_inet_create_conn(p, -2, NULL, INPORT_ANY, FALSE);
fail_unless(data_conn != NULL, "Failed to create conn: %s",
strerror(errno));
mark_point();
res = proxy_ftp_conn_accept(p, data_conn, NULL, FALSE);
fail_unless(res == NULL, "Failed to handle null ctrl conn");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
ctrl_conn = pr_inet_create_conn(p, -2, NULL, INPORT_ANY, FALSE);
fail_unless(ctrl_conn != NULL, "Failed to create conn: %s",
strerror(errno));
session.xfer.direction = PR_NETIO_IO_RD;
mark_point();
res = proxy_ftp_conn_accept(p, data_conn, ctrl_conn, FALSE);
fail_unless(res == NULL, "Failed to handle null ctrl conn");
fail_unless(errno == EBADF, "Expected EBADF (%d), got '%s' (%d)", EBADF,
strerror(errno), errno);
mark_point();
res = proxy_ftp_conn_accept(p, data_conn, ctrl_conn, TRUE);
fail_unless(res == NULL, "Failed to handle null ctrl conn");
fail_unless(errno == EBADF, "Expected EBADF (%d), got '%s' (%d)", EBADF,
strerror(errno), errno);
session.xfer.direction = PR_NETIO_IO_WR;
mark_point();
res = proxy_ftp_conn_accept(p, data_conn, ctrl_conn, FALSE);
fail_unless(res == NULL, "Failed to handle null ctrl conn");
fail_unless(errno == EBADF, "Expected EBADF (%d), got '%s' (%d)", EBADF,
strerror(errno), errno);
mark_point();
res = proxy_ftp_conn_accept(p, data_conn, ctrl_conn, TRUE);
fail_unless(res == NULL, "Failed to handle null ctrl conn");
fail_unless(errno == EBADF, "Expected EBADF (%d), got '%s' (%d)", EBADF,
strerror(errno), errno);
pr_inet_close(p, ctrl_conn);
pr_inet_close(p, data_conn);
}
END_TEST
START_TEST (connect_test) {
conn_t *res;
const pr_netaddr_t *remote_addr = NULL;
res = proxy_ftp_conn_connect(NULL, NULL, NULL, FALSE);
fail_unless(res == NULL, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
res = proxy_ftp_conn_connect(p, NULL, NULL, FALSE);
fail_unless(res == NULL, "Failed to handle null remote addr");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
remote_addr = pr_netaddr_get_addr(p, "127.0.0.1", NULL);
fail_unless(remote_addr != NULL, "Failed to address for 127.0.0.1: %s",
strerror(errno));
pr_netaddr_set_port((pr_netaddr_t *) remote_addr, htons(6555));
session.xfer.direction = PR_NETIO_IO_RD;
mark_point();
res = proxy_ftp_conn_connect(p, NULL, remote_addr, FALSE);
fail_unless(res == NULL, "Failed to handle bad address family");
fail_unless(errno == ECONNREFUSED, "Expected ECONNREFUSED (%d), got %s (%d)",
ECONNREFUSED, strerror(errno), errno);
mark_point();
res = proxy_ftp_conn_connect(p, NULL, remote_addr, TRUE);
fail_unless(res == NULL, "Failed to handle bad address family");
fail_unless(errno == ECONNREFUSED, "Expected ECONNREFUSED (%d), got %s (%d)",
ECONNREFUSED, strerror(errno), errno);
session.xfer.direction = PR_NETIO_IO_WR;
mark_point();
res = proxy_ftp_conn_connect(p, NULL, remote_addr, FALSE);
fail_unless(res == NULL, "Failed to handle bad address family");
fail_unless(errno == ECONNREFUSED, "Expected ECONNREFUSED (%d), got %s (%d)",
ECONNREFUSED, strerror(errno), errno);
mark_point();
res = proxy_ftp_conn_connect(p, NULL, remote_addr, TRUE);
fail_unless(res == NULL, "Failed to handle bad address family");
fail_unless(errno == ECONNREFUSED, "Expected ECONNREFUSED (%d), got %s (%d)",
ECONNREFUSED, strerror(errno), errno);
/* Try connecting to Google's DNS server. */
remote_addr = pr_netaddr_get_addr(p, "8.8.8.8", NULL);
fail_unless(remote_addr != NULL, "Failed to resolve '8.8.8.8': %s",
strerror(errno));
pr_netaddr_set_port((pr_netaddr_t *) remote_addr, htons(53));
mark_point();
res = proxy_ftp_conn_connect(p, NULL, remote_addr, FALSE);
fail_unless(res != NULL, "Failed to connect: %s", strerror(errno));
pr_inet_close(p, res);
mark_point();
res = proxy_ftp_conn_connect(p, NULL, remote_addr, TRUE);
fail_unless(res != NULL, "Failed to connect: %s", strerror(errno));
pr_inet_close(p, res);
}
END_TEST
START_TEST (listen_test) {
conn_t *res;
const pr_netaddr_t *bind_addr = NULL;
res = proxy_ftp_conn_listen(NULL, NULL, FALSE);
fail_unless(res == NULL, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
res = proxy_ftp_conn_listen(p, NULL, FALSE);
fail_unless(res == NULL, "Failed to handle null bind address");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
bind_addr = pr_netaddr_get_addr(p, "127.0.0.1", NULL);
fail_unless(bind_addr != NULL, "Failed to address for 127.0.0.1: %s",
strerror(errno));
pr_netaddr_set_port((pr_netaddr_t *) bind_addr, htons(0));
mark_point();
res = proxy_ftp_conn_listen(p, bind_addr, FALSE);
fail_unless(res != NULL, "Failed to listen: %s", strerror(errno));
pr_inet_close(p, res);
mark_point();
res = proxy_ftp_conn_listen(p, bind_addr, TRUE);
fail_unless(res != NULL, "Failed to listen: %s", strerror(errno));
pr_inet_close(p, res);
}
END_TEST
Suite *tests_get_ftp_conn_suite(void) {
Suite *suite;
TCase *testcase;
suite = suite_create("ftp.conn");
testcase = tcase_create("base");
tcase_add_checked_fixture(testcase, set_up, tear_down);
tcase_add_test(testcase, accept_test);
tcase_add_test(testcase, connect_test);
tcase_add_test(testcase, listen_test);
suite_add_tcase(suite, testcase);
return suite;
}
proftpd-mod_proxy-0.8/t/api/ftp/ctrl.c 0000664 0000000 0000000 00000030236 14020740307 0017773 0 ustar 00root root 0000000 0000000 /*
* ProFTPD - mod_proxy testsuite
* Copyright (c) 2016 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
*
* As a special exemption, TJ Saunders and other respective copyright holders
* give permission to link this program with OpenSSL, and distribute the
* resulting executable, without including the source code for OpenSSL in the
* source distribution.
*/
/* FTP Control API tests. */
#include "../tests.h"
static pool *p = NULL;
static void set_up(void) {
if (p == NULL) {
p = permanent_pool = session.pool = make_sub_pool(NULL);
session.c = NULL;
session.notes = NULL;
}
init_netaddr();
init_netio();
init_inet();
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("netio", 1, 20);
pr_trace_set_levels("proxy.ftp.ctrl", 1, 20);
}
pr_inet_set_default_family(p, AF_INET);
pr_response_set_pool(NULL);
}
static void tear_down(void) {
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("netio", 0, 0);
pr_trace_set_levels("proxy.ftp.ctrl", 0, 0);
}
pr_inet_set_default_family(p, 0);
pr_inet_clear();
pr_response_set_pool(NULL);
if (p) {
destroy_pool(p);
p = permanent_pool = session.pool = NULL;
session.c = NULL;
session.notes = NULL;
}
}
START_TEST (handle_async_test) {
int res, flags = PROXY_FTP_CTRL_FL_IGNORE_EOF;
conn_t *frontend_conn, *backend_conn;
pr_netio_stream_t *nstrm;
mark_point();
res = proxy_ftp_ctrl_handle_async(NULL, NULL, NULL, flags);
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_ftp_ctrl_handle_async(p, NULL, NULL, flags);
fail_unless(res < 0, "Failed to handle null backend conn");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
backend_conn = pr_inet_create_conn(p, -2, NULL, INPORT_ANY, FALSE);
fail_unless(backend_conn != NULL, "Failed to create conn: %s",
strerror(errno));
mark_point();
res = proxy_ftp_ctrl_handle_async(p, backend_conn, NULL, flags);
fail_unless(res < 0, "Failed to handle null frontend conn");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
frontend_conn = pr_inet_create_conn(p, -2, NULL, INPORT_ANY, FALSE);
fail_unless(frontend_conn != NULL, "Failed to create conn: %s",
strerror(errno));
mark_point();
res = proxy_ftp_ctrl_handle_async(p, backend_conn, frontend_conn, flags);
fail_unless(res < 0, "Failed to handle null backend conn stream");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
nstrm = pr_netio_open(p, PR_NETIO_STRM_CTRL, 8, PR_NETIO_IO_RD);
backend_conn->instrm = nstrm;
mark_point();
res = proxy_ftp_ctrl_handle_async(p, backend_conn, frontend_conn, flags);
fail_unless(res == 0, "Failed to handle async IO: %s", strerror(errno));
proxy_sess_state |= PROXY_SESS_STATE_CONNECTED;
mark_point();
res = proxy_ftp_ctrl_handle_async(p, backend_conn, frontend_conn, flags);
fail_unless(res == 0, "Failed to handle async IO: %s", strerror(errno));
proxy_sess_state &= ~PROXY_SESS_STATE_CONNECTED;
pr_inet_close(p, frontend_conn);
pr_inet_close(p, backend_conn);
}
END_TEST
START_TEST (recv_resp_test) {
int flags = PROXY_FTP_CTRL_FL_IGNORE_EOF, len;
pr_response_t *resp;
unsigned int nlines = 0;
conn_t *ctrl_conn = NULL;
size_t buflen;
pr_buffer_t *pbuf;
pr_netio_stream_t *nstrm;
mark_point();
resp = proxy_ftp_ctrl_recv_resp(NULL, NULL, NULL, flags);
fail_unless(resp == NULL, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
mark_point();
resp = proxy_ftp_ctrl_recv_resp(p, NULL, NULL, flags);
fail_unless(resp == NULL, "Failed to handle null ctrl conn");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
ctrl_conn = pr_inet_create_conn(p, -2, NULL, INPORT_ANY, FALSE);
fail_unless(ctrl_conn != NULL, "Failed to create conn: %s",
strerror(errno));
mark_point();
resp = proxy_ftp_ctrl_recv_resp(p, ctrl_conn, NULL, flags);
fail_unless(resp == NULL, "Failed to handle null response nlines");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
mark_point();
resp = proxy_ftp_ctrl_recv_resp(p, ctrl_conn, &nlines, flags);
fail_unless(resp == NULL, "Failed to handle EOF");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
nstrm = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_RD);
fail_unless(nstrm != NULL, "Failed to open ctrl stream: %s", strerror(errno));
pbuf = pr_netio_buffer_alloc(nstrm);
fail_unless(pbuf != NULL, "Failed to allocate stream buffer: %s",
strerror(errno));
buflen = pbuf->buflen;
len = snprintf(pbuf->buf, pbuf->buflen-1, "%s", "Foo");
pbuf->remaining = len;
pbuf->current = pbuf->buf;
ctrl_conn->instrm = nstrm;
mark_point();
resp = proxy_ftp_ctrl_recv_resp(p, ctrl_conn, &nlines, flags);
fail_unless(resp == NULL, "Failed to handle invalid response");
fail_unless(errno == E2BIG, "Expected E2BIG (%d), got %s (%d)", E2BIG,
strerror(errno), errno);
len = snprintf(pbuf->buf, pbuf->buflen-1, "%s", "Foo\r\n");
pbuf->remaining = len;
pbuf->current = pbuf->buf;
mark_point();
resp = proxy_ftp_ctrl_recv_resp(p, ctrl_conn, &nlines, flags);
fail_unless(resp == NULL, "Failed to handle invalid response");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
len = snprintf(pbuf->buf, pbuf->buflen-1, "%s", "Foo\r\n");
pbuf->remaining = pbuf->buflen = len;
pbuf->current = pbuf->buf;
ctrl_conn->instrm = nstrm;
mark_point();
resp = proxy_ftp_ctrl_recv_resp(p, ctrl_conn, &nlines, flags);
fail_unless(resp == NULL, "Failed to handle invalid response");
fail_unless(errno == EBADF, "Expected EBADF (%d), got %s (%d)", EBADF,
strerror(errno), errno);
len = snprintf(pbuf->buf, pbuf->buflen-1, "%s", "Food\r\n");
pbuf->buflen = buflen;
pbuf->remaining = len;
pbuf->current = pbuf->buf;
mark_point();
resp = proxy_ftp_ctrl_recv_resp(p, ctrl_conn, &nlines, flags);
fail_unless(resp == NULL, "Failed to handle invalid response");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
len = snprintf(pbuf->buf, pbuf->buflen-1, "%s", "1ood\r\n");
pbuf->remaining = len;
pbuf->current = pbuf->buf;
mark_point();
resp = proxy_ftp_ctrl_recv_resp(p, ctrl_conn, &nlines, flags);
fail_unless(resp == NULL, "Failed to handle invalid response");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
len = snprintf(pbuf->buf, pbuf->buflen-1, "%s", "12od\r\n");
pbuf->remaining = len;
pbuf->current = pbuf->buf;
mark_point();
resp = proxy_ftp_ctrl_recv_resp(p, ctrl_conn, &nlines, flags);
fail_unless(resp == NULL, "Failed to handle invalid response");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
len = snprintf(pbuf->buf, pbuf->buflen-1, "%s", "123d\r\n");
pbuf->remaining = len;
pbuf->current = pbuf->buf;
mark_point();
resp = proxy_ftp_ctrl_recv_resp(p, ctrl_conn, &nlines, flags);
fail_unless(resp == NULL, "Failed to handle invalid response");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
len = snprintf(pbuf->buf, pbuf->buflen-1, "%s", "001 Foo\r\n");
pbuf->remaining = len;
pbuf->current = pbuf->buf;
mark_point();
resp = proxy_ftp_ctrl_recv_resp(p, ctrl_conn, &nlines, flags);
fail_unless(resp == NULL, "Failed to handle invalid response");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
len = snprintf(pbuf->buf, pbuf->buflen-1, "%s", "999 Foo\r\n");
pbuf->remaining = len;
pbuf->current = pbuf->buf;
mark_point();
resp = proxy_ftp_ctrl_recv_resp(p, ctrl_conn, &nlines, flags);
fail_unless(resp == NULL, "Failed to handle invalid response");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
len = snprintf(pbuf->buf, pbuf->buflen-1, "%s", "200 Foo\r\n");
pbuf->remaining = len;
pbuf->current = pbuf->buf;
mark_point();
resp = proxy_ftp_ctrl_recv_resp(p, ctrl_conn, &nlines, flags);
fail_unless(resp != NULL, "Failed to receive response: %s", strerror(errno));
fail_unless(strcmp(resp->num, R_200) == 0, "Expected '%s', got '%s'", R_200,
resp->num);
fail_unless(nlines == 1, "Expected 1, got %u", nlines);
/* XXX TODO: multiline responses! */
pr_inet_close(p, ctrl_conn);
}
END_TEST
START_TEST (send_cmd_test) {
int res;
conn_t *ctrl_conn;
cmd_rec *cmd;
res = proxy_ftp_ctrl_send_cmd(NULL, NULL, NULL);
fail_unless(res < 0, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
res = proxy_ftp_ctrl_send_cmd(p, NULL, NULL);
fail_unless(res < 0, "Failed to handle null conn");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
ctrl_conn = pr_inet_create_conn(p, -2, NULL, INPORT_ANY, FALSE);
fail_unless(ctrl_conn != NULL, "Failed to create conn: %s",
strerror(errno));
res = proxy_ftp_ctrl_send_cmd(p, ctrl_conn, NULL);
fail_unless(res < 0, "Failed to handle null command");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
cmd = pr_cmd_alloc(p, 2, "FOO", "bar");
mark_point();
res = proxy_ftp_ctrl_send_cmd(p, ctrl_conn, cmd);
fail_unless(res < 0, "Failed to handle command without stream");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
cmd = pr_cmd_alloc(p, 1, "FOO");
mark_point();
res = proxy_ftp_ctrl_send_cmd(p, ctrl_conn, cmd);
fail_unless(res < 0, "Failed to handle command without stream");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
pr_inet_close(p, ctrl_conn);
}
END_TEST
START_TEST (send_resp_test) {
int res;
pr_response_t *resp;
res = proxy_ftp_ctrl_send_resp(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);
res = proxy_ftp_ctrl_send_resp(p, NULL, NULL, 0);
fail_unless(res < 0, "Failed to handle null response");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
resp = pcalloc(p, sizeof(pr_response_t));
resp->num = "123";
resp->msg = pstrdup(p, "foo bar?");
res = proxy_ftp_ctrl_send_resp(p, NULL, resp, 0);
fail_unless(res == 0, "Failed to handle response: %s", strerror(errno));
res = proxy_ftp_ctrl_send_resp(p, NULL, resp, 3);
fail_unless(res == 0, "Failed to handle response: %s", strerror(errno));
}
END_TEST
Suite *tests_get_ftp_ctrl_suite(void) {
Suite *suite;
TCase *testcase;
suite = suite_create("ftp.ctrl");
testcase = tcase_create("base");
tcase_add_checked_fixture(testcase, set_up, tear_down);
tcase_add_test(testcase, handle_async_test);
tcase_add_test(testcase, recv_resp_test);
tcase_add_test(testcase, send_cmd_test);
tcase_add_test(testcase, send_resp_test);
suite_add_tcase(suite, testcase);
return suite;
}
proftpd-mod_proxy-0.8/t/api/ftp/data.c 0000664 0000000 0000000 00000013011 14020740307 0017730 0 ustar 00root root 0000000 0000000 /*
* ProFTPD - mod_proxy testsuite
* Copyright (c) 2016 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
*
* As a special exemption, TJ Saunders and other respective copyright holders
* give permission to link this program with OpenSSL, and distribute the
* resulting executable, without including the source code for OpenSSL in the
* source distribution.
*/
/* FTP Data API tests. */
#include "../tests.h"
static pool *p = NULL;
static void set_up(void) {
if (p == NULL) {
p = permanent_pool = session.pool = make_sub_pool(NULL);
session.c = NULL;
session.notes = NULL;
}
init_netaddr();
init_netio();
init_inet();
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("proxy.ftp.data", 1, 20);
}
}
static void tear_down(void) {
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("proxy.ftp.data", 0, 0);
}
pr_inet_clear();
if (p) {
destroy_pool(p);
p = permanent_pool = session.pool = NULL;
session.c = NULL;
session.notes = NULL;
}
}
START_TEST (recv_test) {
pr_buffer_t *pbuf;
conn_t *conn;
mark_point();
pbuf = proxy_ftp_data_recv(NULL, NULL, FALSE);
fail_unless(pbuf == NULL, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
mark_point();
pbuf = proxy_ftp_data_recv(p, NULL, FALSE);
fail_unless(pbuf == 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));
mark_point();
pbuf = proxy_ftp_data_recv(p, conn, FALSE);
fail_unless(pbuf == NULL, "Failed to handle missing instream");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
conn->instrm = pr_netio_open(p, PR_NETIO_STRM_DATA, -1, PR_NETIO_IO_RD);
fail_unless(conn->instrm != NULL, "Failed open data stream: %s",
strerror(errno));
mark_point();
pbuf = proxy_ftp_data_recv(p, conn, FALSE);
fail_unless(pbuf == NULL, "Failed to handle bad instream fd");
fail_unless(errno == EBADF, "Expected EBADF (%d), got %s (%d)", EBADF,
strerror(errno), errno);
mark_point();
pbuf = proxy_ftp_data_recv(p, conn, TRUE);
fail_unless(pbuf == NULL, "Failed to handle bad instream fd");
fail_unless(errno == EBADF, "Expected EBADF (%d), got %s (%d)", EBADF,
strerror(errno), errno);
/* Fill in the instrm fd with an fd to an empty file */
/* Fill in the instrm fd with an fd to /dev/null */
pr_inet_close(p, conn);
}
END_TEST
START_TEST (send_test) {
int res;
pr_buffer_t *pbuf;
conn_t *conn;
mark_point();
res = proxy_ftp_data_send(NULL, NULL, NULL, FALSE);
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_ftp_data_send(p, NULL, NULL, FALSE);
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, -2, NULL, INPORT_ANY, FALSE);
fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno));
mark_point();
res = proxy_ftp_data_send(p, conn, NULL, FALSE);
fail_unless(res < 0, "Failed to handle null buffer");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
conn->outstrm = pr_netio_open(p, PR_NETIO_STRM_DATA, -1, PR_NETIO_IO_WR);
fail_unless(conn->outstrm != NULL, "Failed open data stream: %s",
strerror(errno));
mark_point();
res = proxy_ftp_data_send(p, conn, NULL, FALSE);
fail_unless(res < 0, "Failed to handle null buffer");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
pbuf = pcalloc(p, sizeof(pr_buffer_t));
pbuf->buflen = 1024;
pbuf->buf = palloc(p, pbuf->buflen);
pbuf->current = pbuf->buf + 2;
mark_point();
res = proxy_ftp_data_send(p, conn, pbuf, FALSE);
fail_unless(res < 0, "Sent data unexpectedly");
fail_unless(errno == EBADF, "Expected EBADF (%d), got %s (%d)", EBADF,
strerror(errno), errno);
mark_point();
res = proxy_ftp_data_send(p, conn, pbuf, TRUE);
fail_unless(res < 0, "Sent data unexpectedly");
fail_unless(errno == EBADF, "Expected EBADF (%d), got %s (%d)", EBADF,
strerror(errno), errno);
pr_inet_close(p, conn);
}
END_TEST
Suite *tests_get_ftp_data_suite(void) {
Suite *suite;
TCase *testcase;
suite = suite_create("ftp.data");
testcase = tcase_create("base");
tcase_add_checked_fixture(testcase, set_up, tear_down);
tcase_add_test(testcase, recv_test);
tcase_add_test(testcase, send_test);
suite_add_tcase(suite, testcase);
return suite;
}
proftpd-mod_proxy-0.8/t/api/ftp/dirlist.c 0000664 0000000 0000000 00000025723 14020740307 0020506 0 ustar 00root root 0000000 0000000 /*
* ProFTPD - mod_proxy testsuite
* Copyright (c) 2020 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
*
* As a special exemption, TJ Saunders and other respective copyright holders
* give permission to link this program with OpenSSL, and distribute the
* resulting executable, without including the source code for OpenSSL in the
* source distribution.
*/
/* FTP Dirlist API tests. */
#include "../tests.h"
static pool *p = NULL;
static void set_up(void) {
if (p == NULL) {
p = permanent_pool = session.pool = make_sub_pool(NULL);
session.c = NULL;
session.notes = NULL;
}
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("proxy.ftp.dirlist", 1, 20);
}
}
static void tear_down(void) {
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("proxy.ftp.dirlist", 0, 0);
}
if (p != NULL) {
destroy_pool(p);
p = permanent_pool = session.pool = NULL;
session.c = NULL;
session.notes = NULL;
}
}
START_TEST (init_test) {
int res;
mark_point();
res = proxy_ftp_dirlist_init(NULL, NULL);
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_ftp_dirlist_init(p, NULL);
fail_unless(res < 0, "Failed to handle null proxy_sess");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
}
END_TEST
START_TEST (finish_test) {
int res;
mark_point();
res = proxy_ftp_dirlist_finish(NULL);
fail_unless(res < 0, "Failed to handle null proxy_sess");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
}
END_TEST
START_TEST (from_dos_test) {
struct proxy_dirlist_fileinfo *res = NULL;
const char *text = NULL;
size_t textlen = 0;
mark_point();
res = proxy_ftp_dirlist_fileinfo_from_dos(NULL, NULL, 0, 0);
fail_unless(res == NULL, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
mark_point();
res = proxy_ftp_dirlist_fileinfo_from_dos(p, NULL, 0, 0);
fail_unless(res == NULL, "Failed to handle null text");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
text = "foo bar baz";
mark_point();
res = proxy_ftp_dirlist_fileinfo_from_dos(p, text, 0, 0);
fail_unless(res == NULL, "Failed to handle zero text len");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
textlen = strlen(text);
mark_point();
res = proxy_ftp_dirlist_fileinfo_from_dos(p, text, textlen, 0);
fail_unless(res == NULL, "Failed to handle bad text");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
}
END_TEST
START_TEST (from_unix_test) {
struct proxy_dirlist_fileinfo *res = NULL;
const char *text = NULL;
size_t textlen = 0;
time_t now;
struct tm *tm;
mark_point();
res = proxy_ftp_dirlist_fileinfo_from_unix(NULL, NULL, 0, NULL, 0);
fail_unless(res == NULL, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
mark_point();
res = proxy_ftp_dirlist_fileinfo_from_unix(p, NULL, 0, NULL, 0);
fail_unless(res == NULL, "Failed to handle null text");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
text = "foo bar baz";
mark_point();
res = proxy_ftp_dirlist_fileinfo_from_unix(p, text, 0, NULL, 0);
fail_unless(res == NULL, "Failed to handle zero text len");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
textlen = strlen(text);
mark_point();
res = proxy_ftp_dirlist_fileinfo_from_unix(p, text, textlen, NULL, 0);
fail_unless(res == NULL, "Failed to handle null tm");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
time(&now);
tm = pr_gmtime(p, &now);
mark_point();
res = proxy_ftp_dirlist_fileinfo_from_unix(p, text, textlen, tm, 0);
fail_unless(res == NULL, "Failed to handle bad text");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
}
END_TEST
START_TEST (from_text_test) {
struct proxy_session *proxy_sess = NULL;
struct proxy_dirlist_fileinfo *res = NULL;
const char *text = NULL;
size_t textlen = 0;
time_t now;
struct tm *tm;
mark_point();
res = proxy_ftp_dirlist_fileinfo_from_text(NULL, NULL, 0, NULL, NULL, 0);
fail_unless(res == NULL, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
mark_point();
res = proxy_ftp_dirlist_fileinfo_from_text(p, NULL, 0, NULL, NULL, 0);
fail_unless(res == NULL, "Failed to handle null text");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
text = "foo bar baz";
mark_point();
res = proxy_ftp_dirlist_fileinfo_from_text(p, text, 0, NULL, NULL, 0);
fail_unless(res == NULL, "Failed to handle zero text len");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
textlen = strlen(text);
mark_point();
res = proxy_ftp_dirlist_fileinfo_from_text(p, text, textlen, NULL, NULL, 0);
fail_unless(res == NULL, "Failed to handle null tm");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
time(&now);
tm = pr_gmtime(p, &now);
mark_point();
res = proxy_ftp_dirlist_fileinfo_from_text(p, text, textlen, tm, NULL, 0);
fail_unless(res == NULL, "Failed to handle null userdata");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
proxy_sess = (struct proxy_session *) proxy_session_alloc(p);
fail_unless(proxy_sess != NULL, "Failed to allocate proxy session: %s",
strerror(errno));
mark_point();
res = proxy_ftp_dirlist_fileinfo_from_text(p, text, textlen, tm, proxy_sess,
0);
fail_unless(res == NULL, "Failed to handle null proxy_sess->dirlist_ctx");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
mark_point();
proxy_session_free(p, proxy_sess);
}
END_TEST
START_TEST (to_facts_test) {
const char *text;
struct proxy_dirlist_fileinfo *pdf;
mark_point();
text = proxy_ftp_dirlist_fileinfo_to_facts(NULL, NULL, NULL);
fail_unless(text == NULL, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
mark_point();
text = proxy_ftp_dirlist_fileinfo_to_facts(p, NULL, NULL);
fail_unless(text == NULL, "Failed to handle null fileinfo");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
pdf = pcalloc(p, sizeof(struct proxy_dirlist_fileinfo));
mark_point();
text = proxy_ftp_dirlist_fileinfo_to_facts(p, pdf, NULL);
fail_unless(text == NULL, "Failed to handle null textlen");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
}
END_TEST
START_TEST (to_text_test) {
int res;
struct proxy_session *proxy_sess = NULL;
char *buf, *output_text = NULL;
size_t buflen, maxlen, output_textlen = 0;
mark_point();
res = proxy_ftp_dirlist_to_text(NULL, NULL, 0, 0, NULL, NULL, NULL);
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_ftp_dirlist_to_text(p, NULL, 0, 0, NULL, NULL, NULL);
fail_unless(res < 0, "Failed to handle null buf");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
buf = "foo bar baz";
mark_point();
res = proxy_ftp_dirlist_to_text(p, buf, 0, 0, NULL, NULL, NULL);
fail_unless(res < 0, "Failed to handle zero buflen");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
buflen = strlen(buf);
mark_point();
res = proxy_ftp_dirlist_to_text(p, buf, buflen, 0, NULL, NULL, NULL);
fail_unless(res < 0, "Failed to handle zero max textsz");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
maxlen = 1024;
mark_point();
res = proxy_ftp_dirlist_to_text(p, buf, buflen, maxlen, NULL, NULL, NULL);
fail_unless(res < 0, "Failed to handle null output text");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
mark_point();
res = proxy_ftp_dirlist_to_text(p, buf, buflen, maxlen, &output_text, NULL,
NULL);
fail_unless(res < 0, "Failed to handle null output textlen");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
mark_point();
res = proxy_ftp_dirlist_to_text(p, buf, buflen, maxlen, &output_text,
&output_textlen, NULL);
fail_unless(res < 0, "Failed to handle null userdata");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
proxy_sess = (struct proxy_session *) proxy_session_alloc(p);
fail_unless(proxy_sess != NULL, "Failed to allocate proxy session: %s",
strerror(errno));
mark_point();
res = proxy_ftp_dirlist_to_text(p, buf, buflen, maxlen, &output_text,
&output_textlen, proxy_sess);
fail_unless(res < 0, "Failed to handle null proxy_sess->dirlist_ctx");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
mark_point();
proxy_session_free(p, proxy_sess);
}
END_TEST
Suite *tests_get_ftp_dirlist_suite(void) {
Suite *suite;
TCase *testcase;
suite = suite_create("ftp.dirlist");
testcase = tcase_create("base");
tcase_add_checked_fixture(testcase, set_up, tear_down);
tcase_add_test(testcase, init_test);
tcase_add_test(testcase, finish_test);
tcase_add_test(testcase, from_dos_test);
tcase_add_test(testcase, from_unix_test);
tcase_add_test(testcase, from_text_test);
tcase_add_test(testcase, to_facts_test);
tcase_add_test(testcase, to_text_test);
suite_add_tcase(suite, testcase);
return suite;
}
proftpd-mod_proxy-0.8/t/api/ftp/facts.c 0000664 0000000 0000000 00000003735 14020740307 0020133 0 ustar 00root root 0000000 0000000 /*
* ProFTPD - mod_proxy testsuite
* Copyright (c) 2020 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
*
* As a special exemption, TJ Saunders and other respective copyright holders
* give permission to link this program with OpenSSL, and distribute the
* resulting executable, without including the source code for OpenSSL in the
* source distribution.
*/
/* FTP Facts API tests. */
#include "../tests.h"
static pool *p = NULL;
static void set_up(void) {
if (p == NULL) {
p = permanent_pool = session.pool = make_sub_pool(NULL);
}
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("proxy.ftp.facts", 1, 20);
}
}
static void tear_down(void) {
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("proxy.ftp.facts", 0, 0);
}
if (p != NULL) {
destroy_pool(p);
p = permanent_pool = session.pool = NULL;
}
}
START_TEST (get_facts_test) {
}
END_TEST
START_TEST (parse_facts_test) {
}
END_TEST
Suite *tests_get_ftp_facts_suite(void) {
Suite *suite;
TCase *testcase;
suite = suite_create("ftp.facts");
testcase = tcase_create("base");
tcase_add_checked_fixture(testcase, set_up, tear_down);
tcase_add_test(testcase, get_facts_test);
tcase_add_test(testcase, parse_facts_test);
suite_add_tcase(suite, testcase);
return suite;
}
proftpd-mod_proxy-0.8/t/api/ftp/msg.c 0000664 0000000 0000000 00000045044 14020740307 0017620 0 ustar 00root root 0000000 0000000 /*
* ProFTPD - mod_proxy testsuite
* Copyright (c) 2016-2021 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
*
* As a special exemption, TJ Saunders and other respective copyright holders
* give permission to link this program with OpenSSL, and distribute the
* resulting executable, without including the source code for OpenSSL in the
* source distribution.
*/
/* FTP Message API tests. */
#include "../tests.h"
static pool *p = NULL;
static unsigned char use_ipv6 = FALSE;
static void set_up(void) {
if (p == NULL) {
p = permanent_pool = session.pool = proxy_pool = make_sub_pool(NULL);
session.c = NULL;
session.notes = NULL;
}
init_netaddr();
use_ipv6 = pr_netaddr_use_ipv6();
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("proxy.ftp.msg", 1, 20);
}
}
static void tear_down(void) {
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("proxy.ftp.msg", 0, 0);
}
if (use_ipv6 == FALSE) {
pr_netaddr_disable_ipv6();
}
if (p) {
destroy_pool(p);
p = permanent_pool = session.pool = proxy_pool = NULL;
session.c = NULL;
session.notes = NULL;
}
}
START_TEST (fmt_addr_test) {
const char *res, *expected;
const pr_netaddr_t *addr;
unsigned short port = 2121;
mark_point();
res = proxy_ftp_msg_fmt_addr(NULL, NULL, 0, FALSE);
fail_unless(res == NULL, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
mark_point();
res = proxy_ftp_msg_fmt_addr(p, NULL, 0, FALSE);
fail_unless(res == NULL, "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 get addr for 127.0.0.1: %s",
strerror(errno));
mark_point();
res = proxy_ftp_msg_fmt_addr(p, addr, port, FALSE);
fail_unless(res != NULL, "Failed to format addr: %s", strerror(errno));
expected = "127,0,0,1,8,73";
fail_unless(strcmp(res, expected) == 0, "Expected '%s', got '%s'",
expected, res);
addr = pr_netaddr_get_addr(p, "169.254.254.254", NULL);
fail_unless(addr != NULL, "Failed to get addr for 169.254.254.254: %s",
strerror(errno));
res = proxy_ftp_msg_fmt_addr(p, addr, 38550, FALSE);
fail_unless(res != NULL, "Failed to format addr: %s", strerror(errno));
expected = "169,254,254,254,150,150";
fail_unless(strcmp(res, expected) == 0, "Expected '%s', got '%s'",
expected, res);
}
END_TEST
START_TEST (fmt_ext_addr_test) {
const char *res, *expected;
const pr_netaddr_t *addr;
unsigned short port = 2121;
mark_point();
res = proxy_ftp_msg_fmt_ext_addr(NULL, NULL, 0, 0, FALSE);
fail_unless(res == NULL, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
mark_point();
res = proxy_ftp_msg_fmt_ext_addr(p, NULL, 0, 0, FALSE);
fail_unless(res == NULL, "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 get addr for 127.0.0.1: %s",
strerror(errno));
mark_point();
res = proxy_ftp_msg_fmt_ext_addr(p, addr, port, 0, FALSE);
fail_unless(res == NULL, "Failed to handle null addr");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
mark_point();
res = proxy_ftp_msg_fmt_ext_addr(p, addr, port, PR_CMD_EPRT_ID, FALSE);
fail_unless(res != NULL, "Failed to format addr: %s", strerror(errno));
expected = "|1|127.0.0.1|2121|";
fail_unless(strcmp(res, expected) == 0, "Expected '%s', got '%s'",
expected, res);
mark_point();
res = proxy_ftp_msg_fmt_ext_addr(p, addr, port, PR_CMD_EPSV_ID, FALSE);
fail_unless(res != NULL, "Failed to format addr: %s", strerror(errno));
expected = "|||2121|";
fail_unless(strcmp(res, expected) == 0, "Expected '%s', got '%s'",
expected, res);
#if PR_USE_IPV6
addr = pr_netaddr_get_addr(p, "::1", NULL);
fail_unless(addr != NULL, "Failed to get addr for ::1: %s",
strerror(errno));
mark_point();
res = proxy_ftp_msg_fmt_ext_addr(p, addr, port, PR_CMD_EPRT_ID, FALSE);
fail_unless(res != NULL, "Failed to format addr: %s", strerror(errno));
expected = "|2|::1|2121|";
fail_unless(strcmp(res, expected) == 0, "Expected '%s', got '%s'",
expected, res);
mark_point();
res = proxy_ftp_msg_fmt_ext_addr(p, addr, port, PR_CMD_EPSV_ID, FALSE);
fail_unless(res != NULL, "Failed to format addr: %s", strerror(errno));
expected = "|||2121|";
fail_unless(strcmp(res, expected) == 0, "Expected '%s', got '%s'",
expected, res);
#endif /* PR_USE_IPV6 */
}
END_TEST
START_TEST (parse_addr_test) {
const pr_netaddr_t *res;
const char *msg, *expected, *ip_str;
res = proxy_ftp_msg_parse_addr(NULL, NULL, 0);
fail_unless(res == NULL, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
res = proxy_ftp_msg_parse_addr(p, NULL, 0);
fail_unless(res == NULL, "Failed to handle null msg");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
msg = "foo";
res = proxy_ftp_msg_parse_addr(p, msg, 0);
fail_unless(res == NULL, "Failed to handle invalid format");
fail_unless(errno == EPERM, "Expected EPERM (%d), got '%s' (%d)", EPERM,
strerror(errno), errno);
msg = "(a,b,c,d,e,f)";
res = proxy_ftp_msg_parse_addr(p, msg, 0);
fail_unless(res == NULL, "Failed to handle invalid format");
fail_unless(errno == EPERM, "Expected EPERM (%d), got '%s' (%d)", EPERM,
strerror(errno), errno);
msg = "(1000,2000,3000,4000,5000,6000)";
res = proxy_ftp_msg_parse_addr(p, msg, 0);
fail_unless(res == NULL, "Failed to handle invalid format");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
msg = "(1,2,3,4,5000,6000)";
res = proxy_ftp_msg_parse_addr(p, msg, 0);
fail_unless(res == NULL, "Failed to handle invalid format");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
msg = "(0,0,0,0,1,2)";
res = proxy_ftp_msg_parse_addr(p, msg, 0);
fail_unless(res == NULL, "Failed to handle invalid format");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
msg = "(1,2,3,4,0,0)";
res = proxy_ftp_msg_parse_addr(p, msg, 0);
fail_unless(res == NULL, "Failed to handle invalid format");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
msg = "(127,0,0,1,8,73)";
res = proxy_ftp_msg_parse_addr(p, msg, 0);
fail_unless(res != NULL, "Failed to parse message '%s': %s", msg,
strerror(errno));
ip_str = pr_netaddr_get_ipstr(res);
expected = "127.0.0.1";
fail_unless(strcmp(ip_str, expected) == 0, "Expected '%s', got '%s'",
expected, ip_str);
fail_unless(ntohs(pr_netaddr_get_port(res)) == 2121,
"Expected 2121, got %u", ntohs(pr_netaddr_get_port(res)));
msg = "(195,144,107,198,8,73)";
res = proxy_ftp_msg_parse_addr(p, msg, 0);
fail_unless(res != NULL, "Failed to parse message '%s': %s", msg,
strerror(errno));
ip_str = pr_netaddr_get_ipstr(res);
expected = "195.144.107.198";
fail_unless(strcmp(ip_str, expected) == 0, "Expected '%s', got '%s'",
expected, ip_str);
fail_unless(ntohs(pr_netaddr_get_port(res)) == 2121,
"Expected 2121, got %u", ntohs(pr_netaddr_get_port(res)));
#ifdef PR_USE_IPV6
msg = "(127,0,0,1,8,73)";
res = proxy_ftp_msg_parse_addr(p, msg, AF_INET);
fail_unless(res != NULL, "Failed to parse message '%s': %s", msg,
strerror(errno));
ip_str = pr_netaddr_get_ipstr(res);
expected = "127.0.0.1";
fail_unless(strcmp(ip_str, expected) == 0, "Expected '%s', got '%s'",
expected, ip_str);
msg = "(127,0,0,1,8,73)";
res = proxy_ftp_msg_parse_addr(p, msg, AF_INET6);
fail_unless(res != NULL, "Failed to parse message '%s': %s", msg,
strerror(errno));
ip_str = pr_netaddr_get_ipstr(res);
expected = "::ffff:127.0.0.1";
fail_unless(strcmp(ip_str, expected) == 0, "Expected '%s', got '%s'",
expected, ip_str);
msg = "(195,144,107,198,8,73)";
res = proxy_ftp_msg_parse_addr(p, msg, AF_INET6);
fail_unless(res != NULL, "Failed to parse message '%s': %s", msg,
strerror(errno));
ip_str = pr_netaddr_get_ipstr(res);
expected = "::ffff:195.144.107.198";
fail_unless(strcmp(ip_str, expected) == 0, "Expected '%s', got '%s'",
expected, ip_str);
fail_unless(ntohs(pr_netaddr_get_port(res)) == 2121,
"Expected 2121, got %u", ntohs(pr_netaddr_get_port(res)));
pr_netaddr_disable_ipv6();
msg = "(127,0,0,1,8,73)";
res = proxy_ftp_msg_parse_addr(p, msg, AF_INET6);
fail_unless(res != NULL, "Failed to parse message '%s': %s", msg,
strerror(errno));
ip_str = pr_netaddr_get_ipstr(res);
expected = "127.0.0.1";
fail_unless(strcmp(ip_str, expected) == 0, "Expected '%s', got '%s'",
expected, ip_str);
pr_netaddr_enable_ipv6();
#endif /* PR_USE_IPV6 */
}
END_TEST
START_TEST (parse_ext_addr_test) {
const pr_netaddr_t *addr, *res;
const char *msg;
res = proxy_ftp_msg_parse_ext_addr(NULL, NULL, NULL, 0, NULL);
fail_unless(res == NULL, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
res = proxy_ftp_msg_parse_ext_addr(p, NULL, NULL, 0, NULL);
fail_unless(res == NULL, "Failed to handle null msg");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
msg = "foo";
res = proxy_ftp_msg_parse_ext_addr(p, msg, NULL, 0, NULL);
fail_unless(res == NULL, "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 get address for 127.0.0.1: %s",
strerror(errno));
res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, 0, NULL);
fail_unless(res == NULL, "Failed to handle bad network protocol");
fail_unless(errno == EPROTOTYPE, "Expected EPROTOTYPE (%d), got '%s' (%d)",
EPROTOTYPE, strerror(errno), errno);
/* EPSV response formats */
res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
fail_unless(res == NULL, "Failed to handle bad EPSV response");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
msg = "(foo";
res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
fail_unless(res == NULL, "Failed to handle bad EPSV response");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
msg = "(foo)";
res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
fail_unless(res == NULL, "Failed to handle bad network protocol");
fail_unless(errno == EPROTOTYPE, "Expected EPROTOTYPE (%d), got '%s' (%d)",
EPROTOTYPE, strerror(errno), errno);
msg = "(1)";
res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
fail_unless(res == NULL, "Failed to handle bad network protocol");
fail_unless(errno == EPROTOTYPE, "Expected EPROTOTYPE (%d), got '%s' (%d)",
EPROTOTYPE, strerror(errno), errno);
msg = "(|4)";
res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
fail_unless(res == NULL, "Failed to handle bad network protocol");
fail_unless(errno == EPROTOTYPE, "Expected EPROTOTYPE (%d), got '%s' (%d)",
EPROTOTYPE, strerror(errno), errno);
msg = "(|0)";
res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
fail_unless(res == NULL, "Failed to handle bad network protocol");
fail_unless(errno == EPROTOTYPE, "Expected EPROTOTYPE (%d), got '%s' (%d)",
EPROTOTYPE, strerror(errno), errno);
msg = "(|1)";
res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
fail_unless(res == NULL, "Failed to handle bad network protocol");
fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
strerror(errno), errno);
msg = "(|2)";
res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
fail_unless(res == NULL, "Failed to handle bad network protocol");
fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
strerror(errno), errno);
/* Where the network protocol matches that of the address... */
msg = "(|1|)";
res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
fail_unless(res == NULL, "Failed to handle badly formatted message");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
msg = "(|1|1.2.3.4)";
res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
fail_unless(res == NULL, "Failed to handle badly formatted message");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
msg = "(|1|1.2.3.4|5)";
res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
fail_unless(res == NULL, "Failed to handle badly formatted message");
fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
strerror(errno), errno);
msg = "(|1|1.2.3.4|5|)";
res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
fail_unless(res != NULL, "Failed to handle formatted message '%s': %s", msg,
strerror(errno));
msg = "(||1.2.3.4|5|)";
res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
fail_unless(res != NULL, "Failed to handle formatted message '%s': %s", msg,
strerror(errno));
msg = "(||1.2.3.4|5|)";
res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, "all");
fail_unless(res != NULL, "Failed to handle formatted message '%s': %s", msg,
strerror(errno));
msg = "(||1.2.3.4|5|)";
res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, "1");
fail_unless(res != NULL, "Failed to handle formatted message '%s': %s", msg,
strerror(errno));
msg = "(|||5|)";
res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
fail_unless(res != NULL, "Failed to handle formatted message '%s': %s", msg,
strerror(errno));
fail_unless(
strcmp(pr_netaddr_get_ipstr(addr), pr_netaddr_get_ipstr(res)) == 0,
"Expected '%s', got '%s'", pr_netaddr_get_ipstr(addr),
pr_netaddr_get_ipstr(res));
/* ...and where the network protocol does not match that of the address. */
msg = "(||::1|5|)";
res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
fail_unless(res == NULL, "Failed to handle network protocol mismatch");
fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
strerror(errno), errno);
msg = "(|2|1.2.3.4|5)";
res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
fail_unless(res == NULL, "Failed to handle network protocol mismatch");
fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
strerror(errno), errno);
#ifdef PR_USE_IPV6
addr = pr_netaddr_get_addr(p, "::1", NULL);
fail_unless(addr != NULL, "Failed to get address for ::1: %s",
strerror(errno));
msg = "(|2|1.2.3.4|5)";
res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
fail_unless(res == NULL, "Failed to handle network protocol mismatch");
fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
strerror(errno), errno);
msg = "(|1|::1|5)";
res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
fail_unless(res == NULL, "Failed to handle network protocol mismatch");
fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
strerror(errno), errno);
msg = "(|2|::1|5)";
res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
fail_unless(res == NULL, "Failed to handle network protocol mismatch");
fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
strerror(errno), errno);
msg = "(|2|::1|5|)";
res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
fail_unless(res != NULL, "Failed to handle formatted message '%s': %s", msg,
strerror(errno));
msg = "(|2|::1|5|)";
res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, "ALL");
fail_unless(res != NULL, "Failed to handle formatted message '%s': %s", msg,
strerror(errno));
msg = "(||::1|5|)";
res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, "2");
fail_unless(res != NULL, "Failed to handle formatted message '%s': %s", msg,
strerror(errno));
msg = "(||::1|5|)";
res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
fail_unless(res != NULL, "Failed to handle formatted message '%s': %s", msg,
strerror(errno));
msg = "(|||5|)";
res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
fail_unless(res != NULL, "Failed to handle formatted message '%s': %s", msg,
strerror(errno));
fail_unless(
strcmp(pr_netaddr_get_ipstr(addr), pr_netaddr_get_ipstr(res)) == 0,
"Expected '%s', got '%s'", pr_netaddr_get_ipstr(addr),
pr_netaddr_get_ipstr(res));
msg = "(||1.2.3.4|5|)";
res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
fail_unless(res == NULL, "Failed to handle network protocol mismatch");
fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
strerror(errno), errno);
#endif /* PR_USE_IPV6 */
}
END_TEST
Suite *tests_get_ftp_msg_suite(void) {
Suite *suite;
TCase *testcase;
suite = suite_create("ftp.msg");
testcase = tcase_create("base");
tcase_add_checked_fixture(testcase, set_up, tear_down);
tcase_add_test(testcase, fmt_addr_test);
tcase_add_test(testcase, fmt_ext_addr_test);
tcase_add_test(testcase, parse_addr_test);
tcase_add_test(testcase, parse_ext_addr_test);
suite_add_tcase(suite, testcase);
return suite;
}
proftpd-mod_proxy-0.8/t/api/ftp/sess.c 0000664 0000000 0000000 00000012400 14020740307 0017775 0 ustar 00root root 0000000 0000000 /*
* ProFTPD - mod_proxy testsuite
* Copyright (c) 2016 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
*
* As a special exemption, TJ Saunders and other respective copyright holders
* give permission to link this program with OpenSSL, and distribute the
* resulting executable, without including the source code for OpenSSL in the
* source distribution.
*/
/* FTP Session API tests. */
#include "../tests.h"
static pool *p = NULL;
static void set_up(void) {
if (p == NULL) {
p = permanent_pool = session.pool = make_sub_pool(NULL);
session.c = NULL;
session.notes = NULL;
}
init_netaddr();
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("proxy.ftp.sess", 1, 20);
}
}
static void tear_down(void) {
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("proxy.ftp.sess", 0, 0);
}
if (p) {
destroy_pool(p);
p = permanent_pool = session.pool = NULL;
session.c = NULL;
session.notes = NULL;
}
}
START_TEST (get_feat_test) {
int res;
const struct proxy_session *proxy_sess = NULL;
res = proxy_ftp_sess_get_feat(NULL, NULL);
fail_unless(res < 0, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
res = proxy_ftp_sess_get_feat(p, NULL);
fail_unless(res < 0, "Failed to handle null proxy session");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
proxy_sess = proxy_session_alloc(p);
mark_point();
res = proxy_ftp_sess_get_feat(p, proxy_sess);
fail_unless(res < 0, "Failed to handle null proxy session");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
proxy_session_free(p, proxy_sess);
}
END_TEST
START_TEST (send_auth_tls_test) {
int res;
const struct proxy_session *proxy_sess = NULL;
res = proxy_ftp_sess_send_auth_tls(NULL, NULL);
fail_unless(res < 0, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
res = proxy_ftp_sess_send_auth_tls(p, NULL);
fail_unless(res < 0, "Failed to handle null proxy session");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
proxy_sess = proxy_session_alloc(p);
mark_point();
res = proxy_ftp_sess_send_auth_tls(p, proxy_sess);
#ifdef PR_USE_OPENSSL
fail_unless(res < 0, "Sent AUTH TLS unexpectedly");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
#endif /* PR_USE_OPENSSL */
proxy_session_free(p, proxy_sess);
}
END_TEST
START_TEST (send_host_test) {
int res;
const struct proxy_session *proxy_sess = NULL;
res = proxy_ftp_sess_send_host(NULL, NULL);
fail_unless(res < 0, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
res = proxy_ftp_sess_send_host(p, NULL);
fail_unless(res < 0, "Failed to handle null proxy session");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
proxy_sess = proxy_session_alloc(p);
mark_point();
res = proxy_ftp_sess_send_host(p, proxy_sess);
fail_unless(res == 0, "Failed to (maybe) send HOST: %s", strerror(errno));
proxy_session_free(p, proxy_sess);
}
END_TEST
START_TEST (send_pbsz_prot_test) {
int res;
const struct proxy_session *proxy_sess = NULL;
res = proxy_ftp_sess_send_pbsz_prot(NULL, NULL);
fail_unless(res < 0, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
res = proxy_ftp_sess_send_pbsz_prot(p, NULL);
fail_unless(res < 0, "Failed to handle null proxy session");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
proxy_sess = proxy_session_alloc(p);
mark_point();
res = proxy_ftp_sess_send_pbsz_prot(p, proxy_sess);
fail_unless(res == 0, "Failed to (maybe) send PBSZ/PROT: %s",
strerror(errno));
proxy_session_free(p, proxy_sess);
}
END_TEST
Suite *tests_get_ftp_sess_suite(void) {
Suite *suite;
TCase *testcase;
suite = suite_create("ftp.sess");
testcase = tcase_create("base");
tcase_add_checked_fixture(testcase, set_up, tear_down);
tcase_add_test(testcase, get_feat_test);
tcase_add_test(testcase, send_auth_tls_test);
tcase_add_test(testcase, send_host_test);
tcase_add_test(testcase, send_pbsz_prot_test);
suite_add_tcase(suite, testcase);
return suite;
}
proftpd-mod_proxy-0.8/t/api/ftp/xfer.c 0000664 0000000 0000000 00000022476 14020740307 0020002 0 ustar 00root root 0000000 0000000 /*
* ProFTPD - mod_proxy testsuite
* Copyright (c) 2016 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
*
* As a special exemption, TJ Saunders and other respective copyright holders
* give permission to link this program with OpenSSL, and distribute the
* resulting executable, without including the source code for OpenSSL in the
* source distribution.
*/
/* FTP Transfer API tests. */
#include "../tests.h"
extern xaset_t *server_list;
static pool *p = NULL;
static void create_main_server(void) {
server_rec *s;
s = pr_parser_server_ctxt_open("127.0.0.1");
s->ServerName = "Test Server";
main_server = s;
}
static void set_up(void) {
if (p == NULL) {
p = permanent_pool = session.pool = make_sub_pool(NULL);
main_server = NULL;
server_list = NULL;
session.c = NULL;
session.notes = NULL;
}
init_config();
init_netaddr();
init_netio();
init_inet();
server_list = xaset_create(p, NULL);
pr_parser_prepare(p, &server_list);
create_main_server();
pr_response_set_pool(p);
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("proxy.ftp.conn", 1, 20);
pr_trace_set_levels("proxy.ftp.xfer", 1, 20);
}
pr_inet_set_default_family(p, AF_INET);
}
static void tear_down(void) {
pr_inet_set_default_family(p, 0);
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("proxy.ftp.conn", 0, 0);
pr_trace_set_levels("proxy.ftp.xfer", 0, 0);
}
pr_response_set_pool(NULL);
pr_parser_cleanup();
pr_inet_clear();
if (p) {
destroy_pool(p);
p = permanent_pool = session.pool = NULL;
main_server = NULL;
server_list = NULL;
session.c = NULL;
session.notes = NULL;
}
}
START_TEST (prepare_active_test) {
int res;
cmd_rec *cmd;
struct proxy_session *proxy_sess = NULL;
res = proxy_ftp_xfer_prepare_active(0, NULL, NULL, NULL, 0);
fail_unless(res < 0, "Failed to handle null command");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
cmd = pr_cmd_alloc(p, 1, "FOO");
res = proxy_ftp_xfer_prepare_active(0, cmd, NULL, NULL, 0);
fail_unless(res < 0, "Failed to handle null error code");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
res = proxy_ftp_xfer_prepare_active(0, cmd, "500", NULL, 0);
fail_unless(res < 0, "Failed to handle null proxy session");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
proxy_sess = (struct proxy_session *) proxy_session_alloc(p);
mark_point();
res = proxy_ftp_xfer_prepare_active(0, cmd, "500", proxy_sess, 0);
fail_unless(res < 0, "Failed to handle null proxy session");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
proxy_sess->backend_ctrl_conn = pr_inet_create_conn(p, -1, NULL, INPORT_ANY,
FALSE);
fail_unless(proxy_sess->backend_ctrl_conn != NULL,
"Failed to open backend control conn: %s", strerror(errno));
session.c = pr_inet_create_conn(p, -1, NULL, INPORT_ANY, FALSE);
fail_unless(session.c != NULL,
"Failed to open session control conn: %s", strerror(errno));
session.c->local_addr = session.c->remote_addr = pr_netaddr_get_addr(p,
"127.0.0.1", NULL);
fail_unless(session.c->remote_addr != NULL, "Failed to get address: %s",
strerror(errno));
mark_point();
res = proxy_ftp_xfer_prepare_active(0, cmd, "500", proxy_sess, 0);
fail_unless(res < 0, "Failed to handle illegal FTP command");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
/* Prevent NULL pointer dereferences which would only happen during
* testing.
*/
proxy_sess->backend_ctrl_conn->remote_addr = session.c->remote_addr;
mark_point();
res = proxy_ftp_xfer_prepare_active(PR_CMD_PORT_ID, cmd, "500", proxy_sess,
0);
fail_unless(res < 0, "Failed to handle bad PORT command");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
mark_point();
res = proxy_ftp_xfer_prepare_active(PR_CMD_EPRT_ID, cmd, "500", proxy_sess,
0);
fail_unless(res < 0, "Failed to handle bad EPRT command");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
cmd = pr_cmd_alloc(p, 1, "EPRT");
mark_point();
res = proxy_ftp_xfer_prepare_active(0, cmd, "500", proxy_sess, 0);
fail_unless(res < 0, "Failed to handle bad EPRT command");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
cmd = pr_cmd_alloc(p, 1, "PORT");
mark_point();
res = proxy_ftp_xfer_prepare_active(0, cmd, "500", proxy_sess, 0);
fail_unless(res < 0, "Failed to handle bad PORT command");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
pr_inet_close(p, session.c);
proxy_session_free(p, proxy_sess);
}
END_TEST
START_TEST (prepare_passive_test) {
const pr_netaddr_t *addr;
cmd_rec *cmd;
struct proxy_session *proxy_sess;
addr = proxy_ftp_xfer_prepare_passive(0, NULL, NULL, NULL, 0);
fail_unless(addr == NULL, "Failed to handle null command");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
cmd = pr_cmd_alloc(p, 1, "FOO");
addr = proxy_ftp_xfer_prepare_passive(0, cmd, NULL, NULL, 0);
fail_unless(addr == NULL, "Failed to handle null error code");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
addr = proxy_ftp_xfer_prepare_passive(0, cmd, "500", NULL, 0);
fail_unless(addr == NULL, "Failed to handle null proxy session");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
proxy_sess = (struct proxy_session *) proxy_session_alloc(p);
mark_point();
addr = proxy_ftp_xfer_prepare_passive(0, cmd, "500", proxy_sess, 0);
fail_unless(addr == NULL, "Failed to handle null proxy session");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
proxy_sess->backend_ctrl_conn = pr_inet_create_conn(p, -1, NULL, INPORT_ANY,
FALSE);
fail_unless(proxy_sess->backend_ctrl_conn != NULL,
"Failed to open backend control conn: %s", strerror(errno));
session.c = pr_inet_create_conn(p, -1, NULL, INPORT_ANY, FALSE);
fail_unless(session.c != NULL,
"Failed to open session control conn: %s", strerror(errno));
session.c->local_addr = session.c->remote_addr = pr_netaddr_get_addr(p,
"127.0.0.1", NULL);
fail_unless(session.c->remote_addr != NULL, "Failed to get address: %s",
strerror(errno));
mark_point();
addr = proxy_ftp_xfer_prepare_passive(0, cmd, "500", proxy_sess, 0);
fail_unless(addr == NULL, "Failed to handle illegal FTP command");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
/* Prevent NULL pointer dereferences which would only happen during
* testing.
*/
proxy_sess->backend_ctrl_conn->remote_addr = session.c->remote_addr;
mark_point();
addr = proxy_ftp_xfer_prepare_passive(PR_CMD_PASV_ID, cmd, "500", proxy_sess,
0);
fail_unless(addr == NULL, "Failed to handle bad PASV command");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
mark_point();
addr = proxy_ftp_xfer_prepare_passive(PR_CMD_EPSV_ID, cmd, "500", proxy_sess,
0);
fail_unless(addr == NULL, "Failed to handle bad EPSV command");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
cmd = pr_cmd_alloc(p, 1, "EPSV");
mark_point();
addr = proxy_ftp_xfer_prepare_passive(0, cmd, "500", proxy_sess, 0);
fail_unless(addr == NULL, "Failed to handle bad EPSV command");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
cmd = pr_cmd_alloc(p, 1, "PASV");
mark_point();
addr = proxy_ftp_xfer_prepare_passive(0, cmd, "500", proxy_sess, 0);
fail_unless(addr == NULL, "Failed to handle bad PASV command");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
pr_inet_close(p, session.c);
proxy_session_free(p, proxy_sess);
}
END_TEST
Suite *tests_get_ftp_xfer_suite(void) {
Suite *suite;
TCase *testcase;
suite = suite_create("ftp.xfer");
testcase = tcase_create("base");
tcase_add_checked_fixture(testcase, set_up, tear_down);
tcase_add_test(testcase, prepare_active_test);
tcase_add_test(testcase, prepare_passive_test);
suite_add_tcase(suite, testcase);
return suite;
}
proftpd-mod_proxy-0.8/t/api/inet.c 0000664 0000000 0000000 00000026275 14020740307 0017205 0 ustar 00root root 0000000 0000000 /*
* ProFTPD - mod_proxy testsuite
* Copyright (c) 2015-2017 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
*
* As a special exemption, TJ Saunders and other respective copyright holders
* give permission to link this program with OpenSSL, and distribute the
* resulting executable, without including the source code for OpenSSL in the
* source distribution.
*/
/* Proxy Inet API tests. */
#include "tests.h"
static pool *p = NULL;
/* Fixtures */
static void set_up(void) {
if (p == NULL) {
p = permanent_pool = make_sub_pool(NULL);
session.c = NULL;
session.notes = NULL;
}
init_netaddr();
init_netio();
init_inet();
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("netio", 1, 20);
pr_trace_set_levels("inet", 1, 20);
pr_trace_set_levels("proxy.inet", 1, 20);
}
pr_inet_set_default_family(p, AF_INET);
}
static void tear_down(void) {
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("netio", 0, 0);
pr_trace_set_levels("inet", 0, 0);
pr_trace_set_levels("proxy.inet", 0, 0);
}
pr_inet_set_default_family(p, 0);
pr_inet_clear();
if (p) {
destroy_pool(p);
p = permanent_pool = NULL;
session.c = NULL;
session.notes = NULL;
}
}
/* Tests */
START_TEST (inet_accept_test) {
conn_t *conn;
mark_point();
conn = proxy_inet_accept(NULL, NULL, NULL, -1, -1, FALSE);
fail_unless(conn == NULL, "Failed to handle null arguments");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
}
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_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);
}
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 || errno == EADDRNOTAVAIL,
"Expected ECONNREFUSED (%d), ENETUNREACH (%d), or EADDRNOTAVAIL (%d), got %s (%d)",
ECONNREFUSED, ENETUNREACH, EADDRNOTAVAIL, 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 == ECONNREFUSED || errno == ENETUNREACH || errno == EADDRNOTAVAIL,
"Expected ECONNREFUSED (%d), ENETUNREACH (%d), or EADDRNOTAVAIL (%d), got %s (%d)",
ECONNREFUSED, ENETUNREACH, EADDRNOTAVAIL, 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_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);
}
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
Suite *tests_get_inet_suite(void) {
Suite *suite;
TCase *testcase;
suite = suite_create("inet");
testcase = tcase_create("base");
tcase_add_checked_fixture(testcase, set_up, tear_down);
tcase_add_test(testcase, inet_accept_test);
tcase_add_test(testcase, inet_close_test);
tcase_add_test(testcase, inet_connect_ipv4_test);
tcase_add_test(testcase, inet_connect_ipv6_test);
tcase_add_test(testcase, inet_listen_test);
tcase_add_test(testcase, inet_openrw_test);
suite_add_tcase(suite, testcase);
return suite;
}
proftpd-mod_proxy-0.8/t/api/netio.c 0000664 0000000 0000000 00000033622 14020740307 0017356 0 ustar 00root root 0000000 0000000 /*
* ProFTPD - mod_proxy testsuite
* Copyright (c) 2015-2020 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
*
* As a special exemption, TJ Saunders and other respective copyright holders
* give permission to link this program with OpenSSL, and distribute the
* resulting executable, without including the source code for OpenSSL in the
* source distribution.
*/
/* Proxy NetIO API tests. */
#include "tests.h"
static pool *p = NULL;
static void set_up(void) {
if (p == NULL) {
p = permanent_pool = make_sub_pool(NULL);
session.c = NULL;
session.notes = NULL;
}
init_netio();
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("netio", 1, 20);
pr_trace_set_levels("proxy.netio", 1, 20);
}
}
static void tear_down(void) {
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("netio", 0, 0);
pr_trace_set_levels("proxy.netio", 0, 0);
}
if (p) {
destroy_pool(p);
p = permanent_pool = NULL;
session.c = NULL;
session.notes = NULL;
}
}
START_TEST (netio_close_test) {
int res;
res = proxy_netio_close(NULL);
fail_unless(res < 0, "Failed to handle null stream");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
}
END_TEST
START_TEST (netio_open_test) {
int res;
pr_netio_stream_t *nstrm;
nstrm = proxy_netio_open(NULL, 0, -1, PR_NETIO_IO_RD);
fail_unless(nstrm == NULL, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
nstrm = proxy_netio_open(p, 77, -1, PR_NETIO_IO_RD);
fail_unless(nstrm == NULL, "Failed to handle unsupported stream type");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
nstrm = proxy_netio_open(p, PR_NETIO_STRM_OTHR, -1, PR_NETIO_IO_RD);
fail_unless(nstrm != NULL, "Failed to handle othr stream type: %s",
strerror(errno));
res = proxy_netio_close(nstrm);
fail_unless(res < 0, "Successfully closed stream unexpectedly");
fail_unless(errno == EBADF, "Expected EBADF (%d), got '%s' (%d)", EBADF,
strerror(errno), errno);
}
END_TEST
START_TEST (netio_poll_test) {
int res;
pr_netio_stream_t *nstrm;
res = proxy_netio_poll(NULL);
fail_unless(res < 0, "Failed to handle null stream");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
nstrm = proxy_netio_open(p, PR_NETIO_STRM_OTHR, -1, PR_NETIO_IO_RD);
fail_unless(nstrm != NULL, "Failed to handle othr stream type: %s",
strerror(errno));
res = proxy_netio_poll(nstrm);
fail_unless(res < 0, "Polled stream unexpectedly");
fail_unless(errno == EBADF, "Expected EBADF (%d), got '%s' (%d)", EBADF,
strerror(errno), errno);
res = proxy_netio_close(nstrm);
fail_unless(res < 0, "Successfully closed stream unexpectedly");
fail_unless(errno == EBADF, "Expected EBADF (%d), got '%s' (%d)", EBADF,
strerror(errno), errno);
}
END_TEST
START_TEST (netio_postopen_test) {
int res;
pr_netio_stream_t *nstrm;
res = proxy_netio_postopen(NULL);
fail_unless(res < 0, "Failed to handle null stream");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
nstrm = proxy_netio_open(p, PR_NETIO_STRM_OTHR, -1, PR_NETIO_IO_RD);
fail_unless(nstrm != NULL, "Failed to handle othr stream type: %s",
strerror(errno));
res = proxy_netio_postopen(nstrm);
fail_unless(res == 0, "Failed to postopen stream: %s", strerror(errno));
res = proxy_netio_close(nstrm);
fail_unless(res < 0, "Successfully closed stream unexpectedly");
fail_unless(errno == EBADF, "Expected EBADF (%d), got '%s' (%d)", EBADF,
strerror(errno), errno);
}
END_TEST
START_TEST (netio_printf_test) {
int res;
pr_netio_stream_t *nstrm;
res = proxy_netio_printf(NULL, "%s", "foo");
fail_unless(res < 0, "Failed to handle null stream");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
nstrm = proxy_netio_open(p, PR_NETIO_STRM_OTHR, -1, PR_NETIO_IO_RD);
fail_unless(nstrm != NULL, "Failed to handle othr stream type: %s",
strerror(errno));
res = proxy_netio_printf(nstrm, "%d", 7);
fail_unless(res < 0, "Failed to handle null stream");
fail_unless(errno == EBADF, "Expected EBADF (%d), got '%s' (%d)", EBADF,
strerror(errno), errno);
res = proxy_netio_close(nstrm);
fail_unless(res < 0, "Successfully closed stream unexpectedly");
fail_unless(errno == EBADF, "Expected EBADF (%d), got '%s' (%d)", EBADF,
strerror(errno), errno);
}
END_TEST
START_TEST (netio_read_test) {
int res;
pr_netio_stream_t *nstrm;
char *buf;
size_t bufsz;
bufsz = 1024;
buf = palloc(p, bufsz);
mark_point();
res = proxy_netio_read(NULL, buf, bufsz, 1);
fail_unless(res < 0, "Failed to handle null stream");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
nstrm = proxy_netio_open(p, PR_NETIO_STRM_OTHR, -1, PR_NETIO_IO_RD);
fail_unless(nstrm != NULL, "Failed to handle othr stream type: %s",
strerror(errno));
mark_point();
res = proxy_netio_read(nstrm, buf, bufsz, 1);
fail_unless(res < 0, "Successfully read from stream unexpectedly");
fail_unless(errno == EBADF, "Expected EBADF (%d), got '%s' (%d)", EBADF,
strerror(errno), errno);
res = proxy_netio_close(nstrm);
fail_unless(res < 0, "Successfully closed stream unexpectedly");
fail_unless(errno == EBADF, "Expected EBADF (%d), got '%s' (%d)", EBADF,
strerror(errno), errno);
}
END_TEST
START_TEST (netio_reset_poll_interval_test) {
int res;
pr_netio_stream_t *nstrm;
mark_point();
proxy_netio_reset_poll_interval(NULL);
nstrm = proxy_netio_open(p, PR_NETIO_STRM_OTHR, -1, PR_NETIO_IO_RD);
fail_unless(nstrm != NULL, "Failed to handle othr stream type: %s",
strerror(errno));
mark_point();
proxy_netio_reset_poll_interval(nstrm);
res = proxy_netio_close(nstrm);
fail_unless(res < 0, "Successfully closed stream unexpectedly");
fail_unless(errno == EBADF, "Expected EBADF (%d), got '%s' (%d)", EBADF,
strerror(errno), errno);
}
END_TEST
START_TEST (netio_set_poll_interval_test) {
int res;
pr_netio_stream_t *nstrm;
mark_point();
proxy_netio_set_poll_interval(NULL, 1);
nstrm = proxy_netio_open(p, PR_NETIO_STRM_OTHR, -1, PR_NETIO_IO_RD);
fail_unless(nstrm != NULL, "Failed to handle othr stream type: %s",
strerror(errno));
mark_point();
proxy_netio_set_poll_interval(nstrm, 1);
res = proxy_netio_close(nstrm);
fail_unless(res < 0, "Successfully closed stream unexpectedly");
fail_unless(errno == EBADF, "Expected EBADF (%d), got '%s' (%d)", EBADF,
strerror(errno), errno);
}
END_TEST
START_TEST (netio_shutdown_test) {
int res;
pr_netio_stream_t *nstrm;
mark_point();
res = proxy_netio_shutdown(NULL, 0);
fail_unless(res < 0, "Failed to handle null stream");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
nstrm = proxy_netio_open(p, PR_NETIO_STRM_OTHR, -1, PR_NETIO_IO_RD);
fail_unless(nstrm != NULL, "Failed to handle othr stream type: %s",
strerror(errno));
mark_point();
res = proxy_netio_shutdown(nstrm, 0);
fail_unless(res < 0, "Successfully shutdown stream unexpectedly");
fail_unless(errno == EBADF, "Expected EBADF (%d), got '%s' (%d)", EBADF,
strerror(errno), errno);
res = proxy_netio_close(nstrm);
fail_unless(res < 0, "Successfully closed stream unexpectedly");
fail_unless(errno == EBADF, "Expected EBADF (%d), got '%s' (%d)", EBADF,
strerror(errno), errno);
}
END_TEST
START_TEST (netio_write_test) {
int res;
pr_netio_stream_t *nstrm;
mark_point();
res = proxy_netio_write(NULL, "foo", 3);
fail_unless(res < 0, "Failed to handle null stream");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
nstrm = proxy_netio_open(p, PR_NETIO_STRM_OTHR, -1, PR_NETIO_IO_RD);
fail_unless(nstrm != NULL, "Failed to handle othr stream type: %s",
strerror(errno));
mark_point();
res = proxy_netio_write(nstrm, "foo", 1);
fail_unless(res < 0, "Wrote to stream unexpectedly");
fail_unless(errno == EBADF, "Expected EBADF (%d), got '%s' (%d)", EBADF,
strerror(errno), errno);
res = proxy_netio_close(nstrm);
fail_unless(res < 0, "Successfully closed stream unexpectedly");
fail_unless(errno == EBADF, "Expected EBADF (%d), got '%s' (%d)", EBADF,
strerror(errno), errno);
}
END_TEST
START_TEST (netio_set_test) {
pr_netio_t *netio = NULL;
int res, strm_type = PR_NETIO_STRM_OTHR;
netio = proxy_netio_unset(strm_type, NULL);
fail_unless(netio == NULL, "Failed to handle null function string");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
netio = proxy_netio_unset(strm_type, "foo");
fail_unless(netio == NULL, "Expected null othr NetIO, got %p", netio);
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
res = proxy_netio_set(strm_type, netio);
fail_unless(res == 0, "Failed to set null othr netio: %s", strerror(errno));
strm_type = PR_NETIO_STRM_CTRL;
res = proxy_netio_set(strm_type, netio);
fail_unless(res == 0, "Failed to set null ctrl netio: %s", strerror(errno));
res = proxy_netio_set(strm_type, netio);
fail_unless(res == 0, "Failed to set null ctrl netio again: %s",
strerror(errno));
netio = pr_alloc_netio2(p, NULL, "testsuite");
res = proxy_netio_set(strm_type, netio);
fail_unless(res == 0, "Failed to set ctrl netio: %s", strerror(errno));
res = proxy_netio_set(strm_type, netio);
fail_unless(res == 0, "Failed to set ctrl netio again: %s", strerror(errno));
netio = proxy_netio_unset(strm_type, "testcase");
fail_unless(netio != NULL, "Failed to unset ctrl netio: %s", strerror(errno));
strm_type = PR_NETIO_STRM_DATA;
netio = NULL;
res = proxy_netio_set(strm_type, netio);
fail_unless(res == 0, "Failed to set null data netio: %s", strerror(errno));
res = proxy_netio_set(strm_type, netio);
fail_unless(res == 0, "Failed to set null data netio again: %s",
strerror(errno));
netio = pr_alloc_netio2(p, NULL, "testsuite");
res = proxy_netio_set(strm_type, netio);
fail_unless(res == 0, "Failed to set data netio: %s", strerror(errno));
res = proxy_netio_set(strm_type, netio);
fail_unless(res == 0, "Failed to set data netio again: %s", strerror(errno));
netio = proxy_netio_unset(strm_type, "testcase");
fail_unless(netio != NULL, "Failed to unset data netio: %s", strerror(errno));
}
END_TEST
START_TEST (netio_use_test) {
pr_netio_t *netio = NULL;
int res, strm_type = PR_NETIO_STRM_OTHR;
res = proxy_netio_using(strm_type, NULL);
fail_unless(res < 0, "Failed to handle null argument");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
res = proxy_netio_using(strm_type, &netio);
fail_unless(res < 0, "Failed to handle othr stream type");
fail_unless(errno == ENOENT, "Expected ENOENT (%d), got '%s' (%d)", ENOENT,
strerror(errno), errno);
res = proxy_netio_using(PR_NETIO_STRM_CTRL, &netio);
fail_unless(res == 0, "Failed to handle ctrl stream type: %s",
strerror(errno));
fail_unless(netio == NULL, "Expected null ctrl netio, got %p", netio);
res = proxy_netio_using(PR_NETIO_STRM_DATA, &netio);
fail_unless(res == 0, "Failed to handle data stream type: %s",
strerror(errno));
fail_unless(netio == NULL, "Expected null data netio, got %p", netio);
res = proxy_netio_use(strm_type, NULL);
fail_unless(res < 0, "Failed to handle othr stream type");
fail_unless(errno == ENOSYS, "Expected ENOSYS (%d), got '%s' (%d)", ENOSYS,
strerror(errno), errno);
res = proxy_netio_use(PR_NETIO_STRM_CTRL, NULL);
fail_unless(res == 0, "Failed to handle ctrl stream type: %s",
strerror(errno));
netio = proxy_netio_unset(PR_NETIO_STRM_CTRL, "testcase");
fail_unless(netio == NULL, "Unset ctrl stream unexpectedly");
fail_unless(errno == ENOSYS, "Expected ENOSYS (%d), got '%s' (%d)", ENOSYS,
strerror(errno), errno);
res = proxy_netio_use(PR_NETIO_STRM_DATA, NULL);
fail_unless(res == 0, "Failed to handle data stream type: %s",
strerror(errno));
netio = proxy_netio_unset(PR_NETIO_STRM_DATA, "testcase");
fail_unless(netio == NULL, "Unset data stream unexpectedly");
fail_unless(errno == ENOSYS, "Expected ENOSYS (%d), got '%s' (%d)", ENOSYS,
strerror(errno), errno);
}
END_TEST
Suite *tests_get_netio_suite(void) {
Suite *suite;
TCase *testcase;
suite = suite_create("netio");
testcase = tcase_create("base");
tcase_add_checked_fixture(testcase, set_up, tear_down);
tcase_add_test(testcase, netio_close_test);
tcase_add_test(testcase, netio_open_test);
tcase_add_test(testcase, netio_poll_test);
tcase_add_test(testcase, netio_postopen_test);
tcase_add_test(testcase, netio_printf_test);
tcase_add_test(testcase, netio_read_test);
tcase_add_test(testcase, netio_reset_poll_interval_test);
tcase_add_test(testcase, netio_set_poll_interval_test);
tcase_add_test(testcase, netio_shutdown_test);
tcase_add_test(testcase, netio_write_test);
tcase_add_test(testcase, netio_set_test);
tcase_add_test(testcase, netio_use_test);
suite_add_tcase(suite, testcase);
return suite;
}
proftpd-mod_proxy-0.8/t/api/random.c 0000664 0000000 0000000 00000005412 14020740307 0017514 0 ustar 00root root 0000000 0000000 /*
* ProFTPD - mod_proxy testsuite
* Copyright (c) 2013-2016 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
*
* As a special exemption, TJ Saunders and other respective copyright holders
* give permission to link this program with OpenSSL, and distribute the
* resulting executable, without including the source code for OpenSSL in the
* source distribution.
*/
/* Random API tests. */
#include "tests.h"
static pool *p = NULL;
static void set_up(void) {
if (p == NULL) {
p = make_sub_pool(NULL);
session.c = NULL;
session.notes = NULL;
}
proxy_random_init();
}
static void tear_down(void) {
if (p) {
destroy_pool(p);
p = NULL;
session.c = NULL;
session.notes = NULL;
}
}
START_TEST (random_next_range_10_test) {
register unsigned int i;
long min, max;
min = -4;
max = 5;
for (i = 0; i < 10; i++) {
long num;
num = proxy_random_next(min, max);
fail_if(num < min, "random number %ld less than minimum %ld", num, min);
fail_if(num > max, "random number %ld greater than maximum %ld", num, max);
}
}
END_TEST
START_TEST (random_next_range_1000_test) {
register int i;
long min, max;
int count = 10, seen[10];
min = 0;
max = count-1;
memset(seen, 0, sizeof(seen));
for (i = 0; i < 1000; i++) {
long num;
num = proxy_random_next(min, max);
fail_if(num < min, "random number %ld less than minimum %ld", num, min);
fail_if(num > max, "random number %ld greater than maximum %ld", num, max);
seen[num] = 1;
}
/* In 1000 rounds, the chances of seeing all 10 possible numbers is pretty
* good, right?
*/
for (i = 0; i < count; i++) {
fail_unless(seen[i] == 1, "Expected to have generated number %d", i);
}
}
END_TEST
Suite *tests_get_random_suite(void) {
Suite *suite;
TCase *testcase;
suite = suite_create("random");
testcase = tcase_create("base");
tcase_add_checked_fixture(testcase, set_up, tear_down);
tcase_add_test(testcase, random_next_range_10_test);
tcase_add_test(testcase, random_next_range_1000_test);
suite_add_tcase(suite, testcase);
return suite;
}
proftpd-mod_proxy-0.8/t/api/reverse.c 0000664 0000000 0000000 00000074552 14020740307 0017722 0 ustar 00root root 0000000 0000000 /*
* ProFTPD - mod_proxy testsuite
* Copyright (c) 2013-2020 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
*
* As a special exemption, TJ Saunders and other respective copyright holders
* give permission to link this program with OpenSSL, and distribute the
* resulting executable, without including the source code for OpenSSL in the
* source distribution.
*/
/* Reverse-proxy API tests */
#include "tests.h"
extern xaset_t *server_list;
static pool *p = NULL;
static const char *test_dir = "/tmp/mod_proxy-test-reverse";
static const char *test_file = "/tmp/mod_proxy-test-reverse/servers.json";
static config_rec *policy_config = NULL;
static void create_main_server(void) {
server_rec *s;
s = pr_parser_server_ctxt_open("127.0.0.1");
s->ServerName = "Test Server";
main_server = s;
}
static void test_cleanup(pool *cleanup_pool) {
(void) unlink(test_file);
(void) tests_rmpath(cleanup_pool, test_dir);
}
static FILE *test_prep(void) {
int res;
mode_t perms;
FILE *fh;
perms = 0770;
res = mkdir(test_dir, perms);
if (res < 0 &&
errno != EEXIST) {
fail_unless(res == 0, "Failed to create tmp directory '%s': %s", test_dir,
strerror(errno));
}
res = chmod(test_dir, perms);
fail_unless(res == 0, "Failed to set perms %04o on directory '%s': %s",
perms, test_dir, strerror(errno));
fh = fopen(test_file, "w+");
fail_if(fh == NULL, "Failed to create tmp file '%s': %s", test_file,
strerror(errno));
perms = 0660;
res = chmod(test_file, perms);
fail_unless(res == 0, "Failed to set perms %04o on file '%s': %s",
perms, test_file, strerror(errno));
return fh;
}
static void set_up(void) {
if (p == NULL) {
p = permanent_pool = session.pool = make_sub_pool(NULL);
main_server = NULL;
server_list = NULL;
session.c = NULL;
session.notes = NULL;
}
test_cleanup(p);
init_config();
init_fs();
init_netaddr();
init_netio();
init_inet();
server_list = xaset_create(p, NULL);
pr_parser_prepare(p, &server_list);
create_main_server();
proxy_db_init(p);
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("netio", 1, 20);
pr_trace_set_levels("proxy.conn", 1, 20);
pr_trace_set_levels("proxy.db", 1, 20);
pr_trace_set_levels("proxy.reverse", 1, 20);
pr_trace_set_levels("proxy.tls", 1, 20);
pr_trace_set_levels("proxy.uri", 1, 20);
pr_trace_set_levels("proxy.ftp.ctrl", 1, 20);
pr_trace_set_levels("proxy.ftp.sess", 1, 20);
}
pr_inet_set_default_family(p, AF_INET);
}
static void tear_down(void) {
pr_inet_set_default_family(p, 0);
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("netio", 0, 0);
pr_trace_set_levels("proxy.conn", 0, 0);
pr_trace_set_levels("proxy.db", 0, 0);
pr_trace_set_levels("proxy.reverse", 0, 0);
pr_trace_set_levels("proxy.tls", 0, 0);
pr_trace_set_levels("proxy.uri", 0, 0);
pr_trace_set_levels("proxy.ftp.ctrl", 0, 0);
pr_trace_set_levels("proxy.ftp.sess", 0, 0);
}
pr_inet_clear();
pr_parser_cleanup();
proxy_db_free();
test_cleanup(p);
if (p) {
destroy_pool(p);
p = permanent_pool = session.pool = NULL;
main_server = NULL;
server_list = NULL;
session.c = NULL;
session.notes = NULL;
}
}
START_TEST (reverse_free_test) {
int res;
res = proxy_reverse_free(NULL);
fail_unless(res < 0, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
res = proxy_reverse_free(p);
fail_unless(res == 0, "Failed to free Reverse API resources: %s",
strerror(errno));
}
END_TEST
START_TEST (reverse_init_test) {
int res, flags = PROXY_DB_OPEN_FL_SKIP_VACUUM;
FILE *fh;
res = proxy_reverse_init(NULL, NULL, flags);
fail_unless(res < 0, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
res = proxy_reverse_init(p, NULL, flags);
fail_unless(res < 0, "Failed to handle null tables dir");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
fh = test_prep();
fclose(fh);
mark_point();
res = proxy_reverse_init(p, test_dir, flags);
fail_unless(res == 0, "Failed to init Reverse API resources: %s",
strerror(errno));
res = proxy_reverse_free(p);
fail_unless(res == 0, "Failed to free Reverse API resources: %s",
strerror(errno));
test_cleanup(p);
}
END_TEST
START_TEST (reverse_sess_free_test) {
int res;
mark_point();
res = proxy_reverse_sess_free(p, NULL);
fail_unless(res == 0, "Failed to free Reverse API session resources: %s",
strerror(errno));
}
END_TEST
START_TEST (reverse_sess_init_test) {
int res, flags = PROXY_DB_OPEN_FL_SKIP_VACUUM;
config_rec *c;
array_header *backends;
const char *uri;
const struct proxy_conn *pconn;
mark_point();
res = proxy_reverse_sess_init(NULL, NULL, NULL, flags);
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_reverse_sess_init(p, NULL, NULL, flags);
fail_unless(res < 0, "Unexpectedly init'd Reverse API session resources");
fail_unless(errno == EPERM, "Expected EPERM (%d), got '%s' (%d)", EPERM,
strerror(errno), errno);
c = add_config_param("ProxyReverseServers", 2, NULL, NULL);
backends = make_array(c->pool, 1, sizeof(struct proxy_conn *));
uri = "ftp://127.0.0.1:21";
pconn = proxy_conn_create(c->pool, uri, 0);
*((const struct proxy_conn **) push_array(backends)) = pconn;
c->argv[0] = backends;
c = add_config_param("ProxyReverseServers", 2, NULL, NULL);
backends = make_array(c->pool, 1, sizeof(struct proxy_conn *));
uri = "ftp://127.0.0.1:2121";
pconn = proxy_conn_create(c->pool, uri, 0);
*((const struct proxy_conn **) push_array(backends)) = pconn;
c->argv[0] = backends;
mark_point();
res = proxy_reverse_sess_init(NULL, NULL, NULL, flags);
fail_unless(res < 0, "Unexpectedly init'd Reverse API session resources");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
mark_point();
res = proxy_reverse_sess_free(p, NULL);
fail_unless(res == 0, "Failed to free Reverse API session resources: %s",
strerror(errno));
}
END_TEST
static int test_connect_policy(int policy_id, array_header *src_backends) {
int flags = PROXY_DB_OPEN_FL_SKIP_VACUUM;
FILE *fh;
config_rec *c;
array_header *backends;
fh = test_prep();
fclose(fh);
mark_point();
if (policy_config != NULL) {
c = policy_config;
} else {
policy_config = c = add_config_param("ProxyReverseConnectPolicy", 1, NULL);
c->argv[0] = palloc(c->pool, sizeof(int));
}
*((int *) c->argv[0]) = policy_id;
mark_point();
c = add_config_param("ProxyReverseServers", 2, NULL, NULL);
backends = make_array(c->pool, 1, sizeof(struct proxy_conn *));
if (src_backends == NULL) {
const char *uri;
const struct proxy_conn *pconn;
uri = "ftp://127.0.0.1:21";
pconn = proxy_conn_create(c->pool, uri, 0);
*((const struct proxy_conn **) push_array(backends)) = pconn;
} else {
array_cat(backends, src_backends);
}
c->argv[0] = backends;
mark_point();
return proxy_reverse_init(p, test_dir, flags);
}
START_TEST (reverse_connect_policy_random_test) {
int res;
res = test_connect_policy(PROXY_REVERSE_CONNECT_POLICY_RANDOM, NULL);
fail_unless(res == 0, "Failed to test ReverseConnectPolicy Random: %s",
strerror(errno));
mark_point();
res = proxy_reverse_sess_exit(p);
fail_unless(res == 0, "Failed to exit session: %s", strerror(errno));
mark_point();
res = proxy_reverse_free(p);
fail_unless(res == 0, "Failed to free Reverse API resources: %s",
strerror(errno));
test_cleanup(p);
}
END_TEST
START_TEST (reverse_connect_policy_roundrobin_test) {
int res;
res = test_connect_policy(PROXY_REVERSE_CONNECT_POLICY_ROUND_ROBIN, NULL);
fail_unless(res == 0, "Failed to test ReverseConnectPolicy RoundRobin: %s",
strerror(errno));
mark_point();
res = proxy_reverse_sess_exit(p);
fail_unless(res == 0, "Failed to exit session: %s", strerror(errno));
mark_point();
res = proxy_reverse_free(p);
fail_unless(res == 0, "Failed to free Reverse API resources: %s",
strerror(errno));
test_cleanup(p);
}
END_TEST
START_TEST (reverse_connect_policy_leastconns_test) {
int res;
res = test_connect_policy(PROXY_REVERSE_CONNECT_POLICY_LEAST_CONNS, NULL);
fail_unless(res == 0, "Failed to test ReverseConnectPolicy LeastConns: %s",
strerror(errno));
mark_point();
res = proxy_reverse_sess_exit(p);
fail_unless(res == 0, "Failed to exit session: %s", strerror(errno));
mark_point();
res = proxy_reverse_free(p);
fail_unless(res == 0, "Failed to free Reverse API resources: %s",
strerror(errno));
test_cleanup(p);
}
END_TEST
START_TEST (reverse_connect_policy_leastresponsetime_test) {
int res;
res = test_connect_policy(PROXY_REVERSE_CONNECT_POLICY_LEAST_RESPONSE_TIME,
NULL);
fail_unless(res == 0,
"Failed to test ReverseConnectPolicy LeastResponseTime: %s",
strerror(errno));
mark_point();
res = proxy_reverse_sess_exit(p);
fail_unless(res == 0, "Failed to exit session: %s", strerror(errno));
mark_point();
res = proxy_reverse_free(p);
fail_unless(res == 0, "Failed to free Reverse API resources: %s",
strerror(errno));
test_cleanup(p);
}
END_TEST
START_TEST (reverse_connect_policy_shuffle_test) {
int res;
res = test_connect_policy(PROXY_REVERSE_CONNECT_POLICY_SHUFFLE, NULL);
fail_unless(res == 0, "Failed to test ReverseConnectPolicy Shuffle: %s",
strerror(errno));
mark_point();
res = proxy_reverse_sess_exit(p);
fail_unless(res == 0, "Failed to exit session: %s", strerror(errno));
mark_point();
res = proxy_reverse_free(p);
fail_unless(res == 0, "Failed to free Reverse API resources: %s",
strerror(errno));
test_cleanup(p);
}
END_TEST
START_TEST (reverse_connect_policy_peruser_test) {
int res;
res = test_connect_policy(PROXY_REVERSE_CONNECT_POLICY_PER_USER, NULL);
fail_unless(res == 0, "Failed to test ReverseConnectPolicy PerUser: %s",
strerror(errno));
mark_point();
res = proxy_reverse_sess_exit(p);
fail_unless(res == 0, "Failed to exit session: %s", strerror(errno));
mark_point();
res = proxy_reverse_free(p);
fail_unless(res == 0, "Failed to free Reverse API resources: %s",
strerror(errno));
test_cleanup(p);
}
END_TEST
START_TEST (reverse_connect_policy_pergroup_test) {
int res;
/* Note: This should fail without having the UseReverseProxyAuth ProxyOption
* enabled.
*/
res = test_connect_policy(PROXY_REVERSE_CONNECT_POLICY_PER_GROUP, NULL);
fail_unless(res < 0, "Expected ReverseConnectPolicy PerGroup to fail");
fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
strerror(errno), errno);
mark_point();
res = proxy_reverse_sess_exit(p);
fail_unless(res == 0, "Failed to exit session: %s", strerror(errno));
mark_point();
res = proxy_reverse_free(p);
fail_unless(res == 0, "Failed to free Reverse API resources: %s",
strerror(errno));
test_cleanup(p);
}
END_TEST
START_TEST (reverse_connect_policy_perhost_test) {
int res;
res = test_connect_policy(PROXY_REVERSE_CONNECT_POLICY_PER_HOST, NULL);
fail_unless(res == 0, "Failed to test ReverseConnectPolicy PerHost: %s",
strerror(errno));
mark_point();
res = proxy_reverse_sess_exit(p);
fail_unless(res == 0, "Failed to exit session: %s", strerror(errno));
mark_point();
res = proxy_reverse_free(p);
fail_unless(res == 0, "Failed to free Reverse API resources: %s",
strerror(errno));
test_cleanup(p);
}
END_TEST
static void test_handle_user_pass(int policy_id, array_header *src_backends) {
int res, successful = FALSE, block_responses = FALSE;
int flags = PROXY_DB_OPEN_FL_SKIP_VACUUM;
struct proxy_session *proxy_sess;
cmd_rec *cmd;
FILE *fh;
fh = test_prep();
fclose(fh);
mark_point();
res = test_connect_policy(PROXY_REVERSE_CONNECT_POLICY_RANDOM, src_backends);
fail_unless(res == 0, "Failed to test ReverseConnectPolicy Random: %s",
strerror(errno));
proxy_sess = (struct proxy_session *) proxy_session_alloc(p);
session.notes = pr_table_alloc(p, 0);
pr_table_add(session.notes, "mod_proxy.proxy-session", proxy_sess,
sizeof(struct proxy_session));
session.c = pr_inet_create_conn(p, -1, NULL, INPORT_ANY, FALSE);
fail_unless(session.c != NULL,
"Failed to open session control conn: %s", strerror(errno));
session.c->local_addr = session.c->remote_addr = pr_netaddr_get_addr(p,
"127.0.0.1", NULL);
fail_unless(session.c->remote_addr != NULL, "Failed to get address: %s",
strerror(errno));
mark_point();
res = proxy_reverse_sess_init(p, test_dir, proxy_sess, flags);
fail_unless(res == 0, "Failed to init Reverse API session resources: %s",
strerror(errno));
cmd = pr_cmd_alloc(p, 2, "USER", "anonymous");
cmd->arg = pstrdup(p, "anonymous");
mark_point();
res = proxy_reverse_handle_user(cmd, proxy_sess, &successful,
&block_responses);
fail_if(res != 1, "Failed to handle USER");
cmd = pr_cmd_alloc(p, 2, "PASS", "ftp@nospam.org");
cmd->arg = pstrdup(p, "ftp@nospam.org");
mark_point();
res = proxy_reverse_handle_pass(cmd, proxy_sess, &successful,
&block_responses);
fail_unless(res < 0, "Handled PASS unexpectedly");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
mark_point();
res = proxy_reverse_sess_exit(p);
fail_unless(res == 0, "Failed to exit session: %s", strerror(errno));
mark_point();
res = proxy_reverse_free(p);
fail_unless(res == 0, "Failed to free Reverse API resources: %s",
strerror(errno));
proxy_session_free(p, proxy_sess);
test_cleanup(p);
}
START_TEST (reverse_handle_user_pass_random_test) {
const char *uri;
const struct proxy_conn *pconn;
array_header *backends;
/* Skip this test on travis, for now. It fails unexpectedly. */
if (getenv("TRAVIS") != NULL) {
return;
}
backends = make_array(p, 1, sizeof(struct proxy_conn *));
uri = "ftp://127.0.0.1:21";
pconn = proxy_conn_create(p, uri, 0);
*((const struct proxy_conn **) push_array(backends)) = pconn;
uri = "ftp://ftp.microsoft.com:21";
pconn = proxy_conn_create(p, uri, 0);
*((const struct proxy_conn **) push_array(backends)) = pconn;
test_handle_user_pass(PROXY_REVERSE_CONNECT_POLICY_RANDOM, backends);
test_handle_user_pass(PROXY_REVERSE_CONNECT_POLICY_RANDOM, backends);
}
END_TEST
START_TEST (reverse_handle_user_pass_roundrobin_test) {
const char *uri;
const struct proxy_conn *pconn;
array_header *backends;
/* Skip this test on travis, for now. It fails unexpectedly. */
if (getenv("TRAVIS") != NULL) {
return;
}
backends = make_array(p, 1, sizeof(struct proxy_conn *));
uri = "ftp://127.0.0.1:21";
pconn = proxy_conn_create(p, uri, 0);
*((const struct proxy_conn **) push_array(backends)) = pconn;
uri = "ftp://ftp.microsoft.com:21";
pconn = proxy_conn_create(p, uri, 0);
*((const struct proxy_conn **) push_array(backends)) = pconn;
test_handle_user_pass(PROXY_REVERSE_CONNECT_POLICY_ROUND_ROBIN, backends);
test_handle_user_pass(PROXY_REVERSE_CONNECT_POLICY_ROUND_ROBIN, backends);
}
END_TEST
START_TEST (reverse_handle_user_pass_leastconns_test) {
const char *uri;
const struct proxy_conn *pconn;
array_header *backends;
/* Skip this test on travis, for now. It fails unexpectedly. */
if (getenv("TRAVIS") != NULL) {
return;
}
backends = make_array(p, 1, sizeof(struct proxy_conn *));
uri = "ftp://127.0.0.1:21";
pconn = proxy_conn_create(p, uri, 0);
*((const struct proxy_conn **) push_array(backends)) = pconn;
uri = "ftp://ftp.microsoft.com:21";
pconn = proxy_conn_create(p, uri, 0);
*((const struct proxy_conn **) push_array(backends)) = pconn;
test_handle_user_pass(PROXY_REVERSE_CONNECT_POLICY_LEAST_CONNS, backends);
test_handle_user_pass(PROXY_REVERSE_CONNECT_POLICY_LEAST_CONNS, backends);
}
END_TEST
START_TEST (reverse_handle_user_pass_leastresponsetime_test) {
const char *uri;
const struct proxy_conn *pconn;
array_header *backends;
/* Skip this test on travis, for now. It fails unexpectedly. */
if (getenv("TRAVIS") != NULL) {
return;
}
backends = make_array(p, 1, sizeof(struct proxy_conn *));
uri = "ftp://127.0.0.1:21";
pconn = proxy_conn_create(p, uri, 0);
*((const struct proxy_conn **) push_array(backends)) = pconn;
uri = "ftp://ftp.microsoft.com:21";
pconn = proxy_conn_create(p, uri, 0);
*((const struct proxy_conn **) push_array(backends)) = pconn;
test_handle_user_pass(PROXY_REVERSE_CONNECT_POLICY_LEAST_RESPONSE_TIME,
backends);
test_handle_user_pass(PROXY_REVERSE_CONNECT_POLICY_LEAST_RESPONSE_TIME,
backends);
}
END_TEST
START_TEST (reverse_handle_user_pass_shuffle_test) {
const char *uri;
const struct proxy_conn *pconn;
array_header *backends;
/* Skip this test on travis, for now. It fails unexpectedly. */
if (getenv("TRAVIS") != NULL) {
return;
}
backends = make_array(p, 1, sizeof(struct proxy_conn *));
uri = "ftp://127.0.0.1:21";
pconn = proxy_conn_create(p, uri, 0);
*((const struct proxy_conn **) push_array(backends)) = pconn;
uri = "ftp://ftp.microsoft.com:21";
pconn = proxy_conn_create(p, uri, 0);
*((const struct proxy_conn **) push_array(backends)) = pconn;
test_handle_user_pass(PROXY_REVERSE_CONNECT_POLICY_SHUFFLE, backends);
test_handle_user_pass(PROXY_REVERSE_CONNECT_POLICY_SHUFFLE, backends);
}
END_TEST
START_TEST (reverse_handle_user_pass_peruser_test) {
const char *uri;
const struct proxy_conn *pconn;
array_header *backends;
/* Skip this test on travis, for now. It fails unexpectedly. */
if (getenv("TRAVIS") != NULL) {
return;
}
backends = make_array(p, 1, sizeof(struct proxy_conn *));
uri = "ftp://127.0.0.1:21";
pconn = proxy_conn_create(p, uri, 0);
*((const struct proxy_conn **) push_array(backends)) = pconn;
uri = "ftp://ftp.microsoft.com:21";
pconn = proxy_conn_create(p, uri, 0);
*((const struct proxy_conn **) push_array(backends)) = pconn;
test_handle_user_pass(PROXY_REVERSE_CONNECT_POLICY_PER_USER, backends);
test_handle_user_pass(PROXY_REVERSE_CONNECT_POLICY_PER_USER, backends);
}
END_TEST
START_TEST (reverse_handle_user_pass_pergroup_test) {
const char *uri;
const struct proxy_conn *pconn;
array_header *backends;
/* Skip this test on travis, for now. It fails unexpectedly. */
if (getenv("TRAVIS") != NULL) {
return;
}
backends = make_array(p, 1, sizeof(struct proxy_conn *));
uri = "ftp://127.0.0.1:21";
pconn = proxy_conn_create(p, uri, 0);
*((const struct proxy_conn **) push_array(backends)) = pconn;
uri = "ftp://ftp.microsoft.com:21";
pconn = proxy_conn_create(p, uri, 0);
*((const struct proxy_conn **) push_array(backends)) = pconn;
test_handle_user_pass(PROXY_REVERSE_CONNECT_POLICY_PER_GROUP, backends);
test_handle_user_pass(PROXY_REVERSE_CONNECT_POLICY_PER_GROUP, backends);
}
END_TEST
START_TEST (reverse_handle_user_pass_perhost_test) {
const char *uri;
const struct proxy_conn *pconn;
array_header *backends;
/* Skip this test on travis, for now. It fails unexpectedly. */
if (getenv("TRAVIS") != NULL) {
return;
}
backends = make_array(p, 1, sizeof(struct proxy_conn *));
uri = "ftp://127.0.0.1:21";
pconn = proxy_conn_create(p, uri, 0);
*((const struct proxy_conn **) push_array(backends)) = pconn;
uri = "ftp://ftp.microsoft.com:21";
pconn = proxy_conn_create(p, uri, 0);
*((const struct proxy_conn **) push_array(backends)) = pconn;
test_handle_user_pass(PROXY_REVERSE_CONNECT_POLICY_PER_HOST, backends);
test_handle_user_pass(PROXY_REVERSE_CONNECT_POLICY_PER_HOST, backends);
}
END_TEST
START_TEST (reverse_json_parse_uris_args_test) {
array_header *uris;
const char *path;
uris = proxy_reverse_json_parse_uris(NULL, NULL, 0);
fail_unless(uris == NULL, "Failed to handle null arguments");
fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
uris = proxy_reverse_json_parse_uris(p, NULL, 0);
fail_unless(uris == NULL, "Failed to handle null path argument");
fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
path = "/tmp/test.dat";
uris = proxy_reverse_json_parse_uris(NULL, path, 0);
fail_unless(uris == NULL, "Failed to handle null pool argument");
fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
}
END_TEST
START_TEST (reverse_json_parse_uris_isreg_test) {
array_header *uris;
const char *path;
int res;
test_cleanup(p);
path = "servers.json";
uris = proxy_reverse_json_parse_uris(p, path, 0);
fail_unless(uris == NULL, "Failed to handle relative path '%s'", path);
fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
path = test_file;
uris = proxy_reverse_json_parse_uris(p, path, 0);
fail_unless(uris == NULL, "Failed to handle nonexistent file '%s'", path);
fail_unless(errno == ENOENT, "Failed to set errno to ENOENT");
res = mkdir(test_dir, 0777);
fail_unless(res == 0, "Failed to create tmp directory '%s': %s", test_dir,
strerror(errno));
uris = proxy_reverse_json_parse_uris(p, test_dir, 0);
fail_unless(uris == NULL, "Failed to handle directory path '%s'", test_dir);
fail_unless(errno == EISDIR, "Failed to set errno to EISDIR");
test_cleanup(p);
}
END_TEST
START_TEST (reverse_json_parse_uris_perms_test) {
array_header *uris;
const char *path;
int fd, res;
mode_t perms;
/* Note: any extra chmods are necessary to workaround any umask in the
* environment. Sigh.
*/
perms = 0777;
res = mkdir(test_dir, perms);
fail_unless(res == 0, "Failed to create tmp directory '%s': %s", test_dir,
strerror(errno));
res = chmod(test_dir, perms);
fail_unless(res == 0, "Failed to set perms %04o on directory '%s': %s",
perms, test_dir, strerror(errno));
/* First, make a world-writable file. */
perms = 0666;
fd = open(test_file, O_WRONLY|O_CREAT, perms);
fail_if(fd < 0, "Failed to create tmp file '%s': %s", test_file,
strerror(errno));
res = fchmod(fd, perms);
fail_unless(res == 0, "Failed to set perms %04o on file '%s': %s",
perms, test_file, strerror(errno));
path = test_file;
uris = proxy_reverse_json_parse_uris(p, path, 0);
fail_unless(uris == NULL, "Failed to handle world-writable file '%s'",
path);
fail_unless(errno == EPERM, "Failed to set errno to EPERM, got %d (%s)",
errno, strerror(errno));
/* Now make the file user/group-writable only, but leave the parent
* directory world-writable.
*/
perms = 0660;
res = fchmod(fd, perms);
fail_unless(res == 0, "Failed to set perms %04o on file '%s': %s",
perms, test_file, strerror(errno));
uris = proxy_reverse_json_parse_uris(p, path, 0);
fail_unless(uris == NULL, "Failed to handle world-writable directory '%s'",
test_file);
fail_unless(errno == EPERM, "Failed to set errno to EPERM, got %d (%s)",
errno, strerror(errno));
(void) close(fd);
test_cleanup(p);
}
END_TEST
START_TEST (reverse_json_parse_uris_empty_test) {
array_header *uris;
FILE *fh = NULL;
int res;
test_cleanup(p);
fh = test_prep();
/* Write a file with no lines. */
res = fclose(fh);
fail_if(res < 0, "Failed to write file '%s': %s", test_file,
strerror(errno));
mark_point();
uris = proxy_reverse_json_parse_uris(p, test_file, 0);
fail_unless(uris != NULL, "Did not receive parsed list as expected");
fail_unless(uris->nelts == 0, "Expected zero elements, found %d",
uris->nelts);
test_cleanup(p);
}
END_TEST
START_TEST (reverse_json_parse_uris_malformed_test) {
array_header *uris;
FILE *fh = NULL;
int res;
test_cleanup(p);
fh = test_prep();
fprintf(fh, "[ \"http://127.0.0.1:80\",\n");
fprintf(fh, "\"ftp:/127.0.0.1::21\",\n");
fprintf(fh, "\"ftp://foo.bar.baz:21\" ]\n");
res = fclose(fh);
fail_if(res < 0, "Failed to write file '%s': %s", test_file,
strerror(errno));
mark_point();
uris = proxy_reverse_json_parse_uris(p, test_file, 0);
fail_unless(uris != NULL, "Did not receive parsed list as expected");
fail_unless(uris->nelts == 0, "Expected zero elements, found %d",
uris->nelts);
test_cleanup(p);
}
END_TEST
START_TEST (reverse_json_parse_uris_usable_test) {
array_header *uris;
FILE *fh = NULL;
int res;
unsigned int expected;
test_cleanup(p);
fh = test_prep();
/* Write a file with usable URLs. */
fprintf(fh, "[ \"ftp://127.0.0.1\",\n");
fprintf(fh, "\"ftp://localhost:2121\",\n");
fprintf(fh, "\"ftp://[::1]:21212\" ]\n");
res = fclose(fh);
fail_if(res < 0, "Failed to write file '%s': %s", test_file,
strerror(errno));
mark_point();
uris = proxy_reverse_json_parse_uris(p, test_file, 0);
fail_unless(uris != NULL, "Did not receive parsed list as expected");
expected = 3;
fail_unless(uris->nelts == expected, "Expected %d elements, found %d",
expected, uris->nelts);
test_cleanup(p);
}
END_TEST
START_TEST (reverse_connect_get_policy_test) {
int res;
const char *policy;
res = proxy_reverse_connect_get_policy(NULL);
fail_unless(res < 0, "Failed to handle null argument");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
policy = "foo";
res = proxy_reverse_connect_get_policy(policy);
fail_unless(res < 0, "Failed to handle unsupported policy '%s'", policy);
fail_unless(errno == ENOENT, "Expected ENOENT (%d), got '%s' (%d)", ENOENT,
strerror(errno), errno);
policy = "random2";
res = proxy_reverse_connect_get_policy(policy);
fail_unless(res < 0, "Failed to handle unsupported policy '%s'", policy);
fail_unless(errno == ENOENT, "Expected ENOENT (%d), got '%s' (%d)", ENOENT,
strerror(errno), errno);
policy = "random";
res = proxy_reverse_connect_get_policy(policy);
fail_unless(res == PROXY_REVERSE_CONNECT_POLICY_RANDOM,
"Failed to handle supported policy '%s'", policy);
policy = "roundrobin";
res = proxy_reverse_connect_get_policy(policy);
fail_unless(res == PROXY_REVERSE_CONNECT_POLICY_ROUND_ROBIN,
"Failed to handle supported policy '%s'", policy);
policy = "shuffle";
res = proxy_reverse_connect_get_policy(policy);
fail_unless(res == PROXY_REVERSE_CONNECT_POLICY_SHUFFLE,
"Failed to handle supported policy '%s'", policy);
policy = "leastconns";
res = proxy_reverse_connect_get_policy(policy);
fail_unless(res == PROXY_REVERSE_CONNECT_POLICY_LEAST_CONNS,
"Failed to handle supported policy '%s'", policy);
policy = "peruser";
res = proxy_reverse_connect_get_policy(policy);
fail_unless(res == PROXY_REVERSE_CONNECT_POLICY_PER_USER,
"Failed to handle supported policy '%s'", policy);
policy = "pergroup";
res = proxy_reverse_connect_get_policy(policy);
fail_unless(res == PROXY_REVERSE_CONNECT_POLICY_PER_GROUP,
"Failed to handle supported policy '%s'", policy);
policy = "perhost";
res = proxy_reverse_connect_get_policy(policy);
fail_unless(res == PROXY_REVERSE_CONNECT_POLICY_PER_HOST,
"Failed to handle supported policy '%s'", policy);
policy = "leastresponsetime";
res = proxy_reverse_connect_get_policy(policy);
fail_unless(res == PROXY_REVERSE_CONNECT_POLICY_LEAST_RESPONSE_TIME,
"Failed to handle supported policy '%s'", policy);
}
END_TEST
START_TEST (reverse_use_proxy_auth_test) {
int res;
res = proxy_reverse_use_proxy_auth();
fail_unless(res == FALSE, "Expected false, got %d", res);
}
END_TEST
START_TEST (reverse_have_authenticated_test) {
int res;
cmd_rec *cmd = NULL;
res = proxy_reverse_have_authenticated(cmd);
fail_unless(res == FALSE, "Expected false, got %d", res);
proxy_sess_state |= PROXY_SESS_STATE_BACKEND_AUTHENTICATED;
res = proxy_reverse_have_authenticated(cmd);
fail_unless(res == TRUE, "Expected true, got %d", res);
proxy_sess_state &= ~PROXY_SESS_STATE_BACKEND_AUTHENTICATED;
}
END_TEST
Suite *tests_get_reverse_suite(void) {
Suite *suite;
TCase *testcase;
suite = suite_create("reverse");
testcase = tcase_create("base");
tcase_add_checked_fixture(testcase, set_up, tear_down);
tcase_add_test(testcase, reverse_free_test);
tcase_add_test(testcase, reverse_init_test);
tcase_add_test(testcase, reverse_sess_free_test);
tcase_add_test(testcase, reverse_sess_init_test);
tcase_add_test(testcase, reverse_connect_policy_random_test);
tcase_add_test(testcase, reverse_connect_policy_roundrobin_test);
tcase_add_test(testcase, reverse_connect_policy_leastconns_test);
tcase_add_test(testcase, reverse_connect_policy_leastresponsetime_test);
tcase_add_test(testcase, reverse_connect_policy_shuffle_test);
tcase_add_test(testcase, reverse_connect_policy_peruser_test);
tcase_add_test(testcase, reverse_connect_policy_pergroup_test);
tcase_add_test(testcase, reverse_connect_policy_perhost_test);
tcase_add_test(testcase, reverse_handle_user_pass_random_test);
tcase_add_test(testcase, reverse_handle_user_pass_roundrobin_test);
tcase_add_test(testcase, reverse_handle_user_pass_leastconns_test);
tcase_add_test(testcase, reverse_handle_user_pass_leastresponsetime_test);
tcase_add_test(testcase, reverse_handle_user_pass_shuffle_test);
tcase_add_test(testcase, reverse_handle_user_pass_peruser_test);
tcase_add_test(testcase, reverse_handle_user_pass_pergroup_test);
tcase_add_test(testcase, reverse_handle_user_pass_perhost_test);
tcase_add_test(testcase, reverse_json_parse_uris_args_test);
tcase_add_test(testcase, reverse_json_parse_uris_isreg_test);
tcase_add_test(testcase, reverse_json_parse_uris_perms_test);
tcase_add_test(testcase, reverse_json_parse_uris_empty_test);
tcase_add_test(testcase, reverse_json_parse_uris_malformed_test);
tcase_add_test(testcase, reverse_json_parse_uris_usable_test);
tcase_add_test(testcase, reverse_connect_get_policy_test);
tcase_add_test(testcase, reverse_use_proxy_auth_test);
tcase_add_test(testcase, reverse_have_authenticated_test);
suite_add_tcase(suite, testcase);
return suite;
}
proftpd-mod_proxy-0.8/t/api/session.c 0000664 0000000 0000000 00000015157 14020740307 0017726 0 ustar 00root root 0000000 0000000 /*
* ProFTPD - mod_proxy testsuite
* Copyright (c) 2016-2017 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
*
* As a special exemption, TJ Saunders and other respective copyright holders
* give permission to link this program with OpenSSL, and distribute the
* resulting executable, without including the source code for OpenSSL in the
* source distribution.
*/
/* Session API tests. */
#include "tests.h"
extern xaset_t *server_list;
static pool *p = NULL;
static void create_main_server(void) {
server_rec *s;
s = pr_parser_server_ctxt_open("127.0.0.1");
s->ServerName = "Test Server";
main_server = s;
}
static void set_up(void) {
if (p == NULL) {
p = permanent_pool = session.pool = make_sub_pool(NULL);
main_server = NULL;
server_list = NULL;
session.c = NULL;
session.notes = NULL;
}
init_config();
init_netaddr();
init_netio();
init_inet();
init_auth();
server_list = xaset_create(p, NULL);
pr_parser_prepare(p, &server_list);
create_main_server();
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("proxy.session", 1, 20);
}
pr_inet_set_default_family(p, AF_INET);
}
static void tear_down(void) {
pr_inet_set_default_family(p, 0);
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("proxy.session", 0, 0);
}
pr_parser_cleanup();
pr_inet_clear();
if (p) {
destroy_pool(p);
p = permanent_pool = session.pool = NULL;
main_server = NULL;
server_list = NULL;
session.c = NULL;
session.notes = NULL;
}
}
START_TEST (session_free_test) {
int res;
res = proxy_session_free(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);
res = proxy_session_free(p, NULL);
fail_unless(res < 0, "Failed to handle null session");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
}
END_TEST
START_TEST (session_alloc_test) {
struct proxy_session *proxy_sess;
proxy_sess = (struct proxy_session *) proxy_session_alloc(NULL);
fail_unless(proxy_sess == NULL, "Failed to handle null argument");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
proxy_sess = (struct proxy_session *) proxy_session_alloc(p);
fail_unless(proxy_sess != NULL, "Failed to allocate proxy session: %s",
strerror(errno));
mark_point();
proxy_session_free(p, proxy_sess);
proxy_sess = (struct proxy_session *) proxy_session_alloc(p);
fail_unless(proxy_sess != NULL, "Failed to allocate proxy session: %s",
strerror(errno));
proxy_sess->frontend_data_conn = pr_inet_create_conn(p, -1, NULL, INPORT_ANY,
FALSE);
proxy_sess->backend_ctrl_conn = pr_inet_create_conn(p, -1, NULL, INPORT_ANY,
FALSE);
proxy_sess->backend_data_conn = pr_inet_create_conn(p, -1, NULL, INPORT_ANY,
FALSE);
mark_point();
proxy_session_free(p, proxy_sess);
}
END_TEST
START_TEST (session_check_password_test) {
int res;
const char *user, *passwd;
mark_point();
res = proxy_session_check_password(NULL, 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);
mark_point();
res = proxy_session_check_password(p, NULL, NULL);
fail_unless(res < 0, "Failed to handle null user");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
user = "foo";
mark_point();
res = proxy_session_check_password(p, user, NULL);
fail_unless(res < 0, "Failed to handle null passwd");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
passwd = "bar";
mark_point();
res = proxy_session_check_password(p, user, passwd);
fail_unless(res < 0, "Failed to handle unknown user");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
}
END_TEST
START_TEST (session_setup_env_test) {
int res, flags = 0;
const char *user;
mark_point();
res = proxy_session_setup_env(NULL, NULL, flags);
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_session_setup_env(p, NULL, flags);
fail_unless(res < 0, "Failed to handle null user");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
strerror(errno), errno);
session.c = pr_inet_create_conn(p, -1, NULL, INPORT_ANY, FALSE);
fail_unless(session.c != NULL,
"Failed to open session control conn: %s", strerror(errno));
session.c->remote_name = pstrdup(p, "127.0.0.1");
user = "foo";
mark_point();
res = proxy_session_setup_env(p, user, flags);
fail_unless(res == 0, "Failed to setup environment: %s", strerror(errno));
fail_unless(proxy_sess_state & PROXY_SESS_STATE_PROXY_AUTHENTICATED,
"Expected PROXY_AUTHENTICATED state set");
proxy_sess_state &= ~PROXY_SESS_STATE_PROXY_AUTHENTICATED;
user = "root";
mark_point();
res = proxy_session_setup_env(p, user, flags);
fail_unless(res == 0, "Failed to setup environment: %s", strerror(errno));
fail_unless(proxy_sess_state & PROXY_SESS_STATE_PROXY_AUTHENTICATED,
"Expected PROXY_AUTHENTICATED state set");
proxy_sess_state &= ~PROXY_SESS_STATE_PROXY_AUTHENTICATED;
pr_inet_close(p, session.c);
session.c = NULL;
}
END_TEST
Suite *tests_get_session_suite(void) {
Suite *suite;
TCase *testcase;
suite = suite_create("session");
testcase = tcase_create("base");
tcase_add_checked_fixture(testcase, set_up, tear_down);
tcase_add_test(testcase, session_free_test);
tcase_add_test(testcase, session_alloc_test);
tcase_add_test(testcase, session_check_password_test);
tcase_add_test(testcase, session_setup_env_test);
suite_add_tcase(suite, testcase);
return suite;
}
proftpd-mod_proxy-0.8/t/api/str.c 0000664 0000000 0000000 00000005500 14020740307 0017042 0 ustar 00root root 0000000 0000000 /*
* ProFTPD - mod_proxy testsuite
* Copyright (c) 2020 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
*
* As a special exemption, TJ Saunders and other respective copyright holders
* give permission to link this program with OpenSSL, and distribute the
* resulting executable, without including the source code for OpenSSL in the
* source distribution.
*/
/* String API tests */
#include "tests.h"
static pool *p = NULL;
static void set_up(void) {
if (p == NULL) {
p = permanent_pool = make_sub_pool(NULL);
}
}
static void tear_down(void) {
if (p != NULL) {
destroy_pool(p);
p = permanent_pool = NULL;
}
}
START_TEST (strnstr_test) {
const char *s1, *s2;
size_t len;
char *res;
mark_point();
res = proxy_strnstr(NULL, NULL, 0);
fail_unless(res == NULL, "Failed to handle null s1");
mark_point();
s1 = "haystack";
res = proxy_strnstr(s1, NULL, 0);
fail_unless(res == NULL, "Failed to handle null s2");
mark_point();
s2 = "needle";
res = proxy_strnstr(s1, s2, 0);
fail_unless(res == NULL, "Failed to handle zero len");
mark_point();
len = 2;
res = proxy_strnstr(s1, s2, len);
fail_unless(res == NULL, "Expected null, got %p for len %lu", res,
(unsigned long) len);
mark_point();
s1 = " ";
res = proxy_strnstr(s1, s2, len);
fail_unless(res == NULL, "Expected null, got %p for s1 spaces", res);
mark_point();
s1 = "haystack";
s2 = "";
res = proxy_strnstr(s1, s2, len);
fail_unless(res == NULL, "Expected null, got %p for s2 empty", res);
mark_point();
s1 = "haystack";
s2 = "haystack";
len = 8;
res = proxy_strnstr(s1, s2, len);
fail_unless(res != NULL, "Expected %p, got %p for s1 == s2", s1, res);
mark_point();
s1 = "haystack";
s2 = "sta";
len = 7;
res = proxy_strnstr(s1, s2, len);
fail_unless(res != NULL, "Expected %p, got %p", s1 + 3, res);
}
END_TEST
Suite *tests_get_str_suite(void) {
Suite *suite;
TCase *testcase;
suite = suite_create("str");
testcase = tcase_create("base");
tcase_add_checked_fixture(testcase, set_up, tear_down);
tcase_add_test(testcase, strnstr_test);
suite_add_tcase(suite, testcase);
return suite;
}
proftpd-mod_proxy-0.8/t/api/stubs.c 0000664 0000000 0000000 00000014366 14020740307 0017404 0 ustar 00root root 0000000 0000000 /*
* ProFTPD - mod_proxy API testsuite
* Copyright (c) 2012-2018 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
*
* As a special exemption, TJ Saunders and other respective copyright holders
* give permission to link this program with OpenSSL, and distribute the
* resulting executable, without including the source code for OpenSSL in the
* source distribution.
*/
#include "tests.h"
/* Stubs */
session_t session;
int ServerUseReverseDNS = FALSE;
server_rec *main_server = NULL;
pid_t mpid = 1;
unsigned char is_master = TRUE;
volatile unsigned int recvd_signal_flags = 0;
module *static_modules[] = { NULL };
module *loaded_modules = NULL;
xaset_t *server_list = NULL;
int proxy_logfd = -1;
module proxy_module;
pool *proxy_pool = NULL;
unsigned long proxy_opts = 0UL;
unsigned int proxy_sess_state = 0;
int proxy_datastore = 1;
void *proxy_datastore_data = NULL;
size_t proxy_datastore_datasz = 0;
static cmd_rec *next_cmd = NULL;
int tests_rmpath(pool *p, const char *path) {
DIR *dirh;
struct dirent *dent;
int res, xerrno = 0;
if (path == NULL) {
errno = EINVAL;
return -1;
}
dirh = opendir(path);
if (dirh == NULL) {
xerrno = errno;
/* Change the permissions in the directory, and try again. */
if (chmod(path, (mode_t) 0755) == 0) {
dirh = opendir(path);
}
if (dirh == NULL) {
pr_trace_msg("testsuite", 9,
"error opening '%s': %s", path, strerror(xerrno));
errno = xerrno;
return -1;
}
}
while ((dent = readdir(dirh)) != NULL) {
struct stat st;
char *file;
pr_signals_handle();
if (strncmp(dent->d_name, ".", 2) == 0 ||
strncmp(dent->d_name, "..", 3) == 0) {
continue;
}
file = pdircat(p, path, dent->d_name, NULL);
if (stat(file, &st) < 0) {
pr_trace_msg("testsuite", 9,
"unable to stat '%s': %s", file, strerror(errno));
continue;
}
if (S_ISDIR(st.st_mode)) {
res = tests_rmpath(p, file);
if (res < 0) {
pr_trace_msg("testsuite", 9,
"error removing directory '%s': %s", file, strerror(errno));
}
} else {
res = unlink(file);
if (res < 0) {
pr_trace_msg("testsuite", 9,
"error removing file '%s': %s", file, strerror(errno));
}
}
}
closedir(dirh);
res = rmdir(path);
if (res < 0) {
xerrno = errno;
pr_trace_msg("testsuite", 9,
"error removing directory '%s': %s", path, strerror(xerrno));
errno = xerrno;
}
return res;
}
int tests_stubs_set_next_cmd(cmd_rec *cmd) {
next_cmd = cmd;
return 0;
}
int login_check_limits(xaset_t *set, int recurse, int and, int *found) {
return TRUE;
}
int xferlog_open(const char *path) {
return 0;
}
int pr_cmd_read(cmd_rec **cmd) {
if (next_cmd != NULL) {
*cmd = next_cmd;
next_cmd = NULL;
} else {
errno = ENOENT;
*cmd = NULL;
}
return 0;
}
int pr_config_get_server_xfer_bufsz(int direction) {
int bufsz = -1;
switch (direction) {
case PR_NETIO_IO_RD:
bufsz = PR_TUNABLE_DEFAULT_RCVBUFSZ;
break;
case PR_NETIO_IO_WR:
bufsz = PR_TUNABLE_DEFAULT_SNDBUFSZ;
break;
default:
errno = EINVAL;
return -1;
}
return bufsz;
}
void pr_log_auth(int priority, const char *fmt, ...) {
if (getenv("TEST_VERBOSE") != NULL) {
va_list msg;
fprintf(stderr, "AUTH: ");
va_start(msg, fmt);
vfprintf(stderr, fmt, msg);
va_end(msg);
fprintf(stderr, "\n");
}
}
void pr_log_debug(int level, const char *fmt, ...) {
if (getenv("TEST_VERBOSE") != NULL) {
va_list msg;
fprintf(stderr, "DEBUG%d: ", level);
va_start(msg, fmt);
vfprintf(stderr, fmt, msg);
va_end(msg);
fprintf(stderr, "\n");
}
}
int pr_log_event_generate(unsigned int log_type, int log_fd, int log_level,
const char *log_msg, size_t log_msglen) {
errno = ENOSYS;
return -1;
}
int pr_log_event_listening(unsigned int log_type) {
return FALSE;
}
int pr_log_openfile(const char *log_file, int *log_fd, mode_t log_mode) {
int res;
struct stat st;
if (log_file == NULL ||
log_fd == NULL) {
errno = EINVAL;
return -1;
}
res = stat(log_file, &st);
if (res < 0) {
if (errno != ENOENT) {
return -1;
}
} else {
if (S_ISDIR(st.st_mode)) {
errno = EISDIR;
return -1;
}
}
*log_fd = STDERR_FILENO;
return 0;
}
void pr_log_pri(int prio, const char *fmt, ...) {
if (getenv("TEST_VERBOSE") != NULL) {
va_list msg;
fprintf(stderr, "PRI%d: ", prio);
va_start(msg, fmt);
vfprintf(stderr, fmt, msg);
va_end(msg);
fprintf(stderr, "\n");
}
}
void pr_log_stacktrace(int fd, const char *name) {
}
int pr_log_writefile(int fd, const char *name, const char *fmt, ...) {
if (getenv("TEST_VERBOSE") != NULL) {
va_list msg;
fprintf(stderr, "%s: ", name);
va_start(msg, fmt);
vfprintf(stderr, fmt, msg);
va_end(msg);
fprintf(stderr, "\n");
}
return 0;
}
int pr_scoreboard_entry_update(pid_t pid, ...) {
return 0;
}
void pr_session_disconnect(module *m, int reason_code, const char *details) {
}
const char *pr_session_get_protocol(int flags) {
return "ftp";
}
void pr_signals_handle(void) {
}
/* Module-specific stubs */
module proxy_module = {
/* Always NULL */
NULL, NULL,
/* Module API version */
0x20,
/* Module name */
"proxy",
/* Module configuration handler table */
NULL,
/* Module command handler table */
NULL,
/* Module authentication handler table */
NULL,
/* Module initialization */
NULL,
/* Session initialization */
NULL,
/* Module version */
MOD_PROXY_VERSION
};
proftpd-mod_proxy-0.8/t/api/tests.c 0000664 0000000 0000000 00000010212 14020740307 0017370 0 ustar 00root root 0000000 0000000 /*
* ProFTPD - mod_proxy API testsuite
* Copyright (c) 2012-2020 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
*
* As a special exemption, TJ Saunders and other respective copyright holders
* give permission to link this program with OpenSSL, and distribute the
* resulting executable, without including the source code for OpenSSL in the
* source distribution.
*/
#include "tests.h"
struct testsuite_info {
const char *name;
Suite *(*get_suite)(void);
};
static struct testsuite_info suites[] = {
{ "db", tests_get_db_suite },
{ "dns", tests_get_dns_suite },
{ "conn", tests_get_conn_suite },
{ "netio", tests_get_netio_suite },
{ "inet", tests_get_inet_suite },
{ "random", tests_get_random_suite },
{ "reverse", tests_get_reverse_suite },
{ "forward", tests_get_forward_suite },
{ "str", tests_get_str_suite },
{ "tls", tests_get_tls_suite },
{ "uri", tests_get_uri_suite },
{ "session", tests_get_session_suite },
{ "ftp.msg", tests_get_ftp_msg_suite },
{ "ftp.conn", tests_get_ftp_conn_suite },
{ "ftp.ctrl", tests_get_ftp_ctrl_suite },
{ "ftp.data", tests_get_ftp_data_suite },
{ "ftp.dirlist", tests_get_ftp_dirlist_suite },
{ "ftp.facts", tests_get_ftp_facts_suite },
{ "ftp.sess", tests_get_ftp_sess_suite },
{ "ftp.xfer", tests_get_ftp_xfer_suite },
{ NULL, NULL }
};
static Suite *tests_get_suite(const char *suite) {
register unsigned int i;
for (i = 0; suites[i].name != NULL; i++) {
if (strcmp(suite, suites[i].name) == 0) {
return (*suites[i].get_suite)();
}
}
errno = ENOENT;
return NULL;
}
int main(int argc, char *argv[]) {
const char *log_file = "api-tests.log";
int nfailed = 0;
SRunner *runner = NULL;
char *requested = NULL;
runner = srunner_create(NULL);
/* XXX This log name should be set outside this code, e.g. via environment
* variable or command-line option.
*/
srunner_set_log(runner, log_file);
requested = getenv("PROXY_TEST_SUITE");
if (requested) {
Suite *suite;
suite = tests_get_suite(requested);
if (suite) {
srunner_add_suite(runner, suite);
} else {
fprintf(stderr,
"No such test suite ('%s') requested via PROXY_TEST_SUITE\n",
requested);
return EXIT_FAILURE;
}
} else {
register unsigned int i;
for (i = 0; suites[i].name; i++) {
Suite *suite;
suite = (suites[i].get_suite)();
if (suite) {
srunner_add_suite(runner, suite);
}
}
}
/* Configure the Trace API to write to stderr. */
pr_trace_use_stderr(TRUE);
requested = getenv("PROXY_TEST_NOFORK");
if (requested) {
srunner_set_fork_status(runner, CK_NOFORK);
} else {
requested = getenv("CK_DEFAULT_TIMEOUT");
if (requested == NULL) {
setenv("CK_DEFAULT_TIMEOUT", "60", 1);
}
}
srunner_run_all(runner, CK_NORMAL);
nfailed = srunner_ntests_failed(runner);
if (runner)
srunner_free(runner);
if (nfailed != 0) {
fprintf(stderr, "-------------------------------------------------\n");
fprintf(stderr, " FAILED %d %s\n\n", nfailed,
nfailed != 1 ? "tests" : "test");
fprintf(stderr, " Please send email to:\n\n");
fprintf(stderr, " tj@castaglia.org\n\n");
fprintf(stderr, " containing the `%s' file (in the t/ directory)\n", log_file);
fprintf(stderr, " and the output from running `proftpd -V'\n");
fprintf(stderr, "-------------------------------------------------\n");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
proftpd-mod_proxy-0.8/t/api/tests.h 0000664 0000000 0000000 00000005540 14020740307 0017405 0 ustar 00root root 0000000 0000000 /*
* ProFTPD - mod_proxy API testsuite
* Copyright (c) 2012-2020 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
*
* As a special exemption, TJ Saunders and other respective copyright holders
* give permission to link this program with OpenSSL, and distribute the
* resulting executable, without including the source code for OpenSSL in the
* source distribution.
*/
/* Testsuite management */
#ifndef MOD_PROXY_TESTS_H
#define MOD_PROXY_TESTS_H
#include "mod_proxy.h"
#include "proxy/random.h"
#include "proxy/db.h"
#include "proxy/dns.h"
#include "proxy/conn.h"
#include "proxy/netio.h"
#include "proxy/inet.h"
#include "proxy/str.h"
#include "proxy/uri.h"
#include "proxy/tls.h"
#include "proxy/tls/db.h"
#include "proxy/tls/redis.h"
#include "proxy/session.h"
#include "proxy/reverse.h"
#include "proxy/reverse/db.h"
#include "proxy/reverse/redis.h"
#include "proxy/forward.h"
#include "proxy/ftp/msg.h"
#include "proxy/ftp/conn.h"
#include "proxy/ftp/ctrl.h"
#include "proxy/ftp/data.h"
#include "proxy/ftp/dirlist.h"
#include "proxy/ftp/facts.h"
#include "proxy/ftp/sess.h"
#include "proxy/ftp/xfer.h"
#ifdef HAVE_CHECK_H
# include
#else
# error "Missing Check installation; necessary for ProFTPD testsuite"
#endif
int tests_rmpath(pool *p, const char *path);
int tests_stubs_set_next_cmd(cmd_rec *cmd);
Suite *tests_get_conn_suite(void);
Suite *tests_get_db_suite(void);
Suite *tests_get_dns_suite(void);
Suite *tests_get_inet_suite(void);
Suite *tests_get_netio_suite(void);
Suite *tests_get_random_suite(void);
Suite *tests_get_reverse_suite(void);
Suite *tests_get_forward_suite(void);
Suite *tests_get_str_suite(void);
Suite *tests_get_tls_suite(void);
Suite *tests_get_uri_suite(void);
Suite *tests_get_session_suite(void);
Suite *tests_get_ftp_msg_suite(void);
Suite *tests_get_ftp_conn_suite(void);
Suite *tests_get_ftp_ctrl_suite(void);
Suite *tests_get_ftp_data_suite(void);
Suite *tests_get_ftp_dirlist_suite(void);
Suite *tests_get_ftp_facts_suite(void);
Suite *tests_get_ftp_sess_suite(void);
Suite *tests_get_ftp_xfer_suite(void);
extern volatile unsigned int recvd_signal_flags;
extern pid_t mpid;
extern server_rec *main_server;
#endif /* MOD_PROXY_TESTS_H */
proftpd-mod_proxy-0.8/t/api/tls.c 0000664 0000000 0000000 00000021352 14020740307 0017037 0 ustar 00root root 0000000 0000000 /*
* ProFTPD - mod_proxy testsuite
* Copyright (c) 2015-2020 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
*
* As a special exemption, TJ Saunders and other respective copyright holders
* give permission to link this program with OpenSSL, and distribute the
* resulting executable, without including the source code for OpenSSL in the
* source distribution.
*/
/* Proxy TLS API tests. */
#include "tests.h"
extern xaset_t *server_list;
static pool *p = NULL;
static const char *test_dir = "/tmp/mod_proxy-test-tls";
static void create_main_server(void) {
pool *main_pool;
main_pool = make_sub_pool(permanent_pool);
pr_pool_tag(main_pool, "testsuite#main_server pool");
server_list = xaset_create(main_pool, NULL);
main_server = (server_rec *) pcalloc(main_pool, sizeof(server_rec));
xaset_insert(server_list, (xasetmember_t *) main_server);
main_server->pool = main_pool;
main_server->conf = xaset_create(main_pool, NULL);
main_server->set = server_list;
main_server->sid = 1;
main_server->notes = pr_table_nalloc(main_pool, 0, 8);
/* TCP KeepAlive is enabled by default, with the system defaults. */
main_server->tcp_keepalive = palloc(main_server->pool,
sizeof(struct tcp_keepalive));
main_server->tcp_keepalive->keepalive_enabled = TRUE;
main_server->tcp_keepalive->keepalive_idle = -1;
main_server->tcp_keepalive->keepalive_count = -1;
main_server->tcp_keepalive->keepalive_intvl = -1;
main_server->ServerName = "Test Server";
main_server->ServerPort = 21;
}
static int create_test_dir(void) {
int res;
mode_t perms;
perms = 0770;
res = mkdir(test_dir, perms);
fail_unless(res == 0, "Failed to create tmp directory '%s': %s", test_dir,
strerror(errno));
res = chmod(test_dir, perms);
fail_unless(res == 0, "Failed to set perms %04o on directory '%s': %s",
perms, test_dir, strerror(errno));
return 0;
}
static void set_up(void) {
if (p == NULL) {
p = permanent_pool = proxy_pool = make_sub_pool(NULL);
server_list = NULL;
main_server = NULL;
session.c = NULL;
session.notes = NULL;
}
(void) tests_rmpath(p, test_dir);
create_main_server();
(void) create_test_dir();
init_netio();
proxy_db_init(p);
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("proxy.db", 1, 20);
pr_trace_set_levels("proxy.tls", 1, 20);
}
}
static void tear_down(void) {
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("proxy.db", 0, 0);
pr_trace_set_levels("proxy.tls", 0, 0);
}
proxy_db_free();
(void) tests_rmpath(p, test_dir);
if (p) {
destroy_pool(p);
p = permanent_pool = proxy_pool = NULL;
server_list = NULL;
main_server = NULL;
session.c = NULL;
session.notes = NULL;
}
}
START_TEST (tls_free_test) {
int res;
res = proxy_tls_free(NULL);
fail_unless(res < 0, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
res = proxy_tls_free(p);
fail_unless(res == 0, "Failed to free TLS API resources: %s",
strerror(errno));
}
END_TEST
START_TEST (tls_init_test) {
int res, flags = PROXY_DB_OPEN_FL_SKIP_VACUUM;
res = proxy_tls_init(NULL, NULL, flags);
#ifdef PR_USE_OPENSSL
fail_unless(res < 0, "Failed to handle null pool");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
res = proxy_tls_init(p, NULL, flags);
fail_unless(res < 0, "Failed to handle null tables directory");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
mark_point();
res = proxy_tls_init(p, test_dir, flags);
fail_unless(res == 0, "Failed to init TLS API resources: %s",
strerror(errno));
res = proxy_tls_free(p);
fail_unless(res == 0, "Failed to free TLS API resources: %s",
strerror(errno));
#else
fail_unless(res == 0, "Failed to init TLS API resources: %s",
strerror(errno));
#endif /* PR_USE_OPENSSL */
}
END_TEST
START_TEST (tls_sess_free_test) {
int res;
res = proxy_tls_sess_free(NULL);
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_tls_init(p, test_dir, PROXY_DB_OPEN_FL_SKIP_VACUUM);
fail_unless(res == 0, "Failed to init TLS API resources: %s",
strerror(errno));
mark_point();
res = proxy_tls_sess_free(p);
fail_unless(res == 0, "Failed to release TLS API session resources: %s",
strerror(errno));
res = proxy_tls_free(p);
fail_unless(res == 0, "Failed to free TLS API resources: %s",
strerror(errno));
}
END_TEST
START_TEST (tls_sess_init_test) {
#ifdef PR_USE_OPENSSL
int res, flags = PROXY_DB_OPEN_FL_SKIP_VACUUM;
res = proxy_tls_sess_init(NULL, flags);
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_tls_sess_init(p, flags);
fail_unless(res < 0, "Failed to handle invalid SSL_CTX");
fail_unless(errno == EPERM, "Expected EPERM (%d), got '%s' (%d)", EPERM,
strerror(errno), errno);
mark_point();
res = proxy_tls_init(p, test_dir, flags);
fail_unless(res == 0, "Failed to init TLS API resources: %s",
strerror(errno));
(void) proxy_db_close(p, NULL);
mark_point();
res = proxy_tls_sess_init(p, flags);
fail_unless(res == 0, "Failed to init TLS API session resources: %s",
strerror(errno));
mark_point();
res = proxy_tls_sess_free(p);
fail_unless(res == 0, "Failed to release TLS API session resources: %s",
strerror(errno));
mark_point();
res = proxy_tls_free(p);
fail_unless(res == 0, "Failed to release TLS API resources: %s",
strerror(errno));
#endif /* PR_USE_OPENSSL */
}
END_TEST
START_TEST (tls_using_tls_test) {
int res, tls;
tls = proxy_tls_using_tls();
#ifdef PR_USE_OPENSSL
fail_unless(tls == PROXY_TLS_ENGINE_AUTO, "Expected TLS auto, got %d", tls);
#else
fail_unless(tls == PROXY_TLS_ENGINE_OFF, "Expected TLS off, got %d", tls);
#endif /* PR_USE_OPENSSL */
res = proxy_tls_set_tls(7);
#ifdef PR_USE_OPENSSL
fail_unless(res < 0, "Set TLS unexpectedly");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
res = proxy_tls_set_tls(PROXY_TLS_ENGINE_ON);
tls = proxy_tls_using_tls();
fail_unless(tls == PROXY_TLS_ENGINE_ON, "Expected TLS on, got %d", tls);
res = proxy_tls_set_tls(PROXY_TLS_ENGINE_OFF);
tls = proxy_tls_using_tls();
fail_unless(tls == PROXY_TLS_ENGINE_OFF, "Expected TLS off, got %d", tls);
res = proxy_tls_set_tls(PROXY_TLS_ENGINE_AUTO);
tls = proxy_tls_using_tls();
fail_unless(tls == PROXY_TLS_ENGINE_AUTO, "Expected TLS auto, got %d", tls);
res = proxy_tls_set_tls(PROXY_TLS_ENGINE_IMPLICIT);
tls = proxy_tls_using_tls();
fail_unless(tls == PROXY_TLS_ENGINE_IMPLICIT, "Expected TLS implicit, got %d", tls);
#endif /* PR_USE_OPENSSL */
}
END_TEST
START_TEST (tls_set_data_prot_test) {
int res;
res = proxy_tls_set_data_prot(TRUE);
#ifdef PR_USE_OPENSSL
fail_unless(res == TRUE, "Expected TRUE, got %d", res);
res = proxy_tls_set_data_prot(FALSE);
fail_unless(res == TRUE, "Expected TRUE, got %d", res);
#else
fail_unless(res == FALSE, "Expected FALSE, got %d", res);
res = proxy_tls_set_data_prot(FALSE);
fail_unless(res == FALSE, "Expected FALSE, got %d", res);
#endif /* PR_USE_OPENSSL */
res = proxy_tls_set_data_prot(FALSE);
fail_unless(res == FALSE, "Expected FALSE, got %d", res);
(void) proxy_tls_set_data_prot(TRUE);
}
END_TEST
Suite *tests_get_tls_suite(void) {
Suite *suite;
TCase *testcase;
suite = suite_create("tls");
testcase = tcase_create("base");
tcase_add_checked_fixture(testcase, set_up, tear_down);
tcase_add_test(testcase, tls_free_test);
tcase_add_test(testcase, tls_init_test);
tcase_add_test(testcase, tls_sess_free_test);
tcase_add_test(testcase, tls_sess_init_test);
tcase_add_test(testcase, tls_using_tls_test);
tcase_add_test(testcase, tls_set_data_prot_test);
suite_add_tcase(suite, testcase);
return suite;
}
proftpd-mod_proxy-0.8/t/api/uri.c 0000664 0000000 0000000 00000054236 14020740307 0017043 0 ustar 00root root 0000000 0000000 /*
* ProFTPD - mod_proxy testsuite
* Copyright (c) 2012-2020 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
*
* As a special exemption, TJ Saunders and other respective copyright holders
* give permission to link this program with OpenSSL, and distribute the
* resulting executable, without including the source code for OpenSSL in the
* source distribution.
*/
/* URI API tests */
#include "tests.h"
static pool *p = NULL;
static void set_up(void) {
if (p == NULL) {
p = permanent_pool = make_sub_pool(NULL);
session.c = NULL;
session.notes = NULL;
}
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("proxy.uri", 1, 20);
}
}
static void tear_down(void) {
if (getenv("TEST_VERBOSE") != NULL) {
pr_trace_set_levels("proxy.uri", 0, 0);
}
if (p != NULL) {
destroy_pool(p);
p = permanent_pool = NULL;
session.c = NULL;
session.notes = NULL;
}
}
START_TEST (uri_parse_test) {
const char *uri;
char *scheme, *host, *username, *password;
unsigned int port;
int res;
mark_point();
res = proxy_uri_parse(NULL, NULL, NULL, NULL, NULL, NULL, NULL);
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_uri_parse(p, NULL, NULL, NULL, NULL, NULL, NULL);
fail_unless(res < 0, "Failed to handle null URI");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
mark_point();
uri = "foo";
res = proxy_uri_parse(p, uri, NULL, NULL, NULL, NULL, NULL);
fail_unless(res < 0, "Failed to handle null scheme");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
mark_point();
res = proxy_uri_parse(p, uri, &scheme, NULL, NULL, NULL, NULL);
fail_unless(res < 0, "Failed to handle null host");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
mark_point();
res = proxy_uri_parse(p, uri, &scheme, &host, NULL, NULL, NULL);
fail_unless(res < 0, "Failed to handle null port");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
mark_point();
res = proxy_uri_parse(p, uri, &scheme, &host, &port, NULL, NULL);
fail_unless(res < 0, "Failed to handle URI missing a colon");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
mark_point();
scheme = host = username = password = NULL;
port = 0;
uri = "foo:";
res = proxy_uri_parse(p, uri, &scheme, &host, &port, NULL, NULL);
fail_unless(res < 0, "Failed to handle unknown/unsupported scheme");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
mark_point();
scheme = host = username = password = NULL;
port = 0;
uri = "foo@:";
res = proxy_uri_parse(p, uri, &scheme, &host, &port, NULL, NULL);
fail_unless(res < 0, "Failed to handle illegal scheme character");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
mark_point();
scheme = host = username = password = NULL;
port = 0;
uri = "ftp:";
res = proxy_uri_parse(p, uri, &scheme, &host, &port, NULL, NULL);
fail_unless(res < 0, "Failed to handle URI lacking double slashes");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
mark_point();
scheme = host = username = password = NULL;
port = 0;
uri = "ftp:/";
res = proxy_uri_parse(p, uri, &scheme, &host, &port, NULL, NULL);
fail_unless(res < 0, "Failed to handle URI lacking double slashes");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
mark_point();
scheme = host = username = password = NULL;
port = 0;
uri = "ftp:/a";
res = proxy_uri_parse(p, uri, &scheme, &host, &port, NULL, NULL);
fail_unless(res < 0, "Failed to handle URI lacking double slashes");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
mark_point();
scheme = host = username = password = NULL;
port = 0;
uri = "ftp://";
res = proxy_uri_parse(p, uri, &scheme, &host, &port, NULL, NULL);
fail_unless(res < 0, "Failed to handle URI lacking hostname/port");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
mark_point();
scheme = host = username = password = NULL;
port = 0;
uri = "ftp://%2f";
res = proxy_uri_parse(p, uri, &scheme, &host, &port, NULL, NULL);
fail_unless(res < 0, "Failed to handle URI using URL encoding");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
mark_point();
scheme = host = username = password = NULL;
port = 0;
uri = "ftp://foo";
res = proxy_uri_parse(p, uri, &scheme, &host, &port, &username, &password);
fail_unless(res == 0, "Expected successful parsing of URI '%s', got %s", uri,
strerror(errno));
fail_unless(strcmp(scheme, "ftp") == 0,
"Expected scheme '%s', got '%s'", "ftp", scheme);
fail_unless(strcmp(host, "foo") == 0,
"Expected host '%s', got '%s'", "foo", host);
fail_unless(port == 21,
"Expected port '%u', got '%u'", 21, port);
fail_unless(username == NULL, "Expected null username, got '%s'", username);
fail_unless(password == NULL, "Expected null password, got '%s'", password);
mark_point();
scheme = host = username = password = NULL;
port = 0;
uri = "ftps://foo";
res = proxy_uri_parse(p, uri, &scheme, &host, &port, &username, &password);
fail_unless(res == 0, "Expected successful parsing of URI '%s', got %s", uri,
strerror(errno));
fail_unless(strcmp(scheme, "ftps") == 0,
"Expected scheme '%s', got '%s'", "ftps", scheme);
fail_unless(strcmp(host, "foo") == 0,
"Expected host '%s', got '%s'", "foo", host);
fail_unless(port == 21,
"Expected port '%u', got '%u'", 21, port);
fail_unless(username == NULL, "Expected null username, got '%s'", username);
fail_unless(password == NULL, "Expected null password, got '%s'", password);
mark_point();
scheme = host = username = password = NULL;
port = 0;
uri = "sftp://foo";
res = proxy_uri_parse(p, uri, &scheme, &host, &port, &username, &password);
fail_unless(res == 0, "Expected successful parsing of URI '%s', got %s", uri,
strerror(errno));
fail_unless(strcmp(scheme, "sftp") == 0,
"Expected scheme '%s', got '%s'", "sftp", scheme);
fail_unless(strcmp(host, "foo") == 0,
"Expected host '%s', got '%s'", "foo", host);
fail_unless(port == 22,
"Expected port '%u', got '%u'", 22, port);
fail_unless(username == NULL, "Expected null username, got '%s'", username);
fail_unless(password == NULL, "Expected null password, got '%s'", password);
mark_point();
scheme = host = username = password = NULL;
port = 0;
uri = "ftp://foo:2121";
res = proxy_uri_parse(p, uri, &scheme, &host, &port, &username, &password);
fail_unless(res == 0, "Expected successful parsing of URI '%s', got %s", uri,
strerror(errno));
fail_unless(strcmp(scheme, "ftp") == 0,
"Expected scheme '%s', got '%s'", "ftp", scheme);
fail_unless(strcmp(host, "foo") == 0,
"Expected host '%s', got '%s'", "foo", host);
fail_unless(port == 2121,
"Expected port '%u', got '%u'", 2121, port);
fail_unless(username == NULL, "Expected null username, got '%s'", username);
fail_unless(password == NULL, "Expected null password, got '%s'", password);
mark_point();
scheme = host = username = password = NULL;
port = 0;
uri = "ftp://127.0.0.1:2121";
res = proxy_uri_parse(p, uri, &scheme, &host, &port, &username, &password);
fail_unless(res == 0, "Expected successful parsing of URI '%s', got %s", uri,
strerror(errno));
fail_unless(strcmp(scheme, "ftp") == 0,
"Expected scheme '%s', got '%s'", "ftp", scheme);
fail_unless(strcmp(host, "127.0.0.1") == 0,
"Expected host '%s', got '%s'", "127.0.0.1", host);
fail_unless(port == 2121,
"Expected port '%u', got '%u'", 2121, port);
fail_unless(username == NULL, "Expected null username, got '%s'", username);
fail_unless(password == NULL, "Expected null password, got '%s'", password);
mark_point();
scheme = host = username = password = NULL;
port = 0;
uri = "ftp://[::1]:2121";
res = proxy_uri_parse(p, uri, &scheme, &host, &port, &username, &password);
fail_unless(res == 0, "Expected successful parsing of URI '%s', got %s", uri,
strerror(errno));
fail_unless(strcmp(scheme, "ftp") == 0,
"Expected scheme '%s', got '%s'", "ftp", scheme);
fail_unless(strcmp(host, "::1") == 0,
"Expected host '%s', got '%s'", "::1", host);
fail_unless(port == 2121,
"Expected port '%u', got '%u'", 2121, port);
fail_unless(username == NULL, "Expected null username, got '%s'", username);
fail_unless(password == NULL, "Expected null password, got '%s'", password);
mark_point();
scheme = host = username = password = NULL;
port = 0;
uri = "ftp://[::1:2121";
res = proxy_uri_parse(p, uri, &scheme, &host, &port, &username, &password);
fail_unless(res < 0, "Failed to reject URI with bad IPv6 host encoding");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
mark_point();
scheme = host = username = password = NULL;
port = 0;
uri = "ftps://foo:2121";
res = proxy_uri_parse(p, uri, &scheme, &host, &port, &username, &password);
fail_unless(res == 0, "Expected successful parsing of URI '%s', got %s", uri,
strerror(errno));
fail_unless(strcmp(scheme, "ftps") == 0,
"Expected scheme '%s', got '%s'", "ftps", scheme);
fail_unless(strcmp(host, "foo") == 0,
"Expected host '%s', got '%s'", "foo", host);
fail_unless(port == 2121,
"Expected port '%u', got '%u'", 2121, port);
fail_unless(username == NULL, "Expected null username, got '%s'", username);
fail_unless(password == NULL, "Expected null password, got '%s'", password);
mark_point();
scheme = host = username = password = NULL;
port = 0;
uri = "sftp://foo:2222";
res = proxy_uri_parse(p, uri, &scheme, &host, &port, &username, &password);
fail_unless(res == 0, "Expected successful parsing of URI '%s', got %s", uri,
strerror(errno));
fail_unless(strcmp(scheme, "sftp") == 0,
"Expected scheme '%s', got '%s'", "sftp", scheme);
fail_unless(strcmp(host, "foo") == 0,
"Expected host '%s', got '%s'", "foo", host);
fail_unless(port == 2222,
"Expected port '%u', got '%u'", 2222, port);
fail_unless(username == NULL, "Expected null username, got '%s'", username);
fail_unless(password == NULL, "Expected null password, got '%s'", password);
mark_point();
scheme = host = username = password = NULL;
port = 0;
uri = "ftp://user:password@host:21";
res = proxy_uri_parse(p, uri, &scheme, &host, &port, &username, &password);
fail_unless(res == 0, "Expected successful parsing of URI '%s', got %s", uri,
strerror(errno));
fail_unless(strcmp(scheme, "ftp") == 0,
"Expected scheme '%s', got '%s'", "ftp", scheme);
fail_unless(strcmp(host, "host") == 0,
"Expected host '%s', got '%s'", "host", host);
fail_unless(port == 21,
"Expected port '%u', got '%u'", 21, port);
fail_unless(username != NULL, "Expected non-null username");
fail_unless(strcmp(username, "user") == 0,
"Expected username '%s', got '%s'", "user", username);
fail_unless(password != NULL, "Expected non-null password");
fail_unless(strcmp(password, "password") == 0,
"Expected password '%s', got '%s'", "password", password);
mark_point();
scheme = host = username = password = NULL;
port = 0;
uri = "ftp://user:@host:21";
res = proxy_uri_parse(p, uri, &scheme, &host, &port, &username, &password);
fail_unless(res == 0, "Expected successful parsing of URI '%s', got %s", uri,
strerror(errno));
fail_unless(strcmp(scheme, "ftp") == 0,
"Expected scheme '%s', got '%s'", "ftp", scheme);
fail_unless(strcmp(host, "host") == 0,
"Expected host '%s', got '%s'", "host", host);
fail_unless(port == 21,
"Expected port '%u', got '%u'", 21, port);
fail_unless(username != NULL, "Expected non-null username");
fail_unless(strcmp(username, "user") == 0,
"Expected username '%s', got '%s'", "user", username);
fail_unless(password != NULL, "Expected non-null password");
fail_unless(strcmp(password, "") == 0,
"Expected password '%s', got '%s'", "", password);
mark_point();
scheme = host = username = password = NULL;
port = 0;
uri = "ftp://user@host:21";
res = proxy_uri_parse(p, uri, &scheme, &host, &port, &username, &password);
fail_unless(res == 0, "Expected successful parsing of URI '%s', got %s", uri,
strerror(errno));
fail_unless(strcmp(scheme, "ftp") == 0,
"Expected scheme '%s', got '%s'", "ftp", scheme);
fail_unless(strcmp(host, "host") == 0,
"Expected host '%s', got '%s'", "host", host);
fail_unless(port == 21,
"Expected port '%u', got '%u'", 21, port);
fail_unless(username == NULL, "Expected null username, got '%s'", username);
fail_unless(password == NULL, "Expected null password, got '%s'", password);
mark_point();
scheme = host = username = password = NULL;
port = 0;
uri = "ftp://anonymous:email@example.com@host:21";
res = proxy_uri_parse(p, uri, &scheme, &host, &port, &username, &password);
fail_unless(res == 0, "Expected successful parsing of URI '%s', got %s", uri,
strerror(errno));
fail_unless(strcmp(scheme, "ftp") == 0,
"Expected scheme '%s', got '%s'", "ftp", scheme);
fail_unless(strcmp(host, "host") == 0,
"Expected host '%s', got '%s'", "host", host);
fail_unless(port == 21,
"Expected port '%u', got '%u'", 21, port);
fail_unless(username != NULL, "Expected non-null username");
fail_unless(strcmp(username, "anonymous") == 0,
"Expected username '%s', got '%s'", "anonymous", username);
fail_unless(password != NULL, "Expected non-null password");
fail_unless(strcmp(password, "email@example.com") == 0,
"Expected password '%s', got '%s'", "email@example.com", password);
mark_point();
scheme = host = username = password = NULL;
port = 0;
uri = "ftp://user@domain:email@example.com@host:21";
res = proxy_uri_parse(p, uri, &scheme, &host, &port, &username, &password);
fail_unless(res == 0, "Expected successful parsing of URI '%s', got %s", uri,
strerror(errno));
fail_unless(strcmp(scheme, "ftp") == 0,
"Expected scheme '%s', got '%s'", "ftp", scheme);
fail_unless(strcmp(host, "host") == 0,
"Expected host '%s', got '%s'", "host", host);
fail_unless(port == 21,
"Expected port '%u', got '%u'", 21, port);
fail_unless(username != NULL, "Expected non-null username");
fail_unless(strcmp(username, "user@domain") == 0,
"Expected username '%s', got '%s'", "user@domain", username);
fail_unless(password != NULL, "Expected non-null password");
fail_unless(strcmp(password, "email@example.com") == 0,
"Expected password '%s', got '%s'", "email@example.com", password);
mark_point();
scheme = host = username = password = NULL;
port = 0;
uri = "ftp://host:65555";
res = proxy_uri_parse(p, uri, &scheme, &host, &port, NULL, NULL);
fail_unless(res < 0, "Failed to reject URI with too-large port");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
mark_point();
scheme = host = username = password = NULL;
port = 0;
uri = "ftp://foo:2121/home";
res = proxy_uri_parse(p, uri, &scheme, &host, &port, &username, &password);
fail_unless(res == 0, "Expected successful parsing of URI '%s', got %s", uri,
strerror(errno));
fail_unless(strcmp(scheme, "ftp") == 0,
"Expected scheme '%s', got '%s'", "ftp", scheme);
fail_unless(strcmp(host, "foo") == 0,
"Expected host '%s', got '%s'", "foo", host);
fail_unless(port == 2121,
"Expected port '%u', got '%u'", 2121, port);
fail_unless(username == NULL, "Expected null username, got '%s'", username);
fail_unless(password == NULL, "Expected null password, got '%s'", password);
mark_point();
scheme = host = username = password = NULL;
port = 0;
uri = "ftps://foo:2121/home";
res = proxy_uri_parse(p, uri, &scheme, &host, &port, &username, &password);
fail_unless(res == 0, "Expected successful parsing of URI '%s', got %s", uri,
strerror(errno));
fail_unless(strcmp(scheme, "ftps") == 0,
"Expected scheme '%s', got '%s'", "ftps", scheme);
fail_unless(strcmp(host, "foo") == 0,
"Expected host '%s', got '%s'", "foo", host);
fail_unless(port == 2121,
"Expected port '%u', got '%u'", 2121, port);
fail_unless(username == NULL, "Expected null username, got '%s'", username);
fail_unless(password == NULL, "Expected null password, got '%s'", password);
mark_point();
scheme = host = username = password = NULL;
port = 0;
uri = "sftp://foo:2222/home";
res = proxy_uri_parse(p, uri, &scheme, &host, &port, &username, &password);
fail_unless(res == 0, "Expected successful parsing of URI '%s', got %s", uri,
strerror(errno));
fail_unless(strcmp(scheme, "sftp") == 0,
"Expected scheme '%s', got '%s'", "sftp", scheme);
fail_unless(strcmp(host, "foo") == 0,
"Expected host '%s', got '%s'", "foo", host);
fail_unless(port == 2222,
"Expected port '%u', got '%u'", 2222, port);
fail_unless(username == NULL, "Expected null username, got '%s'", username);
fail_unless(password == NULL, "Expected null password, got '%s'", password);
mark_point();
scheme = host = username = password = NULL;
port = 0;
uri = "ftp://host:65555:foo";
res = proxy_uri_parse(p, uri, &scheme, &host, &port, NULL, NULL);
fail_unless(res < 0, "Failed to reject URI with bad port spec");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
mark_point();
scheme = host = username = password = NULL;
port = 0;
uri = "ftp://host:70000";
res = proxy_uri_parse(p, uri, &scheme, &host, &port, NULL, NULL);
fail_unless(res < 0, "Failed to reject URI with invalid port spec");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
mark_point();
scheme = host = username = password = NULL;
port = 0;
uri = "http://host";
res = proxy_uri_parse(p, uri, &scheme, &host, &port, NULL, NULL);
fail_unless(res < 0, "Failed to reject URI with unsupported scheme");
fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
strerror(errno), errno);
/* SRV scheme variants */
mark_point();
scheme = host = username = password = NULL;
port = 0;
uri = "ftp+srv://foo:2121/home";
res = proxy_uri_parse(p, uri, &scheme, &host, &port, &username, &password);
fail_unless(res == 0, "Expected successful parsing of URI '%s', got %s", uri,
strerror(errno));
fail_unless(strcmp(scheme, "ftp+srv") == 0,
"Expected scheme '%s', got '%s'", "ftp+srv", scheme);
fail_unless(strcmp(host, "foo") == 0,
"Expected host '%s', got '%s'", "foo", host);
fail_unless(port == 0,
"Expected port '%u', got '%u'", 0, port);
fail_unless(username == NULL, "Expected null username, got '%s'", username);
fail_unless(password == NULL, "Expected null password, got '%s'", password);
mark_point();
scheme = host = username = password = NULL;
port = 0;
uri = "ftps+srv://foo.bar";
res = proxy_uri_parse(p, uri, &scheme, &host, &port, &username, &password);
fail_unless(res == 0, "Expected successful parsing of URI '%s', got %s", uri,
strerror(errno));
fail_unless(strcmp(scheme, "ftps+srv") == 0,
"Expected scheme '%s', got '%s'", "ftps+srv", scheme);
fail_unless(strcmp(host, "foo.bar") == 0,
"Expected host '%s', got '%s'", "foo.bar", host);
fail_unless(port == 0,
"Expected port '%u', got '%u'", 0, port);
fail_unless(username == NULL, "Expected null username, got '%s'", username);
fail_unless(password == NULL, "Expected null password, got '%s'", password);
/* TXT scheme variants */
mark_point();
scheme = host = username = password = NULL;
port = 0;
uri = "ftp+txt://foo:2121/home";
res = proxy_uri_parse(p, uri, &scheme, &host, &port, &username, &password);
fail_unless(res == 0, "Expected successful parsing of URI '%s', got %s", uri,
strerror(errno));
fail_unless(strcmp(scheme, "ftp+txt") == 0,
"Expected scheme '%s', got '%s'", "ftp+txt", scheme);
fail_unless(strcmp(host, "foo") == 0,
"Expected host '%s', got '%s'", "foo", host);
fail_unless(port == 0,
"Expected port '%u', got '%u'", 0, port);
fail_unless(username == NULL, "Expected null username, got '%s'", username);
fail_unless(password == NULL, "Expected null password, got '%s'", password);
mark_point();
scheme = host = username = password = NULL;
port = 0;
uri = "ftps+txt://foo.bar";
res = proxy_uri_parse(p, uri, &scheme, &host, &port, &username, &password);
fail_unless(res == 0, "Expected successful parsing of URI '%s', got %s", uri,
strerror(errno));
fail_unless(strcmp(scheme, "ftps+txt") == 0,
"Expected scheme '%s', got '%s'", "ftps+txt", scheme);
fail_unless(strcmp(host, "foo.bar") == 0,
"Expected host '%s', got '%s'", "foo.bar", host);
fail_unless(port == 0,
"Expected port '%u', got '%u'", 0, port);
fail_unless(username == NULL, "Expected null username, got '%s'", username);
fail_unless(password == NULL, "Expected null password, got '%s'", password);
}
END_TEST
Suite *tests_get_uri_suite(void) {
Suite *suite;
TCase *testcase;
suite = suite_create("uri");
testcase = tcase_create("base");
tcase_add_checked_fixture(testcase, set_up, tear_down);
tcase_add_test(testcase, uri_parse_test);
suite_add_tcase(suite, testcase);
return suite;
}
proftpd-mod_proxy-0.8/t/etc/ 0000775 0000000 0000000 00000000000 14020740307 0016070 5 ustar 00root root 0000000 0000000 proftpd-mod_proxy-0.8/t/etc/modules/ 0000775 0000000 0000000 00000000000 14020740307 0017540 5 ustar 00root root 0000000 0000000 proftpd-mod_proxy-0.8/t/etc/modules/mod_tls/ 0000775 0000000 0000000 00000000000 14020740307 0021201 5 ustar 00root root 0000000 0000000 proftpd-mod_proxy-0.8/t/etc/modules/mod_tls/ca-cert.pem 0000664 0000000 0000000 00000004651 14020740307 0023230 0 ustar 00root root 0000000 0000000 -----BEGIN CERTIFICATE-----
MIIEZTCCA86gAwIBAgIBADANBgkqhkiG9w0BAQUFADCBvjEQMA4GA1UEAxMHY2Et
Y2VydDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT
B1NlYXR0bGUxEjAQBgNVBAoTCUNhc3RhZ2xpYTErMCkGA1UECxMiQ2FzdGFnbGlh
IFJlc2VhcmNoIGFuZCBEZXZlbG9wbWVudDEUMBIGA1UECxMLVEogU2F1bmRlcnMx
HzAdBgkqhkiG9w0BCQEWEHRqQGNhc3RhZ2xpYS5vcmcwHhcNMTAwNjI5MTYyNDEw
WhcNMjAwNjI2MTYyNDEwWjCBvjEQMA4GA1UEAxMHY2EtY2VydDELMAkGA1UEBhMC
VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1NlYXR0bGUxEjAQBgNV
BAoTCUNhc3RhZ2xpYTErMCkGA1UECxMiQ2FzdGFnbGlhIFJlc2VhcmNoIGFuZCBE
ZXZlbG9wbWVudDEUMBIGA1UECxMLVEogU2F1bmRlcnMxHzAdBgkqhkiG9w0BCQEW
EHRqQGNhc3RhZ2xpYS5vcmcwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALWi
DVcsabN5AxcvbwWozT3+sl++c2QBRFVJlRh36BAOl/PhxeJQl5g/EUJiYMu6I1oQ
tQPHXZR0ydMOhP83z/ss58fMey4ORUM4YeG4VyVWvp1K2Xb7CkzBUdta15elxTFJ
KACJa3TXThHaEU6+DCWAjyLIwLEYgotF63MeCpYlAgMBAAGjggFvMIIBazAMBgNV
HRMEBTADAQH/ME4GA1UdEQRHMEWCEXd3dy5jYXN0YWdsaWEub3JngRB0akBjYXN0
YWdsaWEub3JnhwR/AAABhhhodHRwOi8vd3d3LmNhc3RhZ2xpYS5vcmcwHQYDVR0O
BBYEFNPnga0QioAG4wJj4tA5rkbgcJubMIHrBgNVHSMEgeMwgeCAFNPnga0QioAG
4wJj4tA5rkbgcJuboYHEpIHBMIG+MRAwDgYDVQQDEwdjYS1jZXJ0MQswCQYDVQQG
EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHU2VhdHRsZTESMBAG
A1UEChMJQ2FzdGFnbGlhMSswKQYDVQQLEyJDYXN0YWdsaWEgUmVzZWFyY2ggYW5k
IERldmVsb3BtZW50MRQwEgYDVQQLEwtUSiBTYXVuZGVyczEfMB0GCSqGSIb3DQEJ
ARYQdGpAY2FzdGFnbGlhLm9yZ4IBADANBgkqhkiG9w0BAQUFAAOBgQAG7Wmx9l9B
Q2G2mNxFYWZKB7Zxf5pMsckiXCa+4lku5W4apsdLlA8QrkTezsOlpJZQaxwq2R2K
FFvIp9XD6L4mmGWjaffp4PDLtbE6d3U3HFmRdKK7f0OLBqSNvsp0v+7D3GzHN3+o
pqr76JfEI5biylaX2YXvLZki0ht9qlKt6g==
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQC1og1XLGmzeQMXL28FqM09/rJfvnNkAURVSZUYd+gQDpfz4cXi
UJeYPxFCYmDLuiNaELUDx12UdMnTDoT/N8/7LOfHzHsuDkVDOGHhuFclVr6dStl2
+wpMwVHbWteXpcUxSSgAiWt0104R2hFOvgwlgI8iyMCxGIKLRetzHgqWJQIDAQAB
AoGAVJqyehue9NF2ZhNbNJinWaxM7BorZ7bLXKrUvzwDJY+WqixNX5jItEsUQAbR
LbR7iRVlK+hup5sq85u8yaD2yC/juo23QrPnRSEEXM6HFMfJ+/ZuwAqaP48NnxFL
fy+AX1zaieePCLj/IcMj64mT9h/avvSBppX98BUzuh/YrAECQQDvuzFtw9SC8L4F
rNNggAdtW/LkP6Lx3n0N5JSM7ClqYOM+NnAimhDoR7/y+Qx9nzU6CuAHGUKB3U4u
ThaDNC0BAkEAwfWHii64o+00S7XSFQV9K2bx0AhGy6hCLQfwXKuM3btpXMzk34kC
HnDB3tzDP+bDx+FlwfFFJdLu9WJyfM8VJQJBALC1VzYFx7vNIQSl5BmZxd/Ci0Pb
9Iw86Ak5mJZX7h9P07GkBvw6fIP7f23mTmK63E0wfvo8kF2Rd3OCc+26pAECQFFj
IdjN+hRvOH58cQb5IqjPrbBJiMt0czBKIIYCRj3UokWahH94EjeLwQ4vPI7X2ldJ
MVXMU+OnOzYkdT4B9zECQDmnnMHaWJQGfjjQCXFQJvce+aPxV40CTf5opLsvEyPS
zNgD0rFPqX9h6ap37NE7qlOb2Ffp577A2AuEeEa0KdM=
-----END RSA PRIVATE KEY-----
proftpd-mod_proxy-0.8/t/etc/modules/mod_tls/client-cert.pem 0000664 0000000 0000000 00000011747 14020740307 0024127 0 ustar 00root root 0000000 0000000 Certificate:
Data:
Version: 3 (0x2)
Serial Number: 17 (0x11)
Signature Algorithm: sha1WithRSAEncryption
Issuer: CN=ca-cert, C=US, ST=Washington, L=Seattle, O=Castaglia, OU=Castaglia Research and Development, OU=TJ Saunders/emailAddress=tj@castaglia.org
Validity
Not Before: Jun 29 16:24:56 2010 GMT
Not After : Jun 26 16:24:56 2020 GMT
Subject: CN=client-cert, C=US/emailAddress=tj@castaglia.org, O=Castaglia, OU=Castaglia Research and Development, OU=TJ Saunders, ST=Washington
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (1024 bit)
Modulus (1024 bit):
00:c0:37:cd:37:10:30:b7:61:a2:54:8e:2e:03:b6:
10:63:55:7b:1d:6f:74:fe:63:50:fe:d1:4b:00:85:
68:1b:ba:34:06:0f:a6:e4:55:07:dd:8d:73:4e:59:
fb:f4:5c:fa:eb:bb:84:ea:80:cc:8e:7f:7d:46:6c:
c3:e5:56:bc:74:56:62:db:28:59:6f:6b:79:16:66:
df:07:91:aa:63:df:0b:9e:1e:85:bd:86:42:a5:a9:
03:c5:b4:e9:91:d7:bb:ac:c9:40:c4:53:65:58:e0:
27:48:78:68:33:54:4d:74:30:59:3b:b5:a4:cc:3a:
e5:9a:b9:c0:72:dc:ba:34:67
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Comment:
CertTool Certificate
X509v3 Subject Alternative Name:
DNS:familiar.castaglia.org, email:tj@castaglia.org, IP Address:127.0.0.1, URI:http://www.castaglia.org
X509v3 Subject Key Identifier:
E5:B0:C4:5B:D8:0A:C1:B5:0A:6B:F7:18:64:1D:EB:6D:39:E1:B2:77
X509v3 Authority Key Identifier:
keyid:D3:E7:81:AD:10:8A:80:06:E3:02:63:E2:D0:39:AE:46:E0:70:9B:9B
DirName:/CN=ca-cert/C=US/ST=Washington/L=Seattle/O=Castaglia/OU=Castaglia Research and Development/OU=TJ Saunders/emailAddress=tj@castaglia.org
serial:00
Signature Algorithm: sha1WithRSAEncryption
3f:3e:b9:08:67:f9:8f:ca:30:38:b3:c2:29:73:52:29:52:bd:
b7:a3:d3:5a:d2:64:24:29:52:6b:ba:db:72:d8:7c:d6:f3:54:
0e:51:0c:2e:e8:2e:dc:0f:d9:88:9a:bc:67:fa:a1:cb:57:fd:
a6:33:50:72:7a:8c:52:56:15:ad:18:7a:1c:04:82:d9:69:d6:
f0:5a:60:d4:d2:84:d1:fb:fd:37:14:3e:8c:63:3f:a7:4a:1a:
2e:62:3d:6d:cb:69:68:c4:5e:c2:57:89:5f:f0:45:a8:d5:74:
b7:7d:b1:b4:e0:b4:94:20:e7:32:7c:c8:60:93:8e:dc:80:16:
3f:6d
-----BEGIN CERTIFICATE-----
MIIEfjCCA+egAwIBAgIBETANBgkqhkiG9w0BAQUFADCBvjEQMA4GA1UEAxMHY2Et
Y2VydDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT
B1NlYXR0bGUxEjAQBgNVBAoTCUNhc3RhZ2xpYTErMCkGA1UECxMiQ2FzdGFnbGlh
IFJlc2VhcmNoIGFuZCBEZXZlbG9wbWVudDEUMBIGA1UECxMLVEogU2F1bmRlcnMx
HzAdBgkqhkiG9w0BCQEWEHRqQGNhc3RhZ2xpYS5vcmcwHhcNMTAwNjI5MTYyNDU2
WhcNMjAwNjI2MTYyNDU2WjCBsDEUMBIGA1UEAxMLY2xpZW50LWNlcnQxCzAJBgNV
BAYTAlVTMR8wHQYJKoZIhvcNAQkBFhB0akBjYXN0YWdsaWEub3JnMRIwEAYDVQQK
EwlDYXN0YWdsaWExKzApBgNVBAsTIkNhc3RhZ2xpYSBSZXNlYXJjaCBhbmQgRGV2
ZWxvcG1lbnQxFDASBgNVBAsTC1RKIFNhdW5kZXJzMRMwEQYDVQQIEwpXYXNoaW5n
dG9uMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDAN803EDC3YaJUji4DthBj
VXsdb3T+Y1D+0UsAhWgbujQGD6bkVQfdjXNOWfv0XPrru4TqgMyOf31GbMPlVrx0
VmLbKFlva3kWZt8Hkapj3wueHoW9hkKlqQPFtOmR17usyUDEU2VY4CdIeGgzVE10
MFk7taTMOuWaucBy3Lo0ZwIDAQABo4IBljCCAZIwCQYDVR0TBAIwADAjBglghkgB
hvhCAQ0EFhYUQ2VydFRvb2wgQ2VydGlmaWNhdGUwUwYDVR0RBEwwSoIWZmFtaWxp
YXIuY2FzdGFnbGlhLm9yZ4EQdGpAY2FzdGFnbGlhLm9yZ4cEfwAAAYYYaHR0cDov
L3d3dy5jYXN0YWdsaWEub3JnMB0GA1UdDgQWBBTlsMRb2ArBtQpr9xhkHettOeGy
dzCB6wYDVR0jBIHjMIHggBTT54GtEIqABuMCY+LQOa5G4HCbm6GBxKSBwTCBvjEQ
MA4GA1UEAxMHY2EtY2VydDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0
b24xEDAOBgNVBAcTB1NlYXR0bGUxEjAQBgNVBAoTCUNhc3RhZ2xpYTErMCkGA1UE
CxMiQ2FzdGFnbGlhIFJlc2VhcmNoIGFuZCBEZXZlbG9wbWVudDEUMBIGA1UECxML
VEogU2F1bmRlcnMxHzAdBgkqhkiG9w0BCQEWEHRqQGNhc3RhZ2xpYS5vcmeCAQAw
DQYJKoZIhvcNAQEFBQADgYEAPz65CGf5j8owOLPCKXNSKVK9t6PTWtJkJClSa7rb
cth81vNUDlEMLugu3A/ZiJq8Z/qhy1f9pjNQcnqMUlYVrRh6HASC2WnW8Fpg1NKE
0fv9NxQ+jGM/p0oaLmI9bctpaMRewleJX/BFqNV0t32xtOC0lCDnMnzIYJOO3IAW
P20=
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDAN803EDC3YaJUji4DthBjVXsdb3T+Y1D+0UsAhWgbujQGD6bk
VQfdjXNOWfv0XPrru4TqgMyOf31GbMPlVrx0VmLbKFlva3kWZt8Hkapj3wueHoW9
hkKlqQPFtOmR17usyUDEU2VY4CdIeGgzVE10MFk7taTMOuWaucBy3Lo0ZwIDAQAB
AoGBAJXi7YMifNqCp7KHrBn4vo62+Wnan8A+ccpCKdoeLTBx4l9XlSw3ogqBYoiW
YoIKfx+S+fJivR/hCi8AYUFUgV5bkBxkHCdDRDZxPEV7ntKShHVhwdPavOlk49np
xTWAvdtKO1sxwMO4FQyFUdtiK7xoHxe+0ln6uusRNjzGo6cBAkEA7xzYUON8y2Cl
Dw31Tr3LfkO8an4HaRfh+lHRQz1fX74gpNNlCuW/wv2l9ur2BPb1XebaGazCYkrI
53yv+cSkAwJBAM3LGdLZb/u629XhJdvUUZlAY1rycYXCY1UuWqXGVGwxBhcrTRqD
LW2CaxHtm05XJMtBfYMSXSMKMxAiWUOeSs0CQCpp+nD2uUc2IHE4L6BFCFigWUam
jlf09Y+6fZ0owMcx6YZzPQQe1tIWvh67dOJSkBmU/nD5dQ2MaHCvbGOontMCQC+k
SUIq3GXmiGYnTWBq8skLwvSXE/jnW5+or4uZMoopf0N13s+4dpfXjXoFC+NDAV2c
t7XUVoN6JQAjM48X4jECQQDMateInnOkLFOHIN4LSNO5zHmmorm2gLXUL0CYdOJy
r/X6TZCD4g5T7Ol4h5RGSnaltG3KBUD2BCASRjxcOyRR
-----END RSA PRIVATE KEY-----
proftpd-mod_proxy-0.8/t/etc/modules/mod_tls/psk.dat 0000664 0000000 0000000 00000000501 14020740307 0022464 0 ustar 00root root 0000000 0000000 25e262660dc554c2e77f33e3cdc9e7467070d4e6193a6a87f6ba6c08aeb76246278e8ca50d41254315cbc6f5a3afc87922620151a16fffde6b38dd3c8bf71e7ba87d95d880f2d6049d8b148a5883234189b7a5249d787e0b2fe4befe41bfce0b29634f6acde3db0e477d49efb766772a78de99e0ff316e6910b0c83c2875c77a551bf2e940807b5e705516509a00c9fc7d88956f89b6600efc4ca74bd12493a5
proftpd-mod_proxy-0.8/t/etc/modules/mod_tls/server-cert.pem 0000664 0000000 0000000 00000011747 14020740307 0024157 0 ustar 00root root 0000000 0000000 Certificate:
Data:
Version: 3 (0x2)
Serial Number: 16 (0x10)
Signature Algorithm: sha1WithRSAEncryption
Issuer: CN=ca-cert, C=US, ST=Washington, L=Seattle, O=Castaglia, OU=Castaglia Research and Development, OU=TJ Saunders/emailAddress=tj@castaglia.org
Validity
Not Before: Jun 29 16:24:34 2010 GMT
Not After : Jun 26 16:24:34 2020 GMT
Subject: CN=server-cert, C=US/emailAddress=tj@castaglia.org, O=Castaglia, OU=Castaglia Research and Development, OU=TJ Saunders, ST=Washington
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (1024 bit)
Modulus (1024 bit):
00:b3:a8:42:3c:58:10:ee:18:d2:32:67:21:63:dc:
e7:22:d6:e9:c0:50:08:70:3a:50:cd:9a:87:1b:72:
0b:0d:15:e6:60:c7:09:2d:14:cf:36:da:59:87:ca:
0d:49:ea:ca:48:7f:7a:1d:95:e7:2e:a8:5d:bd:fe:
9c:2b:24:21:49:bf:ed:c6:99:5a:a6:f7:0e:3c:05:
81:1a:35:a9:69:d5:95:db:77:3f:c0:56:62:a4:4b:
83:51:b1:3a:a1:a5:ba:e4:bc:cb:9b:dc:d4:cd:96:
a2:d6:86:52:cd:4d:08:4b:50:fd:a9:25:40:6d:75:
ea:8b:7a:0d:ba:13:06:95:81
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Comment:
CertTool Certificate
X509v3 Subject Alternative Name:
DNS:familiar.castaglia.org, email:tj@castaglia.org, IP Address:127.0.0.1, URI:http://www.castaglia.org
X509v3 Subject Key Identifier:
5B:7B:5E:F5:33:1C:69:75:D4:47:D4:C1:26:F3:CB:2A:B0:CF:EC:79
X509v3 Authority Key Identifier:
keyid:D3:E7:81:AD:10:8A:80:06:E3:02:63:E2:D0:39:AE:46:E0:70:9B:9B
DirName:/CN=ca-cert/C=US/ST=Washington/L=Seattle/O=Castaglia/OU=Castaglia Research and Development/OU=TJ Saunders/emailAddress=tj@castaglia.org
serial:00
Signature Algorithm: sha1WithRSAEncryption
2b:5f:59:94:b2:60:b7:c0:26:9b:ec:86:a6:4c:ea:e1:37:36:
92:6d:2f:c5:fc:ad:ca:e6:60:1f:56:88:32:8b:df:1a:67:35:
b9:62:1f:4a:d1:dd:77:08:86:81:8c:ed:66:5a:99:35:d2:9d:
30:64:9c:56:21:54:75:cf:bc:94:83:d3:bd:13:a3:2b:b7:ed:
a7:31:53:43:6c:08:ee:15:7e:cb:19:9e:1e:fc:03:10:82:6b:
a9:0e:12:42:2f:7b:33:fd:3b:c7:59:20:13:93:c1:ce:b5:b1:
77:7f:d3:ae:7e:84:77:f5:ec:b0:1b:51:6b:7a:cf:a8:66:63:
f1:46
-----BEGIN CERTIFICATE-----
MIIEfjCCA+egAwIBAgIBEDANBgkqhkiG9w0BAQUFADCBvjEQMA4GA1UEAxMHY2Et
Y2VydDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT
B1NlYXR0bGUxEjAQBgNVBAoTCUNhc3RhZ2xpYTErMCkGA1UECxMiQ2FzdGFnbGlh
IFJlc2VhcmNoIGFuZCBEZXZlbG9wbWVudDEUMBIGA1UECxMLVEogU2F1bmRlcnMx
HzAdBgkqhkiG9w0BCQEWEHRqQGNhc3RhZ2xpYS5vcmcwHhcNMTAwNjI5MTYyNDM0
WhcNMjAwNjI2MTYyNDM0WjCBsDEUMBIGA1UEAxMLc2VydmVyLWNlcnQxCzAJBgNV
BAYTAlVTMR8wHQYJKoZIhvcNAQkBFhB0akBjYXN0YWdsaWEub3JnMRIwEAYDVQQK
EwlDYXN0YWdsaWExKzApBgNVBAsTIkNhc3RhZ2xpYSBSZXNlYXJjaCBhbmQgRGV2
ZWxvcG1lbnQxFDASBgNVBAsTC1RKIFNhdW5kZXJzMRMwEQYDVQQIEwpXYXNoaW5n
dG9uMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCzqEI8WBDuGNIyZyFj3Oci
1unAUAhwOlDNmocbcgsNFeZgxwktFM822lmHyg1J6spIf3odlecuqF29/pwrJCFJ
v+3GmVqm9w48BYEaNalp1ZXbdz/AVmKkS4NRsTqhpbrkvMub3NTNlqLWhlLNTQhL
UP2pJUBtdeqLeg26EwaVgQIDAQABo4IBljCCAZIwCQYDVR0TBAIwADAjBglghkgB
hvhCAQ0EFhYUQ2VydFRvb2wgQ2VydGlmaWNhdGUwUwYDVR0RBEwwSoIWZmFtaWxp
YXIuY2FzdGFnbGlhLm9yZ4EQdGpAY2FzdGFnbGlhLm9yZ4cEfwAAAYYYaHR0cDov
L3d3dy5jYXN0YWdsaWEub3JnMB0GA1UdDgQWBBRbe171MxxpddRH1MEm88sqsM/s
eTCB6wYDVR0jBIHjMIHggBTT54GtEIqABuMCY+LQOa5G4HCbm6GBxKSBwTCBvjEQ
MA4GA1UEAxMHY2EtY2VydDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0
b24xEDAOBgNVBAcTB1NlYXR0bGUxEjAQBgNVBAoTCUNhc3RhZ2xpYTErMCkGA1UE
CxMiQ2FzdGFnbGlhIFJlc2VhcmNoIGFuZCBEZXZlbG9wbWVudDEUMBIGA1UECxML
VEogU2F1bmRlcnMxHzAdBgkqhkiG9w0BCQEWEHRqQGNhc3RhZ2xpYS5vcmeCAQAw
DQYJKoZIhvcNAQEFBQADgYEAK19ZlLJgt8Amm+yGpkzq4Tc2km0vxfytyuZgH1aI
MovfGmc1uWIfStHddwiGgYztZlqZNdKdMGScViFUdc+8lIPTvROjK7ftpzFTQ2wI
7hV+yxmeHvwDEIJrqQ4SQi97M/07x1kgE5PBzrWxd3/Trn6Ed/XssBtRa3rPqGZj
8UY=
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCzqEI8WBDuGNIyZyFj3Oci1unAUAhwOlDNmocbcgsNFeZgxwkt
FM822lmHyg1J6spIf3odlecuqF29/pwrJCFJv+3GmVqm9w48BYEaNalp1ZXbdz/A
VmKkS4NRsTqhpbrkvMub3NTNlqLWhlLNTQhLUP2pJUBtdeqLeg26EwaVgQIDAQAB
AoGASudQFlCxXlPC73jIFxa213O7KY80tXXa0p4mzm6R5PbIgnj5fm46pqgKw+6d
87+MbwWXKFajeHSCAQDyo5oAtkdp7pecB2lRDK2QMkpP+ehI8NuC9T+2cLSnHHJc
3YVD/MIhzdMKD/AmbypjzC9YY4wVxthXmw3czAf1pUuYUAECQQDp75h/Vm/6pWT0
2464N0sQLnwz4se09ZxPfto/Gwq0X2fYDWmY5hKFe6fVauCo5Ha+yUVc1JPqWLvx
wrctXbMhAkEAxJoZjNtDMMwFXHPtgRjjJN3S332kskFxQ3x+Gk3pS6kxzw7FRtG7
1VGco3YyitaQlbcKuDVnCqcd7PA7b+T2YQJAFyblOsT9NBsmUK1iBI1EWoefNytc
hGZCYAO36cLtXkiK6HD7YGx0rM0+IPsA3PYvYlZdDQDk2q6JezXAFzdMwQJADIlT
BcNZhnwL/3g49dlzan9mme+2F9PKeCYxGFZNgRCZ530moTxwgMrCdT3tPSMvdwyD
93kYR/qeEuTCtYDhIQJBANa1VX5gVZryNwbXoPxo0H80NXrJLkUt6h16pncMXg/s
9gJsg19El2YsZVeom4RwtTEVLDEbgUXKp1225Z/LX74=
-----END RSA PRIVATE KEY-----
proftpd-mod_proxy-0.8/t/lib/ 0000775 0000000 0000000 00000000000 14020740307 0016063 5 ustar 00root root 0000000 0000000 proftpd-mod_proxy-0.8/t/lib/ProFTPD/ 0000775 0000000 0000000 00000000000 14020740307 0017301 5 ustar 00root root 0000000 0000000 proftpd-mod_proxy-0.8/t/lib/ProFTPD/Tests/ 0000775 0000000 0000000 00000000000 14020740307 0020403 5 ustar 00root root 0000000 0000000 proftpd-mod_proxy-0.8/t/lib/ProFTPD/Tests/Modules/ 0000775 0000000 0000000 00000000000 14020740307 0022013 5 ustar 00root root 0000000 0000000 proftpd-mod_proxy-0.8/t/lib/ProFTPD/Tests/Modules/mod_proxy.pm 0000664 0000000 0000000 00002605343 14020740307 0024406 0 ustar 00root root 0000000 0000000 package ProFTPD::Tests::Modules::mod_proxy;
use lib qw(t/lib);
use base qw(ProFTPD::TestSuite::Child);
use strict;
use Carp;
use Cwd;
use File::Copy;
use File::Path qw(mkpath);
use File::Spec;
use IO::Handle;
use IO::Socket::INET;
use Time::HiRes qw(gettimeofday tv_interval usleep);
use ProFTPD::TestSuite::FTP;
use ProFTPD::TestSuite::Utils qw(:auth :config :running :test :testsuite);
$| = 1;
my $order = 0;
my $TESTS = {
proxy_sighup => {
order => ++$order,
test_class => [qw(forking os_linux)],
},
proxy_reverse_connect => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_connect_failed_bad_dst_addr => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_connect_failed_non2xx => {
order => ++$order,
test_class => [qw(forking mod_wrap2 mod_wrap2_file reverse)],
},
proxy_reverse_connect_failed_timeout => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_login => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_login_roundrobin_after_host => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_login_peruser_after_host => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_login_extra_user => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_login_extra_pass => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_login_failed => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_login_chrooted => {
order => ++$order,
test_class => [qw(forking reverse rootprivs)],
},
proxy_reverse_login_no_backend_proxy_protocol => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_feat => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_abort => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_list_pasv => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_list_port => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_list_pasv_enoent => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_list_port_enoent => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_epsv => {
order => ++$order,
test_class => [qw(forking reverse)],
},
# TODO: proxy_reverse_epsv_all
proxy_reverse_eprt_ipv4 => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_eprt_ipv6 => {
order => ++$order,
test_class => [qw(feature_ipv6 forking reverse)],
},
proxy_reverse_retr_pasv_ascii => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_retr_pasv_binary => {
order => ++$order,
test_class => [qw(forking reverse)],
},
# This needs to handle chunks larger than the transfer buffer size;
# maybe use SocketOptions to tune them differently; handle short writes
# via outer/inner loops in data_send().
proxy_reverse_retr_large_file => {
order => ++$order,
test_class => [qw(forking reverse slow)],
},
proxy_reverse_retr_empty_file => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_retr_abort => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_stor_pasv => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_stor_port => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_stor_large_file => {
order => ++$order,
test_class => [qw(forking reverse slow)],
},
proxy_reverse_stor_empty_file => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_stor_pasv_eperm => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_stor_port_eperm => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_stor_abort => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_rest_retr => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_rest_stor => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_stat => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_unknown_cmd => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_uri_creds_login => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_uri_creds_login_failed_bad_dst_user => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_uri_creds_login_failed_bad_dst_passwd => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_uri_creds_login_with_reverse_proxy_auth => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_passiveports_pasv => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_passiveports_epsv => {
order => ++$order,
test_class => [qw(forking reverse)],
},
# MasqueradeAddress only really applies to PASV
proxy_reverse_config_masqueradeaddress => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_allowforeignaddress_port => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_allowforeignaddress_eprt => {
order => ++$order,
test_class => [qw(forking reverse)],
},
# Normal TimeoutIdle, honored by mod_proxy (frontend and backend)
proxy_reverse_config_timeoutidle_frontend => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_timeoutidle_backend => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_timeoutlogin_frontend => {
order => ++$order,
test_class => [qw(forking reverse)],
},
# Normal TimeoutNoTransfer, honored by mod_proxy (frontend and backend)
proxy_reverse_config_timeoutnoxfer_frontend => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_timeoutnoxfer_backend => {
order => ++$order,
test_class => [qw(forking reverse)],
},
# Normal TimeoutStalled, honored by mod_proxy (frontend and backend)
proxy_reverse_config_timeoutstalled_frontend => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_timeoutstalled_backend => {
order => ++$order,
test_class => [qw(forking reverse)],
},
# XXX What about TimeoutSession, TimeoutLinger?
proxy_reverse_config_datatransferpolicy_pasv_list_pasv => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_datatransferpolicy_pasv_list_port => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_datatransferpolicy_port_list_pasv => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_datatransferpolicy_port_list_port => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_datatransferpolicy_epsv_list_pasv => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_datatransferpolicy_epsv_list_port => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_datatransferpolicy_eprt_list_pasv => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_datatransferpolicy_eprt_list_port => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_datatransferpolicy_active_list_pasv => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_datatransferpolicy_active_list_port => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_datatransferpolicy_active_list_eprt_port_fallback => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_datatransferpolicy_passive_list_pasv => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_datatransferpolicy_passive_list_epsv_pasv_fallback => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_datatransferpolicy_passive_list_port => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_datatransferpolicy_client => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_directorylistpolicy_client => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_directorylistpolicy_list_unix => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_directorylistpolicy_list_unix_use_slink => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_directorylistpolicy_list_unix_wide_dir => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_directorylistpolicy_list_windows => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_directorylistpolicy_list_backend_error => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_directorylistpolicy_list_opts_mlst => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_connect_policy_random => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_connect_policy_shuffle => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_connect_policy_roundrobin => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_connect_policy_roundrobin_issue132 => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_connect_policy_leastconns => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_connect_policy_leastresponsetime => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_connect_policy_per_host => {
order => ++$order,
test_class => [qw(forking mod_ifsession reverse)],
},
proxy_reverse_config_connect_policy_per_user => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_connect_policy_per_user_by_json => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_connect_policy_per_user_no_fallback_issue148 => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_connect_policy_per_group => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_connect_policy_per_group_by_json => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_reverseservers_json => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_reverseservers_json_per_user => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_transfer_rate_retr => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_use_reverse_proxy_auth_login => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_use_reverse_proxy_auth_login_extra_user => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_use_reverse_proxy_auth_login_extra_pass => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_use_reverse_proxy_auth_login_failed_bad_passwd => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_use_direct_data_transfers_port => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_use_direct_data_transfers_port_failed => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_use_direct_data_transfers_list_failed => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_config_use_direct_data_transfers_pasv => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_limit_list_deny_all => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_limit_list_deny_user => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_limit_list_deny_group => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_limit_mlsd_deny_all => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_limit_retr_deny_all => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_limit_stor_deny_all => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_limit_read_deny_all => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_limit_write_deny_all => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_limit_dirs_deny_all => {
order => ++$order,
test_class => [qw(forking reverse)],
},
# TransferLog entries (binary/ascii, upload/download, complete/aborted)
# Note that TransferLog, as supported by mod_proxy, CANNOT have the absolute
# path of the file transferred; we can only know path as requested by
# the client.
proxy_reverse_xferlog_retr_ascii_ok => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_xferlog_retr_ascii_chrooted_ok => {
order => ++$order,
test_class => [qw(forking reverse rootprivs)],
},
proxy_reverse_xferlog_retr_binary_ok => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_xferlog_stor_ascii_ok => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_xferlog_stor_binary_ok => {
order => ++$order,
test_class => [qw(forking reverse)],
},
# ExtendedLog entries. The most affected will be %D/%d and %F/%f.
proxy_reverse_extlog_retr_var_F_f => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_extlog_stor_var_F_f => {
order => ++$order,
test_class => [qw(forking reverse)],
},
proxy_reverse_extlog_list_var_D_d => {
order => ++$order,
test_class => [qw(forking reverse)],
},
# LastLog? WtmpLog?
# HiddenStore? (should have no effect)
# TransferPriority?
proxy_reverse_proxy_protocol_v1_ipv4 => {
order => ++$order,
test_class => [qw(forking mod_proxy_protocol reverse)],
},
proxy_reverse_proxy_protocol_v1_ipv6 => {
order => ++$order,
test_class => [qw(feature_ipv6 forking mod_proxy_protocol reverse)],
},
proxy_reverse_proxy_protocol_v2_ipv4 => {
order => ++$order,
test_class => [qw(forking mod_proxy_protocol reverse)],
},
proxy_reverse_proxy_protocol_v2_ipv6 => {
order => ++$order,
test_class => [qw(feature_ipv6 forking mod_proxy_protocol reverse)],
},
# proxy_reverse_proxy_protocol_v1_ipv6_useipv6_off
# proxy_reverse_proxy_protocol_v1_unknown
# proxy_reverse_proxy_protocol_v2_ipv6_useipv6_off
# proxy_reverse_proxy_protocol_v2_unknown
proxy_forward_connect => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_connect_failed_timeout => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_noproxyauth_login => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_noproxyauth_login_after_host => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_noproxyauth_login_extra_user => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_noproxyauth_login_extra_pass => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_noproxyauth_login_ipv6_dst_addr => {
order => ++$order,
test_class => [qw(feature_ipv6 forking forward)],
},
proxy_forward_noproxyauth_login_netftp_fw_type_1 => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_noproxyauth_login_failed_bad_dst_addr => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_noproxyauth_login_failed_proxy_dst_addr => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_noproxyauth_login_failed_non2xx => {
order => ++$order,
test_class => [qw(forking forward mod_wrap2 mod_wrap2_file)],
},
proxy_forward_noproxyauth_login_failed_login_limit => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_noproxyauth_login_failed_bad_sequence => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_noproxyauth_login_failed_bad_dst_passwd => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_login_feat_first => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_list_pasv => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_list_port => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_epsv => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_eprt_ipv4 => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_eprt_ipv6 => {
order => ++$order,
test_class => [qw(feature_ipv6 forking forward)],
},
proxy_forward_retr_port => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_stor_pasv => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_userwithproxyauth_login => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_userwithproxyauth_login_extra_user => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_userwithproxyauth_login_extra_pass => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_userwithproxyauth_login_user_incl_at_symbol => {
order => ++$order,
test_class => [qw(forking forward)],
},
# Note: The following test is disabled because Net::FTP has a bug in the
# handling of a FTP_FIREWALL_TYPE=2. Specifically, in its login() method,
# it does not properly construct the $fwuser variable unless there is a
# ~/.netrc file -- and such a file cannot be used for tests like this.
#
# proxy_forward_userwithproxyauth_login_netftp_fw_type_2
proxy_forward_userwithproxyauth_login_failed_bad_dst_addr => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_userwithproxyauth_login_failed_non2xx => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_userwithproxyauth_login_failed_limit_login => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_userwithproxyauth_login_failed_bad_sequence => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_userwithproxyauth_login_failed_bad_proxy_passwd => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_userwithproxyauth_login_failed_bad_dst_passwd => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_userwithproxyauth_bad_sequence_no_dst_login => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_proxyuserwithproxyauth_login => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_proxyuserwithproxyauth_login_extra_user => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_proxyuserwithproxyauth_login_extra_pass => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_proxyuserwithproxyauth_login_user_incl_at_symbol => {
order => ++$order,
test_class => [qw(forking forward)],
},
# Note: The following test is disabled because Net::FTP has a bug in the
# handling of a FTP_FIREWALL_TYPE=6. Specifically, in its login() method,
# it does not properly construct the $fwuser variable unless there is a
# ~/.netrc file -- and such a file cannot be used for tests like this.
#
# proxy_forward_proxyuserwithproxyauth_login_netftp_fw_type6
proxy_forward_proxyuserwithproxyauth_login_failed_bad_dst_addr => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_proxyuserwithproxyauth_login_failed_non2xx => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_proxyuserwithproxyauth_login_failed_limit_login => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_proxyuserwithproxyauth_login_failed_bad_sequence => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_proxyuserwithproxyauth_login_failed_bad_proxy_passwd => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_proxyuserwithproxyauth_login_failed_bad_dst_passwd => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_proxyuserwithproxyauth_bad_sequence_no_dst_login => {
order => ++$order,
test_class => [qw(forking forward)],
},
# proxy_forward_config_displayconnect
proxy_forward_config_forward_to => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_config_forward_to_negated => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_config_use_direct_data_transfers_port => {
order => ++$order,
test_class => [qw(forking forward)],
},
proxy_forward_config_use_direct_data_transfers_pasv => {
order => ++$order,
test_class => [qw(forking forward)],
},
# proxy_forward_config_timeoutlogin_frontend
# proxy_forward_config_timeoutlogin_backend
# proxy_forward_config_maxloginattempts (frontend or backend?)
# proxy_forward_xferlog_retr_ascii_ok
# proxy_forward_xferlog_retr_binary_ok
# proxy_forward_xferlog_stor_ascii_ok
# proxy_forward_xferlog_stor_binary_ok
# proxy_forward_extlog_retr_var_F_f
# proxy_forward_extlog_stor_var_F_f
# proxy_forward_extlog_list_var_D_d
# XXX TODO Issue #21
# proxy_forward_config_directorylistpolicy_client
# proxy_forward_config_directorylistpolicy_list_unix
# proxy_forward_config_directorylistpolicy_list_windows
};
sub new {
return shift()->SUPER::new(@_);
}
sub list_tests {
return testsuite_get_runnable_tests($TESTS);
}
sub config_hash2array {
my $hash = shift;
my $array = [];
foreach my $key (keys(%$hash)) {
push(@$array, "$key $hash->{$key}\n");
}
return $array;
}
sub get_reverse_proxy_config {
my $tmpdir = shift;
my $log_file = shift;
my $vhost_port = shift;
my $table_dir = File::Spec->rel2abs("$tmpdir/var/proxy");
my $config = {
ProxyEngine => 'on',
ProxyLog => $log_file,
ProxyReverseServers => "ftp://127.0.0.1:$vhost_port",
ProxyRole => 'reverse',
ProxyTables => $table_dir,
};
return $config;
}
sub get_forward_proxy_config {
my $tmpdir = shift;
my $log_file = shift;
my $vhost_port = shift;
my $table_dir = File::Spec->rel2abs("$tmpdir/var/proxy");
my $config = {
ProxyEngine => 'on',
ProxyLog => $log_file,
ProxyRole => 'forward',
ProxyTables => $table_dir,
ProxyTimeoutConnect => '1sec',
Class => {
'forward-proxy' => {
From => '127.0.0.1',
ProxyForwardEnabled => 'on',
},
},
};
return $config;
}
sub ftp_list {
my $self = shift;
my $client = shift;
my $conn = $client->list_raw();
unless ($conn) {
die("Failed to LIST: " . $client->response_code() . ' ' .
$client->response_msg());
}
my $buf;
$conn->read($buf, 8192, 10);
eval { $conn->close() };
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
$self->assert_transfer_ok($resp_code, $resp_msg);
($resp_code, $resp_msg) = $client->quit();
my $expected = 221;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = 'Goodbye.';
$self->assert($expected eq $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
1;
}
sub get_server_pid {
my $pid_file = shift;
my $pid;
if (open(my $fh, "< $pid_file")) {
$pid = <$fh>;
chomp($pid);
close($fh);
} else {
croak("Can't read $pid_file: $!");
}
return $pid;
}
sub server_open_fds {
my $pid_file = shift;
my $pid = get_server_pid($pid_file);
my $proc_dir = "/proc/$pid/fd";
if (opendir(my $dirh, $proc_dir)) {
my $count = 0;
# Only count entries whose names are numbers
while (my $dent = readdir($dirh)) {
if ($dent =~ /^\d+$/) {
$count++;
}
}
closedir($dirh);
return $count;
} else {
croak("Can't open directory '$proc_dir': $!");
}
}
sub proxy_sighup {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'proxy');
my $vhost_port = ProFTPD::TestSuite::Utils::get_high_numbered_port();
$vhost_port += 12;
my $proxy_config = get_reverse_proxy_config($tmpdir, $setup->{log_file},
$vhost_port);
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'DEFAULT:10 event:10 lock:0 scoreboard:0 signal:0 proxy:20 proxy.db:20 proxy.ftp.conn:20 proxy.ftp.ctrl:20 proxy.ftp.data:20 proxy.ftp.msg:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
SocketBindTight => 'on',
IfModules => {
'mod_proxy.c' => $proxy_config,
'mod_delay.c' => {
DelayEngine => 'off',
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
if (open(my $fh, ">> $setup->{config_file}")) {
print $fh <
Port $vhost_port
ServerName "Real Server"
WtmpLog off
TransferLog none