Implement query logging
This commit is contained in:
parent
3ffad7be44
commit
5685844f43
|
@ -24,6 +24,7 @@ type Config struct {
|
|||
CacheNegTTL uint32 `toml:"cache_neg_ttl"`
|
||||
CacheMinTTL uint32 `toml:"cache_min_ttl"`
|
||||
CacheMaxTTL uint32 `toml:"cache_max_ttl"`
|
||||
QueryLog QueryLogConfig `toml:"query_log"`
|
||||
ServersConfig map[string]ServerConfig `toml:"servers"`
|
||||
SourcesConfig map[string]SourceConfig `toml:"sources"`
|
||||
}
|
||||
|
@ -58,6 +59,11 @@ type SourceConfig struct {
|
|||
RefreshDelay int `toml:"refresh_delay"`
|
||||
}
|
||||
|
||||
type QueryLogConfig struct {
|
||||
File string
|
||||
Format string
|
||||
}
|
||||
|
||||
func ConfigLoad(proxy *Proxy, config_file string) error {
|
||||
configFile := flag.String("config", "dnscrypt-proxy.toml", "path to the configuration file")
|
||||
flag.Parse()
|
||||
|
@ -82,6 +88,16 @@ func ConfigLoad(proxy *Proxy, config_file string) error {
|
|||
proxy.cacheNegTTL = config.CacheNegTTL
|
||||
proxy.cacheMinTTL = config.CacheMinTTL
|
||||
proxy.cacheMaxTTL = config.CacheMaxTTL
|
||||
if len(config.QueryLog.Format) == 0 {
|
||||
config.QueryLog.Format = "tsv"
|
||||
} else {
|
||||
config.QueryLog.Format = strings.ToLower(config.QueryLog.Format)
|
||||
}
|
||||
if config.QueryLog.Format != "tsv" {
|
||||
return errors.New("Unsupported query log format")
|
||||
}
|
||||
proxy.queryLogFile = config.QueryLog.File
|
||||
proxy.queryLogFormat = config.QueryLog.Format
|
||||
if len(config.ServerNames) == 0 {
|
||||
for serverName := range config.ServersConfig {
|
||||
config.ServerNames = append(config.ServerNames, serverName)
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
## List of servers to use
|
||||
## If this line is commented, all registered servers will be used
|
||||
|
||||
server_names = ["dnscrypt.org-fr", "adguard-dns", "fvz-anyone"]
|
||||
server_names = ["dnscrypt.org-fr"]
|
||||
|
||||
|
||||
## List of local addresses and ports to listen to. Can be IPv4 and/or IPv6.
|
||||
|
@ -48,6 +48,18 @@ cert_refresh_delay = 30
|
|||
block_ipv6 = false
|
||||
|
||||
|
||||
############## Query logging ##############
|
||||
|
||||
## Log client queries to a file
|
||||
|
||||
[query_log]
|
||||
### Full path to the query log file
|
||||
file = "/tmp/query.log"
|
||||
|
||||
### Query log format (currently supported: tsv)
|
||||
format = "tsv"
|
||||
|
||||
|
||||
############## DNS Cache ##############
|
||||
|
||||
## Enable a basic DNS cache to reduce outgoing traffic
|
||||
|
|
|
@ -28,6 +28,8 @@ type Proxy struct {
|
|||
cacheNegTTL uint32
|
||||
cacheMinTTL uint32
|
||||
cacheMaxTTL uint32
|
||||
queryLogFile string
|
||||
queryLogFormat string
|
||||
pluginsGlobals PluginsGlobals
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,10 @@ import (
|
|||
"crypto/sha512"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
@ -47,6 +50,9 @@ type PluginsState struct {
|
|||
|
||||
func InitPluginsGlobals(pluginsGlobals *PluginsGlobals, proxy *Proxy) error {
|
||||
queryPlugins := &[]Plugin{}
|
||||
if len(proxy.queryLogFile) != 0 {
|
||||
*queryPlugins = append(*queryPlugins, Plugin(new(PluginQueryLog)))
|
||||
}
|
||||
if proxy.pluginBlockIPv6 {
|
||||
*queryPlugins = append(*queryPlugins, Plugin(new(PluginBlockIPv6)))
|
||||
}
|
||||
|
@ -184,7 +190,7 @@ func (plugin *PluginBlockIPv6) Name() string {
|
|||
}
|
||||
|
||||
func (plugin *PluginBlockIPv6) Description() string {
|
||||
return "Immediately return a synthetic response to AAAA queries"
|
||||
return "Immediately return a synthetic response to AAAA queries."
|
||||
}
|
||||
|
||||
func (plugin *PluginBlockIPv6) Init(proxy *Proxy) error {
|
||||
|
@ -219,17 +225,28 @@ func (plugin *PluginBlockIPv6) Eval(pluginsState *PluginsState, msg *dns.Msg) er
|
|||
|
||||
// -------- querylog plugin --------
|
||||
|
||||
type PluginQueryLog struct{}
|
||||
type PluginQueryLog struct {
|
||||
sync.Mutex
|
||||
outFd *os.File
|
||||
}
|
||||
|
||||
func (plugin *PluginQueryLog) Name() string {
|
||||
return "querylog"
|
||||
}
|
||||
|
||||
func (plugin *PluginQueryLog) Description() string {
|
||||
return "Log DNS queries"
|
||||
return "Log DNS queries."
|
||||
}
|
||||
|
||||
func (plugin *PluginQueryLog) Init(proxy *Proxy) error {
|
||||
plugin.Lock()
|
||||
defer plugin.Unlock()
|
||||
outFd, err := os.OpenFile(proxy.queryLogFile, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
plugin.outFd = outFd
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -242,6 +259,36 @@ func (plugin *PluginQueryLog) Reload() error {
|
|||
}
|
||||
|
||||
func (plugin *PluginQueryLog) Eval(pluginsState *PluginsState, msg *dns.Msg) error {
|
||||
questions := msg.Question
|
||||
if len(questions) == 0 {
|
||||
return nil
|
||||
}
|
||||
question := questions[0]
|
||||
now := time.Now()
|
||||
year, month, day := now.Date()
|
||||
hour, minute, second := now.Clock()
|
||||
tsStr := fmt.Sprintf("[%d-%02d-%02d %02d:%02d:%02d]", year, int(month), day, hour, minute, second)
|
||||
var clientIPStr string
|
||||
if pluginsState.clientProto == "udp" {
|
||||
clientIPStr = (*pluginsState.clientAddr).(*net.UDPAddr).IP.String()
|
||||
} else {
|
||||
clientIPStr = (*pluginsState.clientAddr).(*net.TCPAddr).IP.String()
|
||||
}
|
||||
qName := question.Name
|
||||
if len(qName) > 1 && strings.HasSuffix(qName, ".") {
|
||||
qName = qName[0 : len(qName)-1]
|
||||
}
|
||||
qType, ok := dns.TypeToString[question.Qtype]
|
||||
if !ok {
|
||||
qType = string(qType)
|
||||
}
|
||||
line := fmt.Sprintf("%s\t%s\t%s\t%s\n", tsStr, clientIPStr, qName, qType)
|
||||
plugin.Lock()
|
||||
if plugin.outFd == nil {
|
||||
return errors.New("Log file not initialized")
|
||||
}
|
||||
plugin.outFd.WriteString(line)
|
||||
defer plugin.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue