Skip to content

Commit 5685844

Browse files
committedJan 15, 2018
Implement query logging
1 parent 3ffad7b commit 5685844

File tree

4 files changed

+81
-4
lines changed

4 files changed

+81
-4
lines changed
 

‎dnscrypt-proxy/config.go

+16
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ type Config struct {
2424
CacheNegTTL uint32 `toml:"cache_neg_ttl"`
2525
CacheMinTTL uint32 `toml:"cache_min_ttl"`
2626
CacheMaxTTL uint32 `toml:"cache_max_ttl"`
27+
QueryLog QueryLogConfig `toml:"query_log"`
2728
ServersConfig map[string]ServerConfig `toml:"servers"`
2829
SourcesConfig map[string]SourceConfig `toml:"sources"`
2930
}
@@ -58,6 +59,11 @@ type SourceConfig struct {
5859
RefreshDelay int `toml:"refresh_delay"`
5960
}
6061

62+
type QueryLogConfig struct {
63+
File string
64+
Format string
65+
}
66+
6167
func ConfigLoad(proxy *Proxy, config_file string) error {
6268
configFile := flag.String("config", "dnscrypt-proxy.toml", "path to the configuration file")
6369
flag.Parse()
@@ -82,6 +88,16 @@ func ConfigLoad(proxy *Proxy, config_file string) error {
8288
proxy.cacheNegTTL = config.CacheNegTTL
8389
proxy.cacheMinTTL = config.CacheMinTTL
8490
proxy.cacheMaxTTL = config.CacheMaxTTL
91+
if len(config.QueryLog.Format) == 0 {
92+
config.QueryLog.Format = "tsv"
93+
} else {
94+
config.QueryLog.Format = strings.ToLower(config.QueryLog.Format)
95+
}
96+
if config.QueryLog.Format != "tsv" {
97+
return errors.New("Unsupported query log format")
98+
}
99+
proxy.queryLogFile = config.QueryLog.File
100+
proxy.queryLogFormat = config.QueryLog.Format
85101
if len(config.ServerNames) == 0 {
86102
for serverName := range config.ServersConfig {
87103
config.ServerNames = append(config.ServerNames, serverName)

‎dnscrypt-proxy/dnscrypt-proxy.toml

+13-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
## List of servers to use
1212
## If this line is commented, all registered servers will be used
1313

14-
server_names = ["dnscrypt.org-fr", "adguard-dns", "fvz-anyone"]
14+
server_names = ["dnscrypt.org-fr"]
1515

1616

1717
## List of local addresses and ports to listen to. Can be IPv4 and/or IPv6.
@@ -48,6 +48,18 @@ cert_refresh_delay = 30
4848
block_ipv6 = false
4949

5050

51+
############## Query logging ##############
52+
53+
## Log client queries to a file
54+
55+
[query_log]
56+
### Full path to the query log file
57+
file = "/tmp/query.log"
58+
59+
### Query log format (currently supported: tsv)
60+
format = "tsv"
61+
62+
5163
############## DNS Cache ##############
5264

5365
## Enable a basic DNS cache to reduce outgoing traffic

‎dnscrypt-proxy/main.go

+2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ type Proxy struct {
2828
cacheNegTTL uint32
2929
cacheMinTTL uint32
3030
cacheMaxTTL uint32
31+
queryLogFile string
32+
queryLogFormat string
3133
pluginsGlobals PluginsGlobals
3234
}
3335

‎dnscrypt-proxy/plugins.go

+50-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ import (
44
"crypto/sha512"
55
"encoding/binary"
66
"errors"
7+
"fmt"
78
"net"
9+
"os"
10+
"strings"
811
"sync"
912
"time"
1013

@@ -47,6 +50,9 @@ type PluginsState struct {
4750

4851
func InitPluginsGlobals(pluginsGlobals *PluginsGlobals, proxy *Proxy) error {
4952
queryPlugins := &[]Plugin{}
53+
if len(proxy.queryLogFile) != 0 {
54+
*queryPlugins = append(*queryPlugins, Plugin(new(PluginQueryLog)))
55+
}
5056
if proxy.pluginBlockIPv6 {
5157
*queryPlugins = append(*queryPlugins, Plugin(new(PluginBlockIPv6)))
5258
}
@@ -184,7 +190,7 @@ func (plugin *PluginBlockIPv6) Name() string {
184190
}
185191

186192
func (plugin *PluginBlockIPv6) Description() string {
187-
return "Immediately return a synthetic response to AAAA queries"
193+
return "Immediately return a synthetic response to AAAA queries."
188194
}
189195

190196
func (plugin *PluginBlockIPv6) Init(proxy *Proxy) error {
@@ -219,17 +225,28 @@ func (plugin *PluginBlockIPv6) Eval(pluginsState *PluginsState, msg *dns.Msg) er
219225

220226
// -------- querylog plugin --------
221227

222-
type PluginQueryLog struct{}
228+
type PluginQueryLog struct {
229+
sync.Mutex
230+
outFd *os.File
231+
}
223232

224233
func (plugin *PluginQueryLog) Name() string {
225234
return "querylog"
226235
}
227236

228237
func (plugin *PluginQueryLog) Description() string {
229-
return "Log DNS queries"
238+
return "Log DNS queries."
230239
}
231240

232241
func (plugin *PluginQueryLog) Init(proxy *Proxy) error {
242+
plugin.Lock()
243+
defer plugin.Unlock()
244+
outFd, err := os.OpenFile(proxy.queryLogFile, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
245+
if err != nil {
246+
return err
247+
}
248+
plugin.outFd = outFd
249+
233250
return nil
234251
}
235252

@@ -242,6 +259,36 @@ func (plugin *PluginQueryLog) Reload() error {
242259
}
243260

244261
func (plugin *PluginQueryLog) Eval(pluginsState *PluginsState, msg *dns.Msg) error {
262+
questions := msg.Question
263+
if len(questions) == 0 {
264+
return nil
265+
}
266+
question := questions[0]
267+
now := time.Now()
268+
year, month, day := now.Date()
269+
hour, minute, second := now.Clock()
270+
tsStr := fmt.Sprintf("[%d-%02d-%02d %02d:%02d:%02d]", year, int(month), day, hour, minute, second)
271+
var clientIPStr string
272+
if pluginsState.clientProto == "udp" {
273+
clientIPStr = (*pluginsState.clientAddr).(*net.UDPAddr).IP.String()
274+
} else {
275+
clientIPStr = (*pluginsState.clientAddr).(*net.TCPAddr).IP.String()
276+
}
277+
qName := question.Name
278+
if len(qName) > 1 && strings.HasSuffix(qName, ".") {
279+
qName = qName[0 : len(qName)-1]
280+
}
281+
qType, ok := dns.TypeToString[question.Qtype]
282+
if !ok {
283+
qType = string(qType)
284+
}
285+
line := fmt.Sprintf("%s\t%s\t%s\t%s\n", tsStr, clientIPStr, qName, qType)
286+
plugin.Lock()
287+
if plugin.outFd == nil {
288+
return errors.New("Log file not initialized")
289+
}
290+
plugin.outFd.WriteString(line)
291+
defer plugin.Unlock()
245292
return nil
246293
}
247294

0 commit comments

Comments
 (0)