印度包网
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

175 lines
3.8 KiB

package tunnel
import (
"context"
"fmt"
"github.com/go-redis/redis/v8"
"golang.org/x/crypto/ssh"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"io"
"log"
"net"
"sync/atomic"
"time"
)
/*
notice: 利用隧道代理实现本地连接服务器程序
*/
var (
// ssh配置
sshPem = `` // todo 私钥填充
sshHost = "47.106.150.32"
sshPort = 22
sshUser = "root"
sshPass = "cH6YIEPCCrFsTNJ4"
// mysql配置
mysqlHost = "127.0.0.1"
mysqlPort = 3306
mysqlUser = "root"
mysqlPass = "pFlu4oNgTKhMdttQ"
mysqlDB = "c_game"
// redis配置
redisHost = "127.0.0.1"
redisPort = 6379
redisPass = "cYUTZma6wEzrdvDJ"
redisDB = 1
// 本地转发端口
LocalPort int32 = 1000 // 从1000开始尝试20次
)
// 转发数据
func forward(local, remote net.Conn) {
defer local.Close()
defer remote.Close()
done := make(chan struct{})
go func() {
_, _ = io.Copy(local, remote)
done <- struct{}{}
}()
go func() {
_, _ = io.Copy(remote, local)
done <- struct{}{}
}()
<-done
}
func getListener() (net.Listener, int32) {
var (
listener net.Listener
err error
port int32
tryCount int32 = 100
)
for index := int32(0); index < tryCount; index++ {
port = atomic.AddInt32(&LocalPort, 1)
address := fmt.Sprintf("localhost:%d", port)
listener, err = net.Listen("tcp", address)
if err == nil && listener != nil {
break
}
log.Printf("[WARN]: listen %s, listener[%+v] err[%+v]", address, listener, err)
}
if listener == nil && err != nil {
log.Fatalf("listener err, tryCount[%d] ", tryCount)
}
return listener, port
}
func getSshConfig() (cfg *ssh.ClientConfig) {
cfg = &ssh.ClientConfig{
User: sshUser,
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
Timeout: 10 * time.Second,
}
if sshPem != "" {
signer, err := ssh.ParsePrivateKey([]byte(sshPem))
if err != nil {
log.Fatalf("Failed to parse private key: %s", err.Error())
}
cfg.Auth = append(cfg.Auth, ssh.PublicKeys(signer))
}
if sshPass != "" {
cfg.Auth = append(cfg.Auth, ssh.Password(sshPass))
}
return cfg
}
func binding(listener net.Listener, sshClient *ssh.Client, processHost string, processPort int) {
for {
localConn, err := listener.Accept()
if err != nil {
log.Printf("Failed to accept connection: %v", err)
return
}
remoteConn, err := sshClient.Dial("tcp", fmt.Sprintf("%s:%d", processHost, processPort))
if err != nil {
log.Printf("Failed to dial remote Redis: %v", err)
localConn.Close()
continue
}
go forward(localConn, remoteConn)
}
}
func getSshClient() *ssh.Client {
sshConfig := getSshConfig()
sshClient, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", sshHost, sshPort), sshConfig)
if err != nil {
log.Fatalf("Failed to dial SSH: %v", err)
}
return sshClient
}
func GetMysql() *gorm.DB {
// 连接服务器
sshClient := getSshClient()
// 获取本地监听
listener, localPort := getListener()
// 转发进程数据
go binding(listener, sshClient, mysqlHost, mysqlPort)
// 连接本地端口
dsn := fmt.Sprintf("%s:%s@tcp(127.0.0.1:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local", mysqlUser, mysqlPass, localPort, mysqlDB)
// 打开数据库连接
db, err := gorm.Open(mysql.New(mysql.Config{
DSN: dsn,
}), &gorm.Config{})
if err != nil {
log.Fatalf("create db err, %s", err.Error())
}
return db
}
func GetRedis() (*redis.Client, int32) {
// 连接服务器
sshClient := getSshClient()
// 建立本地监听
listener, localPort := getListener()
// 转发进程数据
go binding(listener, sshClient, redisHost, redisPort)
// 连接本地端口
rdb := redis.NewClient(&redis.Options{
Addr: fmt.Sprintf("127.0.0.1:%d", localPort),
Password: redisPass,
DB: redisDB,
})
ctx := context.Background()
v, err := rdb.Ping(ctx).Result()
_ = v
if err != nil {
log.Fatalf("Failed to connect to Redis: %v", err)
}
return rdb, localPort
}