194 lines
3.3 KiB
Go
194 lines
3.3 KiB
Go
package ftp
|
|
|
|
import (
|
|
"bufio"
|
|
"crypto/tls"
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.loafle.net/commons_go/logging"
|
|
cnsm "git.loafle.net/commons_go/network_service_matcher"
|
|
)
|
|
|
|
// FTP is a Session for file Transfer Protocol
|
|
type FTPS struct {
|
|
conn net.Conn
|
|
addr string
|
|
tlsconfig *tls.Config
|
|
|
|
reader *bufio.Reader
|
|
writer *bufio.Writer
|
|
|
|
isFtps bool
|
|
}
|
|
|
|
func (fs *FTPS) close() {
|
|
fs.conn.Close()
|
|
}
|
|
|
|
func (fs *FTPS) quit() (err error) {
|
|
if _, err := fs.cmd(statusCloseConnect, "QUIT"); err != nil {
|
|
return err
|
|
}
|
|
fs.conn.Close()
|
|
fs.conn = nil
|
|
return nil
|
|
}
|
|
|
|
func (fs *FTPS) cmd(expects string, cmd string) (line string, err error) {
|
|
if err = fs.send(cmd); err != nil {
|
|
logging.Logger().Error(fmt.Sprintf("Discovery: FTPS Matcher cmd send error %v", err))
|
|
return "", err
|
|
}
|
|
|
|
if line, err = fs.receive(); err != nil {
|
|
logging.Logger().Error(fmt.Sprintf("Discovery: FTPS Matcher cmd receive error %v", err))
|
|
return line, err
|
|
}
|
|
|
|
if !strings.HasPrefix(line, expects) {
|
|
err = errors.New(line)
|
|
return line, err
|
|
}
|
|
|
|
return line, err
|
|
}
|
|
|
|
func (fs *FTPS) readAndDiscard() (int, error) {
|
|
var i int
|
|
bufferSize := fs.reader.Buffered()
|
|
|
|
for i = 0; i < bufferSize; i++ {
|
|
if _, err := fs.reader.ReadByte(); err != nil {
|
|
return i, err
|
|
}
|
|
}
|
|
|
|
return i, nil
|
|
}
|
|
|
|
func (fs *FTPS) receive() (string, error) {
|
|
line, err := fs.reader.ReadString('\n')
|
|
//log.Debug("< %s", line)
|
|
|
|
if err != nil {
|
|
return line, err
|
|
}
|
|
|
|
fs.readAndDiscard()
|
|
//fmt.Println(line)
|
|
return line, err
|
|
}
|
|
|
|
func (fs *FTPS) send(cmd string) (err error) {
|
|
|
|
if len(cmd) == 0 {
|
|
err = errors.New("command length 0")
|
|
}
|
|
|
|
cmd = fmt.Sprintf(cmd)
|
|
cmd += "\r\n"
|
|
|
|
if _, err := fs.writer.WriteString(cmd); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := fs.writer.Flush(); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (fs *FTPS) authTls(config *tls.Config) error {
|
|
if _, err := fs.cmd(statusTlsUseOK, "AUTH TLS"); err != nil {
|
|
return err
|
|
}
|
|
|
|
fs.tlsconfig = config
|
|
|
|
fs.conn = tls.Client(fs.conn, config)
|
|
fs.writer = bufio.NewWriter(fs.conn)
|
|
fs.reader = bufio.NewReader(fs.conn)
|
|
|
|
_, err := fs.cmd(statusOK, "PBSZ 0")
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = fs.cmd(statusOK, "PROT P")
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
func (fs *FTPS) NewFTPSConnect(addr string) (*FTPS, error) {
|
|
var err error
|
|
var conn net.Conn
|
|
|
|
if conn, err = net.Dial("tcp", addr); err != nil {
|
|
logging.Logger().Error(fmt.Sprintf("Discovery: FTPS Matcher Socket Fail %v", err))
|
|
return nil, err
|
|
}
|
|
|
|
err = conn.SetDeadline(time.Now().Add(3 * time.Second))
|
|
if err != nil {
|
|
//log.Error("FTPS Socket Fail: ", err.Error())
|
|
return nil, err
|
|
}
|
|
|
|
writer := bufio.NewWriter(conn)
|
|
reader := bufio.NewReader(conn)
|
|
|
|
var line string
|
|
|
|
obj := &FTPS{
|
|
conn: conn,
|
|
addr: addr,
|
|
reader: reader,
|
|
writer: writer,
|
|
}
|
|
|
|
line, err = obj.receive()
|
|
|
|
if !strings.HasPrefix(line, "220") {
|
|
err = errors.New(line)
|
|
return nil, err
|
|
}
|
|
|
|
//log.Debug(line)
|
|
|
|
return obj, err
|
|
}
|
|
|
|
func StartCheckFTPS(info cnsm.MatchInfo) (bool, error) {
|
|
|
|
var err error
|
|
var fs *FTPS
|
|
|
|
addr := fmt.Sprintf("%s:%d", info.IP(), info.Port())
|
|
//log.Debug("address : " + addr)
|
|
|
|
if fs, err = fs.NewFTPSConnect(addr); err != nil {
|
|
return false, err
|
|
}
|
|
|
|
defer fs.close()
|
|
|
|
config := &tls.Config{
|
|
InsecureSkipVerify: true,
|
|
ClientAuth: tls.RequestClientCert,
|
|
}
|
|
|
|
if err = fs.authTls(config); err != nil {
|
|
return false, err
|
|
}
|
|
|
|
return true, err
|
|
}
|