2018-12-05 21:13:29 +08:00
|
|
|
package dns
|
|
|
|
|
|
|
|
import (
|
2021-11-17 16:03:47 +08:00
|
|
|
"context"
|
2019-06-28 12:29:08 +08:00
|
|
|
"crypto/tls"
|
2022-08-24 21:36:19 +08:00
|
|
|
"errors"
|
2021-11-17 16:03:47 +08:00
|
|
|
"fmt"
|
2020-02-17 22:13:15 +08:00
|
|
|
"net"
|
2022-04-20 01:52:51 +08:00
|
|
|
"net/netip"
|
2022-05-15 13:16:45 +08:00
|
|
|
"strings"
|
2018-12-05 21:13:29 +08:00
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/Dreamacro/clash/common/cache"
|
2022-12-19 21:34:07 +08:00
|
|
|
N "github.com/Dreamacro/clash/common/net"
|
2022-04-20 01:52:51 +08:00
|
|
|
"github.com/Dreamacro/clash/common/nnip"
|
2022-08-24 21:36:19 +08:00
|
|
|
"github.com/Dreamacro/clash/common/picker"
|
2021-11-17 16:03:47 +08:00
|
|
|
"github.com/Dreamacro/clash/component/dialer"
|
2022-11-12 20:43:48 +08:00
|
|
|
"github.com/Dreamacro/clash/component/resolver"
|
2021-11-17 16:03:47 +08:00
|
|
|
C "github.com/Dreamacro/clash/constant"
|
2018-12-05 21:13:29 +08:00
|
|
|
"github.com/Dreamacro/clash/log"
|
2021-11-17 16:03:47 +08:00
|
|
|
"github.com/Dreamacro/clash/tunnel"
|
2018-12-05 21:13:29 +08:00
|
|
|
|
|
|
|
D "github.com/miekg/dns"
|
|
|
|
)
|
|
|
|
|
2022-11-12 11:14:51 +08:00
|
|
|
const (
|
|
|
|
MaxMsgSize = 65535
|
|
|
|
)
|
|
|
|
|
2022-04-05 20:23:16 +08:00
|
|
|
func putMsgToCache(c *cache.LruCache[string, *D.Msg], key string, msg *D.Msg) {
|
2022-12-22 13:30:23 +08:00
|
|
|
// skip dns cache for acme challenge
|
2023-01-11 09:53:56 +08:00
|
|
|
if len(msg.Question) != 0 {
|
|
|
|
if q := msg.Question[0]; q.Qtype == D.TypeTXT && strings.HasPrefix(q.Name, "_acme-challenge") {
|
|
|
|
log.Debugln("[DNS] dns cache ignored because of acme challenge for: %s", q.Name)
|
|
|
|
return
|
|
|
|
}
|
2022-12-22 13:30:23 +08:00
|
|
|
}
|
2020-05-07 15:10:14 +08:00
|
|
|
var ttl uint32
|
2019-10-14 17:13:23 +08:00
|
|
|
switch {
|
|
|
|
case len(msg.Answer) != 0:
|
2020-05-07 15:10:14 +08:00
|
|
|
ttl = msg.Answer[0].Header().Ttl
|
2019-10-14 17:13:23 +08:00
|
|
|
case len(msg.Ns) != 0:
|
2020-05-07 15:10:14 +08:00
|
|
|
ttl = msg.Ns[0].Header().Ttl
|
2019-10-14 17:13:23 +08:00
|
|
|
case len(msg.Extra) != 0:
|
2020-05-07 15:10:14 +08:00
|
|
|
ttl = msg.Extra[0].Header().Ttl
|
2019-10-14 17:13:23 +08:00
|
|
|
default:
|
2020-06-12 23:39:03 +08:00
|
|
|
log.Debugln("[DNS] response msg empty: %#v", msg)
|
2018-12-05 21:13:29 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-05-07 15:10:14 +08:00
|
|
|
c.SetWithExpire(key, msg.Copy(), time.Now().Add(time.Second*time.Duration(ttl)))
|
2019-02-23 20:31:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func setMsgTTL(msg *D.Msg, ttl uint32) {
|
|
|
|
for _, answer := range msg.Answer {
|
|
|
|
answer.Header().Ttl = ttl
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, ns := range msg.Ns {
|
|
|
|
ns.Header().Ttl = ttl
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, extra := range msg.Extra {
|
|
|
|
extra.Header().Ttl = ttl
|
|
|
|
}
|
2018-12-05 21:13:29 +08:00
|
|
|
}
|
2019-06-28 12:29:08 +08:00
|
|
|
|
|
|
|
func isIPRequest(q D.Question) bool {
|
2023-03-12 15:00:59 +08:00
|
|
|
return q.Qclass == D.ClassINET && (q.Qtype == D.TypeA || q.Qtype == D.TypeAAAA || q.Qtype == D.TypeCNAME)
|
2019-06-28 12:29:08 +08:00
|
|
|
}
|
|
|
|
|
2022-07-21 14:03:49 +08:00
|
|
|
func transform(servers []NameServer, resolver *Resolver) []dnsClient {
|
2020-02-15 21:42:46 +08:00
|
|
|
ret := []dnsClient{}
|
2019-06-28 12:29:08 +08:00
|
|
|
for _, s := range servers {
|
2021-09-06 23:07:34 +08:00
|
|
|
switch s.Net {
|
|
|
|
case "https":
|
2023-04-11 10:29:55 +08:00
|
|
|
ret = append(ret, newDoHClient(s.Addr, resolver, s.PreferH3, s.Params, s.ProxyAdapter, s.ProxyName))
|
2019-06-28 12:29:08 +08:00
|
|
|
continue
|
2021-09-06 23:07:34 +08:00
|
|
|
case "dhcp":
|
|
|
|
ret = append(ret, newDHCPClient(s.Addr))
|
|
|
|
continue
|
2022-01-27 12:25:53 +08:00
|
|
|
case "quic":
|
2023-04-11 10:29:55 +08:00
|
|
|
if doq, err := newDoQ(resolver, s.Addr, s.ProxyAdapter, s.ProxyName); err == nil {
|
2022-11-12 11:14:51 +08:00
|
|
|
ret = append(ret, doq)
|
2022-11-12 20:43:48 +08:00
|
|
|
} else {
|
|
|
|
log.Fatalln("DoQ format error: %v", err)
|
2022-11-12 11:14:51 +08:00
|
|
|
}
|
2022-01-27 12:25:53 +08:00
|
|
|
continue
|
2019-06-28 12:29:08 +08:00
|
|
|
}
|
|
|
|
|
2020-02-17 22:13:15 +08:00
|
|
|
host, port, _ := net.SplitHostPort(s.Addr)
|
2019-06-28 12:29:08 +08:00
|
|
|
ret = append(ret, &client{
|
|
|
|
Client: &D.Client{
|
|
|
|
Net: s.Net,
|
|
|
|
TLSConfig: &tls.Config{
|
2020-04-17 11:29:59 +08:00
|
|
|
ServerName: host,
|
2019-06-28 12:29:08 +08:00
|
|
|
},
|
|
|
|
UDPSize: 4096,
|
2020-01-10 14:13:44 +08:00
|
|
|
Timeout: 5 * time.Second,
|
2019-06-28 12:29:08 +08:00
|
|
|
},
|
2021-11-17 16:03:47 +08:00
|
|
|
port: port,
|
|
|
|
host: host,
|
|
|
|
iface: s.Interface,
|
|
|
|
r: resolver,
|
|
|
|
proxyAdapter: s.ProxyAdapter,
|
2023-04-11 10:29:55 +08:00
|
|
|
proxyName: s.ProxyName,
|
2019-06-28 12:29:08 +08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
return ret
|
|
|
|
}
|
2020-10-13 00:15:49 +08:00
|
|
|
|
|
|
|
func handleMsgWithEmptyAnswer(r *D.Msg) *D.Msg {
|
|
|
|
msg := &D.Msg{}
|
|
|
|
msg.Answer = []D.RR{}
|
|
|
|
|
|
|
|
msg.SetRcode(r, D.RcodeSuccess)
|
|
|
|
msg.Authoritative = true
|
|
|
|
msg.RecursionAvailable = true
|
|
|
|
|
|
|
|
return msg
|
|
|
|
}
|
2021-01-23 14:49:46 +08:00
|
|
|
|
2022-04-20 01:52:51 +08:00
|
|
|
func msgToIP(msg *D.Msg) []netip.Addr {
|
|
|
|
ips := []netip.Addr{}
|
2021-01-23 14:49:46 +08:00
|
|
|
|
|
|
|
for _, answer := range msg.Answer {
|
|
|
|
switch ans := answer.(type) {
|
|
|
|
case *D.AAAA:
|
2022-04-20 01:52:51 +08:00
|
|
|
ips = append(ips, nnip.IpToAddr(ans.AAAA))
|
2021-01-23 14:49:46 +08:00
|
|
|
case *D.A:
|
2022-04-20 01:52:51 +08:00
|
|
|
ips = append(ips, nnip.IpToAddr(ans.A))
|
2021-01-23 14:49:46 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ips
|
|
|
|
}
|
2021-11-17 16:03:47 +08:00
|
|
|
|
2022-05-15 13:16:45 +08:00
|
|
|
func msgToDomain(msg *D.Msg) string {
|
|
|
|
if len(msg.Question) > 0 {
|
|
|
|
return strings.TrimRight(msg.Question[0].Name, ".")
|
|
|
|
}
|
|
|
|
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2022-12-07 20:01:44 +08:00
|
|
|
type dialHandler func(ctx context.Context, network, addr string) (net.Conn, error)
|
2022-06-21 22:59:35 +08:00
|
|
|
|
2023-04-11 10:29:55 +08:00
|
|
|
func getDialHandler(r *Resolver, proxyAdapter C.ProxyAdapter, proxyName string, opts ...dialer.Option) dialHandler {
|
2022-12-07 20:01:44 +08:00
|
|
|
return func(ctx context.Context, network, addr string) (net.Conn, error) {
|
2023-04-11 10:29:55 +08:00
|
|
|
if len(proxyName) == 0 && proxyAdapter == nil {
|
2022-12-07 20:01:44 +08:00
|
|
|
opts = append(opts, dialer.WithResolver(r))
|
|
|
|
return dialer.DialContext(ctx, network, addr, opts...)
|
|
|
|
} else {
|
2022-12-13 12:38:46 +08:00
|
|
|
host, port, err := net.SplitHostPort(addr)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-04-11 10:29:55 +08:00
|
|
|
if proxyAdapter == nil {
|
|
|
|
var ok bool
|
|
|
|
proxyAdapter, ok = tunnel.Proxies()[proxyName]
|
|
|
|
if !ok {
|
|
|
|
opts = append(opts, dialer.WithInterface(proxyName))
|
|
|
|
}
|
2022-12-13 12:38:46 +08:00
|
|
|
}
|
2023-04-11 10:29:55 +08:00
|
|
|
|
2022-12-13 12:38:46 +08:00
|
|
|
if strings.Contains(network, "tcp") {
|
|
|
|
// tcp can resolve host by remote
|
|
|
|
metadata := &C.Metadata{
|
|
|
|
NetWork: C.TCP,
|
|
|
|
Host: host,
|
|
|
|
DstPort: port,
|
|
|
|
}
|
2023-04-11 10:29:55 +08:00
|
|
|
if proxyAdapter != nil {
|
|
|
|
return proxyAdapter.DialContext(ctx, metadata, opts...)
|
2022-12-13 12:38:46 +08:00
|
|
|
}
|
|
|
|
opts = append(opts, dialer.WithResolver(r))
|
|
|
|
return dialer.DialContext(ctx, network, addr, opts...)
|
|
|
|
} else {
|
|
|
|
// udp must resolve host first
|
|
|
|
dstIP, err := resolver.ResolveIPWithResolver(ctx, host, r)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
metadata := &C.Metadata{
|
|
|
|
NetWork: C.UDP,
|
|
|
|
Host: "",
|
|
|
|
DstIP: dstIP,
|
|
|
|
DstPort: port,
|
|
|
|
}
|
2023-04-11 10:29:55 +08:00
|
|
|
if proxyAdapter == nil {
|
2022-12-13 12:38:46 +08:00
|
|
|
return dialer.DialContext(ctx, network, addr, opts...)
|
|
|
|
}
|
|
|
|
|
2023-04-11 10:29:55 +08:00
|
|
|
if !proxyAdapter.SupportUDP() {
|
2022-12-13 12:38:46 +08:00
|
|
|
return nil, fmt.Errorf("proxy adapter [%s] UDP is not supported", proxyAdapter)
|
|
|
|
}
|
|
|
|
|
2023-04-11 10:29:55 +08:00
|
|
|
packetConn, err := proxyAdapter.ListenPacketContext(ctx, metadata, opts...)
|
2022-12-13 12:38:46 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-12-19 21:34:07 +08:00
|
|
|
return N.NewBindPacketConn(packetConn, metadata.UDPAddr()), nil
|
2022-12-13 12:38:46 +08:00
|
|
|
}
|
2022-12-07 20:01:44 +08:00
|
|
|
}
|
2021-11-17 16:03:47 +08:00
|
|
|
}
|
2022-12-07 20:01:44 +08:00
|
|
|
}
|
2021-11-17 16:03:47 +08:00
|
|
|
|
2023-04-11 10:29:55 +08:00
|
|
|
func listenPacket(ctx context.Context, proxyAdapter C.ProxyAdapter, proxyName string, network string, addr string, r *Resolver, opts ...dialer.Option) (net.PacketConn, error) {
|
2022-12-07 20:01:44 +08:00
|
|
|
host, port, err := net.SplitHostPort(addr)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2021-11-17 16:03:47 +08:00
|
|
|
}
|
2023-04-11 10:29:55 +08:00
|
|
|
if proxyAdapter == nil {
|
|
|
|
var ok bool
|
|
|
|
proxyAdapter, ok = tunnel.Proxies()[proxyName]
|
|
|
|
if !ok {
|
|
|
|
opts = append(opts, dialer.WithInterface(proxyName))
|
|
|
|
}
|
2022-12-07 20:01:44 +08:00
|
|
|
}
|
2022-06-21 22:59:35 +08:00
|
|
|
|
2022-12-13 12:38:46 +08:00
|
|
|
// udp must resolve host first
|
|
|
|
dstIP, err := resolver.ResolveIPWithResolver(ctx, host, r)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
metadata := &C.Metadata{
|
|
|
|
NetWork: C.UDP,
|
|
|
|
Host: "",
|
|
|
|
DstIP: dstIP,
|
|
|
|
DstPort: port,
|
|
|
|
}
|
2023-04-11 10:29:55 +08:00
|
|
|
if proxyAdapter == nil {
|
2022-12-13 12:38:46 +08:00
|
|
|
return dialer.ListenPacket(ctx, dialer.ParseNetwork(network, dstIP), "", opts...)
|
|
|
|
}
|
2021-11-17 16:03:47 +08:00
|
|
|
|
2023-04-11 10:29:55 +08:00
|
|
|
if !proxyAdapter.SupportUDP() {
|
2022-12-13 12:38:46 +08:00
|
|
|
return nil, fmt.Errorf("proxy adapter [%s] UDP is not supported", proxyAdapter)
|
2021-11-17 16:03:47 +08:00
|
|
|
}
|
2022-12-13 12:38:46 +08:00
|
|
|
|
2023-04-11 10:29:55 +08:00
|
|
|
return proxyAdapter.ListenPacketContext(ctx, metadata, opts...)
|
2021-11-17 16:03:47 +08:00
|
|
|
}
|
2022-11-12 20:43:48 +08:00
|
|
|
|
2022-08-24 21:36:19 +08:00
|
|
|
func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.Msg, err error) {
|
2022-11-12 20:43:48 +08:00
|
|
|
fast, ctx := picker.WithTimeout[*D.Msg](ctx, resolver.DefaultDNSTimeout)
|
2023-01-28 22:33:03 +08:00
|
|
|
domain := msgToDomain(m)
|
2022-08-24 21:36:19 +08:00
|
|
|
for _, client := range clients {
|
|
|
|
r := client
|
2022-11-19 10:35:45 +08:00
|
|
|
fast.Go(func() (*D.Msg, error) {
|
2023-01-28 22:33:03 +08:00
|
|
|
log.Debugln("[DNS] resolve %s from %s", domain, r.Address())
|
2022-08-24 21:36:19 +08:00
|
|
|
m, err := r.ExchangeContext(ctx, m)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else if m.Rcode == D.RcodeServerFailure || m.Rcode == D.RcodeRefused {
|
|
|
|
return nil, errors.New("server failure")
|
|
|
|
}
|
2023-01-28 22:33:03 +08:00
|
|
|
log.Debugln("[DNS] %s --> %s, from %s", domain, msgToIP(m), r.Address())
|
2022-08-24 21:36:19 +08:00
|
|
|
return m, nil
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
elm := fast.Wait()
|
|
|
|
if elm == nil {
|
|
|
|
err := errors.New("all DNS requests failed")
|
|
|
|
if fErr := fast.Error(); fErr != nil {
|
|
|
|
err = fmt.Errorf("%w, first error: %s", err, fErr.Error())
|
|
|
|
}
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-11-12 20:43:48 +08:00
|
|
|
msg = elm
|
2022-08-24 21:36:19 +08:00
|
|
|
return
|
|
|
|
}
|