fix: ACL IP rules not working for domain requests if resolver not set

This commit is contained in:
Toby 2023-08-19 15:31:36 -07:00
parent acfb10efc0
commit a47285896a
2 changed files with 50 additions and 1 deletions

View file

@ -368,6 +368,7 @@ func (c *serverConfig) fillOutboundConfig(hyConfig *server.Config) error {
var uOb outbounds.PluggableOutbound // "unified" outbound
// ACL
hasACL := false
if c.ACL.File != "" && len(c.ACL.Inline) > 0 {
return configError{Field: "acl", Err: errors.New("cannot set both acl.file and acl.inline")}
}
@ -377,12 +378,14 @@ func (c *serverConfig) fillOutboundConfig(hyConfig *server.Config) error {
DownloadErrFunc: geoipDownloadErrFunc,
}
if c.ACL.File != "" {
hasACL = true
acl, err := outbounds.NewACLEngineFromFile(c.ACL.File, obs, gLoader.Load)
if err != nil {
return configError{Field: "acl.file", Err: err}
}
uOb = acl
} else if len(c.ACL.Inline) > 0 {
hasACL = true
acl, err := outbounds.NewACLEngineFromString(strings.Join(c.ACL.Inline, "\n"), obs, gLoader.Load)
if err != nil {
return configError{Field: "acl.inline", Err: err}
@ -396,7 +399,12 @@ func (c *serverConfig) fillOutboundConfig(hyConfig *server.Config) error {
// Resolver
switch strings.ToLower(c.Resolver.Type) {
case "", "system":
// Do nothing. DirectOutbound will use system resolver by default.
if hasACL {
// If the user uses ACL, we must put a resolver in front of it,
// for IP rules to work on domain requests.
uOb = outbounds.NewSystemResolver(uOb)
}
// Otherwise we can just rely on outbound handling on its own.
case "tcp":
if c.Resolver.TCP.Addr == "" {
return configError{Field: "resolver.tcp.addr", Err: errors.New("empty resolver address")}

View file

@ -0,0 +1,41 @@
package outbounds
import (
"net"
)
// systemResolver is a PluggableOutbound DNS resolver that resolves hostnames
// using the default system DNS server.
// Outbounds typically don't require a resolver, as they can do DNS resolution
// themselves. However, when using ACL, it's necessary to place a resolver in
// front of it in the pipeline (for IP rules to work on domain requests).
type systemResolver struct {
Next PluggableOutbound
}
func NewSystemResolver(next PluggableOutbound) PluggableOutbound {
return &systemResolver{
Next: next,
}
}
func (r *systemResolver) resolve(reqAddr *AddrEx) {
ips, err := net.LookupIP(reqAddr.Host)
if err != nil {
reqAddr.ResolveInfo = &ResolveInfo{Err: err}
return
}
info := &ResolveInfo{}
info.IPv4, info.IPv6 = splitIPv4IPv6(ips)
reqAddr.ResolveInfo = info
}
func (r *systemResolver) TCP(reqAddr *AddrEx) (net.Conn, error) {
r.resolve(reqAddr)
return r.Next.TCP(reqAddr)
}
func (r *systemResolver) UDP(reqAddr *AddrEx) (UDPConn, error) {
r.resolve(reqAddr)
return r.Next.UDP(reqAddr)
}