mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-05-08 14:13:22 +00:00
https://github.com/XTLS/Xray-core/pull/5981#issuecomment-4279809648 Example: https://github.com/XTLS/Xray-core/pull/5981#issuecomment-4283200236 Closes https://github.com/XTLS/Xray-core/issues/5218
156 lines
3.8 KiB
Go
156 lines
3.8 KiB
Go
package conf
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/xtls/xray-core/common/errors"
|
|
"github.com/xtls/xray-core/common/geodata"
|
|
"github.com/xtls/xray-core/common/net"
|
|
"github.com/xtls/xray-core/proxy/dns"
|
|
"google.golang.org/protobuf/proto"
|
|
)
|
|
|
|
type DNSOutboundRuleConfig struct {
|
|
Action string `json:"action"`
|
|
QType *PortList `json:"qtype"`
|
|
Domain *StringList `json:"domain"`
|
|
}
|
|
|
|
func (c *DNSOutboundRuleConfig) Build() (*dns.DNSRuleConfig, error) {
|
|
rule := &dns.DNSRuleConfig{}
|
|
|
|
switch strings.ToLower(c.Action) {
|
|
case "direct":
|
|
rule.Action = dns.RuleAction_Direct
|
|
case "drop":
|
|
rule.Action = dns.RuleAction_Drop
|
|
case "reject":
|
|
rule.Action = dns.RuleAction_Reject
|
|
case "hijack":
|
|
rule.Action = dns.RuleAction_Hijack
|
|
default:
|
|
return nil, errors.New("unknown action: ", c.Action)
|
|
}
|
|
|
|
if c.QType != nil {
|
|
for _, r := range c.QType.Range {
|
|
if r.From > r.To {
|
|
return nil, errors.New("invalid qtype range: ", r.String())
|
|
}
|
|
if r.To > 65535 {
|
|
return nil, errors.New("dns rule qtype out of range: ", r.String())
|
|
}
|
|
for qtype := r.From; qtype <= r.To; qtype++ {
|
|
rule.Qtype = append(rule.Qtype, int32(qtype))
|
|
}
|
|
}
|
|
}
|
|
|
|
if c.Domain != nil {
|
|
rules, err := geodata.ParseDomainRules(*c.Domain, geodata.Domain_Substr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
rule.Domain = rules
|
|
}
|
|
|
|
return rule, nil
|
|
}
|
|
|
|
type DNSOutboundConfig struct {
|
|
Network Network `json:"network"`
|
|
Address *Address `json:"address"`
|
|
Port uint16 `json:"port"`
|
|
UserLevel uint32 `json:"userLevel"`
|
|
Rules []*DNSOutboundRuleConfig `json:"rules"`
|
|
NonIPQuery *string `json:"nonIPQuery"` // todo: remove legacy
|
|
BlockTypes *[]int32 `json:"blockTypes"` // todo: remove legacy
|
|
}
|
|
|
|
func (c *DNSOutboundConfig) Build() (proto.Message, error) {
|
|
config := &dns.Config{
|
|
Server: &net.Endpoint{
|
|
Network: c.Network.Build(),
|
|
Port: uint32(c.Port),
|
|
},
|
|
UserLevel: c.UserLevel,
|
|
}
|
|
if c.Address != nil {
|
|
config.Server.Address = c.Address.Build()
|
|
}
|
|
|
|
// todo: remove legacy
|
|
if c.NonIPQuery != nil || c.BlockTypes != nil {
|
|
if c.Rules != nil {
|
|
return nil, errors.New("legacy nonIPQuery and blockTypes cannot be mixed with rules")
|
|
}
|
|
errors.PrintDeprecatedFeatureWarning(`"nonIPQuery" and "blockTypes" in DNS outbound`, `"rules"`)
|
|
rules, err := c.buildLegacyDNSPolicy()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
config.Rule = rules
|
|
return config, nil
|
|
}
|
|
|
|
for _, r := range c.Rules {
|
|
rule, err := r.Build()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
config.Rule = append(config.Rule, rule)
|
|
}
|
|
|
|
return config, nil
|
|
}
|
|
|
|
// todo: remove legacy
|
|
func (c *DNSOutboundConfig) buildLegacyDNSPolicy() ([]*dns.DNSRuleConfig, error) {
|
|
rules := make([]*dns.DNSRuleConfig, 0, 3)
|
|
|
|
mode := "reject"
|
|
if c.NonIPQuery != nil && *c.NonIPQuery != "" {
|
|
mode = *c.NonIPQuery
|
|
}
|
|
switch mode {
|
|
case "", "reject", "drop", "skip":
|
|
default:
|
|
return nil, errors.New("unknown nonIPQuery: ", mode)
|
|
}
|
|
|
|
if c.BlockTypes != nil && len(*c.BlockTypes) > 0 {
|
|
rule := &dns.DNSRuleConfig{Action: dns.RuleAction_Drop}
|
|
if mode == "reject" {
|
|
rule.Action = dns.RuleAction_Reject
|
|
}
|
|
for _, qtype := range *c.BlockTypes {
|
|
if qtype < 0 || qtype > 65535 {
|
|
return nil, errors.New("legacy blockTypes qtype out of range: ", qtype)
|
|
}
|
|
rule.Qtype = append(rule.Qtype, qtype)
|
|
}
|
|
rules = append(rules, rule)
|
|
}
|
|
|
|
{
|
|
rule := &dns.DNSRuleConfig{Action: dns.RuleAction_Hijack}
|
|
rule.Qtype = append(rule.Qtype, 1)
|
|
rule.Qtype = append(rule.Qtype, 28)
|
|
rules = append(rules, rule)
|
|
}
|
|
|
|
{
|
|
rule := &dns.DNSRuleConfig{Action: dns.RuleAction_Reject}
|
|
if mode == "reject" {
|
|
rule.Action = dns.RuleAction_Reject
|
|
} else if mode == "drop" {
|
|
rule.Action = dns.RuleAction_Drop
|
|
} else if mode == "skip" {
|
|
rule.Action = dns.RuleAction_Direct
|
|
}
|
|
rules = append(rules, rule)
|
|
}
|
|
|
|
return rules, nil
|
|
}
|