2018-01-10 12:01:49 +01:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
2018-01-10 13:40:50 +01:00
|
|
|
"flag"
|
2018-01-10 12:01:49 +01:00
|
|
|
"fmt"
|
2018-01-18 12:22:25 +01:00
|
|
|
"os"
|
2018-01-14 00:08:46 +01:00
|
|
|
"strings"
|
2018-01-10 12:01:49 +01:00
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/BurntSushi/toml"
|
2018-01-11 11:50:54 +01:00
|
|
|
"github.com/jedisct1/dlog"
|
2018-01-10 12:01:49 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
type Config struct {
|
2018-01-19 20:06:04 +01:00
|
|
|
LogLevel int `toml:"log_level"`
|
|
|
|
LogFile *string `toml:"log_file"`
|
|
|
|
UseSyslog bool `toml:"use_syslog"`
|
2018-01-18 13:01:16 +01:00
|
|
|
ServerNames []string `toml:"server_names"`
|
|
|
|
ListenAddresses []string `toml:"listen_addresses"`
|
|
|
|
Daemonize bool
|
|
|
|
ForceTCP bool `toml:"force_tcp"`
|
|
|
|
Timeout int `toml:"timeout_ms"`
|
|
|
|
CertRefreshDelay int `toml:"cert_refresh_delay"`
|
2018-01-21 18:10:38 +01:00
|
|
|
CertIgnoreTimestamp bool `toml:"cert_ignore_timestamp"`
|
2018-01-18 13:01:16 +01:00
|
|
|
BlockIPv6 bool `toml:"block_ipv6"`
|
|
|
|
Cache bool
|
|
|
|
CacheSize int `toml:"cache_size"`
|
|
|
|
CacheNegTTL uint32 `toml:"cache_neg_ttl"`
|
|
|
|
CacheMinTTL uint32 `toml:"cache_min_ttl"`
|
|
|
|
CacheMaxTTL uint32 `toml:"cache_max_ttl"`
|
|
|
|
QueryLog QueryLogConfig `toml:"query_log"`
|
2018-01-20 16:59:40 +01:00
|
|
|
NxLog NxLogConfig `toml:"nx_log"`
|
2018-01-18 13:01:16 +01:00
|
|
|
BlockName BlockNameConfig `toml:"blacklist"`
|
2018-01-21 16:07:44 +01:00
|
|
|
BlockIP BlockIPConfig `toml:"ip_blacklist"`
|
2018-01-18 13:01:16 +01:00
|
|
|
ForwardFile string `toml:"forwarding_rules"`
|
2018-01-25 17:41:36 +01:00
|
|
|
ServersConfig map[string]ServerConfig `toml:"static"`
|
2018-01-18 13:01:16 +01:00
|
|
|
SourcesConfig map[string]SourceConfig `toml:"sources"`
|
|
|
|
SourceRequireDNSSEC bool `toml:"require_dnssec"`
|
|
|
|
SourceRequireNoLog bool `toml:"require_nolog"`
|
2018-01-19 16:38:43 +01:00
|
|
|
SourceIPv4 bool `toml:"ipv4_servers"`
|
|
|
|
SourceIPv6 bool `toml:"ipv6_servers"`
|
2018-01-24 16:51:26 +01:00
|
|
|
MaxClients uint32 `toml:"max_clients"`
|
2018-01-30 15:46:21 +01:00
|
|
|
FallbackResolver string `toml:"fallback_resolver"`
|
2018-01-30 17:37:35 +01:00
|
|
|
IgnoreSystemDNS bool `toml:"ignore_system_dns"`
|
2018-01-10 12:01:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func newConfig() Config {
|
|
|
|
return Config{
|
2018-01-21 18:10:38 +01:00
|
|
|
LogLevel: int(dlog.LogLevel()),
|
|
|
|
ListenAddresses: []string{"127.0.0.1:53"},
|
|
|
|
Timeout: 2500,
|
|
|
|
CertRefreshDelay: 30,
|
|
|
|
CertIgnoreTimestamp: false,
|
|
|
|
Cache: true,
|
|
|
|
CacheSize: 256,
|
|
|
|
CacheNegTTL: 60,
|
|
|
|
CacheMinTTL: 60,
|
|
|
|
CacheMaxTTL: 8600,
|
|
|
|
SourceRequireNoLog: true,
|
|
|
|
SourceIPv4: true,
|
|
|
|
SourceIPv6: false,
|
2018-01-24 16:51:26 +01:00
|
|
|
MaxClients: 100,
|
2018-01-30 15:46:21 +01:00
|
|
|
FallbackResolver: DefaultFallbackResolver,
|
2018-01-30 17:37:35 +01:00
|
|
|
IgnoreSystemDNS: false,
|
2018-01-10 12:01:49 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type ServerConfig struct {
|
2018-01-22 09:59:32 +01:00
|
|
|
Stamp string
|
2018-01-10 12:01:49 +01:00
|
|
|
}
|
|
|
|
|
2018-01-13 23:52:44 +01:00
|
|
|
type SourceConfig struct {
|
|
|
|
URL string
|
|
|
|
MinisignKeyStr string `toml:"minisign_key"`
|
|
|
|
CacheFile string `toml:"cache_file"`
|
|
|
|
FormatStr string `toml:"format"`
|
|
|
|
RefreshDelay int `toml:"refresh_delay"`
|
2018-01-20 16:59:40 +01:00
|
|
|
Prefix string
|
2018-01-13 23:52:44 +01:00
|
|
|
}
|
|
|
|
|
2018-01-16 00:23:16 +01:00
|
|
|
type QueryLogConfig struct {
|
2018-01-20 13:27:37 +01:00
|
|
|
File string
|
|
|
|
Format string
|
|
|
|
IgnoredQtypes []string `toml:"ignored_qtypes"`
|
2018-01-16 00:23:16 +01:00
|
|
|
}
|
|
|
|
|
2018-01-20 16:59:40 +01:00
|
|
|
type NxLogConfig struct {
|
|
|
|
File string
|
|
|
|
Format string
|
|
|
|
}
|
|
|
|
|
2018-01-17 02:40:47 +01:00
|
|
|
type BlockNameConfig struct {
|
2018-01-17 17:03:42 +01:00
|
|
|
File string `toml:"blacklist_file"`
|
|
|
|
LogFile string `toml:"log_file"`
|
|
|
|
Format string `toml:"log_format"`
|
2018-01-17 02:40:47 +01:00
|
|
|
}
|
|
|
|
|
2018-01-21 16:07:44 +01:00
|
|
|
type BlockIPConfig struct {
|
|
|
|
File string `toml:"blacklist_file"`
|
|
|
|
LogFile string `toml:"log_file"`
|
|
|
|
Format string `toml:"log_format"`
|
|
|
|
}
|
|
|
|
|
2018-01-17 11:28:43 +01:00
|
|
|
func ConfigLoad(proxy *Proxy, svcFlag *string, config_file string) error {
|
2018-01-21 22:18:20 +01:00
|
|
|
version := flag.Bool("version", false, "Prints current proxy version")
|
|
|
|
configFile := flag.String("config", "dnscrypt-proxy.toml", "Path to the configuration file")
|
2018-01-21 18:02:32 +01:00
|
|
|
resolve := flag.String("resolve", "", "resolve a name using system libraries")
|
2018-01-30 17:51:47 +01:00
|
|
|
list := flag.Bool("list", false, "print the list of available resolvers")
|
2018-01-10 13:40:50 +01:00
|
|
|
flag.Parse()
|
2018-01-17 11:28:43 +01:00
|
|
|
if *svcFlag == "stop" || *svcFlag == "uninstall" {
|
|
|
|
return nil
|
|
|
|
}
|
2018-01-18 12:22:25 +01:00
|
|
|
if *version {
|
|
|
|
fmt.Println(AppVersion)
|
|
|
|
os.Exit(0)
|
|
|
|
}
|
2018-01-21 18:02:32 +01:00
|
|
|
if resolve != nil && len(*resolve) > 0 {
|
|
|
|
Resolve(*resolve)
|
|
|
|
os.Exit(0)
|
|
|
|
}
|
2018-01-10 12:01:49 +01:00
|
|
|
config := newConfig()
|
2018-01-10 13:40:50 +01:00
|
|
|
if _, err := toml.DecodeFile(*configFile, &config); err != nil {
|
2018-01-10 12:01:49 +01:00
|
|
|
return err
|
|
|
|
}
|
2018-01-19 20:06:04 +01:00
|
|
|
if config.LogLevel >= 0 && config.LogLevel < int(dlog.SeverityLast) {
|
|
|
|
dlog.SetLogLevel(dlog.Severity(config.LogLevel))
|
|
|
|
}
|
2018-01-20 13:56:26 +01:00
|
|
|
if dlog.LogLevel() <= dlog.SeverityDebug && os.Getenv("DEBUG") == "" {
|
|
|
|
dlog.SetLogLevel(dlog.SeverityInfo)
|
|
|
|
}
|
2018-01-19 20:06:04 +01:00
|
|
|
if config.UseSyslog {
|
|
|
|
dlog.UseSyslog(true)
|
|
|
|
} else if config.LogFile != nil {
|
|
|
|
dlog.UseLogFile(*config.LogFile)
|
|
|
|
}
|
2018-01-30 15:46:21 +01:00
|
|
|
proxy.xTransport.fallbackResolver = config.FallbackResolver
|
2018-01-30 17:37:35 +01:00
|
|
|
if len(config.FallbackResolver) > 0 {
|
|
|
|
proxy.xTransport.ignoreSystemDNS = config.IgnoreSystemDNS
|
|
|
|
}
|
2018-01-10 12:01:49 +01:00
|
|
|
proxy.timeout = time.Duration(config.Timeout) * time.Millisecond
|
2018-01-24 16:51:26 +01:00
|
|
|
proxy.maxClients = config.MaxClients
|
2018-01-10 12:01:49 +01:00
|
|
|
proxy.mainProto = "udp"
|
|
|
|
if config.ForceTCP {
|
|
|
|
proxy.mainProto = "tcp"
|
|
|
|
}
|
|
|
|
proxy.certRefreshDelay = time.Duration(config.CertRefreshDelay) * time.Minute
|
2018-01-17 17:22:29 +01:00
|
|
|
proxy.certRefreshDelayAfterFailure = time.Duration(10 * time.Second)
|
2018-01-21 18:10:38 +01:00
|
|
|
proxy.certIgnoreTimestamp = config.CertIgnoreTimestamp
|
2018-01-10 12:01:49 +01:00
|
|
|
if len(config.ListenAddresses) == 0 {
|
2018-01-24 14:44:32 +01:00
|
|
|
dlog.Debugf("No local IP/port configured")
|
2018-01-10 12:01:49 +01:00
|
|
|
}
|
|
|
|
proxy.listenAddresses = config.ListenAddresses
|
|
|
|
proxy.daemonize = config.Daemonize
|
2018-01-10 17:23:20 +01:00
|
|
|
proxy.pluginBlockIPv6 = config.BlockIPv6
|
2018-01-10 18:32:05 +01:00
|
|
|
proxy.cache = config.Cache
|
2018-01-10 19:32:56 +01:00
|
|
|
proxy.cacheSize = config.CacheSize
|
|
|
|
proxy.cacheNegTTL = config.CacheNegTTL
|
|
|
|
proxy.cacheMinTTL = config.CacheMinTTL
|
|
|
|
proxy.cacheMaxTTL = config.CacheMaxTTL
|
2018-01-17 17:03:42 +01:00
|
|
|
|
2018-01-16 00:23:16 +01:00
|
|
|
if len(config.QueryLog.Format) == 0 {
|
|
|
|
config.QueryLog.Format = "tsv"
|
|
|
|
} else {
|
|
|
|
config.QueryLog.Format = strings.ToLower(config.QueryLog.Format)
|
|
|
|
}
|
2018-01-16 18:10:04 +01:00
|
|
|
if config.QueryLog.Format != "tsv" && config.QueryLog.Format != "ltsv" {
|
2018-01-16 00:23:16 +01:00
|
|
|
return errors.New("Unsupported query log format")
|
|
|
|
}
|
|
|
|
proxy.queryLogFile = config.QueryLog.File
|
|
|
|
proxy.queryLogFormat = config.QueryLog.Format
|
2018-01-20 13:27:37 +01:00
|
|
|
proxy.queryLogIgnoredQtypes = config.QueryLog.IgnoredQtypes
|
2018-01-17 17:03:42 +01:00
|
|
|
|
2018-01-20 16:59:40 +01:00
|
|
|
if len(config.NxLog.Format) == 0 {
|
|
|
|
config.NxLog.Format = "tsv"
|
|
|
|
} else {
|
|
|
|
config.NxLog.Format = strings.ToLower(config.NxLog.Format)
|
|
|
|
}
|
|
|
|
if config.NxLog.Format != "tsv" && config.NxLog.Format != "ltsv" {
|
|
|
|
return errors.New("Unsupported NX log format")
|
|
|
|
}
|
|
|
|
proxy.nxLogFile = config.NxLog.File
|
|
|
|
proxy.nxLogFormat = config.NxLog.Format
|
|
|
|
|
2018-01-17 17:03:42 +01:00
|
|
|
if len(config.BlockName.Format) == 0 {
|
|
|
|
config.BlockName.Format = "tsv"
|
|
|
|
} else {
|
|
|
|
config.BlockName.Format = strings.ToLower(config.BlockName.Format)
|
|
|
|
}
|
|
|
|
if config.BlockName.Format != "tsv" && config.BlockName.Format != "ltsv" {
|
|
|
|
return errors.New("Unsupported block log format")
|
|
|
|
}
|
2018-01-17 02:40:47 +01:00
|
|
|
proxy.blockNameFile = config.BlockName.File
|
2018-01-17 17:03:42 +01:00
|
|
|
proxy.blockNameFormat = config.BlockName.Format
|
|
|
|
proxy.blockNameLogFile = config.BlockName.LogFile
|
|
|
|
|
2018-01-21 16:07:44 +01:00
|
|
|
if len(config.BlockIP.Format) == 0 {
|
|
|
|
config.BlockIP.Format = "tsv"
|
|
|
|
} else {
|
|
|
|
config.BlockIP.Format = strings.ToLower(config.BlockIP.Format)
|
|
|
|
}
|
|
|
|
if config.BlockIP.Format != "tsv" && config.BlockIP.Format != "ltsv" {
|
|
|
|
return errors.New("Unsupported IP block log format")
|
|
|
|
}
|
|
|
|
proxy.blockIPFile = config.BlockIP.File
|
|
|
|
proxy.blockIPFormat = config.BlockIP.Format
|
|
|
|
proxy.blockIPLogFile = config.BlockIP.LogFile
|
|
|
|
|
2018-01-17 09:44:03 +01:00
|
|
|
proxy.forwardFile = config.ForwardFile
|
2018-01-18 13:01:16 +01:00
|
|
|
|
|
|
|
requiredProps := ServerInformalProperties(0)
|
|
|
|
if config.SourceRequireDNSSEC {
|
|
|
|
requiredProps |= ServerInformalPropertyDNSSEC
|
|
|
|
}
|
|
|
|
if config.SourceRequireNoLog {
|
|
|
|
requiredProps |= ServerInformalPropertyNoLog
|
|
|
|
}
|
|
|
|
|
2018-01-20 16:59:40 +01:00
|
|
|
for cfgSourceName, cfgSource := range config.SourcesConfig {
|
|
|
|
if cfgSource.URL == "" {
|
|
|
|
return fmt.Errorf("Missing URL for source [%s]", cfgSourceName)
|
2018-01-13 23:52:44 +01:00
|
|
|
}
|
2018-01-20 16:59:40 +01:00
|
|
|
if cfgSource.MinisignKeyStr == "" {
|
|
|
|
return fmt.Errorf("Missing Minisign key for source [%s]", cfgSourceName)
|
2018-01-13 23:52:44 +01:00
|
|
|
}
|
2018-01-20 16:59:40 +01:00
|
|
|
if cfgSource.CacheFile == "" {
|
|
|
|
return fmt.Errorf("Missing cache file for source [%s]", cfgSourceName)
|
2018-01-13 23:52:44 +01:00
|
|
|
}
|
2018-01-20 16:59:40 +01:00
|
|
|
if cfgSource.FormatStr == "" {
|
|
|
|
return fmt.Errorf("Missing format for source [%s]", cfgSourceName)
|
2018-01-13 23:52:44 +01:00
|
|
|
}
|
2018-01-20 16:59:40 +01:00
|
|
|
if cfgSource.RefreshDelay <= 0 {
|
|
|
|
cfgSource.RefreshDelay = 24
|
2018-01-13 23:52:44 +01:00
|
|
|
}
|
2018-01-30 15:46:21 +01:00
|
|
|
source, sourceUrlsToPrefetch, err := NewSource(proxy.xTransport, cfgSource.URL, cfgSource.MinisignKeyStr, cfgSource.CacheFile, cfgSource.FormatStr, time.Duration(cfgSource.RefreshDelay)*time.Hour)
|
2018-01-19 00:06:18 +01:00
|
|
|
proxy.urlsToPrefetch = append(proxy.urlsToPrefetch, sourceUrlsToPrefetch...)
|
2018-01-13 23:52:44 +01:00
|
|
|
if err != nil {
|
2018-01-20 16:59:40 +01:00
|
|
|
dlog.Criticalf("Unable use source [%s]: [%s]", cfgSourceName, err)
|
2018-01-13 23:52:44 +01:00
|
|
|
continue
|
|
|
|
}
|
2018-01-20 16:59:40 +01:00
|
|
|
registeredServers, err := source.Parse(cfgSource.Prefix)
|
2018-01-13 23:52:44 +01:00
|
|
|
if err != nil {
|
2018-01-20 16:59:40 +01:00
|
|
|
dlog.Criticalf("Unable use source [%s]: [%s]", cfgSourceName, err)
|
2018-01-13 23:52:44 +01:00
|
|
|
continue
|
|
|
|
}
|
2018-01-14 00:08:46 +01:00
|
|
|
for _, registeredServer := range registeredServers {
|
2018-01-18 13:01:16 +01:00
|
|
|
if len(config.ServerNames) > 0 {
|
|
|
|
if !includesName(config.ServerNames, registeredServer.name) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
} else if registeredServer.stamp.props&requiredProps != requiredProps {
|
2018-01-14 00:08:46 +01:00
|
|
|
continue
|
|
|
|
}
|
2018-01-19 16:38:43 +01:00
|
|
|
if config.SourceIPv4 || config.SourceIPv6 {
|
|
|
|
isIPv4, isIPv6 := true, false
|
|
|
|
if strings.HasPrefix(registeredServer.stamp.serverAddrStr, "[") {
|
|
|
|
isIPv4, isIPv6 = false, true
|
|
|
|
}
|
|
|
|
if !(config.SourceIPv4 == isIPv4 || config.SourceIPv6 == isIPv6) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
2018-01-19 22:37:05 +01:00
|
|
|
dlog.Debugf("Adding [%s] to the set of wanted resolvers", registeredServer.name)
|
2018-01-14 00:08:46 +01:00
|
|
|
proxy.registeredServers = append(proxy.registeredServers, registeredServer)
|
|
|
|
}
|
2018-01-10 12:01:49 +01:00
|
|
|
}
|
2018-01-17 21:41:36 +01:00
|
|
|
if len(config.ServerNames) == 0 {
|
|
|
|
for serverName := range config.ServersConfig {
|
|
|
|
config.ServerNames = append(config.ServerNames, serverName)
|
|
|
|
}
|
|
|
|
}
|
2018-01-10 12:01:49 +01:00
|
|
|
for _, serverName := range config.ServerNames {
|
|
|
|
serverConfig, ok := config.ServersConfig[serverName]
|
|
|
|
if !ok {
|
2018-01-14 00:08:46 +01:00
|
|
|
continue
|
2018-01-10 12:01:49 +01:00
|
|
|
}
|
|
|
|
var stamp ServerStamp
|
|
|
|
var err error
|
2018-01-22 10:02:06 +01:00
|
|
|
if len(serverConfig.Stamp) == 0 {
|
2018-01-22 09:59:32 +01:00
|
|
|
dlog.Fatalf("Missing stamp for the static [%s] definition", serverName)
|
2018-01-20 14:13:11 +01:00
|
|
|
}
|
2018-01-22 10:02:06 +01:00
|
|
|
stamp, err = NewServerStampFromString(serverConfig.Stamp)
|
2018-01-20 14:13:11 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
2018-01-10 12:01:49 +01:00
|
|
|
}
|
|
|
|
proxy.registeredServers = append(proxy.registeredServers,
|
|
|
|
RegisteredServer{name: serverName, stamp: stamp})
|
|
|
|
}
|
2018-01-13 23:52:44 +01:00
|
|
|
if len(proxy.registeredServers) == 0 {
|
|
|
|
return errors.New("No servers configured")
|
|
|
|
}
|
2018-01-30 17:51:47 +01:00
|
|
|
if *list {
|
|
|
|
for _, registeredServer := range proxy.registeredServers {
|
|
|
|
fmt.Println(registeredServer.name)
|
|
|
|
}
|
|
|
|
os.Exit(0)
|
|
|
|
}
|
2018-01-10 12:01:49 +01:00
|
|
|
return nil
|
|
|
|
}
|
2018-01-14 00:08:46 +01:00
|
|
|
|
|
|
|
func includesName(names []string, name string) bool {
|
|
|
|
for _, found := range names {
|
|
|
|
if strings.EqualFold(found, name) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|