mirror of
https://gitclone.com/github.com/MetaCubeX/Clash.Meta
synced 2025-02-23 07:43:13 +08:00
feat: doh client support ecs
and ecs-override
This commit is contained in:
parent
f305e440ef
commit
ecbbf9d220
29
dns/doh.go
29
dns/doh.go
@ -9,6 +9,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/netip"
|
||||||
"net/url"
|
"net/url"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -67,6 +68,8 @@ type dnsOverHTTPS struct {
|
|||||||
dialer *dnsDialer
|
dialer *dnsDialer
|
||||||
addr string
|
addr string
|
||||||
skipCertVerify bool
|
skipCertVerify bool
|
||||||
|
ecsPrefix netip.Prefix
|
||||||
|
ecsOverride bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// type check
|
// type check
|
||||||
@ -99,6 +102,28 @@ func newDoHClient(urlString string, r *Resolver, preferH3 bool, params map[strin
|
|||||||
doh.skipCertVerify = true
|
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)
|
runtime.SetFinalizer(doh, (*dnsOverHTTPS).Close)
|
||||||
|
|
||||||
return doh
|
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.
|
// Check if there was already an active client before sending the request.
|
||||||
// We'll only attempt to re-connect if there was one.
|
// We'll only attempt to re-connect if there was one.
|
||||||
client, isCached, err := doh.getClient(ctx)
|
client, isCached, err := doh.getClient(ctx)
|
||||||
|
51
dns/edns0_subnet.go
Normal file
51
dns/edns0_subnet.go
Normal 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
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user