Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

connection to bad ftp server hangs whole connection most of the time #256

Open
boindil opened this issue Apr 27, 2022 · 4 comments
Open
Labels
accepted Accepted issue defect The code does not work as intended

Comments

@boindil
Copy link

boindil commented Apr 27, 2022

Describe the bug
The connection attempts to not abort properly

To Reproduce
I've set up an ftp server that can be reached somewhat, but is not fully functional (as tested via telnet)

package main

import (
	"log"
	"time"

	"github.com/jlaffaye/ftp"
)

func main() {
	c, err := ftp.Dial("10.0.2.2:21", ftp.DialWithTimeout(5*time.Second))
	if err != nil {
		log.Fatal(err)
	}

	err = c.Login("anonymous", "anonymous")
	if err != nil {
		log.Fatal(err)
	}

	// Do something with the FTP conn

	if err := c.Quit(); err != nil {
		log.Fatal(err)
	}
}

Expected behavior
dialing is aborted after timeout
p.s.: adding DialWithContext and adding a context that is cancelled after x seconds does not work either

FTP server

  • Name and version: Windows 10 1909 integrated FTP via IIS services
  • Public URL if applicable

Debug output
DialWithDebugOutput literally does nothing when it comes to the error. I guess that somethings waiting for more data to be submitted by the FTP server, but that never happens - thus its hanging.

Additional context
Go: go version go1.18.1 linux/amd64

sometime EOF error, sometimes not
image

corresponds to telnet tests, but this is still not a working FTP connection (command line FTP clients do not work either)
note the ^C in the lower left. The connection would stay open until I did something, while the first one aborts immediately (i guess thats the EOF case)
image

@boindil boindil added the defect The code does not work as intended label Apr 27, 2022
@jlaffaye
Copy link
Owner

jlaffaye commented May 4, 2022

Oh, yes, the timeout is for opening the TCP connection. It is not currently used for every read/write.

@jlaffaye jlaffaye added the accepted Accepted issue label May 4, 2022
@glebteterin
Copy link

In my case it was an attempt to connect to freeSSHd: http://www.freesshd.com/ (identifies as SSH-2.0-WeOnlyDo 2.4.3)

In the Dial we expect to get a status code, but the freeSSHd replies with a single line SSH-2.0-WeOnlyDo 2.4.3, then the next ReadLine() hungs.

@jlaffaye does it make sense to set SetReadDeadline on the underlying network connection in the Dial ?

@lanyi1998
Copy link

I had the same problem

@sjakub
Copy link

sjakub commented Sep 10, 2024

Same problem here. This also happens when connecting to an HTTP server (which doesn't send anything on its own).
The Dial hangs until the remote server closes the connection.

EDIT:
For anybody else dealing with this, I came up with a different way of handling the timeout for the entire connection process.
Basically I use a custom DialFunc that stores all the connections generated:

var netCons []net.Conn

dialOpt := ftp.DialWithDialFunc(
  func(network, address string) (net.Conn, error) {
    dialer := net.Dialer{}
    c, err := dialer.Dial(network, address)
    if c != nil {
      netCons = append(netCons, c)
    }
    return c, err
})

Then I start a routine which, after some timeout delay, if the connection attempt hasn't completed yet, either closes all those connections, or uses SetDeadline with time in the past to get that 'timeout' error. This interrupts the connection attempt, no matter what state it is in.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
accepted Accepted issue defect The code does not work as intended
Projects
None yet
Development

No branches or pull requests

5 participants