Golang实现端口转发,搭隧道

Golang实现端口转发,搭隧道

远航
2022-04-26 / 1 评论 / 720 阅读 / 正在检测是否收录...
背景

 像聚石塔等有些安全性要求较高的服务器,只对外开放了80,443以及22端口,但又想使用宝塔面板进行项目管理和环境搭建工作,申请开放端口又不方便且担心不安全。

准备工作
  1. 安装Golang开发环境: 火箭🚀直达
  2. 学习go mod使用方法: 自行百度
  3. 安装Goland编辑器或者其他文本编辑器(visual studio code)
开始撸代码
package main
// main 万物的起源
func main() {
    
}
准备服务器连接信息
sshAddr := "000.00.000.00:22" // 服务器的 ip:ssh端口
sshUser := "root"             // 用户名,可以新建一个特定用户
sshPasswd := "6666666.66666"  // 密码
Remote := "127.0.0.1:3306"    // 转发到远程的端口,未开放但是你想访问的端口
Listen := "127.0.0.1:3307"    // 需要转发的本地端口,本地访问时使用的端口
连接服务器
serverClient, err := ssh.Dial("tcp", sshAddr, &ssh.ClientConfig{
    User:            sshUser,
    Auth:            []ssh.AuthMethod{ssh.Password(sshPasswd)},
    HostKeyCallback: ssh.InsecureIgnoreHostKey(),
})
if err != nil {
    log.Fatalf("ssh服务器连接异常: %s", err.Error())
}
defer serverClient.Close() // 程序执行完关闭连接,养成好习惯
log.Println("与服务器建立ssh连接成功啦")
监听本地端口
// 监听本地映射端口 这样访问本地端口的时候我就可以发现啦
listener, err := net.Listen("tcp", Listen)
if err != nil {
    log.Fatalf(err.Error())
}
defer listener.Close() // 程序执行完关闭连接,养成好习惯
开始转发数据
// 接收本地发送的数据
conn, err := listener.Accept()
if err != nil { // 养成好习惯处理错误
    log.Println(err)
    return
}
// 通过ssh连接监听远程端口
forwardConn, err := serverClient.Dial("tcp", Remote)
if err != nil { // 养成好习惯处理错误
    log.Fatalln(err.Error())
    return
}
log.Println("ssh端口映射隧道建立成功")
defer forwardConn.Close()     // 用完要关掉
// 转发工作
go io.Copy(forwardConn, conn) // 客户端发送给服务端的数据拷贝给服务端
io.Copy(conn, forwardConn)    // 服务端发送给客户端的数据拷贝给客户端
虽然转发成功了,但是一下就断了,我们改一下
// 加个死循环不断接收然后转发数据
for {
    // 接收本地发送的数据
    conn, err := listener.Accept()
    if err != nil { // 养成好习惯处理错误
        log.Println(err)
        return
    }
    // 通过ssh连接监听远程端口
    forwardConn, err := serverClient.Dial("tcp", Remote)
    if err != nil { // 养成好习惯处理错误
        log.Fatalln(err.Error())
        return
    }
    log.Println("ssh端口映射隧道建立成功")
    defer forwardConn.Close() // 用完要关掉
    // 转发工作
    go io.Copy(forwardConn, conn) // 客户端发送给服务端的数据拷贝给服务端
    io.Copy(conn, forwardConn)    // 服务端发送给客户端的数据拷贝给客户端
}
现在虽然可以一直转发了,但是数据量大其他消息会进入等待
// go的精髓,我们收到数据开启协程去处理然后继续接收就可以啦
for {
    // 接收本地发送的数据
    conn, err := listener.Accept()
    if err != nil { // 养成好习惯处理错误
        log.Println(err)
        return
    }
    // 开启一个协程去处理这次的消息
    go func(conn net.Conn) {
        //建立ssh到后端服务的连接
        forwardConn, err := serverClient.Dial("tcp", Remote)
        if err != nil { // 养成好习惯处理错误
            log.Fatalln(err.Error())
        }
        log.Println("ssh端口映射隧道建立成功")
        defer forwardConn.Close() // 用完要关掉
        // 转发工作
        go io.Copy(forwardConn, conn) // 客户端发送给服务端的数据拷贝给服务端
        io.Copy(conn, forwardConn)    // 服务端发送给客户端的数据拷贝给客户端
    }(conn)
}
这样我们就完成了一个简单的端口转发隧道(完整代码)
package main

import (
    "golang.org/x/crypto/ssh"
    "io"
    "log"
    "net"
)

// main 万物的起源
func main() {
    sshAddr := "000.00.000.00:22" // 服务器的 ip:ssh端口
    sshUser := "root"             // 用户名,可以新建一个特定用户
    sshPasswd := "6666666.66666"  // 密码
    Remote := "127.0.0.1:3306"    // 转发到远程的端口,未开放但是你想访问的端口
    Listen := "127.0.0.1:3307"    // 需要转发的本地端口,本地访问时使用的端口

    serverClient, err := ssh.Dial("tcp", sshAddr, &ssh.ClientConfig{
        User:            sshUser,
        Auth:            []ssh.AuthMethod{ssh.Password(sshPasswd)},
        HostKeyCallback: ssh.InsecureIgnoreHostKey(),
    })
    if err != nil {
        log.Fatalf("ssh服务器连接异常: %s", err.Error())
    }
    defer serverClient.Close() // 程序执行完关闭连接,养成好习惯
    log.Println("与服务器建立ssh连接成功啦")

    // 监听本地映射端口 这样访问本地端口的时候我就可以发现啦
    listener, err := net.Listen("tcp", Listen)
    if err != nil {
        log.Fatalf(err.Error())
    }
    defer listener.Close() // 程序执行完关闭连接,养成好习惯

    for {
        // 接收本地发送的数据
        conn, err := listener.Accept()
        if err != nil { // 养成好习惯处理错误
            log.Println(err)
            return
        }
        // 开启一个协程去处理这次的消息
        go func(conn net.Conn) {
            //建立ssh到后端服务的连接
            forwardConn, err := serverClient.Dial("tcp", Remote)
            if err != nil { // 养成好习惯处理错误
                log.Fatalln(err.Error())
            }
            log.Println("ssh端口映射隧道建立成功")
            defer forwardConn.Close() // 用完要关掉
            // 转发工作
            go io.Copy(forwardConn, conn) // 客户端发送给服务端的数据拷贝给服务端
            io.Copy(conn, forwardConn)    // 服务端发送给客户端的数据拷贝给客户端
        }(conn)
    }
}
运行 go run main.go
使用监听端口连接数据库
host:127.0.0.1
端口:3307
用户名:数据库用户名
密码:数据库密码
连接成功
1

评论 (1)

取消
  1. 头像
    ukjxqkluhj
    Windows 10 · Google Chrome

    真棒!

    回复