配置文件部分:
Go
FtpServer:
ListenAddr: ":2121"
ListenDir: "/data/ftpwww" # ftp目录
PassivePortRange: # end必须大于start,否则会panic, 非被动模式不用配置
Start: 3121
End: 3124
ListenUsers: # ftp账号
- Username: ftpadmin
Password: "123456..."
- Username: ftpadmin
Password: "yueduo-654321..."
加载配置文件
Go
package config
import (
"fmt"
"gopkg.in/yaml.v3"
"os"
)
var (
Conf Config
)
type Config struct {
...
FtpServer FtpServer `yaml:"FtpServer"`
...
}
func InitConfigFromYaml(file string) error {
if file == "" {
file = "config.yaml"
}
f, err := os.Open(file)
if err != nil {
return fmt.Errorf("配置文件打开错误.%w", err)
}
dec := yaml.NewDecoder(f)
err = dec.Decode(&Conf)
if err != nil {
return err
}
return nil
}
main.go引用
Go
//初始化配置文件
err := config.InitConfigFromYaml(f)
if err != nil {
logn.Errorf("配置文件初始化错误,file:%s 错误信息:%v", f, err)
return
}
// 加载ftp
go ftp.FtpDirver()
ftp部分perm
Go
package ftp
import (
"fmt"
"os"
)
// 加载文件权限只读
type ReadOnlyPerm struct{}
func (p *ReadOnlyPerm) GetOwner(path string) (string, error) {
return "ftp", nil
}
func (p *ReadOnlyPerm) GetGroup(path string) (string, error) {
return "ftp", nil
}
func (p *ReadOnlyPerm) GetMode(path string) (os.FileMode, error) {
// 0444: 只读(r--r--r--)
return 0444, nil
}
func (p *ReadOnlyPerm) ChOwner(path, owner string) error {
return fmt.Errorf("permission denied")
}
func (p *ReadOnlyPerm) ChGroup(path, group string) error {
return fmt.Errorf("permission denied")
}
func (p *ReadOnlyPerm) ChMode(path string, mode os.FileMode) error {
return fmt.Errorf("permission denied")
}
dirver.go
Go
package ftp
import (
"fmt"
filedriver "github.com/goftp/file-driver"
"github.com/goftp/server"
"io"
"log"
"net"
"os"
"safe-agent/config"
)
type MultiUserAuth struct {
users map[string]config.FTPUser
}
type PerUserDriverFactory struct {
users map[string]config.FTPUser
}
type PerUserFileDriver struct {
*filedriver.FileDriver
users map[string]config.FTPUser
}
func (d *PerUserFileDriver) Init(conn *server.Conn) {
// 🔥 每个用户设置自己的根目录
d.FileDriver.RootPath = config.Conf.FtpServer.ListenDir
}
func (d *PerUserFileDriver) Delete(path string) error {
return fmt.Errorf("550 permission denied")
}
func (d *PerUserFileDriver) DeleteFile(path string) error {
return fmt.Errorf("550 permission denied")
}
func (d *PerUserFileDriver) Rename(from, to string) error {
return fmt.Errorf("550 permission denied")
}
func (d *PerUserFileDriver) PutFile(destPath string, data io.Reader, appendData bool) (int64, error) {
return 0, fmt.Errorf("550 permission denied")
}
func (d *PerUserFileDriver) Chmod(path string, mode os.FileMode) error {
return fmt.Errorf("550 permission denied")
}
func (d *PerUserFileDriver) Remove(path string) error {
return fmt.Errorf("550 permission denied")
}
func (d *PerUserFileDriver) RemoveDir(path string) error {
return fmt.Errorf("550 permission denied")
}
func (d *PerUserFileDriver) MakeDir(path string) error {
return fmt.Errorf("550 permission denied")
}
func (f *PerUserDriverFactory) NewDriver() (server.Driver, error) {
return &PerUserFileDriver{
FileDriver: &filedriver.FileDriver{
Perm: &ReadOnlyPerm{},
},
users: f.users,
}, nil
}
func (a *MultiUserAuth) CheckPasswd(user, pass string) (bool, error) {
u, ok := a.users[user]
if !ok {
return false, nil
}
return u.Password == pass, nil
}
func FtpDirver() {
userMap := make(map[string]config.FTPUser)
for _, u := range config.Conf.FtpServer.ListenUsers {
userMap[u.Username] = u
}
host, portStr, _ := net.SplitHostPort(config.Conf.FtpServer.ListenAddr)
port := 0
if portStr != "" {
fmt.Sscanf(portStr, "%d", &port)
}
passiveRange := config.Conf.FtpServer.PassivePortRange
passivePorts := fmt.Sprintf("%d-%d", passiveRange.Start, passiveRange.End)
opts := &server.ServerOpts{
Factory: &PerUserDriverFactory{
users: userMap,
},
PassivePorts: passivePorts,
Auth: &MultiUserAuth{users: userMap},
Port: port,
Hostname: host,
}
//log.Printf("FTP server listening on %s", config.Conf.FtpServer.ListenAddr)
fmt.Printf(
"FTP listen=%s passive_ports=%s",
config.Conf.FtpServer.ListenAddr,
passivePorts,
)
s := server.NewServer(opts)
log.Fatal(s.ListenAndServe())
}