宝塔用Go实现内网穿透

1.安装Go语言环境
2.目录结构

/www/wwwroot/根目录/
├── constant/
│   └── constant.go
├── helper/
│   └── helper.go
├── go.mod
└── main.go

PS: go.mod是生成的

根目录执行命令:go mod init 根目录
生成go.mod

手动按照目录创建go文件。

main.go代码(自己替换根目录):

package main

import (
    "io"
    "log"
    "net"
    "根目录/constant"
    "根目录/helper"
)

var serverConn *net.TCPConn
var appConn *net.TCPConn

func main() {
    go serverListen()
    go appListen()
    go tunnelListen()

    select {}
}

func serverListen() {
    tcpListener, err := helper.CreateListen("0.0.0.0" + constant.ServerPort)
    if err != nil {
        panic(err)
    }
    log.Printf("服务端监听地址为:%s\n", tcpListener.Addr().String())

    for {
        serverConn, err = tcpListener.AcceptTCP()
        if err != nil {
            log.Printf("接收连接失败,错误信息为:%s\n", err.Error())
            return
        }
        go helper.KeepAlive(serverConn)
    }
}

func tunnelListen() {
    tcpListener, err := helper.CreateListen("0.0.0.0" + constant.TunnelPort)
    if err != nil {
        panic(err)
    }
    log.Printf("隧道监听地址为:%s\n", tcpListener.Addr().String())
    for {
        tunnelConn, err := tcpListener.AcceptTCP()
        if err != nil {
            log.Printf("接收连接失败,错误信息为:%s\n", err.Error())
            return
        }
        go io.Copy(appConn, tunnelConn)
        go io.Copy(tunnelConn, appConn)
    }
}

func appListen() {
    tcpListener, err := helper.CreateListen(constant.AppTargetPort)
    if err != nil {
        panic(err)
    }
    log.Printf("应用目的服务端监端口地址为:%s\n", tcpListener.Addr().String())

    for {
        appConn, err = tcpListener.AcceptTCP()
        if err != nil {
            log.Printf("接收连接失败,错误信息为:%s\n", err.Error())
            return
        }
        _, err = serverConn.Write([]byte("New Connection"))
        if err != nil {
            log.Printf("发送消息失败,错误信息为:%s\n", err.Error())
        }
    }
}

helper/helper.go代码:

package helper

import (
    "log"
    "net"
    "time"
)

func CreateListen(listenAddr string) (*net.TCPListener, error) {
    tcpAddr, err := net.ResolveTCPAddr("tcp", listenAddr)
    if err != nil {
        return nil, err
    }
    tcpListener, err := net.ListenTCP("tcp", tcpAddr)
    return tcpListener, err
}

func CreateConnect(connectAddr string) (*net.TCPConn, error) {
    tcpAddr, err := net.ResolveTCPAddr("tcp", connectAddr)
    if err != nil {
        return nil, err
    }
    tcpConn, err := net.DialTCP("tcp", nil, tcpAddr)
    return tcpConn, err
}

func KeepAlive(conn *net.TCPConn) {
    for {
        _, err := conn.Write([]byte("KeepAlive"))
        if err != nil {
            log.Printf("[KeepAlive] Error %s", err)
            return
        }
        time.Sleep(time.Second * 30)
    }
}

func GetDataFromConnection(bufSize int, conn *net.TCPConn) ([]byte, error) {
    b := make([]byte, 0)
    for {
        data := make([]byte, bufSize)
        n, err := conn.Read(data)
        if err != nil {
            return nil, err
        }
        b = append(b, data[:n]...)
        if n < bufSize {
            break
        }
    }
    return b, nil
}

constant/constant.go代码:

package constant

const (
    AppPort = ":8080" //本地端口
    ServerPort = ":8081"
    TunnelPort = ":8082"
    AppTargetPort = ":8083"
    ServerIP = "YOUR_SERVER_IP"
    ServerAddr = ServerIP + ServerPort
    TunnelAddr = ServerIP + TunnelPort
    BufSize = 1024
)

执行编译代码命令:`go build -o server
`
会生成一个server文件,然后执行它即可

客户端一样