Skip to content

Commit

Permalink
Merge pull request #1016 from FanDjango/filezilla-server
Browse files Browse the repository at this point in the history
FileZilla integration test server
  • Loading branch information
FanDjango authored Oct 21, 2022
2 parents b7230f7 + 374f9e0 commit a6d9622
Show file tree
Hide file tree
Showing 10 changed files with 359 additions and 1 deletion.
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(),
};
}
}

0 comments on commit a6d9622

Please sign in to comment.