546 lines
14 KiB
Go
546 lines
14 KiB
Go
//Copyright 2022 gdy, 272288813@qq.com
|
|
package rule
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"net"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/gdy666/lucky/base"
|
|
)
|
|
|
|
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 base.RelayRuleOptions `json:"Options"`
|
|
SubRuleList []SubRelayRule `json:"SubRuleList"`
|
|
From string `json:"From"`
|
|
IsEnable bool `json:"Enable"`
|
|
proxyList *[]base.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 *base.RelayRuleOptions) (relayRules *[]RelayRule, err error) {
|
|
//proxyMap := make(map[string]base.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 base.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 []base.Proxy
|
|
|
|
for i := range r.SubRuleList {
|
|
if len(r.BalanceTargetAddressList) == 0 {
|
|
for j := range r.SubRuleList[i].ListenPorts {
|
|
p, e := base.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 := base.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) {
|
|
|
|
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
|
|
}
|
|
|
|
if strings.Contains(relayConfigArray[1], ",") { //均衡负载模式
|
|
if len(listenPorts) != 1 {
|
|
err = fmt.Errorf("均衡负载模式一条配置指定监听一个端口")
|
|
return
|
|
}
|
|
//targetAddressList :
|
|
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 *[]base.Proxy, proxyType, listenIP string, listenPort int) error {
|
|
proxyMap := make(map[string]base.Proxy)
|
|
for i, p := range *proxyList {
|
|
proxyMap[p.GetKey()] = (*proxyList)[i]
|
|
}
|
|
|
|
key := base.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
|
|
}
|