diff --git a/dnscrypt-proxy/logger.go b/dnscrypt-proxy/logger.go index a7989597a7..3915e6ef8d 100644 --- a/dnscrypt-proxy/logger.go +++ b/dnscrypt-proxy/logger.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "io" "os" @@ -8,33 +9,37 @@ import ( "gopkg.in/natefinch/lumberjack.v2" ) -func Logger(logMaxSize int, logMaxAge int, logMaxBackups int, fileName string) io.Writer { +func Logger(logMaxSize, logMaxAge, logMaxBackups int, fileName string) io.Writer { if fileName == "/dev/stdout" { return os.Stdout } - if st, _ := os.Stat(fileName); st != nil && !st.Mode().IsRegular() { - if st.Mode().IsDir() { - dlog.Fatalf("[%v] is a directory", fileName) - } - fp, err := os.OpenFile(fileName, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0o644) - if err != nil { - dlog.Fatalf("Unable to access [%v]: [%v]", fileName, err) + + fileInfo, err := os.Stat(fileName) + if err == nil { + if fileInfo.IsDir() { + dlog.Fatalf("Logger-feil: [%v] er en katalog, ikke en fil", fileName) } - return fp + } else if !os.IsNotExist(err) { + dlog.Fatalf("Logger-feil: Kunne ikke sjekke [%v]: %v", fileName, err) } - if fp, err := os.OpenFile(fileName, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0o644); err == nil { - fp.Close() - } else { - dlog.Errorf("Unable to create [%v]: [%v]", fileName, err) + + file, err := os.OpenFile(fileName, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0o644) + if err != nil { + dlog.Fatalf("Logger-feil: Kunne ikke opprette eller åpne [%v]: %v", fileName, err) } + file.Close() + logger := &lumberjack.Logger{ - LocalTime: true, + Filename: fileName, MaxSize: logMaxSize, MaxAge: logMaxAge, MaxBackups: logMaxBackups, - Filename: fileName, Compress: true, + LocalTime: true, } + fmt.Printf("Logger opprettet: %s (MaxSize: %dMB, MaxAge: %d dager, MaxBackups: %d)\n", + fileName, logMaxSize, logMaxAge, logMaxBackups) + return logger } diff --git a/dnscrypt-proxy/plugin_allow_ip.go b/dnscrypt-proxy/plugin_allow_ip.go index a25b915f54..91dc9fcf5e 100644 --- a/dnscrypt-proxy/plugin_allow_ip.go +++ b/dnscrypt-proxy/plugin_allow_ip.go @@ -5,7 +5,6 @@ import ( "fmt" "io" "net" - "strings" "time" iradix "github.com/hashicorp/go-immutable-radix" @@ -15,7 +14,6 @@ import ( type PluginAllowedIP struct { allowedPrefixes *iradix.Tree - allowedIPs map[string]interface{} logger io.Writer format string } @@ -25,54 +23,20 @@ func (plugin *PluginAllowedIP) Name() string { } func (plugin *PluginAllowedIP) Description() string { - return "Allows DNS queries containing specific IP addresses" + return "Allows DNS queries only from the 192.168.0.0/24 network" } func (plugin *PluginAllowedIP) Init(proxy *Proxy) error { - dlog.Noticef("Loading the set of allowed IP rules from [%s]", proxy.allowedIPFile) - lines, err := ReadTextFile(proxy.allowedIPFile) - if err != nil { - return err - } + dlog.Notice("Initializing allowed IP rules for 192.168.0.0/24") + plugin.allowedPrefixes = iradix.New() - plugin.allowedIPs = make(map[string]interface{}) - for lineNo, line := range strings.Split(lines, "\n") { - line = TrimAndStripInlineComments(line) - if len(line) == 0 { - continue - } - ip := net.ParseIP(line) - trailingStar := strings.HasSuffix(line, "*") - if len(line) < 2 || (ip != nil && trailingStar) { - dlog.Errorf("Suspicious allowed IP rule [%s] at line %d", line, lineNo) - continue - } - if trailingStar { - line = line[:len(line)-1] - } - if strings.HasSuffix(line, ":") || strings.HasSuffix(line, ".") { - line = line[:len(line)-1] - } - if len(line) == 0 { - dlog.Errorf("Empty allowed IP rule at line %d", lineNo) - continue - } - if strings.Contains(line, "*") { - dlog.Errorf("Invalid rule: [%s] - wildcards can only be used as a suffix at line %d", line, lineNo) - continue - } - line = strings.ToLower(line) - if trailingStar { - plugin.allowedPrefixes, _, _ = plugin.allowedPrefixes.Insert([]byte(line), 0) - } else { - plugin.allowedIPs[line] = true - } - } - if len(proxy.allowedIPLogFile) == 0 { - return nil + _, cidr, _ := net.ParseCIDR("192.168.0.0/24") + plugin.allowedPrefixes, _, _ = plugin.allowedPrefixes.Insert([]byte(cidr.String()), true) + + if len(proxy.allowedIPLogFile) > 0 { + plugin.logger = Logger(proxy.logMaxSize, proxy.logMaxAge, proxy.logMaxBackups, proxy.allowedIPLogFile) + plugin.format = proxy.allowedIPFormat } - plugin.logger = Logger(proxy.logMaxSize, proxy.logMaxAge, proxy.logMaxBackups, proxy.allowedIPLogFile) - plugin.format = proxy.allowedIPFormat return nil } @@ -86,72 +50,34 @@ func (plugin *PluginAllowedIP) Reload() error { } func (plugin *PluginAllowedIP) Eval(pluginsState *PluginsState, msg *dns.Msg) error { - answers := msg.Answer - if len(answers) == 0 { + var clientIPStr string + + switch pluginsState.clientProto { + case "udp": + clientIPStr = (*pluginsState.clientAddr).(*net.UDPAddr).IP.String() + case "tcp", "local_doh": + clientIPStr = (*pluginsState.clientAddr).(*net.TCPAddr).IP.String() + default: return nil } - allowed, reason, ipStr := false, "", "" - for _, answer := range answers { - header := answer.Header() - Rrtype := header.Rrtype - if header.Class != dns.ClassINET || (Rrtype != dns.TypeA && Rrtype != dns.TypeAAAA) { - continue - } - if Rrtype == dns.TypeA { - ipStr = answer.(*dns.A).A.String() - } else if Rrtype == dns.TypeAAAA { - ipStr = answer.(*dns.AAAA).AAAA.String() // IPv4-mapped IPv6 addresses are converted to IPv4 - } - if _, found := plugin.allowedIPs[ipStr]; found { - allowed, reason = true, ipStr - break - } - match, _, found := plugin.allowedPrefixes.Root().LongestPrefix([]byte(ipStr)) - if found { - if len(match) == len(ipStr) || (ipStr[len(match)] == '.' || ipStr[len(match)] == ':') { - allowed, reason = true, string(match)+"*" - break - } - } + + clientIP := net.ParseIP(clientIPStr) + if clientIP == nil { + return errors.New("invalid client IP") } - if allowed { - pluginsState.sessionData["whitelisted"] = true - if plugin.logger != nil { - qName := pluginsState.qName - var clientIPStr string - switch pluginsState.clientProto { - case "udp": - clientIPStr = (*pluginsState.clientAddr).(*net.UDPAddr).IP.String() - case "tcp", "local_doh": - clientIPStr = (*pluginsState.clientAddr).(*net.TCPAddr).IP.String() - default: - // Ignore internal flow. - return nil - } - var line string - if plugin.format == "tsv" { - 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) - line = fmt.Sprintf( - "%s\t%s\t%s\t%s\t%s\n", - tsStr, - clientIPStr, - StringQuote(qName), - StringQuote(ipStr), - StringQuote(reason), - ) - } else if plugin.format == "ltsv" { - line = fmt.Sprintf("time:%d\thost:%s\tqname:%s\tip:%s\tmessage:%s\n", time.Now().Unix(), clientIPStr, StringQuote(qName), StringQuote(ipStr), StringQuote(reason)) - } else { - dlog.Fatalf("Unexpected log format: [%s]", plugin.format) - } - if plugin.logger == nil { - return errors.New("Log file not initialized") - } - _, _ = plugin.logger.Write([]byte(line)) - } + + _, cidr, _ := net.ParseCIDR("192.168.0.0/24") + if !cidr.Contains(clientIP) { + dlog.Warnf("Blocked DNS request from unauthorized IP: %s", clientIPStr) + return errors.New("unauthorized IP") } + + if plugin.logger != nil { + qName := pluginsState.qName + now := time.Now() + logEntry := fmt.Sprintf("[%s] Allowed: %s queried %s\n", now.Format(time.RFC3339), clientIPStr, qName) + _, _ = plugin.logger.Write([]byte(logEntry)) + } + return nil } diff --git a/go.mod b/go.mod index 47164e9d78..f54fed8a11 100644 --- a/go.mod +++ b/go.mod @@ -22,8 +22,8 @@ require ( github.com/opencoff/go-sieve v0.2.1 github.com/powerman/check v1.8.0 github.com/quic-go/quic-go v0.50.0 - golang.org/x/crypto v0.35.0 - golang.org/x/net v0.36.0 + golang.org/x/crypto v0.36.0 + golang.org/x/net v0.37.0 golang.org/x/sys v0.31.0 gopkg.in/natefinch/lumberjack.v2 v2.2.1 ) @@ -44,8 +44,8 @@ require ( go.uber.org/mock v0.5.0 // indirect golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect golang.org/x/mod v0.18.0 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/text v0.22.0 // indirect + golang.org/x/sync v0.12.0 // indirect + golang.org/x/text v0.23.0 // indirect golang.org/x/tools v0.22.0 // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect google.golang.org/grpc v1.56.3 // indirect diff --git a/go.sum b/go.sum index 2c13d283e3..2df642bf10 100644 --- a/go.sum +++ b/go.sum @@ -87,23 +87,23 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= -golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= -golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA= -golang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I= -golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= +golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190529164535-6a60838ec259/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= diff --git a/vendor/golang.org/x/sync/errgroup/errgroup.go b/vendor/golang.org/x/sync/errgroup/errgroup.go index b8322598ae..a4ea5d14f1 100644 --- a/vendor/golang.org/x/sync/errgroup/errgroup.go +++ b/vendor/golang.org/x/sync/errgroup/errgroup.go @@ -46,7 +46,7 @@ func (g *Group) done() { // returns a non-nil error or the first time Wait returns, whichever occurs // first. func WithContext(ctx context.Context) (*Group, context.Context) { - ctx, cancel := withCancelCause(ctx) + ctx, cancel := context.WithCancelCause(ctx) return &Group{cancel: cancel}, ctx } diff --git a/vendor/golang.org/x/sync/errgroup/go120.go b/vendor/golang.org/x/sync/errgroup/go120.go deleted file mode 100644 index f93c740b63..0000000000 --- a/vendor/golang.org/x/sync/errgroup/go120.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.20 - -package errgroup - -import "context" - -func withCancelCause(parent context.Context) (context.Context, func(error)) { - return context.WithCancelCause(parent) -} diff --git a/vendor/golang.org/x/sync/errgroup/pre_go120.go b/vendor/golang.org/x/sync/errgroup/pre_go120.go deleted file mode 100644 index 88ce33434e..0000000000 --- a/vendor/golang.org/x/sync/errgroup/pre_go120.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !go1.20 - -package errgroup - -import "context" - -func withCancelCause(parent context.Context) (context.Context, func(error)) { - ctx, cancel := context.WithCancel(parent) - return ctx, func(error) { cancel() } -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 6a9501ac43..d44ea78aed 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -131,7 +131,7 @@ github.com/smartystreets/goconvey/convey/reporting ## explicit; go 1.22 go.uber.org/mock/mockgen go.uber.org/mock/mockgen/model -# golang.org/x/crypto v0.35.0 +# golang.org/x/crypto v0.36.0 ## explicit; go 1.23.0 golang.org/x/crypto/blake2b golang.org/x/crypto/chacha20 @@ -154,7 +154,7 @@ golang.org/x/mod/internal/lazyregexp golang.org/x/mod/modfile golang.org/x/mod/module golang.org/x/mod/semver -# golang.org/x/net v0.36.0 +# golang.org/x/net v0.37.0 ## explicit; go 1.23.0 golang.org/x/net/bpf golang.org/x/net/http/httpguts @@ -168,8 +168,8 @@ golang.org/x/net/internal/socks golang.org/x/net/ipv4 golang.org/x/net/ipv6 golang.org/x/net/proxy -# golang.org/x/sync v0.11.0 -## explicit; go 1.18 +# golang.org/x/sync v0.12.0 +## explicit; go 1.23.0 golang.org/x/sync/errgroup # golang.org/x/sys v0.31.0 ## explicit; go 1.23.0 @@ -180,8 +180,8 @@ golang.org/x/sys/windows/registry golang.org/x/sys/windows/svc golang.org/x/sys/windows/svc/eventlog golang.org/x/sys/windows/svc/mgr -# golang.org/x/text v0.22.0 -## explicit; go 1.18 +# golang.org/x/text v0.23.0 +## explicit; go 1.23.0 golang.org/x/text/secure/bidirule golang.org/x/text/transform golang.org/x/text/unicode/bidi