Implement FTPS implicit FTP over TLS
This commit is contained in:
parent
769512c448
commit
8c9122ed82
@ -6,6 +6,7 @@ go:
|
||||
- 1.8.1
|
||||
env:
|
||||
- FTP_SERVER=vsftpd
|
||||
- FTP_SERVER=vsftpd_implicit_tls
|
||||
- FTP_SERVER=proftpd
|
||||
before_install:
|
||||
- sudo $TRAVIS_BUILD_DIR/.travis/prepare.sh "$FTP_SERVER"
|
||||
|
@ -1,18 +1,31 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
mkdir --mode 0777 -p /var/ftp/incoming
|
||||
|
||||
case "$1" in
|
||||
proftpd)
|
||||
mkdir -p /etc/proftpd/conf.d/
|
||||
cp $TRAVIS_BUILD_DIR/.travis/proftpd.conf /etc/proftpd/conf.d/
|
||||
apt-get install -qq "$1"
|
||||
;;
|
||||
vsftpd)
|
||||
cp $TRAVIS_BUILD_DIR/.travis/vsftpd.conf /etc/vsftpd.conf
|
||||
apt-get install -qq "$1"
|
||||
;;
|
||||
vsftpd_implicit_tls)
|
||||
openssl req \
|
||||
-new \
|
||||
-newkey rsa:1024 \
|
||||
-days 365 \
|
||||
-nodes \
|
||||
-x509 \
|
||||
-subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=localhost" \
|
||||
-keyout /etc/ssl/certs/vsftpd.pem \
|
||||
-out /etc/ssl/certs/vsftpd.pem
|
||||
cp $TRAVIS_BUILD_DIR/.travis/vsftpd_implicit_tls.conf /etc/vsftpd.conf
|
||||
apt-get install -qq vsftpd
|
||||
;;
|
||||
*)
|
||||
echo "unknown software: $1"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
mkdir --mode 0777 -p /var/ftp/incoming
|
||||
|
||||
apt-get install -qq "$1"
|
||||
|
33
.travis/vsftpd_implicit_tls.conf
Normal file
33
.travis/vsftpd_implicit_tls.conf
Normal file
@ -0,0 +1,33 @@
|
||||
# Used by Travis CI
|
||||
|
||||
listen=NO
|
||||
listen_ipv6=YES
|
||||
|
||||
write_enable=YES
|
||||
dirmessage_enable=YES
|
||||
secure_chroot_dir=/var/run/vsftpd/empty
|
||||
|
||||
anonymous_enable=YES
|
||||
anon_root=/var/ftp
|
||||
anon_upload_enable=YES
|
||||
anon_mkdir_write_enable=YES
|
||||
anon_other_write_enable=YES
|
||||
anon_umask=022
|
||||
|
||||
force_local_logins_ssl=YES
|
||||
force_local_data_ssl=YES
|
||||
ssl_enable=YES
|
||||
implicit_ssl=YES
|
||||
listen_port=21
|
||||
ssl_tlsv1=YES
|
||||
ssl_sslv2=NO
|
||||
ssl_sslv3=NO
|
||||
rsa_cert_file=/etc/ssl/certs/vsftpd.pem
|
||||
rsa_private_key_file=/etc/ssl/certs/vsftpd.pem
|
||||
require_ssl_reuse=NO
|
||||
ssl_ciphers=HIGH
|
||||
xferlog_enable=yes
|
||||
log_ftp_protocol=true
|
||||
xferlog_file=/var/log/vsftpd.log
|
||||
debug_ssl=true
|
||||
allow_anon_ssl=true
|
@ -2,8 +2,10 @@ package ftp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"io/ioutil"
|
||||
"net/textproto"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@ -14,20 +16,39 @@ const (
|
||||
testDir = "mydir"
|
||||
)
|
||||
|
||||
func isTLSServer() bool {
|
||||
return os.Getenv("FTP_SERVER") == "vsftpd_implicit_tls"
|
||||
}
|
||||
|
||||
func getConnection() (*ServerConn, error) {
|
||||
if isTLSServer() {
|
||||
return DialImplicitTLS("localhost:21", &tls.Config{InsecureSkipVerify: true})
|
||||
} else {
|
||||
return DialTimeout("localhost:21", 5*time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConnPASV(t *testing.T) {
|
||||
testConn(t, true)
|
||||
testConn(t, true, false)
|
||||
}
|
||||
|
||||
func TestConnEPSV(t *testing.T) {
|
||||
testConn(t, false)
|
||||
testConn(t, false, false)
|
||||
}
|
||||
|
||||
func testConn(t *testing.T, disableEPSV bool) {
|
||||
func TestConnTLS(t *testing.T) {
|
||||
if !isTLSServer() {
|
||||
t.Skip("skipping test in non TLS server env.")
|
||||
}
|
||||
testConn(t, false, true)
|
||||
}
|
||||
|
||||
func testConn(t *testing.T, disableEPSV bool, implicitTLS bool) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
}
|
||||
c, err := getConnection()
|
||||
|
||||
c, err := DialTimeout("localhost:21", 5*time.Second)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -207,6 +228,9 @@ func TestConnIPv6(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
}
|
||||
if isTLSServer() {
|
||||
t.Skip("skipping test in TLS mode.")
|
||||
}
|
||||
|
||||
c, err := DialTimeout("[::1]:21", 5*time.Second)
|
||||
if err != nil {
|
||||
@ -228,7 +252,7 @@ func TestConnIPv6(t *testing.T) {
|
||||
|
||||
// TestConnect tests the legacy Connect function
|
||||
func TestConnect(t *testing.T) {
|
||||
if testing.Short() {
|
||||
if testing.Short() || isTLSServer() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
}
|
||||
|
||||
@ -244,6 +268,9 @@ func TestTimeout(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
}
|
||||
if isTLSServer() {
|
||||
t.Skip("skipping test in TLS mode.")
|
||||
}
|
||||
|
||||
c, err := DialTimeout("localhost:2121", 1*time.Second)
|
||||
if err == nil {
|
||||
@ -251,13 +278,12 @@ func TestTimeout(t *testing.T) {
|
||||
c.Quit()
|
||||
}
|
||||
}
|
||||
|
||||
func TestWrongLogin(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
}
|
||||
|
||||
c, err := DialTimeout("localhost:21", 5*time.Second)
|
||||
c, err := getConnection()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -273,7 +299,7 @@ func TestDeleteDirRecur(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
}
|
||||
c, err := DialTimeout("localhost:21", 5*time.Second)
|
||||
c, err := getConnection()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -355,7 +381,7 @@ func TestFileDeleteDirRecur(t *testing.T) {
|
||||
t.Skip("skipping test in short mode.")
|
||||
}
|
||||
|
||||
c, err := DialTimeout("localhost:21", 5*time.Second)
|
||||
c, err := getConnection()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -414,7 +440,7 @@ func TestMissingFolderDeleteDirRecur(t *testing.T) {
|
||||
t.Skip("skipping test in short mode.")
|
||||
}
|
||||
|
||||
c, err := DialTimeout("localhost:21", 5*time.Second)
|
||||
c, err := getConnection()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
13
ftp.go
13
ftp.go
@ -5,6 +5,7 @@ package ftp
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
@ -62,6 +63,15 @@ func Dial(addr string) (*ServerConn, error) {
|
||||
return DialTimeout(addr, 0)
|
||||
}
|
||||
|
||||
// Dial a ftps server with implicit TLS
|
||||
func DialImplicitTLS(addr string, config *tls.Config) (*ServerConn, error) {
|
||||
tconn, err := tls.Dial("tcp", addr, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dialServer(tconn, 0)
|
||||
}
|
||||
|
||||
// DialTimeout initializes the connection to the specified ftp server address.
|
||||
//
|
||||
// It is generally followed by a call to Login() as most FTP commands require
|
||||
@ -71,7 +81,10 @@ func DialTimeout(addr string, timeout time.Duration) (*ServerConn, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dialServer(tconn, timeout)
|
||||
}
|
||||
|
||||
func dialServer(tconn net.Conn, timeout time.Duration) (*ServerConn, error) {
|
||||
// Use the resolved IP address in case addr contains a domain name
|
||||
// If we use the domain name, we might not resolve to the same IP.
|
||||
remoteAddr := tconn.RemoteAddr().String()
|
||||
|
Loading…
Reference in New Issue
Block a user