Browse Source

PASV support

Gerben Castel 12 years ago
parent
commit
9fdb4d975a
1 changed files with 52 additions and 2 deletions
  1. 52 2
      ftp.go

+ 52 - 2
ftp.go

@@ -153,16 +153,66 @@ func (c *ServerConn) epsv() (port int, err error) {
 	return
 	return
 }
 }
 
 
+// pasv issues an "PASV" command to get a port number for a data connection.
+func (c *ServerConn) pasv() (port int, err error) {
+        _, line, err := c.cmd(StatusPassiveMode, "PASV")
+        if err != nil {
+                return
+        }
+
+        // PASV response format : 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2).
+        start := strings.Index(line, "(")
+        end := strings.LastIndex(line, ")")
+        if start == -1 || end == -1 {
+                err = errors.New("Invalid EPSV response format")
+                return
+        }
+
+        // We have to split the response string
+        pasvData := strings.Split(line[start+1 : end], ",")
+        // Let's compute the port number
+        portPart1, err1  := strconv.Atoi(pasvData[4])
+        if err1 != nil {
+                err = err1
+                return
+        }
+
+        portPart2, err2  := strconv.Atoi(pasvData[5])
+        if err2 != nil {
+                err = err2
+                return
+        }
+
+        // Recompose port
+        port = portPart1 * 256 + portPart2
+        return
+}
+
 // openDataConn creates a new FTP data connection.
 // openDataConn creates a new FTP data connection.
 //
 //
 // Currently, only EPSV is implemented but a fallback to PASV, and to a lesser
 // Currently, only EPSV is implemented but a fallback to PASV, and to a lesser
 // extent, PORT should be added.
 // extent, PORT should be added.
 func (c *ServerConn) openDataConn() (net.Conn, error) {
 func (c *ServerConn) openDataConn() (net.Conn, error) {
-	port, err := c.epsv()
-	if err != nil {
+        var port int
+	var err error
+
+        //  If features contains nat6 or EPSV => EPSV
+        //  else -> PASV
+	_,nat6Supported := c.features["nat6"];
+	_,epsvSupported := c.features["EPSV"];
+        if nat6Supported || epsvSupported {
+	  port, err = c.epsv()
+	  if err != nil {
 		return nil, err
 		return nil, err
+	  }
+	} else {
+          port, err = c.pasv()
+          if err != nil {
+                return nil, err
+          }
 	}
 	}
 
 
+
 	// Build the new net address string
 	// Build the new net address string
 	addr := fmt.Sprintf("%s:%d", c.host, port)
 	addr := fmt.Sprintf("%s:%d", c.host, port)