From 74fc0aec7d4551da7ef1489a5ba9fdc6993cafef Mon Sep 17 00:00:00 2001 From: FanDjango Date: Wed, 12 Oct 2022 22:40:31 +0200 Subject: [PATCH] Add bftpd test server --- FluentFTP.Dockers/Build.bat | 2 + FluentFTP.Dockers/Build.sh | 2 + FluentFTP.Dockers/bftpd/Dockerfile | 62 ++++ FluentFTP.Dockers/bftpd/bftpd.conf | 321 ++++++++++++++++++ FluentFTP.Dockers/bftpd/docker-compose.yml | 14 + FluentFTP.Dockers/bftpd/run-bftpd.sh | 18 + .../Integration/IntegrationTests.cs | 6 + .../Docker/Containers/BfFtpdContainer.cs | 36 ++ .../Docker/DockerFtpContainerIndex.cs | 3 +- 9 files changed, 463 insertions(+), 1 deletion(-) create mode 100644 FluentFTP.Dockers/bftpd/Dockerfile create mode 100644 FluentFTP.Dockers/bftpd/bftpd.conf create mode 100644 FluentFTP.Dockers/bftpd/docker-compose.yml create mode 100644 FluentFTP.Dockers/bftpd/run-bftpd.sh create mode 100644 FluentFTP.Xunit/Docker/Containers/BfFtpdContainer.cs diff --git a/FluentFTP.Dockers/Build.bat b/FluentFTP.Dockers/Build.bat index ecc26a3ab..d070f424a 100644 --- a/FluentFTP.Dockers/Build.bat +++ b/FluentFTP.Dockers/Build.bat @@ -7,4 +7,6 @@ docker build vsftpd -t vsftpd:fluentftp docker build pyftpdlib -t pyftpdlib:fluentftp +docker build bftpd -t bftpd:fluentftp + pause \ No newline at end of file diff --git a/FluentFTP.Dockers/Build.sh b/FluentFTP.Dockers/Build.sh index 0ccf5bfd1..41da8fbcb 100644 --- a/FluentFTP.Dockers/Build.sh +++ b/FluentFTP.Dockers/Build.sh @@ -6,3 +6,5 @@ sudo docker build pureftpd -t pureftpd:fluentftp sudo docker build vsftpd -t vsftpd:fluentftp sudo docker build pyftpdlib -t pyftpdlib:fluentftp + +sudo docker build bftpd -t bftpd:fluentftp diff --git a/FluentFTP.Dockers/bftpd/Dockerfile b/FluentFTP.Dockers/bftpd/Dockerfile new file mode 100644 index 000000000..71549265f --- /dev/null +++ b/FluentFTP.Dockers/bftpd/Dockerfile @@ -0,0 +1,62 @@ +FROM debian:bullseye + +MAINTAINER FluentFTP +LABEL Description="FluentFTP vsftpd docker image based on Debian Bullseye." + +RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections + +RUN apt -y update && apt clean all + +RUN apt install -y \ + apt-utils \ + dialog + +RUN apt install -y \ + iproute2 + +RUN apt remove --purge -y \ + exim4-base \ + mariadb-common + +RUN apt autoremove -y + +RUN apt install -y \ + wget \ + build-essential + + +RUN mkdir /tmp/bftpd/ && \ + cd /tmp/bftpd/ && \ + wget -O bftpd.tar.gz https://downloads.sourceforge.net/project/bftpd/bftpd/bftpd-6.1/bftpd-6.1.tar.gz && \ + tar -xzf bftpd.tar.gz && \ + cd bftpd && \ + ./configure && \ + make && \ + make install + +RUN apt remove --purge -y \ + build-essential \ + wget + +RUN apt autoremove -y + +COPY bftpd.conf /usr/etc/ +RUN sed -i -e "s/\r//" /usr/etc/bftpd.conf +COPY run-bftpd.sh /usr/sbin/ +RUN sed -i -e "s/\r//" /usr/sbin/run-bftpd.sh + +RUN chmod +x /usr/sbin/run-bftpd.sh + +RUN useradd -m -p savatlcb.1m26 fluentuser + +RUN mkdir -p /home/fluentuser/ +RUN chown -R fluentuser:users /home/fluentuser + +RUN mkdir /var/ftp + +VOLUME /home/fluentuser +VOLUME /var/log/bftpd + +EXPOSE 20 21 + +CMD ["/usr/sbin/run-bftpd.sh"] diff --git a/FluentFTP.Dockers/bftpd/bftpd.conf b/FluentFTP.Dockers/bftpd/bftpd.conf new file mode 100644 index 000000000..bacd2644f --- /dev/null +++ b/FluentFTP.Dockers/bftpd/bftpd.conf @@ -0,0 +1,321 @@ +#Configuration file for bftpd. +#The given values are only examples, modify this file for your own needs. + +global{ + #If set to no, access is allowed. + #If set to yes, access is denied without giving a reason. + #If set to anything else, access is denied giving the content of this + #variable as a reason. + DENY_LOGIN="no" + + #The port number where the daemon should listen (only for daemon mode) + PORT="21" + + #You can force bftpd to use a specific port range in passive mode. + #Passive mode means that the client will open data connections + #and the server stays 'passive'. + #This option can be very useful with some firewall configurations. + #Separate values with "," and define ranges with "-". + #bftpd will try to bind one of these ports in ascending order as + #you specify them here. + #If none of the given ports could be bound, the connection is + #is refused. If you want to bind any free port in that case, add + #"0" to the list. + PASSIVE_PORTS="21100-21199" + + #If PORT data connections should be opened from port 20, say yes here. You + #will probably need this if your server is behind a firewall that restricts + #outgoing packets from ports higher than 1024. Note that this may be a + #security hole, as the server can not drop its root privileges completely + #if you say yes here. + DATAPORT20="yes" + + #The password for the administration commands, encrypted (man mkpasswd). + ADMIN_PASS="x" + + #With this option, you can put your entire FTP environment into a chroot + #jail. Apart from security, this offers you the possibility of having + #virtual users that don't exist in the system. + #Additionally, you can make some kind of 'file pool' by creating a directory + #with files which you can symlink from the users' homes (this means setting + #DO_CHROOT=no in order for the users to be able to access that dir. + #Note that you need the following files in your initial chroot directory: + #/etc/passwd, /etc/shadow, /etc/group + #On GNU systems, you will also need the NSS libraries in /lib. + #INITIAL_CHROOT="/ftp" + + #The bftpdutmp file enables you to record user logins and logouts in + #bftpd, which is useful for the administration interface (which is not + #finished yet). You also need the file to be able to restrict the number + #of users simultaneously logged on, and so on. + #Note that the directory in which the file resides must already exist. + #Set the option to "" if you do not want that. This is discouraged for normal + #use, but can be helpful if you want to create a boot floppy or something. + PATH_BFTPDUTMP="/var/run/bftpd/bftpdutmp" + + #This option controls the buffer size while transferring files. + #If you are on a very fast network (fast meaning 100 Mbit/s or more), + #you should set this to 64000 or something like that. + #Transferring from localhost to localhost, I had a transfer speed of + #approx. 15 MB/s with XFER_BUFSIZE=2048 and a speed of approx. 20 MB/s + #with XFER_BUFSIZE=64000. You should not set big values for this if you have + #slow (dialup) clients. + # This option can also be used to (crudely) throttle back + # transfer speeds. Setting this to a very low value + # can slow transfer speeds. + XFER_BUFSIZE="2048" + + + # This variable controls whether the transfer buffer (see above option) + # should change size as more (or less) clients connect to the server. + # Setting this option to "yes" will put more work on your CPU, but + # will avoid chewing up as much bandwidth as more people connect. + # Setting this option to "no" is easier on the CPU, but may cause + # your bandwidth to spike. + CHANGE_BUFSIZE="no" + + + + # This option allows you to add a delay (in microseconds) to + # the time between when one piece of data was sent + # and when the next will be sent. This is to aid in + # throttling bandwidth and applies to each client. The + # throttling effects the DATA transfers only (not control + # connections). + # A value of zero (0) means there is no added delay. + # A value of about 500000 (five hundred thousand) should + # delay for about half a second. + # These delays should be kept low to avoid triggering + # data transfer timeouts. + XFER_DELAY="0" + + # This option determines whether hidden files + # ( files that start with a "." ) + # will be shown in a directory listing. + # If this option is set to "yes", the client will be + # able to see hidden files ONLY if they pass the "-a" + # option to the list command. For example "ls -a". + # If this option is set to "no", then hidden files are + # never shown, regardless of whether "-a" is used. + # Additionally, if we want the server to always send hidden + # files to the client, whether they request hidden files or + # not, set this to "always". + SHOW_HIDDEN_FILES="no" + + # This option determines whether files not readable + # to the ftp user will be shown in a directory listing. + SHOW_NONREADABLE_FILES="no" + + #When set to yes, this option makes the server allow data connections which + #don't go to the client who initiated them. + #This is needed for FXP. + ALLOW_FXP="no" + + #After how many seconds of idle time should a user be kicked from the server? + CONTROL_TIMEOUT="300" + + #After how many seconds of idle time should a user be kicked from the server + #during a file transfer? + DATA_TIMEOUT="30" + + #Use Ratio if you want the client to send a file before he can get a file. + #Usage: RATIO=send/receive or RATIO=none. Example: RATIO=2/1 lets the client + #receive a 1 MB file when he has sent a 2 MB file. + RATIO="none" + + # Use this option to track bandwidth usage. After each session, the server + # will log how much data was uploaded and downloaded for each user. + # This option should point to the directory where the log files will + # be saved. + # Each day gets its own log file, to make it easier to rotate logs. + # Please note, this directory must be created manually. + # BANDWIDTH="/var/log/bftpd" + + #ROOTDIR specifies the root directory of the client. It defaults to %h + #(user's home directory). %u is replaced by the user name. + ROOTDIR="%h" + + #Umask for the files or directories users create. + UMASK="022" + + #Name of the log file. Say "syslog" to log into syslog. + #Say "" for no logging. + LOGFILE="/var/log/bftpd.log" + + #Use %v for version, %h for the server FQDN and %i for the server IP address. + # Note: If you use the "%h" option and you do an initial CHROOT, then + # you'll need to copy your /etc/hosts and /etc/host.conf files into + # the chroot jail. + HELLO_STRING="bftpd %v at %i ready." + + #The server automatically chdirs to the directory given here after login. + AUTO_CHDIR="/" + + #Authentication type, values: PAM, PASSWD + AUTH="PASSWD" + + # The FILE_AUTH variable over-rides the AUTH value. If the FILE_AUTH + # value is set to something other than an empty string ("") + # bftpd will search through the pathname given in order + # to find username/password matches. + # The format of this file is as shown below: + # username password group home_folder + # (for example:) + # robert secret users /home/robert + # james moose users /mnt/storage + # + # A entry with the password field set to * (star) requires + # no password. Any password the users enters will be accepted. + # The following example is for a user with no password. + # anyone * users /home/ftp + # + # This option should almost never be used and is only for situations + # where one (or very few) users need to be granted access to a machine + # where normal user accounts cannot be created. + # Under no circumstances should anyone except root be + # able to read the FILE_AUTH password file. + #FILE_AUTH="/etc/ftpdpassword" + + + #Enable this if you want the client's IP address to be resolved to a host + #name. Note that it increases the overhead and it may not work if your DNS + #is not configured correctly. Clients without a valid DNS name will take very + #long to connect. + RESOLVE_CLIENT_IP="no" + + #Path to the message of the day, seen by all users before login. + MOTD_GLOBAL="/etc/ftpmotd" + + #Path to the message of the day, seen after login, relative to the root + #path of the user (see ROOTDIR). + # Use symbols %u and %h in place of user's username and home directory. + MOTD_USER="/.ftpmotd" + + #If RESOLVE_UIDS is enabled, in directory lists the user and group names + #are shown instead of UID/GID. This may slow down directory listings. + RESOLVE_UIDS="yes" + + #If DO_CHROOT is enabled, a user can not access directories other than his + #HOMEDIR and its subdirectories. DON'T disable this globally if you don't + #want to have a security hole! + DO_CHROOT="yes" + + #Enable this to log each login to wtmp. + LOG_WTMP="yes" + + #If you want bftpd to bind itself to one specific network interface, enter + #its IP address here. Else enter 'any'. This option only works in standalone + #mode. + BIND_TO_ADDR="any" + + + # This option allows you to over-ride the IP address Bftpd + # sends to the client. This may be useful is you are behind + # a router. If an address is given in this option, it over-rides + # the LAN IP your PC had. It is recommended you leave this option + # commented out unless you have a special setup. + #OVERRIDE_IP="127.0.0.1" + + + #Path to the ftpusers file. It can contain user names that are denied. + #If it does not exist, every user can log in. If you don't want this, + #just put a nonexistent filename here. + PATH_FTPUSERS="/etc/ftpusers" + + #Enable this if you want to deny any user who has a shell which is not in + #/etc/shells. + AUTH_ETCSHELLS="no" + + #With the option ALLOWCOMMAND_XXXX, you can disable the command XXXX. + #For example, if you don't want any user to delete files, you can do + #ALLOWCOMMAND_DELE="no" + #Of course, you can disable it for specific users by writing the appropriate + #lines into the user structures. + ALLOWCOMMAND_DELE="yes" + ALLOWCOMMAND_STOR="yes" + ALLOWCOMMAND_SITE="no" + + #Files that belong to these groups (comma-separated) are hidden in LIST/NLST. + HIDE_GROUP="" + + #What message should be used as reply for the QUIT command? + QUIT_MSG="See you later..." + + #The number of users that can be logged in at the same time. + #If set to "0", an unlimited users will be able to connect. This is not + #recommended, as it makes DoS attacks possible, even if the clients are + #kicked after a short time. + USERLIMIT_GLOBAL="0" + + #This variable controls how often one user can be logged in at one time. + #This allows you to have a big connection limit (see above) and nevertheless + #prevent single users from having a lot of connections. + #This option may also be useful in a user {} or group {} environment. + USERLIMIT_SINGLEUSER="0" + + #This variable controls how many users are allowed to connect from the same IP + #address. This prvents one user (or machine) from taking all of the avail + #connections. + #If you want to allow unlimited connections, leave this option as "0". + USERLIMIT_HOST="0" + + #This option allows you to force files to be compressed + #on the fly during upload. A ".gz" extension will be given + #to the file. This should usually be turned off ("no"), but + #may be useful to servers with smaller storage space. + #To enable this option set the value to "yes". + # + # To use this option, bftpd must be configured using + # "./configure --enable-libz" _before_ running "make". + GZ_UPLOAD="no" + + #This option allows you to set whether or not files + #with the extension .gz should be uncompressed on-the-fly + #during downloads. This should usually be turned off ("no"). + #To enable this feature, set the value to "yes". + # + #To use this option, bftpd must be configured using + # "./configure --enable-libz" _before_ running "make". + GZ_DOWNLOAD="no" + + # This option is enabled when the server should run + # a script before writing to the file system. This should + # usually be commented out, unless you need to prepare the + # file system for writing. + # NOTE: Be careful when using this option and the DO_CHROOT option. + # The location of the root directory can change when using DO_CHROOT. + # The current working directory (cwd) is passed to the script you run. + # PRE_WRITE_SCRIPT="/bin/true" + + # This option is enabled when the server should run + # a script after writing to the file system. This should + # usually be commented out, unless you need to do something + # to the file system after writing. + # NOTE: Be careful when using this option and the DO_CHROOT option. + # The location of the root directory can change when using DO_CHROOT. + # The current working directory (cwd) is passed to the script you run. + # POST_WRITE_SCRIPT="/bin/false" + + # The GNU C library makes some assumptions about the local time zone + # when run in a chroot environment. The Bftpd server tries to work + # around these assumptions to give the correct time. If we are + # running in an environment which does not require the time zone + # fix, set TIMEZONE_FIX to "no". + # TIMEZONE_FIX="no" +} + +user ftp { + #Any password fits. + ANONYMOUS_USER="yes" + DENY_LOGIN="Anonymous login disabled." + #ROOTDIR="/path/for/anonymous/user" +} + +user anonymous { + #If the client wants anonymous, ftp is taken instead. + ALIAS="ftp" +} + +user root { + DENY_LOGIN="Root login not allowed." +} diff --git a/FluentFTP.Dockers/bftpd/docker-compose.yml b/FluentFTP.Dockers/bftpd/docker-compose.yml new file mode 100644 index 000000000..458821286 --- /dev/null +++ b/FluentFTP.Dockers/bftpd/docker-compose.yml @@ -0,0 +1,14 @@ +services: + bftpd: + build: + context: . + network: host + restart: unless-stopped + restart: always + ports: + - 0.0.0.0:20:20 + - 0.0.0.0:21:21 + - 21100-21199:21100-21199 + volumes: + - ./home:/home/bftpd + - ./logs:/var/log/bftpd diff --git a/FluentFTP.Dockers/bftpd/run-bftpd.sh b/FluentFTP.Dockers/bftpd/run-bftpd.sh new file mode 100644 index 000000000..07901878b --- /dev/null +++ b/FluentFTP.Dockers/bftpd/run-bftpd.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +# stdout server info: +cat << EOB + ************************************************* + * * + * Docker image: fluentftp bftpd * + * * + ************************************************* + + SERVER SETTINGS + --------------- + · FTP User: fluentuser + · FTP Password: fluentpass +EOB + +# Run bftpd: +&>/dev/null /usr/sbin/bftpd -c /usr/etc/bftpd.conf -D diff --git a/FluentFTP.Tests/Integration/IntegrationTests.cs b/FluentFTP.Tests/Integration/IntegrationTests.cs index 2af38785d..1534f14c7 100644 --- a/FluentFTP.Tests/Integration/IntegrationTests.cs +++ b/FluentFTP.Tests/Integration/IntegrationTests.cs @@ -28,6 +28,12 @@ public async Task ProFtpdSsl() { await IntegrationTestRunner.Run(FtpServer.ProFTPD, UseSsl); } + // These can only do FTP + [Fact] + public async Task Bftpd() { + await IntegrationTestRunner.Run(FtpServer.BFTPd); + } + // Still need SSL variants of these [Fact] public async Task PureFtpd() { diff --git a/FluentFTP.Xunit/Docker/Containers/BfFtpdContainer.cs b/FluentFTP.Xunit/Docker/Containers/BfFtpdContainer.cs new file mode 100644 index 000000000..693ad3459 --- /dev/null +++ b/FluentFTP.Xunit/Docker/Containers/BfFtpdContainer.cs @@ -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 BFtpdContainer : DockerFtpContainer { + + public BFtpdContainer() { + ServerType = FtpServer.BFTPd; + ServerName = "bftpd"; + DockerImage = "bftpd:fluentftp"; + //without SSL: + // RunCommand = "docker run --rm -it -p 21:21 -p 21100-21199:21100-21199 bftpd:fluentftp"; + //with SSL: + // not possible + } + + /// + /// For help creating this section see https://github.com/testcontainers/testcontainers-dotnet#supported-commands + /// + public override ITestcontainersBuilder Configure(ITestcontainersBuilder builder) { + + builder = builder.WithPortBinding(20); + + builder = ExposePortRange(builder, 21100, 21199); + + return builder; + } + + } + +} diff --git a/FluentFTP.Xunit/Docker/DockerFtpContainerIndex.cs b/FluentFTP.Xunit/Docker/DockerFtpContainerIndex.cs index 6aa54008d..b631b9ff2 100644 --- a/FluentFTP.Xunit/Docker/DockerFtpContainerIndex.cs +++ b/FluentFTP.Xunit/Docker/DockerFtpContainerIndex.cs @@ -12,7 +12,8 @@ internal static class DockerFtpContainerIndex { new ProFtpdContainer(), new PureFtpdContainer(), new PyFtpdLibContainer(), - new VsFtpdContainer() + new VsFtpdContainer(), + new BFtpdContainer() }; } }