I won't say much nonsense, let's just read the code~
package main import ( "bytes" "context" "database/sql" "errors" "fmt" "/go-sql-driver/mysql" "/x/crypto/ssh" "io" "io/ioutil" "net" "os" ) type ViaSSHDialer struct { client * _ * } func (self *ViaSSHDialer) Dial(context ,addr string) (, error) { return ("tcp", addr) } type remoteScriptType byte type remoteShellType byte const ( cmdLine remoteScriptType = iota rawScript scriptFile interactiveShell remoteShellType = iota nonInteractiveShell ) type Client struct { client * } func main() { client, err := DialWithPasswd("ip:port", "user", "password") if err != nil { panic(err) } out, err := ("ls -l").Output() if err != nil { panic(err) } (string(out)) // Now we register the ViaSSHDialer with the ssh connection as a parameter ("mysql+tcp", (&ViaSSHDialer{,nil}).Dial) //("mysql+tcp", (&ViaSSHDialer{}).Dial) if db, err := ("mysql", ("%s:%s@mysql+tcp(%s)/%s","Aiqitest", "uf6amk146d2aoemi7", "139.196.174.234:3306", "Aiqitest")); err == nil { ("Successfully connected to the db\n") if rows, err := ("SELECT id, name FROM table ORDER BY id"); err == nil { for () { var id int64 var name string (&id, &name) ("ID: %d Name: %s\n", id, name) } () } else { ("Failure: %s", ()) } () } } // DialWithPasswd starts a client connection to the given SSH server with passwd authmethod. func DialWithPasswd(addr, user, passwd string) (*Client, error) { config := &{ User: user, Auth: []{ (passwd), }, HostKeyCallback: (func(hostname string, remote , key ) error { return nil }), } return Dial("tcp", addr, config) } // DialWithKey starts a client connection to the given SSH server with key authmethod. func DialWithKey(addr, user, keyfile string) (*Client, error) { key, err := (keyfile) if err != nil { return nil, err } signer, err := (key) if err != nil { return nil, err } config := &{ User: user, Auth: []{ (signer), }, HostKeyCallback: (func(hostname string, remote , key ) error { return nil }), } return Dial("tcp", addr, config) } // DialWithKeyWithPassphrase same as DialWithKey but with a passphrase to decrypt the private key func DialWithKeyWithPassphrase(addr, user, keyfile string, passphrase string) (*Client, error) { key, err := (keyfile) if err != nil { return nil, err } signer, err := (key, []byte(passphrase)) if err != nil { return nil, err } config := &{ User: user, Auth: []{ (signer), }, HostKeyCallback: (func(hostname string, remote , key ) error { return nil }), } return Dial("tcp", addr, config) } // Dial starts a client connection to the given SSH server. // This is wrap the func Dial(network, addr string, config *) (*Client, error) { client, err := (network, addr, config) if err != nil { return nil, err } return &Client{ client: client, }, nil } func (c *Client) Close() error { return () } // Cmd create a command on client func (c *Client) Cmd(cmd string) *remoteScript { return &remoteScript{ _type: cmdLine, client: , script: (cmd + "\n"), } } // Script func (c *Client) Script(script string) *remoteScript { return &remoteScript{ _type: rawScript, client: , script: (script + "\n"), } } // ScriptFile func (c *Client) ScriptFile(fname string) *remoteScript { return &remoteScript{ _type: scriptFile, client: , scriptFile: fname, } } type remoteScript struct { client * _type remoteScriptType script * scriptFile string err error stdout stderr } // Run func (rs *remoteScript) Run() error { if != nil { () return } if rs._type == cmdLine { return () } else if rs._type == rawScript { return () } else if rs._type == scriptFile { return () } else { return ("Not supported remoteScript type") } } func (rs *remoteScript) Output() ([]byte, error) { if != nil { return nil, ("Stdout already set") } var out = &out err := () return (), err } func (rs *remoteScript) SmartOutput() ([]byte, error) { if != nil { return nil, ("Stdout already set") } if != nil { return nil, ("Stderr already set") } var ( stdout stderr ) = &stdout = &stderr err := () if err != nil { return (), err } return (), err } func (rs *remoteScript) Cmd(cmd string) *remoteScript { _, err := (cmd + "\n") if err != nil { = err } return rs } func (rs *remoteScript) SetStdio(stdout, stderr ) *remoteScript { = stdout = stderr return rs } func (rs *remoteScript) runCmd(cmd string) error { session, err := () if err != nil { return err } defer () = = if err := (cmd); err != nil { return err } return nil } func (rs *remoteScript) runCmds() error { for { statment, err := ('\n') if err == { break } if err != nil { return err } if err := (statment); err != nil { return err } } return nil } func (rs *remoteScript) runScript() error { session, err := () if err != nil { return err } = = = if err := (); err != nil { return err } if err := (); err != nil { return err } return nil } func (rs *remoteScript) runScriptFile() error { var buffer file, err := () if err != nil { return err } _, err = (&buffer, file) if err != nil { return err } = &buffer return () } type remoteShell struct { client * requestPty bool terminalConfig *TerminalConfig stdin stdout stderr } type TerminalConfig struct { Term string Hight int Weight int Modes } // Terminal create a interactive shell on client. func (c *Client) Terminal(config *TerminalConfig) *remoteShell { return &remoteShell{ client: , terminalConfig: config, requestPty: true, } } // Shell create a noninteractive shell on client. func (c *Client) Shell() *remoteShell { return &remoteShell{ client: , requestPty: false, } } func (rs *remoteShell) SetStdio(stdin , stdout, stderr ) *remoteShell { = stdin = stdout = stderr return rs } // Start start a remote shell on client func (rs *remoteShell) Start() error { session, err := () if err != nil { return err } defer () if == nil { = } else { = } if == nil { = } else { = } if == nil { = } else { = } if { tc := if tc == nil { tc = &TerminalConfig{ Term: "xterm", Hight: 40, Weight: 80, } } if err := (, , , ); err != nil { return err } } if err := (); err != nil { return err } if err := (); err != nil { return err } return nil }
Supplement: Use golang to write socks5 proxy server 2-ssh remote proxy
Last time I used golang to implement the local socks5 proxy, but using the proxy is of course for harmonious Internet access, so this time I will introduce the use of ssh to implement the remote proxy, using the official ssh package
/x/crypto/ssh
It's not difficult to connect to ssh with golang
Read the key, set the configuration, and connect to the server is OK (it is not recommended to connect to ssh with username + password)
b, err := ("/home/myml/.ssh/id_rsa") if err != nil { (err) return } pKey, err := (b) if err != nil { (err) return } config := { User: "userName", Auth: []{ (pKey), }, } client, err = ("tcp", "Host:22", &config) if err != nil { (err) return } ("Connecting to the server successfully") defer ()
In this way, you get a client, which has a Dial() function to create socket connections. This is created on the server, which can break through network restrictions. Add to the last sock5 proxy, change it to, and the server can access it with the proxy.
server, err := ("tcp", addr) if err != nil { (err) return } ([]byte{0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) go (server, conn) (conn, server)
Below is the code that can successfully run and perform remote proxy (test in Chrome and proxychains). The ssh server and configuration information must be modified to your own.
// socks5ProxyProxy project package main import ( "bytes" "encoding/binary" "fmt" "io" "io/ioutil" "log" "net" "/x/crypto/ssh" ) func socks5Proxy(conn ) { defer () var b [1024]byte n, err := (b[:]) if err != nil { (err) return } ("% x", b[:n]) ([]byte{0x05, 0x00}) n, err = (b[:]) if err != nil { (err) return } ("% x", b[:n]) var addr string switch b[3] { case 0x01: sip := sockIP{} if err := ((b[4:n]), , &sip); err != nil { ("Request parsing error") return } addr = () case 0x03: host := string(b[5 : n-2]) var port uint16 err = ((b[n-2:n]), , &port) if err != nil { (err) return } addr = ("%s:%d", host, port) } server, err := ("tcp", addr) if err != nil { (err) return } ([]byte{0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) go (server, conn) (conn, server) } type sockIP struct { A, B, C, D byte PORT uint16 } func (ip sockIP) toAddr() string { return ("%d.%d.%d.%d:%d", , , , , ) } func socks5ProxyStart() { ( | ) server, err := ("tcp", ":8080") if err != nil { (err) } defer () ("Start accept connections") for { client, err := () if err != nil { (err) return } ("A new connection") go socks5Proxy(client) } } var client * func main() { b, err := ("/home/myml/.ssh/id_rsa") if err != nil { (err) return } pKey, err := (b) if err != nil { (err) return } config := { User: "user", Auth: []{ (pKey), }, } client, err = ("tcp", "host:22", &config) if err != nil { (err) return } ("Connecting to the server successfully") defer () () socks5ProxyStart() return }
The above is personal experience. I hope you can give you a reference and I hope you can support me more. If there are any mistakes or no complete considerations, I would like to give you advice.