Compare commits
5 Commits
Author | SHA1 | Date |
---|---|---|
|
adc0949c71 | |
|
12336a9c40 | |
|
2b2faec437 | |
|
676aa5bdcb | |
|
36d32e7222 |
|
@ -17,14 +17,17 @@ func (p Protocol) String() string {
|
|||
return "TCP"
|
||||
case 1:
|
||||
return "UDP"
|
||||
case 2:
|
||||
return "TCP-TLS"
|
||||
}
|
||||
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
const (
|
||||
ProtocolTCP Protocol = 0
|
||||
ProtocolUDP Protocol = 1
|
||||
ProtocolTCP Protocol = 0
|
||||
ProtocolUDP Protocol = 1
|
||||
ProtocolTCPTLS Protocol = 2
|
||||
)
|
||||
|
||||
type IForward interface {
|
||||
|
|
|
@ -2,9 +2,11 @@ package forward
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"git.makemake.in/kzkzzzz/mycommon/mylog"
|
||||
"io"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net"
|
||||
"time"
|
||||
|
@ -61,7 +63,7 @@ func (t *TCP) Forward() error {
|
|||
//listener, err := lc.Listen(ctx0, "tcp", t.forwardInfo.LocalAddr)
|
||||
// 启动 TCP 监听
|
||||
|
||||
mylog.Infof("[TCP] %s %s -> %s", t.forwardInfo.Name, t.forwardInfo.LocalAddr, t.forwardInfo.TargetAddr)
|
||||
log.Printf("[TCP] [%s] %s -> %s", t.forwardInfo.Name, t.forwardInfo.LocalAddr, t.forwardInfo.TargetAddr)
|
||||
|
||||
go func() {
|
||||
ctx, cancelCtx := context.WithCancel(context.Background())
|
||||
|
@ -87,12 +89,27 @@ func (t *TCP) handleConn(mainCtx context.Context, localConn net.Conn, targetAddr
|
|||
|
||||
targetAddr := targetAddrList[rand.Intn(len(targetAddrList))]
|
||||
|
||||
// 连接到目标地址
|
||||
targetConn, err := net.Dial("tcp", targetAddr)
|
||||
var (
|
||||
targetConn net.Conn
|
||||
err error
|
||||
)
|
||||
|
||||
switch t.forwardInfo.Protocol {
|
||||
case ProtocolTCPTLS:
|
||||
|
||||
targetConn, err = tls.Dial("tcp", targetAddr, &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
})
|
||||
|
||||
default:
|
||||
targetConn, err = net.Dial("tcp", targetAddr)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
mylog.Error("Error connecting to target:", err)
|
||||
return
|
||||
}
|
||||
|
||||
defer targetConn.Close()
|
||||
|
||||
ctx, cancelCtx := context.WithCancel(context.Background())
|
||||
|
|
|
@ -2,6 +2,7 @@ package forward
|
|||
|
||||
import (
|
||||
"git.makemake.in/kzkzzzz/mycommon/mylog"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net"
|
||||
"time"
|
||||
|
@ -36,7 +37,7 @@ func (u *UDP) Forward() error {
|
|||
}
|
||||
u.conn = conn
|
||||
|
||||
mylog.Infof("[UDP] %s %s -> %s", u.forwardInfo.Name, u.forwardInfo.LocalAddr, u.forwardInfo.TargetAddr)
|
||||
log.Printf("[UDP] [%s] %s -> %s", u.forwardInfo.Name, u.forwardInfo.LocalAddr, u.forwardInfo.TargetAddr)
|
||||
|
||||
go func() {
|
||||
err := u.handleConn(conn)
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -3,8 +3,8 @@
|
|||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>端口转发配置</title>
|
||||
<script type="module" crossorigin src="./assets/index-lqpwyav5.js"></script>
|
||||
<title>端口转发</title>
|
||||
<script type="module" crossorigin src="./assets/index-B_FuHUXB.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="./assets/index-BA8XwqWY.css">
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -12,7 +12,9 @@ import (
|
|||
enTr "github.com/go-playground/validator/v10/translations/en"
|
||||
"github.com/spf13/cast"
|
||||
"gorm.io/gorm"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"proxyport/app/db"
|
||||
"proxyport/app/forward"
|
||||
"proxyport/app/model"
|
||||
|
@ -29,6 +31,7 @@ type Cfg struct {
|
|||
ListenAddr string
|
||||
User string
|
||||
Password string
|
||||
WebName string
|
||||
}
|
||||
|
||||
func Start(ctx context.Context) {
|
||||
|
@ -48,6 +51,8 @@ func Start(ctx context.Context) {
|
|||
engine.GET("/", func(ctx *gin.Context) {
|
||||
ctx.HTML(http.StatusOK, "index.html", nil)
|
||||
})
|
||||
|
||||
engine.GET("/GetConfig", GetConfig)
|
||||
engine.GET("/List", List)
|
||||
engine.POST("/Create", Create)
|
||||
engine.POST("/Update", Update)
|
||||
|
@ -60,7 +65,7 @@ func Start(ctx context.Context) {
|
|||
}
|
||||
|
||||
go func() {
|
||||
mylog.Infof("http listen on %s", hs.Addr)
|
||||
log.Printf("http listen on %s", hs.Addr)
|
||||
mylog.Warn(hs.ListenAndServe())
|
||||
}()
|
||||
|
||||
|
@ -84,6 +89,12 @@ func cors() gin.HandlerFunc {
|
|||
}
|
||||
}
|
||||
|
||||
func GetConfig(ctx *gin.Context) {
|
||||
success(ctx, gin.H{
|
||||
"web_name": Config.WebName,
|
||||
})
|
||||
}
|
||||
|
||||
func List(ctx *gin.Context) {
|
||||
data := make([]*model.Forward, 0)
|
||||
|
||||
|
@ -100,7 +111,7 @@ func Create(ctx *gin.Context) {
|
|||
TargetAddr string `json:"target_addr" binding:"min=1"`
|
||||
LocalPort int `json:"local_port" binding:"required"`
|
||||
Name string `json:"name" binding:"required"`
|
||||
ForwardType int `json:"protocol" binding:"oneof=0 1"`
|
||||
ForwardType int `json:"protocol"`
|
||||
Status int `json:"status" binding:"oneof=0 1"`
|
||||
}
|
||||
|
||||
|
@ -169,7 +180,7 @@ func Update(ctx *gin.Context) {
|
|||
TargetAddr string `json:"target_addr" binding:"min=1"`
|
||||
LocalPort int `json:"local_port" binding:"required"`
|
||||
Name string `json:"name" binding:"required"`
|
||||
Protocol int `json:"protocol" binding:"oneof=0 1"`
|
||||
Protocol int `json:"protocol"`
|
||||
Status int `json:"status" binding:"oneof=0 1"`
|
||||
}
|
||||
|
||||
|
@ -269,23 +280,45 @@ func Delete(ctx *gin.Context) {
|
|||
success(ctx, "ok")
|
||||
}
|
||||
|
||||
var addrReg = regexp.MustCompile(`^[^:]+:([0-9]{1,5})$`)
|
||||
var (
|
||||
hostReg = regexp.MustCompile(`^[a-zA-Z0-9]+[a-zA-Z0-9\-.]*[a-zA-Z]+$`)
|
||||
letterReg = regexp.MustCompile(`[a-zA-Z\-]`)
|
||||
emptyReg = regexp.MustCompile(`\s+`)
|
||||
)
|
||||
|
||||
func checkAddr(addr string) error {
|
||||
res := addrReg.FindStringSubmatch(addr)
|
||||
if len(res) != 2 {
|
||||
return fmt.Errorf("invalid addr: %s", addr)
|
||||
addr = strings.TrimSpace(addr)
|
||||
|
||||
if emptyReg.MatchString(addr) {
|
||||
return fmt.Errorf("addr format err: %s", addr)
|
||||
}
|
||||
|
||||
intPort := cast.ToInt(res[1])
|
||||
if intPort < 10 || intPort > 65535 {
|
||||
return fmt.Errorf("port: %d out of range: 10 - 65535", intPort)
|
||||
sp := strings.SplitN(addr, ":", 2)
|
||||
|
||||
if len(sp) != 2 {
|
||||
return fmt.Errorf("addr format err: %s", addr)
|
||||
}
|
||||
|
||||
//_, err := netip.ParseAddrPort(addr)
|
||||
//if err != nil {
|
||||
// return err
|
||||
//}
|
||||
host := sp[0]
|
||||
port := sp[1]
|
||||
intPort := cast.ToInt(port)
|
||||
|
||||
if intPort > 65535 || intPort < 10 {
|
||||
return fmt.Errorf("port [%s] out of range: 10 - 65535", port)
|
||||
}
|
||||
|
||||
if !letterReg.MatchString(host) {
|
||||
_, err := netip.ParseAddrPort(addr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ip [%s] format err: %s", host, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if !hostReg.MatchString(host) {
|
||||
return fmt.Errorf("host [%s] format err", host)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>端口转发配置</title>
|
||||
<title>端口转发</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
<template>
|
||||
<div>
|
||||
<div>
|
||||
<h2>端口转发</h2>
|
||||
<h2>
|
||||
<span>{{ data.title }}</span>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div style="width: 100%;">
|
||||
|
@ -9,37 +11,41 @@
|
|||
</div>
|
||||
|
||||
<div>
|
||||
<el-table :data="data.list" style="width: 100%">
|
||||
<el-table-column align="center" label="协议">
|
||||
<el-table :data="data.list" style="width: 100%;" max-height="75vh">
|
||||
<el-table-column align="center" label="协议" width="150">
|
||||
<template #default="scope">
|
||||
<div v-if="scope.row.protocol === 1">
|
||||
<el-tag type="success">UDP</el-tag>
|
||||
<el-tag disable-transitions type="success">UDP</el-tag>
|
||||
</div>
|
||||
|
||||
<div v-else-if="scope.row.protocol === 2">
|
||||
<el-tag disable-transitions type="success">TCP-TLS</el-tag>
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<el-tag type="primary">TCP</el-tag>
|
||||
<el-tag disable-transitions type="primary">TCP</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
|
||||
<el-table-column align="center" label="状态">
|
||||
<el-table-column align="center" label="状态" width="150">
|
||||
<template #default="scope">
|
||||
<el-switch v-model="scope.row.status_bool" @change="switchStatus(scope.row)"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
|
||||
<el-table-column align="center" prop="name" label="名称"/>
|
||||
<el-table-column align="center" prop="local_port" label="本地端口"/>
|
||||
<el-table-column align="center" prop="name" label="名称" width="350"/>
|
||||
<el-table-column align="center" prop="local_port" label="本地端口" width="150"/>
|
||||
|
||||
<el-table-column align="center" label="远程地址">
|
||||
<template #default="scope">
|
||||
<div style="white-space: pre">{{ formatList(scope.row.target_addr) }}</div>
|
||||
<div style="white-space: pre-wrap; word-break: break-all">{{ formatList(scope.row.target_addr) }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="操作">
|
||||
<el-table-column align="center" label="操作" width="200">
|
||||
<template #default="scope">
|
||||
<el-button size="small" type="primary" @click="updateForward(scope.row)">修改</el-button>
|
||||
|
||||
|
@ -61,6 +67,8 @@
|
|||
:title="data.form.id > 0 ? '修改': '添加'"
|
||||
width="600px"
|
||||
align-center
|
||||
:close-on-click-modal="false"
|
||||
:show-close="false"
|
||||
>
|
||||
|
||||
<div>
|
||||
|
@ -71,6 +79,7 @@
|
|||
<el-radio-group v-model="data.form.protocol">
|
||||
<el-radio :value="0">TCP</el-radio>
|
||||
<el-radio :value="1">UDP</el-radio>
|
||||
<el-radio :value="2">TCP-TLS</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
|
@ -108,17 +117,31 @@ import {onMounted, reactive} from "vue";
|
|||
import http from "@/helper/http.js";
|
||||
|
||||
const data = reactive({
|
||||
title: "端口转发",
|
||||
list: [],
|
||||
dialogVisible: false,
|
||||
form: {
|
||||
protocol: 0,
|
||||
}
|
||||
},
|
||||
config: {}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
getConfig()
|
||||
getList()
|
||||
})
|
||||
|
||||
const getConfig = async () => {
|
||||
let res = await http.get("/GetConfig")
|
||||
data.config = res.data.data
|
||||
|
||||
if (data.config.web_name !== "") {
|
||||
data.title = `端口转发 - ${data.config.web_name}`
|
||||
}
|
||||
|
||||
document.title = data.title
|
||||
}
|
||||
|
||||
const createForward = () => {
|
||||
data.dialogVisible = true
|
||||
data.form = {
|
||||
|
@ -175,7 +198,7 @@ const getList = async () => {
|
|||
}
|
||||
}
|
||||
|
||||
console.log(res)
|
||||
// console.log(res)
|
||||
}
|
||||
|
||||
const confirmConfig = async () => {
|
||||
|
|
9
local.sh
9
local.sh
|
@ -5,7 +5,14 @@ set -e
|
|||
case $1 in
|
||||
"backend")
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -v -o temp/proxyport.linux main.go
|
||||
scp -P 5566 temp/proxyport.linux kzkzzzz@193.32.149.42:temp/proxyport/proxyport.linux
|
||||
wsl -d Debian -e bash -c "rsync -rvz -P -e 'ssh -p 22' temp/proxyport.linux zifeng.li@sz-rta-kiwi.test:temp/proxyport/"
|
||||
|
||||
# wsl -d Debian -e bash -c "rsync -rvz -P -e 'ssh -p 22' temp/proxyport.linux zifeng.li@rta-kiwi.test:temp/proxyport/"
|
||||
# wsl -d Debian -e bash -c "rsync -rvz -P -e 'ssh -p 22' temp/proxyport.linux root@10.80.100.101:/opt/temp/proxyport/"
|
||||
;;
|
||||
"pi5")
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -v -o temp/proxyport.arm64 main.go
|
||||
scp temp/proxyport.arm64 pi@100.93.0.65:temp/proxyport/proxyport.arm64
|
||||
;;
|
||||
"frontend")
|
||||
cd frontend
|
||||
|
|
3
main.go
3
main.go
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"flag"
|
||||
"git.makemake.in/kzkzzzz/mycommon/mylog"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"proxyport/app/db"
|
||||
|
@ -18,10 +19,12 @@ var (
|
|||
)
|
||||
|
||||
func main() {
|
||||
log.SetOutput(os.Stdout)
|
||||
flag.StringVar(&logLevel, "log_level", "debug", "log level")
|
||||
flag.StringVar(&web.Config.ListenAddr, "listen_addr", ":28083", "web port")
|
||||
flag.StringVar(&web.Config.User, "user", "", "web user")
|
||||
flag.StringVar(&web.Config.Password, "password", "", "web password")
|
||||
flag.StringVar(&web.Config.WebName, "web_name", "", "web name")
|
||||
flag.Parse()
|
||||
|
||||
mylog.SetLogLevel(logLevel)
|
||||
|
|
Loading…
Reference in New Issue