summaryrefslogtreecommitdiff
path: root/internal/config
diff options
context:
space:
mode:
Diffstat (limited to 'internal/config')
-rw-r--r--internal/config/config.go152
1 files changed, 152 insertions, 0 deletions
diff --git a/internal/config/config.go b/internal/config/config.go
new file mode 100644
index 0000000..f2624c2
--- /dev/null
+++ b/internal/config/config.go
@@ -0,0 +1,152 @@
+package config
+
+import (
+ "flag"
+ "fmt"
+
+ "github.com/BurntSushi/toml"
+)
+
+type Config struct {
+ Server ServerConfig `toml:"server"`
+ Cache CacheConfig `toml:"cache"`
+ Resolver ResolverConfig `toml:"resolver"`
+ Blocklist BlocklistConfig `toml:"blocklist"`
+ Log LogConfig `toml:"log"`
+}
+
+type ServerConfig struct {
+ ListenUDP string `toml:"listen_udp"`
+ ListenTCP string `toml:"listen_tcp"`
+ ListenDOH string `toml:"listen_doh"`
+}
+
+type CacheConfig struct {
+ MaxEntries int `toml:"max_entries"`
+ DBPath string `toml:"db_path"`
+}
+
+type ResolverConfig struct {
+ Timeout string `toml:"timeout"`
+ MaxDelegations int `toml:"max_delegations"`
+}
+
+type BlocklistConfig struct {
+ Response string `toml:"response"`
+ Files []string `toml:"files"`
+ URLs []string `toml:"urls"`
+}
+
+type LogConfig struct {
+ Level string `toml:"level"`
+}
+
+type CLIFlags struct {
+ Config string
+ LogLevel string
+ ListenUDP string
+ ListenTCP string
+ ListenDOH string
+}
+
+func ParseFlags() CLIFlags {
+ var f CLIFlags
+ flag.StringVar(&f.Config, "config", "linum.toml", "path to config file")
+ flag.StringVar(&f.LogLevel, "loglevel", "", "log level (debug|info|warn|error)")
+ flag.StringVar(&f.ListenUDP, "udp", "", "UDP listen address")
+ flag.StringVar(&f.ListenTCP, "tcp", "", "TCP listen address")
+ flag.StringVar(&f.ListenDOH, "doh", "", "DoH listen address")
+ flag.Parse()
+ return f
+}
+
+func Default() Config{
+ return Config{
+ Server: ServerConfig{
+ ListenUDP: ":5353",
+ ListenTCP: ":5353",
+ ListenDOH: ":8443",
+ },
+ Cache: CacheConfig{
+ MaxEntries: 100000,
+ },
+ Resolver: ResolverConfig{
+ Timeout: "2s",
+ MaxDelegations: 30,
+ },
+ Blocklist: BlocklistConfig{
+ Response: "zero_ip",
+ },
+ Log: LogConfig{
+ Level: "info",
+ },
+ }
+}
+
+func LoadFile(path string) (Config, error) {
+ var cfg Config
+ _, err := toml.DecodeFile(path, &cfg)
+ return cfg, err
+}
+
+func Merge(dst, src Config) Config {
+ if src.Server.ListenUDP != "" {
+ dst.Server.ListenUDP = src.Server.ListenUDP
+ }
+ if src.Server.ListenTCP != "" {
+ dst.Server.ListenTCP = src.Server.ListenTCP
+ }
+ if src.Server.ListenDOH != "" {
+ dst.Server.ListenDOH = src.Server.ListenDOH
+ }
+ if src.Cache.MaxEntries > 0 {
+ dst.Cache.MaxEntries = src.Cache.MaxEntries
+ }
+ if src.Cache.DBPath != "" {
+ dst.Cache.DBPath = src.Cache.DBPath
+ }
+ if src.Resolver.Timeout != "" {
+ dst.Resolver.Timeout = src.Resolver.Timeout
+ }
+ if src.Resolver.MaxDelegations > 0 {
+ dst.Resolver.MaxDelegations = src.Resolver.MaxDelegations
+ }
+ if src.Blocklist.Response != "" {
+ dst.Blocklist.Response = src.Blocklist.Response
+ }
+ if len(src.Blocklist.Files) > 0 {
+ dst.Blocklist.Files = src.Blocklist.Files
+ }
+ if len(src.Blocklist.URLs) > 0 {
+ dst.Blocklist.URLs = src.Blocklist.URLs
+ }
+ if src.Log.Level != "" {
+ dst.Log.Level = src.Log.Level
+ }
+ return dst
+}
+
+func (f CLIFlags) Apply(cfg Config) Config {
+ if f.ListenUDP != "" {
+ cfg.Server.ListenUDP = f.ListenUDP
+ }
+ if f.ListenTCP != "" {
+ cfg.Server.ListenTCP = f.ListenTCP
+ }
+ if f.ListenDOH != "" {
+ cfg.Server.ListenDOH = f.ListenDOH
+ }
+ if f.LogLevel != "" {
+ cfg.Log.Level = f.LogLevel
+ }
+ return cfg
+}
+
+func (c Config) Validate() error {
+ switch c.Blocklist.Response {
+ case "zero_ip", "nxdomain", "":
+ default:
+ return fmt.Errorf("invalid blocklist response %q (want zero_ip or nxdomain)", c.Blocklist.Response)
+ }
+ return nil
+}