131 lines
4.2 KiB
Go

package singbox
import (
"strconv"
"github.com/perfect-panel/server/pkg/logger"
"github.com/perfect-panel/server/pkg/rules"
)
type Rule struct {
Outbound string `json:"outbound,omitempty"`
ClashMode string `json:"clash_mode,omitempty"`
RuleSet []string `json:"rule_set,omitempty"`
Domain []string `json:"domain,omitempty"`
DomainSuffix []string `json:"domain_suffix,omitempty"`
DomainKeyword []string `json:"domain_keyword,omitempty"`
DomainRegex []string `json:"domain_regex,omitempty"`
GeoIP []string `json:"geoip,omitempty"`
IPCIDR []string `json:"ip_cidr,omitempty"`
IPIsPrivate bool `json:"ip_is_private,omitempty"`
SourceIPCIDR []string `json:"source_ip_cidr,omitempty"`
ProcessName []string `json:"process_name,omitempty"`
ProcessPath []string `json:"process_path,omitempty"`
SourcePort []uint16 `json:"source_port,omitempty"`
Protocol []string `json:"protocol,omitempty"`
Port []uint16 `json:"port,omitempty"`
Action string `json:"action,omitempty"`
Inbound []string `json:"inbound,omitempty"`
Rules []Rule `json:"rules,omitempty"`
Type string `json:"type,omitempty"`
Mode string `json:"mode,omitempty"`
}
type RuleSet struct {
Tag string `json:"tag,omitempty"`
Type string `json:"type,omitempty"`
Format string `json:"format,omitempty"`
URL string `json:"url,omitempty"`
DownloadDetour string `json:"download_detour,omitempty"`
}
func adapterToSingboxRule(texts []string) []Rule {
var rulesList []Rule
for _, rule := range texts {
r := rules.NewRule(rule, "")
if r == nil {
continue
}
rulesList = addRuleToItem(rulesList, r.Target, *r)
}
return rulesList
}
func addRuleToItem(group []Rule, outbound string, rule rules.Rule) []Rule {
for i := range group {
if group[i].Outbound == outbound {
switch rules.ParseRuleType(rule.Type) {
case rules.Domain:
group[i].Domain = append(group[i].Domain, rule.Payload)
return group
case rules.DomainSuffix:
group[i].DomainSuffix = append(group[i].DomainSuffix, rule.Payload)
return group
case rules.DomainKeyword:
group[i].DomainKeyword = append(group[i].DomainKeyword, rule.Payload)
return group
case rules.IPCIDR:
group[i].IPCIDR = append(group[i].IPCIDR, rule.Payload)
return group
case rules.SrcIPCIDR:
group[i].SourceIPCIDR = append(group[i].SourceIPCIDR, rule.Payload)
return group
case rules.SrcPort:
port, err := strconv.ParseUint(rule.Payload, 10, 16)
if err != nil {
logger.Errorf("[adapterToSingboxRule] failed to parse port %s to uint16", rule.Payload)
return group
}
group[i].SourcePort = append(group[i].SourcePort, uint16(port))
return group
case rules.GEOIP:
group[i].GeoIP = append(group[i].GeoIP, rule.Payload)
return group
case rules.Process:
group[i].ProcessName = append(group[i].ProcessName, rule.Payload)
return group
case rules.ProcessPath:
group[i].ProcessPath = append(group[i].ProcessPath, rule.Payload)
return group
default:
logger.Errorf("[adapterToSingboxRule] unknown rule type %s", rule.Type)
return group
}
}
}
newRule := Rule{
Outbound: outbound,
}
switch rules.ParseRuleType(rule.Type) {
case rules.Domain:
newRule.Domain = []string{rule.Payload}
case rules.DomainSuffix:
newRule.DomainSuffix = []string{rule.Payload}
case rules.DomainKeyword:
newRule.DomainKeyword = []string{rule.Payload}
case rules.IPCIDR:
newRule.IPCIDR = []string{rule.Payload}
case rules.SrcIPCIDR:
newRule.SourceIPCIDR = []string{rule.Payload}
case rules.SrcPort:
port, err := strconv.ParseUint(rule.Payload, 10, 16)
if err != nil {
logger.Errorf("[adapterToSingboxRule] failed to parse port %s to uint16", rule.Payload)
return group
}
newRule.SourcePort = []uint16{uint16(port)}
case rules.GEOIP:
newRule.GeoIP = []string{rule.Payload}
case rules.Process:
newRule.ProcessName = []string{rule.Payload}
case rules.ProcessPath:
newRule.ProcessPath = []string{rule.Payload}
default:
logger.Errorf("[adapterToSingboxRule] unknown rule type %s", rule.Type)
return group
}
group = append(group, newRule)
return group
}