feat: all dns client support disable-ipv4 and disable-ipv6 params

This commit is contained in:
wwqgtxx 2025-06-06 00:24:57 +08:00
parent 2f9a3b3469
commit 29a37f4f4b
3 changed files with 68 additions and 43 deletions

View File

@ -1168,10 +1168,21 @@ func parseNameServer(servers []string, respectRules bool, preferH3 bool) ([]dns.
return nil, fmt.Errorf("DNS NameServer[%d] format error: %s", idx, err.Error()) return nil, fmt.Errorf("DNS NameServer[%d] format error: %s", idx, err.Error())
} }
proxyName := u.Fragment var proxyName string
params := map[string]string{}
for _, s := range strings.Split(u.Fragment, "&") {
arr := strings.SplitN(s, "=", 2)
switch len(arr) {
case 0:
continue
case 1:
proxyName = arr[0]
case 2:
params[arr[0]] = arr[1]
}
}
var addr, dnsNetType string var addr, dnsNetType string
params := map[string]string{}
switch u.Scheme { switch u.Scheme {
case "udp": case "udp":
addr, err = hostWithDefaultPort(u.Host, "53") addr, err = hostWithDefaultPort(u.Host, "53")
@ -1189,23 +1200,8 @@ func parseNameServer(servers []string, respectRules bool, preferH3 bool) ([]dns.
addr, err = hostWithDefaultPort(u.Host, "80") addr, err = hostWithDefaultPort(u.Host, "80")
} }
if err == nil { if err == nil {
proxyName = ""
clearURL := url.URL{Scheme: u.Scheme, Host: addr, Path: u.Path, User: u.User} clearURL := url.URL{Scheme: u.Scheme, Host: addr, Path: u.Path, User: u.User}
addr = clearURL.String() addr = clearURL.String()
if len(u.Fragment) != 0 {
for _, s := range strings.Split(u.Fragment, "&") {
arr := strings.Split(s, "=")
if len(arr) == 0 {
continue
} else if len(arr) == 1 {
proxyName = arr[0]
} else if len(arr) == 2 {
params[arr[0]] = arr[1]
} else {
params[arr[0]] = strings.Join(arr[1:], "=")
}
}
}
} }
case "quic": case "quic":
addr, err = hostWithDefaultPort(u.Host, "853") addr, err = hostWithDefaultPort(u.Host, "853")

View File

@ -6,8 +6,10 @@ import (
"fmt" "fmt"
"net" "net"
"strings" "strings"
"time"
"github.com/metacubex/mihomo/component/ca" "github.com/metacubex/mihomo/component/ca"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/log" "github.com/metacubex/mihomo/log"
D "github.com/miekg/dns" D "github.com/miekg/dns"
@ -105,3 +107,20 @@ func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error)
} }
func (c *client) ResetConnection() {} func (c *client) ResetConnection() {}
func newClient(addr string, resolver *Resolver, netType string, proxyAdapter C.ProxyAdapter, proxyName string) *client {
host, port, _ := net.SplitHostPort(addr)
return &client{
Client: &D.Client{
Net: netType,
TLSConfig: &tls.Config{
ServerName: host,
},
UDPSize: 4096,
Timeout: 5 * time.Second,
},
port: port,
host: host,
dialer: newDNSDialer(resolver, proxyAdapter, proxyName),
}
}

View File

@ -2,10 +2,8 @@ package dns
import ( import (
"context" "context"
"crypto/tls"
"errors" "errors"
"fmt" "fmt"
"net"
"net/netip" "net/netip"
"strings" "strings"
"time" "time"
@ -92,42 +90,54 @@ func isIPRequest(q D.Question) bool {
func transform(servers []NameServer, resolver *Resolver) []dnsClient { func transform(servers []NameServer, resolver *Resolver) []dnsClient {
ret := make([]dnsClient, 0, len(servers)) ret := make([]dnsClient, 0, len(servers))
for _, s := range servers { for _, s := range servers {
var c dnsClient
switch s.Net { switch s.Net {
case "https": case "https":
ret = append(ret, newDoHClient(s.Addr, resolver, s.PreferH3, s.Params, s.ProxyAdapter, s.ProxyName)) c = newDoHClient(s.Addr, resolver, s.PreferH3, s.Params, s.ProxyAdapter, s.ProxyName)
continue
case "dhcp": case "dhcp":
ret = append(ret, newDHCPClient(s.Addr)) c = newDHCPClient(s.Addr)
continue
case "system": case "system":
ret = append(ret, newSystemClient()) c = newSystemClient()
continue
case "rcode": case "rcode":
ret = append(ret, newRCodeClient(s.Addr)) c = newRCodeClient(s.Addr)
continue
case "quic": case "quic":
ret = append(ret, newDoQ(s.Addr, resolver, s.ProxyAdapter, s.ProxyName)) c = newDoQ(s.Addr, resolver, s.ProxyAdapter, s.ProxyName)
continue default:
c = newClient(s.Addr, resolver, s.Net, s.ProxyAdapter, s.ProxyName)
} }
host, port, _ := net.SplitHostPort(s.Addr) if s.Params["disable-ipv4"] == "true" {
ret = append(ret, &client{ c = newDisableTypeClient(c, D.TypeA)
Client: &D.Client{ }
Net: s.Net,
TLSConfig: &tls.Config{ if s.Params["disable-ipv6"] == "true" {
ServerName: host, c = newDisableTypeClient(c, D.TypeAAAA)
}, }
UDPSize: 4096,
Timeout: 5 * time.Second, ret = append(ret, c)
},
port: port,
host: host,
dialer: newDNSDialer(resolver, s.ProxyAdapter, s.ProxyName),
})
} }
return ret return ret
} }
type disableTypeClient struct {
dnsClient
qType uint16
}
func (c disableTypeClient) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) {
if len(m.Question) > 0 {
q := m.Question[0]
if q.Qtype == c.qType {
return handleMsgWithEmptyAnswer(m), nil
}
}
return c.dnsClient.ExchangeContext(ctx, m)
}
func newDisableTypeClient(c dnsClient, qType uint16) dnsClient {
return disableTypeClient{c, qType}
}
func handleMsgWithEmptyAnswer(r *D.Msg) *D.Msg { func handleMsgWithEmptyAnswer(r *D.Msg) *D.Msg {
msg := &D.Msg{} msg := &D.Msg{}
msg.Answer = []D.RR{} msg.Answer = []D.RR{}