Browse Source

Merge pull request #115 from ncw/fix-pasv

Parse IP address returned with PASV to fix load balanced FTP servers
Julien Laffaye 7 years ago
parent
commit
427467931c
1 changed files with 13 additions and 8 deletions
  1. 13 8
      ftp.go

+ 13 - 8
ftp.go

@@ -216,7 +216,7 @@ func (c *ServerConn) epsv() (port int, err error) {
 }
 }
 
 
 // pasv issues a "PASV" command to get a port number for a data connection.
 // pasv issues a "PASV" command to get a port number for a data connection.
-func (c *ServerConn) pasv() (port int, err error) {
+func (c *ServerConn) pasv() (host string, port int, err error) {
 	_, line, err := c.cmd(StatusPassiveMode, "PASV")
 	_, line, err := c.cmd(StatusPassiveMode, "PASV")
 	if err != nil {
 	if err != nil {
 		return
 		return
@@ -226,14 +226,16 @@ func (c *ServerConn) pasv() (port int, err error) {
 	start := strings.Index(line, "(")
 	start := strings.Index(line, "(")
 	end := strings.LastIndex(line, ")")
 	end := strings.LastIndex(line, ")")
 	if start == -1 || end == -1 {
 	if start == -1 || end == -1 {
-		return 0, errors.New("Invalid PASV response format")
+		err = errors.New("Invalid PASV response format")
+		return
 	}
 	}
 
 
 	// We have to split the response string
 	// We have to split the response string
 	pasvData := strings.Split(line[start+1:end], ",")
 	pasvData := strings.Split(line[start+1:end], ",")
 
 
 	if len(pasvData) < 6 {
 	if len(pasvData) < 6 {
-		return 0, errors.New("Invalid PASV response format")
+		err = errors.New("Invalid PASV response format")
+		return
 	}
 	}
 
 
 	// Let's compute the port number
 	// Let's compute the port number
@@ -251,15 +253,18 @@ func (c *ServerConn) pasv() (port int, err error) {
 
 
 	// Recompose port
 	// Recompose port
 	port = portPart1*256 + portPart2
 	port = portPart1*256 + portPart2
+
+	// Make the IP address to connect to
+	host = strings.Join(pasvData[0:4], ".")
 	return
 	return
 }
 }
 
 
-// getDataConnPort returns a port for a new data connection
+// getDataConnPort returns a host, port for a new data connection
 // it uses the best available method to do so
 // it uses the best available method to do so
-func (c *ServerConn) getDataConnPort() (int, error) {
+func (c *ServerConn) getDataConnPort() (string, int, error) {
 	if !c.DisableEPSV {
 	if !c.DisableEPSV {
 		if port, err := c.epsv(); err == nil {
 		if port, err := c.epsv(); err == nil {
-			return port, nil
+			return c.host, port, nil
 		}
 		}
 
 
 		// if there is an error, disable EPSV for the next attempts
 		// if there is an error, disable EPSV for the next attempts
@@ -271,12 +276,12 @@ func (c *ServerConn) getDataConnPort() (int, error) {
 
 
 // openDataConn creates a new FTP data connection.
 // openDataConn creates a new FTP data connection.
 func (c *ServerConn) openDataConn() (net.Conn, error) {
 func (c *ServerConn) openDataConn() (net.Conn, error) {
-	port, err := c.getDataConnPort()
+	host, port, err := c.getDataConnPort()
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	return net.DialTimeout("tcp", net.JoinHostPort(c.host, strconv.Itoa(port)), c.timeout)
+	return net.DialTimeout("tcp", net.JoinHostPort(host, strconv.Itoa(port)), c.timeout)
 }
 }
 
 
 // cmd is a helper function to execute a command and check for the expected FTP
 // cmd is a helper function to execute a command and check for the expected FTP