golang 通过ssh代理连接mysql的操作
来源:脚本之家
2022-12-23 16:40:33
0浏览
收藏
怎么入门Golang编程?需要学习哪些知识点?这是新手们刚接触编程时常见的问题;下面golang学习网就来给大家整理分享一些知识点,希望能够给初学者一些帮助。本篇文章就来介绍《golang 通过ssh代理连接mysql的操作》,涉及到MySQL、ssh,有需要的可以收藏一下
我就废话不多说了,大家还是直接看代码吧~
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 }
以上为个人经验,希望能给大家一个参考,也希望大家多多支持golang学习网。如有错误或未考虑完全的地方,望不吝赐教。
终于介绍完啦!小伙伴们,这篇关于《golang 通过ssh代理连接mysql的操作》的介绍应该让你收获多多了吧!欢迎大家收藏或分享给更多需要学习的朋友吧~golang学习网公众号也会发布Golang相关知识,快来关注吧!
版本声明
本文转载于:脚本之家 如有侵犯,请联系study_golang@163.com删除

- 上一篇
- Golang 实现Thrift客户端连接池方式

- 下一篇
- 浅谈golang结构体偷懒初始化
评论列表
-
- 无情的白猫
- 这篇技术贴真是及时雨啊,好细啊,赞 👍👍,mark,关注作者大大了!希望作者大大能多写Golang相关的文章。
- 2023-01-04 07:19:57
-
- 兴奋的小笼包
- 这篇文章内容太及时了,好细啊,太给力了,已收藏,关注博主了!希望博主能多写Golang相关的文章。
- 2023-01-02 22:41:04
查看更多
最新文章
-
- Golang · Go教程 | 5小时前 |
- Go语言time包定时任务易错点深度解析
- 324浏览 收藏
-
- Golang · Go教程 | 11小时前 |
- Debian中处理Strings编码问题的技巧
- 381浏览 收藏
-
- Golang · Go教程 | 22小时前 |
- Debian备份与恢复操作攻略
- 486浏览 收藏
-
- Golang · Go教程 | 1天前 |
- Tigervnc在Debian上是否与防火墙有冲突
- 276浏览 收藏
-
- Golang · Go教程 | 1天前 |
- Debian上Kubernetes性能优化秘籍
- 419浏览 收藏
-
- Golang · Go教程 | 1天前 |
- Golang在Debian上的安全配置攻略
- 201浏览 收藏
-
- Golang · Go教程 | 1天前 |
- Go语言高并发优化攻略,突破性能瓶颈
- 208浏览 收藏
-
- Golang · Go教程 | 1天前 |
- Go语言切片与数组易混淆问题深度解析
- 102浏览 收藏
-
- Golang · Go教程 | 1天前 | log ZAP 异步日志 lumberjack 日志轮转
- Go语言高效日志记录与管理秘籍
- 362浏览 收藏
-
- Golang · Go教程 | 1天前 |
- Filebeat在Debian上的安装配置攻略
- 271浏览 收藏
查看更多
课程推荐
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 508次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 484次学习
查看更多
AI推荐
-
- PPTFake答辩PPT生成器
- PPTFake答辩PPT生成器,专为答辩准备设计,极致高效生成PPT与自述稿。智能解析内容,提供多样模板,数据可视化,贴心配套服务,灵活自主编辑,降低制作门槛,适用于各类答辩场景。
- 12次使用
-
- Lovart
- SEO摘要探索Lovart AI,这款专注于设计领域的AI智能体,通过多模态模型集成和智能任务拆解,实现全链路设计自动化。无论是品牌全案设计、广告与视频制作,还是文创内容创作,Lovart AI都能满足您的需求,提升设计效率,降低成本。
- 12次使用
-
- 美图AI抠图
- 美图AI抠图,依托CVPR 2024竞赛亚军技术,提供顶尖的图像处理解决方案。适用于证件照、商品、毛发等多场景,支持批量处理,3秒出图,零PS基础也能轻松操作,满足个人与商业需求。
- 26次使用
-
- PetGPT
- SEO摘要PetGPT 是一款基于 Python 和 PyQt 开发的智能桌面宠物程序,集成了 OpenAI 的 GPT 模型,提供上下文感知对话和主动聊天功能。用户可高度自定义宠物的外观和行为,支持插件热更新和二次开发。适用于需要陪伴和效率辅助的办公族、学生及 AI 技术爱好者。
- 25次使用
-
- 可图AI图片生成
- 探索快手旗下可灵AI2.0发布的可图AI2.0图像生成大模型,体验从文本生成图像、图像编辑到风格转绘的全链路创作。了解其技术突破、功能创新及在广告、影视、非遗等领域的应用,领先于Midjourney、DALL-E等竞品。
- 52次使用
查看更多
相关文章
-
- golang MySQL实现对数据库表存储获取操作示例
- 2022-12-22 499浏览
-
- 搞一个自娱自乐的博客(二) 架构搭建
- 2023-02-16 244浏览
-
- B-Tree、B+Tree以及B-link Tree
- 2023-01-19 235浏览
-
- mysql面试题
- 2023-01-17 157浏览
-
- MySQL数据表简单查询
- 2023-01-10 101浏览