mirror of
https://github.com/ScuroNeko/mtg.git
synced 2026-08-31 10:34:01 +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.
|
# it has to access.
|
||||||
#
|
#
|
||||||
# By default we use Cloudflare.
|
# By default we use Cloudflare.
|
||||||
|
#
|
||||||
|
# DEPRECATED option:
|
||||||
|
# If dns option is specified, it will be used instead
|
||||||
doh-ip = "1.1.1.1"
|
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
|
# mtg can work via proxies (for now, we support only socks5). Proxy
|
||||||
# configuration is done via list. So, you can specify many proxies
|
# configuration is done via list. So, you can specify many proxies
|
||||||
# there.
|
# there.
|
||||||
@@ -149,25 +174,13 @@ doh-ip = "1.1.1.1"
|
|||||||
#
|
#
|
||||||
# Proxy configuration is done via ordinary URI schema:
|
# 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
|
# Only socks5 proxy is used. user/password is optional. As you can
|
||||||
# see, you can specify some parameters in GET query. These parameters
|
# see, you can specify some parameters in GET query. These parameters
|
||||||
# configure circuit breaker.
|
# 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 = [
|
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
|
# network timeouts define different settings for timeouts. tcp timeout
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
"github.com/9seconds/mtg/v2/mtglib"
|
"github.com/9seconds/mtg/v2/mtglib"
|
||||||
)
|
)
|
||||||
@@ -56,6 +57,7 @@ type Config struct {
|
|||||||
Idle TypeDuration `json:"idle"`
|
Idle TypeDuration `json:"idle"`
|
||||||
} `json:"timeout"`
|
} `json:"timeout"`
|
||||||
DOHIP TypeIP `json:"dohIp"`
|
DOHIP TypeIP `json:"dohIp"`
|
||||||
|
DNS TypeDNSURI `json:"dns"`
|
||||||
Proxies []TypeProxyURL `json:"proxies"`
|
Proxies []TypeProxyURL `json:"proxies"`
|
||||||
} `json:"network"`
|
} `json:"network"`
|
||||||
Stats struct {
|
Stats struct {
|
||||||
@@ -76,6 +78,16 @@ type Config struct {
|
|||||||
} `json:"stats"`
|
} `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 {
|
func (c *Config) GetDomainFrontingPort(defaultValue uint) uint {
|
||||||
if port := c.DomainFronting.Port.Get(0); port != 0 {
|
if port := c.DomainFronting.Port.Get(0); port != 0 {
|
||||||
return port
|
return port
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ type tomlConfig struct {
|
|||||||
Idle string `toml:"idle" json:"idle,omitempty"`
|
Idle string `toml:"idle" json:"idle,omitempty"`
|
||||||
} `toml:"timeout" json:"timeout,omitempty"`
|
} `toml:"timeout" json:"timeout,omitempty"`
|
||||||
DOHIP string `toml:"doh-ip" json:"dohIp,omitempty"`
|
DOHIP string `toml:"doh-ip" json:"dohIp,omitempty"`
|
||||||
|
DNS string `toml:"dns" json:"dns,omitempty"`
|
||||||
Proxies []string `toml:"proxies" json:"proxies,omitempty"`
|
Proxies []string `toml:"proxies" json:"proxies,omitempty"`
|
||||||
} `toml:"network" json:"network,omitempty"`
|
} `toml:"network" json:"network,omitempty"`
|
||||||
Stats struct {
|
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
|
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 {
|
switch u.Scheme {
|
||||||
case "tls":
|
case "tls":
|
||||||
return dns.NewDoTResolver(u.Host, dns.DoTCache(dnsCacheOptions...))
|
return dns.NewDoTResolver(u.Host, dns.DoTCache(dnsCacheOptions...))
|
||||||
|
|||||||
Reference in New Issue
Block a user