Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FileZilla integration test server #1016

Merged
merged 2 commits into from
Oct 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions FluentFTP.Dockers/Build.bat
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ docker build bftpd -t bftpd:fluentftp

docker build glftpd -t glftpd:fluentftp

docker build filezilla -t filezilla:fluentftp

pause
2 changes: 2 additions & 0 deletions FluentFTP.Dockers/Build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ sudo docker build pyftpdlib -t pyftpdlib:fluentftp
sudo docker build bftpd -t bftpd:fluentftp

sudo docker build glftpd -t glftpd:fluentftp

sudo docker build filezilla -t filezilla:fluentftp
153 changes: 153 additions & 0 deletions FluentFTP.Dockers/filezilla/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
#
# Stage 1: build
#

FROM debian:bullseye-slim AS build

SHELL ["/bin/bash", "-c"]

ARG LIBFILEZILLA_VERSION=0.39.2
ARG FILEZILLA_VERSION=1.5.1

ARG LIBFILEZILLA_URL=https://download.filezilla-project.org/libfilezilla/libfilezilla-${LIBFILEZILLA_VERSION}.tar.bz2
ARG FILEZILLA_URL=https://download.filezilla-project.org/server/FileZilla_Server_${FILEZILLA_VERSION}_src.tar.bz2

ARG DEBIAN_FRONTEND=noninteractive
ARG APT_CMD='apt install -y --no-install-recommends'

WORKDIR /
RUN apt update && apt upgrade -y && apt install -y apt-utils && \
\
$APT_CMD \
curl \
ca-certificates \
bzip2 \
binutils \
build-essential \
pkg-config \
libgmp-dev \
nettle-dev \
gnutls-dev \
gettext \
libwxgtk3.0-gtk3-dev

WORKDIR /tmp/libfilezilla
RUN curl -L ${LIBFILEZILLA_URL} | tar xj --strip 1 -C /tmp/libfilezilla

WORKDIR /tmp/filezilla
RUN curl -L ${FILEZILLA_URL} | tar xj --strip 1 -C /tmp/filezilla

#
# configure, make, make install sequences for libfilezilla and filezilla-server
#
WORKDIR /
RUN export CFLAGS="-Os -fomit-frame-pointer" && \
export CXXFLAGS="$CFLAGS" && \
export CPPFLAGS="$CFLAGS" && \
export LDFLAGS="-Wl,--as-needed" && \
#
# libfilezilla
#
cd /tmp/libfilezilla && \
\
./configure --enable-shared=no --with-pic && \
\
make -j$(nproc) && \
make install && \
#
# filezilla-server
#
cd /tmp/filezilla/src/server && \
#
# need to changes the source code to not refuse to work if unprotected_hardlinks is 0
#
sed -i "s/(has_unprotected_hardlinks)/(false)/" main.cpp && \
#
# need to create some bogus files because there is a bug in filezilla-server Makefile
#
cd /tmp/filezilla/res/share/icons/hicolor && \
\
mkdir -p 128x128/apps && cd $_ && echo '.' > filezilla-server-gui.png && cd ../.. && \
mkdir -p 16x16/apps && cd $_ && echo '.' > filezilla-server-gui.png && cd ../.. && \
mkdir -p 20x20/apps && cd $_ && echo '.' > filezilla-server-gui.png && cd ../.. && \
mkdir -p 24x24/apps && cd $_ && echo '.' > filezilla-server-gui.png && cd ../.. && \
mkdir -p 256x256/apps && cd $_ && echo '.' > filezilla-server-gui.png && cd ../.. && \
mkdir -p 32x32/apps && cd $_ && echo '.' > filezilla-server-gui.png && cd ../.. && \
mkdir -p 48x48/apps && cd $_ && echo '.' > filezilla-server-gui.png && cd ../.. && \
mkdir -p scalable/apps && cd $_ && echo '.' > filezilla-server-gui.svg && cd ../.. && \
\
cd /tmp/filezilla && \
\
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig && \
./configure --with-pugixml=builtin && \
\
make -j$(nproc) && \
make install

WORKDIR /tmp/filezilla

#
# The certificate and the certificate signature
#
# Make self signed key/cert pair:
# openssl ecparam -name prime256v1 -genkey -noout -out key.pem && \
# openssl req -new -x509 -key key.pem -out cert.pem -days 3650
#
RUN openssl ecparam -name prime256v1 -genkey -noout -out key.pem && \
openssl req -new -x509 -key key.pem -out cert.pem -days 3650 -subj "/C=US/ST=State/L=/O=Dev/CN=fluentftp"

#
# Stage 2: production
#

FROM debian:bullseye-slim AS production

SHELL ["/bin/bash", "-c"]

ARG DEBIAN_FRONTEND=noninteractive
ARG APT_CMD='apt install -y --no-install-recommends'

WORKDIR /
RUN apt update && apt upgrade -y && apt install -y apt-utils

#
# Bring in settings.xml (PASV port ranges, certificate refs),
# and users.xml (contains fluentuser and his password)
#
COPY --from=build /usr/local/bin /usr/local/bin

