Howto: Anonymous FTP server on LAN: FreeBSD's FTPD

Using FreeBSD's /usr/libexec/ftpd which will soon be ftp/freebsd-ftpd. This doesn't use a secure connection, so it's not meant for transferring confidential files. The way the anonymous ftpd server is set up, it doesn't use a password either. Read only mode is optional.

Add FTP user
adduser
Code:
user: ftp
shell: nologin
choose default or custom
 ftp home directory
To later change directory or other variables, use chsh(1). On FreeBSD, ftpd will select this as the home directory.

FTPD directories and permissions
~/ftp/ set permissions to root:wheel, and set to 755, so it's un-writable by group and other. If it needs ftp:wheel, for the directory itself, with nothing else under it for it to work, as ftp is the original owner when this user directory is creating, then the configuration is lacking, as the owner needs to be root.
~/ftp/bin/ needed if access to system's commands is restricted.
~/ftp/etc/ owned by root:wheel, and un-writable by anyone, as permission 555
~/ftp/pub/ owned by root:wheel; should be 755 or 775. Shouldn't be owned by ftp or ftp group. Should be download only. This is where files for sharing on the anonymous ftp server belong. Files in this directory belong to its respective owner, rather than being relevant to the ftp directory structure. To upload, use incoming.
~/ftp/incoming/ this directory is only for anyone, especially anonymous, to upload files to. This directory is optional, only if you need it for this purpose. Files should be uploaded here, instead of to pub by anonymous users. Its owner is nobody:wheel; permissions are 1777. To use this directory, read-only mode shouldn't be enabled.
Remove . (dot) files, that come with the newly created ftp directory.
This is according to ftpd(8) and other documentation.

/etc/ftpusers is where to place users who are denied access.
/etc/ftpwelcome is where a welcome message can be placed.
~/ftp/etc/ftpmotd where message after successfully logging in can be placed.

Trying server and client
Start the anonymous server, by trying /usr/libexec/ftpd -A -D. The A flag is for anonymous, and D is for starting as a daemon. -r mode is optional for read only mode, only if you want to prevent uploads to the relevant incoming/ directory to your anonymous server.

Test with ftp localhost first, then, try starting ftpd by using the ip address of your computer listed by ifconfig(8). Optionally, add alias through rc.conf and restart netif:
Code:
ifconfig_re0_alias0="inet 192.168.10.1 netmask 0xffffff00"
In my case, this is a Class C IP address. To make the ftpd server available outside of computer, firewall settings may need to be temporary disabled, to adjust settings and test functionality. ftp uses port 21, per /etc/services.

To see the port running use ps ax |grep ftp or sockstat -l |grep ftp as root.

Make configuration permanent
FreeBSD's version of ftpd comes with its own service startup script. rc.conf:
Code:
ftpd_enable="YES"
ftpd_flags="-A -D"
The -r flag is optional, depending on if you want to be able to upload to the incoming/ directory of your anonymous ftp server. For other ftpd's without a service start up script available, one would use inetd.conf(8) instead.

FTP usage
Choose "ftp" or its login alias of "anonymous" as the user, then press enter for password. Other users as anonymous can be added through /etc/ftpchroot.

On the ftp console, use ? for help. Use close to exit a connection. Then, enter ftp to try to connect to a local network address. Alternatively, than the IP address, your computer's hostname followed by .lan can be used: this hostname can be found in rc.conf. If the wrong user was entered, the user command can be used. Use ls and cd to move around in the ftp directories, and get to retrieve files. This can be used on your local computer for testing, however, this is also useful on the network. mget and mput are for multiple downloads or uploads. lcd is to change directories outside of the ftp directory for saving: not applicable to anonymous users.

Using from smart phone
For using this ftp directory from your smart phone, the apps FTP Client and Total Commander with its ftp plugin can be used to access this anonymous ftpd directory. Use the IP address of your computer, its alias, or its hostname with the LAN name.

