mirror of
https://github.com/ScuroNeko/mtg.git
synced 2026-08-31 09:44:03 +03:00
Propagate DNS setting to configuration
This commit is contained in:
+27
-14
@@ -134,8 +134,33 @@ allow-fallback-on-unknown-dc = false
|
||||
# it has to access.
|
||||
#
|
||||
# By default we use Cloudflare.
|
||||
#
|
||||
# DEPRECATED option:
|
||||
# If dns option is specified, it will be used instead
|
||||
doh-ip = "1.1.1.1"
|
||||
|
||||
# Starting from mtg v2.1.12 we have changed a configuration for DNS. Now it
|
||||
# supports DNS-over-HTTPS, DNS-over-TLS, custom UDP resolver and system
|
||||
# resolver.
|
||||
#
|
||||
# Here is how to define DNS-over-HTTPS:
|
||||
# - https://1.1.1.1
|
||||
# - https://1.1.1.1/dns-query
|
||||
# - https://cloudflare-dns.com/dns-query
|
||||
# - https://cloudflare-dns.com
|
||||
#
|
||||
# Here is how to define DNS-over-TLS:
|
||||
# - tls://1.1.1.1
|
||||
# - tls://cloudflare-dns.com
|
||||
#
|
||||
# Here is how to define a custom UDP resolver (we support only IPs here)
|
||||
# - 1.1.1.1
|
||||
# - udp://1.1.1.1
|
||||
#
|
||||
# If you set it to empty string, default resolver will be used.
|
||||
# But please comment out doh-ip
|
||||
dns = "https://1.1.1.1"
|
||||
|
||||
# mtg can work via proxies (for now, we support only socks5). Proxy
|
||||
# configuration is done via list. So, you can specify many proxies
|
||||
# there.
|
||||
@@ -149,25 +174,13 @@ doh-ip = "1.1.1.1"
|
||||
#
|
||||
# Proxy configuration is done via ordinary URI schema:
|
||||
#
|
||||
# socks5://user:password@host:port?open_threshold=5&half_open_timeout=1m&reset_failures_timeout=10s
|
||||
# socks5://user:password@host:port
|
||||
#
|
||||
# Only socks5 proxy is used. user/password is optional. As you can
|
||||
# see, you can specify some parameters in GET query. These parameters
|
||||
# configure circuit breaker.
|
||||
#
|
||||
# open_threshold means a number of errors which should happen so we stop
|
||||
# use a proxy.
|
||||
#
|
||||
# half_open_timeout means a time period (in Golang duration notation)
|
||||
# after which we can retry with this proxy
|
||||
#
|
||||
# reset_failures_timeout means a time period when we flush out errors
|
||||
# when circuit breaker in closed state.
|
||||
#
|
||||
# Please see https://docs.microsoft.com/en-us/azure/architecture/patterns/circuit-breaker
|
||||
# on details about circuit breakers.
|
||||
proxies = [
|
||||
# "socks5://user:password@host:port?open_threshold=5&half_open_timeout=1m&reset_failures_timeout=10s"
|
||||
# "socks5://user:password@host:port"
|
||||
]
|
||||
|
||||
# network timeouts define different settings for timeouts. tcp timeout
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
|
||||
"github.com/9seconds/mtg/v2/mtglib"
|
||||
)
|
||||
@@ -56,6 +57,7 @@ type Config struct {
|
||||
Idle TypeDuration `json:"idle"`
|
||||
} `json:"timeout"`
|
||||
DOHIP TypeIP `json:"dohIp"`
|
||||
DNS TypeDNSURI `json:"dns"`
|
||||
Proxies []TypeProxyURL `json:"proxies"`
|
||||
} `json:"network"`
|
||||
Stats struct {
|
||||
@@ -76,6 +78,16 @@ type Config struct {
|
||||
} `json:"stats"`
|
||||
}
|
||||
|
||||
func (c *Config) GetDNS() *url.URL {
|
||||
var dohURL *url.URL
|
||||
|
||||
if dohIP := c.Network.DOHIP.Get(nil); dohIP != nil {
|
||||
dohURL, _ = url.Parse("https://" + dohIP.String())
|
||||
}
|
||||
|
||||
return c.Network.DNS.Get(dohURL)
|
||||
}
|
||||
|
||||
func (c *Config) GetDomainFrontingPort(defaultValue uint) uint {
|
||||
if port := c.DomainFronting.Port.Get(0); port != 0 {
|
||||
return port
|
||||
|
||||
@@ -52,6 +52,7 @@ type tomlConfig struct {
|
||||
Idle string `toml:"idle" json:"idle,omitempty"`
|
||||
} `toml:"timeout" json:"timeout,omitempty"`
|
||||
DOHIP string `toml:"doh-ip" json:"dohIp,omitempty"`
|
||||
DNS string `toml:"dns" json:"dns,omitempty"`
|
||||
Proxies []string `toml:"proxies" json:"proxies,omitempty"`
|
||||
} `toml:"network" json:"network,omitempty"`
|
||||
Stats struct {
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type TypeDNSURI struct {
|
||||
Value *url.URL
|
||||
}
|
||||
|
||||
func (t *TypeDNSURI) Set(value string) error {
|
||||
parsed, err := url.Parse(value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("value is not URI: %w", err)
|
||||
}
|
||||
|
||||
if parsed.Host == "" {
|
||||
parsed.Host = parsed.Path
|
||||
parsed.Path = ""
|
||||
parsed.Scheme = "udp"
|
||||
}
|
||||
|
||||
switch parsed.Scheme {
|
||||
case "https", "tls":
|
||||
case "udp":
|
||||
if ip := net.ParseIP(parsed.Hostname()); ip == nil {
|
||||
return fmt.Errorf("simple DNS must IP address: %s", parsed.Hostname())
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unsupported DNS type %s", parsed.Scheme)
|
||||
}
|
||||
|
||||
if parsed.Scheme != "https" && parsed.Path != "" {
|
||||
return fmt.Errorf("path is supported only for DoH: %s", parsed)
|
||||
}
|
||||
|
||||
if parsed.User != nil {
|
||||
return fmt.Errorf("used info is not supported: %s", parsed.User.String())
|
||||
}
|
||||
|
||||
t.Value = parsed
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *TypeDNSURI) Get(defaultValue *url.URL) *url.URL {
|
||||
if t.Value != nil {
|
||||
return t.Value
|
||||
}
|
||||
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
func (t *TypeDNSURI) UnmarshalText(data []byte) error {
|
||||
return t.Set(string(data))
|
||||
}
|
||||
|
||||
func (t TypeDNSURI) MarshalText() ([]byte, error) {
|
||||
return []byte(t.String()), nil
|
||||
}
|
||||
|
||||
func (t TypeDNSURI) String() string {
|
||||
if t.Value == nil {
|
||||
return ""
|
||||
}
|
||||
return t.Value.String()
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package config_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/9seconds/mtg/v2/internal/config"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
type typeDNSURITestStruct struct {
|
||||
Value config.TypeDNSURI `json:"value"`
|
||||
}
|
||||
|
||||
type TypeDNSURITestSuite struct {
|
||||
suite.Suite
|
||||
}
|
||||
|
||||
func (suite *TypeDNSURITestSuite) TestUnmarshalFail() {
|
||||
testData := []string{
|
||||
"xx",
|
||||
"ppar",
|
||||
"",
|
||||
"dns://hahaha",
|
||||
"udp://xcxxcv",
|
||||
"udp://1.1.1.1/xcv",
|
||||
"1.1.1.1/xxx",
|
||||
"tls://dns/xx",
|
||||
"tls://1.1.1.1/xx",
|
||||
"https://user:password@1.1.1.1",
|
||||
"tls://user:password@1.1.1.1",
|
||||
"udp://user:password@1.1.1.1",
|
||||
}
|
||||
|
||||
for _, v := range testData {
|
||||
data, err := json.Marshal(map[string]string{
|
||||
"value": v,
|
||||
})
|
||||
suite.NoError(err)
|
||||
|
||||
suite.T().Run(v, func(t *testing.T) {
|
||||
assert.Error(t, json.Unmarshal(data, &typeDNSURITestStruct{}))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *TypeDNSURITestSuite) TestUnmarshalOk() {
|
||||
testData := []string{
|
||||
"1.1.1.1",
|
||||
"tls://1.1.1.1",
|
||||
"tls://dns.google",
|
||||
"https://1.1.1.1",
|
||||
"https://1.1.1.1/dns-query",
|
||||
"https://dns.google",
|
||||
"https://dns.google/dns-query",
|
||||
"udp://1.1.1.1",
|
||||
}
|
||||
|
||||
for _, v := range testData {
|
||||
data, err := json.Marshal(map[string]string{
|
||||
"value": v,
|
||||
})
|
||||
suite.NoError(err)
|
||||
|
||||
suite.T().Run(v, func(t *testing.T) {
|
||||
testStruct := &typeDNSURITestStruct{}
|
||||
assert.NoError(t, json.Unmarshal(data, testStruct))
|
||||
if v == "1.1.1.1" {
|
||||
v = "udp://" + v
|
||||
}
|
||||
assert.Equal(t, v, testStruct.Value.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *TypeDNSURITestSuite) TestMarshalOk() {
|
||||
testData := []string{
|
||||
"tls://1.1.1.1",
|
||||
"tls://dns.google",
|
||||
"https://1.1.1.1",
|
||||
"https://1.1.1.1/dns-query",
|
||||
}
|
||||
|
||||
for _, v := range testData {
|
||||
suite.T().Run(v, func(t *testing.T) {
|
||||
testStruct := &typePreferIPTestStruct{
|
||||
Value: config.TypePreferIP{
|
||||
Value: v,
|
||||
},
|
||||
}
|
||||
|
||||
encodedJSON, err := json.Marshal(testStruct)
|
||||
assert.NoError(t, err)
|
||||
|
||||
expectedJSON, err := json.Marshal(map[string]string{
|
||||
"value": v,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.JSONEq(t, string(expectedJSON), string(encodedJSON))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *TypeDNSURITestSuite) TestGet() {
|
||||
value := config.TypeDNSURI{}
|
||||
suite.Nil(value.Get(nil))
|
||||
|
||||
suite.NoError(value.Set("tls://1.1.1.1"))
|
||||
suite.NotNil(value.Get(nil))
|
||||
}
|
||||
|
||||
func TestDNSURI(t *testing.T) {
|
||||
t.Parallel()
|
||||
suite.Run(t, &TypeDNSURITestSuite{})
|
||||
}
|
||||
@@ -21,6 +21,14 @@ func GetDNS(u *url.URL) (*net.Resolver, error) {
|
||||
return dns.NewCachingResolver(nil, dnsCacheOptions...), nil
|
||||
}
|
||||
|
||||
if u.Scheme == "" {
|
||||
u.Scheme = "udp"
|
||||
}
|
||||
if u.Scheme == "udp" && u.Host == "" {
|
||||
u.Host = u.Path
|
||||
u.Path = ""
|
||||
}
|
||||
|
||||
switch u.Scheme {
|
||||
case "tls":
|
||||
return dns.NewDoTResolver(u.Host, dns.DoTCache(dnsCacheOptions...))
|
||||
|
||||
Reference in New Issue
Block a user