Merge from remote branch

This commit is contained in:
yaling888
2021-10-28 11:36:11 +08:00
86 changed files with 1065 additions and 461 deletions

View File

@ -15,9 +15,10 @@ import (
type client struct {
*D.Client
r *Resolver
port string
host string
r *Resolver
port string
host string
iface string
}
func (c *client) Exchange(m *D.Msg) (*D.Msg, error) {
@ -45,7 +46,11 @@ func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error)
network = "tcp"
}
conn, err := dialer.DialContext(ctx, network, net.JoinHostPort(ip.String(), c.port))
options := []dialer.Option{}
if c.iface != "" {
options = append(options, dialer.WithInterface(c.iface))
}
conn, err := dialer.DialContext(ctx, network, net.JoinHostPort(ip.String(), c.port), options...)
if err != nil {
return nil, err
}

View File

@ -68,8 +68,11 @@ func (d *dhcpClient) resolve(ctx context.Context) (*Resolver, error) {
dns, err := dhcp.ResolveDNSFromDHCP(ctx, d.ifaceName)
if err == nil {
nameserver := make([]NameServer, 0, len(dns))
for _, d := range dns {
nameserver = append(nameserver, NameServer{Addr: net.JoinHostPort(d.String(), "53")})
for _, item := range dns {
nameserver = append(nameserver, NameServer{
Addr: net.JoinHostPort(item.String(), "53"),
Interface: d.ifaceName,
})
}
res = NewResolver(Config{

View File

@ -3,7 +3,7 @@ package dns
import (
"bytes"
"context"
"io/ioutil"
"io"
"net"
"net/http"
@ -28,13 +28,21 @@ func (dc *dohClient) Exchange(m *D.Msg) (msg *D.Msg, err error) {
}
func (dc *dohClient) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) {
req, err := dc.newRequest(m)
// https://datatracker.ietf.org/doc/html/rfc8484#section-4.1
// In order to maximize cache friendliness, SHOULD use a DNS ID of 0 in every DNS request.
newM := *m
newM.Id = 0
req, err := dc.newRequest(&newM)
if err != nil {
return nil, err
}
req = req.WithContext(ctx)
return dc.doRequest(req)
msg, err = dc.doRequest(req)
if err == nil {
msg.Id = m.Id
}
return
}
// newRequest returns a new DoH request given a dns.Msg.
@ -62,7 +70,7 @@ func (dc *dohClient) doRequest(req *http.Request) (msg *D.Msg, err error) {
}
defer resp.Body.Close()
buf, err := ioutil.ReadAll(resp.Body)
buf, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}

View File

@ -5,20 +5,21 @@ import (
"github.com/Dreamacro/clash/common/cache"
"github.com/Dreamacro/clash/component/fakeip"
C "github.com/Dreamacro/clash/constant"
)
type ResolverEnhancer struct {
mode EnhancedMode
mode C.DNSMode
fakePool *fakeip.Pool
mapping *cache.LruCache
}
func (h *ResolverEnhancer) FakeIPEnabled() bool {
return h.mode == FAKEIP
return h.mode == C.DNSFakeIP
}
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 {
@ -67,7 +68,7 @@ func (h *ResolverEnhancer) PatchFrom(o *ResolverEnhancer) {
}
if h.fakePool != nil && o.fakePool != nil {
h.fakePool.PatchFrom(o.fakePool)
h.fakePool.CloneFrom(o.fakePool)
}
}
@ -75,7 +76,7 @@ func NewEnhancer(cfg Config) *ResolverEnhancer {
var fakePool *fakeip.Pool
var mapping *cache.LruCache
if cfg.EnhancedMode != NORMAL {
if cfg.EnhancedMode != C.DNSNormal {
fakePool = cfg.Pool
mapping = cache.NewLRUCache(cache.WithSize(4096), cache.WithStale(true))
}

View File

@ -8,14 +8,17 @@ import (
"github.com/Dreamacro/clash/common/cache"
"github.com/Dreamacro/clash/component/fakeip"
"github.com/Dreamacro/clash/component/trie"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/context"
"github.com/Dreamacro/clash/log"
D "github.com/miekg/dns"
)
type handler func(ctx *context.DNSContext, r *D.Msg) (*D.Msg, error)
type middleware func(next handler) handler
type (
handler func(ctx *context.DNSContext, r *D.Msg) (*D.Msg, error)
middleware func(next handler) handler
)
func withHosts(hosts *trie.DomainTrie) middleware {
return func(next handler) handler {
@ -105,7 +108,7 @@ func withFakeIP(fakePool *fakeip.Pool) middleware {
q := r.Question[0]
host := strings.TrimRight(q.Name, ".")
if fakePool.LookupHost(host) {
if fakePool.ShouldSkipped(host) {
return next(ctx, r)
}
@ -176,11 +179,11 @@ func NewHandler(resolver *Resolver, mapper *ResolverEnhancer) handler {
middlewares = append(middlewares, withHosts(resolver.hosts))
}
if mapper.mode == FAKEIP {
if mapper.mode == C.DNSFakeIP {
middlewares = append(middlewares, withFakeIP(mapper.fakePool))
}
if mapper.mode != NORMAL {
if mapper.mode != C.DNSNormal {
middlewares = append(middlewares, withMapping(mapper.mapping))
}

View File

@ -14,6 +14,7 @@ import (
"github.com/Dreamacro/clash/component/fakeip"
"github.com/Dreamacro/clash/component/resolver"
"github.com/Dreamacro/clash/component/trie"
C "github.com/Dreamacro/clash/constant"
D "github.com/miekg/dns"
"golang.org/x/sync/singleflight"
@ -215,7 +216,6 @@ func (r *Resolver) shouldOnlyQueryFallback(m *D.Msg) bool {
}
func (r *Resolver) ipExchange(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) {
if matched := r.matchPolicy(m); len(matched) != 0 {
res := <-r.asyncExchange(ctx, matched, m)
return res.Msg, res.Error
@ -302,8 +302,9 @@ func (r *Resolver) asyncExchange(ctx context.Context, client []dnsClient, msg *D
}
type NameServer struct {
Net string
Addr string
Net string
Addr string
Interface string
}
type FallbackFilter struct {
@ -317,7 +318,7 @@ type Config struct {
Main, Fallback []NameServer
Default []NameServer
IPv6 bool
EnhancedMode EnhancedMode
EnhancedMode C.DNSMode
FallbackFilter FallbackFilter
Pool *fakeip.Pool
Hosts *trie.DomainTrie

View File

@ -2,8 +2,6 @@ package dns
import (
"crypto/tls"
"encoding/json"
"errors"
"net"
"time"
@ -13,72 +11,6 @@ import (
D "github.com/miekg/dns"
)
var (
// EnhancedModeMapping is a mapping for EnhancedMode enum
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) {
var ttl uint32
switch {
@ -138,9 +70,10 @@ func transform(servers []NameServer, resolver *Resolver) []dnsClient {
UDPSize: 4096,
Timeout: 5 * time.Second,
},
port: port,
host: host,
r: resolver,
port: port,
host: host,
iface: s.Interface,
r: resolver,
})
}
return ret