About alternative ftp servers
For reference, this isn't tftpd/tftp (traditional/trivial ftp) as that doesn't have these commands, and that's for more limited but for some purposes essential use. With tftpd(8), you must know the file name, and it uses the /tftpboot/ directory. tftpd also runs on port 69, as opposed to port 21. It's typically for diskless booting.

For an attempted comparison of non-viral licensed ftp servers and hints about their use: Thread netbsds-tnftpd-compared-to-other-ftp-servers.95259. That thread had to be re-edited and corrected. There's also mention of secure FTP servers which use SSL/TLS.

Refs
  • Network Administration with FreeBSD 7
  • BSD UNIX Toolbox
  • FreeBSD 6 Unleashed
  • FreeBSD documentation
 
ftp/tnftpd is an alternative from NetBSD. It's for The NetBSD FTP daemon: the T is for The rather than trivial/traditional, since TNFTPD doesn't use TFTP conventions.

FTP SSL/TLS ports, nonviral license:
ftp/uftp - SSL/TLS
ftp/pure-ftpd - SSL/TLS
ftp/bsdftpd-ssl - SSL/TLS

FTP SSL/TLS ports, GPL:
ftp/vsftpd - SSL/TLS
ftp/wzdftpd - SSL/TLS

Security based on permissions/access, rather than SSL/TLS nor SSH
ftp/twoftpd - security not reliant on SSL/TLS nor SSH. Security is based on permisisons.
ftp/oftpd - anonymous and uploads only. May be secure by those aspects, but nothing on TLS/SSL
ftp/publicfile - not SSL/TLS, not HTTPS

SFTP server
I've decided to look into sftp for comparison to ftps. sftp isn't really ftp, but it behaves basically as ftp. They differ in protocol design, while having a similar function of file transfer, as sftp uses the ssh protocol and configuration files. The real ftp really doesn't work well with ssh, as they normally interrupt each other, as ftp isn't made for ssh. ssh connects from another direction, and ftp thinks that it's an illegitimate attempt. sftp uses port 22, the same as the ssh it uses. Configuration of sftp relies upon the configuration of ssh.

/etc/ssh/sshd_config is the configuration file for FreeBSD's /usr/libexec/sftp-server:
sshd_config:Subsystem sftp /usr/libexec/sftp-server

scp works the same way as sftp, however it has less features, like you cannot list the files you want to retrieve. scp also uses the ssh protocol.

More that are secure based on SSH, usually SFTP
ftp/sftpgo - SFTP, but has FTP/S support
ftp/bbftp-server - like SFTP but uses its own transfer protocol

For more of sftp and ssh:
 
There was a minor error in the previous post: .lan was used as an example in the network lan address. It was set there for it to be useful. I have configured it with this address as an alias, but it may not be the way. However, it depends upon the LAN address set by your router/gateway/modem or other device which manages your network. Use netstat -r to see the name of the IP address [hostname and network address] hosting your ftpd server. IP Aliases for this connection may show up as loopback devices, which lead to the actual IP address, but these aliases can be used.

/etc/hosts has examples of private IP ranges. More advanced set up can use this configuration file for setting a name for an IP address. It's possible to accidentally make an FTP server inaccessible outside of the computer through here or through other configuration files.

Firewall
Another caveat is, if you're using a canned firewall of IPFW, insert into rc.conf the exceptions to allow:
Code:
firewall_enable="YES"
firewall_type="workstation"
firewall_myservices="20/tcp 21/tcp 989/tcp 38434/tcp"
firewall_allowservices="myhost.mylan.net" # ip address or hostname
In my case, I had to temporarily turn off my firewall, to check the setting, then, adjust my firewall based on that.

Client configuration
ftp client can be started with -a, so that it won't ask for the password. Alternatively, .netrc can be used to set this, for instance:
Code:
default login anonymous password ftp@domain
If you're using a set specific domain, you can replace the word domain. Otherwise, this will work, and you'll have to set this on the console.

Troubleshooting
See /var/log/messages or /var/log/xferlog. Also, start the daemon with the -l option: ftpd -l.

