1 Star 0 Fork 0

soen / ftp-server-lib

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
transfer_pasv.go 8.87 KB
一键复制 编辑 原始数据 按行查看 历史
package ftpserver
import (
"crypto/tls"
"errors"
"fmt"
//"math/rand"
"net"
"strings"
"sync"
"time"
"gitee.com/xxp2014/logdot"
)
// Active/Passive transfer connection handler
type transferHandler interface {
// Get the connection to transfer data on
Open() (net.Conn, error)
// Close the connection (and any associated resource)
Close() error
// Set info about the transfer to return in STAT response
SetInfo(string)
// Info about the transfer to return in STAT response
GetInfo() string
//客户端连接重新计算
ClientRecount(num int)
}
// Passive connection
type passiveTransferHandler struct {
listener net.Listener // TCP or SSL Listener
tcpListener *net.TCPListener // TCP Listener (only keeping it to define a deadline during the accept)
LisBox *GlobalTCPListenerBox
Port int // TCP Port we are listening on
connection net.Conn // TCP Connection established
settings *Settings // Settings
info string // transfer info
logger *logdot.Logdot // Logger
// data connection requirement checker
checkDataConn func(dataConnIP net.IP, channelType DataChannel) error
}
type ipValidationError struct {
error string
}
func (e *ipValidationError) Error() string {
return e.error
}
func (c *clientHandler) getCurrentIP() ([]string, error) {
// Provide our external IP address so the ftp client can connect back to us
ip := c.server.settings.PublicHost
// If we don't have an IP address, we can take the one that was used for the current connection
if ip == "" {
// Defer to the user-provided resolver.
if c.server.settings.PublicIPResolver != nil {
var err error
ip, err = c.server.settings.PublicIPResolver(c)
if err != nil {
return nil, fmt.Errorf("couldn't fetch public IP: %w", err)
}
} else {
ip = strings.Split(c.conn.LocalAddr().String(), ":")[0]
}
}
quads := strings.Split(ip, ".")
if len(quads) != 4 {
c.logger.Warn("Invalid passive IP", "IP", ip)
return nil, &ipValidationError{error: fmt.Sprintf("invalid passive IP %#v", ip)}
}
return quads, nil
}
// ErrNoAvailableListeningPort is returned when no port could be found to accept incoming connection
var ErrNoAvailableListeningPort = errors.New("could not find any port to listen to or MaxClientsSingle limit")
var GlobalTCPListener *net.TCPListener
type GlobalTCPListenerBox struct {
Listener *net.TCPListener
ClientNum int //传输客户端连接数
MaxClientsSingle int //允许最大的客户端连接数量
IsListened bool //是否已经启用监听
}
// key:string value:GlobalTCPListenerBox
var GlobalTCPListeners sync.Map
func (c *clientHandler) findListenerWithinPortRange(portRange *PortRange) (*GlobalTCPListenerBox, error) {
nbAttempts := portRange.End - portRange.Start
nbAttempts = 1 + nbAttempts
for i := 0; i < nbAttempts; i++ {
port := portRange.Start + i
laddr, errResolve := net.ResolveTCPAddr("tcp", fmt.Sprintf("0.0.0.0:%d", port))
if errResolve != nil {
c.logger.Error("Problem resolving local port", "err", errResolve, "port", port)
continue
//return nil, fmt.Errorf("could not resolve port %d: %w", port, errResolve)
}
_, ok := GlobalTCPListeners.Load(laddr.String())
if !ok {
//如果不存在则新监听
tcpListener, errListen := net.ListenTCP("tcp", laddr)
if errListen == nil { //监听可能已经存在了,关闭后重新打开
tcpListener.Close()
tcpListener, errListen = net.ListenTCP("tcp", laddr)
if errListen != nil { //监听失败
c.logger.Error("Problem resolving local port", "err", errListen, "port", port)
return nil, errListen
}
}
//GlobalTCPListener = tcpListener
gtb := &GlobalTCPListenerBox{
Listener: tcpListener,
IsListened: true,
MaxClientsSingle: c.server.settings.MaxClientsSingle,
ClientNum: 0,
}
GlobalTCPListeners.Store(laddr.String(), gtb)
return gtb, nil
}
}
var gtlbMinBox *GlobalTCPListenerBox
//所有端口都已经监听 则遍历出 连接数最少的端口的监听者返回
GlobalTCPListeners.Range(func(key, value any) bool {
lis := value.(*GlobalTCPListenerBox)
if (gtlbMinBox == nil || gtlbMinBox.ClientNum == 0 || gtlbMinBox.ClientNum > lis.ClientNum) && lis.ClientNum < lis.MaxClientsSingle {
gtlbMinBox = lis
}
return true
})
if gtlbMinBox == nil {
c.logger.Warn(
"Could not find any free port",
"nbAttempts", nbAttempts,
"portRangeStart", portRange.Start,
"portRAngeEnd", portRange.End,
)
return nil, ErrNoAvailableListeningPort
}
return gtlbMinBox, nil
}
func (c *clientHandler) handlePASV(param string) error {
command := c.GetLastCommand()
addr, _ := net.ResolveTCPAddr("tcp", ":0")
var tcpListener *net.TCPListener
var tcpListenerBox *GlobalTCPListenerBox
var err error
portRange := c.server.settings.PassiveTransferPortRange
if portRange != nil {
tcpListenerBox, err = c.findListenerWithinPortRange(portRange)
} else {
tcpListener, err = net.ListenTCP("tcp", addr)
}
if err != nil {
c.logger.Error("Could not listen for passive connection", "err", err)
c.writeMessage(StatusServiceNotAvailable, fmt.Sprintf("Could not listen for passive connection: %v", err))
return nil
}
tcpListener = tcpListenerBox.Listener
// The listener will either be plain TCP or TLS
var listener net.Listener
listener = tcpListener
if wrapper, ok := c.server.driver.(MainDriverExtensionPassiveWrapper); ok {
listener, err = wrapper.WrapPassiveListener(listener)
if err != nil {
c.logger.Error("Could not wrap passive connection", "err", err)
c.writeMessage(StatusServiceNotAvailable, fmt.Sprintf("Could not listen for passive connection: %v", err))
return nil
}
}
if c.HasTLSForTransfers() || c.server.settings.TLSRequired == ImplicitEncryption {
if tlsConfig, err := c.server.driver.GetTLSConfig(); err == nil {
listener = tls.NewListener(listener, tlsConfig)
} else {
c.writeMessage(StatusServiceNotAvailable, fmt.Sprintf("Cannot get a TLS config: %v", err))
return nil
}
}
p := &passiveTransferHandler{
tcpListener: tcpListener,
listener: listener,
Port: tcpListener.Addr().(*net.TCPAddr).Port,
settings: c.server.settings,
logger: logdot.Create(logdot.Option{
Dir: ProgramDir + "runtime/",
File: "log/2006-01-02/2006-01-02 15.log",
SpecificFile: nil,
Stdout: true,
}),
checkDataConn: c.checkDataConnectionRequirement,
LisBox: tcpListenerBox,
}
// We should rewrite this part
if command == "PASV" {
p1 := p.Port / 256
p2 := p.Port - (p1 * 256)
quads, err2 := c.getCurrentIP()
if err2 != nil {
c.writeMessage(StatusServiceNotAvailable, fmt.Sprintf("Could not listen for passive connection: %v", err2))
return nil
}
c.writeMessage(
StatusEnteringPASV,
fmt.Sprintf("Entering Passive Mode (%s,%s,%s,%s,%d,%d)", quads[0], quads[1], quads[2], quads[3], p1, p2))
} else {
c.writeMessage(StatusEnteringEPSV, fmt.Sprintf("Entering Extended Passive Mode (|||%d|)", p.Port))
}
c.transferMu.Lock()
c.transfer = p
c.transferMu.Unlock()
c.setLastDataChannel(DataChannelPassive)
return nil
}
func (p *passiveTransferHandler) ConnectionWait(wait time.Duration) (net.Conn, error) {
if p.connection == nil {
var err error
if err = p.tcpListener.SetDeadline(time.Now().Add(wait)); err != nil {
return nil, fmt.Errorf("failed to set deadline: %w", err)
}
p.connection, err = p.listener.Accept()
if err != nil {
return nil, err
}
ip, err := getIPFromRemoteAddr(p.connection.RemoteAddr())
if err != nil {
p.logger.Warn("Could get remote passive IP address", "err", err)
return nil, err
}
if err := p.checkDataConn(ip, DataChannelPassive); err != nil {
// we don't want to expose the full error to the client, we just log it
p.logger.Warn("Could not validate passive data connection requirement", "err", err)
return nil, &ipValidationError{error: "data connection security requirements not met"}
}
}
return p.connection, nil
}
func (p *passiveTransferHandler) GetInfo() string {
return p.info
}
func (p *passiveTransferHandler) SetInfo(info string) {
p.info = info
}
func (p *passiveTransferHandler) Open() (net.Conn, error) {
timeout := time.Duration(time.Second.Nanoseconds() * int64(p.settings.ConnectionTimeout))
return p.ConnectionWait(timeout)
}
// Closing only the client connection is not supported at that time
func (p *passiveTransferHandler) Close() error {
//if p.tcpListener != nil {
// if err := p.tcpListener.Close(); err != nil {
// p.logger.Warn(
// "Problem closing passive listener",
// "err", err,
// )
// }
//}
if p.connection != nil {
if err := p.connection.Close(); err != nil {
p.logger.Warn(
"Problem closing passive connection",
"err", err,
)
}
}
return nil
}
func (p *passiveTransferHandler) ClientRecount(num int) {
if p.LisBox != nil {
p.LisBox.ClientNum = p.LisBox.ClientNum + num
}
p.logger.Info("连接数", p.LisBox.ClientNum)
}
1
https://gitee.com/xxp2014/ftp-server-lib.git
git@gitee.com:xxp2014/ftp-server-lib.git
xxp2014
ftp-server-lib
ftp-server-lib
v1.0.1

搜索帮助