COPY --from=build /tmp/filezilla/cert.pem /root/cert.pem
COPY --from=build /tmp/filezilla/key.pem /root/key.pem

WORKDIR /root/.config/filezilla-server

COPY settings.xml /root/.config/filezilla-server/settings.xml
COPY users.xml /root/.config/filezilla-server/users.xml

RUN sed -i "s/<keyfile><\/keyfile>/<keyfile>\/root\/key.pem<\/keyfile>/" /root/.config/filezilla-server/settings.xml && \
sed -i "s/<certsfile><\/certsfile>/<certsfile>\/root\/cert.pem<\/certsfile>/" /root/.config/filezilla-server/settings.xml && \
#
# All other settings files can be empty but must exist.
#
touch allowed_ips.xml && \
touch disallowed_ips.xml && \
touch groups.xml

WORKDIR /

COPY run-filezilla.sh /usr/sbin/

RUN sed -i -e "s/\r//" /usr/sbin/run-filezilla.sh && \
chmod +x /usr/sbin/run-filezilla.sh && \
\
useradd -m -p savatlcb.1m26 fluentuser && \
\
mkdir -p /home/fluentuser/ && \
chown -R fluentuser:users /home/fluentuser

VOLUME /home/fluentuser
VOLUME /var/log/filezilla

EXPOSE 20 21

CMD ["/usr/sbin/run-filezilla.sh"]
13 changes: 13 additions & 0 deletions FluentFTP.Dockers/filezilla/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
services:
filezilla:
build:
context: .
network: host
restart: unless-stopped
ports:
- 0.0.0.0:20:20
- 0.0.0.0:21:21
- 21100-21110:21100-21199
volumes:
- ./home:/home/filezilla
- ./logs:/var/log/filezilla
19 changes: 19 additions & 0 deletions FluentFTP.Dockers/filezilla/run-filezilla.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/bin/bash

# stdout server info:
cat << EOB
*************************************************
* *
* Docker image: fluentftp filezilla *
* *
*************************************************

SERVER SETTINGS
---------------
� FTP User: fluentuser
� FTP Password: fluentpass
EOB

# Run filezilla:

