mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2024-11-16 19:56:51 +08:00
Fix: unexpected proxy dial behavior on mapping mode
This commit is contained in:
parent
237fc5f785
commit
a40706ba21
|
@ -62,7 +62,7 @@ type DNS struct {
|
||||||
Fallback []dns.NameServer `yaml:"fallback"`
|
Fallback []dns.NameServer `yaml:"fallback"`
|
||||||
FallbackFilter FallbackFilter `yaml:"fallback-filter"`
|
FallbackFilter FallbackFilter `yaml:"fallback-filter"`
|
||||||
Listen string `yaml:"listen"`
|
Listen string `yaml:"listen"`
|
||||||
EnhancedMode dns.EnhancedMode `yaml:"enhanced-mode"`
|
EnhancedMode C.DNSMode `yaml:"enhanced-mode"`
|
||||||
DefaultNameserver []dns.NameServer `yaml:"default-nameserver"`
|
DefaultNameserver []dns.NameServer `yaml:"default-nameserver"`
|
||||||
FakeIPRange *fakeip.Pool
|
FakeIPRange *fakeip.Pool
|
||||||
Hosts *trie.DomainTrie
|
Hosts *trie.DomainTrie
|
||||||
|
@ -107,7 +107,7 @@ type RawDNS struct {
|
||||||
Fallback []string `yaml:"fallback"`
|
Fallback []string `yaml:"fallback"`
|
||||||
FallbackFilter RawFallbackFilter `yaml:"fallback-filter"`
|
FallbackFilter RawFallbackFilter `yaml:"fallback-filter"`
|
||||||
Listen string `yaml:"listen"`
|
Listen string `yaml:"listen"`
|
||||||
EnhancedMode dns.EnhancedMode `yaml:"enhanced-mode"`
|
EnhancedMode C.DNSMode `yaml:"enhanced-mode"`
|
||||||
FakeIPRange string `yaml:"fake-ip-range"`
|
FakeIPRange string `yaml:"fake-ip-range"`
|
||||||
FakeIPFilter []string `yaml:"fake-ip-filter"`
|
FakeIPFilter []string `yaml:"fake-ip-filter"`
|
||||||
DefaultNameserver []string `yaml:"default-nameserver"`
|
DefaultNameserver []string `yaml:"default-nameserver"`
|
||||||
|
@ -584,7 +584,7 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie) (*DNS, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.EnhancedMode == dns.FAKEIP {
|
if cfg.EnhancedMode == C.DNSFakeIP {
|
||||||
_, ipnet, err := net.ParseCIDR(cfg.FakeIPRange)
|
_, ipnet, err := net.ParseCIDR(cfg.FakeIPRange)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
70
constant/dns.go
Normal file
70
constant/dns.go
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
package constant
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DNSModeMapping is a mapping for EnhancedMode enum
|
||||||
|
var DNSModeMapping = map[string]DNSMode{
|
||||||
|
DNSNormal.String(): DNSNormal,
|
||||||
|
DNSFakeIP.String(): DNSFakeIP,
|
||||||
|
DNSMapping.String(): DNSMapping,
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
DNSNormal DNSMode = iota
|
||||||
|
DNSFakeIP
|
||||||
|
DNSMapping
|
||||||
|
)
|
||||||
|
|
||||||
|
type DNSMode int
|
||||||
|
|
||||||
|
// UnmarshalYAML unserialize EnhancedMode with yaml
|
||||||
|
func (e *DNSMode) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||||
|
var tp string
|
||||||
|
if err := unmarshal(&tp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
mode, exist := DNSModeMapping[tp]
|
||||||
|
if !exist {
|
||||||
|
return errors.New("invalid mode")
|
||||||
|
}
|
||||||
|
*e = mode
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalYAML serialize EnhancedMode with yaml
|
||||||
|
func (e DNSMode) MarshalYAML() (interface{}, error) {
|
||||||
|
return e.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON unserialize EnhancedMode with json
|
||||||
|
func (e *DNSMode) UnmarshalJSON(data []byte) error {
|
||||||
|
var tp string
|
||||||
|
json.Unmarshal(data, &tp)
|
||||||
|
mode, exist := DNSModeMapping[tp]
|
||||||
|
if !exist {
|
||||||
|
return errors.New("invalid mode")
|
||||||
|
}
|
||||||
|
*e = mode
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON serialize EnhancedMode with json
|
||||||
|
func (e DNSMode) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(e.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e DNSMode) String() string {
|
||||||
|
switch e {
|
||||||
|
case DNSNormal:
|
||||||
|
return "normal"
|
||||||
|
case DNSFakeIP:
|
||||||
|
return "fake-ip"
|
||||||
|
case DNSMapping:
|
||||||
|
return "redir-host"
|
||||||
|
default:
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
}
|
|
@ -71,6 +71,7 @@ type Metadata struct {
|
||||||
DstPort string `json:"destinationPort"`
|
DstPort string `json:"destinationPort"`
|
||||||
AddrType int `json:"-"`
|
AddrType int `json:"-"`
|
||||||
Host string `json:"host"`
|
Host string `json:"host"`
|
||||||
|
DNSMode DNSMode `json:"dnsMode"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Metadata) RemoteAddress() string {
|
func (m *Metadata) RemoteAddress() string {
|
||||||
|
@ -85,6 +86,23 @@ func (m *Metadata) Resolved() bool {
|
||||||
return m.DstIP != nil
|
return m.DstIP != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pure is used to solve unexpected behavior
|
||||||
|
// when dialing proxy connection in DNSMapping mode.
|
||||||
|
func (m *Metadata) Pure() *Metadata {
|
||||||
|
if m.DNSMode == DNSMapping && m.DstIP != nil {
|
||||||
|
copy := *m
|
||||||
|
copy.Host = ""
|
||||||
|
if copy.DstIP.To4() != nil {
|
||||||
|
copy.AddrType = AtypIPv4
|
||||||
|
} else {
|
||||||
|
copy.AddrType = AtypIPv6
|
||||||
|
}
|
||||||
|
return ©
|
||||||
|
}
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Metadata) UDPAddr() *net.UDPAddr {
|
func (m *Metadata) UDPAddr() *net.UDPAddr {
|
||||||
if m.NetWork != UDP || m.DstIP == nil {
|
if m.NetWork != UDP || m.DstIP == nil {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -5,20 +5,21 @@ import (
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/common/cache"
|
"github.com/Dreamacro/clash/common/cache"
|
||||||
"github.com/Dreamacro/clash/component/fakeip"
|
"github.com/Dreamacro/clash/component/fakeip"
|
||||||
|
C "github.com/Dreamacro/clash/constant"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ResolverEnhancer struct {
|
type ResolverEnhancer struct {
|
||||||
mode EnhancedMode
|
mode C.DNSMode
|
||||||
fakePool *fakeip.Pool
|
fakePool *fakeip.Pool
|
||||||
mapping *cache.LruCache
|
mapping *cache.LruCache
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ResolverEnhancer) FakeIPEnabled() bool {
|
func (h *ResolverEnhancer) FakeIPEnabled() bool {
|
||||||
return h.mode == FAKEIP
|
return h.mode == C.DNSFakeIP
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ResolverEnhancer) MappingEnabled() bool {
|
func (h *ResolverEnhancer) MappingEnabled() bool {
|
||||||
return h.mode == FAKEIP || h.mode == MAPPING
|
return h.mode == C.DNSFakeIP || h.mode == C.DNSMapping
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ResolverEnhancer) IsExistFakeIP(ip net.IP) bool {
|
func (h *ResolverEnhancer) IsExistFakeIP(ip net.IP) bool {
|
||||||
|
@ -75,7 +76,7 @@ func NewEnhancer(cfg Config) *ResolverEnhancer {
|
||||||
var fakePool *fakeip.Pool
|
var fakePool *fakeip.Pool
|
||||||
var mapping *cache.LruCache
|
var mapping *cache.LruCache
|
||||||
|
|
||||||
if cfg.EnhancedMode != NORMAL {
|
if cfg.EnhancedMode != C.DNSNormal {
|
||||||
fakePool = cfg.Pool
|
fakePool = cfg.Pool
|
||||||
mapping = cache.NewLRUCache(cache.WithSize(4096), cache.WithStale(true))
|
mapping = cache.NewLRUCache(cache.WithSize(4096), cache.WithStale(true))
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/Dreamacro/clash/common/cache"
|
"github.com/Dreamacro/clash/common/cache"
|
||||||
"github.com/Dreamacro/clash/component/fakeip"
|
"github.com/Dreamacro/clash/component/fakeip"
|
||||||
"github.com/Dreamacro/clash/component/trie"
|
"github.com/Dreamacro/clash/component/trie"
|
||||||
|
C "github.com/Dreamacro/clash/constant"
|
||||||
"github.com/Dreamacro/clash/context"
|
"github.com/Dreamacro/clash/context"
|
||||||
"github.com/Dreamacro/clash/log"
|
"github.com/Dreamacro/clash/log"
|
||||||
|
|
||||||
|
@ -178,11 +179,11 @@ func newHandler(resolver *Resolver, mapper *ResolverEnhancer) handler {
|
||||||
middlewares = append(middlewares, withHosts(resolver.hosts))
|
middlewares = append(middlewares, withHosts(resolver.hosts))
|
||||||
}
|
}
|
||||||
|
|
||||||
if mapper.mode == FAKEIP {
|
if mapper.mode == C.DNSFakeIP {
|
||||||
middlewares = append(middlewares, withFakeIP(mapper.fakePool))
|
middlewares = append(middlewares, withFakeIP(mapper.fakePool))
|
||||||
}
|
}
|
||||||
|
|
||||||
if mapper.mode != NORMAL {
|
if mapper.mode != C.DNSNormal {
|
||||||
middlewares = append(middlewares, withMapping(mapper.mapping))
|
middlewares = append(middlewares, withMapping(mapper.mapping))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"github.com/Dreamacro/clash/component/fakeip"
|
"github.com/Dreamacro/clash/component/fakeip"
|
||||||
"github.com/Dreamacro/clash/component/resolver"
|
"github.com/Dreamacro/clash/component/resolver"
|
||||||
"github.com/Dreamacro/clash/component/trie"
|
"github.com/Dreamacro/clash/component/trie"
|
||||||
|
C "github.com/Dreamacro/clash/constant"
|
||||||
|
|
||||||
D "github.com/miekg/dns"
|
D "github.com/miekg/dns"
|
||||||
"golang.org/x/sync/singleflight"
|
"golang.org/x/sync/singleflight"
|
||||||
|
@ -317,7 +318,7 @@ type Config struct {
|
||||||
Main, Fallback []NameServer
|
Main, Fallback []NameServer
|
||||||
Default []NameServer
|
Default []NameServer
|
||||||
IPv6 bool
|
IPv6 bool
|
||||||
EnhancedMode EnhancedMode
|
EnhancedMode C.DNSMode
|
||||||
FallbackFilter FallbackFilter
|
FallbackFilter FallbackFilter
|
||||||
Pool *fakeip.Pool
|
Pool *fakeip.Pool
|
||||||
Hosts *trie.DomainTrie
|
Hosts *trie.DomainTrie
|
||||||
|
|
66
dns/util.go
66
dns/util.go
|
@ -2,8 +2,6 @@ package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -13,70 +11,6 @@ import (
|
||||||
D "github.com/miekg/dns"
|
D "github.com/miekg/dns"
|
||||||
)
|
)
|
||||||
|
|
||||||
// EnhancedModeMapping is a mapping for EnhancedMode enum
|
|
||||||
var EnhancedModeMapping = map[string]EnhancedMode{
|
|
||||||
NORMAL.String(): NORMAL,
|
|
||||||
FAKEIP.String(): FAKEIP,
|
|
||||||
MAPPING.String(): MAPPING,
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
NORMAL EnhancedMode = iota
|
|
||||||
FAKEIP
|
|
||||||
MAPPING
|
|
||||||
)
|
|
||||||
|
|
||||||
type EnhancedMode int
|
|
||||||
|
|
||||||
// UnmarshalYAML unserialize EnhancedMode with yaml
|
|
||||||
func (e *EnhancedMode) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
||||||
var tp string
|
|
||||||
if err := unmarshal(&tp); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
mode, exist := EnhancedModeMapping[tp]
|
|
||||||
if !exist {
|
|
||||||
return errors.New("invalid mode")
|
|
||||||
}
|
|
||||||
*e = mode
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarshalYAML serialize EnhancedMode with yaml
|
|
||||||
func (e EnhancedMode) MarshalYAML() (interface{}, error) {
|
|
||||||
return e.String(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalJSON unserialize EnhancedMode with json
|
|
||||||
func (e *EnhancedMode) UnmarshalJSON(data []byte) error {
|
|
||||||
var tp string
|
|
||||||
json.Unmarshal(data, &tp)
|
|
||||||
mode, exist := EnhancedModeMapping[tp]
|
|
||||||
if !exist {
|
|
||||||
return errors.New("invalid mode")
|
|
||||||
}
|
|
||||||
*e = mode
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarshalJSON serialize EnhancedMode with json
|
|
||||||
func (e EnhancedMode) MarshalJSON() ([]byte, error) {
|
|
||||||
return json.Marshal(e.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e EnhancedMode) String() string {
|
|
||||||
switch e {
|
|
||||||
case NORMAL:
|
|
||||||
return "normal"
|
|
||||||
case FAKEIP:
|
|
||||||
return "fake-ip"
|
|
||||||
case MAPPING:
|
|
||||||
return "redir-host"
|
|
||||||
default:
|
|
||||||
return "unknown"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func putMsgToCache(c *cache.LruCache, key string, msg *D.Msg) {
|
func putMsgToCache(c *cache.LruCache, key string, msg *D.Msg) {
|
||||||
var ttl uint32
|
var ttl uint32
|
||||||
switch {
|
switch {
|
||||||
|
|
|
@ -135,9 +135,11 @@ func preHandleMetadata(metadata *C.Metadata) error {
|
||||||
metadata.AddrType = C.AtypDomainName
|
metadata.AddrType = C.AtypDomainName
|
||||||
if resolver.FakeIPEnabled() {
|
if resolver.FakeIPEnabled() {
|
||||||
metadata.DstIP = nil
|
metadata.DstIP = nil
|
||||||
|
metadata.DNSMode = C.DNSFakeIP
|
||||||
} else if node := resolver.DefaultHosts.Search(host); node != nil {
|
} else if node := resolver.DefaultHosts.Search(host); node != nil {
|
||||||
// redir-host should lookup the hosts
|
// redir-host should lookup the hosts
|
||||||
metadata.DstIP = node.Data.(net.IP)
|
metadata.DstIP = node.Data.(net.IP)
|
||||||
|
metadata.DNSMode = C.DNSMapping
|
||||||
}
|
}
|
||||||
} else if resolver.IsFakeIP(metadata.DstIP) {
|
} else if resolver.IsFakeIP(metadata.DstIP) {
|
||||||
return fmt.Errorf("fake DNS record %s missing", metadata.DstIP)
|
return fmt.Errorf("fake DNS record %s missing", metadata.DstIP)
|
||||||
|
@ -219,7 +221,7 @@ func handleUDPConn(packet *inbound.PacketAdapter) {
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultUDPTimeout)
|
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultUDPTimeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
rawPc, err := proxy.ListenPacketContext(ctx, metadata)
|
rawPc, err := proxy.ListenPacketContext(ctx, metadata.Pure())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if rule == nil {
|
if rule == nil {
|
||||||
log.Warnln("[UDP] dial %s to %s error: %s", proxy.Name(), metadata.RemoteAddress(), err.Error())
|
log.Warnln("[UDP] dial %s to %s error: %s", proxy.Name(), metadata.RemoteAddress(), err.Error())
|
||||||
|
@ -271,7 +273,7 @@ func handleTCPConn(connCtx C.ConnContext) {
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTCPTimeout)
|
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTCPTimeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
remoteConn, err := proxy.DialContext(ctx, metadata)
|
remoteConn, err := proxy.DialContext(ctx, metadata.Pure())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if rule == nil {
|
if rule == nil {
|
||||||
log.Warnln("[TCP] dial %s to %s error: %s", proxy.Name(), metadata.RemoteAddress(), err.Error())
|
log.Warnln("[TCP] dial %s to %s error: %s", proxy.Name(), metadata.RemoteAddress(), err.Error())
|
||||||
|
|
Loading…
Reference in New Issue
Block a user