├── .gitignore ├── CHANGELOG.md ├── dssh ├── dssh_test.go └── dssh.go ├── go.mod ├── .example.config.yaml ├── LICENSE ├── go.sum ├── main.go └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | .git 3 | .svn 4 | .idea 5 | .vscode 6 | *.log 7 | git.sh 8 | gittag.sh 9 | gitinit.sh 10 | config.yaml -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## v1.0.3 / 2021-06-26 2 | 3 | - 修复扩展包 4 | 5 | ## v1.0.2 / 2021-06-25 6 | 7 | - Golang SSH 隧道 8 | - 增加扩展包方式 -------------------------------------------------------------------------------- /dssh/dssh_test.go: -------------------------------------------------------------------------------- 1 | package dssh 2 | 3 | import "testing" 4 | 5 | func TestName(t *testing.T) { 6 | Tunnel("root", "", ":22", ":3306", "localhost:13306") 7 | } 8 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/dtapps/go-ssh-tunnel 2 | 3 | go 1.16 4 | 5 | require golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e 6 | 7 | require gopkg.in/yaml.v2 v2.4.0 8 | -------------------------------------------------------------------------------- /.example.config.yaml: -------------------------------------------------------------------------------- 1 | # 服务器 2 | username: "root" #服务器用户名 3 | password: "" #服务器密码 4 | serverAddr: "" #服务器地址 5 | serverPort: "22" #服务器端口 6 | remoteAddr: "" #远程地址 7 | remotePort: "3306" #远程端口 8 | # 本地 9 | localAddr: "localhost" #地址 10 | localPort: "13306" #端口 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 李光春 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI= 2 | golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 3 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 4 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 5 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4= 6 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 7 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= 8 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 9 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 10 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 11 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 12 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 13 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 14 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 15 | -------------------------------------------------------------------------------- /dssh/dssh.go: -------------------------------------------------------------------------------- 1 | package dssh 2 | 3 | import ( 4 | "fmt" 5 | "golang.org/x/crypto/ssh" 6 | "io" 7 | "net" 8 | "time" 9 | ) 10 | 11 | // 转发 12 | func sForward(serverAddr string, remoteAddr string, localConn net.Conn, config *ssh.ClientConfig) { 13 | // 设置sshClientConn 14 | sshClientConn, err := ssh.Dial("tcp", serverAddr, config) 15 | if err != nil { 16 | fmt.Printf("ssh.Dial failed: %s", err) 17 | } 18 | 19 | // 设置Connection 20 | sshConn, err := sshClientConn.Dial("tcp", remoteAddr) 21 | 22 | // 将localConn.Reader复制到sshConn.Writer 23 | go func() { 24 | _, err = io.Copy(sshConn, localConn) 25 | if err != nil { 26 | fmt.Printf("io.Copy failed: %v", err) 27 | } 28 | }() 29 | 30 | // 将sshConn.Reader复制到localConn.Writer 31 | go func() { 32 | _, err = io.Copy(localConn, sshConn) 33 | if err != nil { 34 | fmt.Printf("io.Copy failed: %v", err) 35 | } 36 | }() 37 | } 38 | func Tunnel(username string, password string, serverAddr string, remoteAddr string, localAddr string) { 39 | // 设置SSH配置 40 | fmt.Printf("%s,服务器:%s;远程:%s;本地:%s\n", "设置SSH配置", serverAddr, remoteAddr, localAddr) 41 | config := &ssh.ClientConfig{ 42 | User: username, 43 | Auth: []ssh.AuthMethod{ 44 | ssh.Password(password), 45 | }, 46 | Timeout: 30 * time.Second, 47 | HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error { 48 | return nil 49 | }, 50 | } 51 | 52 | // 设置本地监听器 53 | localListener, err := net.Listen("tcp", localAddr) 54 | if err != nil { 55 | fmt.Printf("net.Listen failed: %v\n", err) 56 | } 57 | 58 | for { 59 | // 设置本地 60 | localConn, err := localListener.Accept() 61 | if err != nil { 62 | fmt.Printf("localListener.Accept failed: %v\n", err) 63 | } 64 | go sForward(serverAddr, remoteAddr, localConn, config) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "golang.org/x/crypto/ssh" 6 | "gopkg.in/yaml.v2" 7 | "io" 8 | "io/ioutil" 9 | "log" 10 | "net" 11 | "time" 12 | ) 13 | 14 | // GlobConfig 定义一个 config结构体变量 15 | var GlobConfig Config 16 | 17 | // Config 声明 配置结构体 18 | type Config struct { 19 | Username string `yaml:"username"` 20 | Password string `yaml:"password"` 21 | ServerAddr string `yaml:"serverAddr"` 22 | ServerPort string `yaml:"serverPort"` 23 | RemoteAddr string `yaml:"remoteAddr"` 24 | RemotePort string `yaml:"remotePort"` 25 | LocalAddr string `yaml:"localAddr"` 26 | LocalPort string `yaml:"localPort"` 27 | } 28 | 29 | // 读取配置文件 30 | func (c *Config) getConfig() *Config { 31 | yamlFile, err := ioutil.ReadFile("config.yaml") 32 | if err != nil { 33 | log.Printf("yamlFile.Get err #%v ", err) 34 | } 35 | err = yaml.Unmarshal(yamlFile, c) 36 | if err != nil { 37 | log.Fatalf("Unmarshal: %v", err) 38 | } 39 | return c 40 | } 41 | 42 | // 初始化读取配置 43 | func init() { 44 | // 直接赋值给结构体 45 | GlobConfig.getConfig() 46 | } 47 | 48 | // 转发 49 | func forward(localConn net.Conn, config *ssh.ClientConfig) { 50 | // 设置sshClientConn 51 | sshClientConn, err := ssh.Dial("tcp", fmt.Sprintf("%s:%s", GlobConfig.ServerAddr, GlobConfig.ServerPort), config) 52 | if err != nil { 53 | fmt.Printf("ssh.Dial failed: %s", err) 54 | } 55 | 56 | // 设置Connection 57 | sshConn, err := sshClientConn.Dial("tcp", fmt.Sprintf("%s:%s", GlobConfig.RemoteAddr, GlobConfig.RemotePort)) 58 | 59 | // 将localConn.Reader复制到sshConn.Writer 60 | go func() { 61 | _, err = io.Copy(sshConn, localConn) 62 | if err != nil { 63 | fmt.Printf("io.Copy failed: %v", err) 64 | } 65 | }() 66 | 67 | // 将sshConn.Reader复制到localConn.Writer 68 | go func() { 69 | _, err = io.Copy(localConn, sshConn) 70 | if err != nil { 71 | fmt.Printf("io.Copy failed: %v", err) 72 | } 73 | }() 74 | } 75 | 76 | func main() { 77 | // 设置SSH配置 78 | fmt.Printf("%s,服务器:%s:%s;远程:%s:%s;本地:%s:%s\n", "设置SSH配置", GlobConfig.ServerAddr, GlobConfig.ServerPort, GlobConfig.RemoteAddr, GlobConfig.RemotePort, GlobConfig.LocalAddr, GlobConfig.LocalPort) 79 | config := &ssh.ClientConfig{ 80 | User: GlobConfig.Username, 81 | Auth: []ssh.AuthMethod{ 82 | ssh.Password(GlobConfig.Password), 83 | }, 84 | Timeout: 30 * time.Second, 85 | HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error { 86 | return nil 87 | }, 88 | } 89 | 90 | // 设置本地监听器 91 | localListener, err := net.Listen("tcp", fmt.Sprintf("%s:%s", GlobConfig.LocalAddr, GlobConfig.LocalPort)) 92 | if err != nil { 93 | fmt.Printf("net.Listen failed: %v\n", err) 94 | } 95 | 96 | for { 97 | // 设置本地 98 | localConn, err := localListener.Accept() 99 | if err != nil { 100 | fmt.Printf("localListener.Accept failed: %v\n", err) 101 | } 102 | go forward(localConn, config) 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | https://www.dtapp.net/ 2 | 3 |

