overflow_discovery/service/matcher/ftp/ftps.go
crusader 3dd6cb79ca ing
2017-11-21 21:47:55 +09:00

194 lines
3.4 KiB
Go

package ftp
import (
"bufio"
"crypto/tls"
"errors"
"fmt"
"net"
"strings"
"time"
"git.loafle.net/commons_go/logging"
"git.loafle.net/overflow/overflow_discovery/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 matcher.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
}