&>/dev/null /usr/local/bin/filezilla-server
100 changes: 100 additions & 0 deletions FluentFTP.Dockers/filezilla/settings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<filezilla xmlns:fz="https://filezilla-project.org/" xmlns="https://filezilla-project.org/" fz:product_flavour="standard" fz:product_version="1.5.1">
<!--The server's locale. By default, the one defined by the appropriate environment variables is used.-->
<locale></locale>
<!--Logging options.-->
<logger>
<!--The name of the log file. If empty, the log goes to stderr.-->
<name></name>
<!--The maximum number of files to be used for the log rotation. Default is 0, meaning no rotation happens.-->
<max_amount_of_rotated_files>0</max_amount_of_rotated_files>
<!--The maximum size each log file can reach before being closed and a new one being opened. Only meaningful if max_amount_of_rotated_files > 0.-->
<max_file_size>9223372036854775807</max_file_size>
<!--Which types of logs must be enabled. Defaults to error|status|reply|command . See <libfilezilla/logger.hpp> for the values of the various types.-->
<enabled_types>15</enabled_types>
<!--Criteria used to rotate files. Currently: size-based (0) or daily rotation (1).-->
<rotation_type>0</rotation_type>
<!--Include headers for each line of logging (date&time and possibly others). Set it to false if you have your own way of tagging log lines. Default is true.-->
<include_headers>true</include_headers>
</logger>
<!--Settings common to all file transfer protocols-->
<all_protocols>
<!--Autobanner options-->
<autobanner>
<!--The duration, in milliseconds, of the IP ban.-->
<ban_duration>300000</ban_duration>
<!--The duration, in milliseconds, during which the number of failed login attempts is monitored.-->
<login_failure_time_window>100</login_failure_time_window>
<!--The number of login attempts that are allowed to fail, within the time window specified by the parameter [login_failures_time_window]. The value 0 disables this mechanism.-->
<login_failure_time_window>0</login_failure_time_window>
</autobanner>
<!--Performance options.-->
<performance>
<!--Number of threads to distribute sessions to.-->
<number_of_session_threads>0</number_of_session_threads>
<!--Size of receving data socket buffer. Numbers < 0 mean use system defaults. Defaults to -1.-->
<receive_buffer_size>-1</receive_buffer_size>
<!--Size of sending data socket buffer. Numbers < 0 mean use system defaults. Defaults to -1.-->
<send_buffer_size>-1</send_buffer_size>
</performance>
<!--Timeout options.-->
<timeouts>
<!--Login timeout (fz::duration)-->
<login_timeout>60000</login_timeout>
<!--Activity timeout (fz::duration).-->
<activity_timeout>3600000</activity_timeout>
</timeouts>
</all_protocols>
<!--FTP Server options-->
<ftp_server>
<!--List of addresses and ports the FTP server will listen on.-->
<listener>
<address>0.0.0.0</address>
<port>21</port>
<tls_mode>0</tls_mode>
</listener>
<listener>
<address>::</address>
<port>21</port>
<tls_mode>0</tls_mode>
</listener>
<!--Session-related options.-->
<session>
<!--PASV settings-->
<pasv>
<!--IPV4 IP or name host that overrides the local address when PASV is used. Leave empty to not perform the override-->
<host_override>localhost</host_override>
<!--If set to true, then the host is not overriden for local connections.-->
<do_not_override_host_if_peer_is_local>true</do_not_override_host_if_peer_is_local>
<!--Port range to be used for PASV connections-->
<port_range>
<!--Maximum value for the port range to be used for PASV connections-->
<min>21100</min>
<!--Maximum value for the port range to be used for PASV connections-->
<max>21199</max>
</port_range>
</pasv>
<!--TLS certificate data.-->
<tls min_protocol_version="2" index="1">
<!--Path to the private key in PEM format.-->
<keyfile></keyfile>
<!--Path to the certificates file in PEM format.-->
<certsfile></certsfile>
<!--Password to decrypt private key. *DO NOT USE FOR NEWLY CREATED CERTIFICATES* *ONLY USE WHEN IMPORTING OLD SERVER CONFIG*-->
<password></password>
</tls>
</session>
<!--Additional welcome message.-->
<welcome_message has_version="true"></welcome_message>
</ftp_server>
<!--Administration options.-->
<admin>
<local_port></local_port>
<password index="0" />
</admin>
<!--ACME (Let's Encrypt and the like) settings.-->
<acme>
<account_id></account_id>
<how_to_serve_challenges index="0" />
</acme>
</filezilla>
27 changes: 27 additions & 0 deletions FluentFTP.Dockers/filezilla/users.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<filezilla xmlns:fz="https://filezilla-project.org/" xmlns="https://filezilla-project.org/" fz:product_flavour="standard" fz:product_version="1.5.1">
<default_impersonator index="0" enabled="false">
<name></name>
<password></password>
</default_impersonator>
<user name="&lt;system user>" enabled="false">
<mount_point tvfs_path="/" native_path=":h" access="1" recursive="2" />
<rate_limits inbound="5120" outbound="5120" session_inbound="unlimited" session_outbound="unlimited" />
<allowed_ips></allowed_ips>
<disallowed_ips></disallowed_ips>
<description>This user can impersonate any system user.</description>
<impersonation login_only="false" />
</user>
<user name="fluentuser" enabled="true">
<mount_point tvfs_path="/" native_path="/home/fluentuser" access="1" recursive="2" />
<rate_limits inbound="unlimited" outbound="unlimited" session_inbound="unlimited" session_outbound="unlimited" />
<allowed_ips></allowed_ips>
<disallowed_ips></disallowed_ips>
<description></description>
<password index="1">
<hash>l9jcg8P68htZEZF7iIy6GhrbS8HLFGSikYzaUAnHo5E</hash>
<salt>oFoJsx+xI6ZIEg9dc7fJUnLqjHWklAi2QcuHe5QVhTE</salt>
<iterations>100000</iterations>
</password>
</user>
</filezilla>
5 changes: 5 additions & 0 deletions FluentFTP.Tests/Integration/IntegrationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ public async Task Glftpd() {
await IntegrationTestRunner.Run(FtpServer.glFTPd);
}

[Fact]
public async Task FileZilla() {
await IntegrationTestRunner.Run(FtpServer.FileZilla);
}

// These can only do FTP
[Fact]
public async Task Bftpd() {
Expand Down
36 changes: 36 additions & 0 deletions FluentFTP.Xunit/Docker/Containers/FileZillaContainer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DotNet.Testcontainers.Builders;
using DotNet.Testcontainers.Containers;

namespace FluentFTP.Xunit.Docker.Containers {
internal class FileZillaContainer : DockerFtpContainer {

public FileZillaContainer() {
ServerType = FtpServer.FileZilla;
ServerName = "filezilla";
DockerImage = "filezilla:fluentftp";
//without SSL:
// not possible
//with SSL:
// RunCommand = "docker run --rm -it -p 21:21 -p 21100-21199:21100-21199 filezilla:fluentftp";
}

/// <summary>
/// For help creating this section see https://github.com/testcontainers/testcontainers-dotnet#supported-commands
/// </summary>
public override ITestcontainersBuilder<TestcontainersContainer> Configure(ITestcontainersBuilder<TestcontainersContainer> builder) {

builder = builder.WithPortBinding(20);

builder = ExposePortRange(builder, 21100, 21199);

return builder;
}

}

}
3 changes: 2 additions & 1 deletion FluentFTP.Xunit/Docker/DockerFtpContainerIndex.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ internal static class DockerFtpContainerIndex {
new PyFtpdLibContainer(),
new VsFtpdContainer(),
new BFtpdContainer(),
new GlFtpdContainer()
new GlFtpdContainer(),
new FileZillaContainer(),
};
}
}