Created
July 4, 2023 04:01
-
-
Save YOwatari/f3373b385905796239e16aea0fd4b6a6 to your computer and use it in GitHub Desktop.
Go Uses FTPS (require_ssl_reuse=YES)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"crypto/tls" | |
"fmt" | |
"io" | |
"log" | |
"net" | |
"net/textproto" | |
"strconv" | |
"strings" | |
) | |
const ( | |
host = "127.0.0.1" | |
port = 21000 | |
user = "user" | |
pass = "password" | |
) | |
// reuse session | |
type cache struct { | |
session *tls.ClientSessionState | |
} | |
func (c *cache) Get(_ string) (*tls.ClientSessionState, bool) { | |
return c.session, c.session != nil | |
} | |
func (c *cache) Put(_ string, cs *tls.ClientSessionState) { | |
c.session = cs | |
} | |
var ( | |
tlsConfig = &tls.Config{ | |
InsecureSkipVerify: true, | |
ClientSessionCache: &cache{}, | |
} | |
) | |
func main() { | |
if err := run(); err != nil { | |
panic(err) | |
} | |
} | |
func run() error { | |
conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", host, port)) | |
if err != nil { | |
return err | |
} | |
defer conn.Close() | |
tp := textproto.NewConn(conn) | |
if _, err := response(tp, 220); err != nil { | |
return err | |
} | |
if _, err := request(tp, "AUTH TLS", 234); err != nil { | |
return err | |
} | |
tlsConn := tls.Client(conn, tlsConfig) | |
tlsTp := textproto.NewConn(tlsConn) | |
if _, err := request(tlsTp, fmt.Sprintf("USER %s", user), 331); err != nil { | |
return err | |
} | |
if _, err := request(tlsTp, fmt.Sprintf("PASS %s", pass), 230); err != nil { | |
return err | |
} | |
if _, err := request(tlsTp, "FEAT", 211); err != nil { | |
return err | |
} | |
if _, err := request(tlsTp, "TYPE I", 200); err != nil { | |
return err | |
} | |
if _, err := request(tlsTp, "OPTS UTF8 ON", 200); err != nil { | |
return err | |
} | |
if _, err := request(tlsTp, "PBSZ 0", 200); err != nil { | |
return err | |
} | |
if _, err := request(tlsTp, "PROT P", 200); err != nil { | |
return err | |
} | |
b, err := responseData(tlsTp, "LIST", 150) | |
if err != nil { | |
return err | |
} | |
log.Print(string(b)) | |
if _, err := request(tlsTp, "QUIT", 221); err != nil { | |
return err | |
} | |
return nil | |
} | |
func request(tp *textproto.Conn, cmd string, expectCode int) (string, error) { | |
log.Printf("%s", cmd) | |
id, err := tp.Cmd(cmd) | |
if err != nil { | |
return "", err | |
} | |
tp.StartResponse(id) | |
defer tp.EndResponse(id) | |
return response(tp, expectCode) | |
} | |
func response(tp *textproto.Conn, expectCode int) (string, error) { | |
code, message, err := tp.ReadResponse(expectCode) | |
if err != nil { | |
return "", err | |
} | |
log.Printf("%d %s", code, message) | |
return message, nil | |
} | |
func requestData(tp *textproto.Conn, cmd string, expectCode int) ([]byte, error) { | |
p, err := dataPort(tp) | |
if err != nil { | |
return nil, err | |
} | |
conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", host, p)) | |
if err != nil { | |
return nil, err | |
} | |
defer conn.Close() | |
tlsConn := tls.Client(conn, tlsConfig) | |
if _, err := request(tp, cmd, expectCode); err != nil { | |
return nil, err | |
} | |
b, err := io.ReadAll(tlsConn) | |
if err != nil { | |
return nil, err | |
} | |
return b, nil | |
} | |
func responseData(tp *textproto.Conn, cmd string, expectCode int) ([]byte, error) { | |
b, err := requestData(tp, cmd, expectCode) | |
if err != nil { | |
return nil, err | |
} | |
if _, err := response(tp, 226); err != nil { | |
return nil, err | |
} | |
return b, nil | |
} | |
func dataPort(tp *textproto.Conn) (int, error) { | |
msg, err := request(tp, "EPSV", 229) | |
if err != nil { | |
return 0, err | |
} | |
start := strings.Index(msg, "(") | |
end := strings.Index(msg, ")") | |
data := msg[start+1 : end] | |
fields := strings.Split(data, "|") | |
return strconv.Atoi(fields[3]) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment