golang mysql 远程_golang 通过ssh代理连接mysql的操作

该博客展示了如何使用Golang通过SSH隧道连接到远程MySQL数据库。首先,它演示了如何建立SSH连接,并注册自定义的`ViaSSHDialer`以通过SSH客户端拨号。然后,使用`sql.Open`和`mysql.RegisterDialContext`注册SSH连接,以实现在Golang中通过SSH代理连接到MySQL。
摘要由CSDN通过智能技术生成

我就废话不多说了,大家还是直接看代码吧~

package main

import (

"bytes"

"context"

"database/sql"

"errors"

"fmt"

"github.com/go-sql-driver/mysql"

"golang.org/x/crypto/ssh"

"io"

"io/ioutil"

"net"

"os"

)

type ViaSSHDialer struct {

client *ssh.Client

_ *context.Context

}

func (self *ViaSSHDialer) Dial(context context.Context,addr string) (net.Conn, error) {

return self.client.Dial("tcp", addr)

}

type remoteScriptType byte

type remoteShellType byte

const (

cmdLine remoteScriptType = iota

rawScript

scriptFile

interactiveShell remoteShellType = iota

nonInteractiveShell

)

type Client struct {

client *ssh.Client

}

func main() {

client, err := DialWithPasswd("ip:port", "user", "password")

if err != nil {

panic(err)

}

out, err := client.Cmd("ls -l").Output()

if err != nil {

panic(err)

}

fmt.Println(string(out))

// Now we register the ViaSSHDialer with the ssh connection as a parameter

mysql.RegisterDialContext("mysql+tcp", (&ViaSSHDialer{client.client,nil}).Dial)

//mysql.RegisterDial("mysql+tcp", (&ViaSSHDialer{client.client}).Dial)

if db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@mysql+tcp(%s)/%s","Aiqitest", "uf6amk146d2aoemi7", "139.196.174.234:3306", "Aiqitest"));

err == nil {

fmt.Printf("Successfully connected to the db\n")

if rows, err := db.Query("SELECT id, name FROM table ORDER BY id"); err == nil {

for rows.Next() {

var id int64

var name string

rows.Scan(&id, &name)

fmt.Printf("ID: %d Name: %s\n", id, name)

}

rows.Close()

} else {

fmt.Printf("Failure: %s", err.Error())

}

db.Close()

}

}

// DialWithPasswd starts a client connection to the given SSH server with passwd authmethod.

