Skip to content

Commit 94e3bee

Browse files
committed
feat: add EDNS Client Subnet (ECS) support for accurate GeoDNS
- Add getClientIPFromECS() to extract client subnet from ECS option - Support both IPv4 (family 1) and IPv6 (family 2) subnets - Try ECS first, fall back to source IP if not present - Enables accurate GeoDNS routing through recursive resolvers (1.1.1.1, 8.8.8.8) - Logs detected ECS subnet for debugging
1 parent 797d6c8 commit 94e3bee

1 file changed

Lines changed: 34 additions & 1 deletion

File tree

dns/server.go

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,12 @@ func (s *DNSServer) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) {
8686

8787
log.Printf("[DNS] Query: %s %s from %s", domain, dns.TypeToString[qtype], w.RemoteAddr())
8888

89-
clientIP := extractClientIP(w.RemoteAddr())
89+
// Get client IP, prefer ECS if available
90+
clientIP := getClientIPFromECS(r)
91+
if clientIP == "" {
92+
// Fall back to source IP
93+
clientIP = extractClientIP(w.RemoteAddr())
94+
}
9095

9196
// Try to find exact domain match first
9297
domainConfig := s.configMgr.GetDomain(domain)
@@ -605,6 +610,34 @@ func extractClientIP(addr net.Addr) string {
605610
}
606611
}
607612

613+
// getClientIPFromECS extracts the client IP from EDNS Client Subnet option
614+
// This allows GeoDNS to work correctly behind recursive resolvers like 1.1.1.1
615+
func getClientIPFromECS(r *dns.Msg) string {
616+
for _, opt := range r.Extra {
617+
if opt.Header().Rrtype == dns.TypeOPT {
618+
// EDNS0 option
619+
if edns0, ok := opt.(*dns.OPT); ok {
620+
for _, option := range edns0.Option {
621+
if subnet, ok := option.(*dns.EDNS0_SUBNET); ok {
622+
// Found ECS option
623+
if subnet.Family == 1 { // IPv4
624+
// Convert subnet to IP string
625+
ip := net.IP(subnet.Address).String()
626+
log.Printf("[DNS] ECS detected: client subnet %s/%d", ip, subnet.SourceNetmask)
627+
return ip
628+
} else if subnet.Family == 2 { // IPv6
629+
ip := net.IP(subnet.Address).String()
630+
log.Printf("[DNS] ECS detected: client subnet %s/%d", ip, subnet.SourceNetmask)
631+
return ip
632+
}
633+
}
634+
}
635+
}
636+
}
637+
}
638+
return ""
639+
}
640+
608641
func findBestAgentIP(geoDNSMap map[string]string, fallbackMap map[string]string, clientLocation string, httpProxyEnabled bool, allAgents []config.FallbackAgentInfo) string {
609642
// Try exact match first
610643
if ip, ok := geoDNSMap[clientLocation]; ok {

0 commit comments

Comments
 (0)