Golang FTP Server library
This library allows to easily build a simple and fully-featured FTP server using afero as the backend filesystem.
If you're interested in a fully featured FTP server, you should use sftpgo (fully featured SFTP/FTP server) or ftpserver (basic FTP server).
Current status of the project
Features
- Uploading and downloading files
- Directory listing (LIST + MLST)
- File and directory deletion and renaming
- TLS support (AUTH + PROT)
- File download/upload resume support (REST)
- Passive socket connections (PASV and EPSV commands)
- Active socket connections (PORT and EPRT commands)
- IPv6 support (EPSV + EPRT)
- Small memory footprint
- Clean code: No sleep, no panic, no global sync (only around control/transfer connection per client)
- Uses only the standard library except for:
- Supported extensions:
- AUTH - Control session protection
- AUTH TLS - TLS session
- PROT - Transfer protection
- EPRT/EPSV - IPv6 support
- MDTM - File Modification Time
- SIZE - Size of a file
- REST - Restart of interrupted transfer
- MLST - Simple file listing for machine processing
- MLSD - Directory listing for machine processing
- HASH - Hashing of files
- AVLB - Available space
- COMB - Combine files
Quick test
The easiest way to test this library is to use ftpserver.
The driver
The simplest way to get a good understanding of how the driver shall be implemented is to look at the tests driver.
The base API
The API is directly based on afero.
type MainDriver interface {
GetSettings() (*Settings, error)
ClientConnected(cc ClientContext) (string, error)
ClientDisconnected(cc ClientContext)
AuthUser(cc ClientContext, user, pass string) (ClientDriver, error)
GetTLSConfig() (*tls.Config, error)
}
type ClientDriver interface {
afero.Fs
}
type ClientContext interface {
Path() string
SetDebug(debug bool)
Debug() bool
ID() uint32
RemoteAddr() net.Addr
LocalAddr() net.Addr
GetClientVersion() string
Close() error
HasTLSForControl() bool
HasTLSForTransfers() bool
GetLastCommand() string
GetLastDataChannel() DataChannel
}
type Settings struct {
Listener net.Listener
ListenAddr string
PublicHost string
PublicIPResolver PublicIPResolver
PassiveTransferPortRange *PortRange
ActiveTransferPortNon20 bool
IdleTimeout int
ConnectionTimeout int
DisableMLSD bool
DisableMLST bool
DisableMFMT bool
Banner string
TLSRequired TLSRequirement
DisableLISTArgs bool
DisableSite bool
DisableActiveMode bool
EnableHASH bool
DisableSTAT bool
DisableSYST bool
EnableCOMB bool
DefaultTransferType TransferType
ActiveConnectionsCheck DataConnectionRequirement
PasvConnectionsCheck DataConnectionRequirement
}
Extensions
There are a few extensions to the base afero APIs so that you can perform some operations that aren't offered by afero.
Pre-allocate some space
type ClientDriverExtensionAllocate interface {
AllocateSpace(size int) error
}
Get available space
type ClientDriverExtensionAvailableSpace interface {
GetAvailableSpace(dirName string) (int64, error)
}
Create symbolic link
type ClientDriverExtensionSymlink interface {
Symlink(oldname, newname string) error
}
Compute file hash
type ClientDriverExtensionHasher interface {
ComputeHash(name string, algo HASHAlgo, startOffset, endOffset int64) (string, error)
}
History of the project
I wanted to make a system which would accept files through FTP and redirect them to something else. Go seemed like the obvious choice and it seemed there was a lot of libraries available but it turns out none of them were in a useable state.