diff --git a/config/config.go b/config/config.go index d79ab65c..498c7c20 100644 --- a/config/config.go +++ b/config/config.go @@ -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()) } - 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 - params := map[string]string{} switch u.Scheme { case "udp": 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") } if err == nil { - proxyName = "" clearURL := url.URL{Scheme: u.Scheme, Host: addr, Path: u.Path, User: u.User} 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": addr, err = hostWithDefaultPort(u.Host, "853") diff --git a/dns/client.go b/dns/client.go index abdad3a6..90c79d70 100644 --- a/dns/client.go +++ b/dns/client.go @@ -6,8 +6,10 @@ import ( "fmt" "net" "strings" + "time" "github.com/metacubex/mihomo/component/ca" + C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/log" 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 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), + } +} diff --git a/dns/util.go b/dns/util.go index ae764648..7a5519be 100644 --- a/dns/util.go +++ b/dns/util.go @@ -2,10 +2,8 @@ package dns import ( "context" - "crypto/tls" "errors" "fmt" - "net" "net/netip" "strings" "time" @@ -92,42 +90,54 @@ func isIPRequest(q D.Question) bool { func transform(servers []NameServer, resolver *Resolver) []dnsClient { ret := make([]dnsClient, 0, len(servers)) for _, s := range servers { + var c dnsClient switch s.Net { case "https": - ret = append(ret, newDoHClient(s.Addr, resolver, s.PreferH3, s.Params, s.ProxyAdapter, s.ProxyName)) - continue + c = newDoHClient(s.Addr, resolver, s.PreferH3, s.Params, s.ProxyAdapter, s.ProxyName) case "dhcp": - ret = append(ret, newDHCPClient(s.Addr)) - continue + c = newDHCPClient(s.Addr) case "system": - ret = append(ret, newSystemClient()) - continue + c = newSystemClient() case "rcode": - ret = append(ret, newRCodeClient(s.Addr)) - continue + c = newRCodeClient(s.Addr) case "quic": - ret = append(ret, newDoQ(s.Addr, resolver, s.ProxyAdapter, s.ProxyName)) - continue + c = newDoQ(s.Addr, resolver, s.ProxyAdapter, s.ProxyName) + default: + c = newClient(s.Addr, resolver, s.Net, s.ProxyAdapter, s.ProxyName) } - host, port, _ := net.SplitHostPort(s.Addr) - ret = append(ret, &client{ - Client: &D.Client{ - Net: s.Net, - TLSConfig: &tls.Config{ - ServerName: host, - }, - UDPSize: 4096, - Timeout: 5 * time.Second, - }, - port: port, - host: host, - dialer: newDNSDialer(resolver, s.ProxyAdapter, s.ProxyName), - }) + if s.Params["disable-ipv4"] == "true" { + c = newDisableTypeClient(c, D.TypeA) + } + + if s.Params["disable-ipv6"] == "true" { + c = newDisableTypeClient(c, D.TypeAAAA) + } + + ret = append(ret, c) } 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 { msg := &D.Msg{} msg.Answer = []D.RR{}