parent
5e820e6555
commit
24b820e67c
|
@ -15,6 +15,9 @@ lucky
|
|||
*.out
|
||||
*.log
|
||||
*.upx
|
||||
*.pem
|
||||
*.crt
|
||||
*.key
|
||||
lucky.conf
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
|
|
33
README.md
33
README.md
|
@ -9,9 +9,7 @@
|
|||
- [后台界面](#后台界面)
|
||||
|
||||
- [开发编译](#开发编译)
|
||||
- [更新日志](#更新日志)
|
||||
- [使用注意与常见问题](#使用注意与常见问题)
|
||||
|
||||
<!-- /TOC -->
|
||||
|
||||
|
||||
|
@ -42,7 +40,6 @@
|
|||
- 支持的DNS服务商和DDNS-GO一样,有Alidns(阿里云),百度云,Cloudflare,Dnspod(腾讯云),华为云.自定义(Callback)内置有每步,No-IP,Dynv6,Dynu模版,一键填充,仅需修改相应用户密码或者token即可快速接入.
|
||||
- 3.http/https反向代理
|
||||
- 特点
|
||||
- SSL证书管理简单
|
||||
- 设置简单
|
||||
- 支持HttpBasic认证
|
||||
- 支持IP黑白名单
|
||||
|
@ -50,6 +47,15 @@
|
|||
- 日志记录最近访问情况
|
||||
- 一键开关子规则
|
||||
- 前端域名与后端地址 支持一对一,一对多(均衡负载),多对多(下一级反向代理)
|
||||
- 4.网络唤醒
|
||||
- 特点
|
||||
- 支持远程控制唤醒和关机操作
|
||||
- 远程唤醒需要 待唤醒端所在局域网内有开启中继唤醒指令的lucky唤醒客户端
|
||||
- 远程关机需要 待关机端运行有luck唤醒客户端
|
||||
- 支持接入第三方物联网平台(点灯科技 巴法云),可通过各大平台的语音助手控制设备唤醒和关机.
|
||||
- 点灯科技支持 小爱同学 小度 天猫精灵
|
||||
- 巴法云支持小爱同学 小度 天猫精灵 google语音 AmazonAlexa
|
||||
- 具备但一般用不上的功能:支持一个设备设置多组网卡mac和多个广播地址,实现批量控制设备.
|
||||
|
||||
- 将要实现的功能
|
||||
- 有建议可联系作者.
|
||||
|
@ -135,11 +141,16 @@
|
|||
#### Http反向代理
|
||||
![](./previews/reverseproxy.png)
|
||||
|
||||
#### 网络唤醒
|
||||
|
||||
![](./previews/wol001.png)
|
||||
|
||||
![](./previews/wol002.png)
|
||||
|
||||
|
||||
|
||||
|
||||
# 开发编译
|
||||
#开发编译
|
||||
|
||||
|
||||
```bash
|
||||
|
@ -147,17 +158,9 @@
|
|||
```
|
||||
|
||||
|
||||
# 更新日志
|
||||
|
||||
2022-10-08 版本1.4.9
|
||||
1.反向代理新增https支持。
|
||||
2.加入SSL证书管理模块
|
||||
3.后台接口支持HTTPS
|
||||
4.端口转发模块重构优化,移除命令行配置功能,注意使用此版本后原来的端口转发配置会全部消失。
|
||||
5.修复已知BUG.
|
||||
6.源码不再和二进制版本同时发布.
|
||||
2022-10-14 v1.4.10
|
||||
1.修复特定情况下反向代理规则添加后无法编辑删除的bug.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -171,5 +174,3 @@
|
|||
|
||||
- 转发规则启用异常,端口转发没有生效时请登录后台查看日志.
|
||||
|
||||
- 开启外网访问可以直接修改配置文件中的"AllowInternetaccess": false, 将false改为true
|
||||
|
||||
|
|
146
config/config.go
146
config/config.go
|
@ -43,31 +43,30 @@ func FlushLoginRandomKey() {
|
|||
loginRandomkey = stringsp.GetRandomString(16)
|
||||
}
|
||||
|
||||
type ConfigureRelayRule struct {
|
||||
Name string `json:"Name"`
|
||||
Configurestr string `json:"Configurestr"`
|
||||
Enable bool `json:"Enable"`
|
||||
Options socketproxy.RelayRuleOptions `json:"Options"`
|
||||
}
|
||||
|
||||
type BaseConfigure struct {
|
||||
AdminWebListenPort int `json:"AdminWebListenPort"` //管理后台端口
|
||||
ProxyCountLimit int64 `json:"ProxyCountLimit"` //全局代理数量限制
|
||||
AdminAccount string `json:"AdminAccount"` //登录账号
|
||||
AdminPassword string `json:"AdminPassword"` //登录密码
|
||||
AllowInternetaccess bool `json:"AllowInternetaccess"` //允许外网访问
|
||||
GlobalMaxConnections int64 `json:"GlobalMaxConnections"` //全局最大连接数
|
||||
LogMaxSize int `json:"LogMaxSize"` //日志记录最大条数
|
||||
AdminWebListenPort int `json:"AdminWebListenPort"` //管理后台端口
|
||||
AdminWebListenTLS bool `json:"AdminWebListenTLS"` //启用TLS监听端口
|
||||
AdminWebListenHttpsPort int `json:"AdminWebListenHttpsPort"` //管理后台Https端口
|
||||
|
||||
//ProxyCountLimit int64 `json:"ProxyCountLimit"` //全局代理数量限制
|
||||
AdminAccount string `json:"AdminAccount"` //登录账号
|
||||
AdminPassword string `json:"AdminPassword"` //登录密码
|
||||
AllowInternetaccess bool `json:"AllowInternetaccess"` //允许外网访问
|
||||
//GlobalMaxConnections int64 `json:"GlobalMaxConnections"` //全局最大连接数
|
||||
LogMaxSize int `json:"LogMaxSize"` //日志记录最大条数
|
||||
}
|
||||
|
||||
type ProgramConfigure struct {
|
||||
BaseConfigure BaseConfigure `json:"BaseConfigure"`
|
||||
RelayRuleList []ConfigureRelayRule `json:"RelayRuleList"`
|
||||
WhiteListConfigure WhiteListConfigure `json:"WhiteListConfigure"`
|
||||
BlackListConfigure BlackListConfigure `json:"BlackListConfigure"`
|
||||
DDNSConfigure DDNSConfigure `json:"DDNSConfigure"` //DDNS 参数设置
|
||||
DDNSTaskList []DDNSTask `json:"DDNSTaskList"` //DDNS任务列表
|
||||
ReverseProxyRuleList []ReverseProxyRule `json:"ReverseProxyRuleList"` //反向代理规则列表
|
||||
BaseConfigure BaseConfigure `json:"BaseConfigure"`
|
||||
WhiteListConfigure WhiteListConfigure `json:"WhiteListConfigure"`
|
||||
BlackListConfigure BlackListConfigure `json:"BlackListConfigure"`
|
||||
DDNSConfigure DDNSConfigure `json:"DDNSConfigure"` //DDNS 参数设置
|
||||
DDNSTaskList []DDNSTask `json:"DDNSTaskList"` //DDNS任务列表
|
||||
ReverseProxyRuleList []ReverseProxyRule `json:"ReverseProxyRuleList"` //反向代理规则列表
|
||||
SSLCertficateList []SSLCertficate `json:"SSLCertficateList"` //SSL证书列表
|
||||
PortForwardsRuleList []PortForwardsRule `json:"PortForwardsRuleList"` //端口转发规则列表
|
||||
PortForwardsConfigure PortForwardsConfigure `json:"PortForwardsConfigure"` //端口转发设置
|
||||
WOLDeviceList []WOLDevice `json:"WOLDeviceList"` //网络唤醒设备列表
|
||||
}
|
||||
|
||||
var programConfigureMutex sync.RWMutex
|
||||
|
@ -90,12 +89,6 @@ func GetAuthAccount() map[string]string {
|
|||
return accountInfo
|
||||
}
|
||||
|
||||
func SetConfigRuleList(ruleList *[]ConfigureRelayRule) {
|
||||
programConfigureMutex.Lock()
|
||||
defer programConfigureMutex.Unlock()
|
||||
programConfigure.RelayRuleList = *ruleList
|
||||
}
|
||||
|
||||
func GetRunMode() string {
|
||||
return runMode
|
||||
}
|
||||
|
@ -146,14 +139,51 @@ func GetDDNSConfigure() DDNSConfigure {
|
|||
return conf
|
||||
}
|
||||
|
||||
func GetPortForwardsConfigure() PortForwardsConfigure {
|
||||
programConfigureMutex.RLock()
|
||||
defer programConfigureMutex.RUnlock()
|
||||
conf := programConfigure.PortForwardsConfigure
|
||||
return conf
|
||||
}
|
||||
|
||||
func SetPortForwardsConfigure(conf *PortForwardsConfigure) error {
|
||||
programConfigureMutex.Lock()
|
||||
defer programConfigureMutex.Unlock()
|
||||
|
||||
if conf.PortForwardsLimit < 0 {
|
||||
conf.PortForwardsLimit = 0
|
||||
} else if conf.PortForwardsLimit > 1024 {
|
||||
conf.PortForwardsLimit = 1024
|
||||
}
|
||||
|
||||
if conf.TCPPortforwardMaxConnections < 0 {
|
||||
conf.TCPPortforwardMaxConnections = 0
|
||||
} else if conf.TCPPortforwardMaxConnections > 4096 {
|
||||
conf.TCPPortforwardMaxConnections = 4096
|
||||
}
|
||||
|
||||
if conf.UDPReadTargetDataMaxgoroutineCount < 0 {
|
||||
conf.UDPReadTargetDataMaxgoroutineCount = 0
|
||||
} else if conf.UDPReadTargetDataMaxgoroutineCount > 4096 {
|
||||
conf.UDPReadTargetDataMaxgoroutineCount = 4096
|
||||
}
|
||||
|
||||
programConfigure.PortForwardsConfigure = *conf
|
||||
|
||||
socketproxy.SetGlobalMaxPortForwardsCountLimit(conf.PortForwardsLimit)
|
||||
socketproxy.SetGlobalTCPPortforwardMaxConnections(conf.TCPPortforwardMaxConnections)
|
||||
socketproxy.SetGlobalUDPReadTargetDataMaxgoroutineCountLimit(conf.UDPReadTargetDataMaxgoroutineCount)
|
||||
return Save()
|
||||
}
|
||||
|
||||
// 保存基础配置
|
||||
func SetBaseConfigure(conf *BaseConfigure) error {
|
||||
programConfigureMutex.Lock()
|
||||
defer programConfigureMutex.Unlock()
|
||||
programConfigure.BaseConfigure = *conf
|
||||
|
||||
socketproxy.SetGlobalMaxConnections(conf.GlobalMaxConnections)
|
||||
socketproxy.SetGlobalMaxProxyCount(conf.ProxyCountLimit)
|
||||
//socketproxy.SetGlobalMaxConnections(conf.GlobalMaxConnections)
|
||||
//socketproxy.SetGlobalMaxPortForwardsCount(conf.ProxyCountLimit)
|
||||
|
||||
if conf.LogMaxSize < minLogSize {
|
||||
conf.LogMaxSize = minLogSize
|
||||
|
@ -200,18 +230,29 @@ func Read(filePath string) (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
if pc.BaseConfigure.GlobalMaxConnections <= 0 {
|
||||
pc.BaseConfigure.GlobalMaxConnections = socketproxy.DEFAULT_GLOBAL_MAX_CONNECTIONS
|
||||
if pc.PortForwardsConfigure.PortForwardsLimit <= 0 {
|
||||
pc.PortForwardsConfigure.PortForwardsLimit = socketproxy.DEFAULT_MAX_PORTFORWARDS_LIMIT
|
||||
}
|
||||
if pc.PortForwardsConfigure.TCPPortforwardMaxConnections <= 0 {
|
||||
pc.PortForwardsConfigure.TCPPortforwardMaxConnections = socketproxy.DEFAULT_GLOBAL_MAX_CONNECTIONS
|
||||
}
|
||||
|
||||
if pc.BaseConfigure.ProxyCountLimit <= 0 {
|
||||
pc.BaseConfigure.ProxyCountLimit = socketproxy.DEFAULT_MAX_PROXY_COUNT
|
||||
if pc.PortForwardsConfigure.UDPReadTargetDataMaxgoroutineCount <= 0 {
|
||||
pc.PortForwardsConfigure.UDPReadTargetDataMaxgoroutineCount = socketproxy.DEFAULT_GLOBAL_UDPReadTargetDataMaxgoroutineCount
|
||||
}
|
||||
|
||||
socketproxy.SetGlobalMaxPortForwardsCountLimit(pc.PortForwardsConfigure.PortForwardsLimit)
|
||||
socketproxy.SetGlobalTCPPortforwardMaxConnections(pc.PortForwardsConfigure.TCPPortforwardMaxConnections)
|
||||
socketproxy.SetGlobalUDPReadTargetDataMaxgoroutineCountLimit(pc.PortForwardsConfigure.UDPReadTargetDataMaxgoroutineCount)
|
||||
|
||||
if pc.BaseConfigure.AdminWebListenPort <= 0 {
|
||||
pc.BaseConfigure.AdminWebListenPort = 16601
|
||||
}
|
||||
|
||||
if pc.BaseConfigure.AdminWebListenHttpsPort <= 0 {
|
||||
pc.BaseConfigure.AdminWebListenHttpsPort = 16626
|
||||
}
|
||||
|
||||
if pc.BaseConfigure.LogMaxSize < minLogSize {
|
||||
pc.BaseConfigure.LogMaxSize = minLogSize
|
||||
} else if pc.BaseConfigure.LogMaxSize > maxLogSize {
|
||||
|
@ -223,11 +264,8 @@ func Read(filePath string) (err error) {
|
|||
return nil
|
||||
}
|
||||
|
||||
func LoadDefault(proxyCountLimit int64,
|
||||
adminWebListenPort int,
|
||||
globalMaxConnections int64) {
|
||||
|
||||
programConfigure = loadDefaultConfigure(proxyCountLimit, adminWebListenPort, globalMaxConnections)
|
||||
func LoadDefault(adminWebListenPort int) {
|
||||
programConfigure = loadDefaultConfigure(adminWebListenPort)
|
||||
}
|
||||
|
||||
func Save() (err error) {
|
||||
|
@ -281,17 +319,13 @@ func readProgramConfigure(filePath string) (conf *ProgramConfigure, err error) {
|
|||
}
|
||||
|
||||
func loadDefaultConfigure(
|
||||
proxyCountLimit int64,
|
||||
adminWebListenPort int,
|
||||
globalMaxConnections int64) *ProgramConfigure {
|
||||
adminWebListenPort int) *ProgramConfigure {
|
||||
|
||||
baseConfigure := BaseConfigure{AdminWebListenPort: adminWebListenPort,
|
||||
GlobalMaxConnections: globalMaxConnections,
|
||||
AdminAccount: defaultAdminAccount,
|
||||
AdminPassword: defaultAdminPassword,
|
||||
ProxyCountLimit: proxyCountLimit,
|
||||
AllowInternetaccess: false,
|
||||
LogMaxSize: defaultLogSize}
|
||||
AdminAccount: defaultAdminAccount,
|
||||
AdminPassword: defaultAdminPassword,
|
||||
AllowInternetaccess: false,
|
||||
LogMaxSize: defaultLogSize}
|
||||
|
||||
whiteListConfigure := WhiteListConfigure{BaseConfigure: WhiteListBaseConfigure{ActivelifeDuration: 36, BasicAccount: defaultAdminAccount, BasicPassword: defaultAdminPassword}}
|
||||
|
||||
|
@ -299,13 +333,21 @@ func loadDefaultConfigure(
|
|||
pc.BaseConfigure = baseConfigure
|
||||
pc.WhiteListConfigure = whiteListConfigure
|
||||
|
||||
if pc.BaseConfigure.GlobalMaxConnections <= 0 {
|
||||
pc.BaseConfigure.GlobalMaxConnections = socketproxy.DEFAULT_GLOBAL_MAX_CONNECTIONS
|
||||
if pc.PortForwardsConfigure.PortForwardsLimit <= 0 {
|
||||
pc.PortForwardsConfigure.PortForwardsLimit = socketproxy.DEFAULT_MAX_PORTFORWARDS_LIMIT
|
||||
}
|
||||
socketproxy.SetGlobalMaxPortForwardsCountLimit(pc.PortForwardsConfigure.PortForwardsLimit)
|
||||
|
||||
if pc.PortForwardsConfigure.TCPPortforwardMaxConnections <= 0 {
|
||||
pc.PortForwardsConfigure.TCPPortforwardMaxConnections = socketproxy.TCPUDP_DEFAULT_SINGLE_PROXY_MAX_CONNECTIONS
|
||||
}
|
||||
socketproxy.SetGlobalTCPPortforwardMaxConnections(pc.PortForwardsConfigure.TCPPortforwardMaxConnections)
|
||||
|
||||
if pc.PortForwardsConfigure.UDPReadTargetDataMaxgoroutineCount <= 0 {
|
||||
pc.PortForwardsConfigure.UDPReadTargetDataMaxgoroutineCount = socketproxy.DEFAULT_GLOBAL_UDPReadTargetDataMaxgoroutineCount
|
||||
}
|
||||
|
||||
if pc.BaseConfigure.ProxyCountLimit <= 0 {
|
||||
pc.BaseConfigure.ProxyCountLimit = socketproxy.DEFAULT_MAX_PROXY_COUNT
|
||||
}
|
||||
socketproxy.SetGlobalUDPReadTargetDataMaxgoroutineCountLimit(pc.PortForwardsConfigure.UDPReadTargetDataMaxgoroutineCount)
|
||||
|
||||
if pc.BaseConfigure.AdminWebListenPort <= 0 {
|
||||
pc.BaseConfigure.AdminWebListenPort = defaultAdminListenPort
|
||||
|
|
|
@ -57,6 +57,7 @@ type DNSConfig struct {
|
|||
ForceInterval int `json:"ForceInterval"` //(秒)即使IP没有变化,到一定时间后依然强制更新或先DNS解析比较IP再更新
|
||||
ResolverDoaminCheck bool `json:"ResolverDoaminCheck"` //调用callback同步前先解析一次域名,如果IP相同就不同步
|
||||
DNSServerList []string `json:"DNSServerList"` //DNS服务器列表
|
||||
CallAPINetwork string `json:"CallAPINetwork"` //空代理tcp, tcp4,tcp6
|
||||
Callback DNSCallback `json:"Callback"`
|
||||
HttpClientProxyType string `json:"HttpClientProxyType"` //http client代理服务器设置
|
||||
HttpClientProxyAddr string `json:"HttpClientProxyAddr"` //代理服务器IP
|
||||
|
@ -64,6 +65,15 @@ type DNSConfig struct {
|
|||
HttpClientProxyPassword string `json:"HttpClientProxyPassword"` //代理密码
|
||||
}
|
||||
|
||||
func (d *DNSConfig) GetCallAPINetwork() string {
|
||||
switch d.CallAPINetwork {
|
||||
case "tcp4", "tcp6":
|
||||
return d.CallAPINetwork
|
||||
default:
|
||||
return "tcp"
|
||||
}
|
||||
}
|
||||
|
||||
type DNSCallback struct {
|
||||
URL string `json:"URL"` //请求地址
|
||||
Method string `json:"Method"` //请求方法
|
||||
|
@ -179,8 +189,8 @@ func GetDDNSTaskConfigureList() []*DDNSTask {
|
|||
}
|
||||
|
||||
func GetDDNSTaskByKey(taskKey string) *DDNSTask {
|
||||
programConfigureMutex.Lock()
|
||||
defer programConfigureMutex.Unlock()
|
||||
programConfigureMutex.RLock()
|
||||
defer programConfigureMutex.RUnlock()
|
||||
taskIndex := -1
|
||||
|
||||
for i := range programConfigure.DDNSTaskList {
|
||||
|
|
|
@ -0,0 +1,452 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gdy666/lucky/socketproxy"
|
||||
"github.com/gdy666/lucky/thirdlib/gdylib/logsbuffer"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type PortForwardsConfigure struct {
|
||||
PortForwardsLimit int64 `json:"PortForwardsLimit"` //全局端口转发数量限制
|
||||
TCPPortforwardMaxConnections int64 `json:"TCPPortforwardMaxConnections"` //端口转发全局TCP并发链接数限制
|
||||
UDPReadTargetDataMaxgoroutineCount int64 `json:"UDPReadTargetDataMaxgoroutineCount"` //端口转发全局UDP读取目标地址数据协程数限制
|
||||
}
|
||||
|
||||
type PortForwardsRule struct {
|
||||
Name string `json:"Name"`
|
||||
Key string `json:"Key"`
|
||||
Enable bool `json:"Enable"`
|
||||
ForwardTypes []string `json:"ForwardTypes"`
|
||||
ListenAddress string `json:"ListenAddress"`
|
||||
ListenPorts string `json:"ListenPorts"`
|
||||
TargetAddressList []string `json:"TargetAddressList"`
|
||||
TargetPorts string `json:"TargetPorts"`
|
||||
Options socketproxy.RelayRuleOptions `json:"Options"`
|
||||
ReverseProxyList *[]socketproxy.Proxy `json:"-"`
|
||||
|
||||
logsBuffer *logsbuffer.LogsBuffer
|
||||
logrus *logrus.Logger
|
||||
LogLevel int `json:"LogLevel"` //日志输出级别
|
||||
LogOutputToConsole bool `json:"LogOutputToConsole"` //日志输出到终端
|
||||
AccessLogMaxNum int `json:"AccessLogMaxNum"`
|
||||
WebListShowLastLogMaxCount int `json:"WebListShowLastLogMaxCount"` //前端列表显示最新日志最大条数
|
||||
}
|
||||
|
||||
func (r *PortForwardsRule) ProxyCount() int {
|
||||
if r.ReverseProxyList == nil {
|
||||
return 0
|
||||
}
|
||||
return len(*r.ReverseProxyList)
|
||||
}
|
||||
|
||||
func (r *PortForwardsRule) StartAllProxys() {
|
||||
if r.ReverseProxyList == nil {
|
||||
return
|
||||
}
|
||||
for i := range *r.ReverseProxyList {
|
||||
|
||||
(*r.ReverseProxyList)[i].StartProxy()
|
||||
}
|
||||
}
|
||||
|
||||
func (r *PortForwardsRule) GetLastLogs(maxCount int) []any {
|
||||
return r.GetLogsBuffer().GetLastLogs(WebLogConvert, maxCount)
|
||||
}
|
||||
|
||||
func (r *PortForwardsRule) Fire(entry *logrus.Entry) error {
|
||||
if !r.LogOutputToConsole {
|
||||
return nil
|
||||
}
|
||||
s, _ := entry.String()
|
||||
log.Print(s)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *PortForwardsRule) Levels() []logrus.Level {
|
||||
return logrus.AllLevels
|
||||
}
|
||||
|
||||
func (r *PortForwardsRule) GetLogrus() *logrus.Logger {
|
||||
if r.logrus == nil {
|
||||
r.logrus = logrus.New()
|
||||
r.logrus.SetLevel(logrus.Level(r.LogLevel))
|
||||
r.logrus.SetOutput(r.GetLogsBuffer())
|
||||
r.logrus.SetFormatter(&logrus.JSONFormatter{
|
||||
TimestampFormat: "2006-01-02 15:04:05",
|
||||
DisableTimestamp: true,
|
||||
DisableHTMLEscape: true,
|
||||
DataKey: "ExtInfo",
|
||||
})
|
||||
r.logrus.AddHook(r)
|
||||
}
|
||||
return r.logrus
|
||||
}
|
||||
|
||||
func (r *PortForwardsRule) GetLogsBuffer() *logsbuffer.LogsBuffer {
|
||||
if r.logsBuffer == nil {
|
||||
r.logsBuffer = logsbuffer.CreateLogbuffer("portforward:"+r.Key, r.AccessLogMaxNum)
|
||||
}
|
||||
return r.logsBuffer
|
||||
}
|
||||
|
||||
func (r *PortForwardsRule) StopAllProxys() {
|
||||
if r.ReverseProxyList == nil {
|
||||
return
|
||||
}
|
||||
for i := range *r.ReverseProxyList {
|
||||
(*r.ReverseProxyList)[i].StopProxy()
|
||||
}
|
||||
}
|
||||
|
||||
// TidyReverseProxyCache 整理端口转发日志缓存
|
||||
func TidyPortforwardLogsCache() {
|
||||
ruleList := GetPortForwardsRuleList()
|
||||
var keyListBuffer strings.Builder
|
||||
for _, rule := range ruleList {
|
||||
keyListBuffer.WriteString(rule.Key)
|
||||
keyListBuffer.WriteString(",")
|
||||
}
|
||||
|
||||
keyListStr := keyListBuffer.String()
|
||||
logsbuffer.LogsBufferStoreMu.Lock()
|
||||
defer logsbuffer.LogsBufferStoreMu.Unlock()
|
||||
|
||||
var needDeleteKeys []string
|
||||
|
||||
for k := range logsbuffer.LogsBufferStore {
|
||||
if !strings.HasPrefix(k, "portforward:") {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(k) <= 13 {
|
||||
continue
|
||||
}
|
||||
|
||||
if !strings.Contains(keyListStr, k[12:]) {
|
||||
needDeleteKeys = append(needDeleteKeys, k)
|
||||
}
|
||||
}
|
||||
|
||||
for i := range needDeleteKeys {
|
||||
delete(logsbuffer.LogsBufferStore, needDeleteKeys[i])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (r *PortForwardsRule) InitProxyList() error {
|
||||
listenPorts, err := PortsStrToIList(r.ListenPorts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
targetPorts, err := PortsStrToIList(r.TargetPorts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(listenPorts) != len(targetPorts) {
|
||||
return fmt.Errorf("端口个数不一致")
|
||||
}
|
||||
var proxyList []socketproxy.Proxy
|
||||
for i := range r.ForwardTypes {
|
||||
for j := range listenPorts {
|
||||
p, err := socketproxy.CreateProxy(r.GetLogrus(), r.ForwardTypes[i],
|
||||
r.ListenAddress,
|
||||
r.TargetAddressList,
|
||||
listenPorts[j],
|
||||
targetPorts[j],
|
||||
&r.Options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
proxyList = append(proxyList, p)
|
||||
}
|
||||
}
|
||||
|
||||
r.ReverseProxyList = &proxyList
|
||||
return nil
|
||||
}
|
||||
|
||||
func PortsCheck(ports1Str, ports2Str string) (bool, error) {
|
||||
ports1, err := PortsStrToIList(ports1Str)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
ports2, err := PortsStrToIList(ports2Str)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if len(ports1) != len(ports2) {
|
||||
return false, fmt.Errorf("端口个数不一致")
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// portsStrToIList
|
||||
func PortsStrToIList(portsStr string) (ports []int, err error) {
|
||||
if portsStr == "" {
|
||||
return
|
||||
}
|
||||
if strings.Contains(portsStr, ",") {
|
||||
tmpStrList := strings.Split(portsStr, ",")
|
||||
for i := range tmpStrList {
|
||||
tps, e := PortsStrToIList(tmpStrList[i])
|
||||
if e != nil {
|
||||
err = fmt.Errorf("端口字符串处理出错:%s", e.Error())
|
||||
return
|
||||
}
|
||||
ports = append(ports, tps...)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
portsStrList := strings.Split(portsStr, "-")
|
||||
if len(portsStrList) > 2 {
|
||||
err = fmt.Errorf("端口%s格式有误", portsStr)
|
||||
return
|
||||
}
|
||||
|
||||
if len(portsStrList) == 1 { //single listen port
|
||||
listenPort, e := portStrToi(portsStrList[0])
|
||||
if e != nil {
|
||||
err = fmt.Errorf("端口格式有误!%s", e.Error())
|
||||
return
|
||||
}
|
||||
ports = append(ports, listenPort)
|
||||
}
|
||||
|
||||
if len(portsStrList) == 2 {
|
||||
minListenPort, e := portStrToi(portsStrList[0])
|
||||
if e != nil {
|
||||
err = fmt.Errorf("端口格式有误!%s", portsStrList[0])
|
||||
return
|
||||
}
|
||||
maxListenPort, e := portStrToi(portsStrList[1])
|
||||
if e != nil {
|
||||
err = fmt.Errorf("端口格式有误!%s", portsStrList[1])
|
||||
return
|
||||
}
|
||||
|
||||
if maxListenPort <= minListenPort {
|
||||
err = fmt.Errorf("前一个端口[%d]要小于后一个端口[%d]", minListenPort, maxListenPort)
|
||||
return
|
||||
}
|
||||
i := minListenPort
|
||||
for {
|
||||
if i > maxListenPort {
|
||||
break
|
||||
}
|
||||
ports = append(ports, i)
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func portStrToi(portStr string) (int, error) {
|
||||
port, err := strconv.Atoi(portStr)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("端口格式有误:%s", err.Error())
|
||||
}
|
||||
if port < 1 || port > 65535 {
|
||||
return 0, fmt.Errorf("端口[%d]超出范围", port)
|
||||
}
|
||||
return port, nil
|
||||
}
|
||||
|
||||
func PortForwardsRuleListInit() {
|
||||
programConfigureMutex.RLock()
|
||||
defer programConfigureMutex.RUnlock()
|
||||
var err error
|
||||
for i := range programConfigure.PortForwardsRuleList {
|
||||
err = programConfigure.PortForwardsRuleList[i].InitProxyList()
|
||||
if err != nil {
|
||||
log.Printf("InitProxyList error:%s\n", err.Error())
|
||||
}
|
||||
if programConfigure.PortForwardsRuleList[i].Enable {
|
||||
programConfigure.PortForwardsRuleList[i].StartAllProxys()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func GetPortForwardsRuleList() []PortForwardsRule {
|
||||
programConfigureMutex.RLock()
|
||||
defer programConfigureMutex.RUnlock()
|
||||
|
||||
var resList []PortForwardsRule
|
||||
|
||||
for i := range programConfigure.PortForwardsRuleList {
|
||||
r := programConfigure.PortForwardsRuleList[i]
|
||||
resList = append(resList, r)
|
||||
}
|
||||
return resList
|
||||
}
|
||||
|
||||
func GetPortForwardsGlobalProxyCount() int {
|
||||
programConfigureMutex.RLock()
|
||||
defer programConfigureMutex.RUnlock()
|
||||
count := 0
|
||||
for i := range programConfigure.PortForwardsRuleList {
|
||||
count += programConfigure.PortForwardsRuleList[i].ProxyCount()
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
func GetPortForwardsGlobalProxyCountExcept(key string) int {
|
||||
programConfigureMutex.RLock()
|
||||
defer programConfigureMutex.RUnlock()
|
||||
count := 0
|
||||
for i := range programConfigure.PortForwardsRuleList {
|
||||
if key == programConfigure.PortForwardsRuleList[i].Key {
|
||||
continue
|
||||
}
|
||||
count += programConfigure.PortForwardsRuleList[i].ProxyCount()
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
func GetPortForwardsRuleByKey(key string) *PortForwardsRule {
|
||||
programConfigureMutex.RLock()
|
||||
defer programConfigureMutex.RUnlock()
|
||||
index := -1
|
||||
|
||||
for i := range programConfigure.PortForwardsRuleList {
|
||||
if programConfigure.PortForwardsRuleList[i].Key == key {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if index == -1 {
|
||||
return nil
|
||||
}
|
||||
res := programConfigure.PortForwardsRuleList[index]
|
||||
return &res
|
||||
}
|
||||
|
||||
func StopAllSocketProxysByRuleKey(key string) error {
|
||||
programConfigureMutex.RLock()
|
||||
defer programConfigureMutex.RUnlock()
|
||||
index := -1
|
||||
|
||||
for i := range programConfigure.PortForwardsRuleList {
|
||||
if programConfigure.PortForwardsRuleList[i].Key == key {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if index == -1 {
|
||||
return fmt.Errorf("找不到key:%s对应的规则", key)
|
||||
}
|
||||
programConfigure.PortForwardsRuleList[index].StopAllProxys()
|
||||
return nil
|
||||
}
|
||||
|
||||
func StartAllSocketProxysByRuleKey(key string) error {
|
||||
programConfigureMutex.RLock()
|
||||
defer programConfigureMutex.RUnlock()
|
||||
index := -1
|
||||
|
||||
for i := range programConfigure.PortForwardsRuleList {
|
||||
if programConfigure.PortForwardsRuleList[i].Key == key {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if index == -1 {
|
||||
return fmt.Errorf("找不到key:%s对应的规则", key)
|
||||
}
|
||||
programConfigure.PortForwardsRuleList[index].StartAllProxys()
|
||||
return nil
|
||||
}
|
||||
|
||||
func PortForwardsRuleListAdd(r *PortForwardsRule) error {
|
||||
programConfigureMutex.Lock()
|
||||
defer programConfigureMutex.Unlock()
|
||||
r.Enable = true
|
||||
programConfigure.PortForwardsRuleList = append(programConfigure.PortForwardsRuleList, *r)
|
||||
return Save()
|
||||
}
|
||||
|
||||
func PortForwardsRuleListDelete(key string) error {
|
||||
programConfigureMutex.Lock()
|
||||
defer programConfigureMutex.Unlock()
|
||||
|
||||
index := -1
|
||||
|
||||
for i := range programConfigure.PortForwardsRuleList {
|
||||
if programConfigure.PortForwardsRuleList[i].Key == key {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if index == -1 {
|
||||
return fmt.Errorf("找不到需要删除的端口转发规则")
|
||||
}
|
||||
|
||||
programConfigure.PortForwardsRuleList[index].StopAllProxys()
|
||||
|
||||
programConfigure.PortForwardsRuleList = DeletePortForwardsRuleListSlice(programConfigure.PortForwardsRuleList, index)
|
||||
return Save()
|
||||
}
|
||||
|
||||
func EnablePortForwardsRuleByKey(key string, enable bool) error {
|
||||
programConfigureMutex.Lock()
|
||||
defer programConfigureMutex.Unlock()
|
||||
index := -1
|
||||
|
||||
for i := range programConfigure.DDNSTaskList {
|
||||
if programConfigure.PortForwardsRuleList[i].Key == key {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if index == -1 {
|
||||
return fmt.Errorf("开关端口转发规则失败,key查找失败")
|
||||
}
|
||||
|
||||
if enable {
|
||||
programConfigure.PortForwardsRuleList[index].StartAllProxys()
|
||||
} else {
|
||||
programConfigure.PortForwardsRuleList[index].StopAllProxys()
|
||||
}
|
||||
|
||||
programConfigure.PortForwardsRuleList[index].Enable = enable
|
||||
return Save()
|
||||
}
|
||||
|
||||
func UpdatePortForwardsRuleToPortForwardsRuleList(key string, r *PortForwardsRule) error {
|
||||
programConfigureMutex.Lock()
|
||||
defer programConfigureMutex.Unlock()
|
||||
index := -1
|
||||
|
||||
for i := range programConfigure.PortForwardsRuleList {
|
||||
if programConfigure.PortForwardsRuleList[i].Key == key {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if index == -1 {
|
||||
return fmt.Errorf("找不到需要更新的端口转发规则")
|
||||
}
|
||||
|
||||
programConfigure.PortForwardsRuleList[index] = *r
|
||||
return Save()
|
||||
}
|
||||
|
||||
func DeletePortForwardsRuleListSlice(a []PortForwardsRule, deleteIndex int) []PortForwardsRule {
|
||||
j := 0
|
||||
for i := range a {
|
||||
if i != deleteIndex {
|
||||
a[j] = a[i]
|
||||
j++
|
||||
}
|
||||
}
|
||||
return a[:j]
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
|
@ -19,30 +20,11 @@ import (
|
|||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var reverseProxyLogsStore map[string]*logsbuffer.LogsBuffer
|
||||
var reverseProxyLogsStoreMu sync.Mutex
|
||||
|
||||
var reverseProxyServerStore sync.Map
|
||||
var reverseProxyServerStoreMu sync.Mutex
|
||||
|
||||
func init() {
|
||||
reverseProxyLogsStore = make(map[string]*logsbuffer.LogsBuffer)
|
||||
}
|
||||
|
||||
func CreateReverseProxyLogbuffer(key string, buffSize int) *logsbuffer.LogsBuffer {
|
||||
reverseProxyLogsStoreMu.Lock()
|
||||
defer reverseProxyLogsStoreMu.Unlock()
|
||||
var buf *logsbuffer.LogsBuffer
|
||||
var ok bool
|
||||
if buf, ok = reverseProxyLogsStore[key]; !ok {
|
||||
buf = &logsbuffer.LogsBuffer{}
|
||||
buf.SetBufferSize(buffSize)
|
||||
reverseProxyLogsStore[key] = buf
|
||||
} else if buf.GetBufferSize() != buffSize {
|
||||
buf.SetBufferSize(buffSize)
|
||||
}
|
||||
|
||||
return buf
|
||||
}
|
||||
|
||||
// TidyReverseProxyCache 整理反向代理日志缓存
|
||||
|
@ -59,18 +41,26 @@ func TidyReverseProxyCache() {
|
|||
}
|
||||
|
||||
keyListStr := keyListBuffer.String()
|
||||
reverseProxyLogsStoreMu.Lock()
|
||||
defer reverseProxyLogsStoreMu.Unlock()
|
||||
logsbuffer.LogsBufferStoreMu.Lock()
|
||||
defer logsbuffer.LogsBufferStoreMu.Unlock()
|
||||
|
||||
var needDeleteKeys []string
|
||||
for k := range reverseProxyLogsStore {
|
||||
if !strings.Contains(keyListStr, k) {
|
||||
for k := range logsbuffer.LogsBufferStore {
|
||||
if !strings.HasPrefix(k, "reverseproxy:") {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(k) <= 13 {
|
||||
continue
|
||||
}
|
||||
|
||||
if !strings.Contains(keyListStr, k[13:]) {
|
||||
needDeleteKeys = append(needDeleteKeys, k)
|
||||
}
|
||||
}
|
||||
|
||||
for i := range needDeleteKeys {
|
||||
delete(reverseProxyLogsStore, needDeleteKeys[i])
|
||||
delete(logsbuffer.LogsBufferStore, needDeleteKeys[i])
|
||||
reverseProxyServerStore.Delete(needDeleteKeys[i])
|
||||
}
|
||||
|
||||
|
@ -85,12 +75,11 @@ type SubReverProxyRule struct {
|
|||
locationsCount int `json:"-"`
|
||||
locationIndex uint64 `json:"-"`
|
||||
|
||||
EnableAccessLog bool `json:"EnableAccessLog"` //开启日志
|
||||
LogLevel int `json:"LogLevel"` //日志输出级别
|
||||
LogOutputToConsole bool `json:"LogOutputToConsole"` //日志输出到终端
|
||||
AccessLogMaxNum int `json:"AccessLogMaxNum"` //最大条数
|
||||
WebListShowLastLogMaxCount int `json:"WebListShowLastLogMaxCount"` //前端列表显示最新日志最大条数
|
||||
RequestInfoLogFormat string `json:"RequestInfoLogFormat"` //请求信息在日志中的格式
|
||||
EnableAccessLog bool `json:"EnableAccessLog"` //开启日志
|
||||
LogLevel int `json:"LogLevel"` //日志输出级别
|
||||
LogOutputToConsole bool `json:"LogOutputToConsole"` //日志输出到终端
|
||||
AccessLogMaxNum int `json:"AccessLogMaxNum"` //最大条数
|
||||
WebListShowLastLogMaxCount int `json:"WebListShowLastLogMaxCount"` //前端列表显示最新日志最大条数
|
||||
|
||||
ForwardedByClientIP bool `json:"ForwardedByClientIP"`
|
||||
TrustedCIDRsStrList []string `json:"TrustedCIDRsStrList"`
|
||||
|
@ -163,12 +152,13 @@ func (r *SubReverProxyRule) Logf(level logrus.Level, c *gin.Context, format stri
|
|||
}).Logf(level, format, v...)
|
||||
}
|
||||
|
||||
func (r *SubReverProxyRule) HandlerReverseProxy(remote *url.URL, path string, c *gin.Context) {
|
||||
func (r *SubReverProxyRule) HandlerReverseProxy(remote *url.URL, host, path string, c *gin.Context) {
|
||||
|
||||
proxy := httputil.NewSingleHostReverseProxy(remote)
|
||||
proxy.Director = func(req *http.Request) {
|
||||
req.Header = c.Request.Header
|
||||
req.Host = remote.Host
|
||||
req.Host = host //remote.Host
|
||||
//req.Host = remote.Host
|
||||
req.URL.Scheme = remote.Scheme
|
||||
req.URL.Host = remote.Host
|
||||
req.URL.Path = path
|
||||
|
@ -182,21 +172,23 @@ func (r *SubReverProxyRule) HandlerReverseProxy(remote *url.URL, path string, c
|
|||
|
||||
}
|
||||
|
||||
func (r *SubReverProxyRule) PrintfToConsole(entry *logrus.Entry) error {
|
||||
func (r *SubReverProxyRule) Fire(entry *logrus.Entry) error {
|
||||
if !r.LogOutputToConsole {
|
||||
return nil
|
||||
}
|
||||
|
||||
s, _ := entry.String()
|
||||
log.Print(s)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *SubReverProxyRule) Levels() []logrus.Level {
|
||||
return logrus.AllLevels
|
||||
}
|
||||
|
||||
func (r *SubReverProxyRule) GetLogrus() *logrus.Logger {
|
||||
if r.logrus == nil {
|
||||
r.logrus = logrus.New()
|
||||
r.logrus.SetLevel(logrus.Level(r.LogLevel))
|
||||
r.GetLogsBuffer().SetFireCallback(r.PrintfToConsole)
|
||||
r.logrus.SetOutput(r.GetLogsBuffer())
|
||||
r.logrus.SetFormatter(&logrus.JSONFormatter{
|
||||
TimestampFormat: "2006-01-02 15:04:05",
|
||||
|
@ -204,8 +196,7 @@ func (r *SubReverProxyRule) GetLogrus() *logrus.Logger {
|
|||
DisableHTMLEscape: true,
|
||||
DataKey: "ExtInfo",
|
||||
})
|
||||
|
||||
r.logrus.AddHook(r.GetLogsBuffer())
|
||||
r.logrus.AddHook(r)
|
||||
|
||||
}
|
||||
return r.logrus
|
||||
|
@ -220,7 +211,7 @@ func (r *SubReverProxyRule) GetLogger() *log.Logger {
|
|||
|
||||
func (r *SubReverProxyRule) GetLogsBuffer() *logsbuffer.LogsBuffer {
|
||||
if r.logsBuffer == nil {
|
||||
r.logsBuffer = CreateReverseProxyLogbuffer(r.Key, r.AccessLogMaxNum)
|
||||
r.logsBuffer = logsbuffer.CreateLogbuffer("reverseproxy:"+r.Key, r.AccessLogMaxNum)
|
||||
}
|
||||
return r.logsBuffer
|
||||
}
|
||||
|
@ -313,7 +304,7 @@ func (r *ReverseProxyRule) ReverseProxyHandler(c *gin.Context) {
|
|||
c.JSON(http.StatusBadGateway, gin.H{"ret": 1, "msg": fmt.Sprintf("后端地址[%s] 转换出错:%s", location, err.Error())})
|
||||
return
|
||||
}
|
||||
subRule.HandlerReverseProxy(remote, path, c)
|
||||
subRule.HandlerReverseProxy(remote, hostName, path, c)
|
||||
|
||||
}
|
||||
|
||||
|
@ -390,6 +381,18 @@ func (r *ReverseProxyRule) ServerStart() error {
|
|||
Handler: ginR,
|
||||
}
|
||||
|
||||
//***************************
|
||||
var err error
|
||||
server.TLSConfig = &tls.Config{}
|
||||
|
||||
if r.EnableTLS {
|
||||
certList := GetValidSSLCertficateList()
|
||||
server.TLSConfig.Certificates = certList
|
||||
}
|
||||
//server.TLSConfig.Certificates = make([]tls.Certificate, 3)
|
||||
|
||||
//****************************
|
||||
|
||||
ln, err := net.Listen(r.Network, r.Addr())
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -398,14 +401,26 @@ func (r *ReverseProxyRule) ServerStart() error {
|
|||
var serveResult error
|
||||
|
||||
go func() {
|
||||
serveResult = server.Serve(ln)
|
||||
|
||||
if !r.EnableTLS {
|
||||
serveResult = server.Serve(ln)
|
||||
return
|
||||
}
|
||||
|
||||
if len(server.TLSConfig.Certificates) <= 0 {
|
||||
log.Printf("可用证书列表为空,%s 未能启用TLS", r.Addr())
|
||||
serveResult = server.Serve(ln)
|
||||
return
|
||||
}
|
||||
log.Printf("%s 已启用TLS", r.Addr())
|
||||
serveResult = server.ServeTLS(ln, "", "")
|
||||
|
||||
}()
|
||||
|
||||
<-time.After(time.Millisecond * 300)
|
||||
|
||||
defer func() {
|
||||
if serveResult == nil {
|
||||
//setPreReverseProxyHttpServer(r.RuleKey, r.server)
|
||||
r.SetServer(server)
|
||||
}
|
||||
}()
|
||||
|
@ -561,7 +576,7 @@ type LogItem struct {
|
|||
}
|
||||
|
||||
// 2006-01-02 15:04:05
|
||||
func ReverseProxyLogConvert(lg *logsbuffer.LogItem) any {
|
||||
func WebLogConvert(lg *logsbuffer.LogItem) any {
|
||||
l := LogItem{
|
||||
LogContent: lg.Content,
|
||||
LogTime: time.Unix(lg.Timestamp/int64(time.Second), 0).Format("2006-01-02 15:04:05")}
|
||||
|
@ -570,11 +585,11 @@ func ReverseProxyLogConvert(lg *logsbuffer.LogItem) any {
|
|||
|
||||
func (r *ReverseProxyRule) GetLastLogs() map[string][]any {
|
||||
res := make(map[string][]any)
|
||||
res["default"] = r.DefaultProxy.GetLogsBuffer().GetLastLogs(ReverseProxyLogConvert, r.DefaultProxy.WebListShowLastLogMaxCount)
|
||||
res["default"] = r.DefaultProxy.GetLogsBuffer().GetLastLogs(WebLogConvert, r.DefaultProxy.WebListShowLastLogMaxCount)
|
||||
|
||||
for i := range r.ProxyList {
|
||||
res[r.ProxyList[i].Key] = r.ProxyList[i].GetLogsBuffer().GetLastLogs(
|
||||
ReverseProxyLogConvert, r.ProxyList[i].WebListShowLastLogMaxCount)
|
||||
WebLogConvert, r.ProxyList[i].WebListShowLastLogMaxCount)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
@ -601,6 +616,7 @@ func GetReverseProxyRuleByKey(ruleKey string) *ReverseProxyRule {
|
|||
ruleIndex := -1
|
||||
|
||||
for i := range programConfigure.ReverseProxyRuleList {
|
||||
|
||||
if programConfigure.ReverseProxyRuleList[i].RuleKey == ruleKey {
|
||||
ruleIndex = i
|
||||
break
|
||||
|
@ -609,6 +625,7 @@ func GetReverseProxyRuleByKey(ruleKey string) *ReverseProxyRule {
|
|||
if ruleIndex == -1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
res := programConfigure.ReverseProxyRuleList[ruleIndex]
|
||||
return &res
|
||||
}
|
||||
|
@ -635,7 +652,7 @@ func ReverseProxyRuleListDelete(ruleKey string) error {
|
|||
}
|
||||
|
||||
if ruleIndex == -1 {
|
||||
return fmt.Errorf("找不到需要删除的DDNS任务")
|
||||
return fmt.Errorf("找不到需要删除的反向代理任务")
|
||||
}
|
||||
|
||||
programConfigure.ReverseProxyRuleList = DeleteReverseProxyRuleListlice(programConfigure.ReverseProxyRuleList, ruleIndex)
|
||||
|
@ -647,7 +664,7 @@ func EnableReverseProxyRuleByKey(ruleKey string, enable bool) error {
|
|||
defer programConfigureMutex.Unlock()
|
||||
ruleIndex := -1
|
||||
|
||||
for i := range programConfigure.DDNSTaskList {
|
||||
for i := range programConfigure.ReverseProxyRuleList {
|
||||
if programConfigure.ReverseProxyRuleList[i].RuleKey == ruleKey {
|
||||
ruleIndex = i
|
||||
break
|
||||
|
@ -666,7 +683,7 @@ func EnableReverseProxySubRule(ruleKey, proxyKey string, enable bool) error {
|
|||
defer programConfigureMutex.Unlock()
|
||||
ruleIndex := -1
|
||||
|
||||
for i := range programConfigure.DDNSTaskList {
|
||||
for i := range programConfigure.ReverseProxyRuleList {
|
||||
if programConfigure.ReverseProxyRuleList[i].RuleKey == ruleKey {
|
||||
ruleIndex = i
|
||||
break
|
||||
|
@ -699,7 +716,7 @@ func UpdateReverseProxyRulet(rule ReverseProxyRule) error {
|
|||
defer programConfigureMutex.Unlock()
|
||||
ruleIndex := -1
|
||||
|
||||
for i := range programConfigure.DDNSTaskList {
|
||||
for i := range programConfigure.ReverseProxyRuleList {
|
||||
if programConfigure.ReverseProxyRuleList[i].RuleKey == rule.RuleKey {
|
||||
ruleIndex = i
|
||||
break
|
||||
|
|
|
@ -0,0 +1,289 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gdy666/lucky/thirdlib/gdylib/stringsp"
|
||||
)
|
||||
|
||||
type SSLCertficate struct {
|
||||
Key string `json:"Key"`
|
||||
Enable bool `json:"Enable"`
|
||||
Remark string `json:"Remark"` //备注
|
||||
CertBase64 string `json:"CertBase64"`
|
||||
KeyBase64 string `json:"KeyBase64"`
|
||||
AddTime string `json:"AddTime"` //添加时间
|
||||
CertsInfo *[]CertInfo `json:"-"`
|
||||
//---------------------
|
||||
Certificate *tls.Certificate `json:"-"`
|
||||
}
|
||||
|
||||
func (s *SSLCertficate) Init() error {
|
||||
tc, err := CreateX509KeyPairByBase64Str(s.CertBase64, s.KeyBase64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("CreateX509KeyPairByBase64Str error:%s", err.Error())
|
||||
}
|
||||
domainsInfo, err := GetCertDomainInfo(tc)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetCertDomainInfo error:%s", err.Error())
|
||||
}
|
||||
s.Certificate = tc
|
||||
s.CertsInfo = domainsInfo
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetOnlyDomain 返回证书第一条域名
|
||||
func (s *SSLCertficate) GetFirstDomain() string {
|
||||
if s.CertsInfo == nil {
|
||||
return ""
|
||||
}
|
||||
if len(*s.CertsInfo) <= 0 {
|
||||
return ""
|
||||
}
|
||||
if len((*s.CertsInfo)[0].Domains) <= 0 {
|
||||
return ""
|
||||
}
|
||||
return (*s.CertsInfo)[0].Domains[0]
|
||||
}
|
||||
|
||||
func CreateX509KeyPairByBase64Str(certBase64, keyBase64 string) (*tls.Certificate, error) {
|
||||
crtBytes, err := base64.StdEncoding.DecodeString(certBase64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("certBase64 decode error:%s", err.Error())
|
||||
}
|
||||
|
||||
keyBytes, err := base64.StdEncoding.DecodeString(keyBase64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("keyBase64 decode error:%s", err.Error())
|
||||
}
|
||||
|
||||
cert, err := tls.X509KeyPair(crtBytes, keyBytes)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create X509KeyPair error:%s", err.Error())
|
||||
}
|
||||
return &cert, nil
|
||||
}
|
||||
|
||||
type CertInfo struct {
|
||||
Domains []string
|
||||
NotBeforeTime string `json:"NotBeforeTime"` //time.Time
|
||||
NotAfterTime string `json:"NotAfterTime"` //time.Time
|
||||
}
|
||||
|
||||
func GetCertDomainInfo(cert *tls.Certificate) (*[]CertInfo, error) {
|
||||
if cert == nil {
|
||||
return nil, fmt.Errorf("cert == nil")
|
||||
}
|
||||
|
||||
var res []CertInfo
|
||||
|
||||
for i := range cert.Certificate {
|
||||
xx, err := x509.ParseCertificate(cert.Certificate[i])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
ds := GetDomainsTrimSpace(xx.DNSNames)
|
||||
if len(ds) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
info := CertInfo{Domains: ds, NotBeforeTime: xx.NotBefore.Format("2006-01-02 15:04:05"), NotAfterTime: xx.NotAfter.Format("2006-01-02 15:04:05")}
|
||||
res = append(res, info)
|
||||
}
|
||||
return &res, nil
|
||||
|
||||
}
|
||||
|
||||
func GetCertDomains(cert *tls.Certificate) []string {
|
||||
var res []string
|
||||
if cert == nil {
|
||||
return res
|
||||
}
|
||||
for i := range cert.Certificate {
|
||||
xx, err := x509.ParseCertificate(cert.Certificate[i])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
for j := range xx.DNSNames {
|
||||
d := strings.TrimSpace(xx.DNSNames[j])
|
||||
if d == "" {
|
||||
continue
|
||||
}
|
||||
res = append(res, d)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// 除去空域名
|
||||
func GetDomainsTrimSpace(dst []string) []string {
|
||||
var res []string
|
||||
for i := range dst {
|
||||
if strings.TrimSpace(dst[i]) == "" {
|
||||
continue
|
||||
}
|
||||
res = append(res, strings.TrimSpace(dst[i]))
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func GetDomainsStrByDomains(dst []string) string {
|
||||
var res strings.Builder
|
||||
for i := range dst {
|
||||
d := strings.TrimSpace(dst[i])
|
||||
if d == "" {
|
||||
continue
|
||||
}
|
||||
if res.Len() > 0 {
|
||||
res.WriteString(",")
|
||||
}
|
||||
res.WriteString(d)
|
||||
}
|
||||
return res.String()
|
||||
}
|
||||
|
||||
//---------------------------------
|
||||
|
||||
func SSLCertficateListInit() {
|
||||
programConfigureMutex.RLock()
|
||||
defer programConfigureMutex.RUnlock()
|
||||
var err error
|
||||
for i := range programConfigure.SSLCertficateList {
|
||||
err = programConfigure.SSLCertficateList[i].Init()
|
||||
if err != nil {
|
||||
log.Printf("SSLCertficateListInit [%s]err:%s", programConfigure.SSLCertficateList[i].Key, err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func GetSSLCertficateList() []SSLCertficate {
|
||||
programConfigureMutex.RLock()
|
||||
defer programConfigureMutex.RUnlock()
|
||||
var res []SSLCertficate
|
||||
if programConfigure == nil {
|
||||
return res
|
||||
}
|
||||
|
||||
for i := range programConfigure.SSLCertficateList {
|
||||
res = append(res, programConfigure.SSLCertficateList[i])
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func SSLCertficateListAdd(s *SSLCertficate) error {
|
||||
programConfigureMutex.Lock()
|
||||
defer programConfigureMutex.Unlock()
|
||||
|
||||
//************
|
||||
//重复检测
|
||||
for i := range programConfigure.SSLCertficateList {
|
||||
if programConfigure.SSLCertficateList[i].CertBase64 == s.CertBase64 {
|
||||
return fmt.Errorf("绑定域名[%s]的相同证书已存在,请勿重复添加", (*s.CertsInfo)[0].Domains[0])
|
||||
}
|
||||
|
||||
if programConfigure.SSLCertficateList[i].GetFirstDomain() != "" &&
|
||||
programConfigure.SSLCertficateList[i].GetFirstDomain() == s.GetFirstDomain() {
|
||||
return fmt.Errorf("绑定域名[%s]的证书已存在,如果要添加新证书请先手动删除旧证书", (*s.CertsInfo)[0].Domains[0])
|
||||
}
|
||||
}
|
||||
|
||||
//************
|
||||
|
||||
if s.Key == "" {
|
||||
s.Key = stringsp.GetRandomString(8)
|
||||
}
|
||||
s.AddTime = time.Now().Format("2006-01-02 15:04:05")
|
||||
s.Enable = true
|
||||
programConfigure.SSLCertficateList = append(programConfigure.SSLCertficateList, *s)
|
||||
return Save()
|
||||
}
|
||||
|
||||
func SSLCertficateListDelete(key string) error {
|
||||
programConfigureMutex.Lock()
|
||||
defer programConfigureMutex.Unlock()
|
||||
deleteIndex := -1
|
||||
|
||||
for i := range programConfigure.SSLCertficateList {
|
||||
if programConfigure.SSLCertficateList[i].Key == key {
|
||||
deleteIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if deleteIndex < 0 {
|
||||
return fmt.Errorf("key:%s 不存在", key)
|
||||
}
|
||||
programConfigure.SSLCertficateList = DeleteSSLCertficateListslice(programConfigure.SSLCertficateList, deleteIndex)
|
||||
return Save()
|
||||
}
|
||||
|
||||
func SSLCertficateEnable(key string, enable bool) error {
|
||||
programConfigureMutex.Lock()
|
||||
defer programConfigureMutex.Unlock()
|
||||
index := -1
|
||||
for i := range programConfigure.SSLCertficateList {
|
||||
if programConfigure.SSLCertficateList[i].Key == key {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if index < 0 {
|
||||
return fmt.Errorf("key:%s 不存在", key)
|
||||
}
|
||||
programConfigure.SSLCertficateList[index].Enable = enable
|
||||
return Save()
|
||||
}
|
||||
|
||||
func SSLCertficateAlterRemark(key, remark string) error {
|
||||
programConfigureMutex.Lock()
|
||||
defer programConfigureMutex.Unlock()
|
||||
index := -1
|
||||
for i := range programConfigure.SSLCertficateList {
|
||||
if programConfigure.SSLCertficateList[i].Key == key {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if index < 0 {
|
||||
return fmt.Errorf("key:%s 不存在", key)
|
||||
}
|
||||
programConfigure.SSLCertficateList[index].Remark = remark
|
||||
return Save()
|
||||
}
|
||||
|
||||
func DeleteSSLCertficateListslice(a []SSLCertficate, deleteIndex int) []SSLCertficate {
|
||||
j := 0
|
||||
for i := range a {
|
||||
if i != deleteIndex {
|
||||
a[j] = a[i]
|
||||
j++
|
||||
}
|
||||
}
|
||||
return a[:j]
|
||||
}
|
||||
|
||||
func GetValidSSLCertficateList() []tls.Certificate {
|
||||
var res []tls.Certificate
|
||||
var gdnRes []tls.Certificate
|
||||
sslListCache := GetSSLCertficateList()
|
||||
for _, s := range sslListCache {
|
||||
if !s.Enable {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(s.GetFirstDomain(), "*.") {
|
||||
gdnRes = append(gdnRes, *s.Certificate)
|
||||
continue
|
||||
}
|
||||
res = append(res, *s.Certificate)
|
||||
}
|
||||
res = append(res, gdnRes...)
|
||||
|
||||
return res
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gdy666/lucky/thirdlib/gdylib/netinterfaces"
|
||||
"github.com/gdy666/lucky/thirdlib/gdylib/stringsp"
|
||||
"github.com/gdy666/lucky/thirdlib/go-wol"
|
||||
)
|
||||
|
||||
type WOLDevice struct {
|
||||
Key string
|
||||
DeviceName string
|
||||
MacList []string
|
||||
BroadcastIPs []string
|
||||
Port int
|
||||
Relay bool //交给中继设备发送
|
||||
Repeat int //重复发送次数
|
||||
}
|
||||
|
||||
func (d *WOLDevice) WakeUp() error {
|
||||
return WakeOnLan(d.MacList, d.BroadcastIPs, d.Port, d.Repeat)
|
||||
}
|
||||
|
||||
func WakeOnLan(macList []string, broadcastIps []string, port, repeat int) (err error) {
|
||||
globalBroadcastList := netinterfaces.GetGlobalIPv4BroadcastList()
|
||||
matchCount := 0
|
||||
|
||||
defer func() {
|
||||
if matchCount <= 0 {
|
||||
err = fmt.Errorf("找不到匹配的局域网广播IP,未能发送唤醒指令")
|
||||
}
|
||||
}()
|
||||
|
||||
if len(broadcastIps) > 0 {
|
||||
for _, bcst := range broadcastIps {
|
||||
bcstOk := stringsp.StrIsInList(bcst, globalBroadcastList)
|
||||
if !bcstOk {
|
||||
continue
|
||||
}
|
||||
matchCount++
|
||||
for _, mac := range macList {
|
||||
wol.WakeUpRepeat(mac, bcst, "", port, repeat)
|
||||
}
|
||||
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
for _, bcst := range globalBroadcastList {
|
||||
matchCount++
|
||||
for _, mac := range macList {
|
||||
wol.WakeUpRepeat(mac, bcst, "", port, repeat)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
func GetWOLDeviceByKey(key string) *WOLDevice {
|
||||
programConfigureMutex.Lock()
|
||||
defer programConfigureMutex.Unlock()
|
||||
index := -1
|
||||
|
||||
for i := range programConfigure.WOLDeviceList {
|
||||
if programConfigure.WOLDeviceList[i].Key == key {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if index < 0 {
|
||||
return nil
|
||||
}
|
||||
device := programConfigure.WOLDeviceList[index]
|
||||
return &device
|
||||
|
||||
}
|
||||
|
||||
func GetWOLDeviceList() []WOLDevice {
|
||||
programConfigureMutex.RLock()
|
||||
defer programConfigureMutex.RUnlock()
|
||||
var res []WOLDevice
|
||||
if programConfigure == nil {
|
||||
return res
|
||||
}
|
||||
|
||||
for i := range programConfigure.WOLDeviceList {
|
||||
res = append(res, programConfigure.WOLDeviceList[i])
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func WOLDeviceListAdd(d *WOLDevice) error {
|
||||
programConfigureMutex.Lock()
|
||||
defer programConfigureMutex.Unlock()
|
||||
|
||||
if d.Key == "" {
|
||||
d.Key = stringsp.GetRandomString(8)
|
||||
}
|
||||
programConfigure.WOLDeviceList = append(programConfigure.WOLDeviceList, *d)
|
||||
return Save()
|
||||
}
|
||||
|
||||
func WOLDeviceListAlter(d *WOLDevice) error {
|
||||
programConfigureMutex.Lock()
|
||||
defer programConfigureMutex.Unlock()
|
||||
index := -1
|
||||
for i := range programConfigure.WOLDeviceList {
|
||||
if programConfigure.WOLDeviceList[i].Key == d.Key {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if index < 0 {
|
||||
return fmt.Errorf("key:%s 不存在", d.Key)
|
||||
}
|
||||
programConfigure.WOLDeviceList[index] = *d
|
||||
return Save()
|
||||
}
|
||||
|
||||
func WOLDeviceListDelete(key string) error {
|
||||
programConfigureMutex.Lock()
|
||||
defer programConfigureMutex.Unlock()
|
||||
deleteIndex := -1
|
||||
|
||||
for i := range programConfigure.WOLDeviceList {
|
||||
if programConfigure.WOLDeviceList[i].Key == key {
|
||||
deleteIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if deleteIndex < 0 {
|
||||
return fmt.Errorf("key:%s 不存在", key)
|
||||
}
|
||||
programConfigure.WOLDeviceList = DeleteWOLDeviceListslice(programConfigure.WOLDeviceList, deleteIndex)
|
||||
return Save()
|
||||
}
|
||||
|
||||
func DeleteWOLDeviceListslice(a []WOLDevice, deleteIndex int) []WOLDevice {
|
||||
j := 0
|
||||
for i := range a {
|
||||
if i != deleteIndex {
|
||||
a[j] = a[i]
|
||||
j++
|
||||
}
|
||||
}
|
||||
return a[:j]
|
||||
}
|
|
@ -161,8 +161,9 @@ func getDomainItem(fullDomain string, domains *[]ddnscore.Domain) *ddnscore.Doma
|
|||
|
||||
func (d *DNSCommon) CreateHTTPClient() (*http.Client, error) {
|
||||
ddnsGlobalConf := config.GetDDNSConfigure()
|
||||
|
||||
return httputils.CreateHttpClient(
|
||||
"tcp",
|
||||
d.task.DNS.GetCallAPINetwork(),
|
||||
"",
|
||||
!ddnsGlobalConf.HttpClientSecureVerify,
|
||||
d.task.DNS.HttpClientProxyType,
|
||||
|
|
|
@ -2,7 +2,6 @@ package ddns
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/gdy666/lucky/ddnscore.go"
|
||||
|
@ -142,12 +141,17 @@ func (dnspod *Dnspod) modify(result DnspodRecordListResp, domain *ddnscore.Domai
|
|||
|
||||
// 公共
|
||||
func (dnspod *Dnspod) commonRequest(apiAddr string, values url.Values, domain *ddnscore.Domain) (status DnspodStatus, err error) {
|
||||
resp, e := http.PostForm(
|
||||
client, e := dnspod.CreateHTTPClient()
|
||||
if e != nil {
|
||||
err = e
|
||||
return
|
||||
}
|
||||
resp, e := client.PostForm(
|
||||
apiAddr,
|
||||
values,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
if e != nil {
|
||||
err = e
|
||||
return
|
||||
}
|
||||
|
|
14
go.mod
14
go.mod
|
@ -3,15 +3,17 @@ module github.com/gdy666/lucky
|
|||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/buger/jsonparser v1.1.1
|
||||
github.com/eclipse/paho.mqtt.golang v1.4.1
|
||||
github.com/fatedier/golib v0.2.0
|
||||
github.com/gin-contrib/gzip v0.0.6
|
||||
github.com/gin-gonic/gin v1.8.1
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||
github.com/guonaihong/gout v0.3.1
|
||||
github.com/miekg/dns v1.1.50
|
||||
github.com/shirou/gopsutil/v3 v3.22.8
|
||||
github.com/shirou/gopsutil/v3 v3.22.9
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
golang.org/x/net v0.0.0-20220921203646-d300de134e69
|
||||
golang.org/x/net v0.0.0-20221004154528-8021a29435af
|
||||
)
|
||||
|
||||
require (
|
||||
|
@ -21,6 +23,7 @@ require (
|
|||
github.com/go-playground/universal-translator v0.18.0 // indirect
|
||||
github.com/go-playground/validator/v10 v10.11.1 // indirect
|
||||
github.com/goccy/go-json v0.9.11 // indirect
|
||||
github.com/gorilla/websocket v1.4.2 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/leodido/go-urn v1.2.1 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c // indirect
|
||||
|
@ -34,10 +37,11 @@ require (
|
|||
github.com/tklauser/numcpus v0.5.0 // indirect
|
||||
github.com/ugorji/go/codec v1.2.7 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20221010152910-d6f0a8c073c2 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde // indirect
|
||||
golang.org/x/sys v0.0.0-20221010170243-090e33056c14 // indirect
|
||||
golang.org/x/text v0.3.8 // indirect
|
||||
golang.org/x/tools v0.1.12 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
|
|
31
go.sum
31
go.sum
|
@ -1,7 +1,11 @@
|
|||
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
|
||||
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/eclipse/paho.mqtt.golang v1.4.1 h1:tUSpviiL5G3P9SZZJPC4ZULZJsxQKXxfENpMvdbAXAI=
|
||||
github.com/eclipse/paho.mqtt.golang v1.4.1/go.mod h1:JGt0RsEwEX+Xa/agj90YJ9d9DH2b7upDZMK9HRbFvCA=
|
||||
github.com/fatedier/golib v0.2.0 h1:8BxiUcjleBlXBYlTNUllD8KZZHaFU/NP/vP0Yu1Fkpg=
|
||||
github.com/fatedier/golib v0.2.0/go.mod h1:e2NPpBGUFsHDjXrfP1B5aK3S0+yUeVxgqfc3go3KNj0=
|
||||
github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
|
||||
|
@ -30,11 +34,12 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS
|
|||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/guonaihong/gout v0.3.1 h1:pj/44Jw0TTmcHF2RjMaCWhKPwCH98YuQejbN15Hts/o=
|
||||
github.com/guonaihong/gout v0.3.1/go.mod h1:lhje0jRkh/gcIogrG22ENPITo9tylQa3kwD9eVxcDrk=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
|
@ -76,8 +81,8 @@ github.com/power-devops/perfstat v0.0.0-20220216144756-c35f1ee13d7c/go.mod h1:Om
|
|||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||
github.com/shirou/gopsutil/v3 v3.22.8 h1:a4s3hXogo5mE2PfdfJIonDbstO/P+9JszdfhAHSzD9Y=
|
||||
github.com/shirou/gopsutil/v3 v3.22.8/go.mod h1:s648gW4IywYzUfE/KjXxUsqrqx/T2xO5VqOXxONeRfI=
|
||||
github.com/shirou/gopsutil/v3 v3.22.9 h1:yibtJhIVEMcdw+tCTbOPiF1VcsuDeTE4utJ8Dm4c5eA=
|
||||
github.com/shirou/gopsutil/v3 v3.22.9/go.mod h1:bBYl1kjgEJpWpxeHmLI+dVHWtyAwfcmSBLDsp2TNT8A=
|
||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
|
@ -104,26 +109,29 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
|||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0 h1:a5Yg6ylndHHYJqIPrdq0AhvR6KTvDTAvgBtaidhEevY=
|
||||
golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20221010152910-d6f0a8c073c2 h1:x8vtB3zMecnlqZIwJNUUpwYKYSqCz5jXbiyv0ZJJZeI=
|
||||
golang.org/x/crypto v0.0.0-20221010152910-d6f0a8c073c2/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20190228165749-92fc7df08ae7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220921203646-d300de134e69 h1:hUJpGDpnfwdJW8iNypFjmSY0sCBEL+spFTZ2eO+Sfps=
|
||||
golang.org/x/net v0.0.0-20220921203646-d300de134e69/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.0.0-20221004154528-8021a29435af h1:wv66FM3rLZGPdxpYL+ApnDe2HzHcTFta3z5nsc13wI4=
|
||||
golang.org/x/net v0.0.0-20221004154528-8021a29435af/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
|
||||
golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde h1:ejfdSekXMDxDLbRrJMwUk6KnSLZ2McaUCVcIKM+N6jc=
|
||||
golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -137,14 +145,15 @@ golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 h1:h+EGohizhe9XlX18rfpa8k8RAc5XyaeamM+0VHRd4lc=
|
||||
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20221010170243-090e33056c14 h1:k5II8e6QD8mITdi+okbbmR/cIyEbeXLBhy5Ha4nevyc=
|
||||
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
|
|
92
main.go
92
main.go
|
@ -13,18 +13,11 @@ import (
|
|||
"github.com/gdy666/lucky/config"
|
||||
"github.com/gdy666/lucky/ddns"
|
||||
"github.com/gdy666/lucky/reverseproxy"
|
||||
"github.com/gdy666/lucky/rule"
|
||||
"github.com/gdy666/lucky/socketproxy"
|
||||
)
|
||||
|
||||
var (
|
||||
listenPort = flag.Int("p", 16601, "http Admin Web listen port ")
|
||||
pcl = flag.Int64("pcl", -1, "global proxy count limit")
|
||||
gpmc = flag.Int64("gpmc", -1, "global proxy max connections,default(1024)")
|
||||
udpPackageSize = flag.Int("ups", socketproxy.UDP_DEFAULT_PACKAGE_SIZE, "udp package max size")
|
||||
smc = flag.Int64("smc", socketproxy.TCPUDP_DEFAULT_SINGLE_PROXY_MAX_CONNECTIONS, "signle proxy max connections,default(128)")
|
||||
upm = flag.Bool("upm", true, "udp proxy Performance Mode open")
|
||||
udpshort = flag.Bool("udpshort", false, "udp short mode,eg dns")
|
||||
configureFileURL = flag.String("c", "", "configure file url")
|
||||
)
|
||||
|
||||
|
@ -50,7 +43,7 @@ func main() {
|
|||
if err != nil {
|
||||
log.Printf("%s", err.Error())
|
||||
log.Printf("载入默认配置以及命令行设定的参数")
|
||||
config.LoadDefault(*pcl, *listenPort, *gpmc)
|
||||
config.LoadDefault(*listenPort)
|
||||
if len(*configureFileURL) > 0 {
|
||||
err = config.Save()
|
||||
if err != nil {
|
||||
|
@ -63,39 +56,31 @@ func main() {
|
|||
|
||||
config.BlackListInit()
|
||||
config.WhiteListInit()
|
||||
config.SSLCertficateListInit()
|
||||
|
||||
//fmt.Printf("*gcf:%v\n", *gcf)
|
||||
|
||||
socketproxy.SetSafeCheck(config.SafeCheck)
|
||||
socketproxy.SetGlobalMaxConnections(gcf.BaseConfigure.GlobalMaxConnections)
|
||||
socketproxy.SetGlobalMaxProxyCount(gcf.BaseConfigure.ProxyCountLimit)
|
||||
//socketproxy.SetGlobalMaxConnections(gcf.BaseConfigure.GlobalMaxConnections)
|
||||
//socketproxy.SetGlobalMaxProxyCount(gcf.BaseConfigure.ProxyCountLimit)
|
||||
config.SetRunMode(runMode)
|
||||
config.SetVersion(version)
|
||||
log.Printf("RunMode:%s\n", runMode)
|
||||
log.Printf("version:%s\tcommit %s, built at %s\n", version, commit, date)
|
||||
RunAdminWeb(gcf.BaseConfigure.AdminWebListenPort, gcf.BaseConfigure.LogMaxSize)
|
||||
|
||||
RunAdminWeb(&gcf.BaseConfigure)
|
||||
|
||||
runTime = time.Now()
|
||||
|
||||
// if *upm {
|
||||
// log.Printf("udp proxy Performance Mode open ")
|
||||
// }
|
||||
//LoadRuleFromConfigFile(gcf)
|
||||
|
||||
//log.Printf("Gobal proxy max connections:[%d] single proxy max connections:[%d]\n", base.GetGlobalMaxConnections(), base.GetSingleProxyMaxConnections(smc))
|
||||
|
||||
if len(flag.Args()) > 0 {
|
||||
LoadRuleListFromCMD(flag.Args())
|
||||
}
|
||||
|
||||
LoadRuleFromConfigFile(gcf)
|
||||
|
||||
rule.EnableAllRelayRule() //开启规则
|
||||
config.PortForwardsRuleListInit()
|
||||
|
||||
//config.DDNSTaskListTaskDetailsInit()
|
||||
config.DDNSTaskListConfigureCheck()
|
||||
ddnsConf := config.GetDDNSConfigure()
|
||||
if ddnsConf.Enable {
|
||||
ddns.Run(time.Duration(ddnsConf.FirstCheckDelay)*time.Second, time.Duration(ddnsConf.Intervals)*time.Second)
|
||||
go ddns.Run(time.Duration(ddnsConf.FirstCheckDelay)*time.Second, time.Duration(ddnsConf.Intervals)*time.Second)
|
||||
}
|
||||
|
||||
reverseproxy.InitReverseProxyServer()
|
||||
|
@ -123,43 +108,24 @@ func main() {
|
|||
<-exit
|
||||
}
|
||||
|
||||
func LoadRuleListFromCMD(args []string) {
|
||||
options := socketproxy.RelayRuleOptions{UDPPackageSize: *udpPackageSize,
|
||||
SingleProxyMaxConnections: *smc,
|
||||
UDPProxyPerformanceMode: *upm,
|
||||
UDPShortMode: *udpshort}
|
||||
// func LoadRuleFromConfigFile(pc *config.ProgramConfigure) {
|
||||
// if pc == nil {
|
||||
// return
|
||||
// }
|
||||
// for i := range pc.RelayRuleList {
|
||||
// relayRule, err := rule.CreateRuleByConfigureAndOptions(
|
||||
// pc.RelayRuleList[i].Name,
|
||||
// pc.RelayRuleList[i].Configurestr,
|
||||
// pc.RelayRuleList[i].Options)
|
||||
// if err != nil {
|
||||
// continue
|
||||
// }
|
||||
// relayRule.From = "configureFile" //规则来源
|
||||
// relayRule.IsEnable = pc.RelayRuleList[i].Enable
|
||||
|
||||
relayRules, err := rule.GetRelayRulesFromCMD(flag.Args(), &options)
|
||||
if err != nil {
|
||||
log.Print("config.GetRelayRulesFromCMD err:", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
_, e := rule.AddRuleToGlobalRuleList(false, (*relayRules)...)
|
||||
if e != nil {
|
||||
log.Printf("%s\n", e)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func LoadRuleFromConfigFile(pc *config.ProgramConfigure) {
|
||||
if pc == nil {
|
||||
return
|
||||
}
|
||||
for i := range pc.RelayRuleList {
|
||||
relayRule, err := rule.CreateRuleByConfigureAndOptions(
|
||||
pc.RelayRuleList[i].Name,
|
||||
pc.RelayRuleList[i].Configurestr,
|
||||
pc.RelayRuleList[i].Options)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
relayRule.From = "configureFile" //规则来源
|
||||
relayRule.IsEnable = pc.RelayRuleList[i].Enable
|
||||
|
||||
_, e := rule.AddRuleToGlobalRuleList(false, *relayRule)
|
||||
if e != nil {
|
||||
log.Printf("%s\n", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
// _, e := rule.AddRuleToGlobalRuleList(false, *relayRule)
|
||||
// if e != nil {
|
||||
// log.Printf("%s\n", e)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 41 KiB |
Binary file not shown.
After Width: | Height: | Size: 75 KiB |
|
@ -71,6 +71,6 @@ func GetAccessLogs(ruleKey, proxyKey string, pageSize, page int) (int, []any) {
|
|||
if subRule == nil {
|
||||
return 0, res
|
||||
}
|
||||
total, res = subRule.GetLogsBuffer().GetLogsByLimit(config.ReverseProxyLogConvert, pageSize, page)
|
||||
total, res = subRule.GetLogsBuffer().GetLogsByLimit(config.WebLogConvert, pageSize, page)
|
||||
return total, res
|
||||
}
|
||||
|
|
264
rule/global.go
264
rule/global.go
|
@ -1,264 +0,0 @@
|
|||
// Copyright 2022 gdy, 272288813@qq.com
|
||||
package rule
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/gdy666/lucky/config"
|
||||
"github.com/gdy666/lucky/socketproxy"
|
||||
)
|
||||
|
||||
var globalRelayRules *[]RelayRule
|
||||
var globalRelayRulesMutex sync.RWMutex
|
||||
|
||||
func SetGlobalRelayRules(rl *[]RelayRule) {
|
||||
globalRelayRulesMutex.Lock()
|
||||
defer globalRelayRulesMutex.Unlock()
|
||||
globalRelayRules = rl
|
||||
syncRuleListToConfigure()
|
||||
}
|
||||
|
||||
func AddRuleToGlobalRuleList(sync bool, rl ...RelayRule) (string, error) {
|
||||
globalRelayRulesMutex.Lock()
|
||||
defer globalRelayRulesMutex.Unlock()
|
||||
|
||||
var err error
|
||||
|
||||
if globalRelayRules == nil {
|
||||
var rrl []RelayRule
|
||||
globalRelayRules = &rrl
|
||||
}
|
||||
|
||||
for i := range rl {
|
||||
isExits := false
|
||||
for j := range *globalRelayRules {
|
||||
if (*globalRelayRules)[j].MainConfigure == rl[i].MainConfigure {
|
||||
isExits = true
|
||||
if err == nil {
|
||||
err = fmt.Errorf("\n\t规则[%s]已存在,不再重复加入规则列表", rl[i].MainConfigure)
|
||||
} else {
|
||||
err = fmt.Errorf("%s\n\t规则[%s]已存在,不再重复加入规则列表", err.Error(), rl[i].MainConfigure)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if !isExits {
|
||||
*globalRelayRules = append(*globalRelayRules, rl[i])
|
||||
if rl[i].From != "cmd" && sync {
|
||||
syncRes := ""
|
||||
if syncErr := syncRuleListToConfigure(); syncErr != nil {
|
||||
syncRes = syncErr.Error()
|
||||
}
|
||||
return syncRes, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "", err
|
||||
}
|
||||
|
||||
func AlterRuleInGlobalRuleListByKey(key string, rule *RelayRule) (bool, error) {
|
||||
globalRelayRulesMutex.Lock()
|
||||
defer globalRelayRulesMutex.Unlock()
|
||||
|
||||
keyIndex := -1
|
||||
|
||||
for i := range *globalRelayRules {
|
||||
if (*globalRelayRules)[i].MainConfigure != key {
|
||||
continue
|
||||
}
|
||||
keyIndex = i
|
||||
break
|
||||
}
|
||||
|
||||
if keyIndex < 0 {
|
||||
return true, fmt.Errorf("修改转发规则失败,规则[%s]不存在", key)
|
||||
}
|
||||
|
||||
(*globalRelayRules)[keyIndex].Disable()
|
||||
(*globalRelayRules)[keyIndex] = *rule
|
||||
|
||||
syncErr := syncRuleListToConfigure()
|
||||
syncSuccess := true
|
||||
if syncErr != nil {
|
||||
syncSuccess = false
|
||||
}
|
||||
|
||||
return syncSuccess, nil
|
||||
}
|
||||
|
||||
func DeleteGlobalRuleByKey(key string) (bool, error) {
|
||||
globalRelayRulesMutex.Lock()
|
||||
defer globalRelayRulesMutex.Unlock()
|
||||
|
||||
if globalRelayRules == nil {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
deleteIndex := -1
|
||||
|
||||
for i := range *globalRelayRules {
|
||||
if (*globalRelayRules)[i].MainConfigure == key {
|
||||
deleteIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if deleteIndex < 0 {
|
||||
return true, fmt.Errorf("relayRule[%s]no found,delete failed", key)
|
||||
}
|
||||
*globalRelayRules = DeleteRuleSlice(*globalRelayRules, deleteIndex)
|
||||
|
||||
syncError := syncRuleListToConfigure()
|
||||
syncSuccess := true
|
||||
if syncError != nil {
|
||||
syncSuccess = false
|
||||
}
|
||||
|
||||
return syncSuccess, nil
|
||||
}
|
||||
|
||||
func GetRuleByMainConfigure(configStr string) *RelayRule {
|
||||
globalRelayRulesMutex.RLock()
|
||||
defer globalRelayRulesMutex.RUnlock()
|
||||
if globalRelayRules == nil {
|
||||
return nil
|
||||
}
|
||||
for i := range *globalRelayRules {
|
||||
//fmt.Printf("MainConfigure %s:::%s\n", (*globalRelayRules)[i].MainConfigure, configStr)
|
||||
if (*globalRelayRules)[i].MainConfigure == configStr {
|
||||
r := (*globalRelayRules)[i]
|
||||
return &r
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetGlobalEnableProxyCount() int64 {
|
||||
globalRelayRulesMutex.RLock()
|
||||
defer globalRelayRulesMutex.RUnlock()
|
||||
|
||||
if globalRelayRules == nil {
|
||||
return 0
|
||||
}
|
||||
count := int64(0)
|
||||
for _, r := range *globalRelayRules {
|
||||
if !r.IsEnable {
|
||||
continue
|
||||
}
|
||||
if r.proxyList == nil {
|
||||
continue
|
||||
}
|
||||
count += int64(len(*r.proxyList))
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
// func StartAllProxy() {
|
||||
// allProxyListMutex.Lock()
|
||||
// defer allProxyListMutex.Unlock()
|
||||
// if allProxyList == nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
// for _, p := range *allProxyList {
|
||||
// go p.StartProxy()
|
||||
// }
|
||||
// }
|
||||
|
||||
func EnableAllRelayRule() error {
|
||||
globalRelayRulesMutex.RLock()
|
||||
defer globalRelayRulesMutex.RUnlock()
|
||||
var err error
|
||||
|
||||
if globalRelayRules == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for i := range *globalRelayRules {
|
||||
if GetGlobalEnableProxyCount()+(*globalRelayRules)[i].GetProxyCount() <= socketproxy.GetGlobalMaxProxyCount() {
|
||||
if (*globalRelayRules)[i].From == "cmd" || ((*globalRelayRules)[i].From == "configureFile" && (*globalRelayRules)[i].IsEnable) {
|
||||
(*globalRelayRules)[i].Enable()
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if GetGlobalEnableProxyCount()+(*globalRelayRules)[i].GetProxyCount() > socketproxy.DEFAULT_MAX_PROXY_COUNT {
|
||||
if err == nil {
|
||||
err = fmt.Errorf("\n\t超出代理数最大限制,规则[%s]未启用", (*globalRelayRules)[i].MainConfigure)
|
||||
} else {
|
||||
err = fmt.Errorf("%s\n\t超出代理数最大限制,规则[%s]未启用", err.Error(), (*globalRelayRules)[i].MainConfigure)
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func EnableRelayRuleByKey(key string) (*RelayRule, bool, error) {
|
||||
globalRelayRulesMutex.RLock()
|
||||
defer globalRelayRulesMutex.RUnlock()
|
||||
|
||||
for i := range *globalRelayRules {
|
||||
if (*globalRelayRules)[i].MainConfigure == key {
|
||||
(*globalRelayRules)[i].Enable()
|
||||
syncErr := syncRuleListToConfigure()
|
||||
synsSuccess := true
|
||||
if syncErr != nil {
|
||||
synsSuccess = false
|
||||
}
|
||||
|
||||
return &(*globalRelayRules)[i], synsSuccess, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, true, fmt.Errorf("规则[%s]不存在,开启失败", key)
|
||||
}
|
||||
|
||||
func DisableRelayRuleByKey(key string) (*RelayRule, bool, error) {
|
||||
globalRelayRulesMutex.RLock()
|
||||
defer globalRelayRulesMutex.RUnlock()
|
||||
|
||||
for i := range *globalRelayRules {
|
||||
if (*globalRelayRules)[i].MainConfigure == key {
|
||||
(*globalRelayRules)[i].Disable()
|
||||
syncErr := syncRuleListToConfigure()
|
||||
synsSuccess := true
|
||||
if syncErr != nil {
|
||||
synsSuccess = false
|
||||
}
|
||||
return &(*globalRelayRules)[i], synsSuccess, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, true, fmt.Errorf("规则[%s]不存在,停用失败", key)
|
||||
}
|
||||
|
||||
func DeleteRuleSlice(a []RelayRule, deleteIndex int) []RelayRule {
|
||||
j := 0
|
||||
for i := range a {
|
||||
if i != deleteIndex {
|
||||
a[j] = a[i]
|
||||
j++
|
||||
}
|
||||
}
|
||||
return a[:j]
|
||||
}
|
||||
|
||||
// syncRuleListToConfigure 同步规则列表到配置
|
||||
func syncRuleListToConfigure() error {
|
||||
var ruleList []config.ConfigureRelayRule
|
||||
for i := range *globalRelayRules {
|
||||
if (*globalRelayRules)[i].From == "cmd" {
|
||||
continue
|
||||
}
|
||||
rule := config.ConfigureRelayRule{
|
||||
Name: (*globalRelayRules)[i].Name,
|
||||
Configurestr: (*globalRelayRules)[i].MainConfigure,
|
||||
Enable: (*globalRelayRules)[i].IsEnable,
|
||||
Options: (*globalRelayRules)[i].Options}
|
||||
ruleList = append(ruleList, rule)
|
||||
}
|
||||
config.SetConfigRuleList(&ruleList)
|
||||
return config.Save()
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
// Copyright 2022 gdy, 272288813@qq.com
|
||||
package rule
|
||||
|
||||
import "github.com/gdy666/lucky/socketproxy"
|
||||
|
||||
type RelayRuleProxyInfo struct {
|
||||
Proxy string `json:"Proxy"`
|
||||
CurrentConnections int64 `json:"CurrentConnections"`
|
||||
TrafficIn int64 `json:"TrafficIn"`
|
||||
TrafficOut int64 `json:"TrafficOut"`
|
||||
}
|
||||
|
||||
func GetRelayRuleList() (*[]RelayRule, map[string][]RelayRuleProxyInfo) {
|
||||
globalRelayRulesMutex.RLock()
|
||||
defer globalRelayRulesMutex.RUnlock()
|
||||
var rl []RelayRule
|
||||
proxyInfoMap := make(map[string][]RelayRuleProxyInfo)
|
||||
if globalRelayRules == nil {
|
||||
return &rl, proxyInfoMap
|
||||
}
|
||||
|
||||
for i := range *globalRelayRules {
|
||||
rl = append(rl, (*globalRelayRules)[i])
|
||||
var rpl []RelayRuleProxyInfo
|
||||
if (*globalRelayRules)[i].proxyList == nil {
|
||||
proxyInfoMap[(*globalRelayRules)[i].MainConfigure] = rpl
|
||||
continue
|
||||
}
|
||||
for pindex := range *(*globalRelayRules)[i].proxyList {
|
||||
pi := RelayRuleProxyInfo{
|
||||
Proxy: (*(*globalRelayRules)[i].proxyList)[pindex].GetKey(),
|
||||
CurrentConnections: (*(*globalRelayRules)[i].proxyList)[pindex].GetCurrentConnections(),
|
||||
TrafficIn: (*(*globalRelayRules)[i].proxyList)[pindex].GetTrafficIn(),
|
||||
TrafficOut: (*(*globalRelayRules)[i].proxyList)[pindex].GetTrafficOut()}
|
||||
rpl = append(rpl, pi)
|
||||
}
|
||||
proxyInfoMap[(*globalRelayRules)[i].MainConfigure] = rpl
|
||||
}
|
||||
|
||||
return &rl, proxyInfoMap
|
||||
}
|
||||
|
||||
//GetAllProxyInfo
|
||||
// func GetAllProxyInfo() map[string]interface{} {
|
||||
// allProxyListMutex.Lock()
|
||||
// defer allProxyListMutex.Unlock()
|
||||
// info := make(map[string]interface{})
|
||||
// if allProxyList == nil {
|
||||
// return info
|
||||
// }
|
||||
// for _, p := range *allProxyList {
|
||||
// pi := GetProxyInfo(p)
|
||||
// info[p.GetKey()] = pi
|
||||
// }
|
||||
|
||||
// return info
|
||||
// }
|
||||
|
||||
func GetProxyInfo(p socketproxy.Proxy) map[string]string {
|
||||
pi := make(map[string]string)
|
||||
pi["proxyType"] = p.GetProxyType()
|
||||
pi["key"] = p.GetKey()
|
||||
pi["status"] = p.GetStatus()
|
||||
pi["fromRule"] = p.FromRule()
|
||||
return pi
|
||||
}
|
|
@ -1,546 +0,0 @@
|
|||
// Copyright 2022 gdy, 272288813@qq.com
|
||||
package rule
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gdy666/lucky/socketproxy"
|
||||
)
|
||||
|
||||
type RelayRule struct {
|
||||
Name string `json:"Name"`
|
||||
MainConfigure string `json:"Mainconfigure"`
|
||||
RelayType string `json:"RelayType"`
|
||||
ListenIP string `json:"ListenIP"`
|
||||
ListenPorts string `json:"ListenPorts"`
|
||||
TargetIP string `json:"TargetIP"`
|
||||
TargetPorts string `json:"TargetPorts"`
|
||||
BalanceTargetAddressList []string `json:"BalanceTargetAddressList"`
|
||||
Options socketproxy.RelayRuleOptions `json:"Options"`
|
||||
SubRuleList []SubRelayRule `json:"SubRuleList"`
|
||||
From string `json:"From"`
|
||||
IsEnable bool `json:"Enable"`
|
||||
proxyList *[]socketproxy.Proxy `json:"-"`
|
||||
}
|
||||
|
||||
type SubRelayRule struct {
|
||||
ProxyType string `json:"ProxyType"`
|
||||
BindIP string `json:"BindIP"`
|
||||
ListenPorts []int `json:"ListenPorts"`
|
||||
TargetHost string `json:"TargetHost"`
|
||||
TargetPorts []int `json:"TargetPorts"`
|
||||
BalanceTargetAddressAddress []string `json:"BalanceTargetAddressAddress"`
|
||||
}
|
||||
|
||||
func (r *RelayRule) Enable() {
|
||||
r.IsEnable = true
|
||||
if r.proxyList == nil {
|
||||
return
|
||||
}
|
||||
for _, p := range *r.proxyList {
|
||||
p.StartProxy()
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RelayRule) GetProxyCount() int64 {
|
||||
if r.proxyList == nil {
|
||||
return 0
|
||||
}
|
||||
return int64(len(*r.proxyList))
|
||||
}
|
||||
|
||||
func (r *RelayRule) Disable() {
|
||||
r.IsEnable = false
|
||||
if r.proxyList == nil {
|
||||
return
|
||||
}
|
||||
for _, p := range *r.proxyList {
|
||||
p.StopProxy()
|
||||
}
|
||||
}
|
||||
|
||||
func GetRelayRulesFromCMD(configureList []string, options *socketproxy.RelayRuleOptions) (relayRules *[]RelayRule, err error) {
|
||||
//proxyMap := make(map[string]socketproxy.Proxy)
|
||||
|
||||
var relayRuleList []RelayRule
|
||||
|
||||
for _, configure := range configureList {
|
||||
|
||||
relayRule, err := CreateRuleByConfigureAndOptions("", configure, *options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
relayRule.From = "cmd" //规则来源
|
||||
|
||||
relayRuleList = append(relayRuleList, *relayRule)
|
||||
}
|
||||
|
||||
return &relayRuleList, nil
|
||||
}
|
||||
|
||||
func (r *RelayRule) CreateMainConfigure() (configure string) {
|
||||
if len(r.BalanceTargetAddressList) > 0 {
|
||||
configure = fmt.Sprintf("%s@%s:%sto%s", r.RelayType, r.ListenIP, r.ListenPorts, strings.Join(r.BalanceTargetAddressList, "|"))
|
||||
} else {
|
||||
if strings.Compare(r.ListenPorts, r.TargetPorts) == 0 {
|
||||
configure = fmt.Sprintf("%s@%s:%sto%s", r.RelayType, r.ListenIP, r.ListenPorts, r.TargetIP)
|
||||
} else {
|
||||
configure = fmt.Sprintf("%s@%s:%sto%s:%s", r.RelayType, r.ListenIP, r.ListenPorts, r.TargetIP, r.TargetPorts)
|
||||
}
|
||||
}
|
||||
return configure
|
||||
}
|
||||
|
||||
func CreateRuleByConfigureAndOptions(name, configureStr string, options socketproxy.RelayRuleOptions) (rule *RelayRule, err error) {
|
||||
var r RelayRule
|
||||
r.Options = options
|
||||
r.SubRuleList, r.RelayType, r.ListenIP, r.ListenPorts, r.TargetIP, r.TargetPorts, r.BalanceTargetAddressList, err = createSubRuleListFromConfigure(configureStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r.MainConfigure = r.CreateMainConfigure()
|
||||
|
||||
// if len(r.BalanceTargetAddressList) > 0 {
|
||||
// r.MainConfigure = fmt.Sprintf("%s@%s:%sto%s", r.RelayType, r.ListenIP, r.ListenPorts, strings.Join(r.BalanceTargetAddressList, ","))
|
||||
// } else {
|
||||
// if strings.Compare(r.ListenPorts, r.TargetPorts) == 0 {
|
||||
// r.MainConfigure = fmt.Sprintf("%s@%s:%sto%s", r.RelayType, r.ListenIP, r.ListenPorts, r.TargetIP)
|
||||
// } else {
|
||||
// r.MainConfigure = fmt.Sprintf("%s@%s:%sto%s:%s", r.RelayType, r.ListenIP, r.ListenPorts, r.TargetIP, r.TargetPorts)
|
||||
// }
|
||||
// }
|
||||
|
||||
var pl []socketproxy.Proxy
|
||||
|
||||
for i := range r.SubRuleList {
|
||||
if len(r.BalanceTargetAddressList) == 0 {
|
||||
for j := range r.SubRuleList[i].ListenPorts {
|
||||
p, e := socketproxy.CreateProxy(r.SubRuleList[i].ProxyType,
|
||||
r.SubRuleList[i].BindIP,
|
||||
r.SubRuleList[i].TargetHost,
|
||||
nil,
|
||||
r.SubRuleList[i].ListenPorts[j],
|
||||
r.SubRuleList[i].TargetPorts[j],
|
||||
&options)
|
||||
if e != nil {
|
||||
log.Printf("CreateProxy error:%s", e.Error())
|
||||
continue
|
||||
}
|
||||
p.SetFromRule(r.MainConfigure)
|
||||
pl = append(pl, p)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
p, e := socketproxy.CreateProxy(r.SubRuleList[i].ProxyType,
|
||||
r.SubRuleList[i].BindIP,
|
||||
r.SubRuleList[i].TargetHost,
|
||||
&r.BalanceTargetAddressList,
|
||||
r.SubRuleList[i].ListenPorts[0],
|
||||
0,
|
||||
&options)
|
||||
if e != nil {
|
||||
log.Printf("CreateProxy error:%s", e.Error())
|
||||
continue
|
||||
}
|
||||
p.SetFromRule(r.MainConfigure)
|
||||
pl = append(pl, p)
|
||||
|
||||
}
|
||||
|
||||
r.proxyList = &pl
|
||||
|
||||
r.Name = name
|
||||
|
||||
return &r, nil
|
||||
}
|
||||
|
||||
func createSubRuleListFromConfigure(str string) (subRelyList []SubRelayRule, proxytypeListStr, listenIP, listenPortsStr, targetIP, targetePortsStr string, targetAddressList []string, err error) {
|
||||
//log.Printf("ConfigureStr:%s\n", str)
|
||||
splitRes := strings.Split(str, "@")
|
||||
if len(splitRes) > 2 {
|
||||
err = fmt.Errorf("relay参数:%s格式有误!000", str)
|
||||
return
|
||||
}
|
||||
|
||||
proxytypeListStr = "tcp,udp"
|
||||
|
||||
relayConfig := splitRes[0]
|
||||
|
||||
if len(splitRes) == 2 {
|
||||
proxytypeListStr = splitRes[0]
|
||||
relayConfig = splitRes[1]
|
||||
}
|
||||
|
||||
proxyTypeList := getProxyTypeList(proxytypeListStr)
|
||||
err = checkProxyType(proxyTypeList)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
proxytypeListStr = convertProxyTypeByList(proxyTypeList)
|
||||
|
||||
relayConfigArray := strings.Split(relayConfig, "to")
|
||||
if len(relayConfigArray) > 2 {
|
||||
err = fmt.Errorf("relay参数:%s格式有误!001", str)
|
||||
return
|
||||
}
|
||||
|
||||
var listenPorts []int
|
||||
var targetPorts []int
|
||||
|
||||
switch len(relayConfigArray) {
|
||||
case 1: //监听端口没有指定 比如 192.168.31.22:80,443,20000-20010
|
||||
tip, tPortsStr, e := getIpAndPortFromAddress(relayConfigArray[0], true, true)
|
||||
if e != nil {
|
||||
err = fmt.Errorf("参数中目标地址部分参数[%s]格式有误", relayConfigArray[0])
|
||||
return
|
||||
}
|
||||
|
||||
targetPorts, e = portsStrToIList(tPortsStr)
|
||||
if e != nil {
|
||||
err = fmt.Errorf("参数[%s]中的目标端口部分出错:%s", str, e.Error())
|
||||
return
|
||||
}
|
||||
targetePortsStr = tPortsStr
|
||||
listenPortsStr = tPortsStr
|
||||
listenPorts = targetPorts
|
||||
targetIP = tip
|
||||
|
||||
case 2: //监听端口有指定 比如 80,443,20000-20010to192.168.31.222 ,但目标地址的端口不一定指定
|
||||
bindAddress := relayConfigArray[0]
|
||||
bip, bPortsStr, e := getIpAndPortFromAddress(bindAddress, false, false)
|
||||
if e != nil {
|
||||
err = fmt.Errorf("参数[%s]中的监听端口部分出错:%s", str, e.Error())
|
||||
return
|
||||
}
|
||||
listenIP = bip
|
||||
|
||||
listenPortsStr = bPortsStr
|
||||
//fmt.Printf("bip:%s bindPortsStr:%s\n", bip, bindPortsStr)
|
||||
|
||||
listenPorts, e = portsStrToIList(bPortsStr)
|
||||
if e != nil {
|
||||
err = fmt.Errorf("参数中绑定端口部分参数[%s]格式有误", bPortsStr)
|
||||
return
|
||||
}
|
||||
|
||||
//log.Printf("relayConfigArray[1]:\t[%s]", relayConfigArray[1])
|
||||
|
||||
if strings.Contains(relayConfigArray[1], "|") { //均衡负载模式
|
||||
if len(listenPorts) != 1 {
|
||||
err = fmt.Errorf("均衡负载模式一条配置指定监听一个端口")
|
||||
return
|
||||
}
|
||||
targetAddressList = strings.Split(relayConfigArray[1], "|")
|
||||
|
||||
} else {
|
||||
targetAddress := relayConfigArray[1]
|
||||
|
||||
tip, tPortsStr, e := getIpAndPortFromAddress(targetAddress, true, false)
|
||||
if e != nil {
|
||||
err = fmt.Errorf("参数中目标地址部分参数[%s]格式有误", targetAddress)
|
||||
return
|
||||
}
|
||||
targetePortsStr = tPortsStr
|
||||
|
||||
targetPorts, e = portsStrToIList(tPortsStr)
|
||||
|
||||
if e != nil {
|
||||
err = fmt.Errorf("参数[%s]中的目标端口部分出错:%s", str, e.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if len(listenPorts) > 0 && len(targetPorts) == 0 {
|
||||
targetPorts = listenPorts
|
||||
targetePortsStr = listenPortsStr
|
||||
} else if len(listenPorts) == 0 && len(targetPorts) > 0 {
|
||||
listenPorts = targetPorts
|
||||
listenPortsStr = targetePortsStr
|
||||
}
|
||||
|
||||
if len(listenPorts) != len(targetPorts) {
|
||||
err = fmt.Errorf("参数[%s]中监听端口数量和目标端口数量不一致", str)
|
||||
|
||||
// fmt.Printf("listenPorts:%v\n", listenPorts)
|
||||
// fmt.Printf("targetPorts:%v\n", targetPorts)
|
||||
return
|
||||
}
|
||||
targetIP = tip
|
||||
}
|
||||
|
||||
default:
|
||||
|
||||
}
|
||||
|
||||
var SubBaseRule SubRelayRule
|
||||
SubBaseRule.BindIP = listenIP
|
||||
SubBaseRule.ListenPorts = append(SubBaseRule.ListenPorts, listenPorts...)
|
||||
|
||||
if len(targetAddressList) == 0 {
|
||||
SubBaseRule.TargetHost = targetIP
|
||||
SubBaseRule.TargetPorts = append(SubBaseRule.TargetPorts, targetPorts...)
|
||||
|
||||
} else {
|
||||
SubBaseRule.BalanceTargetAddressAddress = targetAddressList
|
||||
}
|
||||
|
||||
for i := range proxyTypeList {
|
||||
dt := SubBaseRule
|
||||
dt.ProxyType = proxyTypeList[i]
|
||||
subRelyList = append(subRelyList, dt)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func convertProxyTypeByList(proxyTypeList []string) (proxyType string) {
|
||||
for i := range proxyTypeList {
|
||||
if i == 0 {
|
||||
proxyType = proxyTypeList[i]
|
||||
continue
|
||||
}
|
||||
proxyType += "," + proxyTypeList[i]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getProxyTypeList(proxyTypeListStr string) (proxyTypeList []string) {
|
||||
//tmpList = strings.Split(proxyTypeListStr, ",")
|
||||
//var
|
||||
tmpMap := make(map[string]int)
|
||||
|
||||
if strings.Contains(proxyTypeListStr, "tcp4") && strings.Contains(proxyTypeListStr, "tcp6") {
|
||||
proxyTypeList = append(proxyTypeList, "tcp")
|
||||
tmpMap["tcp"] = 1
|
||||
proxyTypeListStr = strings.Replace(proxyTypeListStr, "tcp4", ",", -1)
|
||||
proxyTypeListStr = strings.Replace(proxyTypeListStr, "tcp6", ",", -1)
|
||||
}
|
||||
|
||||
if strings.Contains(proxyTypeListStr, "udp4") && strings.Contains(proxyTypeListStr, "udp6") {
|
||||
proxyTypeList = append(proxyTypeList, "udp")
|
||||
tmpMap["udp"] = 1
|
||||
proxyTypeListStr = strings.Replace(proxyTypeListStr, "udp4", ",", -1)
|
||||
proxyTypeListStr = strings.Replace(proxyTypeListStr, "udp6", ",", -1)
|
||||
}
|
||||
|
||||
tmpList := strings.Split(proxyTypeListStr, ",")
|
||||
for i := range tmpList {
|
||||
if len(tmpList[i]) <= 2 {
|
||||
continue
|
||||
}
|
||||
if _, ok := tmpMap[tmpList[i]]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
_, tcpOK := tmpMap["tcp"]
|
||||
_, udpOK := tmpMap["udp"]
|
||||
|
||||
if (tmpList[i] == "tcp4" || tmpList[i] == "tcp6") && tcpOK {
|
||||
continue
|
||||
}
|
||||
|
||||
if (tmpList[i] == "udp4" || tmpList[i] == "udp6") && udpOK {
|
||||
continue
|
||||
}
|
||||
|
||||
proxyTypeList = append(proxyTypeList, tmpList[i])
|
||||
tmpMap[tmpList[i]] = 1
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func checkProxyType(proxyTypeList []string) error {
|
||||
for _, proxyType := range proxyTypeList {
|
||||
|
||||
switch proxyType {
|
||||
case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6":
|
||||
{
|
||||
return nil
|
||||
}
|
||||
default:
|
||||
{
|
||||
return fmt.Errorf("unsupport Proxy Type:%s", proxyType)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// CheckProxyConflict 冲突检查
|
||||
func CheckProxyConflict(proxyList *[]socketproxy.Proxy, proxyType, listenIP string, listenPort int) error {
|
||||
proxyMap := make(map[string]socketproxy.Proxy)
|
||||
for i, p := range *proxyList {
|
||||
proxyMap[p.GetKey()] = (*proxyList)[i]
|
||||
}
|
||||
|
||||
key := socketproxy.GetProxyKey(proxyType, listenIP, listenPort)
|
||||
if _, ok := proxyMap[key]; ok {
|
||||
return fmt.Errorf("绑定的地址和端口存在冲突![%s]", key)
|
||||
}
|
||||
anyBindKey := fmt.Sprintf("%s@:%d", proxyType, listenPort)
|
||||
|
||||
if strings.Compare(key, anyBindKey) == 0 {
|
||||
for exitsKey := range proxyMap {
|
||||
if strings.HasSuffix(exitsKey, anyBindKey) {
|
||||
return fmt.Errorf("绑定的地址和端口存在冲突![%s][%s]", key, exitsKey)
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if _, ok := proxyMap[anyBindKey]; ok {
|
||||
return fmt.Errorf("绑定的地址和端口存在冲突![%s]", key)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// getIpAndPortsFromAddress
|
||||
func getIpAndPortFromAddress(address string, needip bool, needports bool) (ip string, ports string, err error) {
|
||||
ipAndPortIndex := strings.LastIndex(address, ":")
|
||||
|
||||
// defer func() {
|
||||
// fmt.Printf("\nFuck: [%s]--->[%s]", ip, ports)
|
||||
// }()
|
||||
|
||||
if ipAndPortIndex < 0 || (!needip && !needports) {
|
||||
|
||||
switch {
|
||||
case (!needip && needports): //地址中仅有端口
|
||||
ports = address
|
||||
case (needip && !needports): //地址中仅有ip
|
||||
{
|
||||
ip = address
|
||||
}
|
||||
case (!needip && !needports): //地址中 端口和ip都不是必须
|
||||
{
|
||||
|
||||
if ipAndPortIndex > 0 {
|
||||
ip = address[:ipAndPortIndex]
|
||||
ports = address[ipAndPortIndex+1:]
|
||||
break
|
||||
}
|
||||
|
||||
//但address非空,判断
|
||||
if address == "" {
|
||||
break
|
||||
}
|
||||
if net.ParseIP(address) != nil {
|
||||
ip = address
|
||||
} else {
|
||||
ports = address
|
||||
if strings.HasPrefix(ports, ":") {
|
||||
ports = ports[1:]
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
ports = address[ipAndPortIndex+1:]
|
||||
|
||||
if ipAndPortIndex <= 1 {
|
||||
//fmt.Printf("Fuck:%s\n", ports)
|
||||
return
|
||||
}
|
||||
|
||||
addressHost := address[:ipAndPortIndex]
|
||||
addressHost = strings.Replace(addressHost, "[", "", -1)
|
||||
addressHost = strings.Replace(addressHost, "]", "", -1)
|
||||
|
||||
if net.ParseIP(addressHost) == nil {
|
||||
err = fmt.Errorf("ip[%s]格式有误", address[:ipAndPortIndex])
|
||||
return
|
||||
}
|
||||
|
||||
ip = addressHost
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// portsStrToIList
|
||||
func portsStrToIList(portsStr string) (ports []int, err error) {
|
||||
|
||||
if portsStr == "" {
|
||||
return
|
||||
}
|
||||
|
||||
if strings.Contains(portsStr, ",") {
|
||||
tmpStrList := strings.Split(portsStr, ",")
|
||||
for i := range tmpStrList {
|
||||
tps, e := portsStrToIList(tmpStrList[i])
|
||||
if e != nil {
|
||||
err = fmt.Errorf("端口参数处理出错:%s", e.Error())
|
||||
return
|
||||
}
|
||||
ports = append(ports, tps...)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
portsStrList := strings.Split(portsStr, "-")
|
||||
if len(portsStrList) > 2 {
|
||||
err = fmt.Errorf("端口%s格式有误", portsStr)
|
||||
return
|
||||
}
|
||||
|
||||
if len(portsStrList) == 1 { //single listen port
|
||||
listenPort, e := portStrToi(portsStrList[0])
|
||||
if e != nil {
|
||||
err = fmt.Errorf("端口格式有误!%s", e.Error())
|
||||
return
|
||||
}
|
||||
ports = append(ports, listenPort)
|
||||
}
|
||||
|
||||
if len(portsStrList) == 2 {
|
||||
minListenPort, e := portStrToi(portsStrList[0])
|
||||
if e != nil {
|
||||
err = fmt.Errorf("端口格式有误!%s", portsStrList[0])
|
||||
return
|
||||
}
|
||||
maxListenPort, e := portStrToi(portsStrList[1])
|
||||
if e != nil {
|
||||
err = fmt.Errorf("端口格式有误!%s", portsStrList[1])
|
||||
return
|
||||
}
|
||||
|
||||
if maxListenPort <= minListenPort {
|
||||
err = fmt.Errorf("前一个端口[%d]要小于后一个端口[%d]", minListenPort, maxListenPort)
|
||||
return
|
||||
}
|
||||
i := minListenPort
|
||||
for {
|
||||
if i > maxListenPort {
|
||||
break
|
||||
}
|
||||
ports = append(ports, i)
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func portStrToi(portStr string) (int, error) {
|
||||
port, err := strconv.Atoi(portStr)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("端口格式有误:%s", err.Error())
|
||||
}
|
||||
if port < 1 || port > 65535 {
|
||||
return 0, fmt.Errorf("端口[%d]超出范围", port)
|
||||
}
|
||||
return port, nil
|
||||
}
|
|
@ -1,251 +0,0 @@
|
|||
package rule
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_createSubRuleListFromConfigure_1(t *testing.T) {
|
||||
argsA := "53to192.168.31.1"
|
||||
|
||||
goportsList, _, _, _, _, _, _, e := createSubRuleListFromConfigure(argsA)
|
||||
if e != nil || len(goportsList) != 2 {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testA error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
|
||||
if goportsList[0].ProxyType != "tcp" || len(goportsList[0].ListenPorts) != 1 || goportsList[0].TargetHost != "192.168.31.1" || len(goportsList[0].TargetPorts) != 1 || len(goportsList[0].ListenPorts) != len(goportsList[0].TargetPorts) {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testB error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
|
||||
if goportsList[0].ListenPorts[0] != 53 || goportsList[0].TargetPorts[0] != 53 {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testC error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
|
||||
if goportsList[1].ProxyType != "udp" || len(goportsList[0].ListenPorts) != 1 || goportsList[0].TargetHost != "192.168.31.1" || len(goportsList[0].TargetPorts) != 1 || len(goportsList[0].ListenPorts) != len(goportsList[0].TargetPorts) {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testD error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
|
||||
if goportsList[1].ListenPorts[0] != 53 || goportsList[1].TargetPorts[0] != 53 {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testE error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func Test_createSubRuleListFromConfigure_2(t *testing.T) {
|
||||
argsA := "tcp@53to192.168.31.1"
|
||||
|
||||
goportsList, _, _, _, _, _, _, e := createSubRuleListFromConfigure(argsA)
|
||||
if e != nil || len(goportsList) != 1 {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testA error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
|
||||
if goportsList[0].ProxyType != "tcp" || len(goportsList[0].ListenPorts) != 1 || goportsList[0].TargetHost != "192.168.31.1" || len(goportsList[0].TargetPorts) != 1 || len(goportsList[0].ListenPorts) != len(goportsList[0].TargetPorts) {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testB error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
|
||||
if goportsList[0].ListenPorts[0] != 53 || goportsList[0].TargetPorts[0] != 53 {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testC error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func Test_createSubRuleListFromConfigure_3(t *testing.T) {
|
||||
argsA := "udp4@53to192.168.31.1"
|
||||
|
||||
goportsList, _, _, _, _, _, _, e := createSubRuleListFromConfigure(argsA)
|
||||
if e != nil || len(goportsList) != 1 {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testA error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
|
||||
if goportsList[0].ProxyType != "udp4" || len(goportsList[0].ListenPorts) != 1 || goportsList[0].TargetHost != "192.168.31.1" || len(goportsList[0].TargetPorts) != 1 || len(goportsList[0].ListenPorts) != len(goportsList[0].TargetPorts) {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testB error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
|
||||
if goportsList[0].ListenPorts[0] != 53 || goportsList[0].TargetPorts[0] != 53 {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testC error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func Test_createSubRuleListFromConfigure_4_0(t *testing.T) {
|
||||
argsList := []string{"tcp@20000-20021to192.168.31.1", "tcp@192.168.31.1:20000-20021", "tcp@20000-20021to192.168.31.1:20000-20021"}
|
||||
|
||||
for _, argsA := range argsList {
|
||||
goportsList, _, _, _, _, _, _, e := createSubRuleListFromConfigure(argsA)
|
||||
if e != nil || len(goportsList) != 1 {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testA error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
|
||||
if goportsList[0].ProxyType != "tcp" || len(goportsList[0].ListenPorts) != 22 || goportsList[0].TargetHost != "192.168.31.1" || len(goportsList[0].TargetPorts) != 22 || len(goportsList[0].ListenPorts) != len(goportsList[0].TargetPorts) {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testB error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
|
||||
if goportsList[0].ListenPorts[0] != 20000 || goportsList[0].TargetPorts[0] != 20000 {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testC error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
|
||||
if goportsList[0].ListenPorts[21] != 20021 || goportsList[0].TargetPorts[21] != 20021 {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testD error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func Test_createSubRuleListFromConfigure_4_1(t *testing.T) {
|
||||
argsA := "tcp@30000-30021to192.168.31.1:20000-20021"
|
||||
|
||||
goportsList, _, _, _, _, _, _, e := createSubRuleListFromConfigure(argsA)
|
||||
if e != nil || len(goportsList) != 1 {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testA error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
|
||||
if goportsList[0].ProxyType != "tcp" || len(goportsList[0].ListenPorts) != 22 || goportsList[0].TargetHost != "192.168.31.1" || len(goportsList[0].TargetPorts) != 22 || len(goportsList[0].ListenPorts) != len(goportsList[0].TargetPorts) {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testB error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
|
||||
if goportsList[0].ListenPorts[0] != 30000 || goportsList[0].TargetPorts[0] != 20000 {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testC error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
|
||||
if goportsList[0].ListenPorts[21] != 30021 || goportsList[0].TargetPorts[21] != 20021 {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testD error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func Test_createSubRuleListFromConfigure_5_0(t *testing.T) {
|
||||
//argsA :=
|
||||
args := []string{"tcp@80,443,20000-20021to192.168.31.1:80,443,20000-20021",
|
||||
"tcp@192.168.31.1:80,443,20000-20021",
|
||||
"tcp@80,443,20000-20021to192.168.31.1"}
|
||||
|
||||
for _, argsA := range args {
|
||||
goportsList, _, _, _, _, _, _, e := createSubRuleListFromConfigure(argsA)
|
||||
if e != nil || len(goportsList) != 1 {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testA error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
|
||||
if goportsList[0].ProxyType != "tcp" || len(goportsList[0].ListenPorts) != 24 || goportsList[0].TargetHost != "192.168.31.1" || len(goportsList[0].TargetPorts) != 24 || len(goportsList[0].ListenPorts) != len(goportsList[0].TargetPorts) {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testB error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
|
||||
if goportsList[0].ListenPorts[0] != 80 || goportsList[0].TargetPorts[0] != 80 {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testC error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
|
||||
if goportsList[0].ListenPorts[23] != 20021 || goportsList[0].TargetPorts[23] != 20021 {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testD error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_createSubRuleListFromConfigure_5_1(t *testing.T) {
|
||||
//argsA :=
|
||||
args := []string{"tcp@80,443,30000-30021to192.168.31.1:81,443,20000-20021"}
|
||||
|
||||
for _, argsA := range args {
|
||||
goportsList, _, _, _, _, _, _, e := createSubRuleListFromConfigure(argsA)
|
||||
if e != nil || len(goportsList) != 1 {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testA error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
|
||||
if goportsList[0].ProxyType != "tcp" || len(goportsList[0].ListenPorts) != 24 || goportsList[0].TargetHost != "192.168.31.1" || len(goportsList[0].TargetPorts) != 24 || len(goportsList[0].ListenPorts) != len(goportsList[0].TargetPorts) {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testB error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
|
||||
if goportsList[0].ListenPorts[0] != 80 || goportsList[0].TargetPorts[0] != 81 {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testC error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
|
||||
if goportsList[0].ListenPorts[23] != 30021 || goportsList[0].TargetPorts[23] != 20021 {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testD error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func Test_createSubRuleListFromConfigure_6_0(t *testing.T) {
|
||||
//argsA :=
|
||||
args := []string{"tcp6@80,443to192.168.31.1:80,443",
|
||||
"tcp6@80,443to192.168.31.1",
|
||||
"tcp6@192.168.31.1:80,443"}
|
||||
|
||||
for _, argsA := range args {
|
||||
goportsList, _, _, _, _, _, _, e := createSubRuleListFromConfigure(argsA)
|
||||
if e != nil || len(goportsList) != 1 {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testA error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
|
||||
if goportsList[0].ProxyType != "tcp6" || len(goportsList[0].ListenPorts) != 2 || goportsList[0].TargetHost != "192.168.31.1" || len(goportsList[0].TargetPorts) != 2 || len(goportsList[0].ListenPorts) != len(goportsList[0].TargetPorts) {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testB error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
|
||||
if goportsList[0].ListenPorts[0] != 80 || goportsList[0].TargetPorts[0] != 80 {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testC error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
|
||||
if goportsList[0].ListenPorts[1] != 443 || goportsList[0].TargetPorts[1] != 443 {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testD error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func Test_createSubRuleListFromConfigure_6_1(t *testing.T) {
|
||||
//argsA :=
|
||||
args := []string{"tcp@80,443to192.168.31.1:81,443"}
|
||||
|
||||
for _, argsA := range args {
|
||||
goportsList, _, _, _, _, _, _, e := createSubRuleListFromConfigure(argsA)
|
||||
if e != nil || len(goportsList) != 1 {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testA error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
|
||||
if goportsList[0].ProxyType != "tcp" || len(goportsList[0].ListenPorts) != 2 || goportsList[0].TargetHost != "192.168.31.1" || len(goportsList[0].TargetPorts) != 2 || len(goportsList[0].ListenPorts) != len(goportsList[0].TargetPorts) {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testB error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
|
||||
if goportsList[0].ListenPorts[0] != 80 || goportsList[0].TargetPorts[0] != 81 {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testC error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
|
||||
if goportsList[0].ListenPorts[1] != 443 || goportsList[0].TargetPorts[1] != 443 {
|
||||
t.Errorf("createSubRuleListFromConfigure [%s] testD error %v", argsA, goportsList)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -11,8 +11,6 @@ type BaseProxyConf struct {
|
|||
key string
|
||||
ProxyType string // tcp tcp4 tcp6 udp udp4 udp6
|
||||
|
||||
//TrafficMonitor bool //流量监控
|
||||
fromRule string
|
||||
}
|
||||
|
||||
func (p *BaseProxyConf) GetProxyType() string {
|
||||
|
@ -23,14 +21,6 @@ func (p *BaseProxyConf) GetStatus() string {
|
|||
return p.ProxyType
|
||||
}
|
||||
|
||||
func (p *BaseProxyConf) SetFromRule(rule string) {
|
||||
p.fromRule = rule
|
||||
}
|
||||
|
||||
func (p *BaseProxyConf) FromRule() string {
|
||||
return p.fromRule
|
||||
}
|
||||
|
||||
func (p *BaseProxyConf) ReceiveDataCallback(nw int64) {
|
||||
atomic.AddInt64(&p.TrafficIn, nw)
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"sync"
|
||||
|
||||
"github.com/gdy666/lucky/thirdlib/gdylib/pool"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type Proxy interface {
|
||||
|
@ -23,8 +24,7 @@ type Proxy interface {
|
|||
GetListenPort() int
|
||||
GetKey() string
|
||||
GetCurrentConnections() int64
|
||||
SetFromRule(string)
|
||||
FromRule() string
|
||||
|
||||
String() string
|
||||
GetTrafficIn() int64
|
||||
GetTrafficOut() int64
|
||||
|
@ -32,11 +32,12 @@ type Proxy interface {
|
|||
}
|
||||
|
||||
type RelayRuleOptions struct {
|
||||
UDPPackageSize int `json:"UDPPackageSize,omitempty"`
|
||||
SingleProxyMaxConnections int64 `json:"SingleProxyMaxConnections,omitempty"`
|
||||
UDPProxyPerformanceMode bool `json:"UDPProxyPerformanceMode,omitempty"`
|
||||
UDPShortMode bool `json:"UDPShortMode,omitempty"`
|
||||
SafeMode string `json:"SafeMode,omitempty"`
|
||||
UDPPackageSize int `json:"UDPPackageSize,omitempty"`
|
||||
SingleProxyMaxTCPConnections int64 `json:"SingleProxyMaxTCPConnections,omitempty"`
|
||||
SingleProxyMaxUDPReadTargetDatagoroutineCount int64 `json:"SingleProxyMaxUDPReadTargetDatagoroutineCount"`
|
||||
UDPProxyPerformanceMode bool `json:"UDPProxyPerformanceMode,omitempty"`
|
||||
UDPShortMode bool `json:"UDPShortMode,omitempty"`
|
||||
SafeMode string `json:"SafeMode,omitempty"`
|
||||
}
|
||||
|
||||
// Join two io.ReadWriteCloser and do some operations.
|
||||
|
@ -157,16 +158,16 @@ func formatFileSize(fileSize int64) (size string) {
|
|||
|
||||
}
|
||||
|
||||
func CreateProxy(proxyType, listenIP, targetHost string, balanceTargetAddressList *[]string, listenPort, targetPort int, options *RelayRuleOptions) (p Proxy, err error) {
|
||||
func CreateProxy(log *logrus.Logger, proxyType, listenIP string, targetAddressList []string, listenPort, targetPort int, options *RelayRuleOptions) (p Proxy, err error) {
|
||||
//key := GetProxyKey(proxyType, listenIP, listenPort)
|
||||
switch {
|
||||
case strings.HasPrefix(proxyType, "tcp"):
|
||||
{
|
||||
return CreateTCPProxy(proxyType, listenIP, targetHost, balanceTargetAddressList, listenPort, targetPort, options), nil
|
||||
return CreateTCPProxy(log, proxyType, listenIP, targetAddressList, listenPort, targetPort, options), nil
|
||||
}
|
||||
case strings.HasPrefix(proxyType, "udp"):
|
||||
{
|
||||
return CreateUDPProxy(proxyType, listenIP, targetHost, balanceTargetAddressList, listenPort, targetPort, options), nil
|
||||
return CreateUDPProxy(log, proxyType, listenIP, targetAddressList, listenPort, targetPort, options), nil
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("未支持的类型:%s", proxyType)
|
||||
|
|
|
@ -7,6 +7,8 @@ import (
|
|||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type TCPProxy struct {
|
||||
|
@ -20,20 +22,18 @@ type TCPProxy struct {
|
|||
connMapMutex sync.Mutex
|
||||
}
|
||||
|
||||
func CreateTCPProxy(proxyType, listenIP, targetIP string, balanceTargetAddressList *[]string, listenPort, targetPort int, options *RelayRuleOptions) *TCPProxy {
|
||||
func CreateTCPProxy(log *logrus.Logger, proxyType, listenIP string, targetAddressList []string, listenPort, targetPort int, options *RelayRuleOptions) *TCPProxy {
|
||||
p := &TCPProxy{}
|
||||
p.ProxyType = proxyType
|
||||
p.listenIP = listenIP
|
||||
p.listenPort = listenPort
|
||||
p.targetIP = targetIP
|
||||
p.targetAddressList = targetAddressList
|
||||
p.targetPort = targetPort
|
||||
if balanceTargetAddressList != nil {
|
||||
p.balanceTargetAddressList = *balanceTargetAddressList
|
||||
}
|
||||
p.log = log
|
||||
|
||||
p.safeMode = options.SafeMode
|
||||
|
||||
p.SetMaxConnections(options.SingleProxyMaxConnections)
|
||||
p.SetMaxConnections(options.SingleProxyMaxTCPConnections)
|
||||
return p
|
||||
}
|
||||
|
||||
|
@ -41,24 +41,26 @@ func (p *TCPProxy) GetStatus() string {
|
|||
return fmt.Sprintf("%s\nactivity connections:[%d]", p.String(), p.GetCurrentConnections())
|
||||
}
|
||||
|
||||
// func (p *TCPProxy) CheckConns() bool {
|
||||
// if GetGlobalTCPConns() >= tcpGlobalMaxConnections || p.GetCurrentConnections() >= p.TcpSingleProxyMaxConns {
|
||||
// // if p.GetGlobalTCPConns() >= tcpGlobalMaxConnections {
|
||||
// // log.Println("")
|
||||
// // }
|
||||
// // if p.GetCurrentTCPConns() >= p.TcpSingleProxyMaxConns {
|
||||
// // log.Printf("超出单代理TCP限制")
|
||||
// // }
|
||||
// return false
|
||||
// }
|
||||
// return true
|
||||
// }
|
||||
func (p *TCPProxy) CheckConnectionsLimit() error {
|
||||
|
||||
if GetGlobalTCPPortForwardConnections() >= GetGlobalTCPPortforwardMaxConnections() {
|
||||
return fmt.Errorf("超出TCP最大总连接数[%d]限制", GetGlobalTCPPortforwardMaxConnections())
|
||||
}
|
||||
|
||||
if p.GetCurrentConnections() >= p.SingleProxyMaxConnections {
|
||||
return fmt.Errorf("超出单端口TCP最大连接数[%d]限制", p.SingleProxyMaxConnections)
|
||||
}
|
||||
|
||||
//全局,单端口限制
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *TCPProxy) StartProxy() {
|
||||
p.listenConnMutex.Lock()
|
||||
defer p.listenConnMutex.Unlock()
|
||||
if p.listenConn != nil {
|
||||
log.Printf("proxy %s is started", p.String())
|
||||
//log.Printf("proxy %s is started", p.String())
|
||||
p.log.Warnf("proxy %s is started", p.String())
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -69,16 +71,16 @@ func (p *TCPProxy) StartProxy() {
|
|||
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "Only one usage of each socket address") {
|
||||
log.Printf("监听IP端口[%s]已被占用,proxy[%s]启动失败", p.GetListentAddress(), p.String())
|
||||
p.log.Errorf("监听IP端口[%s]已被占用,proxy[%s]启动失败", p.GetListentAddress(), p.String())
|
||||
} else {
|
||||
log.Printf("Cannot start proxy[%s]:%s", p.String(), err)
|
||||
p.log.Errorf("Cannot start proxy[%s]:%s", p.String(), err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
p.listenConn = ln
|
||||
|
||||
log.Printf("[proxy][start][%s]", p.String())
|
||||
p.log.Infof("[端口转发][开启][%s]", p.String())
|
||||
|
||||
go func() {
|
||||
for {
|
||||
|
@ -88,36 +90,32 @@ func (p *TCPProxy) StartProxy() {
|
|||
if strings.Contains(err.Error(), "use of closed network connection") {
|
||||
break
|
||||
}
|
||||
log.Printf(" Cannot accept connection due to error %s", err.Error())
|
||||
p.log.Errorf(" Cannot accept connection due to error %s", err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
err = p.CheckConnectionsLimit()
|
||||
if err != nil {
|
||||
//p.PrintConnectionsInfo()
|
||||
p.log.Warnf("[%s]超出最大连接数限制,不再接受新连接:%s", p.GetKey(), err.Error())
|
||||
newConn.Close()
|
||||
continue
|
||||
}
|
||||
|
||||
newConnAddr := newConn.RemoteAddr().String()
|
||||
if !p.SafeCheck(newConnAddr) {
|
||||
log.Printf("[%s]新连接 [%s]安全检查未通过", p.GetKey(), newConnAddr)
|
||||
p.log.Warnf("[%s]新连接 [%s]安全检查未通过", p.GetKey(), newConnAddr)
|
||||
newConn.Close()
|
||||
continue
|
||||
}
|
||||
//log.Printf("[%s]新连接[%s]安全检查通过", p.GetKey(), newConnAddr)
|
||||
|
||||
//fmt.Printf("连接IP:[%s]\n", newConn.RemoteAddr().String())
|
||||
|
||||
//log.Printf("new tdp connection %s@%s [%s]===>%s", p.ProxyType, p.ListentAddress, newConn.RemoteAddr().String(), p.TargetAddress)
|
||||
if !p.CheckConnections() {
|
||||
//log.Printf("超出最大连接数限制\n")
|
||||
p.PrintConnectionsInfo()
|
||||
log.Printf("[%s]超出最大连接数限制,不再接受新连接", p.GetKey())
|
||||
newConn.Close()
|
||||
continue
|
||||
}
|
||||
p.log.Infof("[%s]新连接[%s]安全检查通过", p.GetKey(), newConnAddr)
|
||||
|
||||
p.connMapMutex.Lock()
|
||||
p.connMap[newConn.RemoteAddr().String()] = newConn
|
||||
p.connMapMutex.Unlock()
|
||||
|
||||
//atomic.AddInt64(&tcpconnections, 1)
|
||||
p.AddCurrentConnections(1)
|
||||
//fmt.Printf("当前全局TCP连接数:%d\n", p.GetGlobalTCPConns())
|
||||
go p.handle(newConn)
|
||||
}
|
||||
}()
|
||||
|
@ -134,7 +132,7 @@ func (p *TCPProxy) StopProxy() {
|
|||
p.listenConnMutex.Lock()
|
||||
defer p.listenConnMutex.Unlock()
|
||||
defer func() {
|
||||
log.Printf("[proxy][stop][%s]", p.String())
|
||||
p.log.Infof("[端口转发][关闭][%s]", p.String())
|
||||
}()
|
||||
if p.listenConn == nil {
|
||||
return
|
||||
|
@ -152,7 +150,6 @@ func (p *TCPProxy) StopProxy() {
|
|||
}
|
||||
|
||||
func (p *TCPProxy) handle(conn net.Conn) {
|
||||
|
||||
//dialer := net.Dialer{Timeout: 10 * time.Second}
|
||||
//targetConn, err := dialer.Dial("tcp", p.TargetAddress)
|
||||
targetConn, err := net.Dial("tcp", p.GetTargetAddress())
|
||||
|
@ -166,7 +163,9 @@ func (p *TCPProxy) handle(conn net.Conn) {
|
|||
|
||||
p.connMapMutex.Lock()
|
||||
delete(p.connMap, conn.RemoteAddr().String())
|
||||
p.log.Infof("[%s]%s 断开连接", p.GetKey(), conn.RemoteAddr().String())
|
||||
p.connMapMutex.Unlock()
|
||||
|
||||
}()
|
||||
|
||||
if err != nil {
|
||||
|
|
|
@ -3,23 +3,28 @@ package socketproxy
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const TCP_DEFAULT_STREAM_BUFFERSIZE = 128
|
||||
|
||||
const DEFAULT_GLOBAL_MAX_CONNECTIONS = int64(10240)
|
||||
const DEFAULT_GLOBAL_MAX_CONNECTIONS = int64(1024)
|
||||
const DEFAULT_GLOBAL_UDPReadTargetDataMaxgoroutineCount = int64(1024)
|
||||
const TCPUDP_DEFAULT_SINGLE_PROXY_MAX_CONNECTIONS = int64(256)
|
||||
const DEFAULT_MAX_PROXY_COUNT = int64(128)
|
||||
|
||||
var globalMaxConnections = DEFAULT_GLOBAL_MAX_CONNECTIONS
|
||||
const DEFAULT_MAX_PORTFORWARDS_LIMIT = int64(128)
|
||||
|
||||
var globalCurrentConnections int64 = 0
|
||||
var gloMaxProxyCount int64 = DEFAULT_MAX_PROXY_COUNT
|
||||
var globalTCPPortforwardMaxConnectionsLimit = DEFAULT_GLOBAL_MAX_CONNECTIONS
|
||||
var globalUDPReadTargetDataMaxgoroutineCountLimit = DEFAULT_GLOBAL_UDPReadTargetDataMaxgoroutineCount
|
||||
|
||||
var globalTCPPortForwardCurrentConnections int64 = 0
|
||||
var globalUDPPortForwardCurrentGroutineCount int64 = 0
|
||||
|
||||
var gloMaxPortForwardsCountLimit int64 = DEFAULT_MAX_PORTFORWARDS_LIMIT
|
||||
|
||||
var safeCheckFunc func(mode, ip string) bool
|
||||
|
||||
|
@ -27,66 +32,68 @@ func SetSafeCheck(f func(mode, ip string) bool) {
|
|||
safeCheckFunc = f
|
||||
}
|
||||
|
||||
func SetGlobalMaxProxyCount(max int64) {
|
||||
atomic.StoreInt64(&gloMaxProxyCount, max)
|
||||
func SetGlobalUDPReadTargetDataMaxgoroutineCountLimit(max int64) {
|
||||
atomic.StoreInt64(&globalUDPReadTargetDataMaxgoroutineCountLimit, max)
|
||||
}
|
||||
|
||||
func GetGlobalMaxProxyCount() int64 {
|
||||
return atomic.LoadInt64(&gloMaxProxyCount)
|
||||
func GetGlobalUDPReadTargetDataMaxgoroutineCountLimit() int64 {
|
||||
return atomic.LoadInt64(&globalUDPReadTargetDataMaxgoroutineCountLimit)
|
||||
}
|
||||
|
||||
func SetGlobalMaxConnections(max int64) {
|
||||
atomic.StoreInt64(&globalMaxConnections, max)
|
||||
func SetGlobalMaxPortForwardsCountLimit(max int64) {
|
||||
atomic.StoreInt64(&gloMaxPortForwardsCountLimit, max)
|
||||
}
|
||||
|
||||
func GetGlobalMaxConnections() int64 {
|
||||
return atomic.LoadInt64(&globalMaxConnections)
|
||||
func GetGlobalMaxPortForwardsCountLimit() int64 {
|
||||
return atomic.LoadInt64(&gloMaxPortForwardsCountLimit)
|
||||
}
|
||||
|
||||
func GetSingleProxyMaxConnections(m *int64) int64 {
|
||||
if *m <= 0 {
|
||||
return TCPUDP_DEFAULT_SINGLE_PROXY_MAX_CONNECTIONS
|
||||
}
|
||||
return *m
|
||||
|
||||
func SetGlobalTCPPortforwardMaxConnections(max int64) {
|
||||
atomic.StoreInt64(&globalTCPPortforwardMaxConnectionsLimit, max)
|
||||
}
|
||||
|
||||
func GetGlobalConnections() int64 {
|
||||
return atomic.LoadInt64(&globalCurrentConnections)
|
||||
func GetGlobalTCPPortforwardMaxConnections() int64 {
|
||||
return atomic.LoadInt64(&globalTCPPortforwardMaxConnectionsLimit)
|
||||
}
|
||||
|
||||
func GloBalCOnnectionsAdd(add int64) int64 {
|
||||
return atomic.AddInt64(&globalCurrentConnections, add)
|
||||
func GetGlobalTCPPortForwardConnections() int64 {
|
||||
return atomic.LoadInt64(&globalTCPPortForwardCurrentConnections)
|
||||
}
|
||||
|
||||
func GloBalTCPPortForwardConnectionsAdd(add int64) int64 {
|
||||
return atomic.AddInt64(&globalTCPPortForwardCurrentConnections, add)
|
||||
}
|
||||
|
||||
func GetGlobalUDPPortForwardGroutineCount() int64 {
|
||||
return atomic.LoadInt64(&globalUDPPortForwardCurrentGroutineCount)
|
||||
}
|
||||
|
||||
func GloBalUDPPortForwardGroutineCountAdd(add int64) int64 {
|
||||
return atomic.AddInt64(&globalUDPPortForwardCurrentGroutineCount, add)
|
||||
}
|
||||
|
||||
type TCPUDPProxyCommonConf struct {
|
||||
CurrentConnectionsCount int64
|
||||
SingleProxyMaxConnections int64
|
||||
targetBalanceIndex int64
|
||||
|
||||
BaseProxyConf
|
||||
listentAddress string
|
||||
listenIP string
|
||||
listenPort int
|
||||
targetIP string
|
||||
targetPort int
|
||||
targetAddress string
|
||||
|
||||
balanceTargetAddressList []string //均衡负载转发
|
||||
targetBalanceIndexMutex sync.Mutex
|
||||
//targetIP string
|
||||
targetAddressList []string
|
||||
targetAddressCount int
|
||||
targetAddressIndex uint64
|
||||
targetAddressLock sync.Mutex
|
||||
targetPort int
|
||||
|
||||
safeMode string
|
||||
log *logrus.Logger
|
||||
}
|
||||
|
||||
func (p *TCPUDPProxyCommonConf) CheckConnections() bool {
|
||||
if p.GetCurrentConnections() >= GetGlobalMaxConnections() || p.GetCurrentConnections() >= p.SingleProxyMaxConnections {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *TCPUDPProxyCommonConf) PrintConnectionsInfo() {
|
||||
log.Printf("[%s]当前连接数:[%d],单代理最大连接数限制[%d],全局最大连接数限制[%d]\n", p.GetKey(), p.GetCurrentConnections(), p.SingleProxyMaxConnections, GetGlobalMaxConnections())
|
||||
}
|
||||
// func (p *TCPUDPProxyCommonConf) PrintConnectionsInfo() {
|
||||
// p.log.Infof("[%s]当前连接数:[%d],当前端口最大TCP连接数限制[%d],全局最大TCP连接数限制[%d]", p.GetKey(), p.GetCurrentConnections(), p.SingleProxyMaxConnections, GetGlobalTCPPortforwardMaxConnections())
|
||||
// }
|
||||
|
||||
func (p *TCPUDPProxyCommonConf) SetMaxConnections(max int64) {
|
||||
if max <= 0 {
|
||||
|
@ -98,17 +105,22 @@ func (p *TCPUDPProxyCommonConf) SetMaxConnections(max int64) {
|
|||
|
||||
func (p *TCPUDPProxyCommonConf) AddCurrentConnections(a int64) {
|
||||
atomic.AddInt64(&p.CurrentConnectionsCount, a)
|
||||
GloBalCOnnectionsAdd(a)
|
||||
if strings.HasPrefix(p.ProxyType, "tcp") {
|
||||
GloBalTCPPortForwardConnectionsAdd(a)
|
||||
return
|
||||
}
|
||||
|
||||
if strings.HasPrefix(p.ProxyType, "udp") {
|
||||
GloBalUDPPortForwardGroutineCountAdd(a)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (p *TCPUDPProxyCommonConf) GetCurrentConnections() int64 {
|
||||
return atomic.LoadInt64(&p.CurrentConnectionsCount)
|
||||
}
|
||||
|
||||
func (p *TCPProxy) GetCurrentCon() int64 {
|
||||
return atomic.LoadInt64(&p.CurrentConnectionsCount)
|
||||
}
|
||||
|
||||
func (p *TCPUDPProxyCommonConf) GetListentAddress() string {
|
||||
if p.listentAddress == "" {
|
||||
if strings.Contains(p.listenIP, ":") {
|
||||
|
@ -136,33 +148,19 @@ func (p *TCPUDPProxyCommonConf) GetListenPort() int {
|
|||
}
|
||||
|
||||
func (p *TCPUDPProxyCommonConf) GetTargetAddress() string {
|
||||
if len(p.balanceTargetAddressList) == 0 {
|
||||
if p.targetAddress == "" {
|
||||
if strings.Contains(p.targetIP, ":") {
|
||||
p.targetAddress = fmt.Sprintf("[%s]:%d", p.targetIP, p.targetPort)
|
||||
} else {
|
||||
p.targetAddress = fmt.Sprintf("%s:%d", p.targetIP, p.targetPort)
|
||||
}
|
||||
}
|
||||
return p.targetAddress
|
||||
p.targetAddressLock.Lock()
|
||||
defer p.targetAddressLock.Unlock()
|
||||
if p.targetAddressCount <= 0 {
|
||||
p.targetAddressCount = len(p.targetAddressList)
|
||||
p.targetAddressIndex = 0
|
||||
}
|
||||
|
||||
var address string
|
||||
addressListLength := int64(len(p.balanceTargetAddressList))
|
||||
p.targetBalanceIndexMutex.Lock()
|
||||
address = p.balanceTargetAddressList[p.targetBalanceIndex%addressListLength]
|
||||
p.targetBalanceIndex++
|
||||
p.targetBalanceIndexMutex.Unlock()
|
||||
|
||||
address := fmt.Sprintf("%s:%d", p.targetAddressList[p.targetAddressIndex%uint64(p.targetAddressCount)], p.targetPort)
|
||||
p.targetAddressIndex++
|
||||
return address
|
||||
}
|
||||
|
||||
func (p *TCPUDPProxyCommonConf) String() string {
|
||||
if len(p.balanceTargetAddressList) == 0 {
|
||||
return fmt.Sprintf("%s@%s ===> %s", p.ProxyType, p.GetListentAddress(), p.GetTargetAddress())
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s@%s ===> %v", p.ProxyType, p.GetListentAddress(), p.balanceTargetAddressList)
|
||||
return fmt.Sprintf("%s@%v ===> %v:%d", p.ProxyType, p.GetListentAddress(), p.targetAddressList, p.targetPort)
|
||||
}
|
||||
|
||||
func (p *TCPUDPProxyCommonConf) SafeCheck(remodeAddr string) bool {
|
||||
|
|
|
@ -3,7 +3,6 @@ package socketproxy
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
@ -12,6 +11,7 @@ import (
|
|||
|
||||
"github.com/fatedier/golib/errors"
|
||||
"github.com/gdy666/lucky/thirdlib/gdylib/pool"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const UDP_DEFAULT_PACKAGE_SIZE = 1500
|
||||
|
@ -29,11 +29,14 @@ type UDPProxy struct {
|
|||
relayChs []chan *udpPackge
|
||||
replyCh chan *udpPackge
|
||||
|
||||
udpPackageSize int
|
||||
targetudpConnItemMap map[string]*udpMapItem
|
||||
targetudpConnItemMapMutex sync.RWMutex
|
||||
Upm bool //性能模式
|
||||
ShortMode bool
|
||||
udpPackageSize int
|
||||
//targetudpConnItemMap map[string]*udpMapItem
|
||||
//targetudpConnItemMapMutex sync.RWMutex
|
||||
targetConnectSessions sync.Map
|
||||
Upm bool //性能模式
|
||||
ShortMode bool
|
||||
isStop bool
|
||||
SingleProxyMaxUDPReadTargetDatagoroutineCount int64
|
||||
}
|
||||
|
||||
type udpPackge struct {
|
||||
|
@ -42,21 +45,25 @@ type udpPackge struct {
|
|||
remoteAddr *net.UDPAddr
|
||||
}
|
||||
|
||||
func CreateUDPProxy(proxyType, listenIP, targetIP string, balanceTargetAddressList *[]string, listenPort, targetPort int, options *RelayRuleOptions) *UDPProxy {
|
||||
type udpTagetConSession struct {
|
||||
targetConn *net.UDPConn
|
||||
lastTime time.Time
|
||||
}
|
||||
|
||||
func CreateUDPProxy(log *logrus.Logger, proxyType, listenIP string, targetAddressList []string, listenPort, targetPort int, options *RelayRuleOptions) *UDPProxy {
|
||||
p := &UDPProxy{}
|
||||
//p.Key = key
|
||||
p.ProxyType = proxyType
|
||||
p.listenIP = listenIP
|
||||
p.listenPort = listenPort
|
||||
p.targetIP = targetIP
|
||||
p.targetAddressList = targetAddressList
|
||||
p.targetPort = targetPort
|
||||
if balanceTargetAddressList != nil {
|
||||
p.balanceTargetAddressList = *balanceTargetAddressList
|
||||
}
|
||||
|
||||
p.Upm = options.UDPProxyPerformanceMode
|
||||
p.ShortMode = options.UDPShortMode
|
||||
p.safeMode = options.SafeMode
|
||||
p.log = log
|
||||
p.SingleProxyMaxUDPReadTargetDatagoroutineCount = options.SingleProxyMaxUDPReadTargetDatagoroutineCount
|
||||
|
||||
p.SetUDPPacketSize(options.UDPPackageSize)
|
||||
return p
|
||||
|
@ -97,16 +104,16 @@ func (p *UDPProxy) StartProxy() {
|
|||
bindAddr, err := net.ResolveUDPAddr(p.ProxyType, p.GetListentAddress())
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Cannot start proxy[%s]:%s", p.GetKey(), err)
|
||||
p.log.Errorf("Cannot start proxy[%s]:%s", p.GetKey(), err)
|
||||
return
|
||||
}
|
||||
|
||||
ln, err := net.ListenUDP(p.ProxyType, bindAddr)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), " bind: Only one usage of each socket address") {
|
||||
log.Printf("监听IP端口[%s]已被占用,proxy[%s]启动失败", p.GetListentAddress(), p.String())
|
||||
p.log.Errorf("监听IP端口[%s]已被占用,proxy[%s]启动失败", p.GetListentAddress(), p.String())
|
||||
} else {
|
||||
log.Printf("Cannot start proxy[%s]:%s", p.String(), err)
|
||||
p.log.Errorf("Cannot start proxy[%s]:%s", p.String(), err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -116,17 +123,8 @@ func (p *UDPProxy) StartProxy() {
|
|||
|
||||
p.listenConn = ln
|
||||
|
||||
log.Printf("[proxy][start][%s]", p.String())
|
||||
p.log.Infof("[端口转发][开启][%s]", p.String())
|
||||
|
||||
// p.targetAddr, err = net.ResolveUDPAddr(p.ProxyType, p.TargetAddress)
|
||||
// if err != nil {
|
||||
// log.Printf("net.ResolveUDPAddr[%s] error:%s", p.TargetAddress, err.Error())
|
||||
// return
|
||||
// }
|
||||
|
||||
//go p.test()
|
||||
|
||||
//p.relayCh = make(chan *udpPackge, 1024)
|
||||
p.relayChs = make([]chan *udpPackge, p.getHandlegoroutineNum())
|
||||
|
||||
for i := range p.relayChs {
|
||||
|
@ -134,19 +132,20 @@ func (p *UDPProxy) StartProxy() {
|
|||
}
|
||||
|
||||
p.replyCh = make(chan *udpPackge, 1024)
|
||||
if p.targetudpConnItemMap == nil {
|
||||
p.targetudpConnItemMap = make(map[string]*udpMapItem)
|
||||
}
|
||||
// if p.targetudpConnItemMap == nil {
|
||||
// p.targetudpConnItemMap = make(map[string]*udpMapItem)
|
||||
// }
|
||||
|
||||
for i := range p.relayChs {
|
||||
go p.Forwarder(i, p.relayChs[i])
|
||||
}
|
||||
|
||||
go p.replyDataToRemotAddress()
|
||||
go p.CheckTargetUDPConn()
|
||||
|
||||
go p.CheckTargetUDPConnectSessions()
|
||||
|
||||
for i := 0; i < p.getHandlegoroutineNum(); i++ {
|
||||
go p.ListenFunc(ln)
|
||||
go p.ListenHandler(ln)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -155,14 +154,13 @@ func (p *UDPProxy) StopProxy() {
|
|||
p.listenConnMutex.Lock()
|
||||
defer p.listenConnMutex.Unlock()
|
||||
defer func() {
|
||||
p.targetudpConnItemMapMutex.Lock()
|
||||
for _, v := range p.targetudpConnItemMap {
|
||||
v.conn.Close()
|
||||
}
|
||||
p.targetudpConnItemMap = nil
|
||||
p.targetudpConnItemMap = make(map[string]*udpMapItem)
|
||||
p.targetudpConnItemMapMutex.Unlock()
|
||||
log.Printf("[proxy][stop][%s]", p.String())
|
||||
p.targetConnectSessions.Range(func(key any, value any) bool {
|
||||
session := value.(*udpTagetConSession)
|
||||
session.targetConn.Close()
|
||||
p.targetConnectSessions.Delete(key)
|
||||
return true
|
||||
})
|
||||
p.log.Infof("[端口转发][关闭][%s]", p.String())
|
||||
}()
|
||||
|
||||
if p.listenConn == nil {
|
||||
|
@ -170,7 +168,11 @@ func (p *UDPProxy) StopProxy() {
|
|||
}
|
||||
p.listenConn.Close()
|
||||
p.listenConn = nil
|
||||
|
||||
p.isStop = true
|
||||
close(p.replyCh)
|
||||
for i := range p.relayChs {
|
||||
close(p.relayChs[i])
|
||||
}
|
||||
}
|
||||
|
||||
// ReadFromTargetOnce one clientAddr only read once,short mode eg: udp dns
|
||||
|
@ -181,11 +183,11 @@ func (p *UDPProxy) ReadFromTargetOnce() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (p *UDPProxy) GetStatus() string {
|
||||
return fmt.Sprintf("%s max packet size[%d]", p.String(), p.GetUDPPacketSize())
|
||||
}
|
||||
// func (p *UDPProxy) GetStatus() string {
|
||||
// return fmt.Sprintf("%s max packet size[%d]", p.String(), p.GetUDPPacketSize())
|
||||
// }
|
||||
|
||||
func (p *UDPProxy) ListenFunc(ln *net.UDPConn) {
|
||||
func (p *UDPProxy) ListenHandler(ln *net.UDPConn) {
|
||||
|
||||
inDatabuf := pool.GetBuf(p.GetUDPPacketSize())
|
||||
defer pool.PutBuf(inDatabuf)
|
||||
|
@ -195,40 +197,33 @@ func (p *UDPProxy) ListenFunc(ln *net.UDPConn) {
|
|||
break
|
||||
}
|
||||
|
||||
inDatabufSize, clientAddr, err := ln.ReadFromUDP(inDatabuf)
|
||||
inDatabufSize, remoteAddr, err := ln.ReadFromUDP(inDatabuf)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), `smaller than the datagram`) {
|
||||
log.Printf("%s ReadFromUDP error,the udp packet size is smaller than the datagram,please use flag '-ups xxx'set udp packet size \n", p.String())
|
||||
p.log.Errorf("[%s] UDP包最大长度设置过小,请重新设置", p.GetKey())
|
||||
} else {
|
||||
if !strings.Contains(err.Error(), "use of closed network connection") {
|
||||
log.Printf(" %s ReadFromUDP error:\n%s \n", p.String(), err.Error())
|
||||
p.log.Errorf(" %s ReadFromUDP error:\n%s \n", p.String(), err.Error())
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
//fmt.Printf("inDatabufSize:%d\n", inDatabufSize)
|
||||
|
||||
newConnAddr := clientAddr.String()
|
||||
if !p.SafeCheck(newConnAddr) {
|
||||
log.Printf("[%s]新连接 [%s]安全检查未通过", p.GetKey(), newConnAddr)
|
||||
remoteAddrStr := remoteAddr.String()
|
||||
if !p.SafeCheck(remoteAddrStr) {
|
||||
p.log.Warnf("[%s]新连接 [%s]安全检查未通过", p.GetKey(), remoteAddrStr)
|
||||
continue
|
||||
}
|
||||
|
||||
// var newConOk bool
|
||||
// p.targetudpConnItemMapMutex.RLock()
|
||||
// _, newConOk = p.targetudpConnItemMap[clientAddr.String()]
|
||||
// p.targetudpConnItemMapMutex.RUnlock()
|
||||
// if !newConOk {
|
||||
// log.Printf("new udp connection %s@%s [%s]===>%s", p.ProxyType, p.ListentAddress, clientAddr.String(), p.TargetAddress)
|
||||
// }
|
||||
//log.Printf("new udp connection %s@%s [%s]===>%s", p.ProxyType, p.ListentAddress, clientAddr.String(), p.TargetAddress)
|
||||
_, ok := p.targetConnectSessions.Load(remoteAddrStr)
|
||||
if !ok {
|
||||
p.log.Infof("[%s]新连接 [%s]安全检查通过", p.GetKey(), remoteAddrStr)
|
||||
}
|
||||
|
||||
data := pool.GetBuf(inDatabufSize)
|
||||
copy(data, inDatabuf[:inDatabufSize])
|
||||
|
||||
inUdpPack := udpPackge{dataSize: inDatabufSize, data: &data, remoteAddr: clientAddr}
|
||||
//p.relayCh <- &inUdpPack
|
||||
inUdpPack := udpPackge{dataSize: inDatabufSize, data: &data, remoteAddr: remoteAddr}
|
||||
|
||||
p.relayChs[i%uint64(p.getHandlegoroutineNum())] <- &inUdpPack
|
||||
i++
|
||||
|
@ -236,150 +231,146 @@ func (p *UDPProxy) ListenFunc(ln *net.UDPConn) {
|
|||
}
|
||||
}
|
||||
|
||||
type udpMapItem struct {
|
||||
conn *net.UDPConn
|
||||
lastTime time.Time
|
||||
func (p *UDPProxy) handlerDataFromTargetAddress(raddr *net.UDPAddr, tgConn *net.UDPConn) {
|
||||
readBuffer := pool.GetBuf(p.GetUDPPacketSize())
|
||||
var session *udpTagetConSession
|
||||
sessionKey := raddr.String()
|
||||
|
||||
defer func() {
|
||||
pool.PutBuf(readBuffer)
|
||||
if p.ReadFromTargetOnce() {
|
||||
tgConn.Close()
|
||||
} else {
|
||||
p.targetConnectSessions.Delete(sessionKey)
|
||||
}
|
||||
p.AddCurrentConnections(-1)
|
||||
p.log.Infof("[%s]目标地址[%s]关闭连接[%s]", p.GetKey(), tgConn.RemoteAddr().String(), tgConn.LocalAddr().String())
|
||||
}()
|
||||
|
||||
var targetConn *net.UDPConn
|
||||
|
||||
p.AddCurrentConnections(1)
|
||||
for {
|
||||
targetConn = nil
|
||||
session = nil
|
||||
|
||||
timeout := 1200 * time.Millisecond
|
||||
if p.ReadFromTargetOnce() {
|
||||
timeout = 300 * time.Millisecond
|
||||
}
|
||||
|
||||
if p.ReadFromTargetOnce() {
|
||||
targetConn = tgConn
|
||||
} else {
|
||||
se, ok := p.targetConnectSessions.Load(sessionKey)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
session = se.(*udpTagetConSession)
|
||||
targetConn = session.targetConn
|
||||
}
|
||||
|
||||
targetConn.SetReadDeadline(time.Now().Add(timeout))
|
||||
n, _, err := targetConn.ReadFromUDP(readBuffer)
|
||||
if err != nil {
|
||||
errStr := err.Error()
|
||||
if strings.Contains(errStr, `i/o timeout`) && !p.ReadFromTargetOnce() {
|
||||
continue
|
||||
}
|
||||
if !strings.Contains(errStr, `use of closed network connection`) {
|
||||
p.log.Errorf("[%s]targetConn ReadFromUDP error:%s", p.GetKey(), err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
data := pool.GetBuf(n)
|
||||
copy(data, readBuffer[:n])
|
||||
udpMsg := udpPackge{dataSize: n, data: &data, remoteAddr: raddr}
|
||||
|
||||
if err = errors.PanicToError(func() {
|
||||
select {
|
||||
case p.replyCh <- &udpMsg: //转发数据到远程地址
|
||||
default:
|
||||
}
|
||||
}); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if p.ReadFromTargetOnce() { //一次性
|
||||
return
|
||||
}
|
||||
|
||||
//非一次性,刷新时间或者退出
|
||||
_, ok := p.targetConnectSessions.Load(sessionKey)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *UDPProxy) Forwarder(kk int, replych chan *udpPackge) {
|
||||
|
||||
// read from targetAddr and write clientAddr
|
||||
readFromtargetAddrFunc := func(raddr *net.UDPAddr, udpItemKey string, tgConn *net.UDPConn) {
|
||||
readBuffer := pool.GetBuf(p.GetUDPPacketSize())
|
||||
defer func() {
|
||||
pool.PutBuf(readBuffer)
|
||||
if p.ReadFromTargetOnce() {
|
||||
tgConn.Close()
|
||||
}
|
||||
p.AddCurrentConnections(-1)
|
||||
}()
|
||||
|
||||
var targetConn *net.UDPConn
|
||||
var udpItem *udpMapItem
|
||||
var ok bool
|
||||
p.AddCurrentConnections(1)
|
||||
for {
|
||||
targetConn = nil
|
||||
udpItem = nil
|
||||
|
||||
timeout := 1200 * time.Millisecond
|
||||
if p.ReadFromTargetOnce() {
|
||||
timeout = 30 * time.Millisecond
|
||||
}
|
||||
|
||||
if p.ReadFromTargetOnce() {
|
||||
targetConn = tgConn
|
||||
} else {
|
||||
p.targetudpConnItemMapMutex.RLock()
|
||||
udpItem, ok = p.targetudpConnItemMap[udpItemKey]
|
||||
if !ok {
|
||||
p.targetudpConnItemMapMutex.RUnlock()
|
||||
return
|
||||
}
|
||||
p.targetudpConnItemMapMutex.RUnlock()
|
||||
targetConn = udpItem.conn
|
||||
}
|
||||
|
||||
targetConn.SetReadDeadline(time.Now().Add(timeout))
|
||||
n, _, err := targetConn.ReadFromUDP(readBuffer)
|
||||
if err != nil {
|
||||
errStr := err.Error()
|
||||
|
||||
if strings.Contains(errStr, `i/o timeout`) && !p.ReadFromTargetOnce() {
|
||||
continue
|
||||
}
|
||||
if !strings.Contains(errStr, `use of closed network connection`) {
|
||||
log.Printf("targetConn ReadFromUDP error:%s", err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
data := pool.GetBuf(n)
|
||||
copy(data, readBuffer[:n])
|
||||
udpMsg := udpPackge{dataSize: n, data: &data, remoteAddr: raddr}
|
||||
|
||||
if err = errors.PanicToError(func() {
|
||||
select {
|
||||
case p.replyCh <- &udpMsg:
|
||||
default:
|
||||
}
|
||||
}); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !p.ReadFromTargetOnce() {
|
||||
p.targetudpConnItemMapMutex.Lock()
|
||||
udpItem, ok := p.targetudpConnItemMap[udpItemKey]
|
||||
if ok {
|
||||
udpItem.lastTime = time.Now()
|
||||
}
|
||||
p.targetudpConnItemMapMutex.Unlock()
|
||||
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if p.ReadFromTargetOnce() {
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
var targetConn *net.UDPConn
|
||||
|
||||
// read from readCh
|
||||
for udpMsg := range replych {
|
||||
err = nil
|
||||
targetConn = nil
|
||||
se, ok := p.targetConnectSessions.Load(udpMsg.remoteAddr.String())
|
||||
|
||||
//if p.ReadFromTargetOnce()
|
||||
p.targetudpConnItemMapMutex.Lock()
|
||||
udpConnItem, ok := p.targetudpConnItemMap[udpMsg.remoteAddr.String()]
|
||||
if !ok || p.ReadFromTargetOnce() { //??
|
||||
|
||||
tgAddr, err := net.ResolveUDPAddr(p.ProxyType, p.GetTargetAddress())
|
||||
if !ok {
|
||||
err := p.CheckReadTargetDataGoroutineLimit()
|
||||
if err != nil {
|
||||
log.Printf("net.ResolveUDPAddr[%s] error:%s", p.GetTargetAddress(), err.Error())
|
||||
p.targetudpConnItemMapMutex.Unlock()
|
||||
p.log.Warnf("[%s]转发中止:%s", p.GetKey(), err.Error())
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
var session *udpTagetConSession
|
||||
if ok {
|
||||
session = se.(*udpTagetConSession)
|
||||
} else {
|
||||
session = &udpTagetConSession{}
|
||||
}
|
||||
|
||||
if !ok {
|
||||
addr := p.GetTargetAddress()
|
||||
tgAddr, err := net.ResolveUDPAddr("udp", addr)
|
||||
if err != nil {
|
||||
p.log.Errorf("[%s]UDP端口转发目标地址[%s]解析出错:%s", p.GetKey(), addr, err.Error())
|
||||
pool.PutBuf(*udpMsg.data)
|
||||
continue
|
||||
}
|
||||
|
||||
targetConn, err = net.DialUDP("udp", nil, tgAddr)
|
||||
|
||||
targetConn, err := net.DialUDP("udp", nil, tgAddr)
|
||||
if err != nil {
|
||||
p.targetudpConnItemMapMutex.Unlock()
|
||||
p.log.Errorf("[%s]UDP端口转发目标地址[%s]连接出错:%s", p.GetKey(), addr, err.Error())
|
||||
pool.PutBuf(*udpMsg.data)
|
||||
continue
|
||||
}
|
||||
targetConn.SetWriteBuffer(4 * 1024 * 1024)
|
||||
targetConn.SetReadBuffer(4 * 1024 * 1024)
|
||||
|
||||
if !ok && !p.ReadFromTargetOnce() {
|
||||
p.AddCurrentConnections(1)
|
||||
newItem := udpMapItem{conn: targetConn, lastTime: time.Now()}
|
||||
p.targetudpConnItemMap[udpMsg.remoteAddr.String()] = &newItem
|
||||
udpConnItem = &newItem
|
||||
}
|
||||
|
||||
} else {
|
||||
udpConnItem.lastTime = time.Now()
|
||||
targetConn = udpConnItem.conn
|
||||
session.targetConn = targetConn
|
||||
}
|
||||
p.targetudpConnItemMapMutex.Unlock()
|
||||
session.lastTime = time.Now()
|
||||
|
||||
p.ReceiveDataCallback(int64(udpMsg.dataSize))
|
||||
_, err = targetConn.Write(*udpMsg.data)
|
||||
if !p.ReadFromTargetOnce() { //只存储非一次性
|
||||
p.targetConnectSessions.Store(udpMsg.remoteAddr.String(), session)
|
||||
}
|
||||
|
||||
p.ReceiveDataCallback(int64(udpMsg.dataSize)) //接收流量记录
|
||||
|
||||
_, err = session.targetConn.Write(*udpMsg.data)
|
||||
if err != nil {
|
||||
targetConn.Close()
|
||||
p.log.Errorf("[%s]转发数据到目标端口出错:%s", p.GetKey(), err.Error())
|
||||
session.targetConn.Close()
|
||||
continue
|
||||
}
|
||||
pool.PutBuf(*udpMsg.data)
|
||||
|
||||
if !ok || p.ReadFromTargetOnce() {
|
||||
go readFromtargetAddrFunc(udpMsg.remoteAddr, udpMsg.remoteAddr.String(), targetConn)
|
||||
if !ok {
|
||||
go p.handlerDataFromTargetAddress(udpMsg.remoteAddr, session.targetConn)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -391,43 +382,42 @@ func (p *UDPProxy) replyDataToRemotAddress() {
|
|||
_, err := p.listenConn.WriteToUDP(*(msg.data), msg.remoteAddr)
|
||||
pool.PutBuf(*msg.data)
|
||||
if err != nil {
|
||||
log.Printf("udpConn.WriteToUDP error:%s", err.Error())
|
||||
p.log.Errorf("[%s]转发目标端口数据到远程端口出错:%s", p.GetKey(), err.Error())
|
||||
continue
|
||||
}
|
||||
p.SendDataCallback(int64(msg.dataSize))
|
||||
p.SendDataCallback(int64(msg.dataSize)) //发送流量记录
|
||||
}
|
||||
}
|
||||
|
||||
func (p *UDPProxy) CheckTargetUDPConn() {
|
||||
func (p *UDPProxy) CheckReadTargetDataGoroutineLimit() error {
|
||||
if GetGlobalUDPPortForwardGroutineCount() >= GetGlobalUDPReadTargetDataMaxgoroutineCountLimit() {
|
||||
return fmt.Errorf("超出端口转发全局UDP读取目标地址数据协程数限制[%d]", GetGlobalUDPReadTargetDataMaxgoroutineCountLimit())
|
||||
}
|
||||
|
||||
if p.GetCurrentConnections() >= p.SingleProxyMaxUDPReadTargetDatagoroutineCount {
|
||||
return fmt.Errorf("超出单端口UDP读取目标地址数据协程数限制[%d]", p.SingleProxyMaxUDPReadTargetDatagoroutineCount)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *UDPProxy) CheckTargetUDPConnectSessions() {
|
||||
for {
|
||||
<-time.After(time.Second * 1)
|
||||
// connCout := atomic.LoadInt64(&p.targetudpConnCount)
|
||||
// if connCout <= 0 {
|
||||
// continue
|
||||
// }
|
||||
if p.isStop {
|
||||
return
|
||||
}
|
||||
if p.GetCurrentConnections() <= 0 {
|
||||
continue
|
||||
}
|
||||
p.targetudpConnItemMapMutex.Lock()
|
||||
|
||||
var deleteList []string
|
||||
|
||||
for k, v := range p.targetudpConnItemMap {
|
||||
if time.Since(v.lastTime) >= 30*time.Second {
|
||||
v.conn.Close()
|
||||
deleteList = append(deleteList, k)
|
||||
p.targetConnectSessions.Range(func(key any, value any) bool {
|
||||
session := value.(*udpTagetConSession)
|
||||
if time.Since(session.lastTime) >= 30*time.Second {
|
||||
session.targetConn.Close()
|
||||
p.targetConnectSessions.Delete(key)
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
//fmt.Printf("map:%v\t deleteList:%v\n", p.targetudpConnItemMap, deleteList)
|
||||
|
||||
for i := range deleteList {
|
||||
delete(p.targetudpConnItemMap, deleteList[i])
|
||||
//log.Printf("删除targetudpConnItemMap [%s]\n", deleteList[i])
|
||||
//atomic.AddInt64(&p.targetudpConnCount, -1)
|
||||
p.AddCurrentConnections(-1)
|
||||
}
|
||||
|
||||
p.targetudpConnItemMapMutex.Unlock()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
package blinker
|
||||
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
VA_TYPE_LIGHT = "light"
|
||||
VA_TYPE_OUTLET = "outlet"
|
||||
VA_TYPE_MULTI_OUTLET = "multi_outlet"
|
||||
VA_TYPE_SENSOR = "sensor"
|
||||
VA_TYPE_FAN = "fan"
|
||||
VA_TYPE_AIRCONDITION = "aircondition"
|
||||
)
|
||||
|
||||
type VoiceAssistant struct {
|
||||
DeviceType string //语言助手类型 (设备类型).
|
||||
VAType string //语言助手类型 MIOT AliGenie DuerOS
|
||||
Device *BlinkerDevice
|
||||
topic string
|
||||
}
|
||||
|
||||
func (v *VoiceAssistant) GetSKey() string {
|
||||
switch v.VAType {
|
||||
case "MIOT":
|
||||
return "miType"
|
||||
case "AliGenie":
|
||||
return "aliType"
|
||||
case "DuerOS":
|
||||
return "duerType"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func (v *VoiceAssistant) PowerChangeReply(msgid, st string) {
|
||||
state := "off"
|
||||
|
||||
if st == "true" {
|
||||
state = "on"
|
||||
}
|
||||
|
||||
// if v.VAType == "MIOT" {
|
||||
// if state == "on" {
|
||||
// state = "true"
|
||||
// } else {
|
||||
// state = "false"
|
||||
// }
|
||||
// }
|
||||
|
||||
data := map[string]string{"pState": state}
|
||||
v.Device.SendMessage("vAssistant", v.GetToDevice(), msgid, data)
|
||||
}
|
||||
|
||||
func (v *VoiceAssistant) QueryDeviceState(msgid string) {
|
||||
state := v.Device.state
|
||||
// if v.VAType == "MIOT" {
|
||||
// if state == "on" {
|
||||
// state = "true"
|
||||
// } else {
|
||||
// state = "false"
|
||||
// }
|
||||
// }
|
||||
data := map[string]string{"pState": state}
|
||||
v.Device.SendMessage("vAssistant", v.GetToDevice(), msgid, data)
|
||||
}
|
||||
|
||||
func (v *VoiceAssistant) GetToDevice() string {
|
||||
// if v.Device.DetailInfo.Broker == "blinker" {
|
||||
// return "ServerReceiver"
|
||||
// }
|
||||
return v.topic
|
||||
}
|
||||
|
||||
func CreateVoiceAssistant(deviceType, vaType string) *VoiceAssistant {
|
||||
switch vaType {
|
||||
case "MIOT":
|
||||
return &VoiceAssistant{DeviceType: deviceType, VAType: vaType, topic: fmt.Sprintf("%s_r", vaType)}
|
||||
case "AliGenie":
|
||||
return &VoiceAssistant{DeviceType: deviceType, VAType: vaType, topic: fmt.Sprintf("%s_r", vaType)}
|
||||
case "DuerOS":
|
||||
{
|
||||
newDeviceType := ""
|
||||
switch deviceType {
|
||||
case VA_TYPE_LIGHT:
|
||||
newDeviceType = "LIGHT"
|
||||
case VA_TYPE_OUTLET:
|
||||
newDeviceType = "SOCKET"
|
||||
case VA_TYPE_MULTI_OUTLET:
|
||||
newDeviceType = "MULTI_SOCKET"
|
||||
case VA_TYPE_SENSOR:
|
||||
newDeviceType = "AIR_MONITOR"
|
||||
default:
|
||||
}
|
||||
if newDeviceType == "" {
|
||||
return nil
|
||||
}
|
||||
return &VoiceAssistant{DeviceType: newDeviceType, VAType: vaType, topic: fmt.Sprintf("%s_r", vaType)}
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
|
@ -0,0 +1,439 @@
|
|||
package blinker
|
||||
|
||||
import (
|
||||
"compress/gzip"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/buger/jsonparser"
|
||||
MQTT "github.com/eclipse/paho.mqtt.golang"
|
||||
)
|
||||
|
||||
const (
|
||||
HOST = "https://iot.diandeng.tech"
|
||||
API_AUTH = HOST + "/api/v1/user/device/diy/auth"
|
||||
API_HEARTBEAT = HOST + "/api/v1/user/device/heartbeat"
|
||||
API_VOICE_ASSISTANT = HOST + "/api/v1/user/device/voice_assistant"
|
||||
)
|
||||
|
||||
type BlinkerDevice struct {
|
||||
authKey string
|
||||
|
||||
subTopic string
|
||||
pubTopic string
|
||||
exasubTopic string //aliyun特有
|
||||
exapubTopic string //aliyun特有
|
||||
|
||||
client MQTT.Client
|
||||
DetailInfo BlinkerDetailInfo
|
||||
heartBeatChan chan uint8
|
||||
hbmu sync.Mutex
|
||||
preSendTime time.Time
|
||||
sendMsgChan chan message
|
||||
//
|
||||
state string
|
||||
|
||||
voiceAssistants map[string]*VoiceAssistant
|
||||
}
|
||||
|
||||
type message struct {
|
||||
TargetType string
|
||||
Device string
|
||||
MessageID string
|
||||
Msg any
|
||||
}
|
||||
|
||||
func CreateBlinkerDevice(ak string) *BlinkerDevice {
|
||||
d := &BlinkerDevice{authKey: ak}
|
||||
d.voiceAssistants = make(map[string]*VoiceAssistant)
|
||||
d.state = "on"
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *BlinkerDevice) AddVoiceAssistant(v *VoiceAssistant) {
|
||||
v.Device = d
|
||||
d.voiceAssistants[v.VAType] = v
|
||||
}
|
||||
|
||||
func (d *BlinkerDevice) SyncAssistants() error {
|
||||
for _, v := range d.voiceAssistants {
|
||||
skey := v.GetSKey()
|
||||
dataMap := make(map[string]string)
|
||||
dataMap["token"] = d.DetailInfo.IotToken
|
||||
dataMap[skey] = v.DeviceType
|
||||
|
||||
dataBytes, _ := json.Marshal(dataMap)
|
||||
|
||||
resp, err := http.Post(API_VOICE_ASSISTANT, "application/json", strings.NewReader(string(dataBytes)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = GetBytesFromHttpResponse(resp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//fmt.Printf("同步语音助手结果:%s\n", respBytes)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *BlinkerDevice) RunSenderMessageService() {
|
||||
for m := range d.sendMsgChan {
|
||||
t := time.Since(d.preSendTime) - time.Millisecond*1100
|
||||
if t < 0 {
|
||||
//log.Printf("太快,睡眠一下:%d\n", -t)
|
||||
<-time.After(-t)
|
||||
}
|
||||
d.sendMessage(m.TargetType, m.Device, m.MessageID, m.Msg)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (d *BlinkerDevice) RunHeartBearTimer() {
|
||||
if !d.hbmu.TryLock() {
|
||||
return
|
||||
}
|
||||
defer d.hbmu.Unlock()
|
||||
log.Printf("开始心跳...\n")
|
||||
d.heartBeatChan <- uint8(1)
|
||||
for range d.heartBeatChan {
|
||||
d.heartBeat()
|
||||
<-time.After(time.Second * 599)
|
||||
d.heartBeatChan <- uint8(1)
|
||||
}
|
||||
log.Printf("心跳中止...\n")
|
||||
}
|
||||
|
||||
func (d *BlinkerDevice) Init() error {
|
||||
apiurl := fmt.Sprintf("%s?authKey=%s", API_AUTH, d.authKey)
|
||||
resp, err := http.Get(apiurl)
|
||||
if err != nil {
|
||||
return fmt.Errorf("device init http.Get err:%s", err.Error())
|
||||
}
|
||||
|
||||
var infoRes BlinkerInfoRes
|
||||
err = GetAndParseJSONResponseFromHttpResponse(resp, &infoRes)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parse DeviceInfo resp err:%s", err.Error())
|
||||
}
|
||||
|
||||
d.DetailInfo = infoRes.Detail
|
||||
|
||||
err = d.SyncAssistants()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// if d.DetailInfo.Broker == "blinker" {
|
||||
// d.subTopic = fmt.Sprintf("/device/%s/r", d.DetailInfo.DeviceName)
|
||||
// d.pubTopic = fmt.Sprintf("/device/%s/s", d.DetailInfo.DeviceName)
|
||||
// return nil
|
||||
// }
|
||||
|
||||
// if d.DetailInfo.Broker == "aliyun" {
|
||||
// d.subTopic = fmt.Sprintf("/%s/%s/r", d.DetailInfo.ProductKey, d.DetailInfo.DeviceName)
|
||||
// d.pubTopic = fmt.Sprintf("/%s/%s/s", d.DetailInfo.ProductKey, d.DetailInfo.DeviceName)
|
||||
// d.exasubTopic = "/device/ServerSender/r"
|
||||
// d.exapubTopic = "/device/ServerReceiver/s"
|
||||
// return nil
|
||||
// }
|
||||
|
||||
d.subTopic = fmt.Sprintf("/device/%s/r", d.DetailInfo.DeviceName)
|
||||
d.pubTopic = fmt.Sprintf("/device/%s/s", d.DetailInfo.DeviceName)
|
||||
d.exasubTopic = "/device/ServerSender/r"
|
||||
d.exapubTopic = "/device/ServerReceiver/s"
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *BlinkerDevice) Login() error {
|
||||
opts := MQTT.NewClientOptions()
|
||||
|
||||
brokeyURL := fmt.Sprintf("%s:%s", d.DetailInfo.Host, d.DetailInfo.Port)
|
||||
|
||||
//brokeyURL := fmt.Sprintf("tcp://broker.diandeng.tech:%s", d.DetailInfo.Port)
|
||||
opts.AddBroker(brokeyURL)
|
||||
opts.SetClientID(d.DetailInfo.DeviceName)
|
||||
opts.SetUsername(d.DetailInfo.IotID)
|
||||
opts.SetPassword(d.DetailInfo.IotToken)
|
||||
|
||||
//opts.SetKeepAlive(time.Second * 3)
|
||||
//opts.WillRetained = true
|
||||
|
||||
//choke := make(chan [2]string)
|
||||
// opts.SetDefaultPublishHandler(func(client MQTT.Client, msg MQTT.Message) {
|
||||
// //choke <- [2]string{msg.Topic(), string(msg.Payload())}
|
||||
// msg.Payload()
|
||||
// })
|
||||
|
||||
opts.SetOnConnectHandler(func(c MQTT.Client) {
|
||||
log.Printf("连接成功!")
|
||||
d.client = c
|
||||
c.Subscribe(d.subTopic, byte(0), d.ReceiveMessageHandler)
|
||||
//c.Subscribe(d.exasubTopic, byte(0), d.ReceiveMessageHandler)
|
||||
d.heartBeatChan = make(chan uint8, 1)
|
||||
go d.RunHeartBearTimer()
|
||||
d.sendMsgChan = make(chan message, 8)
|
||||
go d.RunSenderMessageService()
|
||||
})
|
||||
|
||||
opts.OnConnectionLost = func(c MQTT.Client, err error) {
|
||||
log.Printf("连接丢失:%s\n", err.Error())
|
||||
close(d.heartBeatChan)
|
||||
close(d.sendMsgChan)
|
||||
d.client = nil
|
||||
}
|
||||
|
||||
//opts.
|
||||
|
||||
client := MQTT.NewClient(opts)
|
||||
|
||||
if token := client.Connect(); token.Wait() && token.Error() != nil {
|
||||
return fmt.Errorf("连接出错:%s", token.Error())
|
||||
}
|
||||
|
||||
<-time.After(time.Second * 60000)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *BlinkerDevice) heartBeat() error {
|
||||
|
||||
//hr := fmt.Sprintf("%s?deviceName=%s&key=%s&heartbeat=600", SERVER+HEARTBEAT_URL, d.DetailInfo.DeviceName, d.authKey)
|
||||
|
||||
hr := fmt.Sprintf("%s?deviceName=%s&key=%s&heartbeat=600", API_HEARTBEAT, d.DetailInfo.DeviceName, d.authKey)
|
||||
resp, err := http.Get(hr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("device init http.Get err:%s", err.Error())
|
||||
}
|
||||
|
||||
respBytes, err := GetBytesFromHttpResponse(resp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("HearBeat:%s\n", string(respBytes))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *BlinkerDevice) ReceiveMessageHandler(c MQTT.Client, m MQTT.Message) {
|
||||
|
||||
log.Printf("接收到MQTT消息:【%s】%s\n", m.Topic(), m.Payload())
|
||||
|
||||
if m.Topic() != d.subTopic {
|
||||
return
|
||||
}
|
||||
|
||||
fromDevice, fromDeviceErr := jsonparser.GetString(m.Payload(), "fromDevice")
|
||||
if fromDeviceErr != nil || (fromDevice != d.DetailInfo.UUID && fromDevice != "ServerSender") {
|
||||
return
|
||||
}
|
||||
|
||||
if fromDevice == d.DetailInfo.UUID {
|
||||
d.ownAppMessagehandler(m.Payload())
|
||||
return
|
||||
}
|
||||
|
||||
from, fromErr := jsonparser.GetString(m.Payload(), "data", "from")
|
||||
if fromErr != nil {
|
||||
return
|
||||
}
|
||||
switch from {
|
||||
case "MIOT", "AliGenie", "DuerOS":
|
||||
d.voiceAssistantMessageHandler(from, m.Payload())
|
||||
default:
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (d *BlinkerDevice) voiceAssistantMessageHandler(from string, msg []byte) {
|
||||
|
||||
fmt.Printf("from:%s msg:%s\n", from, string(msg))
|
||||
|
||||
va, ok := d.voiceAssistants[from]
|
||||
if !ok {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
//fmt.Printf("voiceAssistantMessageHandler\t msg:[%s]\n", msg)
|
||||
messageId, messageIdErr := jsonparser.GetString(msg, "data", "messageId")
|
||||
if messageIdErr != nil {
|
||||
return
|
||||
}
|
||||
|
||||
//jsonparser.GetString(msg, "data", "set")
|
||||
pstate, pstateErr := jsonparser.GetString(msg, "data", "set", "pState")
|
||||
if pstateErr == nil {
|
||||
d.powerChange(va, messageId, pstate)
|
||||
return
|
||||
}
|
||||
|
||||
_, getKeyerr := jsonparser.GetString(msg, "data", "get")
|
||||
if getKeyerr == nil {
|
||||
va.QueryDeviceState(messageId)
|
||||
}
|
||||
//va.Power()
|
||||
|
||||
}
|
||||
|
||||
func (d *BlinkerDevice) powerChange(va *VoiceAssistant, msgId, state string) {
|
||||
d.state = state
|
||||
if va != nil {
|
||||
va.PowerChangeReply(msgId, state)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *BlinkerDevice) ownAppMessagehandler(msg []byte) {
|
||||
getValue, getKeyError := jsonparser.GetString(msg, "data", "get")
|
||||
if getKeyError == nil {
|
||||
switch getValue {
|
||||
case "state":
|
||||
d.SendMessage("OwnApp", d.DetailInfo.UUID, "", map[string]any{"state": "online"})
|
||||
case "timing":
|
||||
d.SendMessage("OwnApp", d.DetailInfo.UUID, "", map[string]any{"timing": map[string]any{"timing": []any{}}}) //{"timing":{"timing":[]}}
|
||||
case "countdown":
|
||||
d.SendMessage("OwnApp", d.DetailInfo.UUID, "", map[string]any{"countdown": "false"}) //`{ "countdown": false }`
|
||||
default:
|
||||
fmt.Printf(` "data", "get":Value:%s`, getValue)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
type mess2device struct {
|
||||
DeviceType string `json:"deviceType"`
|
||||
Data any `json:"data"`
|
||||
FromDeivce string `json:"fromDevice"`
|
||||
ToDevice string `json:"toDevice"`
|
||||
}
|
||||
|
||||
type mess2assistant struct {
|
||||
DeviceType string `json:"deviceType"`
|
||||
Data any `json:"data"`
|
||||
FromDeivce string `json:"fromDevice"`
|
||||
ToDevice string `json:"toDevice"`
|
||||
MessageID string `json:"-"` //`json:"messageId"`
|
||||
}
|
||||
|
||||
func (d *BlinkerDevice) formatMess2assistant(targetType, toDevice, msgid string, data any) ([]byte, error) {
|
||||
m := mess2assistant{DeviceType: targetType, Data: data, FromDeivce: d.DetailInfo.DeviceName, ToDevice: toDevice, MessageID: msgid}
|
||||
rawBytes, err := json.Marshal(m)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
|
||||
str := base64.StdEncoding.EncodeToString(rawBytes)
|
||||
log.Printf("回复语音助手:%s\n", string(rawBytes))
|
||||
//fmt.Printf("base64:%s\n", str)
|
||||
|
||||
return []byte(str), nil
|
||||
//return rawBytes, nil
|
||||
}
|
||||
|
||||
func (d *BlinkerDevice) formatMess2Device(targetType, toDevice string, data any) ([]byte, error) {
|
||||
m := mess2device{DeviceType: targetType, Data: data, FromDeivce: d.DetailInfo.DeviceName, ToDevice: toDevice}
|
||||
return json.Marshal(m)
|
||||
}
|
||||
|
||||
func (d *BlinkerDevice) SendMessage(targetType, todevice, msgid string, msg any) {
|
||||
m := message{Device: todevice, Msg: msg, TargetType: targetType, MessageID: msgid}
|
||||
d.sendMsgChan <- m
|
||||
}
|
||||
|
||||
func (d *BlinkerDevice) sendMessage(targetType, todevice, msgid string, msg any) error {
|
||||
if d.client == nil {
|
||||
return fmt.Errorf("SendMessage error:client == nil")
|
||||
}
|
||||
var pubTopic string
|
||||
var payload []byte
|
||||
var err error
|
||||
if targetType == "OwnApp" {
|
||||
pubTopic = d.pubTopic
|
||||
payload, err = d.formatMess2Device(targetType, todevice, msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if targetType == "vAssistant" {
|
||||
//pubTopic = "/device/ServerReceiver/s"
|
||||
//pubTopic = fmt.Sprintf("/sys/%s/%s/rrpc/response/%s", d.DetailInfo.ProductKey, d.DetailInfo.DeviceName, msgid)
|
||||
//pubTopic = fmt.Sprintf("%s", d.exapubTopic)
|
||||
pubTopic = d.pubTopic
|
||||
payload, err = d.formatMess2assistant(targetType, todevice, msgid, msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("topic:%s\n", pubTopic)
|
||||
|
||||
if token := d.client.Publish(pubTopic, 0, false, payload); token.Wait() && token.Error() != nil {
|
||||
fmt.Printf("Publish error:%s\n", token.Error())
|
||||
return token.Error()
|
||||
}
|
||||
d.preSendTime = time.Now()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//-----------------------
|
||||
|
||||
type BlinkerDetailInfo struct {
|
||||
Broker string `json:"broker"`
|
||||
DeviceName string `json:"deviceName"`
|
||||
Host string `json:"host"`
|
||||
IotID string `json:"iotId"`
|
||||
IotToken string `json:"iotToken"`
|
||||
Port string `json:"port"`
|
||||
ProductKey string `json:"productKey"`
|
||||
UUID string `json:"uuid"`
|
||||
}
|
||||
|
||||
type BlinkerInfoRes struct {
|
||||
Message int `json:"message"`
|
||||
Detail BlinkerDetailInfo `json:"detail"`
|
||||
}
|
||||
|
||||
// GetStringFromHttpResponse 从response获取
|
||||
func GetBytesFromHttpResponse(resp *http.Response) ([]byte, error) {
|
||||
if resp == nil || resp.Body == nil {
|
||||
return []byte{}, fmt.Errorf("resp.Body = nil")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var body []byte
|
||||
var err error
|
||||
if resp.Header.Get("Content-Encoding") == "gzip" {
|
||||
reader, err := gzip.NewReader(resp.Body)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
body, err = ioutil.ReadAll(reader)
|
||||
return body, err
|
||||
}
|
||||
body, err = ioutil.ReadAll(resp.Body)
|
||||
return body, err
|
||||
}
|
||||
|
||||
func GetAndParseJSONResponseFromHttpResponse(resp *http.Response, result interface{}) error {
|
||||
bytes, err := GetBytesFromHttpResponse(resp)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetBytesFromHttpResponse err:%s", err.Error())
|
||||
}
|
||||
if len(bytes) > 0 {
|
||||
err = json.Unmarshal(bytes, &result)
|
||||
if err != nil {
|
||||
//log.Printf("请求接口解析json结果失败! ERROR: %s\n", err)
|
||||
return fmt.Errorf("GetAndParseJSONResponseFromHttpResponse 解析JSON结果出错:%s", err.Error())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -12,6 +12,7 @@ import (
|
|||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/proxy"
|
||||
|
@ -239,6 +240,13 @@ func NewTransport(transportNetwork,
|
|||
Timeout: 30 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
LocalAddr: localAddr,
|
||||
Control: func(network, address string, c syscall.RawConn) error {
|
||||
// fmt.Printf("network:%s\taddress:%s\n", network, address)
|
||||
if network != transportNetwork && transportNetwork != "tcp" {
|
||||
return fmt.Errorf("must use :%s", transportNetwork)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
||||
transport = &http.Transport{
|
||||
|
|
|
@ -49,9 +49,10 @@ func (l *LogsBuffer) Fire(entry *logrus.Entry) error {
|
|||
return fmt.Errorf("entry.String() err:%s", err.Error())
|
||||
}
|
||||
|
||||
l.AddLog(entry.Time, entryStr, entry.Data)
|
||||
if l.fireCallback != nil {
|
||||
return l.fireCallback(entry)
|
||||
} else {
|
||||
l.AddLog(entry.Time, entryStr, entry.Data)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -169,3 +170,30 @@ func (l *LogsBuffer) GetLogCount() int {
|
|||
defer l.mu.Unlock()
|
||||
return len(l.logsStore)
|
||||
}
|
||||
|
||||
//---------------------------
|
||||
|
||||
var LogsBufferStore map[string]*LogsBuffer
|
||||
var LogsBufferStoreMu sync.Mutex
|
||||
|
||||
func init() {
|
||||
LogsBufferStore = make(map[string]*LogsBuffer)
|
||||
}
|
||||
|
||||
func CreateLogbuffer(key string, buffSize int) *LogsBuffer {
|
||||
if strings.TrimSpace(key) == "" {
|
||||
return nil
|
||||
}
|
||||
LogsBufferStoreMu.Lock()
|
||||
defer LogsBufferStoreMu.Unlock()
|
||||
var buf *LogsBuffer
|
||||
var ok bool
|
||||
if buf, ok = LogsBufferStore[key]; !ok {
|
||||
buf = &LogsBuffer{}
|
||||
buf.SetBufferSize(buffSize)
|
||||
LogsBufferStore[key] = buf
|
||||
} else if buf.GetBufferSize() != buffSize {
|
||||
buf.SetBufferSize(buffSize)
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
|
|
@ -152,3 +152,45 @@ func GetIPFromNetInterface(ipType, netinterface, ipreg string) string {
|
|||
|
||||
return ""
|
||||
}
|
||||
|
||||
func GetGlobalIPv4BroadcastList() []string {
|
||||
var res []string
|
||||
allNetInterfaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return res
|
||||
}
|
||||
|
||||
for i := 0; i < len(allNetInterfaces); i++ {
|
||||
if (allNetInterfaces[i].Flags & net.FlagUp) != 0 {
|
||||
addrs, _ := allNetInterfaces[i].Addrs()
|
||||
|
||||
for _, address := range addrs {
|
||||
if ipnet, ok := address.(*net.IPNet); ok && ipnet.IP.IsGlobalUnicast() {
|
||||
_, bits := ipnet.Mask.Size()
|
||||
// 需匹配全局单播地址
|
||||
//if bits == 128 && ipv6Unicast.Contains(ipnet.IP) {
|
||||
|
||||
if bits == 32 {
|
||||
//ipv4 = append(ipv4, ipnet.IP.String())
|
||||
bcst := GetBroadcast(ipnet.IP, ipnet.Mask)
|
||||
res = append(res, bcst)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func GetBroadcast(ip net.IP, mask net.IPMask) string {
|
||||
|
||||
bcst := make(net.IP, len(ip))
|
||||
copy(bcst, ip)
|
||||
for i := 0; i < len(mask); i++ {
|
||||
ipIdx := len(bcst) - i - 1
|
||||
bcst[ipIdx] = ip[ipIdx] | ^mask[len(mask)-i-1]
|
||||
}
|
||||
return bcst.String()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package stringsp
|
||||
|
||||
func StrIsInList(str string, strList []string) bool {
|
||||
checkMap := make(map[string]uint8)
|
||||
for i := range strList {
|
||||
checkMap[strList[i]] = 1
|
||||
}
|
||||
if _, ok := checkMap[str]; ok {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package wol
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var (
|
||||
delims = ":-"
|
||||
reMAC = regexp.MustCompile(`^([0-9a-fA-F]{2}[` + delims + `]){5}([0-9a-fA-F]{2})$`)
|
||||
)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// MACAddress represents a 6 byte network mac address.
|
||||
type MACAddress [6]byte
|
||||
|
||||
// MagicPacket is constituted of 6 bytes of 0xFF followed by 16-groups of the
|
||||
// destination MAC address.
|
||||
type MagicPacket struct {
|
||||
header [6]byte
|
||||
payload [16]MACAddress
|
||||
}
|
||||
|
||||
// New returns a magic packet based on a mac address string.
|
||||
func New(mac string) (*MagicPacket, error) {
|
||||
var packet MagicPacket
|
||||
var macAddr MACAddress
|
||||
|
||||
hwAddr, err := net.ParseMAC(mac)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// We only support 6 byte MAC addresses since it is much harder to use the
|
||||
// binary.Write(...) interface when the size of the MagicPacket is dynamic.
|
||||
if !reMAC.MatchString(mac) {
|
||||
return nil, fmt.Errorf("%s is not a IEEE 802 MAC-48 address", mac)
|
||||
}
|
||||
|
||||
// Copy bytes from the returned HardwareAddr -> a fixed size MACAddress.
|
||||
for idx := range macAddr {
|
||||
macAddr[idx] = hwAddr[idx]
|
||||
}
|
||||
|
||||
// Setup the header which is 6 repetitions of 0xFF.
|
||||
for idx := range packet.header {
|
||||
packet.header[idx] = 0xFF
|
||||
}
|
||||
|
||||
// Setup the payload which is 16 repetitions of the MAC addr.
|
||||
for idx := range packet.payload {
|
||||
packet.payload[idx] = macAddr
|
||||
}
|
||||
|
||||
return &packet, nil
|
||||
}
|
||||
|
||||
// Marshal serializes the magic packet structure into a 102 byte slice.
|
||||
func (mp *MagicPacket) Marshal() ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
if err := binary.Write(&buf, binary.BigEndian, mp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
package wol
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
func WakeUpRepeat(macAddr, broadcastIP, bcastInterface string, port, repeat int) {
|
||||
i := 0
|
||||
for {
|
||||
WakeUp(macAddr, broadcastIP, bcastInterface, port)
|
||||
i++
|
||||
if i >= repeat {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func WakeUp(macAddr, broadcastIP, bcastInterface string, port int) error {
|
||||
var localAddr *net.UDPAddr
|
||||
var err error
|
||||
if bcastInterface != "" {
|
||||
localAddr, err = ipFromInterface(bcastInterface)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
bcastAddr := fmt.Sprintf("%s:%d", broadcastIP, port)
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", bcastAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Build the magic packet.
|
||||
mp, err := New(macAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bs, err := mp.Marshal()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
conn, err := net.DialUDP("udp", localAddr, udpAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
//fmt.Printf("Attempting to send a magic packet to MAC %s\n", macAddr)
|
||||
//fmt.Printf("... Broadcasting to: %s\n", bcastAddr)
|
||||
n, err := conn.Write(bs)
|
||||
if err == nil && n != 102 {
|
||||
err = fmt.Errorf("magic packet sent was %d bytes (expected 102 bytes sent)", n)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//fmt.Printf("Magic packet sent successfully to %s\n", macAddr)
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// ipFromInterface returns a `*net.UDPAddr` from a network interface name.
|
||||
func ipFromInterface(iface string) (*net.UDPAddr, error) {
|
||||
ief, err := net.InterfaceByName(iface)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
addrs, err := ief.Addrs()
|
||||
if err == nil && len(addrs) <= 0 {
|
||||
err = fmt.Errorf("no address associated with interface %s", iface)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Validate that one of the addrs is a valid network IP address.
|
||||
for _, addr := range addrs {
|
||||
switch ip := addr.(type) {
|
||||
case *net.IPNet:
|
||||
if !ip.IP.IsLoopback() && ip.IP.To4() != nil {
|
||||
return &net.UDPAddr{
|
||||
IP: ip.IP,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("no address associated with interface %s", iface)
|
||||
}
|
13
web.go
13
web.go
|
@ -1,16 +1,11 @@
|
|||
//go:build adminweb
|
||||
// +build adminweb
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gdy666/lucky/config"
|
||||
"github.com/gdy666/lucky/web"
|
||||
"log"
|
||||
)
|
||||
|
||||
func RunAdminWeb(listenPort, logMaxSize int) {
|
||||
listen := fmt.Sprintf(":%d", listenPort)
|
||||
go web.RunAdminWeb(listen, logMaxSize)
|
||||
log.Printf("AdminWeb listen on %s", listen)
|
||||
func RunAdminWeb(conf *config.BaseConfigure) {
|
||||
//listen := fmt.Sprintf(":%d", listenPort)
|
||||
go web.RunAdminWeb(conf)
|
||||
}
|
||||
|
|
|
@ -46,12 +46,15 @@ declare module '@vue/runtime-core' {
|
|||
Log: typeof import('./src/components/Log.vue')['default']
|
||||
Login: typeof import('./src/components/Login.vue')['default']
|
||||
Pmenu: typeof import('./src/components/Pmenu.vue')['default']
|
||||
PortForward: typeof import('./src/components/PortForward.vue')['default']
|
||||
PortForwardSet: typeof import('./src/components/PortForwardSet.vue')['default']
|
||||
PSet: typeof import('./src/components/PSet.vue')['default']
|
||||
RelaySet: typeof import('./src/components/RelaySet.vue')['default']
|
||||
ReverseProxy: typeof import('./src/components/ReverseProxy.vue')['default']
|
||||
SSL: typeof import('./src/components/SSL.vue')['default']
|
||||
Status: typeof import('./src/components/Status.vue')['default']
|
||||
WhiteLists: typeof import('./src/components/WhiteLists.vue')['default']
|
||||
WhiteListSet: typeof import('./src/components/WhiteListSet.vue')['default']
|
||||
WOL: typeof import('./src/components/tools/WOL.vue')['default']
|
||||
}
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -8,8 +8,8 @@
|
|||
|
||||
|
||||
<title>Lucky</title>
|
||||
<script type="module" crossorigin src="/assets/index.2c06576c.js"></script>
|
||||
<link rel="stylesheet" href="/assets/index.6859b28a.css">
|
||||
<script type="module" crossorigin src="/assets/index.e5c8aec2.js"></script>
|
||||
<link rel="stylesheet" href="/assets/index.f23c7bd8.css">
|
||||
</head>
|
||||
<body style="margin:0">
|
||||
<div id="app"></div>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -17,7 +17,6 @@
|
|||
<el-main id="pageContent">
|
||||
<Log v-if="global.currentPage.value=='#log'?true:false"></Log>
|
||||
<Status v-if="global.currentPage.value=='#status'?true:false"></Status>
|
||||
<Relayset v-if="global.currentPage.value=='#relayset'?true:false"></Relayset>
|
||||
<Pset v-if="global.currentPage.value=='#set'?true:false"></Pset>
|
||||
<Login v-if="global.currentPage.value=='#login'?true:false"></Login>
|
||||
<WhiteListSet v-if="global.currentPage.value=='#whitelistset'?true:false"></WhiteListSet>
|
||||
|
@ -26,7 +25,11 @@
|
|||
<DDNS v-if="global.currentPage.value=='#ddnstasklist'?true:false"></DDNS>
|
||||
<DDNSSet v-if="global.currentPage.value=='#ddnsset'?true:false"></DDNSSet>
|
||||
<ReverseProxy v-if="global.currentPage.value=='#reverseproxylist'?true:false"></ReverseProxy>
|
||||
<SSL v-if="global.currentPage.value=='#ssl'?true:false"></SSL>
|
||||
<About v-if="global.currentPage.value=='#about'?true:false"></About>
|
||||
<PortForward v-if="global.currentPage.value=='#portforward'"></PortForward>
|
||||
<PortForwardSet v-if="global.currentPage.value=='#portforwardset'"></PortForwardSet>
|
||||
<WOL v-if="global.currentPage.value=='#wol'"></WOL>
|
||||
</el-main>
|
||||
|
||||
</el-container>
|
||||
|
@ -43,7 +46,6 @@ import { onMounted,ref,inject ,computed } from 'vue'
|
|||
import Status from './components/status.vue'
|
||||
import Log from './components/log.vue';
|
||||
import Pmenu from './components/pmenu.vue';
|
||||
import Relayset from './components/relayset.vue';
|
||||
import Pset from './components/pset.vue';
|
||||
import Login from './components/login.vue';
|
||||
import WhiteListSet from './components/WhiteListSet.vue';
|
||||
|
@ -52,9 +54,10 @@ import BlackLists from './components/BlackLists.vue';
|
|||
import DDNS from './components/DDNS.vue';
|
||||
import ReverseProxy from './components/reverseproxy.vue';
|
||||
|
||||
|
||||
import {apiGetVersion} from "./apis/utils.js"
|
||||
import DDNSSet from './components/DDNSSet.vue';
|
||||
|
||||
import SSL from './components/SSL.vue'
|
||||
|
||||
//console.log("111")
|
||||
|
||||
|
|
|
@ -339,6 +339,45 @@ export function apiGetConfigure() {
|
|||
})
|
||||
}
|
||||
|
||||
export function apiDeleteSSL(key) {
|
||||
return httpRequest({
|
||||
url: '/api/ssl',
|
||||
method: 'delete',
|
||||
method: 'delete',
|
||||
headers:{'Authorization':GetToken()},
|
||||
params:{_:new Date().valueOf(),key:key}
|
||||
})
|
||||
}
|
||||
|
||||
export function apiAddSSL(data) {
|
||||
return httpRequest({
|
||||
url: '/api/ssl',
|
||||
method: 'post',
|
||||
headers:{'Authorization':GetToken()},
|
||||
data:data
|
||||
})
|
||||
}
|
||||
|
||||
export function apiAlterSSL(key,field,value) {
|
||||
return httpRequest({
|
||||
url: '/api/ssl',
|
||||
method: 'put',
|
||||
headers:{'Authorization':GetToken()},
|
||||
params:{key:key,field:field,value:value},
|
||||
})
|
||||
}
|
||||
|
||||
export function apiGetSSLList(data) {
|
||||
return httpRequest({
|
||||
url: '/api/ssl',
|
||||
method: 'get',
|
||||
headers:{'Authorization':GetToken()},
|
||||
params:{_:new Date().valueOf()}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
export function apiAddReverseProxyRule(data) {
|
||||
return httpRequest({
|
||||
|
@ -404,3 +443,130 @@ export function apiReverseProxyRuleLogs(ruleKey,proxyKey,pageSize,page) {
|
|||
page:page}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
|
||||
export function apiGetPortForwardRuleList() {
|
||||
return httpRequest({
|
||||
url: '/api/portforwards',
|
||||
method: 'get',
|
||||
headers:{'Authorization':GetToken()},
|
||||
params:{_:new Date().valueOf()}
|
||||
})
|
||||
}
|
||||
|
||||
export function apiAddPortForwardRule(data) {
|
||||
return httpRequest({
|
||||
url: '/api/portforward',
|
||||
method: 'post',
|
||||
headers:{'Authorization':GetToken()},
|
||||
data:data
|
||||
})
|
||||
}
|
||||
|
||||
export function apiDeletePortForwardRule(key) {
|
||||
return httpRequest({
|
||||
url: '/api/portforward',
|
||||
method: 'delete',
|
||||
headers:{'Authorization':GetToken()},
|
||||
params:{_:new Date().valueOf(),key:key}
|
||||
})
|
||||
}
|
||||
|
||||
export function apiAlterPortForwardRule(data) {
|
||||
return httpRequest({
|
||||
url: '/api/portforward',
|
||||
method: 'put',
|
||||
headers:{'Authorization':GetToken()},
|
||||
data:data
|
||||
})
|
||||
}
|
||||
|
||||
export function apiPortForwardRuleEnable(key,enable) {
|
||||
return httpRequest({
|
||||
url: '/api/portforward/enable',
|
||||
method: 'get',
|
||||
headers:{'Authorization':GetToken()},
|
||||
params:{_:new Date().valueOf(),enable:enable,key:key}
|
||||
})
|
||||
}
|
||||
|
||||
export function apiQueryPortForwardConfigure() {
|
||||
return httpRequest({
|
||||
url: '/api/portforward/configure',
|
||||
method: 'get',
|
||||
headers:{'Authorization':GetToken()},
|
||||
params:{_:new Date().valueOf()}
|
||||
})
|
||||
}
|
||||
|
||||
export function apiAlterPortForwardConfigure(data) {
|
||||
return httpRequest({
|
||||
url: '/api/portforward/configure',
|
||||
method: 'put',
|
||||
headers:{'Authorization':GetToken()},
|
||||
data:data
|
||||
})
|
||||
}
|
||||
|
||||
export function apiPortforwardRuleLogs(key,pageSize,page) {
|
||||
return httpRequest({
|
||||
url: '/api/portforward/logs',
|
||||
method: 'get',
|
||||
headers:{'Authorization':GetToken()},
|
||||
params:{
|
||||
_:new Date().valueOf(),
|
||||
key:key,
|
||||
pageSize:pageSize,
|
||||
page:page}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
//-----------------
|
||||
|
||||
export function apiGetWOLDeviceList() {
|
||||
return httpRequest({
|
||||
url: '/api/wol/devices',
|
||||
method: 'get',
|
||||
headers:{'Authorization':GetToken()},
|
||||
params:{_:new Date().valueOf()}
|
||||
})
|
||||
}
|
||||
|
||||
export function apiAddWOLDevice(data) {
|
||||
return httpRequest({
|
||||
url: '/api/wol/device',
|
||||
method: 'post',
|
||||
headers:{'Authorization':GetToken()},
|
||||
data:data
|
||||
})
|
||||
}
|
||||
|
||||
export function apiDeleteWOLDevice(key) {
|
||||
return httpRequest({
|
||||
url: '/api/wol/device',
|
||||
method: 'delete',
|
||||
headers:{'Authorization':GetToken()},
|
||||
params:{_:new Date().valueOf(),key:key}
|
||||
})
|
||||
}
|
||||
|
||||
export function apiWOLDeviceWakeUp(key) {
|
||||
return httpRequest({
|
||||
url: '/api/wol/device/wakeup',
|
||||
method: 'get',
|
||||
headers:{'Authorization':GetToken()},
|
||||
params:{_:new Date().valueOf(),key:key}
|
||||
})
|
||||
}
|
||||
|
||||
export function apiAlterWOLDevice(data) {
|
||||
return httpRequest({
|
||||
url: '/api/wol/device',
|
||||
method: 'put',
|
||||
headers:{'Authorization':GetToken()},
|
||||
data:data
|
||||
})
|
||||
}
|
|
@ -17,11 +17,15 @@
|
|||
|
||||
<div class="line">
|
||||
|
||||
<el-link type="primary" href="tencent://message/?uin=272288814&Site=&Menu=yes" target="_blank">QQ联系作者</el-link>
|
||||
邮箱: 272288814@qq.com
|
||||
<el-link type="primary" href="tencent://message/?uin=272288813&Site=&Menu=yes" target="_blank">QQ联系作者</el-link>
|
||||
邮箱: 272288813@qq.com
|
||||
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
Lukcy交流 QQ群: 602427029
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
Github <el-link type="primary" href="https://github.com/gdy666/lucky" target="_blank">https://github.com/gdy666/lucky</el-link>
|
||||
</div>
|
||||
|
@ -30,10 +34,6 @@
|
|||
Gitee <el-link type="primary" href="https://gitee.com/gdy666/lucky" target="_blank">https://gitee.com/gdy666/lucky</el-link>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<el-link type="primary" href="https://pan.baidu.com/s/1NfumD9XjYU3OTeVmbu6vOQ?pwd=6666" target="_blank">最新版本可访问百度网盘</el-link>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
本项目借鉴引用或参考的第三方开源项目: <el-link type="primary" href="https://github.com/fatedier/frp" target="_blank">frp</el-link> <el-link type="primary" href="https://github.com/jeessy2/ddns-go" target="_blank">ddns-go</el-link>
|
||||
</div>
|
||||
|
|
|
@ -128,10 +128,10 @@ const flushBlackListlife = (index, ip, life) => {
|
|||
|
||||
const addBlackList = () => {
|
||||
|
||||
if (!isIP(addBlackListForm.value.IP)) {
|
||||
MessageShow("error", "IP格式有误,请检查修正后再添加")
|
||||
return
|
||||
}
|
||||
// if (!isIP(addBlackListForm.value.IP)) {
|
||||
// MessageShow("error", "IP格式有误,请检查修正后再添加")
|
||||
// return
|
||||
// }
|
||||
|
||||
apiFlushBlackList(addBlackListForm.value.IP, addBlackListForm.value.Life).then((res) => {
|
||||
if (res.ret == 0) {
|
||||
|
|
|
@ -111,7 +111,7 @@
|
|||
</template>
|
||||
<el-button color="#409eff" size="default">
|
||||
{{ task.TaskState.WebhookCallTime == "" ? '从未触发' :
|
||||
task.TaskState.WebhookCallTime
|
||||
task.TaskState.WebhookCallTime
|
||||
}}
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
|
@ -172,7 +172,8 @@
|
|||
<el-descriptions-item label="域名">
|
||||
<el-button color="#409eff" size="default"
|
||||
@click="copyDomain(domain.SubDomain, domain.DomainName)">
|
||||
{{ domain.SubDomain == '' ? domain.DomainName : domain.SubDomain + "." + domain.DomainName }}
|
||||
{{ domain.SubDomain == '' ? domain.DomainName : domain.SubDomain + "." +
|
||||
domain.DomainName }}
|
||||
</el-button>
|
||||
</el-descriptions-item>
|
||||
|
||||
|
@ -185,7 +186,8 @@
|
|||
|
||||
</template>
|
||||
|
||||
<el-button :type="domain.UpdateStatus == '失败' ? 'danger' : task.Enable ? 'success' : 'info'"
|
||||
<el-button
|
||||
:type="domain.UpdateStatus == '失败' ? 'danger' : task.Enable ? 'success' : 'info'"
|
||||
size="small">
|
||||
{{ task.Enable ? domain.UpdateStatus : '停止同步' }}
|
||||
</el-button>
|
||||
|
@ -571,6 +573,17 @@
|
|||
|
||||
</div>
|
||||
|
||||
<p>DNS接口调用额外设置</p>
|
||||
<div class="fromitemChildDivRadius">
|
||||
<el-form-item label="DNS接口调用使用的网络类型" label-width="auto">
|
||||
<el-select v-model="DDNSForm.DNS.CallAPINetwork" class="m-2" placeholder="请选择">
|
||||
<el-option v-for="item in TCPNetworkTypeList" :key="item.value" :label="item.label"
|
||||
:value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<p>DNS接口调用代理设置</p>
|
||||
<div class="fromitemChildDivRadius">
|
||||
|
@ -991,7 +1004,7 @@
|
|||
<span class="dialog-footer">
|
||||
<el-button @click="addDDNSDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="exeAddOrAlterDDNSOption">{{ DDNSFormOptionType == "add" ? '添加' :
|
||||
'修改'
|
||||
'修改'
|
||||
}}
|
||||
</el-button>
|
||||
</span>
|
||||
|
@ -1159,6 +1172,21 @@ const DNSCallbackServerList = [
|
|||
},
|
||||
]
|
||||
|
||||
const TCPNetworkTypeList = [
|
||||
{
|
||||
value: '',
|
||||
label: 'tcp',
|
||||
},
|
||||
{
|
||||
value: 'tcp4',
|
||||
label: 'tcp4',
|
||||
},
|
||||
{
|
||||
value: 'tcp6',
|
||||
label: 'tcp6',
|
||||
},
|
||||
]
|
||||
|
||||
const WebHookTest = () => {
|
||||
console.log("WebHookTest")
|
||||
|
||||
|
@ -1584,6 +1612,7 @@ const DDNSForm = ref(
|
|||
Secret: "",
|
||||
ForceInterval: 3600,
|
||||
ResolverDoaminCheck: false,
|
||||
CallAPINetwork: "",
|
||||
DNSServerList: [""],
|
||||
HttpClientProxyType: "",
|
||||
HttpClientProxyAddr: "",
|
||||
|
@ -1634,6 +1663,7 @@ const preDDNSFrom = ref(
|
|||
ResolverDoaminCheck: false,
|
||||
DNSServerList: [''],
|
||||
HttpClientProxyType: "",
|
||||
CallAPINetwork: "",
|
||||
HttpClientProxyAddr: "",
|
||||
HttpClientProxyUser: "",
|
||||
HttpClientProxyPassword: "",
|
||||
|
@ -1701,6 +1731,7 @@ const showAddOrAlterDDNSTaskDialog = (optionType: string, task: any) => {
|
|||
ResolverDoaminCheck: true,
|
||||
DNSServerList: [],
|
||||
HttpClientProxyType: "",
|
||||
CallAPINetwork: "",
|
||||
HttpClientProxyAddr: "",
|
||||
HttpClientProxyUser: "",
|
||||
HttpClientProxyPassword: "",
|
||||
|
@ -1755,6 +1786,7 @@ const showAddOrAlterDDNSTaskDialog = (optionType: string, task: any) => {
|
|||
ResolverDoaminCheck: true,
|
||||
DNSServerList: [],
|
||||
HttpClientProxyType: "",
|
||||
CallAPINetwork: "",
|
||||
HttpClientProxyAddr: "",
|
||||
HttpClientProxyUser: "",
|
||||
HttpClientProxyPassword: "",
|
||||
|
@ -1800,6 +1832,7 @@ const showAddOrAlterDDNSTaskDialog = (optionType: string, task: any) => {
|
|||
ResolverDoaminCheck: task.DNS.ResolverDoaminCheck,
|
||||
DNSServerList: task.DNS.DNSServerList,
|
||||
HttpClientProxyType: task.DNS.HttpClientProxyType,
|
||||
CallAPINetwork: task.DNS.CallAPINetwork,
|
||||
HttpClientProxyAddr: task.DNS.HttpClientProxyAddr,
|
||||
HttpClientProxyUser: task.DNS.HttpClientProxyUser,
|
||||
HttpClientProxyPassword: task.DNS.HttpClientProxyPassword,
|
||||
|
@ -1852,6 +1885,7 @@ const showAddOrAlterDDNSTaskDialog = (optionType: string, task: any) => {
|
|||
ResolverDoaminCheck: task.DNS.ResolverDoaminCheck,
|
||||
DNSServerList: task.DNS.DNSServerList,
|
||||
HttpClientProxyType: task.DNS.HttpClientProxyType,
|
||||
CallAPINetwork: task.DNS.CallAPINetwork,
|
||||
HttpClientProxyAddr: task.DNS.HttpClientProxyAddr,
|
||||
HttpClientProxyUser: task.DNS.HttpClientProxyUser,
|
||||
HttpClientProxyPassword: task.DNS.HttpClientProxyPassword,
|
||||
|
@ -2495,7 +2529,7 @@ onUnmounted(() => {
|
|||
margin-left: 3px;
|
||||
margin-top: 3px;
|
||||
margin-right: 3px;
|
||||
margin-bottom: 25px;
|
||||
margin-bottom: 5px;
|
||||
min-width: 1200px;
|
||||
|
||||
}
|
||||
|
|
|
@ -93,7 +93,7 @@ const Login = () => {
|
|||
if (res.ret == 0) {
|
||||
MessageShow("success", "登录成功")
|
||||
global.storage.setItem("token",res.token)
|
||||
global.currentPage.value = "#set"
|
||||
//global.currentPage.value = "#set"
|
||||
location.hash="#set"
|
||||
//console.log("cookies:"+res.cookies)
|
||||
|
||||
|
|
|
@ -10,11 +10,14 @@
|
|||
<div class="formradius" :style="{
|
||||
borderRadius: 'base',
|
||||
}">
|
||||
|
||||
|
||||
|
||||
<el-form :model="form" class="SetForm" label-width="auto">
|
||||
<el-form-item label="后台管理端口" id="adminListen">
|
||||
<el-input-number v-model="form.AdminWebListenPort" autocomplete="off" />
|
||||
</el-form-item>
|
||||
|
||||
<div class="AdminListenDivRadius">
|
||||
|
||||
<p>后台管理入口设置</p>
|
||||
|
||||
<el-form-item label="外网访问" id="adminListen">
|
||||
<el-switch v-model="form.AllowInternetaccess" class="mb-1" inline-prompt
|
||||
|
@ -22,6 +25,30 @@
|
|||
active-text="允许" inactive-text="禁止" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="端口(http)" id="adminListen">
|
||||
<el-input-number v-model="form.AdminWebListenPort" autocomplete="off" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="TLS端口(https)" id="adminListen">
|
||||
<el-tooltip class="box-item" effect="dark" :trigger-keys="[]" content="">
|
||||
<template #content>
|
||||
外网访问时建议使用https端口访问<br />
|
||||
自行确认启用前先添加对应域名的SSL证书<br />
|
||||
保存修改或增删SSL证书后请手动重启程序使得设置或证书生效<br />
|
||||
</template>
|
||||
<el-switch v-model="form.AdminWebListenTLS" class="mb-1" inline-prompt
|
||||
width="50px"
|
||||
active-text="启用" inactive-text="禁用" />
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="端口(https)" id="adminListen" v-show="form.AdminWebListenTLS">
|
||||
<el-input-number v-model="form.AdminWebListenHttpsPort" autocomplete="off" />
|
||||
</el-form-item>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="AdminListenDivRadius">
|
||||
<el-form-item label="管理登录账号" id="adminAccount">
|
||||
<el-input v-model="form.AdminAccount" placeholder="管理登录账号" autocomplete="off"
|
||||
style="witdh:390px;" />
|
||||
|
@ -30,19 +57,24 @@
|
|||
<el-form-item label="管理登录密码" id="adminPassword">
|
||||
<el-input v-model="form.AdminPassword" placeholder="管理登录密码" autocomplete="off" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<div class="AdminListenDivRadius">
|
||||
<el-form-item label="日志记录最大条数" id="logMaxSize">
|
||||
<el-input-number v-model="form.LogMaxSize" autocomplete="off" :min="1024" :max="40960" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
|
||||
<el-form-item label="全局最大端口代理数量" id="proxyCountLimit">
|
||||
|
||||
|
||||
<!-- <el-form-item label="全局最大端口代理数量" id="proxyCountLimit">
|
||||
<el-input-number v-model="form.ProxyCountLimit" autocomplete="off" :min="1" :max="1024" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="全局最大连接数" id="globalMaxConnections">
|
||||
<el-input-number v-model="form.GlobalMaxConnections" autocomplete="off" :min="1" :max="65535" />
|
||||
</el-form-item>
|
||||
</el-form-item> -->
|
||||
|
||||
|
||||
|
||||
|
@ -115,7 +147,7 @@ const callRestoreConfigureAPI = (res: any, uploadFile: any, uploadFiles: any) =>
|
|||
let fileName = res.file
|
||||
|
||||
ElMessageBox.confirm(
|
||||
"确认要将[" + fileName + "]替换为大吉现有配置?替换完成后大吉会自动重启",
|
||||
"确认要将[" + fileName + "]替换为Lucky现有配置?替换完成后Lucky会自动重启",
|
||||
'Warning',
|
||||
{
|
||||
confirmButtonText: '确认',
|
||||
|
@ -126,11 +158,11 @@ const callRestoreConfigureAPI = (res: any, uploadFile: any, uploadFiles: any) =>
|
|||
.then(() => {
|
||||
apiGetRestoreConfigureConfirm(res.restoreConfigureKey).then(res => {
|
||||
if (res.ret != 0) {
|
||||
MessageShow("error", "将[" + fileName + "]替换为大吉现有配置出错:" + res.msg)
|
||||
MessageShow("error", "将[" + fileName + "]替换为Lucky现有配置出错:" + res.msg)
|
||||
return
|
||||
}
|
||||
|
||||
MessageShow("success", "将[" + fileName + "]替换为大吉现有配置成功")
|
||||
MessageShow("success", "将[" + fileName + "]替换为Lucky现有配置成功")
|
||||
|
||||
setTimeout(() => {
|
||||
window.location.href = window.location.protocol + "//" + window.location.hostname + ":" + res.port;
|
||||
|
@ -138,7 +170,7 @@ const callRestoreConfigureAPI = (res: any, uploadFile: any, uploadFiles: any) =>
|
|||
|
||||
}).catch((error) => {
|
||||
console.log("网络出错:" + error)
|
||||
MessageShow("error", "将[" + res.file + "]替换为大吉现有配置出错:" + error)
|
||||
MessageShow("error", "将[" + res.file + "]替换为Lucky现有配置出错:" + error)
|
||||
})
|
||||
|
||||
})
|
||||
|
@ -149,10 +181,12 @@ const callRestoreConfigureAPI = (res: any, uploadFile: any, uploadFiles: any) =>
|
|||
|
||||
const rawData = {
|
||||
AdminWebListenPort: 1,
|
||||
AdminWebListenTLS:false,
|
||||
AdminWebListenHttpsPort:16626,
|
||||
AdminAccount: "",
|
||||
AdminPassword: "",
|
||||
ProxyCountLimit: 1,
|
||||
GlobalMaxConnections: 1,
|
||||
// ProxyCountLimit: 1,
|
||||
// GlobalMaxConnections: 1,
|
||||
AllowInternetaccess: false,
|
||||
LogMaxSize:1024,
|
||||
}
|
||||
|
@ -189,8 +223,8 @@ const resetFormData = () => {
|
|||
form.value.AdminWebListenPort = preFormData.value.AdminWebListenPort
|
||||
form.value.AdminAccount = preFormData.value.AdminAccount
|
||||
form.value.AdminPassword = preFormData.value.AdminPassword
|
||||
form.value.ProxyCountLimit = preFormData.value.ProxyCountLimit
|
||||
form.value.GlobalMaxConnections = preFormData.value.GlobalMaxConnections
|
||||
//form.value.ProxyCountLimit = preFormData.value.ProxyCountLimit
|
||||
//form.value.GlobalMaxConnections = preFormData.value.GlobalMaxConnections
|
||||
form.value.AllowInternetaccess = preFormData.value.AllowInternetaccess
|
||||
}
|
||||
|
||||
|
@ -198,8 +232,8 @@ const syncToPreFormData = (data: any) => {
|
|||
preFormData.value.AdminWebListenPort = data.value.AdminWebListenPort
|
||||
preFormData.value.AdminAccount = data.value.AdminAccount
|
||||
preFormData.value.AdminPassword = data.value.AdminPassword
|
||||
preFormData.value.ProxyCountLimit = data.value.ProxyCountLimit
|
||||
preFormData.value.GlobalMaxConnections = data.value.GlobalMaxConnections
|
||||
// preFormData.value.ProxyCountLimit = data.value.ProxyCountLimit
|
||||
// preFormData.value.GlobalMaxConnections = data.value.GlobalMaxConnections
|
||||
preFormData.value.AllowInternetaccess = data.value.AllowInternetaccess
|
||||
}
|
||||
|
||||
|
@ -280,6 +314,20 @@ onMounted(() => {
|
|||
|
||||
|
||||
<style scoped>
|
||||
|
||||
.AdminListenDivRadius {
|
||||
border: 2px solid var(--el-border-color);
|
||||
border-radius: 10px;
|
||||
margin-left: 3px;
|
||||
margin-top: 15px;
|
||||
margin-right: 3px;
|
||||
margin-bottom: 15px;
|
||||
width: 456;
|
||||
padding-top: 9px;
|
||||
padding-left: 9px;
|
||||
padding-right: 9px;
|
||||
}
|
||||
|
||||
.SetForm {
|
||||
margin-top: 15px;
|
||||
margin-left: 20px;
|
||||
|
|
|
@ -34,18 +34,33 @@
|
|||
<span>端口转发</span>
|
||||
</template>
|
||||
|
||||
<el-menu-item index="#relayset">
|
||||
<!-- <el-menu-item index="#relayset">
|
||||
<el-icon>
|
||||
<List />
|
||||
</el-icon>
|
||||
<template #title>转发规则</template>
|
||||
</el-menu-item> -->
|
||||
|
||||
<el-menu-item index="#portforward">
|
||||
<el-icon>
|
||||
<List />
|
||||
</el-icon>
|
||||
<template #title>转发规则列表</template>
|
||||
</el-menu-item>
|
||||
|
||||
<el-menu-item index="#portforwardset">
|
||||
<el-icon>
|
||||
<List />
|
||||
</el-icon>
|
||||
<template #title>设置</template>
|
||||
</el-menu-item>
|
||||
|
||||
</el-sub-menu>
|
||||
|
||||
<el-sub-menu index="#reverseproxy">
|
||||
<template #title>
|
||||
<el-icon>
|
||||
<Position />
|
||||
<Connection />
|
||||
</el-icon>
|
||||
<span>反向代理</span>
|
||||
</template>
|
||||
|
@ -56,6 +71,7 @@
|
|||
</el-icon>
|
||||
<template #title>反向代理规则列表</template>
|
||||
</el-menu-item>
|
||||
|
||||
</el-sub-menu>
|
||||
|
||||
<el-sub-menu index="#ddns">
|
||||
|
@ -81,10 +97,47 @@
|
|||
</el-menu-item>
|
||||
</el-sub-menu>
|
||||
|
||||
<el-sub-menu index="#wol">
|
||||
<template #title>
|
||||
<el-icon>
|
||||
<Bell />
|
||||
</el-icon>
|
||||
<span>网络唤醒</span>
|
||||
</template>
|
||||
|
||||
|
||||
<el-menu-item index="#wol">
|
||||
<el-icon>
|
||||
<Bell />
|
||||
</el-icon>
|
||||
<template #title>网络唤醒设备列表</template>
|
||||
</el-menu-item>
|
||||
|
||||
<el-menu-item index="#wolset">
|
||||
<el-icon>
|
||||
<setting />
|
||||
</el-icon>
|
||||
<template #title>网络唤醒设置</template>
|
||||
</el-menu-item>
|
||||
|
||||
</el-sub-menu>
|
||||
|
||||
|
||||
|
||||
|
||||
<el-divider style="margin-top: 0px;margin-bottom: 0px;" />
|
||||
|
||||
|
||||
|
||||
<el-sub-menu index="#safe">
|
||||
<template #title>
|
||||
<el-icon>
|
||||
<Guide />
|
||||
</el-icon>
|
||||
<span>安全相关</span>
|
||||
</template>
|
||||
|
||||
<el-sub-menu index="#safe">
|
||||
<template #title>
|
||||
<el-icon>
|
||||
<Guide />
|
||||
|
@ -114,6 +167,22 @@
|
|||
</el-menu-item>
|
||||
|
||||
</el-sub-menu>
|
||||
|
||||
<el-menu-item index="#ssl">
|
||||
<el-icon>
|
||||
<Lock />
|
||||
</el-icon>
|
||||
<template #title>SSL证书</template>
|
||||
</el-menu-item>
|
||||
|
||||
|
||||
</el-sub-menu>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<el-menu-item index="#set">
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,220 @@
|
|||
<template>
|
||||
|
||||
<div class="PageRadius" :style="{
|
||||
borderRadius: 'base',
|
||||
}" v-loading="logLoading" element-loading-background="transparent">
|
||||
|
||||
<el-scrollbar height="100%">
|
||||
|
||||
|
||||
<div class="formradius" :style="{
|
||||
borderRadius: 'base',
|
||||
}">
|
||||
|
||||
<el-form :model="form" class="SetForm" label-width="auto">
|
||||
|
||||
<!-- <el-tooltip content="如果不需要DDNS动态域名服务请不要打开这个开关" placement="top">
|
||||
|
||||
<el-form-item label="动态域名服务开关" id="adminListen">
|
||||
<el-switch v-model="form.Enable" class="mb-1" inline-prompt
|
||||
style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949" width="50px"
|
||||
active-text="开启" inactive-text="停用" />
|
||||
</el-form-item>
|
||||
</el-tooltip>
|
||||
|
||||
<el-tooltip content="多数嵌入式设备启用这个开关会导致https访问失败" placement="top">
|
||||
|
||||
<el-form-item label="Http(s) 客户端 安全证书验证" id="adminListen">
|
||||
<el-switch v-model="form.HttpClientSecureVerify" class="mb-1" inline-prompt
|
||||
style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949" width="50px"
|
||||
active-text="启用" inactive-text="禁用" />
|
||||
</el-form-item> -->
|
||||
<!-- </el-tooltip> -->
|
||||
|
||||
<div class="AdminListenDivRadius">
|
||||
|
||||
|
||||
|
||||
|
||||
<el-tooltip content="同一端口tcp和udp类型各算一个,(0-1024)" placement="top">
|
||||
<el-form-item label="全局端口转发最大数量" label-width="auto" min="0" max="1024">
|
||||
<el-input-number v-model="form.PortForwardsLimit" autocomplete="off" />
|
||||
</el-form-item>
|
||||
</el-tooltip>
|
||||
|
||||
<el-tooltip content="端口转发全局TCP最大并发连接数,(0-4096)" placement="top">
|
||||
<el-form-item label="端口转发全局TCP最大并发连接数" label-width="auto" min="0" max="4096">
|
||||
<el-input-number v-model="form.TCPPortforwardMaxConnections" autocomplete="off" />
|
||||
</el-form-item>
|
||||
</el-tooltip>
|
||||
|
||||
<el-tooltip content="端口转发全局UDP读取目标地址数据协程数限制,(0-4096)" placement="top">
|
||||
<el-form-item label="端口转发全局UDP读取目标地址数据协程数限制" label-width="auto" min="0" max="4096">
|
||||
<el-input-number v-model="form.UDPReadTargetDataMaxgoroutineCount" autocomplete="off" />
|
||||
</el-form-item>
|
||||
</el-tooltip>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<!-- <el-tooltip content="DDNS任务每次执行的时间间隔,最小30秒,最长3600秒" placement="top">
|
||||
<el-form-item label="时间间隔(秒)" label-width="auto" :min="30" :max="3600">
|
||||
<el-input-number v-model="form.Intervals" autocomplete="off" />
|
||||
</el-form-item>
|
||||
</el-tooltip> -->
|
||||
|
||||
|
||||
</el-form>
|
||||
|
||||
<el-button type="primary" round @click="RequestAlterPortForwardConfigure">保存修改</el-button>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
import { onMounted, onUnmounted, ref, computed, reactive } from 'vue'
|
||||
import { apiQueryPortForwardConfigure, apiAlterPortForwardConfigure } from '../apis/utils'
|
||||
|
||||
|
||||
import { MessageShow } from '../utils/ui'
|
||||
|
||||
|
||||
const logLoading = ref(true)
|
||||
|
||||
|
||||
const rawData = {
|
||||
// Enable: false,
|
||||
// HttpClientSecureVerify: false,
|
||||
// Intervals: 0,
|
||||
PortForwardsLimit: 0,
|
||||
TCPPortforwardMaxConnections:0,
|
||||
UDPReadTargetDataMaxgoroutineCount:0,
|
||||
}
|
||||
|
||||
const form = ref(rawData)
|
||||
const preFormData = ref(rawData)
|
||||
|
||||
const resetFormData = () => {
|
||||
form.value.PortForwardsLimit = preFormData.value.PortForwardsLimit
|
||||
form.value.TCPPortforwardMaxConnections = preFormData.value.TCPPortforwardMaxConnections
|
||||
}
|
||||
|
||||
const syncToPreFormData = (data: any) => {
|
||||
preFormData.value.PortForwardsLimit = data.value.PortForwardsLimit
|
||||
preFormData.value.TCPPortforwardMaxConnections = data.TCPPortforwardMaxConnections
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const queryPortForwardsConfigure = () => {
|
||||
apiQueryPortForwardConfigure().then((res) => {
|
||||
|
||||
if (res.ret == 0) {
|
||||
logLoading.value = false
|
||||
form.value = res.configure
|
||||
syncToPreFormData(form)
|
||||
return
|
||||
}
|
||||
MessageShow("error", "获取端口转发配置出错")
|
||||
}).catch((error) => {
|
||||
MessageShow("error", "获取端口转发配置出错")
|
||||
})
|
||||
}
|
||||
|
||||
const RequestAlterPortForwardConfigure = () => {
|
||||
apiAlterPortForwardConfigure(form.value).then((res) => {
|
||||
if (res.ret == 0) {
|
||||
MessageShow("success", "配置修改成功")
|
||||
queryPortForwardsConfigure()
|
||||
return
|
||||
}
|
||||
resetFormData()
|
||||
MessageShow("error", res.msg)
|
||||
}).catch((error) => {
|
||||
console.log("配置修改失败,网络请求出错:" + error)
|
||||
MessageShow("error", "配置修改失败,网络请求出错")
|
||||
resetFormData()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
queryPortForwardsConfigure()
|
||||
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
.AdminListenDivRadius {
|
||||
border: 2px solid var(--el-border-color);
|
||||
border-radius: 10px;
|
||||
margin-left: 3px;
|
||||
margin-top: 15px;
|
||||
margin-right: 3px;
|
||||
margin-bottom: 15px;
|
||||
width: 456;
|
||||
padding-top: 9px;
|
||||
padding-left: 9px;
|
||||
padding-right: 9px;
|
||||
}
|
||||
|
||||
|
||||
.SetForm {
|
||||
margin-top: 15px;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.formradius {
|
||||
border: 0px solid var(--el-border-color);
|
||||
border-radius: 0;
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
padding: 15px;
|
||||
|
||||
|
||||
}
|
||||
|
||||
#adminListen {
|
||||
width: 360px;
|
||||
}
|
||||
|
||||
#adminAccount {
|
||||
width: 30vw;
|
||||
max-width: 360px;
|
||||
min-width: 300px;
|
||||
}
|
||||
|
||||
|
||||
#adminPassword {
|
||||
width: 30vw;
|
||||
max-width: 360px;
|
||||
min-width: 300px;
|
||||
}
|
||||
|
||||
|
||||
#proxyCountLimit {
|
||||
width: 360px;
|
||||
}
|
||||
|
||||
|
||||
#globalMaxConnections {
|
||||
width: 360px;
|
||||
}
|
||||
</style>
|
File diff suppressed because it is too large
Load Diff
|
@ -34,6 +34,11 @@
|
|||
<el-button color="#409eff" size="small" v-show="true">
|
||||
{{ rule.ListenPort }}
|
||||
</el-button>
|
||||
|
||||
|
||||
<el-button :type="rule.EnableTLS!=true?'info':'primary'" size="small" v-show="true">
|
||||
{{ rule.EnableTLS==true?'TLS已启用':'TLS未启用' }}
|
||||
</el-button>
|
||||
</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item label="规则操作" :span="2">
|
||||
|
@ -96,7 +101,7 @@
|
|||
<el-button color="#409eff" size="small" v-show="true">
|
||||
{{
|
||||
(rule.DefaultProxy.Locations==undefined||rule.DefaultProxy.Locations==null)||rule.DefaultProxy.Locations.length
|
||||
<=0?'未设置默认规则后端地址':rule.DefaultProxy.Locations.length==1?rule.DefaultProxy.Locations[0]:rule.DefaultProxy.Locations[0]+'...等多个'}}
|
||||
<=0?'未设置':rule.DefaultProxy.Locations.length==1?rule.DefaultProxy.Locations[0]:rule.DefaultProxy.Locations[0]+'...'}}
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</el-descriptions-item>
|
||||
|
@ -140,7 +145,8 @@
|
|||
<template #content v-if="!rule.DefaultProxy.EnableBasicAuth">
|
||||
Basic认证未启用<br />
|
||||
</template>
|
||||
<el-button color="#6666ff" size="small" v-show="true">
|
||||
<el-button color="#6666ff" size="small"
|
||||
v-show="true" :disabled="rule.DefaultProxy.EnableBasicAuth == true ? false : true">
|
||||
{{ rule.DefaultProxy.EnableBasicAuth==false?'Basic认证未启用':'Basic认证已启用' }}
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
|
@ -186,7 +192,7 @@
|
|||
<span v-html="StrArrayListToBrHtml(proxy.Domains)"></span>
|
||||
</template>
|
||||
<el-button color="#409eff" size="small" v-show="true">
|
||||
{{ proxy.Domains.length==1?proxy.Domains[0]:proxy.Domains[0]+' ...等多个' }}
|
||||
{{ proxy.Domains.length==1?proxy.Domains[0]:proxy.Domains[0]+' ...' }}
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</el-descriptions-item>
|
||||
|
@ -197,7 +203,7 @@
|
|||
<span v-html="StrArrayListToBrHtml(proxy.Locations)"></span>
|
||||
</template>
|
||||
<el-button color="#409eff" size="small" v-show="true">
|
||||
{{ proxy.Locations.length==1?proxy.Locations[0]:proxy.Locations[0]+' ...等多个' }}
|
||||
{{ proxy.Locations.length==1?proxy.Locations[0]:proxy.Locations[0]+' ...' }}
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</el-descriptions-item>
|
||||
|
@ -227,7 +233,7 @@
|
|||
<template #content v-if="!proxy.EnableBasicAuth">
|
||||
Basic认证未启用<br />
|
||||
</template>
|
||||
<el-button color="#6666ff" size="small" v-show="true">
|
||||
<el-button color="#6666ff" size="small" v-show="true" :disabled="proxy.EnableBasicAuth == true ? false : true">
|
||||
{{ proxy.EnableBasicAuth==false?'Basic认证未启用':'Basic认证已启用' }}
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
|
@ -306,10 +312,16 @@
|
|||
<el-input-number v-model="ruleForm.ListenPort" autocomplete="off" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="TLS" label-width="auto" v-if="false">
|
||||
<el-tooltip class="box-item" effect="dark" :trigger-keys="[]" content="">
|
||||
<template #content>
|
||||
启用前请先添加SSL证书<br/>
|
||||
增加删除证书后需要重启规则新证书才生效<br/>
|
||||
</template>
|
||||
<el-form-item label="TLS" label-width="auto" v-if="true">
|
||||
<el-switch v-model="ruleForm.EnableTLS" inline-prompt width="50px" active-text="启用"
|
||||
inactive-text="禁用" />
|
||||
</el-form-item>
|
||||
</el-tooltip>
|
||||
|
||||
|
||||
|
||||
|
@ -976,11 +988,6 @@
|
|||
</el-scrollbar>
|
||||
|
||||
|
||||
<!-- <p v-for="log in reverseProxyLogsDialogData">
|
||||
{{log.LogTime}} {{log.LogContent}}
|
||||
</p> -->
|
||||
|
||||
|
||||
<el-pagination :page-size=reverseProxyLogsPageSize :page-sizes="[10,20,50, 100, 200, 300,400,500]" :small="false"
|
||||
:disabled="false" :background="false" layout="total, sizes, prev, pager, next, jumper"
|
||||
:current-page="reverseProxyLogsDialogCurrentPage" :total=reverseProxyLogsTotal
|
||||
|
@ -1803,7 +1810,7 @@ onUnmounted(() => {
|
|||
margin-left: 3px;
|
||||
margin-top: 3px;
|
||||
margin-right: 3px;
|
||||
margin-bottom: 25px;
|
||||
margin-bottom: 10px;
|
||||
min-width: 1350px;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,445 @@
|
|||
<template>
|
||||
|
||||
<div class="PageRadius" :style="{
|
||||
borderRadius: 'base',
|
||||
}">
|
||||
|
||||
<!-- <el-affix position="bottom" :offset="0" class="affix-container">
|
||||
<el-button type="primary" @click="showAddSSLDialog">SSL证书添加 <el-icon>
|
||||
<Plus />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
</el-affix> -->
|
||||
|
||||
|
||||
|
||||
<el-scrollbar height="100%">
|
||||
|
||||
|
||||
|
||||
<div class="itemradius" :style="{
|
||||
borderRadius: 'base',
|
||||
}" v-for="ssl in SSLList">
|
||||
|
||||
<el-descriptions :column="6" border>
|
||||
<el-descriptions-item label="证书备注" :span="2">
|
||||
<el-button size="small" v-show="true">
|
||||
{{ ssl.Remark == '' ? '未备注' : ssl.Remark }}
|
||||
</el-button>
|
||||
</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item label="添加时间" :span="2">
|
||||
<el-button size="small" v-show="true">
|
||||
{{ ssl.AddTime }}
|
||||
</el-button>
|
||||
</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item label="操作" :span="2">
|
||||
|
||||
<el-tooltip :content="ssl.Enable == true ? '证书已启用' : '证书已禁用'" placement="top">
|
||||
<el-switch v-model="ssl.Enable" inline-prompt active-text="开" inactive-text="关"
|
||||
:before-change="sslEnableClick.bind(this, ssl.Enable, ssl)" size="large" />
|
||||
</el-tooltip>
|
||||
|
||||
|
||||
<el-button size="small" type="primary" @click="showAlterRemarkDialog(ssl)">修改备注</el-button>
|
||||
|
||||
|
||||
|
||||
<el-button size="small" type="danger" @click="deleteSSL(ssl)">删除</el-button>
|
||||
</el-descriptions-item>
|
||||
|
||||
<div v-for="cert in ssl.CertsInfo">
|
||||
<!-- <el-descriptions :column="6" border> -->
|
||||
<el-descriptions-item label="绑定域名" :span="2">
|
||||
<el-tooltip placement="bottom" effect="dark" :trigger-keys="[]" content="">
|
||||
<template #content>
|
||||
<span v-html="StrArrayListToBrHtml(cert.Domains)"></span>
|
||||
</template>
|
||||
<el-button size="small" v-show="true" type="primary">
|
||||
{{cert.Domains.length==1?cert.Domains[0]:cert.Domains[0]+'...'}}
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item label="颁发时间" :span="2">
|
||||
<el-button size="small" v-show="true" type="info">
|
||||
{{ cert.NotBeforeTime }}
|
||||
</el-button>
|
||||
</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item label="到期时间" :span="2">
|
||||
<el-button size="small" v-show="true" type="warning">
|
||||
{{ cert.NotAfterTime }}
|
||||
</el-button>
|
||||
</el-descriptions-item>
|
||||
|
||||
|
||||
<!-- </el-descriptions> -->
|
||||
</div>
|
||||
|
||||
</el-descriptions>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</el-scrollbar>
|
||||
|
||||
<el-affix position="bottom" :offset="30" class="affix-container">
|
||||
<el-button type="primary" :round=true @click="showAddSSLDialog">SSL证书添加
|
||||
<el-icon class="el-icon--right">
|
||||
<Plus />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
</el-affix>
|
||||
|
||||
|
||||
|
||||
<el-dialog v-if="addSSLDialogVisible" v-model="addSSLDialogVisible" title="添加SSL证书" draggable
|
||||
:show-close="false" :close-on-click-modal="false" width="400px">
|
||||
|
||||
<el-form :model="addSSLForm">
|
||||
|
||||
<el-form-item label="备注" label-width="auto">
|
||||
<el-input v-model="addSSLForm.Remark" autocomplete="off" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="证书" label-width="auto">
|
||||
<el-upload class="inline-block" :multiple="true" :action="getFileBase64API()"
|
||||
:before-upload="beforeUpload" :show-file-list="false" :headers="{ 'Authorization': GetToken() }"
|
||||
:on-success="callbackGetCreFileBase64">
|
||||
<el-button round class='margin-change'>{{uploadCreButtontext}}</el-button>
|
||||
</el-upload>
|
||||
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="Key" label-width="auto">
|
||||
<el-upload class="inline-block" :multiple="true" :action="getFileBase64API()"
|
||||
:before-upload="beforeUpload" :show-file-list="false" :headers="{ 'Authorization': GetToken() }"
|
||||
:on-success="callbackGetKeyFileBase64">
|
||||
<el-button round class='margin-change'>{{uploadKeyButtontext}}</el-button>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="addSSLDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="addSSL">添加</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-if="alterRemarkDialogShow" v-model="alterRemarkDialogShow" :title=alterRemarkDialogSSLText
|
||||
draggable :show-close="false" :close-on-click-modal="false" width="400px">
|
||||
<el-form-item label="备注" label-width="auto">
|
||||
<el-input v-model="alterRemarkDialogValue" autocomplete="off" />
|
||||
</el-form-item>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="alterRemarkDialogShow = false">取消</el-button>
|
||||
<el-button type="primary" @click="alterSSLRemark">修改</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import { ElMessageBox } from 'element-plus'
|
||||
import { MessageShow } from '../utils/ui'
|
||||
import { StrArrayListToBrHtml } from '../utils/utils'
|
||||
import { GetToken, apiAddSSL, apiGetSSLList, apiDeleteSSL, apiAlterSSL } from '../apis/utils'
|
||||
import type { UploadProps } from 'element-plus'
|
||||
var SSLList = ref([
|
||||
{
|
||||
Key: "",
|
||||
Remark: "",
|
||||
Enable: true,
|
||||
AddTime: "",
|
||||
CertsInfo: [{
|
||||
Domains: [''],
|
||||
NotBeforeTime: '',
|
||||
NotAfterTime: ''
|
||||
},]
|
||||
}
|
||||
])
|
||||
|
||||
|
||||
const addSSLDialogVisible = ref(false)
|
||||
const addSSLForm = ref({ Remark: "", CertBase64: "", KeyBase64: "" })
|
||||
const uploadCreButtontext = ref("")
|
||||
const uploadKeyButtontext = ref("")
|
||||
|
||||
const getFileBase64API = () => {
|
||||
var baseURL = "/" //
|
||||
if (process.env.NODE_ENV == "development") {
|
||||
//开发环境下这个改为自己的接口地址
|
||||
baseURL = 'http://192.168.31.70:16601/'
|
||||
}
|
||||
return baseURL + "api/getfilebase64"
|
||||
}
|
||||
|
||||
|
||||
const alterRemarkDialogShow = ref(false)
|
||||
const alterRemarkDialogValue = ref("")
|
||||
const alterRemarkDialogSSLText = ref("")
|
||||
const alterRemarkDialogSSLKey = ref("")
|
||||
|
||||
const showAlterRemarkDialog = (ssl) => {
|
||||
|
||||
alterRemarkDialogShow.value = true
|
||||
alterRemarkDialogSSLKey.value = ssl.Key
|
||||
alterRemarkDialogValue.value = ssl.Remark
|
||||
alterRemarkDialogSSLText.value = ssl.CertsInfo[0].Domains[0];
|
||||
}
|
||||
|
||||
const callbackGetCreFileBase64 = (res: any, uploadFile: any, uploadFiles: any) => {
|
||||
if (res.ret != 0) {
|
||||
MessageShow("error", res.msg)
|
||||
return
|
||||
}
|
||||
console.log("file:" + res.file)
|
||||
uploadCreButtontext.value = res.file
|
||||
//console.log("base64:"+res.base64)
|
||||
addSSLForm.value.CertBase64 = res.base64
|
||||
}
|
||||
|
||||
const beforeUpload: UploadProps['beforeUpload'] = (rawFile) => {
|
||||
if (rawFile.size / 1024 / 1024 > 1) {
|
||||
MessageShow("error",'文件不能大于1M')
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
const callbackGetKeyFileBase64 = (res: any, uploadFile: any, uploadFiles: any) => {
|
||||
if (res.ret != 0) {
|
||||
MessageShow("error", res.msg)
|
||||
return
|
||||
}
|
||||
console.log("file:" + res.file)
|
||||
uploadKeyButtontext.value = res.file
|
||||
//console.log("base64:"+res.base64)
|
||||
addSSLForm.value.KeyBase64 = res.base64
|
||||
}
|
||||
|
||||
|
||||
const showAddSSLDialog = () => {
|
||||
addSSLDialogVisible.value = true
|
||||
addSSLForm.value.CertBase64 = ""
|
||||
addSSLForm.value.KeyBase64 = ""
|
||||
uploadCreButtontext.value = "选择要上传的证书文件"
|
||||
uploadKeyButtontext.value = "选择要上传的Key文件"
|
||||
}
|
||||
|
||||
|
||||
|
||||
const sslEnableClick = (enable, ssl) => {
|
||||
const enableText = enable == false ? "启用" : "禁用";
|
||||
|
||||
const sslText = ssl.Remark != "" ? ssl.Remark : ssl.CertsInfo[0].Domains[0];
|
||||
|
||||
const sslName = "[" + sslText + "]"
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
ElMessageBox.confirm(
|
||||
'确认要' + enableText + " 证书 " + sslName + "?",
|
||||
'Warning',
|
||||
{
|
||||
confirmButtonText: '确认',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
apiAlterSSL(ssl.Key, "enable", !enable).then(res => {
|
||||
if (res.ret == 0) {
|
||||
resolve(true)
|
||||
MessageShow("success", "证书 " + sslName + enableText + "成功")
|
||||
return
|
||||
}
|
||||
resolve(false)
|
||||
MessageShow("error", "证书 " + sslName + enableText + "失败: " + res.msg)
|
||||
|
||||
// if (res.syncres != undefined && res.syncres != "") {
|
||||
// Notification("warn", res.syncres, 0)
|
||||
// }
|
||||
}).catch((error) => {
|
||||
resolve(false)
|
||||
console.log("证书 " + sslName + enableText + "失败" + ":请求出错" + error)
|
||||
MessageShow("error", "证书 " + sslName + enableText + "失败" + ":请求出错")
|
||||
})
|
||||
|
||||
})
|
||||
.catch(() => {
|
||||
resolve(false)
|
||||
})
|
||||
|
||||
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
const alterSSLRemark = () => {
|
||||
|
||||
|
||||
apiAlterSSL(alterRemarkDialogSSLKey.value, "remark", alterRemarkDialogValue.value).then(res => {
|
||||
if (res.ret == 0) {
|
||||
alterRemarkDialogShow.value = false
|
||||
MessageShow("success", "证书 " + alterRemarkDialogSSLText.value + " 备注修改成功")
|
||||
querySSLList()
|
||||
|
||||
return
|
||||
}
|
||||
MessageShow("error", "证书 " + alterRemarkDialogSSLText.value + " 备注修改失败: " + res.msg)
|
||||
}).catch((error) => {
|
||||
console.log("证书 " + alterRemarkDialogSSLText.value + " 备注修改失败" + ":请求出错" + error)
|
||||
MessageShow("error", "证书 " + alterRemarkDialogSSLText.value + " 备注修改失败" + ":请求出错")
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const addSSL = () => {
|
||||
|
||||
if (addSSLForm.value.CertBase64 == "") {
|
||||
MessageShow("error", "请选择要保存的证书文件")
|
||||
return
|
||||
}
|
||||
|
||||
if (addSSLForm.value.KeyBase64 == "") {
|
||||
MessageShow("error", "请选择要保存的Key文件")
|
||||
return
|
||||
}
|
||||
apiAddSSL(addSSLForm.value).then((res) => {
|
||||
if (res.ret == 0) {
|
||||
//let item = { IP: addWhiteListForm.value.IP, Effectivetime: res.data }
|
||||
//whitelist.value.push(item)
|
||||
addSSLDialogVisible.value = false
|
||||
MessageShow("success", "添加证书成功")
|
||||
querySSLList()
|
||||
return
|
||||
}
|
||||
MessageShow("error", res.msg)
|
||||
|
||||
}).catch((error) => {
|
||||
console.log("添加SSL证书出错 " + error)
|
||||
MessageShow("error", "添加SSL证书出错 " + error)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
const deleteSSL = (ssl) => {
|
||||
const sslText = ssl.Remark != "" ? ssl.Remark : ssl.CertsInfo[0].Domains[0];
|
||||
ElMessageBox.confirm(
|
||||
'确认要删除 ' + sslText + " 的证书?",
|
||||
'Warning',
|
||||
{
|
||||
confirmButtonText: '确认',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}
|
||||
).then(() => {
|
||||
|
||||
apiDeleteSSL(ssl.Key).then((res) => {
|
||||
if (res.ret == 0) {
|
||||
MessageShow("success", "证书删除成功")
|
||||
querySSLList()
|
||||
return
|
||||
}
|
||||
MessageShow("error", res.msg)
|
||||
}).catch((error) => {
|
||||
console.log("证书删除失败,网络请求出错:" + error)
|
||||
MessageShow("error", "证书删除失败,网络请求出错")
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
const querySSLList = () => {
|
||||
apiGetSSLList().then((res) => {
|
||||
if (res.ret == 0) {
|
||||
console.log(res.list)
|
||||
if (res.list != null) {
|
||||
|
||||
SSLList.value = res.list
|
||||
} else {
|
||||
// whitelist.value= []
|
||||
SSLList.value = []
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
MessageShow("error", res.msg)
|
||||
//console.log("getAdminURL "+getAdminURL())
|
||||
}).catch((error) => {
|
||||
MessageShow("error", "查询证书列表列表出错")
|
||||
})
|
||||
}
|
||||
|
||||
const keydown = (e) => {
|
||||
if (e.keyCode != 13) {
|
||||
return
|
||||
}
|
||||
if (!addSSLDialogVisible.value) {
|
||||
return
|
||||
}
|
||||
addSSL()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
querySSLList();
|
||||
window.addEventListener('keydown', keydown)
|
||||
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.formradius {
|
||||
border: 0px solid var(--el-border-color);
|
||||
border-radius: 0;
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
padding: 15px;
|
||||
|
||||
}
|
||||
|
||||
.itemradius {
|
||||
|
||||
border: 1px solid var(--el-border-color);
|
||||
border-radius: 0;
|
||||
margin-left: 3px;
|
||||
margin-top: 3px;
|
||||
margin-right: 3px;
|
||||
margin-bottom: 25px;
|
||||
min-width: 1350px;
|
||||
}
|
||||
|
||||
.affix-container {
|
||||
text-align: center;
|
||||
border-radius: 4px;
|
||||
width: 3vw;
|
||||
background: var(--el-color-primary-light-9);
|
||||
}
|
||||
</style>
|
|
@ -4,8 +4,9 @@
|
|||
<p class="status">CPU全局使用率:{{ status.usedCPU }}</p>
|
||||
<p class="status">当前进程CPU使用率:{{ status.currentProcessUsedCPU }}</p>
|
||||
<p class="status">进程协程数:{{ status.goroutine }} 占用内存:{{ status.processUsedMem }}</p>
|
||||
<p class="status">Lucky 全局连接数:{{ status.currentConnections }} </p>
|
||||
<p class="status">Lucky 全局限制连接数:{{ status.maxConnections }}</p>
|
||||
<p class="status">端口转发TCP总连接数:{{ status.currentTCPConnections }} </p>
|
||||
<p class="status">端口转发全局UDP读取目标地址数据协程数:{{ status.currentUDPConnections }} </p>
|
||||
<p class="status">端口转发TCP全局限制连接数:{{ status.maxTCPConnections }}</p>
|
||||
<p class="status">Lucky 启动时间:{{ status.runTime }}</p>
|
||||
|
||||
|
||||
|
@ -62,8 +63,9 @@ var status=ref({totleMem: '0m',
|
|||
currentProcessUsedCPU:"0%",
|
||||
goroutine:"0",
|
||||
processUsedMem:"0m",
|
||||
currentConnections:0,
|
||||
maxConnections:0,
|
||||
currentTCPConnections:0,
|
||||
currentUDPConnections:0,
|
||||
maxTCPConnections:0,
|
||||
proxysStatus:"",
|
||||
runTime:""})
|
||||
|
||||
|
|
|
@ -0,0 +1,400 @@
|
|||
<template>
|
||||
|
||||
<div class="PageRadius" :style="{
|
||||
borderRadius: 'base',
|
||||
}">
|
||||
<el-scrollbar height="100%">
|
||||
|
||||
<div class="itemradius" :style="{
|
||||
borderRadius: 'base',
|
||||
}" v-for="device in deviceList" >
|
||||
|
||||
<el-descriptions :column="4" border >
|
||||
|
||||
<el-descriptions-item label="设备操作">
|
||||
<el-tooltip placement="bottom" effect="dark" :trigger-keys="[]" content="">
|
||||
<template #content>
|
||||
唤醒<br />
|
||||
</template>
|
||||
<el-button size="small" :icon="Bell" circle type="success" @click="wakeup(device)">
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
|
||||
<el-tooltip placement="bottom" effect="dark" :trigger-keys="[]" content="">
|
||||
<template #content>
|
||||
关机<br />
|
||||
</template>
|
||||
<el-button size="small" :icon="SwitchButton" circle type="danger">
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
|
||||
|
||||
|
||||
<el-button size="small" type="primary" @click="showAlterDeviceDialog(device)">
|
||||
编辑
|
||||
</el-button>
|
||||
|
||||
<el-button size="small" type="danger" @click="deleteDevice(device)">
|
||||
删除
|
||||
</el-button>
|
||||
</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item label="设备名称" >
|
||||
<el-button size="default" v-show="true">
|
||||
{{ device.DeviceName == '' ? '未命名设备' : device.DeviceName }}
|
||||
</el-button>
|
||||
</el-descriptions-item>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<el-descriptions-item label="设备MAC">
|
||||
<el-tooltip placement="bottom" effect="dark" :trigger-keys="[]" content="">
|
||||
<template #content>
|
||||
<span v-html="StrArrayListToBrHtml(device.MacList)"></span>
|
||||
</template>
|
||||
<el-button size="small" v-show="true">
|
||||
{{device.MacList.length==1?device.MacList[0]:device.MacList[0]+'...' }}
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item label="魔法包广播地址">
|
||||
<el-tooltip placement="bottom" effect="dark" :trigger-keys="[]" content="">
|
||||
<template #content>
|
||||
<span v-html="StrArrayListToBrHtml(device.BroadcastIPs)"></span>
|
||||
</template>
|
||||
<el-button size="small" v-show="true">
|
||||
{{device.BroadcastIPs.length==1?device.BroadcastIPs[0]:device.BroadcastIPs[0]+'...' }}
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
|
||||
|
||||
<el-tooltip class="box-item" effect="dark" :trigger-keys="[]" content="">
|
||||
<template #content>
|
||||
端口<br />
|
||||
</template>
|
||||
<el-button size="small" v-show="true">
|
||||
{{device.Port}}
|
||||
</el-button>
|
||||
|
||||
</el-tooltip>
|
||||
|
||||
</el-descriptions-item>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</el-descriptions>
|
||||
|
||||
</div>
|
||||
|
||||
</el-scrollbar>
|
||||
|
||||
<el-affix position="bottom" :offset="30" class="affix-container">
|
||||
<el-button type="primary" :round=true @click="showAddDeviceDialog">添加可唤醒的设备
|
||||
<el-icon class="el-icon--right">
|
||||
<Plus />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
</el-affix>
|
||||
|
||||
<el-dialog v-if="deviceDialogShow" v-model="deviceDialogShow" :title=deviceDialogTitle draggable
|
||||
:show-close="false" :close-on-click-modal="false" width="400px">
|
||||
<el-form-item label="设备名称" label-width="120px">
|
||||
<el-input v-model="deviceForm.DeviceName" autocomplete="off" />
|
||||
</el-form-item>
|
||||
|
||||
<el-tooltip class="box-item" effect="dark" :trigger-keys="[]" content="">
|
||||
<template #content>
|
||||
每行填写一个MAC<br />
|
||||
一般情况填写一个MAC地址即可<br />
|
||||
</template>
|
||||
|
||||
<el-form-item label-width="120px" label="设备MAC">
|
||||
<el-input v-model="deviceFormMacListArea" :autosize="{ minRows: 1, maxRows: 3 }" placeholder=""
|
||||
type="textarea" wrap="off">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-tooltip>
|
||||
|
||||
|
||||
<el-tooltip class="box-item" effect="dark" :trigger-keys="[]" content="">
|
||||
<template #content>
|
||||
不建议使用255.255.255.255<br />
|
||||
一般家用情况,如果路由器的管理地址是192.168.31.1,则填写192.168.31.255作为广播地址<br />
|
||||
菜鸟没法确定的话可留空,程序会遍历全部IPV4地址发送广播<br />
|
||||
每行填写一个广播地址<br />
|
||||
一般情况填写一个广播地址即可<br />
|
||||
</template>
|
||||
|
||||
<el-form-item label-width="120px" label="魔方包广播地址">
|
||||
<el-input v-model="deviceFormBroadcastIPsArea" :autosize="{ minRows: 1, maxRows: 3 }" placeholder=""
|
||||
type="textarea" wrap="off">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-tooltip>
|
||||
|
||||
|
||||
<el-tooltip class="box-item" effect="dark" :trigger-keys="[]" content="">
|
||||
<template #content>
|
||||
默认端口为9<br />
|
||||
没特殊情况不要修改<br />
|
||||
</template>
|
||||
<el-form-item label="端口" label-width="120px" :min="1" :max="65535">
|
||||
<el-input-number v-model="deviceForm.Port" autocomplete="off" />
|
||||
</el-form-item>
|
||||
</el-tooltip>
|
||||
|
||||
<el-tooltip class="box-item" effect="dark" :trigger-keys="[]" content="">
|
||||
<template #content>
|
||||
每次执行唤醒时重复发送魔方包的次数<br />
|
||||
可设置范围(1-10)<br />
|
||||
</template>
|
||||
<el-form-item label="重复次数" label-width="120px" :min="1" :max="10">
|
||||
<el-input-number v-model="deviceForm.Repeat" autocomplete="off" />
|
||||
</el-form-item>
|
||||
</el-tooltip>
|
||||
|
||||
|
||||
<el-tooltip class="box-item" effect="dark" :trigger-keys="[]" content="">
|
||||
<template #content>
|
||||
一般情况忽略即可<br />
|
||||
目标唤醒设备和lucky不在同一局域网时才用得上这个开关<br />
|
||||
发送广播的同时交给中继设备发送<br />
|
||||
</template>
|
||||
<el-form-item label="转播开关" label-width="120px" v-if="true">
|
||||
<el-switch v-model="deviceForm.Relay" inline-prompt width="50px" active-text="启用"
|
||||
inactive-text="禁用" />
|
||||
</el-form-item>
|
||||
</el-tooltip>
|
||||
|
||||
|
||||
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="deviceDialogShow = false">取消</el-button>
|
||||
<el-button type="primary" @click="addOreAlterDevice">{{deviceDialogCommitButtonText}}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import { ElMessageBox } from 'element-plus'
|
||||
import { MessageShow } from '../../utils/ui'
|
||||
import { StrArrayListToBrHtml, StrArrayListToArea, StringToArrayList } from '../../utils/utils'
|
||||
import { GetToken, apiGetWOLDeviceList, apiAddWOLDevice, apiDeleteWOLDevice, apiAlterWOLDevice,apiWOLDeviceWakeUp } from '../../apis/utils'
|
||||
|
||||
import {
|
||||
SwitchButton,
|
||||
AlarmClock,
|
||||
Bell,
|
||||
} from '@element-plus/icons-vue'
|
||||
|
||||
const deviceDialogShow = ref(false)
|
||||
const deviceDialogTitle = ref("")
|
||||
const deviceDialogCommitButtonText = ref("")
|
||||
const deviceFormMacListArea = ref("")
|
||||
const deviceFormBroadcastIPsArea = ref("")
|
||||
const deviceFormActionType = ref("")
|
||||
|
||||
const deviceList = ref([{
|
||||
Key: "",
|
||||
DeviceName: "",
|
||||
MacList: [''],
|
||||
BroadcastIPs: [''],
|
||||
Port: 9,
|
||||
Relay: true,
|
||||
Repeat: 5,
|
||||
},])
|
||||
|
||||
const deviceForm = ref({
|
||||
Key: "",
|
||||
DeviceName: "",
|
||||
MacList: [''],
|
||||
BroadcastIPs: [''],
|
||||
Port: 9,
|
||||
Relay: true,
|
||||
Repeat: 5,
|
||||
})
|
||||
|
||||
const deleteDevice = (device)=>{
|
||||
|
||||
const deviceName = device.DeviceName==""?device.MacList[0]:device.DeviceName;
|
||||
const deviceText = "[" + deviceName +"]"
|
||||
|
||||
ElMessageBox.confirm(
|
||||
'确认要删除待唤醒设备 ' + deviceText + "?",
|
||||
'Warning',
|
||||
{
|
||||
confirmButtonText: '确认',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
console.log("确认删除 " + deviceText)
|
||||
|
||||
apiDeleteWOLDevice(device.Key).then((res) => {
|
||||
if (res.ret == 0) {
|
||||
queryDeviceList();
|
||||
MessageShow("success", "删除成功")
|
||||
} else {
|
||||
MessageShow("error", res.msg)
|
||||
}
|
||||
|
||||
}).catch((error) => {
|
||||
console.log("删除唤醒设备失败,网络请求出错:" + error)
|
||||
MessageShow("error", "删除唤醒设备失败,网络请求出错")
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
const wakeup = (device)=>{
|
||||
apiWOLDeviceWakeUp(device.Key).then((res) => {
|
||||
if (res.ret == 0) {
|
||||
MessageShow("success", "唤醒指令已发送")
|
||||
queryDeviceList();
|
||||
return
|
||||
}
|
||||
MessageShow("error", res.msg)
|
||||
}).catch((error) => {
|
||||
console.log("唤醒指令发送失败,网络请求出错:" + error)
|
||||
MessageShow("error", "唤醒指令发送失败,网络请求出错")
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
const addOreAlterDevice = () => {
|
||||
|
||||
deviceForm.value.BroadcastIPs = StringToArrayList(deviceFormBroadcastIPsArea.value)
|
||||
deviceForm.value.MacList = StringToArrayList(deviceFormMacListArea.value)
|
||||
|
||||
switch (deviceFormActionType.value) {
|
||||
case "add":
|
||||
apiAddWOLDevice(deviceForm.value).then((res) => {
|
||||
if (res.ret == 0) {
|
||||
deviceDialogShow.value = false;
|
||||
MessageShow("success", "设备添加成功")
|
||||
queryDeviceList();
|
||||
return
|
||||
}
|
||||
MessageShow("error", res.msg)
|
||||
}).catch((error) => {
|
||||
console.log("唤醒设备添加失败,网络请求出错:" + error)
|
||||
MessageShow("error", "唤醒设备添加失败,网络请求出错")
|
||||
})
|
||||
break;
|
||||
case "alter":
|
||||
|
||||
apiAlterWOLDevice(deviceForm.value).then((res) => {
|
||||
if (res.ret == 0) {
|
||||
deviceDialogShow.value = false;
|
||||
MessageShow("success", "设备修改成功")
|
||||
queryDeviceList();
|
||||
return
|
||||
}
|
||||
MessageShow("error", res.msg)
|
||||
}).catch((error) => {
|
||||
console.log("唤醒设备修改失败,网络请求出错:" + error)
|
||||
MessageShow("error", "唤醒设备修改失败,网络请求出错")
|
||||
})
|
||||
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
const showAlterDeviceDialog = (device)=>{
|
||||
deviceDialogCommitButtonText.value = "修改"
|
||||
deviceForm.value = {
|
||||
Key: device.Key,
|
||||
DeviceName: device.DeviceName,
|
||||
MacList:device.MacList,
|
||||
BroadcastIPs: device.BroadcastIPs,
|
||||
Port: device.Port,
|
||||
Relay: device.Relay,
|
||||
Repeat: device.Repeat,
|
||||
}
|
||||
deviceFormActionType.value = "alter"
|
||||
deviceFormMacListArea.value = StrArrayListToArea(device.MacList)
|
||||
deviceFormBroadcastIPsArea.value = StrArrayListToArea(device.BroadcastIPs)
|
||||
deviceDialogShow.value = true
|
||||
}
|
||||
|
||||
const showAddDeviceDialog = () => {
|
||||
deviceDialogCommitButtonText.value = "添加"
|
||||
deviceForm.value = {
|
||||
Key: "",
|
||||
DeviceName: "",
|
||||
MacList: [''],
|
||||
BroadcastIPs: [''],
|
||||
Port: 9,
|
||||
Relay: true,
|
||||
Repeat: 5,
|
||||
}
|
||||
|
||||
deviceFormActionType.value = "add"
|
||||
deviceFormMacListArea.value = ""
|
||||
deviceFormBroadcastIPsArea.value = ""
|
||||
deviceDialogShow.value = true
|
||||
|
||||
}
|
||||
|
||||
|
||||
const queryDeviceList = () => {
|
||||
apiGetWOLDeviceList().then((res) => {
|
||||
//console.log(res.data)
|
||||
deviceList.value = res.list
|
||||
}).catch((error) => {
|
||||
console.log("获取设备列表出错:" + error)
|
||||
MessageShow("error", "获获取设备列表出错")
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
var timerID: any
|
||||
|
||||
onMounted(() => {
|
||||
queryDeviceList();
|
||||
|
||||
timerID = setInterval(() => {
|
||||
queryDeviceList();
|
||||
}, 2000);
|
||||
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.itemradius {
|
||||
|
||||
border: 1px solid var(--el-border-color);
|
||||
border-radius: 0;
|
||||
margin-left: 3px;
|
||||
margin-top: 3px;
|
||||
margin-right: 3px;
|
||||
margin-bottom: 5px;
|
||||
min-width: 1200px;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -12,9 +12,10 @@ export function isIP(ip :string){
|
|||
}
|
||||
|
||||
const MenuIndexList = ["#status",
|
||||
"#log","#relayset","#whitelistset",
|
||||
"#log","#whitelistset",
|
||||
"#whitelists","#blacklists","#set",
|
||||
"#login","#ddns","#ddnstasklist","#ddnsset","#about","#reverseproxylist"]
|
||||
"#login","#ddns","#ddnstasklist","#ddnsset",
|
||||
"#about","#reverseproxylist","#ssl","#portforward","#portforwardset","#wol"]
|
||||
|
||||
export function PageExist(page:string) {
|
||||
for(let i in MenuIndexList){
|
||||
|
@ -82,4 +83,13 @@ export const LogLevelList = [
|
|||
value: 6,
|
||||
label: 'Trace',
|
||||
},
|
||||
]
|
||||
]
|
||||
|
||||
export const bytesToSize = (bytes) => {
|
||||
if (bytes === 0) return '0 B';
|
||||
var k = 1000, // or 1024
|
||||
sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
|
||||
i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
|
||||
return (bytes / Math.pow(k, i)).toPrecision(3) + ' ' + sizes[i];
|
||||
}
|
|
@ -70,7 +70,7 @@ func flushblacklist(c *gin.Context) {
|
|||
|
||||
newTime, err := config.BlackListAdd(ip, int32(life))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 1, "msg": "刷新IP有效期出错"})
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 1, "msg": fmt.Sprintf("刷新IP有效期出错:%s", err.Error())})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 0, "data": newTime})
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
package web
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func getFileBase64(c *gin.Context) {
|
||||
file, err := c.FormFile("file")
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 1, "msg": fmt.Sprintf("c.FormFile err:%s", err.Error())})
|
||||
return
|
||||
}
|
||||
|
||||
src, err := file.Open()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 1, "msg": fmt.Sprintf("file.Open err:%s", err.Error())})
|
||||
return
|
||||
}
|
||||
defer src.Close()
|
||||
|
||||
fileBytes, err := io.ReadAll(src)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 1, "msg": fmt.Sprintf("ioutil.ReadAll err:%s", err.Error())})
|
||||
return
|
||||
}
|
||||
|
||||
fileBytesBase64Str := base64.StdEncoding.EncodeToString(fileBytes)
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 0, "file": file.Filename, "base64": fileBytesBase64Str})
|
||||
|
||||
}
|
|
@ -91,9 +91,7 @@ func restoreConfigure(c *gin.Context) {
|
|||
if conf.BaseConfigure.AdminAccount == "" ||
|
||||
conf.BaseConfigure.AdminPassword == "" ||
|
||||
conf.BaseConfigure.AdminWebListenPort <= 0 ||
|
||||
conf.BaseConfigure.AdminWebListenPort >= 65536 ||
|
||||
conf.BaseConfigure.GlobalMaxConnections <= 0 ||
|
||||
conf.BaseConfigure.ProxyCountLimit <= 0 {
|
||||
conf.BaseConfigure.AdminWebListenPort >= 65536 {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 1, "msg": fmt.Sprintf("配置文件[%s]参数有误", file.Filename)})
|
||||
return
|
||||
}
|
||||
|
|
|
@ -0,0 +1,190 @@
|
|||
package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/gdy666/lucky/config"
|
||||
"github.com/gdy666/lucky/socketproxy"
|
||||
"github.com/gdy666/lucky/thirdlib/gdylib/stringsp"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type ruleInfo struct {
|
||||
config.PortForwardsRule
|
||||
ProxyList []proxyInfo
|
||||
LastLogs []any
|
||||
}
|
||||
type proxyInfo struct {
|
||||
Proxy string
|
||||
TrafficIn int64
|
||||
TrafficOut int64
|
||||
CurrentConnections int64
|
||||
}
|
||||
|
||||
func PortForwardsRuleList(c *gin.Context) {
|
||||
ruleRawList := config.GetPortForwardsRuleList()
|
||||
|
||||
var ruleList []ruleInfo
|
||||
|
||||
for i := range ruleRawList {
|
||||
var proxyInfoList []proxyInfo
|
||||
for j := range *ruleRawList[i].ReverseProxyList {
|
||||
p := proxyInfo{
|
||||
Proxy: (*ruleRawList[i].ReverseProxyList)[j].String(),
|
||||
TrafficIn: (*ruleRawList[i].ReverseProxyList)[j].GetTrafficIn(),
|
||||
TrafficOut: (*ruleRawList[i].ReverseProxyList)[j].GetTrafficOut(),
|
||||
CurrentConnections: (*ruleRawList[i].ReverseProxyList)[j].GetCurrentConnections()}
|
||||
proxyInfoList = append(proxyInfoList, p)
|
||||
}
|
||||
r := ruleInfo{
|
||||
PortForwardsRule: ruleRawList[i],
|
||||
ProxyList: proxyInfoList,
|
||||
LastLogs: ruleRawList[i].GetLastLogs(ruleRawList[i].WebListShowLastLogMaxCount)}
|
||||
ruleList = append(ruleList, r)
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 0, "list": ruleList})
|
||||
}
|
||||
|
||||
func PortForwardsRuleAdd(c *gin.Context) {
|
||||
var newRule config.PortForwardsRule
|
||||
err := c.Bind(&newRule)
|
||||
if err != nil {
|
||||
log.Printf("请求解析出错:%s", err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 1, "msg": fmt.Sprintf("请求解析出错:%s", err.Error())})
|
||||
return
|
||||
}
|
||||
|
||||
newRule.Key = stringsp.GetRandomString(16)
|
||||
err = newRule.InitProxyList()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 2, "msg": fmt.Sprintf("添加转发规则过程初始化ProxyList出错:%s", err.Error())})
|
||||
return
|
||||
}
|
||||
|
||||
if int64(config.GetPortForwardsGlobalProxyCount()+newRule.ProxyCount()) > socketproxy.GetGlobalMaxPortForwardsCountLimit() {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 3, "msg": "超出全局端口转发最大数量限制"})
|
||||
return
|
||||
}
|
||||
|
||||
err = config.PortForwardsRuleListAdd(&newRule)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 4, "msg": fmt.Sprintf("添加转发规则出错:%s", err.Error())})
|
||||
return
|
||||
}
|
||||
|
||||
config.StartAllSocketProxysByRuleKey(newRule.Key)
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 0})
|
||||
}
|
||||
|
||||
func PortForwardsRuleAlter(c *gin.Context) {
|
||||
var alterRule config.PortForwardsRule
|
||||
err := c.Bind(&alterRule)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 1, "msg": fmt.Sprintf("请求解析出错:%s", err.Error())})
|
||||
return
|
||||
}
|
||||
|
||||
err = alterRule.InitProxyList()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 2, "msg": fmt.Sprintf("修改转发规则时初始化代理列表出错:%s", err.Error())})
|
||||
return
|
||||
}
|
||||
|
||||
if int64(config.GetPortForwardsGlobalProxyCountExcept(alterRule.Key)+alterRule.ProxyCount()) > socketproxy.GetGlobalMaxPortForwardsCountLimit() {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 3, "msg": "超出全局端口转发最大数量限制"})
|
||||
return
|
||||
}
|
||||
|
||||
config.StopAllSocketProxysByRuleKey(alterRule.Key)
|
||||
|
||||
err = config.UpdatePortForwardsRuleToPortForwardsRuleList(alterRule.Key, &alterRule)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 4, "msg": fmt.Sprintf("修改转发规则出错:%s", err.Error())})
|
||||
return
|
||||
}
|
||||
|
||||
if alterRule.Enable {
|
||||
config.StartAllSocketProxysByRuleKey(alterRule.Key)
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 0})
|
||||
}
|
||||
|
||||
func PortForwardsRuleEnable(c *gin.Context) {
|
||||
enableStr := c.Query("enable")
|
||||
key := c.Query("key")
|
||||
|
||||
var enable bool = false
|
||||
if enableStr == "true" {
|
||||
enable = true
|
||||
}
|
||||
|
||||
err := config.EnablePortForwardsRuleByKey(key, enable)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 1, "msg": fmt.Sprintf("开关转发规则出错:%s", err.Error())})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 0})
|
||||
}
|
||||
|
||||
func PortForwardsRuleDelete(c *gin.Context) {
|
||||
key := c.Query("key")
|
||||
|
||||
err := config.PortForwardsRuleListDelete(key)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 1, "msg": fmt.Sprintf("删除转发规则出错:%s", err.Error())})
|
||||
return
|
||||
}
|
||||
|
||||
config.TidyPortforwardLogsCache()
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 0})
|
||||
}
|
||||
|
||||
func portforwardConfigure(c *gin.Context) {
|
||||
conf := config.GetPortForwardsConfigure()
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 0, "configure": conf})
|
||||
}
|
||||
|
||||
func alterPortForwardConfigure(c *gin.Context) {
|
||||
var requestObj config.PortForwardsConfigure
|
||||
err := c.BindJSON(&requestObj)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 1, "msg": "请求解析出错"})
|
||||
return
|
||||
}
|
||||
|
||||
err = config.SetPortForwardsConfigure(&requestObj)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 2, "msg": "保存配置过程发生错误,请检测相关启动配置"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 0})
|
||||
}
|
||||
|
||||
func getPortwardRuleLogs(c *gin.Context) {
|
||||
key := c.Query("key")
|
||||
pageSize, _ := strconv.Atoi(c.Query("pageSize"))
|
||||
if pageSize <= 0 {
|
||||
pageSize = 10
|
||||
}
|
||||
page, _ := strconv.Atoi(c.Query("page"))
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
|
||||
rule := config.GetPortForwardsRuleByKey(key)
|
||||
if rule == nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 1, "msg": fmt.Sprintf("找不到key:%s对应的规则", key)})
|
||||
return
|
||||
}
|
||||
total, logList := rule.GetLogsBuffer().GetLogsByLimit(config.WebLogConvert, pageSize, page)
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 0, "total": total, "page": page, "pageSize": pageSize, "logs": logList})
|
||||
}
|
|
@ -69,19 +69,6 @@ func alterReverseProxyRule(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
// needStop := false
|
||||
// if preRule != nil &&
|
||||
// (preRule.Network != requestObj.Network ||
|
||||
// preRule.ListenPort != requestObj.ListenPort ||
|
||||
// preRule.Enable != requestObj.Enable ||
|
||||
// !requestObj.Enable) {
|
||||
// needStop = true
|
||||
// }
|
||||
|
||||
// if needStop {
|
||||
|
||||
// }
|
||||
|
||||
reverseproxy.EnableRuleByKey(requestObj.RuleKey, false)
|
||||
//reverseproxy.FlushCache(requestObj.RuleKey)
|
||||
if requestObj.Enable {
|
||||
|
|
|
@ -1,200 +0,0 @@
|
|||
package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gdy666/lucky/rule"
|
||||
"github.com/gdy666/lucky/socketproxy"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func rulelist(c *gin.Context) {
|
||||
ruleList, proxyListInfoMap := rule.GetRelayRuleList()
|
||||
type ruleItem struct {
|
||||
Name string `json:"Name"`
|
||||
MainConfigure string `json:"Mainconfigure"`
|
||||
RelayType string `json:"RelayType"`
|
||||
ListenIP string `json:"ListenIP"`
|
||||
ListenPorts string `json:"ListenPorts"`
|
||||
TargetIP string `json:"TargetIP"`
|
||||
TargetPorts string `json:"TargetPorts"`
|
||||
BalanceTargetAddressList []string `json:"BalanceTargetAddressList"`
|
||||
Options socketproxy.RelayRuleOptions `json:"Options"`
|
||||
SubRuleList []rule.SubRelayRule `json:"SubRuleList"`
|
||||
From string `json:"From"`
|
||||
IsEnable bool `json:"Enable"`
|
||||
ProxyList []rule.RelayRuleProxyInfo `json:"ProxyList"`
|
||||
}
|
||||
|
||||
//proxyListInfoMap[(*ruleList)[i].MainConfigure]
|
||||
var data []ruleItem
|
||||
|
||||
for i := range *ruleList {
|
||||
item := ruleItem{
|
||||
Name: (*ruleList)[i].Name,
|
||||
MainConfigure: (*ruleList)[i].MainConfigure,
|
||||
RelayType: (*ruleList)[i].RelayType,
|
||||
ListenIP: (*ruleList)[i].ListenIP,
|
||||
ListenPorts: (*ruleList)[i].ListenPorts,
|
||||
TargetIP: (*ruleList)[i].TargetIP,
|
||||
TargetPorts: (*ruleList)[i].TargetPorts,
|
||||
Options: (*ruleList)[i].Options,
|
||||
SubRuleList: (*ruleList)[i].SubRuleList,
|
||||
From: (*ruleList)[i].From,
|
||||
IsEnable: (*ruleList)[i].IsEnable,
|
||||
ProxyList: proxyListInfoMap[(*ruleList)[i].MainConfigure],
|
||||
BalanceTargetAddressList: (*ruleList)[i].BalanceTargetAddressList,
|
||||
}
|
||||
data = append(data, item)
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 0, "data": data})
|
||||
|
||||
}
|
||||
|
||||
func addrule(c *gin.Context) {
|
||||
var requestRule rule.RelayRule
|
||||
err := c.BindJSON(&requestRule)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 1, "msg": fmt.Sprintf("请求解析出错:%s", err.Error())})
|
||||
return
|
||||
}
|
||||
|
||||
dealRequestRule(&requestRule)
|
||||
|
||||
configureStr := requestRule.CreateMainConfigure()
|
||||
|
||||
r, err := rule.CreateRuleByConfigureAndOptions(requestRule.Name, configureStr, requestRule.Options)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 1, "msg": fmt.Sprintf("创建转发规则出错:%s", err.Error())})
|
||||
return
|
||||
}
|
||||
|
||||
synsRes, err := rule.AddRuleToGlobalRuleList(true, *r)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 1, "msg": fmt.Sprintf("添加转发规则出错:%s", err.Error())})
|
||||
return
|
||||
}
|
||||
|
||||
r, _, err = rule.EnableRelayRuleByKey(r.MainConfigure)
|
||||
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 0, "msg": fmt.Sprintf("启用规则出错:%s", err.Error())})
|
||||
return
|
||||
}
|
||||
log.Printf("添加转发规则[%s][%s]成功", r.Name, r.MainConfigure)
|
||||
|
||||
if synsRes != "" {
|
||||
synsRes = "保存配置文件出错,请检查配置文件设置"
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 0, "msg": "添加规则并启用成功", "syncres": synsRes})
|
||||
}
|
||||
|
||||
func alterrule(c *gin.Context) {
|
||||
|
||||
var requestRule rule.RelayRule
|
||||
err := c.BindJSON(&requestRule)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 1, "msg": fmt.Sprintf("修改请求解析出错:%s", err.Error())})
|
||||
return
|
||||
}
|
||||
|
||||
dealRequestRule(&requestRule)
|
||||
|
||||
//fmt.Printf("balance:%v\n", requestRule.BalanceTargetAddressList)
|
||||
|
||||
preConfigureStr := requestRule.MainConfigure
|
||||
configureStr := requestRule.CreateMainConfigure()
|
||||
// configureStr := fmt.Sprintf("%s@%s:%sto%s:%s",
|
||||
// requestRule.RelayType,
|
||||
// requestRule.ListenIP, requestRule.ListenPorts,
|
||||
// requestRule.TargetIP, requestRule.TargetPorts)
|
||||
|
||||
r, err := rule.CreateRuleByConfigureAndOptions(requestRule.Name, configureStr, requestRule.Options)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 1, "msg": fmt.Sprintf("修改转发规则[%s]时出错:%s", preConfigureStr, err.Error())})
|
||||
return
|
||||
}
|
||||
|
||||
syncSuccess, err := rule.AlterRuleInGlobalRuleListByKey(preConfigureStr, r)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 1, "msg": fmt.Sprintf("修改转发规则[%s]时出错:%s", preConfigureStr, err.Error())})
|
||||
return
|
||||
}
|
||||
|
||||
r, _, err = rule.EnableRelayRuleByKey(r.MainConfigure)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 0, "msg": fmt.Sprintf("修改转发规则成功,但启用规则时出错:%s", err.Error())})
|
||||
return
|
||||
}
|
||||
log.Printf("修改转发规则[%s][%s]成功", r.Name, r.MainConfigure)
|
||||
|
||||
synsRes := ""
|
||||
|
||||
if !syncSuccess {
|
||||
synsRes = "同步修改规则数据到配置文件出错"
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 0, "msg": "修改转发规则成功", "syncres": synsRes})
|
||||
}
|
||||
|
||||
func deleterule(c *gin.Context) {
|
||||
ruleKey := c.Query("rule")
|
||||
|
||||
rule.DisableRelayRuleByKey(ruleKey)
|
||||
|
||||
syncSuccess, err := rule.DeleteGlobalRuleByKey(ruleKey)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 1, "msg": fmt.Sprintf("删除转发规则出错:%s", err.Error())})
|
||||
return
|
||||
}
|
||||
|
||||
syncRes := ""
|
||||
if !syncSuccess {
|
||||
syncRes = "同步规则信息到配置文件出错"
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 0, "msg": "删除成功", "syncres": syncRes})
|
||||
}
|
||||
|
||||
func dealRequestRule(r *rule.RelayRule) {
|
||||
r.ListenPorts = strings.TrimSpace(r.ListenPorts)
|
||||
r.TargetPorts = strings.TrimSpace(r.TargetPorts)
|
||||
r.ListenIP = strings.TrimSpace(r.ListenIP)
|
||||
r.TargetIP = strings.TrimSpace(r.TargetIP)
|
||||
r.RelayType = strings.TrimSpace(r.RelayType)
|
||||
r.Name = strings.TrimSpace(r.Name)
|
||||
|
||||
}
|
||||
|
||||
func enablerule(c *gin.Context) {
|
||||
|
||||
enable := c.Query("enable")
|
||||
key := c.Query("key")
|
||||
|
||||
var err error
|
||||
var r *rule.RelayRule
|
||||
var syncSuccess bool
|
||||
|
||||
if enable == "true" {
|
||||
r, syncSuccess, err = rule.EnableRelayRuleByKey(key)
|
||||
} else {
|
||||
r, syncSuccess, err = rule.DisableRelayRuleByKey(key)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 1, "msg": fmt.Sprintf("开关规则出错:%s", err.Error())})
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("[%s] relayRule[%s][%s]", enable, r.Name, r.MainConfigure)
|
||||
syncRes := ""
|
||||
if !syncSuccess {
|
||||
syncRes = "同步规则状态到配置文件出错"
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 0, "msg": "", "syncres": syncRes})
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/gdy666/lucky/config"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func addSSL(c *gin.Context) {
|
||||
var requestObj config.SSLCertficate
|
||||
err := c.BindJSON(&requestObj)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 1, "msg": "请求解析出错"})
|
||||
return
|
||||
}
|
||||
|
||||
err = requestObj.Init()
|
||||
if err != nil {
|
||||
log.Printf("addSSL requestObj.Init() error:%s", err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 2, "msg": "证书和Key有误!"})
|
||||
return
|
||||
}
|
||||
|
||||
//fmt.Printf("CertsInfo:%v\n", *requestObj.CertsInfo)
|
||||
err = config.SSLCertficateListAdd(&requestObj)
|
||||
if err != nil {
|
||||
log.Printf("config.SSLCertficateListAdd error:%s", err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 2, "msg": fmt.Sprintf("添加SSL证书出错!:%s", err.Error())})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 0})
|
||||
|
||||
}
|
||||
|
||||
type sslResInfo struct {
|
||||
Key string `json:"Key"`
|
||||
Remark string `json:"Remark"`
|
||||
Enable bool `json:"Enable"`
|
||||
AddTime string `json:"AddTime"`
|
||||
CertsInfo *[]config.CertInfo `json:"CertsInfo"`
|
||||
}
|
||||
|
||||
func getSSLCertficateList(c *gin.Context) {
|
||||
rawList := config.GetSSLCertficateList()
|
||||
var res []sslResInfo
|
||||
for i := range rawList {
|
||||
info := sslResInfo{
|
||||
Key: rawList[i].Key,
|
||||
Remark: rawList[i].Remark,
|
||||
Enable: rawList[i].Enable,
|
||||
AddTime: rawList[i].AddTime,
|
||||
CertsInfo: rawList[i].CertsInfo,
|
||||
}
|
||||
|
||||
res = append(res, info)
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 0, "list": res})
|
||||
}
|
||||
|
||||
func alterSSLCertficate(c *gin.Context) {
|
||||
key := c.Query("key")
|
||||
field := c.Query("field")
|
||||
value := c.Query("value")
|
||||
var err error
|
||||
switch field {
|
||||
case "enable":
|
||||
{
|
||||
enable := false
|
||||
|
||||
if value == "true" {
|
||||
enable = true
|
||||
}
|
||||
err = config.SSLCertficateEnable(key, enable)
|
||||
}
|
||||
case "remark":
|
||||
{
|
||||
err = config.SSLCertficateAlterRemark(key, value)
|
||||
}
|
||||
default:
|
||||
err = fmt.Errorf("不支持修改的字段:%s", field)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 1, "msg": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 0})
|
||||
}
|
||||
|
||||
func deleteSSLCertficate(c *gin.Context) {
|
||||
key := c.Query("key")
|
||||
err := config.SSLCertficateListDelete(key)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 1, "msg": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 0})
|
||||
}
|
72
web/web.go
72
web/web.go
|
@ -1,6 +1,7 @@
|
|||
package web
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"embed"
|
||||
"fmt"
|
||||
"io"
|
||||
|
@ -57,10 +58,10 @@ func init() {
|
|||
|
||||
}
|
||||
|
||||
func RunAdminWeb(listen string, logMaxSize int) {
|
||||
func RunAdminWeb(conf *config.BaseConfigure) {
|
||||
|
||||
//gin.Default()
|
||||
logBuffer.SetBufferSize(logMaxSize)
|
||||
logBuffer.SetBufferSize(conf.LogMaxSize)
|
||||
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
r := gin.New()
|
||||
|
@ -87,11 +88,14 @@ func RunAdminWeb(listen string, logMaxSize int) {
|
|||
authorized.GET("/api/status", status)
|
||||
authorized.GET("/api/test", test)
|
||||
|
||||
authorized.GET("/api/rulelist", rulelist)
|
||||
authorized.POST("/api/rule", addrule)
|
||||
authorized.DELETE("/api/rule", deleterule)
|
||||
authorized.PUT("/api/rule", alterrule)
|
||||
authorized.GET("/api/rule/enable", enablerule)
|
||||
authorized.GET("/api/portforwards", PortForwardsRuleList)
|
||||
authorized.POST("/api/portforward", PortForwardsRuleAdd)
|
||||
authorized.DELETE("/api/portforward", PortForwardsRuleDelete)
|
||||
authorized.PUT("/api/portforward", PortForwardsRuleAlter)
|
||||
authorized.GET("/api/portforward/enable", PortForwardsRuleEnable)
|
||||
authorized.GET("/api/portforward/configure", portforwardConfigure)
|
||||
authorized.PUT("/api/portforward/configure", alterPortForwardConfigure)
|
||||
authorized.GET("/api/portforward/logs", getPortwardRuleLogs)
|
||||
|
||||
authorized.GET("/api/baseconfigure", baseconfigure)
|
||||
authorized.PUT("/api/baseconfigure", alterBaseConfigure)
|
||||
|
@ -125,9 +129,22 @@ func RunAdminWeb(listen string, logMaxSize int) {
|
|||
authorized.GET("/api/reverseproxyrule/enable", enableReverseProxyRule)
|
||||
authorized.GET("/api/reverseproxyrule/logs", getReverseProxyLog)
|
||||
|
||||
authorized.POST("/api/ssl", addSSL)
|
||||
authorized.GET("/api/ssl", getSSLCertficateList)
|
||||
authorized.PUT("/api/ssl", alterSSLCertficate)
|
||||
authorized.DELETE("/api/ssl", deleteSSLCertficate)
|
||||
|
||||
authorized.POST("/api/wol/device", addWOLDevice)
|
||||
authorized.GET("/api/wol/device/wakeup", WOLDeviceWakeUp)
|
||||
authorized.GET("/api/wol/devices", getWOLDeviceList)
|
||||
authorized.PUT("/api/wol/device", alterWOLDevice)
|
||||
authorized.DELETE("/api/wol/device", deleteWOLDevice)
|
||||
|
||||
authorized.GET("/api/info", info)
|
||||
authorized.GET("/api/configure", configure)
|
||||
authorized.POST("/api/configure", restoreConfigure)
|
||||
authorized.POST("/api/getfilebase64", getFileBase64)
|
||||
|
||||
authorized.GET("/api/restoreconfigureconfirm", restoreConfigureConfirm)
|
||||
r.PUT("/api/logout", logout)
|
||||
}
|
||||
|
@ -140,11 +157,39 @@ func RunAdminWeb(listen string, logMaxSize int) {
|
|||
|
||||
//r.Use(func() *gin.Context {})
|
||||
|
||||
err := r.Run(listen)
|
||||
go func() {
|
||||
httpListen := fmt.Sprintf(":%d", conf.AdminWebListenPort)
|
||||
log.Printf("AdminWeb(Http) listen on %s", httpListen)
|
||||
err := r.Run(httpListen)
|
||||
if err != nil {
|
||||
log.Printf("Admin Http Listen error:%s", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
}()
|
||||
|
||||
if err != nil {
|
||||
log.Printf("http.ListenAndServe error:%s", err.Error())
|
||||
os.Exit(1)
|
||||
if conf.AdminWebListenTLS {
|
||||
certlist := config.GetValidSSLCertficateList()
|
||||
if len(certlist) <= 0 {
|
||||
log.Printf("可用SSL证书列表为空,AdminWeb(Https) 监听服务中止运行")
|
||||
return
|
||||
}
|
||||
httpsListen := fmt.Sprintf(":%d", conf.AdminWebListenHttpsPort)
|
||||
|
||||
server := &http.Server{
|
||||
Addr: httpsListen,
|
||||
Handler: r,
|
||||
}
|
||||
server.TLSConfig = &tls.Config{}
|
||||
server.TLSConfig.Certificates = certlist
|
||||
ln, err := net.Listen("tcp", httpsListen)
|
||||
if err != nil {
|
||||
log.Fatalf("Admin Https Listen error:%s", err.Error())
|
||||
}
|
||||
log.Printf("AdminWeb(Https) listen on %s", httpsListen)
|
||||
err = server.ServeTLS(ln, "", "")
|
||||
if err != nil {
|
||||
log.Printf("AdminWeb(Https) Server error:%s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -382,8 +427,9 @@ func status(c *gin.Context) {
|
|||
respMap["currentProcessUsedCPU"] = fmt.Sprintf("%.2f%%", GetCurrentProcessCPUPrecent())
|
||||
respMap["goroutine"] = fmt.Sprintf("%d", runtime.NumGoroutine())
|
||||
respMap["processUsedMem"] = stringsp.BinaryUnitToStr(currentProcessMem)
|
||||
respMap["currentConnections"] = fmt.Sprintf("%d", socketproxy.GetGlobalConnections())
|
||||
respMap["maxConnections"] = fmt.Sprintf("%d", socketproxy.GetGlobalMaxConnections())
|
||||
respMap["currentTCPConnections"] = fmt.Sprintf("%d", socketproxy.GetGlobalTCPPortForwardConnections())
|
||||
respMap["currentUDPConnections"] = fmt.Sprintf("%d", socketproxy.GetGlobalUDPPortForwardGroutineCount())
|
||||
respMap["maxTCPConnections"] = fmt.Sprintf("%d", socketproxy.GetGlobalTCPPortforwardMaxConnections())
|
||||
respMap["usedCPU"] = fmt.Sprintf("%.2f%%", GetCpuPercent())
|
||||
respMap["runTime"] = appInfo.RunTime
|
||||
//respMap["proxysStatus"] = proxyStatusList
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/gdy666/lucky/config"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func addWOLDevice(c *gin.Context) {
|
||||
var requestObj config.WOLDevice
|
||||
err := c.BindJSON(&requestObj)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 1, "msg": "请求解析出错"})
|
||||
return
|
||||
}
|
||||
|
||||
err = checkWolDevice(&requestObj)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 2, "msg": fmt.Sprintf("添加网络唤醒设备出错:%s", err.Error())})
|
||||
return
|
||||
}
|
||||
|
||||
err = config.WOLDeviceListAdd(&requestObj)
|
||||
if err != nil {
|
||||
log.Printf("config.WOLDeviceListAdd error:%s", err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 2, "msg": fmt.Sprintf("添加网络唤醒设备出错!:%s", err.Error())})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 0})
|
||||
}
|
||||
|
||||
func getWOLDeviceList(c *gin.Context) {
|
||||
list := config.GetWOLDeviceList()
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 0, "list": list})
|
||||
}
|
||||
|
||||
func alterWOLDevice(c *gin.Context) {
|
||||
var requestObj config.WOLDevice
|
||||
err := c.BindJSON(&requestObj)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 1, "msg": "请求解析出错"})
|
||||
return
|
||||
}
|
||||
|
||||
err = checkWolDevice(&requestObj)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 2, "msg": fmt.Sprintf("修改网络唤醒设备出错:%s", err.Error())})
|
||||
return
|
||||
}
|
||||
|
||||
err = config.WOLDeviceListAlter(&requestObj)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 1, "msg": fmt.Sprintf("修改网络唤醒设备配置失败:%s", err.Error())})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 0})
|
||||
}
|
||||
|
||||
func deleteWOLDevice(c *gin.Context) {
|
||||
key := c.Query("key")
|
||||
err := config.WOLDeviceListDelete(key)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 1, "msg": fmt.Sprintf("删除网络唤醒设备失败:%s", err.Error())})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 0})
|
||||
}
|
||||
|
||||
func WOLDeviceWakeUp(c *gin.Context) {
|
||||
key := c.Query("key")
|
||||
|
||||
device := config.GetWOLDeviceByKey(key)
|
||||
if device == nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 1, "msg": fmt.Sprintf("找不到Key对应的设备,唤醒失败")})
|
||||
return
|
||||
}
|
||||
err := device.WakeUp()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 2, "msg": "唤醒失败"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"ret": 0})
|
||||
}
|
||||
|
||||
func checkWolDevice(d *config.WOLDevice) error {
|
||||
|
||||
// if strings.TrimSpace(d.DeviceName) == "" {
|
||||
// return fmt.Errorf("设备名称不能为空")
|
||||
// }
|
||||
|
||||
if d.Port <= 0 || d.Port > 065535 {
|
||||
d.Port = 9
|
||||
}
|
||||
|
||||
if d.Repeat <= 0 || d.Repeat > 10 {
|
||||
d.Repeat = 5
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
//go:build !adminweb
|
||||
// +build !adminweb
|
||||
|
||||
package main
|
||||
|
||||
func RunAdminWeb(listenPort int, logMaxSize int) {
|
||||
}
|
Loading…
Reference in New Issue