ソースを参照

transfer logs: add FTP mode

Nicola Murino 4 年 前
コミット
555dc3b0c0
6 ファイル変更63 行追加8 行削除
  1. 8 2
      common/transfer.go
  2. 13 0
      common/transfer_test.go
  3. 2 1
      docs/logs.md
  4. 16 0
      ftpd/handler.go
  5. 15 1
      ftpd/internal_test.go
  6. 9 4
      logger/logger.go

+ 8 - 2
common/transfer.go

@@ -30,6 +30,7 @@ type BaseTransfer struct { //nolint:maligned
 	fsPath          string
 	effectiveFsPath string
 	requestPath     string
+	ftpMode         string
 	start           time.Time
 	MaxWriteSize    int64
 	MinWriteOffset  int64
@@ -68,6 +69,11 @@ func NewBaseTransfer(file vfs.File, conn *BaseConnection, cancelFn func(), fsPat
 	return t
 }
 
+// SetFtpMode sets the FTP mode for the current transfer
+func (t *BaseTransfer) SetFtpMode(mode string) {
+	t.ftpMode = mode
+}
+
 // GetID returns the transfer ID
 func (t *BaseTransfer) GetID() uint64 {
 	return t.ID
@@ -236,7 +242,7 @@ func (t *BaseTransfer) Close() error {
 	elapsed := time.Since(t.start).Nanoseconds() / 1000000
 	if t.transferType == TransferDownload {
 		logger.TransferLog(downloadLogSender, t.fsPath, elapsed, atomic.LoadInt64(&t.BytesSent), t.Connection.User.Username,
-			t.Connection.ID, t.Connection.protocol, t.Connection.localAddr, t.Connection.remoteAddr)
+			t.Connection.ID, t.Connection.protocol, t.Connection.localAddr, t.Connection.remoteAddr, t.ftpMode)
 		ExecuteActionNotification(&t.Connection.User, operationDownload, t.fsPath, t.requestPath, "", "", t.Connection.protocol,
 			atomic.LoadInt64(&t.BytesSent), t.ErrTransfer)
 	} else {
@@ -247,7 +253,7 @@ func (t *BaseTransfer) Close() error {
 		t.Connection.Log(logger.LevelDebug, "uploaded file size %v", fileSize)
 		t.updateQuota(numFiles, fileSize)
 		logger.TransferLog(uploadLogSender, t.fsPath, elapsed, atomic.LoadInt64(&t.BytesReceived), t.Connection.User.Username,
-			t.Connection.ID, t.Connection.protocol, t.Connection.localAddr, t.Connection.remoteAddr)
+			t.Connection.ID, t.Connection.protocol, t.Connection.localAddr, t.Connection.remoteAddr, t.ftpMode)
 		ExecuteActionNotification(&t.Connection.User, operationUpload, t.fsPath, t.requestPath, "", "", t.Connection.protocol, fileSize,
 			t.ErrTransfer)
 	}

+ 13 - 0
common/transfer_test.go

@@ -284,3 +284,16 @@ func TestRemovePartialCryptoFile(t *testing.T) {
 	assert.Equal(t, int64(9), size)
 	assert.NoFileExists(t, testFile)
 }
+
+func TestFTPMode(t *testing.T) {
+	conn := NewBaseConnection("", ProtocolFTP, "", "", dataprovider.User{})
+	transfer := BaseTransfer{
+		Connection:    conn,
+		transferType:  TransferUpload,
+		BytesReceived: 123,
+		Fs:            vfs.NewOsFs("", os.TempDir(), ""),
+	}
+	assert.Empty(t, transfer.ftpMode)
+	transfer.SetFtpMode("active")
+	assert.Equal(t, "active", transfer.ftpMode)
+}

+ 2 - 1
docs/logs.md

@@ -20,7 +20,8 @@ The logs can be divided into the following categories:
   - `username`, string
   - `file_path` string
   - `connection_id` string. Unique connection identifier
-  - `protocol` string. `SFTP` or `SCP`
+  - `protocol` string. `SFTP`, `SCP`, `SSH`, `FTP`, `HTTP`, `DAV`
+  - `ftp_mode`, string. `active` or `passive`. Included only for `FTP` protocol
 - **"command logs"**, SFTP/SCP command logs:
   - `sender` string. `Rename`, `Rmdir`, `Mkdir`, `Symlink`, `Remove`, `Chmod`, `Chown`, `Chtimes`, `Truncate`, `SSHCommand`
   - `level` string

+ 16 - 0
ftpd/handler.go

@@ -30,6 +30,19 @@ type Connection struct {
 	clientContext ftpserver.ClientContext
 }
 
+func (c *Connection) getFTPMode() string {
+	if c.clientContext == nil {
+		return ""
+	}
+	switch c.clientContext.GetLastDataChannel() {
+	case ftpserver.DataChannelActive:
+		return "active"
+	case ftpserver.DataChannelPassive:
+		return "passive"
+	}
+	return ""
+}
+
 // GetClientVersion returns the connected client's version.
 // It returns "Unknown" if the client does not advertise its
 // version
@@ -325,6 +338,7 @@ func (c *Connection) downloadFile(fs vfs.Fs, fsPath, ftpPath string, offset int6
 
 	baseTransfer := common.NewBaseTransfer(file, c.BaseConnection, cancelFn, fsPath, fsPath, ftpPath, common.TransferDownload,
 		0, 0, 0, false, fs)
+	baseTransfer.SetFtpMode(c.getFTPMode())
 	t := newTransfer(baseTransfer, nil, r, offset)
 
 	return t, nil
@@ -390,6 +404,7 @@ func (c *Connection) handleFTPUploadToNewFile(fs vfs.Fs, resolvedPath, filePath,
 
 	baseTransfer := common.NewBaseTransfer(file, c.BaseConnection, cancelFn, resolvedPath, filePath, requestPath,
 		common.TransferUpload, 0, 0, maxWriteSize, true, fs)
+	baseTransfer.SetFtpMode(c.getFTPMode())
 	t := newTransfer(baseTransfer, w, nil, 0)
 
 	return t, nil
@@ -466,6 +481,7 @@ func (c *Connection) handleFTPUploadToExistingFile(fs vfs.Fs, flags int, resolve
 
 	baseTransfer := common.NewBaseTransfer(file, c.BaseConnection, cancelFn, resolvedPath, filePath, requestPath,
 		common.TransferUpload, minWriteOffset, initialSize, maxWriteSize, false, fs)
+	baseTransfer.SetFtpMode(c.getFTPMode())
 	t := newTransfer(baseTransfer, w, nil, 0)
 
 	return t, nil

+ 15 - 1
ftpd/internal_test.go

@@ -253,6 +253,7 @@ xr5cb9VBRBtB9aOKVfuRhpatAfS2Pzm2Htae9lFn7slGPUmu2hkjDw==
 )
 
 type mockFTPClientContext struct {
+	lastDataChannel ftpserver.DataChannel
 }
 
 func (cc mockFTPClientContext) Path() string {
@@ -298,7 +299,7 @@ func (cc mockFTPClientContext) GetLastCommand() string {
 }
 
 func (cc mockFTPClientContext) GetLastDataChannel() ftpserver.DataChannel {
-	return ftpserver.DataChannelPassive
+	return cc.lastDataChannel
 }
 
 // MockOsFs mockable OsFs
@@ -559,6 +560,19 @@ func TestUserInvalidParams(t *testing.T) {
 	assert.Error(t, err)
 }
 
+func TestFTPMode(t *testing.T) {
+	connection := &Connection{
+		BaseConnection: common.NewBaseConnection("", common.ProtocolFTP, "", "", dataprovider.User{}),
+	}
+	assert.Empty(t, connection.getFTPMode())
+	connection.clientContext = mockFTPClientContext{lastDataChannel: ftpserver.DataChannelActive}
+	assert.Equal(t, "active", connection.getFTPMode())
+	connection.clientContext = mockFTPClientContext{lastDataChannel: ftpserver.DataChannelPassive}
+	assert.Equal(t, "passive", connection.getFTPMode())
+	connection.clientContext = mockFTPClientContext{lastDataChannel: 0}
+	assert.Empty(t, connection.getFTPMode())
+}
+
 func TestClientVersion(t *testing.T) {
 	mockCC := mockFTPClientContext{}
 	connID := fmt.Sprintf("2_%v", mockCC.ID())

+ 9 - 4
logger/logger.go

@@ -259,8 +259,10 @@ func ErrorToConsole(format string, v ...interface{}) {
 }
 
 // TransferLog logs uploads or downloads
-func TransferLog(operation, path string, elapsed int64, size int64, user, connectionID, protocol, localAddr, remoteAddr string) {
-	logger.Info().
+func TransferLog(operation, path string, elapsed int64, size int64, user, connectionID, protocol, localAddr,
+	remoteAddr, ftpMode string,
+) {
+	ev := logger.Info().
 		Timestamp().
 		Str("sender", operation).
 		Str("local_addr", localAddr).
@@ -270,8 +272,11 @@ func TransferLog(operation, path string, elapsed int64, size int64, user, connec
 		Str("username", user).
 		Str("file_path", path).
 		Str("connection_id", connectionID).
-		Str("protocol", protocol).
-		Send()
+		Str("protocol", protocol)
+	if ftpMode != "" {
+		ev.Str("ftp_mode", ftpMode)
+	}
+	ev.Send()
 }
 
 // CommandLog logs an SFTP/SCP/SSH command