v2fly/tools/conf/router.go

238 lines
5.9 KiB
Go

package conf
import (
"encoding/json"
"strconv"
"strings"
"v2ray.com/core/app/log"
"v2ray.com/core/app/router"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/tools/geoip"
"github.com/golang/protobuf/proto"
)
type RouterRulesConfig struct {
RuleList []json.RawMessage `json:"rules"`
DomainStrategy string `json:"domainStrategy"`
}
type RouterConfig struct {
Settings *RouterRulesConfig `json:"settings"`
}
func (v *RouterConfig) Build() (*router.Config, error) {
if v.Settings == nil {
return nil, newError("Config: Router settings is not specified.")
}
config := new(router.Config)
settings := v.Settings
config.DomainStrategy = router.Config_AsIs
config.Rule = make([]*router.RoutingRule, len(settings.RuleList))
domainStrategy := strings.ToLower(settings.DomainStrategy)
if domainStrategy == "alwaysip" {
config.DomainStrategy = router.Config_UseIp
} else if domainStrategy == "ipifnonmatch" {
config.DomainStrategy = router.Config_IpIfNonMatch
}
for idx, rawRule := range settings.RuleList {
rule, err := ParseRule(rawRule)
if err != nil {
return nil, err
}
config.Rule[idx] = rule
}
return config, nil
}
type RouterRule struct {
Type string `json:"type"`
OutboundTag string `json:"outboundTag"`
}
func parseIP(s string) (*router.CIDR, error) {
var addr, mask string
i := strings.Index(s, "/")
if i < 0 {
addr = s
} else {
addr = s[:i]
mask = s[i+1:]
}
ip := v2net.ParseAddress(addr)
switch ip.Family() {
case v2net.AddressFamilyIPv4:
bits := uint32(32)
if len(mask) > 0 {
bits64, err := strconv.ParseUint(mask, 10, 32)
if err != nil {
return nil, newError("Config: invalid network mask for router: ", mask).Base(err)
}
bits = uint32(bits64)
}
if bits > 32 {
return nil, newError("Config: invalid network mask for router: ", bits)
}
return &router.CIDR{
Ip: []byte(ip.IP()),
Prefix: bits,
}, nil
case v2net.AddressFamilyIPv6:
bits := uint32(128)
if len(mask) > 0 {
bits64, err := strconv.ParseUint(mask, 10, 32)
if err != nil {
return nil, newError("Config: invalid network mask for router: ", mask).Base(err)
}
bits = uint32(bits64)
}
if bits > 128 {
return nil, newError("Config: invalid network mask for router: ", bits)
}
return &router.CIDR{
Ip: []byte(ip.IP()),
Prefix: bits,
}, nil
default:
return nil, newError("Config: unsupported address for router: ", s)
}
}
func parseFieldRule(msg json.RawMessage) (*router.RoutingRule, error) {
type RawFieldRule struct {
RouterRule
Domain *StringList `json:"domain"`
IP *StringList `json:"ip"`
Port *PortRange `json:"port"`
Network *NetworkList `json:"network"`
SourceIP *StringList `json:"source"`
User *StringList `json:"user"`
InboundTag *StringList `json:"inboundTag"`
}
rawFieldRule := new(RawFieldRule)
err := json.Unmarshal(msg, rawFieldRule)
if err != nil {
return nil, err
}
rule := new(router.RoutingRule)
rule.Tag = rawFieldRule.OutboundTag
if rawFieldRule.Domain != nil {
for _, domain := range *rawFieldRule.Domain {
domainRule := new(router.Domain)
if strings.HasPrefix(domain, "regexp:") {
domainRule.Type = router.Domain_Regex
domainRule.Value = domain[7:]
} else {
domainRule.Type = router.Domain_Plain
domainRule.Value = domain
}
rule.Domain = append(rule.Domain, domainRule)
}
}
if rawFieldRule.IP != nil {
for _, ip := range *rawFieldRule.IP {
ipRule, err := parseIP(ip)
if err != nil {
return nil, newError("Config: invalid IP: ", ip).Base(err)
}
rule.Cidr = append(rule.Cidr, ipRule)
}
}
if rawFieldRule.Port != nil {
rule.PortRange = rawFieldRule.Port.Build()
}
if rawFieldRule.Network != nil {
rule.NetworkList = rawFieldRule.Network.Build()
}
if rawFieldRule.SourceIP != nil {
for _, ip := range *rawFieldRule.SourceIP {
ipRule, err := parseIP(ip)
if err != nil {
return nil, newError("Config: invalid IP: ", ip).Base(err)
}
rule.SourceCidr = append(rule.SourceCidr, ipRule)
}
}
if rawFieldRule.User != nil {
for _, s := range *rawFieldRule.User {
rule.UserEmail = append(rule.UserEmail, s)
}
}
if rawFieldRule.InboundTag != nil {
for _, s := range *rawFieldRule.InboundTag {
rule.InboundTag = append(rule.InboundTag, s)
}
}
return rule, nil
}
func ParseRule(msg json.RawMessage) (*router.RoutingRule, error) {
rawRule := new(RouterRule)
err := json.Unmarshal(msg, rawRule)
if err != nil {
return nil, newError("Config: Invalid router rule.").Base(err)
}
if rawRule.Type == "field" {
fieldrule, err := parseFieldRule(msg)
if err != nil {
return nil, newError("Config: Invalid field rule.").Base(err)
}
return fieldrule, nil
}
if rawRule.Type == "chinaip" {
chinaiprule, err := parseChinaIPRule(msg)
if err != nil {
return nil, newError("Config: Invalid chinaip rule.").Base(err)
}
return chinaiprule, nil
}
if rawRule.Type == "chinasites" {
chinasitesrule, err := parseChinaSitesRule(msg)
if err != nil {
return nil, newError("Config: Invalid chinasites rule.").Base(err)
}
return chinasitesrule, nil
}
return nil, newError("Config: Unknown router rule type: ", rawRule.Type)
}
func parseChinaIPRule(data []byte) (*router.RoutingRule, error) {
rawRule := new(RouterRule)
err := json.Unmarshal(data, rawRule)
if err != nil {
return nil, newError("Config: Invalid router rule.").Base(err)
}
var chinaIPs geoip.CountryIPRange
if err := proto.Unmarshal(geoip.ChinaIPs, &chinaIPs); err != nil {
return nil, newError("Config: Invalid china ips.").Base(err)
}
return &router.RoutingRule{
Tag: rawRule.OutboundTag,
Cidr: chinaIPs.Ips,
}, nil
}
func parseChinaSitesRule(data []byte) (*router.RoutingRule, error) {
rawRule := new(RouterRule)
err := json.Unmarshal(data, rawRule)
if err != nil {
log.Trace(newError("Router: Invalid router rule: ", err).AtError())
return nil, err
}
return &router.RoutingRule{
Tag: rawRule.OutboundTag,
Domain: chinaSitesDomains,
}, nil
}