From ed60976dd21378f49430c32acee0b006fbcb3695 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Sun, 4 Feb 2018 13:35:40 +0100 Subject: [PATCH] Infer TTL from Date: and Expire: headers Unfortunately, Google DNS sets Expire: to the same value as Date: So we may want to use Cache-Control instead. --- dnscrypt-proxy/plugins.go | 5 ++++- dnscrypt-proxy/proxy.go | 31 ++++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/dnscrypt-proxy/plugins.go b/dnscrypt-proxy/plugins.go index 1ea4d748..9774ace0 100644 --- a/dnscrypt-proxy/plugins.go +++ b/dnscrypt-proxy/plugins.go @@ -148,7 +148,7 @@ func (pluginsState *PluginsState) ApplyQueryPlugins(pluginsGlobals *PluginsGloba return packet2, nil } -func (pluginsState *PluginsState) ApplyResponsePlugins(pluginsGlobals *PluginsGlobals, packet []byte) ([]byte, error) { +func (pluginsState *PluginsState) ApplyResponsePlugins(pluginsGlobals *PluginsGlobals, packet []byte, ttl *uint32) ([]byte, error) { if len(*pluginsGlobals.responsePlugins) == 0 { return packet, nil } @@ -177,6 +177,9 @@ func (pluginsState *PluginsState) ApplyResponsePlugins(pluginsGlobals *PluginsGl } } pluginsGlobals.RUnlock() + if ttl != nil { + setMaxTTL(&msg, *ttl) + } packet2, err := msg.PackBuffer(packet) if err != nil { return packet, err diff --git a/dnscrypt-proxy/proxy.go b/dnscrypt-proxy/proxy.go index b8e14bf3..aa34e820 100644 --- a/dnscrypt-proxy/proxy.go +++ b/dnscrypt-proxy/proxy.go @@ -5,6 +5,7 @@ import ( "io/ioutil" "math/rand" "net" + "net/http" "sync/atomic" "time" @@ -263,6 +264,7 @@ func (proxy *Proxy) processIncomingQuery(serverInfo *ServerInfo, clientProto str } } if len(response) == 0 { + var ttl *uint32 if serverInfo.Proto == StampProtoTypeDNSCrypt { encryptedQuery, clientNonce, err := proxy.Encrypt(serverInfo, query, serverProto) if err != nil { @@ -293,6 +295,7 @@ func (proxy *Proxy) processIncomingQuery(serverInfo *ServerInfo, clientProto str if len(response) >= MinDNSPacketSize { SetTransactionID(response, tid) } + ttl = ttlFromHTTPResponse(proxy, resp) } else { dlog.Fatal("Unsupported protocol") } @@ -300,7 +303,7 @@ func (proxy *Proxy) processIncomingQuery(serverInfo *ServerInfo, clientProto str serverInfo.noticeFailure(proxy) return } - response, _ = pluginsState.ApplyResponsePlugins(&proxy.pluginsGlobals, response) + response, _ = pluginsState.ApplyResponsePlugins(&proxy.pluginsGlobals, response, ttl) } if len(response) < MinDNSPacketSize || len(response) > MaxDNSPacketSize { serverInfo.noticeFailure(proxy) @@ -329,3 +332,29 @@ func (proxy *Proxy) processIncomingQuery(serverInfo *ServerInfo, clientProto str } serverInfo.noticeSuccess(proxy) } + +func ttlFromHTTPResponse(proxy *Proxy, resp *http.Response) *uint32 { + expiresStr, dateStr := resp.Header.Get("Expires"), resp.Header.Get("Date") + if len(expiresStr) == 0 || len(dateStr) == 0 { + return nil + } + expires, err := http.ParseTime(expiresStr) + if err != nil { + return nil + } + date, err := http.ParseTime(dateStr) + if err != nil { + return nil + } + if !expires.After(date) { + return nil + } + foundTTL := uint32(expires.Sub(date).Seconds()) + if foundTTL < proxy.cacheMaxTTL { + foundTTL = proxy.cacheMinTTL + } + if foundTTL > proxy.cacheMaxTTL { + foundTTL = proxy.cacheMaxTTL + } + return &foundTTL +}