upstream with actual client ip to upstream
This commit is contained in:
parent
e4bf55d8bc
commit
c58703f735
1 changed files with 50 additions and 4 deletions
54
main.go
54
main.go
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"html/template"
|
"html/template"
|
||||||
"log"
|
"log"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
@ -94,9 +95,17 @@ func (resolver *DNSResolver) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback to upstream for all other cases
|
// Fallback to upstream for all other cases
|
||||||
resp, err := resolver.resolveUpstream(r)
|
var clientIP net.IP
|
||||||
|
switch addr := w.RemoteAddr().(type) {
|
||||||
|
case *net.UDPAddr:
|
||||||
|
clientIP = addr.IP
|
||||||
|
case *net.TCPAddr:
|
||||||
|
clientIP = addr.IP
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := resolver.resolveUpstream(r, clientIP)
|
||||||
if err == nil && resp != nil {
|
if err == nil && resp != nil {
|
||||||
log.Printf("[UPSTREAM] Forwarded %s", q.Name)
|
log.Printf("[UPSTREAM] Forwarded %s (ClientIP: %s)", q.Name, clientIP)
|
||||||
m.Answer = resp.Answer
|
m.Answer = resp.Answer
|
||||||
m.Ns = resp.Ns
|
m.Ns = resp.Ns
|
||||||
m.Extra = resp.Extra
|
m.Extra = resp.Extra
|
||||||
|
|
@ -122,13 +131,50 @@ func (resolver *DNSResolver) getRecordFromDB(domain string, recordType string) (
|
||||||
return ip, nil
|
return ip, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (resolver *DNSResolver) resolveUpstream(r *dns.Msg) (*dns.Msg, error) {
|
func (resolver *DNSResolver) resolveUpstream(r *dns.Msg, clientIP net.IP) (*dns.Msg, error) {
|
||||||
rows, err := resolver.db.Query("SELECT address FROM upstreams")
|
rows, err := resolver.db.Query("SELECT address FROM upstreams")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
|
// Create a copy of the message to avoid side effects
|
||||||
|
req := r.Copy()
|
||||||
|
|
||||||
|
// Add EDNS0 Client Subnet option
|
||||||
|
if clientIP != nil {
|
||||||
|
o := req.IsEdns0()
|
||||||
|
if o == nil {
|
||||||
|
req.SetEdns0(4096, false)
|
||||||
|
o = req.IsEdns0()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter out existing SUBNET options to ensure we are authoritative about the client IP
|
||||||
|
var newOptions []dns.EDNS0
|
||||||
|
for _, opt := range o.Option {
|
||||||
|
if opt.Option() != dns.EDNS0SUBNET {
|
||||||
|
newOptions = append(newOptions, opt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
e := new(dns.EDNS0_SUBNET)
|
||||||
|
e.Code = dns.EDNS0SUBNET
|
||||||
|
if ip4 := clientIP.To4(); ip4 != nil {
|
||||||
|
e.Family = 1 // IPv4
|
||||||
|
e.SourceNetmask = 32
|
||||||
|
e.SourceScope = 0
|
||||||
|
e.Address = ip4
|
||||||
|
} else {
|
||||||
|
e.Family = 2 // IPv6
|
||||||
|
e.SourceNetmask = 128
|
||||||
|
e.SourceScope = 0
|
||||||
|
e.Address = clientIP
|
||||||
|
}
|
||||||
|
|
||||||
|
newOptions = append(newOptions, e)
|
||||||
|
o.Option = newOptions
|
||||||
|
}
|
||||||
|
|
||||||
c := new(dns.Client)
|
c := new(dns.Client)
|
||||||
c.Net = "udp"
|
c.Net = "udp"
|
||||||
|
|
||||||
|
|
@ -140,7 +186,7 @@ func (resolver *DNSResolver) resolveUpstream(r *dns.Msg) (*dns.Msg, error) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, _, err := c.Exchange(r, upstreamAddr)
|
resp, _, err := c.Exchange(req, upstreamAddr)
|
||||||
if err == nil && resp != nil && resp.Rcode != dns.RcodeServerFailure {
|
if err == nil && resp != nil && resp.Rcode != dns.RcodeServerFailure {
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue