feat: Add RCode DNS client
This commit is contained in:
parent
12c113d9cf
commit
1f49fa0c5d
4 changed files with 77 additions and 6 deletions
|
@ -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
54
dns/rcode.go
Normal 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
|
||||||
|
}
|
15
dns/util.go
15
dns/util.go
|
@ -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
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -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]
|
||||||
## global,dns 为 rule-providers 中的名为 global 和 dns 规则订阅,
|
## global,dns 为 rule-providers 中的名为 global 和 dns 规则订阅,
|
||||||
## 且 behavior 必须为 domain/classical,当为 classical 时仅会生效域名类规则
|
## 且 behavior 必须为 domain/classical,当为 classical 时仅会生效域名类规则
|
||||||
|
|
Loading…
Reference in a new issue