File tree Expand file tree Collapse file tree 1 file changed +20
-0
lines changed
Expand file tree Collapse file tree 1 file changed +20
-0
lines changed Original file line number Diff line number Diff line change @@ -516,6 +516,13 @@ function enterPassiveModeIPv4(ftp) {
516516 task . reject ( "Can't parse PASV response: " + res . message ) ;
517517 return ;
518518 }
519+ // If the host in the PASV response has a local address while the control connection hasn't,
520+ // we assume a NAT issue and use the IP of the control connection as the target for the data connection.
521+ // We can't always perform this replacement because it's possible (although unlikely) that the FTP server
522+ // indeed uses a different host for data connections.
523+ if ( ipIsPrivateAddress ( target . host ) && ! ipIsPrivateAddress ( ftp . socket . remoteAddress ) ) {
524+ target . host = ftp . socket . remoteAddress ;
525+ }
519526 const handleConnErr = function ( err ) {
520527 task . reject ( "Can't open data connection in passive mode: " + err . message ) ;
521528 } ;
@@ -572,6 +579,19 @@ function parseIPv4PasvResponse(message) {
572579 } ;
573580}
574581
582+ /**
583+ * Returns true if an IP is a private address according to https://tools.ietf.org/html/rfc1918#section-3
584+ *
585+ * @param {string } ip The IP as a string, e.g. "192.168.0.1"
586+ * @returns {boolean } true if the ip is local.
587+ */
588+ function ipIsPrivateAddress ( ip = "" ) {
589+ const octets = ip . split ( "." ) . map ( o => parseInt ( o , 10 ) ) ;
590+ return octets [ 0 ] === 10 // 10.0.0.0 - 10.255.255.255
591+ || ( octets [ 0 ] === 172 && octets [ 1 ] >= 16 && octets [ 1 ] <= 31 ) // 172.16.0.0 - 172.31.255.255
592+ || ( octets [ 0 ] === 192 && octets [ 1 ] === 168 ) ; // 192.168.0.0 - 192.168.255.255
593+ }
594+
575595/**
576596 * Upload stream data as a file. For example:
577597 *
You can’t perform that action at this time.
0 commit comments