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-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 {
|
|
|
|
ServerNames []string `toml:"server_names"`
|
|
|
|
ListenAddresses []string `toml:"listen_addresses"`
|
|
|
|
Daemonize bool
|
2018-01-10 18:32:05 +01:00
|
|
|
ForceTCP bool `toml:"force_tcp"`
|
|
|
|
Timeout int `toml:"timeout_ms"`
|
|
|
|
CertRefreshDelay int `toml:"cert_refresh_delay"`
|
|
|
|
BlockIPv6 bool `toml:"block_ipv6"`
|
|
|
|
Cache bool
|
2018-01-10 19:32:56 +01:00
|
|
|
CacheSize int `toml:"cache_size"`
|
|
|
|
CacheNegTTL uint32 `toml:"cache_neg_ttl"`
|
|
|
|
CacheMinTTL uint32 `toml:"cache_min_ttl"`
|
|
|
|
CacheMaxTTL uint32 `toml:"cache_max_ttl"`
|
2018-01-16 00:23:16 +01:00
|
|
|
QueryLog QueryLogConfig `toml:"query_log"`
|
2018-01-17 17:03:42 +01:00
|
|
|
BlockName BlockNameConfig `toml:"blacklist"`
|
2018-01-17 09:44:03 +01:00
|
|
|
ForwardFile string `toml:"forwarding_rules"`
|
2018-01-10 12:01:49 +01:00
|
|
|
ServersConfig map[string]ServerConfig `toml:"servers"`
|
2018-01-13 23:52:44 +01:00
|
|
|
SourcesConfig map[string]SourceConfig `toml:"sources"`
|
2018-01-10 12:01:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func newConfig() Config {
|
|
|
|
return Config{
|
|
|
|
ListenAddresses: []string{"127.0.0.1:53"},
|
|
|
|
Timeout: 2500,
|
|
|
|
CertRefreshDelay: 30,
|
2018-01-10 19:32:56 +01:00
|
|
|
Cache: true,
|
|
|
|
CacheSize: 256,
|
|
|
|
CacheNegTTL: 60,
|
|
|
|
CacheMinTTL: 60,
|
|
|
|
CacheMaxTTL: 8600,
|
2018-01-10 12:01:49 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type ServerConfig struct {
|
|
|
|
Stamp string
|
|
|
|
ProviderName string `toml:"provider_name"`
|
|
|
|
Address string
|
|
|
|
PublicKey string `toml:"public_key"`
|
|
|
|
NoLog bool `toml:"no_log"`
|
|
|
|
DNSSEC bool `toml:"dnssec"`
|
|
|
|
}
|
|
|
|
|
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-16 00:23:16 +01:00
|
|
|
type QueryLogConfig 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-17 11:28:43 +01:00
|
|
|
func ConfigLoad(proxy *Proxy, svcFlag *string, config_file string) error {
|
2018-01-13 00:14:12 +01:00
|
|
|
configFile := flag.String("config", "dnscrypt-proxy.toml", "path to the configuration file")
|
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-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
|
|
|
|
}
|
|
|
|
proxy.timeout = time.Duration(config.Timeout) * time.Millisecond
|
|
|
|
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-10 12:01:49 +01:00
|
|
|
if len(config.ListenAddresses) == 0 {
|
|
|
|
return errors.New("No local IP/port configured")
|
|
|
|
}
|
|
|
|
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-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-17 09:44:03 +01:00
|
|
|
proxy.forwardFile = config.ForwardFile
|
2018-01-10 12:01:49 +01:00
|
|
|
if len(config.ServerNames) == 0 {
|
|
|
|
for serverName := range config.ServersConfig {
|
|
|
|
config.ServerNames = append(config.ServerNames, serverName)
|
|
|
|
}
|
|
|
|
}
|
2018-01-13 23:52:44 +01:00
|
|
|
for sourceName, source := range config.SourcesConfig {
|
|
|
|
if source.URL == "" {
|
|
|
|
return fmt.Errorf("Missing URL for source [%s]", sourceName)
|
|
|
|
}
|
|
|
|
if source.MinisignKeyStr == "" {
|
|
|
|
return fmt.Errorf("Missing Minisign key for source [%s]", sourceName)
|
|
|
|
}
|
|
|
|
if source.CacheFile == "" {
|
|
|
|
return fmt.Errorf("Missing cache file for source [%s]", sourceName)
|
|
|
|
}
|
|
|
|
if source.FormatStr == "" {
|
|
|
|
return fmt.Errorf("Missing format for source [%s]", sourceName)
|
|
|
|
}
|
|
|
|
if source.RefreshDelay <= 0 {
|
|
|
|
source.RefreshDelay = 24
|
|
|
|
}
|
|
|
|
source, err := NewSource(source.URL, source.MinisignKeyStr, source.CacheFile, source.FormatStr, time.Duration(source.RefreshDelay)*time.Hour)
|
|
|
|
if err != nil {
|
|
|
|
dlog.Criticalf("Unable use source [%s]: [%s]", sourceName, err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
registeredServers, err := source.Parse()
|
|
|
|
if err != nil {
|
|
|
|
dlog.Criticalf("Unable use source [%s]: [%s]", sourceName, err)
|
|
|
|
continue
|
|
|
|
}
|
2018-01-14 00:08:46 +01:00
|
|
|
for _, registeredServer := range registeredServers {
|
|
|
|
if !includesName(config.ServerNames, registeredServer.name) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
dlog.Infof("Adding [%s] to the set of wanted resolvers", registeredServer.name)
|
|
|
|
proxy.registeredServers = append(proxy.registeredServers, registeredServer)
|
|
|
|
}
|
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
|
|
|
|
if len(serverConfig.Stamp) > 0 {
|
2018-01-11 11:50:54 +01:00
|
|
|
dlog.Fatal("Stamps are not implemented yet")
|
2018-01-10 12:01:49 +01:00
|
|
|
} else {
|
|
|
|
stamp, err = NewServerStampFromLegacy(serverConfig.Address, serverConfig.PublicKey, serverConfig.ProviderName)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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-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
|
|
|
|
}
|