Explorar o código

ftpd: add some security checks

Nicola Murino %!s(int64=4) %!d(string=hai) anos
pai
achega
a3c087456b
Modificáronse 13 ficheiros con 151 adicións e 41 borrados
  1. 4 5
      common/common.go
  2. 6 1
      common/common_test.go
  3. 22 7
      config/config.go
  4. 8 0
      config/config_test.go
  5. 2 0
      docs/full-configuration.md
  6. 20 0
      ftpd/ftpd.go
  7. 4 4
      ftpd/ftpd_test.go
  8. 43 0
      ftpd/internal_test.go
  9. 17 1
      ftpd/server.go
  10. 7 5
      go.mod
  11. 14 14
      go.sum
  12. 2 4
      sftpd/server.go
  13. 2 0
      sftpgo.json

+ 4 - 5
common/common.go

@@ -412,9 +412,8 @@ func (c *Configuration) IsAtomicUploadEnabled() bool {
 }
 
 // GetProxyListener returns a wrapper for the given listener that supports the
-// HAProxy Proxy Protocol or nil if the proxy protocol is not configured
+// HAProxy Proxy Protocol
 func (c *Configuration) GetProxyListener(listener net.Listener) (*proxyproto.Listener, error) {
-	var proxyListener *proxyproto.Listener
 	var err error
 	if c.ProxyProtocol > 0 {
 		var policyFunc func(upstream net.Addr) (proxyproto.Policy, error)
@@ -436,12 +435,12 @@ func (c *Configuration) GetProxyListener(listener net.Listener) (*proxyproto.Lis
 				}
 			}
 		}
-		proxyListener = &proxyproto.Listener{
+		return &proxyproto.Listener{
 			Listener: listener,
 			Policy:   policyFunc,
-		}
+		}, nil
 	}
-	return proxyListener, nil
+	return nil, errors.New("proxy protocol not configured")
 }
 
 // ExecuteStartupHook runs the startup hook if defined

+ 6 - 1
common/common_test.go