Golang SSH Tunnel

4 | 5 | 📦 Golang SSH 隧道 6 | 7 | [comment]: <> (dtapps) 8 | [![GitHub Org's stars](https://img.shields.io/github/stars/dtapps)](https://github.com/dtapps) 9 | 10 | [comment]: <> (go) 11 | [![godoc](https://pkg.go.dev/badge/github.com/dtapps/go-ssh-tunnel?status.svg)](https://pkg.go.dev/github.com/dtapps/go-ssh-tunnel) 12 | [![oproxy.cn](https://goproxy.cn/stats/github.com/dtapps/go-ssh-tunnel/badges/download-count.svg)](https://goproxy.cn/stats/github.com/dtapps/go-ssh-tunnel) 13 | [![goreportcard.com](https://goreportcard.com/badge/github.com/dtapps/go-ssh-tunnel)](https://goreportcard.com/report/github.com/dtapps/go-ssh-tunnel) 14 | [![deps.dev](https://img.shields.io/badge/deps-go-red.svg)](https://deps.dev/go/github.com%2Fdtapps%2Fgo-ssh-tunnel) 15 | 16 | [comment]: <> (github.com) 17 | [![watchers](https://badgen.net/github/watchers/dtapps/go-ssh-tunnel)](https://github.com/dtapps/go-ssh-tunnel/watchers) 18 | [![stars](https://badgen.net/github/stars/dtapps/go-ssh-tunnel)](https://github.com/dtapps/go-ssh-tunnel/stargazers) 19 | [![forks](https://badgen.net/github/forks/dtapps/go-ssh-tunnel)](https://github.com/dtapps/go-ssh-tunnel/network/members) 20 | [![issues](https://badgen.net/github/issues/dtapps/go-ssh-tunnel)](https://github.com/dtapps/go-ssh-tunnel/issues) 21 | [![branches](https://badgen.net/github/branches/dtapps/go-ssh-tunnel)](https://github.com/dtapps/go-ssh-tunnel/branches) 22 | [![releases](https://badgen.net/github/releases/dtapps/go-ssh-tunnel)](https://github.com/dtapps/go-ssh-tunnel/releases) 23 | [![tags](https://badgen.net/github/tags/dtapps/go-ssh-tunnel)](https://github.com/dtapps/go-ssh-tunnel/tags) 24 | [![license](https://badgen.net/github/license/dtapps/go-ssh-tunnel)](https://github.com/dtapps/go-ssh-tunnel/blob/master/LICENSE) 25 | [![GitHub go.mod Go version (subdirectory of monorepo)](https://img.shields.io/github/go-mod/go-version/dtapps/go-ssh-tunnel)](https://github.com/dtapps/go-ssh-tunnel) 26 | [![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/dtapps/go-ssh-tunnel)](https://github.com/dtapps/go-ssh-tunnel/releases) 27 | [![GitHub tag (latest SemVer)](https://img.shields.io/github/v/tag/dtapps/go-ssh-tunnel)](https://github.com/dtapps/go-ssh-tunnel/tags) 28 | [![GitHub pull requests](https://img.shields.io/github/issues-pr/dtapps/go-ssh-tunnel)](https://github.com/dtapps/go-ssh-tunnel/pulls) 29 | [![GitHub issues](https://img.shields.io/github/issues/dtapps/go-ssh-tunnel)](https://github.com/dtapps/go-ssh-tunnel/issues) 30 | [![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/dtapps/go-ssh-tunnel)](https://github.com/dtapps/go-ssh-tunnel) 31 | [![GitHub language count](https://img.shields.io/github/languages/count/dtapps/go-ssh-tunnel)](https://github.com/dtapps/go-ssh-tunnel) 32 | [![GitHub search hit counter](https://img.shields.io/github/search/dtapps/go-ssh-tunnel/go)](https://github.com/dtapps/go-ssh-tunnel) 33 | [![GitHub top language](https://img.shields.io/github/languages/top/dtapps/go-ssh-tunnel)](https://github.com/dtapps/go-ssh-tunnel) 34 | 35 | ## 下载使用 36 | 37 | - 把.example.config.yaml文件重命名为config.yaml 38 | - 修改对应的配置,运行即可 39 | 40 | ## 安装 41 | 42 | ```go 43 | go get -u github.com/dtapps/dtapps/go-ssh-tunnel 44 | ``` 45 | 46 | ```go 47 | package main 48 | 49 | import ( 50 | "github.com/dtapps/go-ssh-tunnel/dssh" 51 | ) 52 | 53 | func main() { 54 | dssh.Tunnel("root", "", ":22", ":3306", "localhost:13306") 55 | } 56 | ``` --------------------------------------------------------------------------------