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()
};
}
}