feat: server resolver config options

This commit is contained in:
Toby 2023-08-04 13:37:19 -07:00
parent be76f0650e
commit 7c94b072ed
5 changed files with 97 additions and 5 deletions

View File

@ -19,6 +19,7 @@ import (
"github.com/apernet/hysteria/core/server" "github.com/apernet/hysteria/core/server"
"github.com/apernet/hysteria/extras/auth" "github.com/apernet/hysteria/extras/auth"
"github.com/apernet/hysteria/extras/obfs" "github.com/apernet/hysteria/extras/obfs"
"github.com/apernet/hysteria/extras/outbounds"
) )
var serverCmd = &cobra.Command{ var serverCmd = &cobra.Command{
@ -41,6 +42,7 @@ type serverConfig struct {
DisableUDP bool `mapstructure:"disableUDP"` DisableUDP bool `mapstructure:"disableUDP"`
UDPIdleTimeout time.Duration `mapstructure:"udpIdleTimeout"` UDPIdleTimeout time.Duration `mapstructure:"udpIdleTimeout"`
Auth serverConfigAuth `mapstructure:"auth"` Auth serverConfigAuth `mapstructure:"auth"`
Resolver serverConfigResolver `mapstructure:"resolver"`
Masquerade serverConfigMasquerade `mapstructure:"masquerade"` Masquerade serverConfigMasquerade `mapstructure:"masquerade"`
} }
@ -89,6 +91,22 @@ type serverConfigAuth struct {
Password string `mapstructure:"password"` Password string `mapstructure:"password"`
} }
type serverConfigResolverTCP struct {
Addr string `mapstructure:"addr"`
Timeout time.Duration `mapstructure:"timeout"`
}
type serverConfigResolverUDP struct {
Addr string `mapstructure:"addr"`
Timeout time.Duration `mapstructure:"timeout"`
}
type serverConfigResolver struct {
Type string `mapstructure:"type"`
TCP serverConfigResolverTCP `mapstructure:"tcp"`
UDP serverConfigResolverUDP `mapstructure:"udp"`
}
type serverConfigMasqueradeFile struct { type serverConfigMasqueradeFile struct {
Dir string `mapstructure:"dir"` Dir string `mapstructure:"dir"`
} }
@ -214,6 +232,36 @@ func (c *serverConfig) fillQUICConfig(hyConfig *server.Config) error {
return nil return nil
} }
func (c *serverConfig) fillOutboundConfig(hyConfig *server.Config) error {
// Resolver, ACL, actual outbound are all implemented through the Outbound interface.
// Depending on the config, we build a chain like this:
// Resolver(ACL(Outbounds...))
// Outbounds
ob := outbounds.NewDirectOutboundSimple(outbounds.DirectOutboundModeAuto)
// Resolver
switch strings.ToLower(c.Resolver.Type) {
case "", "system":
// Do nothing. DirectOutbound will use system resolver by default.
case "tcp":
if c.Resolver.TCP.Addr == "" {
return configError{Field: "resolver.tcp.addr", Err: errors.New("empty resolver address")}
}
ob = outbounds.NewStandardResolverTCP(c.Resolver.TCP.Addr, c.Resolver.TCP.Timeout, ob)
case "udp":
if c.Resolver.UDP.Addr == "" {
return configError{Field: "resolver.udp.addr", Err: errors.New("empty resolver address")}
}
ob = outbounds.NewStandardResolverUDP(c.Resolver.UDP.Addr, c.Resolver.UDP.Timeout, ob)
default:
return configError{Field: "resolver.type", Err: errors.New("unsupported resolver type")}
}
hyConfig.Outbound = &outbounds.PluggableOutboundAdapter{PluggableOutbound: ob}
return nil
}
func (c *serverConfig) fillBandwidthConfig(hyConfig *server.Config) error { func (c *serverConfig) fillBandwidthConfig(hyConfig *server.Config) error {
var err error var err error
if c.Bandwidth.Up != "" { if c.Bandwidth.Up != "" {
@ -308,6 +356,7 @@ func (c *serverConfig) Config() (*server.Config, error) {
c.fillConn, c.fillConn,
c.fillTLSConfig, c.fillTLSConfig,
c.fillQUICConfig, c.fillQUICConfig,
c.fillOutboundConfig,
c.fillBandwidthConfig, c.fillBandwidthConfig,
c.fillDisableUDP, c.fillDisableUDP,
c.fillUDPIdleTimeout, c.fillUDPIdleTimeout,
@ -320,6 +369,7 @@ func (c *serverConfig) Config() (*server.Config, error) {
return nil, err return nil, err
} }
} }
return hyConfig, nil return hyConfig, nil
} }

