feat: doh client support ecs and ecs-override

This commit is contained in:
wwqgtxx 2024-09-11 10:28:34 +08:00
parent f305e440ef
commit ecbbf9d220
2 changed files with 80 additions and 0 deletions

View File

@ -9,6 +9,7 @@ import (
"io"
"net"
"net/http"
"net/netip"
"net/url"
"runtime"
"strconv"
@ -67,6 +68,8 @@ type dnsOverHTTPS struct {
dialer *dnsDialer
addr string
skipCertVerify bool
ecsPrefix netip.Prefix
ecsOverride bool
}
// type check
@ -99,6 +102,28 @@ func newDoHClient(urlString string, r *Resolver, preferH3 bool, params map[strin
doh.skipCertVerify = true
}
if ecs := params["ecs"]; ecs != "" {
prefix, err := netip.ParsePrefix(ecs)
if err != nil {
addr, err := netip.ParseAddr(ecs)
if err != nil {
log.Warnln("DOH [%s] config with invalid ecs: %s", doh.addr, ecs)
} else {
doh.ecsPrefix = netip.PrefixFrom(addr, addr.BitLen())
}
} else {
doh.ecsPrefix = prefix
}
}
if doh.ecsPrefix.IsValid() {
log.Debugln("DOH [%s] config with ecs: %s", doh.addr, doh.ecsPrefix)
}
if params["ecs-override"] == "true" {
doh.ecsOverride = true
}
runtime.SetFinalizer(doh, (*dnsOverHTTPS).Close)
return doh
@ -126,6 +151,10 @@ func (doh *dnsOverHTTPS) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.
}
}()
if doh.ecsPrefix.IsValid() {
setEdns0Subnet(m, doh.ecsPrefix, doh.ecsOverride)
}
// Check if there was already an active client before sending the request.
// We'll only attempt to re-connect if there was one.
client, isCached, err := doh.getClient(ctx)

51
dns/edns0_subnet.go Normal file
View File

@ -0,0 +1,51 @@
package dns
import (
"net/netip"
"github.com/miekg/dns"
)
func setEdns0Subnet(message *dns.Msg, clientSubnet netip.Prefix, override bool) bool {
var (
optRecord *dns.OPT
subnetOption *dns.EDNS0_SUBNET
)
findExists:
for _, record := range message.Extra {
var isOPTRecord bool
if optRecord, isOPTRecord = record.(*dns.OPT); isOPTRecord {
for _, option := range optRecord.Option {
var isEDNS0Subnet bool
if subnetOption, isEDNS0Subnet = option.(*dns.EDNS0_SUBNET); isEDNS0Subnet {
if !override {
return false
}
break findExists
}
}
}
}
if optRecord == nil {
optRecord = &dns.OPT{
Hdr: dns.RR_Header{
Name: ".",
Rrtype: dns.TypeOPT,
},
}
message.Extra = append(message.Extra, optRecord)
}
if subnetOption == nil {
subnetOption = new(dns.EDNS0_SUBNET)
optRecord.Option = append(optRecord.Option, subnetOption)
}
subnetOption.Code = dns.EDNS0SUBNET
if clientSubnet.Addr().Is4() {
subnetOption.Family = 1
} else {
subnetOption.Family = 2
}
subnetOption.SourceNetmask = uint8(clientSubnet.Bits())
subnetOption.Address = clientSubnet.Addr().AsSlice()
return true
}