@@ -557,8 +557,13 @@ func TestQuotaScans(t *testing.T) {
 
 func TestProxyProtocolVersion(t *testing.T) {
 	c := Configuration{
-		ProxyProtocol: 1,
+		ProxyProtocol: 0,
 	}
+	_, err := c.GetProxyListener(nil)
+	if assert.Error(t, err) {
+		assert.Contains(t, err.Error(), "proxy protocol not configured")
+	}
+	c.ProxyProtocol = 1
 	proxyListener, err := c.GetProxyListener(nil)
 	assert.NoError(t, err)
 	assert.Nil(t, proxyListener.Policy)

+ 22 - 7
config/config.go

@@ -46,13 +46,16 @@ var (
 		ApplyProxyConfig: true,
 	}
 	defaultFTPDBinding = ftpd.Binding{
-		Address:          "",
-		Port:             0,
-		ApplyProxyConfig: true,
-		TLSMode:          0,
-		ForcePassiveIP:   "",
-		ClientAuthType:   0,
-		TLSCipherSuites:  nil,
+		Address:                    "",
+		Port:                       0,
+		ApplyProxyConfig:           true,
+		TLSMode:                    0,
+		ForcePassiveIP:             "",
+		ClientAuthType:             0,
+		TLSCipherSuites:            nil,
+		PassiveConnectionsSecurity: 0,
+		ActiveConnectionsSecurity:  0,
+		Debug:                      false,
 	}
 	defaultWebDAVDBinding = webdavd.Binding{
 		Address:         "",
@@ -745,6 +748,18 @@ func getFTPDBindingFromEnv(idx int) {
 		isSet = true
 	}
 
+	pasvSecurity, ok := lookupIntFromEnv(fmt.Sprintf("SFTPGO_FTPD__BINDINGS__%v__PASSIVE_CONNECTIONS_SECURITY", idx))
+	if ok {
+		binding.PassiveConnectionsSecurity = int(pasvSecurity)
+		isSet = true
+	}
+
+	activeSecurity, ok := lookupIntFromEnv(fmt.Sprintf("SFTPGO_FTPD__BINDINGS__%v__ACTIVE_CONNECTIONS_SECURITY", idx))
+	if ok {
+		binding.ActiveConnectionsSecurity = int(activeSecurity)
+		isSet = true
+	}
+
 	debug, ok := lookupBoolFromEnv(fmt.Sprintf("SFTPGO_FTPD__BINDINGS__%v__DEBUG", idx))
 	if ok {
 		binding.Debug = debug

+ 8 - 0
config/config_test.go

@@ -522,12 +522,14 @@ func TestFTPDBindingsFromEnv(t *testing.T) {
 	os.Setenv("SFTPGO_FTPD__BINDINGS__0__TLS_MODE", "2")
 	os.Setenv("SFTPGO_FTPD__BINDINGS__0__FORCE_PASSIVE_IP", "127.0.1.2")
 	os.Setenv("SFTPGO_FTPD__BINDINGS__0__TLS_CIPHER_SUITES", "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256")
+	os.Setenv("SFTPGO_FTPD__BINDINGS__0__PASSIVE_CONNECTIONS_SECURITY", "1")
 	os.Setenv("SFTPGO_FTPD__BINDINGS__9__ADDRESS", "127.0.1.1")
 	os.Setenv("SFTPGO_FTPD__BINDINGS__9__PORT", "2203")
 	os.Setenv("SFTPGO_FTPD__BINDINGS__9__TLS_MODE", "1")
 	os.Setenv("SFTPGO_FTPD__BINDINGS__9__FORCE_PASSIVE_IP", "127.0.1.1")
 	os.Setenv("SFTPGO_FTPD__BINDINGS__9__CLIENT_AUTH_TYPE", "2")
 	os.Setenv("SFTPGO_FTPD__BINDINGS__9__DEBUG", "1")
+	os.Setenv("SFTPGO_FTPD__BINDINGS__9__ACTIVE_CONNECTIONS_SECURITY", "1")
 
 	t.Cleanup(func() {
 		os.Unsetenv("SFTPGO_FTPD__BINDINGS__0__ADDRESS")
@@ -536,12 +538,14 @@ func TestFTPDBindingsFromEnv(t *testing.T) {
 		os.Unsetenv("SFTPGO_FTPD__BINDINGS__0__TLS_MODE")
 		os.Unsetenv("SFTPGO_FTPD__BINDINGS__0__FORCE_PASSIVE_IP")
 		os.Unsetenv("SFTPGO_FTPD__BINDINGS__0__TLS_CIPHER_SUITES")
+		os.Unsetenv("SFTPGO_FTPD__BINDINGS__0__ACTIVE_CONNECTIONS_SECURITY")
 		os.Unsetenv("SFTPGO_FTPD__BINDINGS__9__ADDRESS")
 		os.Unsetenv("SFTPGO_FTPD__BINDINGS__9__PORT")
 		os.Unsetenv("SFTPGO_FTPD__BINDINGS__9__TLS_MODE")
 		os.Unsetenv("SFTPGO_FTPD__BINDINGS__9__FORCE_PASSIVE_IP")
 		os.Unsetenv("SFTPGO_FTPD__BINDINGS__9__CLIENT_AUTH_TYPE")
 		os.Unsetenv("SFTPGO_FTPD__BINDINGS__9__DEBUG")
+		os.Unsetenv("SFTPGO_FTPD__BINDINGS__9__ACTIVE_CONNECTIONS_SECURITY")
 	})
 
 	configDir := ".."
@@ -559,6 +563,8 @@ func TestFTPDBindingsFromEnv(t *testing.T) {
 	require.Equal(t, "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", bindings[0].TLSCipherSuites[0])
 	require.Equal(t, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", bindings[0].TLSCipherSuites[1])
 	require.False(t, bindings[0].Debug)
+	require.Equal(t, 1, bindings[0].PassiveConnectionsSecurity)
+	require.Equal(t, 0, bindings[0].ActiveConnectionsSecurity)
 	require.Equal(t, 2203, bindings[1].Port)
 	require.Equal(t, "127.0.1.1", bindings[1].Address)
 	require.True(t, bindings[1].ApplyProxyConfig) // default value
@@ -566,6 +572,8 @@ func TestFTPDBindingsFromEnv(t *testing.T) {
 	require.Equal(t, "127.0.1.1", bindings[1].ForcePassiveIP)
 	require.Equal(t, 2, bindings[1].ClientAuthType)
 	require.Nil(t, bindings[1].TLSCipherSuites)
+	require.Equal(t, 0, bindings[1].PassiveConnectionsSecurity)
+	require.Equal(t, 1, bindings[1].ActiveConnectionsSecurity)
 	require.True(t, bindings[1].Debug)
 }
 

+ 2 - 0
docs/full-configuration.md

@@ -116,6 +116,8 @@ The configuration file contains the following sections:
     - `force_passive_ip`, ip address. External IP address to expose for passive connections. Leavy empty to autodetect. If not empty, it must be a valid IPv4 address. Defaut: "".
     - `client_auth_type`, integer. Set to `1` to require a client certificate and verify it. Set to `2` to request a client certificate during the TLS handshake and verify it if given, in this mode the client is allowed not to send a certificate. At least one certification authority must be defined in order to verify client certificates. If no certification authority is defined, this setting is ignored. Default: 0.
     - `tls_cipher_suites`, list of strings. List of supported cipher suites for TLS version 1.2. If empty, a default list of secure cipher suites is used, with a preference order based on hardware performance. Note that TLS 1.3 ciphersuites are not configurable. The supported ciphersuites names are defined [here](https://github.com/golang/go/blob/master/src/crypto/tls/cipher_suites.go#L52). Any invalid name will be silently ignored. The order matters, the ciphers listed first will be the preferred ones. Default: empty.
+    - `passive_connections_security`, integer. Defines the security checks for passive data connections. Set to `0` to require matching peer IP addresses of control and data connection. Set to `1` to disable any checks. Please note that if you run the FTP service behind a proxy you must enable the proxy protocol for both control and data connections. Default: `0`.
+    - `active_connections_security`, integer. Defines the security checks for active data connections. The supported values are the same as described for `passive_connections_security`. Please note that disabling the security checks you will make the FTP service vulnerable to bounce attacks on active data connections, so change the default value only if you are on a trusted/internal network. Default: `0`.
     - `debug`, boolean. If enabled any FTP command will be logged. This will generate a lot of logs. Enable only if you are investigating a client compatibility issue or something similar. You shouldn't leave this setting enabled for production servers. Default `false`.
   - `banner`, string. Greeting banner displayed when a connection first comes in. Leave empty to use the default banner. Default `SFTPGo <version> ready`, for example `SFTPGo 1.0.0-dev ready`.
   - `banner_file`, path to the banner file. The contents of the specified file, if any, are displayed when someone connects to the server. It can be a path relative to the config dir or an absolute one. If set, it overrides the banner string provided by the `banner` option. Leave empty to disable.

+ 20 - 0
ftpd/ftpd.go

@@ -51,6 +51,16 @@ type Binding struct {
 	// any invalid name will be silently ignored.
 	// The order matters, the ciphers listed first will be the preferred ones.
 	TLSCipherSuites []string `json:"tls_cipher_suites" mapstructure:"tls_cipher_suites"`
+	// PassiveConnectionsSecurity defines the security checks for passive data connections.
+	// Supported values:
+	// - 0 require matching peer IP addresses of control and data connection. This is the default
+	// - 1 disable any checks
+	PassiveConnectionsSecurity int `json:"passive_connections_security" mapstructure:"passive_connections_security"`
+	// ActiveConnectionsSecurity defines the security checks for active data connections.
+	// The supported values are the same as described for PassiveConnectionsSecurity.
+	// Please note that disabling the security checks you will make the FTP service vulnerable to bounce attacks
+	// on active data connections, so change the default value only if you are on a trusted/internal network
+	ActiveConnectionsSecurity int `json:"active_connections_security" mapstructure:"active_connections_security"`
 	// Debug enables the FTP debug mode. In debug mode, every FTP command will be logged
 	Debug   bool `json:"debug" mapstructure:"debug"`
 	ciphers []uint16
@@ -77,6 +87,16 @@ func (b *Binding) IsValid() bool {
 	return b.Port > 0
 }
 
+func (b *Binding) checkSecuritySettings() error {
+	if b.PassiveConnectionsSecurity < 0 || b.PassiveConnectionsSecurity > 1 {
+		return fmt.Errorf("invalid passive_connections_security: %v", b.PassiveConnectionsSecurity)
+	}
+	if b.ActiveConnectionsSecurity < 0 || b.ActiveConnectionsSecurity > 1 {
+		return fmt.Errorf("invalid active_connections_security: %v", b.ActiveConnectionsSecurity)
+	}
+	return nil
+}
+
 func (b *Binding) checkPassiveIP() error {
 	if b.ForcePassiveIP != "" {
 		ip := net.ParseIP(b.ForcePassiveIP)

+ 4 - 4
ftpd/ftpd_test.go

@@ -2289,13 +2289,13 @@ func TestActiveModeDisabled(t *testing.T) {
 	if assert.NoError(t, err) {
 		code, response, err := client.SendCustomCommand("PORT 10,2,0,2,4,31")
 		assert.NoError(t, err)
-		assert.Equal(t, ftp.StatusCommandOK, code)
-		assert.Equal(t, "PORT command successful", response)
+		assert.Equal(t, ftp.StatusBadArguments, code)
+		assert.Equal(t, "Your request does not meet the configured security requirements", response)
 
 		code, response, err = client.SendCustomCommand("EPRT |1|132.235.1.2|6275|")
 		assert.NoError(t, err)
-		assert.Equal(t, ftp.StatusCommandOK, code)
-		assert.Equal(t, "EPRT command successful", response)
+		assert.Equal(t, ftp.StatusBadArguments, code)
+		assert.Equal(t, "Your request does not meet the configured security requirements", response)
 
 		err = client.Quit()
 		assert.NoError(t, err)

+ 43 - 0
ftpd/internal_test.go

@@ -13,6 +13,7 @@ import (
 
 	"github.com/eikenb/pipeat"
 	ftpserver "github.com/fclairamb/ftpserverlib"
+	"github.com/pires/go-proxyproto"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 
@@ -393,6 +394,19 @@ func TestInitialization(t *testing.T) {
 	_, err = server.GetSettings()
 	assert.Error(t, err)
 
+	binding.PassiveConnectionsSecurity = 100
+	binding.ActiveConnectionsSecurity = 100
+	server = NewServer(c, configDir, binding, 0)
+	_, err = server.GetSettings()
+	if assert.Error(t, err) {
+		assert.Contains(t, err.Error(), "invalid passive_connections_security")
+	}
+	binding.PassiveConnectionsSecurity = 1
+	server = NewServer(c, configDir, binding, 0)
+	_, err = server.GetSettings()
+	if assert.Error(t, err) {
+		assert.Contains(t, err.Error(), "invalid active_connections_security")
+	}
 	binding = Binding{
 		Port:           2121,
 		ForcePassiveIP: "192.168.1",
@@ -467,6 +481,35 @@ func TestServerGetSettings(t *testing.T) {
 	binding.TLSMode = 2
 	assert.Equal(t, "Implicit", binding.GetTLSDescription())
 
+	certPath := filepath.Join(os.TempDir(), "test.crt")
+	keyPath := filepath.Join(os.TempDir(), "test.key")
+	err = os.WriteFile(certPath, []byte(ftpsCert), os.ModePerm)
+	assert.NoError(t, err)
+	err = os.WriteFile(keyPath, []byte(ftpsKey), os.ModePerm)
+	assert.NoError(t, err)
+
+	common.Config.ProxyAllowed = nil
+	c.CertificateFile = certPath
+	c.CertificateKeyFile = keyPath
+	server = NewServer(c, configDir, binding, 0)
+	server.binding.Port = 9021
+	settings, err = server.GetSettings()
+	assert.NoError(t, err)
+	assert.NotNil(t, settings.Listener)
+
+	listener, err := net.Listen("tcp", ":0")
+	assert.NoError(t, err)
+	listener, err = server.WrapPassiveListener(listener)
+	assert.NoError(t, err)
+
+	_, ok := listener.(*proxyproto.Listener)
+	assert.True(t, ok)
+
+	err = os.Remove(certPath)
+	assert.NoError(t, err)
+	err = os.Remove(keyPath)
+	assert.NoError(t, err)
+
 	common.Config = oldConfig
 }
 

+ 17 - 1
ftpd/server.go

@@ -86,6 +86,9 @@ func (s *Server) GetSettings() (*ftpserver.Settings, error) {
 	if err := s.binding.checkPassiveIP(); err != nil {
 		return nil, err
 	}
+	if err := s.binding.checkSecuritySettings(); err != nil {
+		return nil, err
+	}
 	var portRange *ftpserver.PortRange
 	if s.config.PassivePortRange.Start > 0 && s.config.PassivePortRange.End > s.config.PassivePortRange.Start {
 		portRange = &ftpserver.PortRange{
@@ -94,7 +97,7 @@ func (s *Server) GetSettings() (*ftpserver.Settings, error) {
 		}
 	}
 	var ftpListener net.Listener
-	if common.Config.ProxyProtocol > 0 && s.binding.ApplyProxyConfig {
+	if s.binding.HasProxy() {
 		listener, err := net.Listen("tcp", s.binding.GetAddress())
 		if err != nil {
 			logger.Warn(logSender, "", "error starting listener on address %v: %v", s.binding.GetAddress(), err)
@@ -105,6 +108,9 @@ func (s *Server) GetSettings() (*ftpserver.Settings, error) {
 			logger.Warn(logSender, "", "error enabling proxy listener: %v", err)
 			return nil, err
 		}
+		if s.binding.TLSMode == 2 && s.tlsConfig != nil {
+			ftpListener = tls.NewListener(ftpListener, s.tlsConfig)
+		}
 	}
 
 	if s.binding.TLSMode < 0 || s.binding.TLSMode > 2 {
@@ -130,6 +136,8 @@ func (s *Server) GetSettings() (*ftpserver.Settings, error) {
 		EnableHASH:               s.config.HASHSupport > 0,
 		EnableCOMB:               s.config.CombineSupport > 0,
 		DefaultTransferType:      ftpserver.TransferTypeBinary,
+		ActiveConnectionsCheck:   ftpserver.DataConnectionRequirement(s.binding.ActiveConnectionsSecurity),
+		PasvConnectionsCheck:     ftpserver.DataConnectionRequirement(s.binding.PassiveConnectionsSecurity),
 	}, nil
 }
 
@@ -199,6 +207,14 @@ func (s *Server) AuthUser(cc ftpserver.ClientContext, username, password string)
 	return connection, nil
 }
 
+// WrapPassiveListener implements the MainDriverExtensionPassiveWrapper interface
+func (s *Server) WrapPassiveListener(listener net.Listener) (net.Listener, error) {
+	if s.binding.HasProxy() {
+		return common.Config.GetProxyListener(listener)
+	}
+	return listener, nil
+}
+
 // VerifyConnection checks whether a user should be authenticated using a client certificate without prompting for a password
 func (s *Server) VerifyConnection(cc ftpserver.ClientContext, user string, tlsConn *tls.Conn) (ftpserver.ClientDriver, error) {
 	if !s.binding.isMutualTLSEnabled() {

+ 7 - 5
go.mod

@@ -7,7 +7,7 @@ require (
 	github.com/Azure/azure-storage-blob-go v0.14.0
 	github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962
 	github.com/alexedwards/argon2id v0.0.0-20210511081203-7d35d68092b8
-	github.com/aws/aws-sdk-go v1.40.12
+	github.com/aws/aws-sdk-go v1.40.15
 	github.com/cockroachdb/cockroach-go/v2 v2.1.1
 	github.com/eikenb/pipeat v0.0.0-20210603033007-44fc3ffce52b
 	github.com/fatih/color v1.12.0 // indirect
@@ -26,11 +26,11 @@ require (
 	github.com/hashicorp/go-retryablehttp v0.7.0
 	github.com/hashicorp/yamux v0.0.0-20210707203944-259a57b3608c // indirect
 	github.com/jlaffaye/ftp v0.0.0-20201112195030-9aae4d151126
-	github.com/klauspost/compress v1.13.1
-	github.com/klauspost/cpuid/v2 v2.0.8 // indirect
+	github.com/klauspost/compress v1.13.3
+	github.com/klauspost/cpuid/v2 v2.0.9 // indirect
 	github.com/kr/text v0.2.0 // indirect
 	github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect
-	github.com/lestrrat-go/jwx v1.2.4
+	github.com/lestrrat-go/jwx v1.2.5
 	github.com/lib/pq v1.10.2
 	github.com/mattn/go-isatty v0.0.13 // indirect
 	github.com/mattn/go-sqlite3 v1.14.8
@@ -62,13 +62,15 @@ require (
 	golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c
 	golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac
 	google.golang.org/api v0.52.0
-	google.golang.org/genproto v0.0.0-20210729151513-df9385d47c1b // indirect
+	google.golang.org/genproto v0.0.0-20210804223703-f1db76f3300d // indirect
 	google.golang.org/grpc v1.39.0
 	google.golang.org/protobuf v1.27.1
 	gopkg.in/natefinch/lumberjack.v2 v2.0.0
 )
 
 replace (
+	github.com/eikenb/pipeat => github.com/drakkan/pipeat v0.0.0-20210805162858-70e57fa8a639
+	github.com/fclairamb/ftpserverlib => github.com/drakkan/ftpserverlib v0.0.0-20210805132427-425f32d9dc15
 	github.com/jlaffaye/ftp => github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9
 	golang.org/x/crypto => github.com/drakkan/crypto v0.0.0-20210515063737-edf1d3b63536
 	golang.org/x/net => github.com/drakkan/net v0.0.0-20210725074420-30b60d4a1e60

+ 14 - 14
go.sum

@@ -118,8 +118,8 @@ github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZo
 github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
 github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
 github.com/aws/aws-sdk-go v1.38.68/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
-github.com/aws/aws-sdk-go v1.40.12 h1:66+IAWhl+aaZCW1+ndS/GNfAxy8tJca2cMoIF2O325I=
-github.com/aws/aws-sdk-go v1.40.12/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
+github.com/aws/aws-sdk-go v1.40.15 h1:aqQCwW8meVzLCacWX8NEPg8bBkL0ZlcMSbhwrsg6eNE=
+github.com/aws/aws-sdk-go v1.40.15/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
 github.com/aws/aws-sdk-go-v2 v1.7.0/go.mod h1:tb9wi5s61kTDA5qCkcDbt3KRVV74GGslQkl/DRdX/P4=
 github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.5.0/go.mod h1:acH3+MQoiMzozT/ivU+DbRg7Ooo2298RdRaWcOv+4vM=
 github.com/aws/smithy-go v1.5.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
@@ -176,15 +176,17 @@ github.com/drakkan/crypto v0.0.0-20210515063737-edf1d3b63536 h1:3DJdhj83IA3NjlVz
 github.com/drakkan/crypto v0.0.0-20210515063737-edf1d3b63536/go.mod h1:M1JpE4lvRI5LLrE7yTCWfhbsy5rx3oZVjGZad4XMwWc=
 github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9 h1:LPH1dEblAOO/LoG7yHPMtBLXhQmjaga91/DDjWk9jWA=
 github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9/go.mod h1:2lmrmq866uF2tnje75wQHzmPXhmSWUt7Gyx2vgK1RCU=
+github.com/drakkan/ftpserverlib v0.0.0-20210805132427-425f32d9dc15 h1:J7FZPDILyOMYtShuM5hH3GLTL1cCDtoJ1InsxEyl798=
+github.com/drakkan/ftpserverlib v0.0.0-20210805132427-425f32d9dc15/go.mod h1:+Doq95UijHTIaJcWREhyu9dyQOqyoULbVU3OXgs8wEI=
 github.com/drakkan/net v0.0.0-20210725074420-30b60d4a1e60 h1:qGPbhCgKiOglRLoNPgAwdTOp3xW3TC96RSGLkmVdsd0=
 github.com/drakkan/net v0.0.0-20210725074420-30b60d4a1e60/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+github.com/drakkan/pipeat v0.0.0-20210805162858-70e57fa8a639 h1:8tfGdb4kg/YCvAbIrsMazgoNtnqdOqQVDKW12uUCuuU=
+github.com/drakkan/pipeat v0.0.0-20210805162858-70e57fa8a639/go.mod h1:kltMsfRMTHSFdMbK66XdS8mfMW77+FZA1fGY1xYMF84=
 github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
 github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
 github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
 github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
 github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
-github.com/eikenb/pipeat v0.0.0-20210603033007-44fc3ffce52b h1:h7A/b/M1yuYqQwZmRf+9BKuUJQgkgdvXYAwVl7L7WBo=
-github.com/eikenb/pipeat v0.0.0-20210603033007-44fc3ffce52b/go.mod h1:kltMsfRMTHSFdMbK66XdS8mfMW77+FZA1fGY1xYMF84=
 github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -197,8 +199,6 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv
 github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
 github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc=
 github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
-github.com/fclairamb/ftpserverlib v0.15.0 h1:3MmdkZy8orZwemZLgwIdCwcyac3hCH2PcBFo5S/F7AM=
-github.com/fclairamb/ftpserverlib v0.15.0/go.mod h1:+Doq95UijHTIaJcWREhyu9dyQOqyoULbVU3OXgs8wEI=
 github.com/fclairamb/go-log v0.1.0 h1:fNoqk8w62i4EDEuRzDgHdDVTqMYSyr3DS981R7F2x/Y=
 github.com/fclairamb/go-log v0.1.0/go.mod h1:iqmym8aI6xBbZXnZSPjElrmQrlEwjwEemOmIzKaTBM8=
 github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk=
@@ -474,11 +474,11 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
 github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
 github.com/klauspost/compress v1.11.12/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
 github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
-github.com/klauspost/compress v1.13.1 h1:wXr2uRxZTJXHLly6qhJabee5JqIhTRoLBhDOA74hDEQ=
-github.com/klauspost/compress v1.13.1/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
+github.com/klauspost/compress v1.13.3 h1:BtAvtV1+h0YwSVwWoYXMREPpYu9VzTJ9QDI1TEg/iQQ=
+github.com/klauspost/compress v1.13.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
 github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
-github.com/klauspost/cpuid/v2 v2.0.8 h1:bhR2mgIlno/Sfk4oUbH4sPlc83z1yGrN9bvqiq3C33I=
-github.com/klauspost/cpuid/v2 v2.0.8/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
+github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
+github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@@ -507,8 +507,8 @@ github.com/lestrrat-go/httpcc v1.0.0/go.mod h1:tGS/u00Vh5N6FHNkExqGGNId8e0Big+++
 github.com/lestrrat-go/iter v1.0.1 h1:q8faalr2dY6o8bV45uwrxq12bRa1ezKrB6oM9FUgN4A=
 github.com/lestrrat-go/iter v1.0.1/go.mod h1:zIdgO1mRKhn8l9vrZJZz9TUMMFbQbLeTsbqPDrJ/OJc=
 github.com/lestrrat-go/jwx v1.1.6/go.mod h1:c+R8G7qsaFNmTzYjU98A+sMh8Bo/MJqO9GnpqR+X024=
-github.com/lestrrat-go/jwx v1.2.4 h1:EuVGI/hPUSRstxWpWjVcklOe1odJLVrFY9zt4k1pa30=
-github.com/lestrrat-go/jwx v1.2.4/go.mod h1:CAe9Z479rJwIYDR2DqWwMm9c+gCNoYB6+0wBxPkEh0Q=
+github.com/lestrrat-go/jwx v1.2.5 h1:0Akd9qTHrla8eqCV54Z4wRVv54WI54dUHN5D2+mIayc=
+github.com/lestrrat-go/jwx v1.2.5/go.mod h1:CAe9Z479rJwIYDR2DqWwMm9c+gCNoYB6+0wBxPkEh0Q=
 github.com/lestrrat-go/option v0.0.0-20210103042652-6f1ecfceda35/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
 github.com/lestrrat-go/option v1.0.0 h1:WqAWL8kh8VcSoD6xjSH34/1m8yxluXQbDeKNfvFeEO4=
 github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
@@ -1085,8 +1085,8 @@ google.golang.org/genproto v0.0.0-20210624174822-c5cf32407d0a/go.mod h1:SzzZ/N+n
 google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
 google.golang.org/genproto v0.0.0-20210721163202-f1cecdd8b78a/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
 google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
-google.golang.org/genproto v0.0.0-20210729151513-df9385d47c1b h1:4xoALQmXxqVdDdLimpPyPeDdsJzo+nFTJw9euAMpqgM=
-google.golang.org/genproto v0.0.0-20210729151513-df9385d47c1b/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
+google.golang.org/genproto v0.0.0-20210804223703-f1db76f3300d h1:Y9fT4WNRxuD0qofEPeWJwNC5kYLBcSXx0m91zyCMzYY=
+google.golang.org/genproto v0.0.0-20210804223703-f1db76f3300d/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
 google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=

+ 2 - 4
sftpd/server.go

@@ -226,16 +226,14 @@ func (c *Configuration) Initialize(configDir string) error {
 				return
 			}
 
-			if binding.ApplyProxyConfig {
+			if binding.ApplyProxyConfig && common.Config.ProxyProtocol > 0 {
 				proxyListener, err := common.Config.GetProxyListener(listener)
 				if err != nil {
 					logger.Warn(logSender, "", "error enabling proxy listener: %v", err)
 					exitChannel <- err
 					return
 				}
-				if proxyListener != nil {
-					listener = proxyListener
-				}
+				listener = proxyListener
 			}
 
 			exitChannel <- c.serve(listener, serverConfig)

+ 2 - 0
sftpgo.json

@@ -84,6 +84,8 @@
         "force_passive_ip": "",
         "client_auth_type": 0,
         "tls_cipher_suites": [],
+        "passive_connections_security": 0,
+        "active_connections_security": 0,
         "debug": false
       }
     ],