Skip to content
This repository was archived by the owner on Jul 8, 2020. It is now read-only.

Commit d363a2b

Browse files
committed
Explicit TLS mode is implemented.
Partal implementation of RFC 4217 for controll and data connections
1 parent d28b0f6 commit d363a2b

4 files changed

Lines changed: 80 additions & 23 deletions

File tree

cmd.go

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ var (
4040
"ENC": commandEnc{},
4141
"EPRT": commandEprt{},
4242
"EPSV": commandEpsv{},
43-
//"FEAT": commandFeat{},
43+
"FEAT": commandFeat{},
4444
"LIST": commandList{},
4545
"NLST": commandNlst{},
4646
"MDTM": commandMdtm{},
@@ -175,6 +175,9 @@ func init() {
175175
}
176176

177177
func (cmd commandFeat) Execute(conn *Conn, param string) {
178+
if conn.tlsConfig != nil {
179+
featCmds += " AUTH TLS\n PBSZ\n PROT\n"
180+
}
178181
conn.writeMessage(211, fmt.Sprintf(feats, featCmds))
179182
}
180183

@@ -314,7 +317,7 @@ func (cmd commandEpsv) Execute(conn *Conn, param string) {
314317
return
315318
}
316319

317-
socket, err := newPassiveSocket(addr.String()[:lastIdx], conn.logger)
320+
socket, err := newPassiveSocket(addr.String()[:lastIdx], conn.logger, conn.tlsConfig)
318321
if err != nil {
319322
log.Error(err)
320323
conn.writeMessage(425, "Data connection failed")
@@ -595,7 +598,7 @@ func (cmd commandPasv) Execute(conn *Conn, param string) {
595598
conn.writeMessage(425, "Data connection failed")
596599
return
597600
}
598-
socket, err := newPassiveSocket(parts[0], conn.logger)
601+
socket, err := newPassiveSocket(parts[0], conn.logger, conn.tlsConfig)
599602
if err != nil {
600603
conn.writeMessage(425, "Data connection failed")
601604
return
@@ -853,7 +856,16 @@ func (cmd commandAuth) RequireAuth() bool {
853856
}
854857

855858
func (cmd commandAuth) Execute(conn *Conn, param string) {
856-
conn.writeMessage(550, "Action not taken")
859+
log.Println(param, conn)
860+
if param == "TLS" && conn.tlsConfig != nil {
861+
conn.writeMessage(234, "AUTH command OK")
862+
err := conn.upgradeToTls()
863+
if err != nil {
864+
conn.logger.Printf("Error upgrading conection to TLS %v", err)
865+
}
866+
} else {
867+
conn.writeMessage(550, "Action not taken")
868+
}
857869
}
858870

859871
type commandCcc struct{}
@@ -925,7 +937,11 @@ func (cmd commandPbsz) RequireAuth() bool {
925937
}
926938

927939
func (cmd commandPbsz) Execute(conn *Conn, param string) {
928-
conn.writeMessage(550, "Action not taken")
940+
if conn.tls && param == "0" {
941+
conn.writeMessage(200, "OK")
942+
} else {
943+
conn.writeMessage(550, "Action not taken")
944+
}
929945
}
930946

931947
type commandProt struct{}
@@ -943,7 +959,13 @@ func (cmd commandProt) RequireAuth() bool {
943959
}
944960

945961
func (cmd commandProt) Execute(conn *Conn, param string) {
946-
conn.writeMessage(550, "Action not taken")
962+
if conn.tls && param == "P" {
963+
conn.writeMessage(200, "OK")
964+
} else if conn.tls {
965+
conn.writeMessage(536, "Only P level is supported")
966+
} else {
967+
conn.writeMessage(550, "Action not taken")
968+
}
947969
}
948970

949971
type commandConf struct{}

conn.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bufio"
55
"crypto/rand"
66
"crypto/sha256"
7+
"crypto/tls"
78
"encoding/hex"
89
"fmt"
910
"io"
@@ -26,6 +27,7 @@ type Conn struct {
2627
auth Auth
2728
logger *Logger
2829
server *Server
30+
tlsConfig *tls.Config
2931
sessionId string
3032
namePrefix string
3133
reqUser string
@@ -34,6 +36,7 @@ type Conn struct {
3436
lastFilePos int64
3537
appendData bool
3638
closed bool
39+
tls bool
3740
}
3841

3942
func (conn *Conn) LoginUser() string {
@@ -97,6 +100,19 @@ func (conn *Conn) Close() {
97100
}
98101
}
99102

103+
func (Conn *Conn) upgradeToTls() error {
104+
Conn.logger.Print("Upgrading connectiion to TLS")
105+
tlsConn := tls.Server(Conn.conn, Conn.tlsConfig)
106+
err := tlsConn.Handshake()
107+
if err == nil {
108+
Conn.conn = tlsConn
109+
Conn.controlReader = bufio.NewReader(tlsConn)
110+
Conn.controlWriter = bufio.NewWriter(tlsConn)
111+
Conn.tls = true
112+
}
113+
return err
114+
}
115+
100116
// receiveLine accepts a single line FTP command and co-ordinates an
101117
// appropriate response.
102118
func (Conn *Conn) receiveLine(line string) {

server.go

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ type ServerOpts struct {
4040
// if tls used, key file is required
4141
KeyFile string
4242

43+
// If ture TLS is used in RFC4217 mode
44+
ExplicitFTPS bool
45+
4346
WelcomeMessage string
4447
}
4548

@@ -54,6 +57,7 @@ type Server struct {
5457
driverFactory DriverFactory
5558
logger *Logger
5659
listener net.Listener
60+
tlsConfig *tls.Config
5761
}
5862

5963
// serverOptsWithDefaults copies an ServerOpts struct into a new struct,
@@ -93,6 +97,7 @@ func serverOptsWithDefaults(opts *ServerOpts) *ServerOpts {
9397
newOpts.TLS = opts.TLS
9498
newOpts.KeyFile = opts.KeyFile
9599
newOpts.CertFile = opts.CertFile
100+
newOpts.ExplicitFTPS = opts.ExplicitFTPS
96101

97102
return &newOpts
98103
}
@@ -129,17 +134,18 @@ func NewServer(opts *ServerOpts) *Server {
129134
// an active net.TCPConn. The TCP connection should already be open before
130135
// it is handed to this functions. driver is an instance of FTPDriver that
131136
// will handle all auth and persistence details.
132-
func (server *Server) newConn(tcpConn net.Conn, driver Driver, auth Auth) *Conn {
137+
func (server *Server) newConn(tcpConn net.Conn, driver Driver) *Conn {
133138
c := new(Conn)
134139
c.namePrefix = "/"
135140
c.conn = tcpConn
136141
c.controlReader = bufio.NewReader(tcpConn)
137142
c.controlWriter = bufio.NewWriter(tcpConn)
138143
c.driver = driver
139-
c.auth = auth
144+
c.auth = server.Auth
140145
c.server = server
141146
c.sessionId = newSessionId()
142147
c.logger = newLogger(c.sessionId)
148+
c.tlsConfig = server.tlsConfig
143149
driver.Init(c)
144150
return c
145151
}
@@ -172,13 +178,16 @@ func (Server *Server) ListenAndServe() error {
172178
var err error
173179

174180
if Server.ServerOpts.TLS {
175-
var config *tls.Config
176-
config, err = simpleTLSConfig(Server.CertFile, Server.KeyFile)
181+
Server.tlsConfig, err = simpleTLSConfig(Server.CertFile, Server.KeyFile)
177182
if err != nil {
178183
return err
179184
}
180185

181-
listener, err = tls.Listen("tcp", Server.listenTo, config)
186+
if Server.ServerOpts.ExplicitFTPS {
187+
listener, err = net.Listen("tcp", Server.listenTo)
188+
} else {
189+
listener, err = tls.Listen("tcp", Server.listenTo, Server.tlsConfig)
190+
}
182191
} else {
183192
listener, err = net.Listen("tcp", Server.listenTo)
184193
}
@@ -200,7 +209,7 @@ func (Server *Server) ListenAndServe() error {
200209
Server.logger.Printf("Error creating driver, aborting client connection: %v", err)
201210
tcpConn.Close()
202211
} else {
203-
ftpConn := Server.newConn(tcpConn, driver, Server.Auth)
212+
ftpConn := Server.newConn(tcpConn, driver)
204213
go ftpConn.Serve()
205214
}
206215
}

socket.go

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package server
22

33
import (
4+
"crypto/tls"
45
"errors"
56
"net"
67
"strconv"
@@ -74,16 +75,17 @@ func (socket *ftpActiveSocket) Close() error {
7475
}
7576

7677
type ftpPassiveSocket struct {
77-
conn *net.TCPConn
78-
port int
79-
host string
80-
ingress chan []byte
81-
egress chan []byte
82-
logger *Logger
83-
wg sync.WaitGroup
78+
conn net.Conn
79+
port int
80+
host string
81+
ingress chan []byte
82+
egress chan []byte
83+
logger *Logger
84+
wg sync.WaitGroup
85+
tlsConfing *tls.Config
8486
}
8587

86-
func newPassiveSocket(host string, logger *Logger) (DataSocket, error) {
88+
func newPassiveSocket(host string, logger *Logger, tlsConfing *tls.Config) (DataSocket, error) {
8789
socket := new(ftpPassiveSocket)
8890
socket.ingress = make(chan []byte)
8991
socket.egress = make(chan []byte)
@@ -131,11 +133,14 @@ func (socket *ftpPassiveSocket) GoListenAndServe() (err error) {
131133
socket.logger.Print(err)
132134
return
133135
}
134-
listener, err := net.ListenTCP("tcp", laddr)
136+
137+
var listener net.Listener
138+
listener, err = net.ListenTCP("tcp", laddr)
135139
if err != nil {
136140
socket.logger.Print(err)
137141
return
138142
}
143+
139144
add := listener.Addr()
140145
parts := strings.Split(add.String(), ":")
141146
port, err := strconv.Atoi(parts[len(parts)-1])
@@ -146,14 +151,19 @@ func (socket *ftpPassiveSocket) GoListenAndServe() (err error) {
146151

147152
socket.port = port
148153
socket.wg.Add(1)
154+
155+
if socket.tlsConfing != nil {
156+
listener = tls.NewListener(listener, socket.tlsConfing)
157+
}
158+
149159
go func() {
150-
tcpConn, err := listener.AcceptTCP()
160+
conn, err := listener.Accept()
151161
socket.wg.Done()
152162
if err != nil {
153163
socket.logger.Print(err)
154164
return
155165
}
156-
socket.conn = tcpConn
166+
socket.conn = conn
157167
}()
158168
return nil
159169
}

0 commit comments

Comments
 (0)