diff --git a/.gitignore b/.gitignore index a9efdd07..f09cd7ed 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ *~ dnscrypt-proxy/dnscrypt-proxy2 dnscrypt-proxy/dnscrypt-proxy +.idea diff --git a/dnscrypt-proxy/config.go b/dnscrypt-proxy/config.go index 7cf6bab5..20ce6ac3 100644 --- a/dnscrypt-proxy/config.go +++ b/dnscrypt-proxy/config.go @@ -81,6 +81,7 @@ type Config struct { OfflineMode bool `toml:"offline_mode"` HTTPProxyURL string `toml:"http_proxy"` RefusedCodeInResponses bool `toml:"refused_code_in_responses"` + RespondWithIP string `toml:"respond_with_ip"` } func newConfig() Config { @@ -291,6 +292,7 @@ func ConfigLoad(proxy *Proxy, svcFlag *string) error { proxy.xTransport.rebuildTransport() proxy.refusedCodeInResponses = config.RefusedCodeInResponses + proxy.respondWithIP = config.RespondWithIP proxy.timeout = time.Duration(config.Timeout) * time.Millisecond proxy.maxClients = config.MaxClients proxy.mainProto = "udp" diff --git a/dnscrypt-proxy/dnsutils.go b/dnscrypt-proxy/dnsutils.go index aa3b1f59..22c3421e 100644 --- a/dnscrypt-proxy/dnsutils.go +++ b/dnscrypt-proxy/dnsutils.go @@ -2,6 +2,7 @@ package main import ( "encoding/binary" + "net" "strings" "time" @@ -31,7 +32,7 @@ func EmptyResponseFromMessage(srcMsg *dns.Msg) (*dns.Msg, error) { return dstMsg, nil } -func RefusedResponseFromMessage(srcMsg *dns.Msg, refusedCode bool) (*dns.Msg, error) { +func RefusedResponseFromMessage(srcMsg *dns.Msg, refusedCode bool, ip net.IP, ttl uint32) (*dns.Msg, error) { dstMsg, err := EmptyResponseFromMessage(srcMsg) if err != nil { return dstMsg, err @@ -42,12 +43,38 @@ func RefusedResponseFromMessage(srcMsg *dns.Msg, refusedCode bool) (*dns.Msg, er dstMsg.Rcode = dns.RcodeSuccess questions := srcMsg.Question if len(questions) > 0 { - hinfo := new(dns.HINFO) - hinfo.Hdr = dns.RR_Header{Name: questions[0].Name, Rrtype: dns.TypeHINFO, - Class: dns.ClassINET, Ttl: 1} - hinfo.Cpu = "This query has been locally blocked" - hinfo.Os = "by dnscrypt-proxy" - dstMsg.Answer = []dns.RR{hinfo} + question := questions[0] + sendHInfoResponse := true + + if ip != nil { + if question.Qtype == dns.TypeA { + rr := new(dns.A) + rr.Hdr = dns.RR_Header{Name: question.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: ttl} + rr.A = ip.To4() + if rr.A != nil { + dstMsg.Answer = []dns.RR{rr} + sendHInfoResponse = false + } + + } else if question.Qtype == dns.TypeAAAA { + rr := new(dns.AAAA) + rr.Hdr = dns.RR_Header{Name: question.Name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: ttl} + rr.AAAA = ip.To16() + if rr.AAAA != nil { + dstMsg.Answer = []dns.RR{rr} + sendHInfoResponse = false + } + } + } + + if sendHInfoResponse { + hinfo := new(dns.HINFO) + hinfo.Hdr = dns.RR_Header{Name: question.Name, Rrtype: dns.TypeHINFO, + Class: dns.ClassINET, Ttl: 1} + hinfo.Cpu = "This query has been locally blocked" + hinfo.Os = "by dnscrypt-proxy" + dstMsg.Answer = []dns.RR{hinfo} + } } } return dstMsg, nil diff --git a/dnscrypt-proxy/example-dnscrypt-proxy.toml b/dnscrypt-proxy/example-dnscrypt-proxy.toml index 941b381d..90bde69f 100644 --- a/dnscrypt-proxy/example-dnscrypt-proxy.toml +++ b/dnscrypt-proxy/example-dnscrypt-proxy.toml @@ -117,6 +117,12 @@ keepalive = 30 refused_code_in_responses = false +## If refused_code_in_responses is `false`, use this optional setting +## to redirect blocked respones to an IP address (e.g. pixelserv-tls) +## instead of returning an HINFO record + +# respond_with_ip = '192.168.1.4' + ## Load-balancing strategy: 'p2' (default), 'ph', 'first' or 'random' diff --git a/dnscrypt-proxy/plugins.go b/dnscrypt-proxy/plugins.go index 738e1178..e8a7bb48 100644 --- a/dnscrypt-proxy/plugins.go +++ b/dnscrypt-proxy/plugins.go @@ -26,6 +26,7 @@ type PluginsGlobals struct { responsePlugins *[]Plugin loggingPlugins *[]Plugin refusedCodeInResponses bool + respondWithIP net.IP } type PluginsReturnCode int @@ -136,6 +137,7 @@ func InitPluginsGlobals(pluginsGlobals *PluginsGlobals, proxy *Proxy) error { (*pluginsGlobals).responsePlugins = responsePlugins (*pluginsGlobals).loggingPlugins = loggingPlugins (*pluginsGlobals).refusedCodeInResponses = proxy.refusedCodeInResponses + (*pluginsGlobals).respondWithIP = net.ParseIP(proxy.respondWithIP) return nil } @@ -186,7 +188,7 @@ func (pluginsState *PluginsState) ApplyQueryPlugins(pluginsGlobals *PluginsGloba return packet, ret } if pluginsState.action == PluginsActionReject { - synth, err := RefusedResponseFromMessage(&msg, pluginsGlobals.refusedCodeInResponses) + synth, err := RefusedResponseFromMessage(&msg, pluginsGlobals.refusedCodeInResponses, pluginsGlobals.respondWithIP, pluginsState.cacheMinTTL) if err != nil { return nil, err } @@ -234,7 +236,7 @@ func (pluginsState *PluginsState) ApplyResponsePlugins(pluginsGlobals *PluginsGl return packet, ret } if pluginsState.action == PluginsActionReject { - synth, err := RefusedResponseFromMessage(&msg, pluginsGlobals.refusedCodeInResponses) + synth, err := RefusedResponseFromMessage(&msg, pluginsGlobals.refusedCodeInResponses, pluginsGlobals.respondWithIP, pluginsState.cacheMinTTL) if err != nil { return nil, err } diff --git a/dnscrypt-proxy/proxy.go b/dnscrypt-proxy/proxy.go index 9cf97add..8759c2ae 100644 --- a/dnscrypt-proxy/proxy.go +++ b/dnscrypt-proxy/proxy.go @@ -64,6 +64,7 @@ type Proxy struct { logMaxAge int logMaxBackups int refusedCodeInResponses bool + respondWithIP string showCerts bool }