Skip to content

Commit

Permalink
feat: doh client support ecs and ecs-override
Browse files Browse the repository at this point in the history
  • Loading branch information
wwqgtxx committed Sep 11, 2024
1 parent f305e44 commit ecbbf9d
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 0 deletions.
29 changes: 29 additions & 0 deletions dns/doh.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"io"
"net"
"net/http"
"net/netip"
"net/url"
"runtime"
"strconv"
Expand Down Expand Up @@ -67,6 +68,8 @@ type dnsOverHTTPS struct {
dialer *dnsDialer
addr string
skipCertVerify bool
ecsPrefix netip.Prefix
ecsOverride bool
}

// type check
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
51 changes: 51 additions & 0 deletions dns/edns0_subnet.go
Original file line number Diff line number Diff line change
@@ -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
}

0 comments on commit ecbbf9d

Please sign in to comment.