func DialWithPasswd(addr, user, passwd string) (*Client, error) {

config := &ssh.ClientConfig{

User: user,

Auth: []ssh.AuthMethod{

ssh.Password(passwd),

},

HostKeyCallback: ssh.HostKeyCallback(func(hostname string, remote net.Addr, key ssh.PublicKey) 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 := ioutil.ReadFile(keyfile)

if err != nil {

return nil, err

}

signer, err := ssh.ParsePrivateKey(key)

if err != nil {

return nil, err

}

config := &ssh.ClientConfig{

User: user,

Auth: []ssh.AuthMethod{

ssh.PublicKeys(signer),

},

HostKeyCallback: ssh.HostKeyCallback(func(hostname string, remote net.Addr, key ssh.PublicKey) 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 := ioutil.ReadFile(keyfile)

if err != nil {

return nil, err

}

signer, err := ssh.ParsePrivateKeyWithPassphrase(key, []byte(passphrase))

if err != nil {

return nil, err

}

config := &ssh.ClientConfig{

User: user,

Auth: []ssh.AuthMethod{

ssh.PublicKeys(signer),

},

HostKeyCallback: ssh.HostKeyCallback(func(hostname string, remote net.Addr, key ssh.PublicKey) error { return nil }),

}

return Dial("tcp", addr, config)

}

// Dial starts a client connection to the given SSH server.

// This is wrap the ssh.Dial

func Dial(network, addr string, config *ssh.ClientConfig) (*Client, error) {

client, err := ssh.Dial(network, addr, config)

if err != nil {

return nil, err

}

return &Client{

client: client,

}, nil

}

func (c *Client) Close() error {

return c.client.Close()

}

// Cmd create a command on client

func (c *Client) Cmd(cmd string) *remoteScript {

return &remoteScript{

_type: cmdLine,

client: c.client,

script: bytes.NewBufferString(cmd + "\n"),

}

}

// Script

func (c *Client) Script(script string) *remoteScript {

return &remoteScript{

_type: rawScript,

client: c.client,

script: bytes.NewBufferString(script + "\n"),

}

}

// ScriptFile

func (c *Client) ScriptFile(fname string) *remoteScript {

return &remoteScript{

_type: scriptFile,

client: c.client,

scriptFile: fname,

}

}

type remoteScript struct {

client *ssh.Client

_type remoteScriptType

script *bytes.Buffer

scriptFile string

err error

stdout io.Writer

stderr io.Writer

}

// Run

func (rs *remoteScript) Run() error {

if rs.err != nil {

fmt.Println(rs.err)

return rs.err

}

if rs._type == cmdLine {

return rs.runCmds()

} else if rs._type == rawScript {

return rs.runScript()

} else if rs._type == scriptFile {

return rs.runScriptFile()

} else {

return errors.New("Not supported remoteScript type")

}

}

func (rs *remoteScript) Output() ([]byte, error) {

if rs.stdout != nil {

return nil, errors.New("Stdout already set")

}

var out bytes.Buffer

rs.stdout = &out

err := rs.Run()

return out.Bytes(), err

}

func (rs *remoteScript) SmartOutput() ([]byte, error) {

if rs.stdout != nil {

return nil, errors.New("Stdout already set")

}

if rs.stderr != nil {

return nil, errors.New("Stderr already set")

}

var (

stdout bytes.Buffer

stderr bytes.Buffer

)

rs.stdout = &stdout

rs.stderr = &stderr

err := rs.Run()

if err != nil {

return stderr.Bytes(), err

}

return stdout.Bytes(), err

}

func (rs *remoteScript) Cmd(cmd string) *remoteScript {

_, err := rs.script.WriteString(cmd + "\n")

if err != nil {

rs.err = err

}

return rs

}

func (rs *remoteScript) SetStdio(stdout, stderr io.Writer) *remoteScript {

rs.stdout = stdout

rs.stderr = stderr

return rs

}

func (rs *remoteScript) runCmd(cmd string) error {

session, err := rs.client.NewSession()

if err != nil {

return err

}

defer session.Close()

session.Stdout = rs.stdout

session.Stderr = rs.stderr

if err := session.Run(cmd); err != nil {

return err

}

return nil

}

func (rs *remoteScript) runCmds() error {

for {

statment, err := rs.script.ReadString('\n')

if err == io.EOF {

break

}

if err != nil {

return err

}

if err := rs.runCmd(statment); err != nil {

return err

}

}

return nil

}

func (rs *remoteScript) runScript() error {

session, err := rs.client.NewSession()

if err != nil {

return err

}

session.Stdin = rs.script

session.Stdout = rs.stdout

session.Stderr = rs.stderr

if err := session.Shell(); err != nil {

return err

}

if err := session.Wait(); err != nil {

return err

}

return nil

}

func (rs *remoteScript) runScriptFile() error {

var buffer bytes.Buffer

file, err := os.Open(rs.scriptFile)

if err != nil {

return err

}

_, err = io.Copy(&buffer, file)

if err != nil {

return err

}

rs.script = &buffer

return rs.runScript()

}

type remoteShell struct {

client *ssh.Client

requestPty bool

terminalConfig *TerminalConfig

stdin io.Reader

stdout io.Writer

stderr io.Writer

}

type TerminalConfig struct {

Term string

Hight int

Weight int

Modes ssh.TerminalModes

}

// Terminal create a interactive shell on client.

func (c *Client) Terminal(config *TerminalConfig) *remoteShell {

return &remoteShell{

client: c.client,

terminalConfig: config,

requestPty: true,

}

}

// Shell create a noninteractive shell on client.

func (c *Client) Shell() *remoteShell {

return &remoteShell{

client: c.client,

requestPty: false,

}

}

func (rs *remoteShell) SetStdio(stdin io.Reader, stdout, stderr io.Writer) *remoteShell {

rs.stdin = stdin

rs.stdout = stdout

rs.stderr = stderr

return rs

}

// Start start a remote shell on client

func (rs *remoteShell) Start() error {

session, err := rs.client.NewSession()

if err != nil {

return err

}

defer session.Close()

if rs.stdin == nil {

session.Stdin = os.Stdin

} else {

session.Stdin = rs.stdin

}

if rs.stdout == nil {

session.Stdout = os.Stdout

} else {

session.Stdout = rs.stdout

}

if rs.stderr == nil {

session.Stderr = os.Stderr

} else {

session.Stderr = rs.stderr

}

if rs.requestPty {

tc := rs.terminalConfig

if tc == nil {

tc = &TerminalConfig{

Term: "xterm",

Hight: 40,

Weight: 80,

}

}

if err := session.RequestPty(tc.Term, tc.Hight, tc.Weight, tc.Modes); err != nil {

return err

}

}

if err := session.Shell(); err != nil {

return err

}

if err := session.Wait(); err != nil {

return err

}

return nil

}

补充:用golang写socks5代理服务器2-ssh远程代理

上次用golang来实现本地socks5代理,然而使用代理当然是为了和谐上网,所以这次来介绍用ssh来实现远程代理,用到官方ssh包

golang.org/x/crypto/ssh

用golang连接ssh并不难

读取密钥,设置配置,连接服务器就ok了(不建议用用户名+密码方式连接ssh)

b, err := ioutil.ReadFile("/home/myml/.ssh/id_rsa")

if err != nil {

log.Println(err)

return

}

pKey, err := ssh.ParsePrivateKey(b)

if err != nil {

log.Println(err)

return

}

config := ssh.ClientConfig{

User: "userName",

Auth: []ssh.AuthMethod{

ssh.PublicKeys(pKey),

},

}

client, err = ssh.Dial("tcp", "Host:22", &config)

if err != nil {

log.Println(err)

return

}

log.Println("连接服务器成功")

defer client.Close()

这样你就得到了一个client,它有个Dial()函数用来创建socket连接,这个是在服务器上创建的,也就可以突破网络限制了,加上上次的sock5代理,把net.Dial改为client.Dial,就能让服务器来代理访问了

server, err := client.Dial("tcp", addr)

if err != nil {

log.Println(err)

return

}

conn.Write([]byte{0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})

go io.Copy(server, conn)

io.Copy(conn, server)

下面是能成功运行并进行远程代理的代码(在Chrome和proxychains测试),ssh服务器和配置信息要修改为自己的

// socks5ProxyProxy project main.go

package main

import (

"bytes"

"encoding/binary"

"fmt"

"io"

"io/ioutil"

"log"

"net"

"golang.org/x/crypto/ssh"

)

func socks5Proxy(conn net.Conn) {

defer conn.Close()

var b [1024]byte

n, err := conn.Read(b[:])

if err != nil {

log.Println(err)

return

}

log.Printf("% x", b[:n])

conn.Write([]byte{0x05, 0x00})

n, err = conn.Read(b[:])

if err != nil {

log.Println(err)

return

}

log.Printf("% x", b[:n])

var addr string

switch b[3] {

case 0x01:

sip := sockIP{}

if err := binary.Read(bytes.NewReader(b[4:n]), binary.BigEndian, &sip); err != nil {

log.Println("请求解析错误")

return

}

addr = sip.toAddr()

case 0x03:

host := string(b[5 : n-2])

var port uint16

err = binary.Read(bytes.NewReader(b[n-2:n]), binary.BigEndian, &port)

if err != nil {

log.Println(err)

return

}

addr = fmt.Sprintf("%s:%d", host, port)

}

server, err := client.Dial("tcp", addr)

if err != nil {

log.Println(err)

return

}

conn.Write([]byte{0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})

go io.Copy(server, conn)

io.Copy(conn, server)

}

type sockIP struct {

A, B, C, D byte

PORT uint16

}

func (ip sockIP) toAddr() string {

return fmt.Sprintf("%d.%d.%d.%d:%d", ip.A, ip.B, ip.C, ip.D, ip.PORT)

}

func socks5ProxyStart() {

log.SetFlags(log.Ltime | log.Lshortfile)

server, err := net.Listen("tcp", ":8080")

if err != nil {

log.Panic(err)

}

defer server.Close()

log.Println("开始接受连接")

for {

client, err := server.Accept()

if err != nil {

log.Println(err)

return

}

log.Println("一个新连接")

go socks5Proxy(client)

}

}

var client *ssh.Client

func main() {

b, err := ioutil.ReadFile("/home/myml/.ssh/id_rsa")

if err != nil {

log.Println(err)

return

}

pKey, err := ssh.ParsePrivateKey(b)

if err != nil {

log.Println(err)

return

}

config := ssh.ClientConfig{

User: "user",

Auth: []ssh.AuthMethod{

ssh.PublicKeys(pKey),

},

}

client, err = ssh.Dial("tcp", "host:22", &config)

if err != nil {

log.Println(err)

return

}

log.Println("连接服务器成功")

defer client.Close()

client.Dial()

socks5ProxyStart()

return

}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。如有错误或未考虑完全的地方,望不吝赐教。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值