From dd43de5f41d00394cdff2fedabbf8e97e059d79b Mon Sep 17 00:00:00 2001 From: Mats Erik Andersson Date: Wed, 4 Jan 2012 18:33:06 +0100 Subject: [PATCH] ftpd: Regression with active connections. In using an active connection, the port was not cleared properly, leading to a missed port allocation in bind(). A minor portability issue lead to change of hints for getaddrinfo() in resolving `host_port'. --- ChangeLog | 10 ++++++++++ ftpd/ftpcmd.y | 5 ++--- ftpd/ftpd.c | 15 +++++++++++++- tests/ftp-localhost.sh | 44 +++++++++++++++++++++++++++++++++++++++++- 4 files changed, 69 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 774ce149..06cc08ff 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2012-01-04 Mats Erik Andersson + + Regression: Erase port for active data transmission. + + * ftpd/ftpcmd.y (host_port): Use AI_NUMERICHOST and AI_NUMERICSERV + in `HINTS.ai_flags'. Do not use AI_ADDRCONFIG. + * ftpd/ftpd.c (getdatasock): Erase port number stored in DATA_SOURCE. + * tests/ftp-localhost.sh: Detect transfered data and duplicate tests + also for an active connection, not only a passive attempt. + 2012-01-03 Alfred M. Szmidt * bootstrap.conf (gnulib_modules): Removed git-merge-changelog. diff --git a/ftpd/ftpcmd.y b/ftpd/ftpcmd.y index 62bbcbc8..49a43555 100644 --- a/ftpd/ftpcmd.y +++ b/ftpd/ftpcmd.y @@ -620,9 +620,8 @@ host_port memset (&hints, 0, sizeof (hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; -#ifdef AI_ADDRCONFIG - hints.ai_flags = AI_ADDRCONFIG; -#endif + hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV; + err = getaddrinfo (a, p, &hints, &res); if (err) reply (550, "Address failure: %s,%s", a, p); diff --git a/ftpd/ftpd.c b/ftpd/ftpd.c index dfba2fe2..29e9eed9 100644 --- a/ftpd/ftpd.c +++ b/ftpd/ftpd.c @@ -1037,10 +1037,23 @@ getdatasock (const char *mode) goto bad; } - /* anchor socket to avoid multi-homing problems */ + /* Anchor socket to avoid multi-homing problems. */ memcpy (&data_source, &ctrl_addr, sizeof (data_source)); data_source_len = ctrl_addrlen; + /* Erase port number, suggesting bind() to allocate a new port. */ + switch (data_source.ss_family) + { + case AF_INET6: + ((struct sockaddr_in6 *) &data_source)->sin6_port = 0; + break; + case AF_INET: + ((struct sockaddr_in *) &data_source)->sin_port = 0; + break; + default: + break; /* Do nothing; should not happen! */ + } + for (tries = 1;; tries++) { if (bind (s, (struct sockaddr *) &data_source, data_source_len) >= 0) diff --git a/tests/ftp-localhost.sh b/tests/ftp-localhost.sh index 2eec9441..556a717b 100755 --- a/tests/ftp-localhost.sh +++ b/tests/ftp-localhost.sh @@ -74,6 +74,8 @@ $INETD --pidfile=$TMPDIR/inetd.pid $TMPDIR/inetd.conf # Wait for inetd to write pid and open socket sleep 2 +# Test a passive connection. +# cat <$TMPDIR/ftp.stdout + +errno=$? +cat $TMPDIR/ftp.stdout + +if [ $errno != 0 ]; then + echo running ftp failed? errno $errno + exit 77 +fi + +if [ $errno != 0 ]; then + echo running ftp failed? errno $errno + exit 77 +fi + +# Standing control connection? +if ! grep 'FTP server status' $TMPDIR/ftp.stdout; then + echo cannot find expected output for active ftp client? + exit 1 +fi + +# Was data transfer successful? +if ! grep '226 Transfer complete.' $TMPDIR/ftp.stdout; then + echo cannot find transfer result for active ftp client? exit 1 fi