A few network settings had to be cleaned up in my configuration files for it to be accessible again outside of my computer. Also, make sure that your gateway/modem router allow access through your LAN.
 
Updates:
ftp/pftpd - Anonymous, lightweight ftpd that uses permissive license, https://www.lysator.liu.se/~pen/pftpd/

IPFW settings:
/etc/rc.conf
Code:
firewall_type="workstation"
firewall_myservices="21/tcp 35000-65000/tcp"
firewall_allowservices="hostname.lan.tld phonehostname.lan.tld
     ipv6address.ifapplicable"
In this, I've turned off my firewall, with service ipfw stop. Then, used sockstat|grep ftp with the phone/other client connected to find the ports to leave open. There's two address with port columns: one for local address and one for foreign address, each with relevant port numbers. For phone client apps that don't use IPv4, I had to add the IPv6 address into firewall_allowservices=. Turn the firewall back on to test it, and try to include port ranges needed.

hosts.allow
hosts.allow: Thread ftpd-any-way-to-limit-logins.3336
 
I am still on FreeBSD 13.4-RELEASE here and installed the freebsd-ftpd pkg. Note that the freebsd-ftpd port / pkg places its binary in /usr/local/libexec/ and does not install a localized ftpd script in /usr/local/etc/rc.d/. I created my own by copying and editing the /etc/rc.d/ftpd script to be able to use this on the LAN. Note the modification to rcvar and command below:

Code:
# cat /usr/local/etc/rc.d/freebsd-ftpd
#!/bin/sh
#
#

# PROVIDE: ftpd
# REQUIRE: LOGIN FILESYSTEMS
# KEYWORD: shutdown

. /etc/rc.subr

name="ftpd"
desc="Internet File Transfer Protocol daemon"
rcvar="freebsd_ftpd_enable"
command="/usr/local/libexec/${name}"
pidfile="/var/run/${name}.pid"
start_precmd=ftpd_prestart

ftpd_prestart()
{
        rc_flags="-D ${rc_flags}"
        return 0
}

load_rc_config $name
run_rc_command "$1"

Here is the relevant rc.conf entry:

Code:
# grep ftp /etc/rc.conf
freebsd_ftpd_enable="YES"

Here is my relevant pf.conf entry for the server firewall which limits connections to the LAN:

Code:
# grep ftp /etc/pf.conf
pass in on $ext_if proto tcp from 192.168.50.0/24 to ($ext_if) port ftp
 
Last edited:
To make ftpd a little more secure, you can set it to a specific static IP, which you've set an IP alias to. In your /etc/rc.conf, add to ftpd_flags=: -a followed by the static IP address. You can see this after restarting the service, and typing sockstat -4l | grep ftp. The asterisk will be replaced by the set IP address. Already, access is denied from IP's, including from localhost, which aren't of this alias. Now using this IP alias, you can more easily firewall access to it, like ports and devices.

To see routing tables use netstat -r. There's variations of netstat(1) and sockstat(1) sometimes with | grep ftp to see all kinds of processes or network information.

You can also remove ftpmotd and the etc/ directory it's under from ~/ftp/. Depending on the functions of your ftp server, you can have either or both of pub or incoming.

You can shortcut your log in with ftp ftp@IPaddress. ftp is the username, which only ftp or anonymous are accepted users for anonymous ftp.

You can name this IP and local domain in /etc/hosts, for instance:
Code:
# ftp
172.16.0.2    myhost myhost.internal
Local subnet namespaces to IP's can further be named in /etc/networks: networks(5). In this, you would only insert the first set of digits of the IP of that network:
Code:
internal    172
Then, netstat -i will show it.

You must only use IP's and domain namespaces made for private networks. See:
From this, you can replace the IP address with the hostname, or the hostname with the local domain namespace, like: ftp ftp@myhost.internal.


For a TLS/SSL secure ftp, you can try ftp/bsdftpd-ssl. Perhaps someone else can write a HowTo for that one.
 
Back
Top