feat: Add RCode DNS client

This commit is contained in:
H1JK 2023-06-11 23:01:45 +08:00
parent b72219c06a
commit c7de0e0253
4 changed files with 77 additions and 6 deletions

View file

@ -939,6 +939,19 @@ func parseNameServer(servers []string, preferH3 bool) ([]dns.NameServer, error)
dnsNetType = "quic" // DNS over QUIC dnsNetType = "quic" // DNS over QUIC
case "system": case "system":
dnsNetType = "system" // System DNS dnsNetType = "system" // System DNS
case "rcode":
dnsNetType = "rcode"
addr = u.Host
switch addr {
case "success",
"format_error",
"server_failure",
"name_error",
"not_implemented",
"refused":
default:
err = fmt.Errorf("unsupported RCode type: %s", addr)
}
default: default:
return nil, fmt.Errorf("DNS NameServer[%d] unsupport scheme: %s", idx, u.Scheme) return nil, fmt.Errorf("DNS NameServer[%d] unsupport scheme: %s", idx, u.Scheme)
} }

54
dns/rcode.go Normal file
View file

@ -0,0 +1,54 @@
package dns
import (
"context"
"fmt"
D "github.com/miekg/dns"
)
func newRCodeClient(addr string) rcodeClient {
var rcode int
switch addr {
case "success":
rcode = D.RcodeSuccess
case "format_error":
rcode = D.RcodeFormatError
case "server_failure":
rcode = D.RcodeServerFailure
case "name_error":
rcode = D.RcodeNameError
case "not_implemented":
rcode = D.RcodeNotImplemented
case "refused":
rcode = D.RcodeRefused
default:
panic(fmt.Errorf("unsupported RCode type: %s", addr))
}
return rcodeClient{
rcode: rcode,
addr: "rcode://" + addr,
}
}
type rcodeClient struct {
rcode int
addr string
}
var _ dnsClient = rcodeClient{}
func (r rcodeClient) Exchange(m *D.Msg) (*D.Msg, error) {
m.Response = true
m.Rcode = r.rcode
return m, nil
}
func (r rcodeClient) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error) {
return r.Exchange(m)
}
func (r rcodeClient) Address() string {
return r.addr
}

View file

@ -93,7 +93,7 @@ func isIPRequest(q D.Question) bool {
} }
func transform(servers []NameServer, resolver *Resolver) []dnsClient { func transform(servers []NameServer, resolver *Resolver) []dnsClient {
ret := []dnsClient{} ret := make([]dnsClient, 0, len(servers))
for _, s := range servers { for _, s := range servers {
switch s.Net { switch s.Net {
case "https": case "https":
@ -114,6 +114,9 @@ func transform(servers []NameServer, resolver *Resolver) []dnsClient {
} }
ret = append(ret, clients...) ret = append(ret, clients...)
continue continue
case "rcode":
ret = append(ret, newRCodeClient(s.Addr))
continue
case "quic": case "quic":
if doq, err := newDoQ(resolver, s.Addr, s.ProxyAdapter, s.ProxyName); err == nil { if doq, err := newDoQ(resolver, s.Addr, s.ProxyAdapter, s.ProxyName); err == nil {
ret = append(ret, doq) ret = append(ret, doq)
@ -288,16 +291,16 @@ func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.M
fast, ctx := picker.WithTimeout[*D.Msg](ctx, resolver.DefaultDNSTimeout) fast, ctx := picker.WithTimeout[*D.Msg](ctx, resolver.DefaultDNSTimeout)
domain := msgToDomain(m) domain := msgToDomain(m)
for _, client := range clients { for _, client := range clients {
r := client _, ignoreRCodeError := client.(rcodeClient)
fast.Go(func() (*D.Msg, error) { fast.Go(func() (*D.Msg, error) {
log.Debugln("[DNS] resolve %s from %s", domain, r.Address()) log.Debugln("[DNS] resolve %s from %s", domain, client.Address())
m, err := r.ExchangeContext(ctx, m) m, err := client.ExchangeContext(ctx, m)
if err != nil { if err != nil {
return nil, err return nil, err
} else if m.Rcode == D.RcodeServerFailure || m.Rcode == D.RcodeRefused { } else if !ignoreRCodeError && (m.Rcode == D.RcodeServerFailure || m.Rcode == D.RcodeRefused) {
return nil, errors.New("server failure") return nil, errors.New("server failure")
} }
log.Debugln("[DNS] %s --> %s, from %s", domain, msgToIP(m), r.Address()) log.Debugln("[DNS] %s --> %s, from %s", domain, msgToIP(m), client.Address())
return m, nil return m, nil
}) })
} }

View file

@ -238,6 +238,7 @@ dns:
"geosite:cn,private,apple": "geosite:cn,private,apple":
- https://doh.pub/dns-query - https://doh.pub/dns-query
- https://dns.alidns.com/dns-query - https://dns.alidns.com/dns-query
"geosite:category-ads-all": rcode://success
"www.baidu.com,+.google.cn": [223.5.5.5, https://dns.alidns.com/dns-query] "www.baidu.com,+.google.cn": [223.5.5.5, https://dns.alidns.com/dns-query]
## globaldns 为 rule-providers 中的名为 global 和 dns 规则订阅, ## globaldns 为 rule-providers 中的名为 global 和 dns 规则订阅,
## 且 behavior 必须为 domain/classical当为 classical 时仅会生效域名类规则 ## 且 behavior 必须为 domain/classical当为 classical 时仅会生效域名类规则