View File

@ -61,6 +61,17 @@ func TestServerConfig(t *testing.T) {
Type: "password", Type: "password",
Password: "goofy_ahh_password", Password: "goofy_ahh_password",
}, },
Resolver: serverConfigResolver{
Type: "udp",
TCP: serverConfigResolverTCP{
Addr: "123.123.123.123:5353",
Timeout: 4 * time.Second,
},
UDP: serverConfigResolverUDP{
Addr: "4.6.8.0:53",
Timeout: 2 * time.Second,
},
},
Masquerade: serverConfigMasquerade{ Masquerade: serverConfigMasquerade{
Type: "proxy", Type: "proxy",
File: serverConfigMasqueradeFile{ File: serverConfigMasqueradeFile{

View File

@ -41,6 +41,15 @@ auth:
type: password type: password
password: goofy_ahh_password password: goofy_ahh_password
resolver:
type: udp
tcp:
addr: 123.123.123.123:5353
timeout: 4s
udp:
addr: 4.6.8.0:53
timeout: 2s
masquerade: masquerade:
type: proxy type: proxy
file: file:

View File

@ -40,6 +40,12 @@ auth:
type: password type: password
password: some_password password: some_password
# resolver:
# type: udp
# udp:
# addr: 8.8.4.4
# timeout: 2s
masquerade: masquerade:
type: proxy type: proxy
proxy: proxy:

View File

@ -8,6 +8,7 @@ import (
) )
const ( const (
standardResolverDefaultTimeout = 2 * time.Second
standardResolverRetryTimes = 2 standardResolverRetryTimes = 2
) )
@ -22,9 +23,9 @@ type standardResolver struct {
func NewStandardResolverUDP(addr string, timeout time.Duration, next PluggableOutbound) PluggableOutbound { func NewStandardResolverUDP(addr string, timeout time.Duration, next PluggableOutbound) PluggableOutbound {
return &standardResolver{ return &standardResolver{
Addr: addr, Addr: addDefaultPort(addr),
Client: &dns.Client{ Client: &dns.Client{
Timeout: timeout, Timeout: timeoutOrDefault(timeout),
}, },
Next: next, Next: next,
} }
@ -32,15 +33,30 @@ func NewStandardResolverUDP(addr string, timeout time.Duration, next PluggableOu
func NewStandardResolverTCP(addr string, timeout time.Duration, next PluggableOutbound) PluggableOutbound { func NewStandardResolverTCP(addr string, timeout time.Duration, next PluggableOutbound) PluggableOutbound {
return &standardResolver{ return &standardResolver{
Addr: addr, Addr: addDefaultPort(addr),
Client: &dns.Client{ Client: &dns.Client{
Net: "tcp", Net: "tcp",
Timeout: timeout, Timeout: timeoutOrDefault(timeout),
}, },
Next: next, Next: next,
} }
} }
// addDefaultPort adds the default DNS port (53) to the address if not present.
func addDefaultPort(addr string) string {
if _, _, err := net.SplitHostPort(addr); err != nil {
return net.JoinHostPort(addr, "53")
}
return addr
}
func timeoutOrDefault(timeout time.Duration) time.Duration {
if timeout == 0 {
return standardResolverDefaultTimeout
}
return timeout
}
// skipCNAMEChain skips the CNAME chain and returns the last CNAME target. // skipCNAMEChain skips the CNAME chain and returns the last CNAME target.
// Sometimes the DNS server returns a CNAME chain like this, in one packet: // Sometimes the DNS server returns a CNAME chain like this, in one packet:
// domain1.com. CNAME domain2.com. // domain1.com. CNAME domain2.com.