diff --git a/Dockerfile b/Dockerfile index 70668fe0e..85046a14a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -166,9 +166,6 @@ ENV VPN_SERVICE_PROVIDER=pia \ DOT=on \ DOT_PROVIDERS=cloudflare \ DOT_PRIVATE_ADDRESS=127.0.0.1/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,169.254.0.0/16,::1/128,fc00::/7,fe80::/10,::ffff:7f00:1/104,::ffff:a00:0/104,::ffff:a9fe:0/112,::ffff:ac10:0/108,::ffff:c0a8:0/112 \ - DOT_VERBOSITY=1 \ - DOT_VERBOSITY_DETAILS=0 \ - DOT_VALIDATION_LOGLEVEL=0 \ DOT_CACHING=on \ DOT_IPV6=off \ BLOCK_MALICIOUS=on \ @@ -226,10 +223,9 @@ RUN apk add --no-cache --update -l wget && \ apk add --no-cache --update -X "https://dl-cdn.alpinelinux.org/alpine/v3.17/main" openvpn\~2.5 && \ mv /usr/sbin/openvpn /usr/sbin/openvpn2.5 && \ apk del openvpn && \ - apk add --no-cache --update openvpn ca-certificates iptables iptables-legacy unbound tzdata && \ + apk add --no-cache --update openvpn ca-certificates iptables iptables-legacy tzdata && \ mv /usr/sbin/openvpn /usr/sbin/openvpn2.6 && \ - rm -rf /var/cache/apk/* /etc/unbound/* /usr/sbin/unbound-* /etc/openvpn/*.sh /usr/lib/openvpn/plugins/openvpn-plugin-down-root.so && \ + rm -rf /var/cache/apk/* /etc/openvpn/*.sh /usr/lib/openvpn/plugins/openvpn-plugin-down-root.so && \ deluser openvpn && \ - deluser unbound && \ mkdir /gluetun COPY --from=build /tmp/gobuild/entrypoint /gluetun-entrypoint diff --git a/README.md b/README.md index 4c6515bae..1f7b6763e 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,6 @@ Lightweight swiss-knife-like VPN client to multiple VPN service providers - Compatible with amd64, i686 (32 bit), **ARM** 64 bit, ARM 32 bit v6 and v7, and even ppc64le 🎆 - Custom VPN server side port forwarding for [Perfect Privacy](https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/perfect-privacy.md#vpn-server-port-forwarding), [Private Internet Access](https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/private-internet-access.md#vpn-server-port-forwarding), [PrivateVPN](https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/privatevpn.md#vpn-server-port-forwarding) and [ProtonVPN](https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/protonvpn.md#vpn-server-port-forwarding) - Possibility of split horizon DNS by selecting multiple DNS over TLS providers -- Unbound subprogram drops root privileges once launched - Can work as a Kubernetes sidecar container, thanks @rorph ## Setup diff --git a/cmd/gluetun/main.go b/cmd/gluetun/main.go index 38c414b38..588981bdd 100644 --- a/cmd/gluetun/main.go +++ b/cmd/gluetun/main.go @@ -13,7 +13,6 @@ import ( _ "time/tzdata" _ "github.com/breml/rootcerts" - "github.com/qdm12/dns/pkg/unbound" "github.com/qdm12/gluetun/internal/alpine" "github.com/qdm12/gluetun/internal/cli" "github.com/qdm12/gluetun/internal/configuration/settings" @@ -51,7 +50,6 @@ import ( "github.com/qdm12/goshutdown/order" "github.com/qdm12/gosplash" "github.com/qdm12/log" - "github.com/qdm12/updated/pkg/dnscrypto" ) //nolint:gochecknoglobals @@ -188,7 +186,7 @@ func _main(ctx context.Context, buildInfo models.BuildInformation, } var allSettings settings.Settings - err = allSettings.Read(reader) + err = allSettings.Read(reader, logger) if err != nil { return err } @@ -269,16 +267,11 @@ func _main(ctx context.Context, buildInfo models.BuildInformation, ovpnConf := openvpn.New( logger.New(log.SetComponent("openvpn configurator")), cmder, puid, pgid) - dnsCrypto := dnscrypto.New(httpClient, "", "") - const cacertsPath = "/etc/ssl/certs/ca-certificates.crt" - dnsConf := unbound.NewConfigurator(nil, cmder, dnsCrypto, - "/etc/unbound", "/usr/sbin/unbound", cacertsPath) err = printVersions(ctx, logger, []printVersionElement{ {name: "Alpine", getVersion: alpineConf.Version}, {name: "OpenVPN 2.5", getVersion: ovpnConf.Version25}, {name: "OpenVPN 2.6", getVersion: ovpnConf.Version26}, - {name: "Unbound", getVersion: dnsConf.Version}, {name: "IPtables", getVersion: firewallConf.Version}, }) if err != nil { @@ -306,15 +299,8 @@ func _main(ctx context.Context, buildInfo models.BuildInformation, if nonRootUsername != defaultUsername { logger.Info("using existing username " + nonRootUsername + " corresponding to user id " + fmt.Sprint(puid)) } - // set it for Unbound - // TODO remove this when migrating to qdm12/dns v2 - allSettings.DNS.DoT.Unbound.Username = nonRootUsername allSettings.VPN.OpenVPN.ProcessUser = nonRootUsername - if err := os.Chown("/etc/unbound", puid, pgid); err != nil { - return err - } - if err := routingConf.Setup(); err != nil { if strings.Contains(err.Error(), "operation not permitted") { logger.Warn("💡 Tip: Are you passing NET_ADMIN capability to gluetun?") @@ -396,18 +382,22 @@ func _main(ctx context.Context, buildInfo models.BuildInformation, return fmt.Errorf("starting port forwarding loop: %w", err) } - unboundLogger := logger.New(log.SetComponent("dns")) - unboundLooper := dns.NewLoop(dnsConf, allSettings.DNS, httpClient, - unboundLogger) + dnsLogger := logger.New(log.SetComponent("dns")) + dnsLooper, err := dns.NewLoop(allSettings.DNS, httpClient, + dnsLogger) + if err != nil { + return fmt.Errorf("creating DNS loop: %w", err) + } + dnsHandler, dnsCtx, dnsDone := goshutdown.NewGoRoutineHandler( - "unbound", goroutine.OptionTimeout(defaultShutdownTimeout)) - // wait for unboundLooper.Restart or its ticker launched with RunRestartTicker - go unboundLooper.Run(dnsCtx, dnsDone) + "dns", goroutine.OptionTimeout(defaultShutdownTimeout)) + // wait for dnsLooper.Restart or its ticker launched with RunRestartTicker + go dnsLooper.Run(dnsCtx, dnsDone) otherGroupHandler.Add(dnsHandler) dnsTickerHandler, dnsTickerCtx, dnsTickerDone := goshutdown.NewGoRoutineHandler( "dns ticker", goroutine.OptionTimeout(defaultShutdownTimeout)) - go unboundLooper.RunRestartTicker(dnsTickerCtx, dnsTickerDone) + go dnsLooper.RunRestartTicker(dnsTickerCtx, dnsTickerDone) controlGroupHandler.Add(dnsTickerHandler) publicipAPI, _ := pubipapi.ParseProvider(allSettings.PublicIP.API) @@ -434,7 +424,7 @@ func _main(ctx context.Context, buildInfo models.BuildInformation, vpnLogger := logger.New(log.SetComponent("vpn")) vpnLooper := vpn.NewLoop(allSettings.VPN, ipv6Supported, allSettings.Firewall.VPNInputPorts, providers, storage, ovpnConf, netLinker, firewallConf, routingConf, portForwardLooper, - cmder, publicIPLooper, unboundLooper, vpnLogger, httpClient, + cmder, publicIPLooper, dnsLooper, vpnLogger, httpClient, buildInfo, *allSettings.Version.Enabled) vpnHandler, vpnCtx, vpnDone := goshutdown.NewGoRoutineHandler( "vpn", goroutine.OptionTimeout(time.Second)) @@ -474,7 +464,7 @@ func _main(ctx context.Context, buildInfo models.BuildInformation, "http server", goroutine.OptionTimeout(defaultShutdownTimeout)) httpServer, err := server.New(httpServerCtx, controlServerAddress, controlServerLogging, logger.New(log.SetComponent("http server")), - buildInfo, vpnLooper, portForwardLooper, unboundLooper, updaterLooper, publicIPLooper, + buildInfo, vpnLooper, portForwardLooper, dnsLooper, updaterLooper, publicIPLooper, storage, ipv6Supported) if err != nil { return fmt.Errorf("setting up control server: %w", err) diff --git a/go.mod b/go.mod index fb11a1ec0..036cc3d86 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/golang/mock v1.6.0 github.com/klauspost/compress v1.17.9 github.com/klauspost/pgzip v1.2.6 - github.com/qdm12/dns v1.11.0 + github.com/qdm12/dns/v2 v2.0.0-rc6 github.com/qdm12/golibs v0.0.0-20210822203818-5c568b0777b6 github.com/qdm12/gosettings v0.4.2 github.com/qdm12/goshutdown v0.3.0 @@ -16,7 +16,6 @@ require ( github.com/qdm12/gotree v0.2.0 github.com/qdm12/log v0.1.0 github.com/qdm12/ss-server v0.6.0 - github.com/qdm12/updated v0.0.0-20210603204757-205acfe6937e github.com/stretchr/testify v1.9.0 github.com/ulikunitz/xz v0.5.11 github.com/vishvananda/netlink v1.2.1-beta.2 @@ -27,29 +26,37 @@ require ( golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 gopkg.in/ini.v1 v1.67.0 - inet.af/netaddr v0.0.0-20220811202034-502d2d690317 ) require ( + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/google/go-cmp v0.5.9 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/google/go-cmp v0.6.0 // indirect github.com/josharian/native v1.1.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mdlayher/genetlink v1.3.2 // indirect github.com/mdlayher/netlink v1.7.2 // indirect github.com/mdlayher/socket v0.4.1 // indirect - github.com/miekg/dns v1.1.40 // indirect + github.com/miekg/dns v1.1.55 // indirect github.com/mr-tron/base58 v1.2.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_golang v1.16.0 // indirect + github.com/prometheus/client_model v0.3.0 // indirect + github.com/prometheus/common v0.42.0 // indirect + github.com/prometheus/procfs v0.10.1 // indirect github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae // indirect - go4.org/intern v0.0.0-20211027215823-ae77deb06f29 // indirect - go4.org/unsafe/assume-no-moving-gc v0.0.0-20230525183740-e7c30c78aeb2 // indirect golang.org/x/crypto v0.26.0 // indirect golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/sync v0.8.0 // indirect + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect + google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect kernel.org/pub/linux/libs/security/libcap/cap v1.2.69 // indirect kernel.org/pub/linux/libs/security/libcap/psx v1.2.69 // indirect diff --git a/go.sum b/go.sum index 7c293d32d..19abcdb1a 100644 --- a/go.sum +++ b/go.sum @@ -1,65 +1,38 @@ -github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/breml/rootcerts v0.2.17 h1:0/M2BE2Apw0qEJCXDOkaiu7d5Sx5ObNfe1BkImJ4u1I= github.com/breml/rootcerts v0.2.17/go.mod h1:S/PKh+4d1HUn4HQovEB8hPJZO6pUZYrIhmXBhsegfXw= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/dvyukov/go-fuzz v0.0.0-20210103155950-6a8e9d1f2415/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= -github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= -github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= -github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= -github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= -github.com/go-openapi/errors v0.17.2/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= -github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= -github.com/go-openapi/runtime v0.17.2/go.mod h1:QO936ZXeisByFmZEO1IS1Dqhtf4QV1sYYFtIq6Ld86Q= -github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= -github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= -github.com/go-openapi/validate v0.17.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gotify/go-api-client/v2 v2.0.4/go.mod h1:VKiah/UK20bXsr0JObE1eBVLW44zbBouzjuri9iwjFU= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= -github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kyokomi/emoji v2.2.4+incompatible/go.mod h1:mZ6aGCD7yk8j6QY6KICwnZ2pxoszVseX1DNoGtU2tBA= -github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= @@ -67,30 +40,33 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw= github.com/mdlayher/genetlink v1.3.2/go.mod h1:tcC3pkCrPUGIKKsCsp0B3AdaaKuHtaxoJRz3cc+528o= github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= -github.com/miekg/dns v1.1.40 h1:pyyPFfGMnciYUk/mXpKkVmeMQjfXqt3FAJ2hy7tPiLA= -github.com/miekg/dns v1.1.40/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= +github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws= github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= -github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= github.com/phayes/permbits v0.0.0-20190612203442-39d7c581d2ee/go.mod h1:3uODdxMgOaPYeWU7RzZLxVtJHZ/x1f/iHkBZuKJDzuY= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/qdm12/dns v1.11.0 h1:jpcD5DZXXQSQe5a263PL09ghukiIdptvXFOZvyKEm6Q= -github.com/qdm12/dns v1.11.0/go.mod h1:FmQsNOUcrrZ4UFzWAiED56AKXeNgaX3ySbmPwEfNjjE= -github.com/qdm12/golibs v0.0.0-20210603202746-e5494e9c2ebb/go.mod h1:15RBzkun0i8XB7ADIoLJWp9ITRgsz3LroEI2FiOXLRg= -github.com/qdm12/golibs v0.0.0-20210723175634-a75ca7fd74c2/go.mod h1:6aRbg4Z/bTbm9JfxsGXfWKHi7zsOvPfUTK1S5HuAFKg= +github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= +github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= +github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= +github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= +github.com/qdm12/dns/v2 v2.0.0-rc6 h1:h5KpuqZ3IMoSbz2a0OkHzIVc9/jk2vuIm9RoKJuaI78= +github.com/qdm12/dns/v2 v2.0.0-rc6/go.mod h1:Oh34IJIG55BgHoACOf+cgZCgDiFuiJZ6r6gQW58FN+k= github.com/qdm12/golibs v0.0.0-20210822203818-5c568b0777b6 h1:bge5AL7cjHJMPz+5IOz5yF01q/l8No6+lIEBieA8gMg= github.com/qdm12/golibs v0.0.0-20210822203818-5c568b0777b6/go.mod h1:6aRbg4Z/bTbm9JfxsGXfWKHi7zsOvPfUTK1S5HuAFKg= github.com/qdm12/gosettings v0.4.2 h1:Gb39NScPr7OQV+oy0o1OD7A121udITDJuUGa7ljDF58= @@ -105,17 +81,11 @@ github.com/qdm12/log v0.1.0 h1:jYBd/xscHYpblzZAd2kjZp2YmuYHjAAfbTViJWxoPTw= github.com/qdm12/log v0.1.0/go.mod h1:Vchi5M8uBvHfPNIblN4mjXn/oSbiWguQIbsgF1zdQPI= github.com/qdm12/ss-server v0.6.0 h1:OaOdCIBXx0z3DGHPT6Th0v88vGa3MtAS4oRgUsDHGZE= github.com/qdm12/ss-server v0.6.0/go.mod h1:0BO/zEmtTiLDlmQEcjtoHTC+w+cWxwItjBuGP6TWM78= -github.com/qdm12/updated v0.0.0-20210603204757-205acfe6937e h1:4q+uFLawkaQRq3yARYLsjJPZd2wYwxn4g6G/5v0xW1g= -github.com/qdm12/updated v0.0.0-20210603204757-205acfe6937e/go.mod h1:UvJRGkZ9XL3/D7e7JiTTVLm1F3Cymd3/gFpD6frEpBo= github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg= github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= @@ -125,63 +95,38 @@ github.com/vishvananda/netlink v1.2.1-beta.2 h1:Llsql0lnQEbHj0I1OuKyp8otXp0r3q0m github.com/vishvananda/netlink v1.2.1-beta.2/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae h1:4hwBBUfQCFe3Cym0ZtKyq7L16eZUtYKs+BaHDN6mAns= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= -github.com/yl2chen/cidranger v1.0.2/go.mod h1:9U1yz7WPYDwf0vpNWFaeRh0bjwz5RVgRy/9UEQfHl0g= github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk= github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go4.org/intern v0.0.0-20210108033219-3eb7198706b2/go.mod h1:vLqJ+12kCw61iCWsPto0EOHhBS+o4rO5VIucbc9g2Cc= -go4.org/intern v0.0.0-20211027215823-ae77deb06f29 h1:UXLjNohABv4S58tHmeuIZDO6e3mHpW2Dx33gaNt03LE= -go4.org/intern v0.0.0-20211027215823-ae77deb06f29/go.mod h1:cS2ma+47FKrLPdXFpr7CuxiTW3eyJbWew4qx0qtQWDA= -go4.org/unsafe/assume-no-moving-gc v0.0.0-20201222175341-b30ae309168e/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E= -go4.org/unsafe/assume-no-moving-gc v0.0.0-20201222180813-1025295fd063/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E= -go4.org/unsafe/assume-no-moving-gc v0.0.0-20211027215541-db492cf91b37/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E= -go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E= -go4.org/unsafe/assume-no-moving-gc v0.0.0-20230525183740-e7c30c78aeb2 h1:WJhcL4p+YeDxmZWg141nRm7XC8IDmhz7lk5GpadO1Sg= -go4.org/unsafe/assume-no-moving-gc v0.0.0-20230525183740-e7c30c78aeb2/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E= -golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -191,20 +136,19 @@ golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg= golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= @@ -212,25 +156,20 @@ golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uI golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA= golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 h1:CawjfCvYQH2OU3/TnxLx97WDSUDRABfT18pCOYwc2GE= golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6/go.mod h1:3rxYc4HtVcSG9gVaTs2GEBdehh+sYPOwKtyUWEOTb80= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= -gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= -gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gvisor.dev/gvisor v0.0.0-20230927004350-cbd86285d259 h1:TbRPT0HtzFP3Cno1zZo7yPzEEnfu8EjLfl6IU9VfqkQ= gvisor.dev/gvisor v0.0.0-20230927004350-cbd86285d259/go.mod h1:AVgIgHMwK63XvmAzWG9vLQ41YnVHN0du0tEC46fI7yY= -inet.af/netaddr v0.0.0-20210511181906-37180328850c/go.mod h1:z0nx+Dh+7N7CC8V5ayHtHGpZpxLQZZxkIaaz6HN65Ls= -inet.af/netaddr v0.0.0-20220811202034-502d2d690317 h1:U2fwK6P2EqmopP/hFLTOAjWTki0qgd4GMJn5X8wOleU= -inet.af/netaddr v0.0.0-20220811202034-502d2d690317/go.mod h1:OIezDfdzOgFhuw4HuWapWq2e9l0H9tK4F1j+ETRtF3k= kernel.org/pub/linux/libs/security/libcap/cap v1.2.69 h1:N0m3tKYbkRMmDobh/47ngz+AWeV7PcfXMDi8xu3Vrag= kernel.org/pub/linux/libs/security/libcap/cap v1.2.69/go.mod h1:Tk5Ip2TuxaWGpccL7//rAsLRH6RQ/jfqTGxuN/+i/FQ= kernel.org/pub/linux/libs/security/libcap/psx v1.2.69 h1:IdrOs1ZgwGw5CI+BH6GgVVlOt+LAXoPyh7enr8lfaXs= diff --git a/internal/cli/openvpnconfig.go b/internal/cli/openvpnconfig.go index 3ae45441a..4b509061b 100644 --- a/internal/cli/openvpnconfig.go +++ b/internal/cli/openvpnconfig.go @@ -49,7 +49,7 @@ func (c *CLI) OpenvpnConfig(logger OpenvpnConfigLogger, reader *reader.Reader, } var allSettings settings.Settings - err = allSettings.Read(reader) + err = allSettings.Read(reader, logger) if err != nil { return err } diff --git a/internal/configuration/settings/deprecated.go b/internal/configuration/settings/deprecated.go new file mode 100644 index 000000000..77010781c --- /dev/null +++ b/internal/configuration/settings/deprecated.go @@ -0,0 +1,25 @@ +package settings + +import ( + "slices" + + "github.com/qdm12/gosettings/reader" + "golang.org/x/exp/maps" +) + +func readObsolete(r *reader.Reader) (warnings []string) { + keyToMessage := map[string]string{ + "DOT_VERBOSITY": "DOT_VERBOSITY is obsolete, use LOG_LEVEL instead.", + "DOT_VERBOSITY_DETAILS": "DOT_VERBOSITY_DETAILS is obsolete because it was specific to Unbound.", + "DOT_VALIDATION_LOGLEVEL": "DOT_VALIDATION_LOGLEVEL is obsolete because DNSSEC validation is not implemented.", + } + sortedKeys := maps.Keys(keyToMessage) + slices.Sort(sortedKeys) + warnings = make([]string, 0, len(keyToMessage)) + for _, key := range sortedKeys { + if r.Get(key) != nil { + warnings = append(warnings, keyToMessage[key]) + } + } + return warnings +} diff --git a/internal/configuration/settings/dnsblacklist.go b/internal/configuration/settings/dnsblacklist.go index d430c5625..05b147163 100644 --- a/internal/configuration/settings/dnsblacklist.go +++ b/internal/configuration/settings/dnsblacklist.go @@ -3,10 +3,11 @@ package settings import ( "errors" "fmt" + "net/http" "net/netip" "regexp" - "github.com/qdm12/dns/pkg/blacklist" + "github.com/qdm12/dns/v2/pkg/blockbuilder" "github.com/qdm12/gosettings" "github.com/qdm12/gosettings/reader" "github.com/qdm12/gotree" @@ -74,16 +75,18 @@ func (b *DNSBlacklist) overrideWith(other DNSBlacklist) { b.AddBlockedIPPrefixes = gosettings.OverrideWithSlice(b.AddBlockedIPPrefixes, other.AddBlockedIPPrefixes) } -func (b DNSBlacklist) ToBlacklistFormat() (settings blacklist.BuilderSettings, err error) { - return blacklist.BuilderSettings{ - BlockMalicious: *b.BlockMalicious, - BlockAds: *b.BlockAds, - BlockSurveillance: *b.BlockSurveillance, +func (b DNSBlacklist) ToBlockBuilderSettings(client *http.Client) ( + settings blockbuilder.Settings) { + return blockbuilder.Settings{ + Client: client, + BlockMalicious: b.BlockMalicious, + BlockAds: b.BlockAds, + BlockSurveillance: b.BlockSurveillance, AllowedHosts: b.AllowedHosts, AddBlockedHosts: b.AddBlockedHosts, - AddBlockedIPs: netipAddressesToNetaddrIPs(b.AddBlockedIPs), - AddBlockedIPPrefixes: netipPrefixesToNetaddrIPPrefixes(b.AddBlockedIPPrefixes), - }, nil + AddBlockedIPs: b.AddBlockedIPs, + AddBlockedIPPrefixes: b.AddBlockedIPPrefixes, + } } func (b DNSBlacklist) String() string { diff --git a/internal/configuration/settings/dot.go b/internal/configuration/settings/dot.go index dc3ace3b3..157bfc3ce 100644 --- a/internal/configuration/settings/dot.go +++ b/internal/configuration/settings/dot.go @@ -3,8 +3,10 @@ package settings import ( "errors" "fmt" + "net/netip" "time" + "github.com/qdm12/dns/v2/pkg/provider" "github.com/qdm12/gosettings" "github.com/qdm12/gosettings/reader" "github.com/qdm12/gotree" @@ -16,14 +18,18 @@ type DoT struct { // and used. It defaults to true, and cannot be nil // in the internal state. Enabled *bool - // UpdatePeriod is the period to update DNS block - // lists and cryptographic files for DNSSEC validation. + // UpdatePeriod is the period to update DNS block lists. // It can be set to 0 to disable the update. // It defaults to 24h and cannot be nil in // the internal state. UpdatePeriod *time.Duration - // Unbound contains settings to configure Unbound. - Unbound Unbound + // Providers is a list of DNS over TLS providers + Providers []string `json:"providers"` + // Caching is true if the DoT server should cache + // DNS responses. + Caching *bool `json:"caching"` + // IPv6 is true if the DoT server should connect over IPv6. + IPv6 *bool `json:"ipv6"` // Blacklist contains settings to configure the filter // block lists. Blacklist DNSBlacklist @@ -40,9 +46,12 @@ func (d DoT) validate() (err error) { ErrDoTUpdatePeriodTooShort, *d.UpdatePeriod, minUpdatePeriod) } - err = d.Unbound.validate() - if err != nil { - return err + providers := provider.NewProviders() + for _, providerName := range d.Providers { + _, err := providers.Get(providerName) + if err != nil { + return err + } } err = d.Blacklist.validate() @@ -57,7 +66,9 @@ func (d *DoT) copy() (copied DoT) { return DoT{ Enabled: gosettings.CopyPointer(d.Enabled), UpdatePeriod: gosettings.CopyPointer(d.UpdatePeriod), - Unbound: d.Unbound.copy(), + Providers: gosettings.CopySlice(d.Providers), + Caching: gosettings.CopyPointer(d.Caching), + IPv6: gosettings.CopyPointer(d.IPv6), Blacklist: d.Blacklist.copy(), } } @@ -68,7 +79,9 @@ func (d *DoT) copy() (copied DoT) { func (d *DoT) overrideWith(other DoT) { d.Enabled = gosettings.OverrideWithPointer(d.Enabled, other.Enabled) d.UpdatePeriod = gosettings.OverrideWithPointer(d.UpdatePeriod, other.UpdatePeriod) - d.Unbound.overrideWith(other.Unbound) + d.Providers = gosettings.OverrideWithSlice(d.Providers, other.Providers) + d.Caching = gosettings.OverrideWithPointer(d.Caching, other.Caching) + d.IPv6 = gosettings.OverrideWithPointer(d.IPv6, other.IPv6) d.Blacklist.overrideWith(other.Blacklist) } @@ -76,10 +89,26 @@ func (d *DoT) setDefaults() { d.Enabled = gosettings.DefaultPointer(d.Enabled, true) const defaultUpdatePeriod = 24 * time.Hour d.UpdatePeriod = gosettings.DefaultPointer(d.UpdatePeriod, defaultUpdatePeriod) - d.Unbound.setDefaults() + d.Providers = gosettings.DefaultSlice(d.Providers, []string{ + provider.Cloudflare().Name, + }) + d.Caching = gosettings.DefaultPointer(d.Caching, true) + d.IPv6 = gosettings.DefaultPointer(d.IPv6, false) d.Blacklist.setDefaults() } +func (d DoT) GetFirstPlaintextIPv4() (ipv4 netip.Addr) { + providers := provider.NewProviders() + provider, err := providers.Get(d.Providers[0]) + if err != nil { + // Settings should be validated before calling this function, + // so an error happening here is a programming error. + panic(err) + } + + return provider.DoT.IPv4[0].Addr() +} + func (d DoT) String() string { return d.toLinesNode().String() } @@ -98,7 +127,14 @@ func (d DoT) toLinesNode() (node *gotree.Node) { } node.Appendf("Update period: %s", update) - node.AppendNode(d.Unbound.toLinesNode()) + upstreamResolvers := node.Appendf("Upstream resolvers:") + for _, provider := range d.Providers { + upstreamResolvers.Appendf(provider) + } + + node.Appendf("Caching: %s", gosettings.BoolToYesNo(d.Caching)) + node.Appendf("IPv6: %s", gosettings.BoolToYesNo(d.IPv6)) + node.AppendNode(d.Blacklist.toLinesNode()) return node @@ -115,7 +151,14 @@ func (d *DoT) read(reader *reader.Reader) (err error) { return err } - err = d.Unbound.read(reader) + d.Providers = reader.CSV("DOT_PROVIDERS") + + d.Caching, err = reader.BoolPtr("DOT_CACHING") + if err != nil { + return err + } + + d.IPv6, err = reader.BoolPtr("DOT_IPV6") if err != nil { return err } diff --git a/internal/configuration/settings/helpers_test.go b/internal/configuration/settings/helpers_test.go index 52d2cfd91..346e7e9d2 100644 --- a/internal/configuration/settings/helpers_test.go +++ b/internal/configuration/settings/helpers_test.go @@ -1,4 +1,3 @@ package settings -func boolPtr(b bool) *bool { return &b } -func uint8Ptr(n uint8) *uint8 { return &n } +func boolPtr(b bool) *bool { return &b } diff --git a/internal/configuration/settings/netaddr.go b/internal/configuration/settings/netaddr.go deleted file mode 100644 index 9c931398a..000000000 --- a/internal/configuration/settings/netaddr.go +++ /dev/null @@ -1,36 +0,0 @@ -package settings - -import ( - "net/netip" - - "inet.af/netaddr" -) - -func netipAddressToNetaddrIP(address netip.Addr) (ip netaddr.IP) { - if address.Is4() { - return netaddr.IPFrom4(address.As4()) - } - return netaddr.IPFrom16(address.As16()) -} - -func netipAddressesToNetaddrIPs(addresses []netip.Addr) (ips []netaddr.IP) { - ips = make([]netaddr.IP, len(addresses)) - for i := range addresses { - ips[i] = netipAddressToNetaddrIP(addresses[i]) - } - return ips -} - -func netipPrefixToNetaddrIPPrefix(prefix netip.Prefix) (ipPrefix netaddr.IPPrefix) { - netaddrIP := netipAddressToNetaddrIP(prefix.Addr()) - bits := prefix.Bits() - return netaddr.IPPrefixFrom(netaddrIP, uint8(bits)) -} - -func netipPrefixesToNetaddrIPPrefixes(prefixes []netip.Prefix) (ipPrefixes []netaddr.IPPrefix) { - ipPrefixes = make([]netaddr.IPPrefix, len(prefixes)) - for i := range ipPrefixes { - ipPrefixes[i] = netipPrefixToNetaddrIPPrefix(prefixes[i]) - } - return ipPrefixes -} diff --git a/internal/configuration/settings/settings.go b/internal/configuration/settings/settings.go index 162647eab..7ae41c3a8 100644 --- a/internal/configuration/settings/settings.go +++ b/internal/configuration/settings/settings.go @@ -184,7 +184,12 @@ func (s Settings) Warnings() (warnings []string) { return warnings } -func (s *Settings) Read(r *reader.Reader) (err error) { +func (s *Settings) Read(r *reader.Reader, warner Warner) (err error) { + warnings := readObsolete(r) + for _, warning := range warnings { + warner.Warn(warning) + } + readFunctions := map[string]func(r *reader.Reader) error{ "control server": s.ControlServer.read, "DNS": s.DNS.read, diff --git a/internal/configuration/settings/settings_test.go b/internal/configuration/settings/settings_test.go index c675e167d..276c5688b 100644 --- a/internal/configuration/settings/settings_test.go +++ b/internal/configuration/settings/settings_test.go @@ -43,18 +43,10 @@ func Test_Settings_String(t *testing.T) { | └── DNS over TLS settings: | ├── Enabled: yes | ├── Update period: every 24h0m0s -| ├── Unbound settings: -| | ├── Authoritative servers: -| | | └── Cloudflare -| | ├── Caching: yes -| | ├── IPv6: no -| | ├── Verbosity level: 1 -| | ├── Verbosity details level: 0 -| | ├── Validation log level: 0 -| | ├── System user: root -| | └── Allowed networks: -| | ├── 0.0.0.0/0 -| | └── ::/0 +| ├── Upstream resolvers: +| | └── Cloudflare +| ├── Caching: yes +| ├── IPv6: no | └── DNS filtering settings: | ├── Block malicious: yes | ├── Block ads: no diff --git a/internal/configuration/settings/unbound.go b/internal/configuration/settings/unbound.go deleted file mode 100644 index 425348f7b..000000000 --- a/internal/configuration/settings/unbound.go +++ /dev/null @@ -1,223 +0,0 @@ -package settings - -import ( - "errors" - "fmt" - "net/netip" - - "github.com/qdm12/dns/pkg/provider" - "github.com/qdm12/dns/pkg/unbound" - "github.com/qdm12/gosettings" - "github.com/qdm12/gosettings/reader" - "github.com/qdm12/gotree" -) - -// Unbound is settings for the Unbound program. -type Unbound struct { - Providers []string `json:"providers"` - Caching *bool `json:"caching"` - IPv6 *bool `json:"ipv6"` - VerbosityLevel *uint8 `json:"verbosity_level"` - VerbosityDetailsLevel *uint8 `json:"verbosity_details_level"` - ValidationLogLevel *uint8 `json:"validation_log_level"` - Username string `json:"username"` - Allowed []netip.Prefix `json:"allowed"` -} - -func (u *Unbound) setDefaults() { - if len(u.Providers) == 0 { - u.Providers = []string{ - provider.Cloudflare().String(), - } - } - - u.Caching = gosettings.DefaultPointer(u.Caching, true) - u.IPv6 = gosettings.DefaultPointer(u.IPv6, false) - - const defaultVerbosityLevel = 1 - u.VerbosityLevel = gosettings.DefaultPointer(u.VerbosityLevel, defaultVerbosityLevel) - - const defaultVerbosityDetailsLevel = 0 - u.VerbosityDetailsLevel = gosettings.DefaultPointer(u.VerbosityDetailsLevel, defaultVerbosityDetailsLevel) - - const defaultValidationLogLevel = 0 - u.ValidationLogLevel = gosettings.DefaultPointer(u.ValidationLogLevel, defaultValidationLogLevel) - - if u.Allowed == nil { - u.Allowed = []netip.Prefix{ - netip.PrefixFrom(netip.AddrFrom4([4]byte{}), 0), - netip.PrefixFrom(netip.AddrFrom16([16]byte{}), 0), - } - } - - u.Username = gosettings.DefaultComparable(u.Username, "root") -} - -var ( - ErrUnboundVerbosityLevelNotValid = errors.New("Unbound verbosity level is not valid") - ErrUnboundVerbosityDetailsLevelNotValid = errors.New("Unbound verbosity details level is not valid") - ErrUnboundValidationLogLevelNotValid = errors.New("Unbound validation log level is not valid") -) - -func (u Unbound) validate() (err error) { - for _, s := range u.Providers { - _, err := provider.Parse(s) - if err != nil { - return err - } - } - - const maxVerbosityLevel = 5 - if *u.VerbosityLevel > maxVerbosityLevel { - return fmt.Errorf("%w: %d must be between 0 and %d", - ErrUnboundVerbosityLevelNotValid, - *u.VerbosityLevel, - maxVerbosityLevel) - } - - const maxVerbosityDetailsLevel = 4 - if *u.VerbosityDetailsLevel > maxVerbosityDetailsLevel { - return fmt.Errorf("%w: %d must be between 0 and %d", - ErrUnboundVerbosityDetailsLevelNotValid, - *u.VerbosityDetailsLevel, - maxVerbosityDetailsLevel) - } - - const maxValidationLogLevel = 2 - if *u.ValidationLogLevel > maxValidationLogLevel { - return fmt.Errorf("%w: %d must be between 0 and %d", - ErrUnboundValidationLogLevelNotValid, - *u.ValidationLogLevel, maxValidationLogLevel) - } - - return nil -} - -func (u Unbound) copy() (copied Unbound) { - return Unbound{ - Providers: gosettings.CopySlice(u.Providers), - Caching: gosettings.CopyPointer(u.Caching), - IPv6: gosettings.CopyPointer(u.IPv6), - VerbosityLevel: gosettings.CopyPointer(u.VerbosityLevel), - VerbosityDetailsLevel: gosettings.CopyPointer(u.VerbosityDetailsLevel), - ValidationLogLevel: gosettings.CopyPointer(u.ValidationLogLevel), - Username: u.Username, - Allowed: gosettings.CopySlice(u.Allowed), - } -} - -func (u *Unbound) overrideWith(other Unbound) { - u.Providers = gosettings.OverrideWithSlice(u.Providers, other.Providers) - u.Caching = gosettings.OverrideWithPointer(u.Caching, other.Caching) - u.IPv6 = gosettings.OverrideWithPointer(u.IPv6, other.IPv6) - u.VerbosityLevel = gosettings.OverrideWithPointer(u.VerbosityLevel, other.VerbosityLevel) - u.VerbosityDetailsLevel = gosettings.OverrideWithPointer(u.VerbosityDetailsLevel, other.VerbosityDetailsLevel) - u.ValidationLogLevel = gosettings.OverrideWithPointer(u.ValidationLogLevel, other.ValidationLogLevel) - u.Username = gosettings.OverrideWithComparable(u.Username, other.Username) - u.Allowed = gosettings.OverrideWithSlice(u.Allowed, other.Allowed) -} - -func (u Unbound) ToUnboundFormat() (settings unbound.Settings, err error) { - providers := make([]provider.Provider, len(u.Providers)) - for i := range providers { - providers[i], err = provider.Parse(u.Providers[i]) - if err != nil { - return settings, err - } - } - - const port = 53 - - return unbound.Settings{ - ListeningPort: port, - IPv4: true, - Providers: providers, - Caching: *u.Caching, - IPv6: *u.IPv6, - VerbosityLevel: *u.VerbosityLevel, - VerbosityDetailsLevel: *u.VerbosityDetailsLevel, - ValidationLogLevel: *u.ValidationLogLevel, - AccessControl: unbound.AccessControlSettings{ - Allowed: netipPrefixesToNetaddrIPPrefixes(u.Allowed), - }, - Username: u.Username, - }, nil -} - -var ( - ErrConvertingNetip = errors.New("converting net.IP to netip.Addr failed") -) - -func (u Unbound) GetFirstPlaintextIPv4() (ipv4 netip.Addr, err error) { - s := u.Providers[0] - provider, err := provider.Parse(s) - if err != nil { - return ipv4, err - } - - ip := provider.DNS().IPv4[0] - ipv4, ok := netip.AddrFromSlice(ip) - if !ok { - return ipv4, fmt.Errorf("%w: for ip %s (%#v)", - ErrConvertingNetip, ip, ip) - } - return ipv4.Unmap(), nil -} - -func (u Unbound) String() string { - return u.toLinesNode().String() -} - -func (u Unbound) toLinesNode() (node *gotree.Node) { - node = gotree.New("Unbound settings:") - - authServers := node.Appendf("Authoritative servers:") - for _, provider := range u.Providers { - authServers.Appendf(provider) - } - - node.Appendf("Caching: %s", gosettings.BoolToYesNo(u.Caching)) - node.Appendf("IPv6: %s", gosettings.BoolToYesNo(u.IPv6)) - node.Appendf("Verbosity level: %d", *u.VerbosityLevel) - node.Appendf("Verbosity details level: %d", *u.VerbosityDetailsLevel) - node.Appendf("Validation log level: %d", *u.ValidationLogLevel) - node.Appendf("System user: %s", u.Username) - - allowedNetworks := node.Appendf("Allowed networks:") - for _, network := range u.Allowed { - allowedNetworks.Appendf(network.String()) - } - - return node -} - -func (u *Unbound) read(reader *reader.Reader) (err error) { - u.Providers = reader.CSV("DOT_PROVIDERS") - - u.Caching, err = reader.BoolPtr("DOT_CACHING") - if err != nil { - return err - } - - u.IPv6, err = reader.BoolPtr("DOT_IPV6") - if err != nil { - return err - } - - u.VerbosityLevel, err = reader.Uint8Ptr("DOT_VERBOSITY") - if err != nil { - return err - } - - u.VerbosityDetailsLevel, err = reader.Uint8Ptr("DOT_VERBOSITY_DETAILS") - if err != nil { - return err - } - - u.ValidationLogLevel, err = reader.Uint8Ptr("DOT_VALIDATION_LOGLEVEL") - if err != nil { - return err - } - - return nil -} diff --git a/internal/configuration/settings/unbound_test.go b/internal/configuration/settings/unbound_test.go deleted file mode 100644 index bf216fd51..000000000 --- a/internal/configuration/settings/unbound_test.go +++ /dev/null @@ -1,43 +0,0 @@ -package settings - -import ( - "encoding/json" - "net/netip" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func Test_Unbound_JSON(t *testing.T) { - t.Parallel() - - settings := Unbound{ - Providers: []string{"cloudflare"}, - Caching: boolPtr(true), - IPv6: boolPtr(false), - VerbosityLevel: uint8Ptr(1), - VerbosityDetailsLevel: nil, - ValidationLogLevel: uint8Ptr(0), - Username: "user", - Allowed: []netip.Prefix{ - netip.PrefixFrom(netip.AddrFrom4([4]byte{}), 0), - netip.PrefixFrom(netip.AddrFrom16([16]byte{}), 0), - }, - } - - b, err := json.Marshal(settings) - require.NoError(t, err) - - const expected = `{"providers":["cloudflare"],"caching":true,"ipv6":false,` + - `"verbosity_level":1,"verbosity_details_level":null,"validation_log_level":0,` + - `"username":"user","allowed":["0.0.0.0/0","::/0"]}` - - assert.Equal(t, expected, string(b)) - - var resultSettings Unbound - err = json.Unmarshal(b, &resultSettings) - require.NoError(t, err) - - assert.Equal(t, settings, resultSettings) -} diff --git a/internal/constants/colors.go b/internal/constants/colors.go index de8af916e..ecc8ac425 100644 --- a/internal/constants/colors.go +++ b/internal/constants/colors.go @@ -2,10 +2,6 @@ package constants import "github.com/fatih/color" -func ColorUnbound() *color.Color { - return color.New(color.FgCyan) -} - func ColorOpenvpn() *color.Color { return color.New(color.FgHiMagenta) } diff --git a/internal/dns/interfaces.go b/internal/dns/interfaces.go deleted file mode 100644 index efd1d4be3..000000000 --- a/internal/dns/interfaces.go +++ /dev/null @@ -1,15 +0,0 @@ -package dns - -import ( - "context" - - "github.com/qdm12/dns/pkg/unbound" -) - -type Configurator interface { - SetupFiles(ctx context.Context) error - MakeUnboundConf(settings unbound.Settings) (err error) - Start(ctx context.Context, verbosityDetailsLevel uint8) ( - stdoutLines, stderrLines chan string, waitError chan error, err error) - Version(ctx context.Context) (version string, err error) -} diff --git a/internal/dns/logs.go b/internal/dns/logs.go deleted file mode 100644 index 349661531..000000000 --- a/internal/dns/logs.go +++ /dev/null @@ -1,75 +0,0 @@ -package dns - -import ( - "context" - "regexp" - "strings" - - "github.com/qdm12/gluetun/internal/constants" -) - -type logLevel uint8 - -const ( - levelDebug logLevel = iota - levelInfo - levelWarn - levelError -) - -func (l *Loop) collectLines(ctx context.Context, done chan<- struct{}, - stdout, stderr chan string) { - defer close(done) - - var line string - - for { - select { - case <-ctx.Done(): - // Context should only be canceled after stdout and stderr are done - // being written to. - close(stdout) - close(stderr) - return - case line = <-stderr: - case line = <-stdout: - } - - line, level := processLogLine(line) - switch level { - case levelDebug: - l.logger.Debug(line) - case levelInfo: - l.logger.Info(line) - case levelWarn: - l.logger.Warn(line) - case levelError: - l.logger.Error(line) - } - } -} - -var unboundPrefix = regexp.MustCompile(`\[[0-9]{10}\] unbound\[[0-9]+:[0|1]\] `) - -func processLogLine(s string) (filtered string, level logLevel) { - prefix := unboundPrefix.FindString(s) - filtered = s[len(prefix):] - switch { - case strings.HasPrefix(filtered, "notice: "): - filtered = strings.TrimPrefix(filtered, "notice: ") - level = levelInfo - case strings.HasPrefix(filtered, "info: "): - filtered = strings.TrimPrefix(filtered, "info: ") - level = levelInfo - case strings.HasPrefix(filtered, "warn: "): - filtered = strings.TrimPrefix(filtered, "warn: ") - level = levelWarn - case strings.HasPrefix(filtered, "error: "): - filtered = strings.TrimPrefix(filtered, "error: ") - level = levelError - default: - level = levelInfo - } - filtered = constants.ColorUnbound().Sprintf(filtered) - return filtered, level -} diff --git a/internal/dns/logs_test.go b/internal/dns/logs_test.go deleted file mode 100644 index e173027cb..000000000 --- a/internal/dns/logs_test.go +++ /dev/null @@ -1,48 +0,0 @@ -package dns - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func Test_processLogLine(t *testing.T) { - t.Parallel() - tests := map[string]struct { - s string - filtered string - level logLevel - }{ - "empty string": {"", "", levelInfo}, - "random string": {"asdasqdb", "asdasqdb", levelInfo}, - "unbound notice": { - "[1594595249] unbound[75:0] notice: init module 0: validator", - "init module 0: validator", - levelInfo}, - "unbound info": { - "[1594595249] unbound[75:0] info: init module 0: validator", - "init module 0: validator", - levelInfo}, - "unbound warn": { - "[1594595249] unbound[75:0] warn: init module 0: validator", - "init module 0: validator", - levelWarn}, - "unbound error": { - "[1594595249] unbound[75:0] error: init module 0: validator", - "init module 0: validator", - levelError}, - "unbound unknown": { - "[1594595249] unbound[75:0] BLA: init module 0: validator", - "BLA: init module 0: validator", - levelInfo}, - } - for name, tc := range tests { - tc := tc - t.Run(name, func(t *testing.T) { - t.Parallel() - filtered, level := processLogLine(tc.s) - assert.Equal(t, tc.filtered, filtered) - assert.Equal(t, tc.level, level) - }) - } -} diff --git a/internal/dns/loop.go b/internal/dns/loop.go index fc4eb9ef7..f37766e28 100644 --- a/internal/dns/loop.go +++ b/internal/dns/loop.go @@ -2,10 +2,12 @@ package dns import ( "context" + "fmt" "net/http" "time" - "github.com/qdm12/dns/pkg/blacklist" + "github.com/qdm12/dns/v2/pkg/dot" + "github.com/qdm12/dns/v2/pkg/middlewares/filter/mapfilter" "github.com/qdm12/gluetun/internal/configuration/settings" "github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/dns/state" @@ -16,9 +18,9 @@ import ( type Loop struct { statusManager *loopstate.State state *state.State - conf Configurator + server *dot.Server + filter *mapfilter.Filter resolvConf string - blockBuilder blacklist.Builder client *http.Client logger Logger userTrigger bool @@ -34,8 +36,8 @@ type Loop struct { const defaultBackoffTime = 10 * time.Second -func NewLoop(conf Configurator, settings settings.DNS, - client *http.Client, logger Logger) *Loop { +func NewLoop(settings settings.DNS, + client *http.Client, logger Logger) (loop *Loop, err error) { start := make(chan struct{}) running := make(chan models.LoopStatus) stop := make(chan struct{}) @@ -45,12 +47,17 @@ func NewLoop(conf Configurator, settings settings.DNS, statusManager := loopstate.New(constants.Stopped, start, running, stop, stopped) state := state.New(statusManager, settings, updateTicker) + filter, err := mapfilter.New(mapfilter.Settings{}) + if err != nil { + return nil, fmt.Errorf("creating map filter: %w", err) + } + return &Loop{ statusManager: statusManager, state: state, - conf: conf, + server: nil, + filter: filter, resolvConf: "/etc/resolv.conf", - blockBuilder: blacklist.NewBuilder(client), client: client, logger: logger, userTrigger: true, @@ -62,7 +69,7 @@ func NewLoop(conf Configurator, settings settings.DNS, backoffTime: defaultBackoffTime, timeNow: time.Now, timeSince: time.Since, - } + }, nil } func (l *Loop) logAndWait(ctx context.Context, err error) { diff --git a/internal/dns/plaintext.go b/internal/dns/plaintext.go index 09eb8277c..d005c06f1 100644 --- a/internal/dns/plaintext.go +++ b/internal/dns/plaintext.go @@ -2,36 +2,22 @@ package dns import ( "net/netip" + "time" - "github.com/qdm12/dns/pkg/nameserver" + "github.com/qdm12/dns/v2/pkg/nameserver" ) func (l *Loop) useUnencryptedDNS(fallback bool) { settings := l.GetSettings() // Try with user provided plaintext ip address - // if it's not 127.0.0.1 (default for DoT) - targetIP := settings.ServerAddress - if targetIP.Compare(netip.AddrFrom4([4]byte{127, 0, 0, 1})) != 0 { - if fallback { - l.logger.Info("falling back on plaintext DNS at address " + targetIP.String()) - } else { - l.logger.Info("using plaintext DNS at address " + targetIP.String()) - } - nameserver.UseDNSInternally(targetIP.AsSlice()) - const keepNameserver = false - err := nameserver.UseDNSSystemWide(l.resolvConf, targetIP.AsSlice(), keepNameserver) - if err != nil { - l.logger.Error(err.Error()) - } - return - } - - // Use first plaintext DNS IPv4 address - targetIP, err := settings.DoT.Unbound.GetFirstPlaintextIPv4() - if err != nil { - // Unbound should always have a default provider - panic(err) + // if it's not 127.0.0.1 (default for DoT), otherwise + // use the first DoT provider ipv4 address found. + var targetIP netip.Addr + if settings.ServerAddress.Compare(netip.AddrFrom4([4]byte{127, 0, 0, 1})) != 0 { + targetIP = settings.ServerAddress + } else { + targetIP = settings.DoT.GetFirstPlaintextIPv4() } if fallback { @@ -39,9 +25,19 @@ func (l *Loop) useUnencryptedDNS(fallback bool) { } else { l.logger.Info("using plaintext DNS at address " + targetIP.String()) } - nameserver.UseDNSInternally(targetIP.AsSlice()) - const keepNameserver = false - err = nameserver.UseDNSSystemWide(l.resolvConf, targetIP.AsSlice(), keepNameserver) + + const dialTimeout = 3 * time.Second + settingsInternalDNS := nameserver.SettingsInternalDNS{ + IP: targetIP, + Timeout: dialTimeout, + } + nameserver.UseDNSInternally(settingsInternalDNS) + + settingsSystemWide := nameserver.SettingsSystemDNS{ + IP: targetIP, + ResolvPath: l.resolvConf, + } + err := nameserver.UseDNSSystemWide(settingsSystemWide) if err != nil { l.logger.Error(err.Error()) } diff --git a/internal/dns/run.go b/internal/dns/run.go index c6a52bbaa..f5d05e44a 100644 --- a/internal/dns/run.go +++ b/internal/dns/run.go @@ -26,16 +26,14 @@ func (l *Loop) Run(ctx context.Context, done chan<- struct{}) { } for ctx.Err() == nil { - // Upper scope variables for Unbound only + // Upper scope variables for the DNS over TLS server only // Their values are to be used if DOT=off - waitError := make(chan error) - unboundCancel := func() { waitError <- nil } - closeStreams := func() {} + var runError <-chan error settings := l.GetSettings() for !*settings.KeepNameserver && *settings.DoT.Enabled { var err error - unboundCancel, waitError, closeStreams, err = l.setupUnbound(ctx) + runError, err = l.setupServer(ctx) if err == nil { l.backoffTime = defaultBackoffTime l.logger.Info("ready") @@ -49,11 +47,12 @@ func (l *Loop) Run(ctx context.Context, done chan<- struct{}) { return } - if !errors.Is(err, errUpdateFiles) { + if !errors.Is(err, errUpdateBlockLists) { const fallback = true l.useUnencryptedDNS(fallback) } l.logAndWait(ctx, err) + settings = l.GetSettings() } settings = l.GetSettings() @@ -64,40 +63,44 @@ func (l *Loop) Run(ctx context.Context, done chan<- struct{}) { l.userTrigger = false - stayHere := true - for stayHere { - select { - case <-ctx.Done(): - unboundCancel() - <-waitError - close(waitError) - closeStreams() - return - case <-l.stop: - l.userTrigger = true - l.logger.Info("stopping") - const fallback = false - l.useUnencryptedDNS(fallback) - unboundCancel() - <-waitError - // do not close waitError or the waitError - // select case will trigger - closeStreams() - l.stopped <- struct{}{} - case <-l.start: - l.userTrigger = true - l.logger.Info("starting") - stayHere = false - case err := <-waitError: // unexpected error - closeStreams() + exitLoop := l.runWait(ctx, runError) + if exitLoop { + return + } + } +} - unboundCancel() - l.statusManager.SetStatus(constants.Crashed) - const fallback = true - l.useUnencryptedDNS(fallback) - l.logAndWait(ctx, err) - stayHere = false - } +func (l *Loop) runWait(ctx context.Context, runError <-chan error) (exitLoop bool) { + for { + select { + case <-ctx.Done(): + l.stopServer() + // TODO revert OS and Go nameserver when exiting + return true + case <-l.stop: + l.userTrigger = true + l.logger.Info("stopping") + const fallback = false + l.useUnencryptedDNS(fallback) + l.stopServer() + l.stopped <- struct{}{} + case <-l.start: + l.userTrigger = true + l.logger.Info("starting") + return false + case err := <-runError: // unexpected error + l.statusManager.SetStatus(constants.Crashed) + const fallback = true + l.useUnencryptedDNS(fallback) + l.logAndWait(ctx, err) + return false } } } + +func (l *Loop) stopServer() { + stopErr := l.server.Stop() + if stopErr != nil { + l.logger.Error("stopping DoT server: " + stopErr.Error()) + } +} diff --git a/internal/dns/settings.go b/internal/dns/settings.go index 71744c955..4b11ef037 100644 --- a/internal/dns/settings.go +++ b/internal/dns/settings.go @@ -2,7 +2,14 @@ package dns import ( "context" + "fmt" + "github.com/qdm12/dns/v2/pkg/dot" + cachemiddleware "github.com/qdm12/dns/v2/pkg/middlewares/cache" + "github.com/qdm12/dns/v2/pkg/middlewares/cache/lru" + filtermiddleware "github.com/qdm12/dns/v2/pkg/middlewares/filter" + "github.com/qdm12/dns/v2/pkg/middlewares/filter/mapfilter" + "github.com/qdm12/dns/v2/pkg/provider" "github.com/qdm12/gluetun/internal/configuration/settings" ) @@ -12,3 +19,55 @@ func (l *Loop) SetSettings(ctx context.Context, settings settings.DNS) ( outcome string) { return l.state.SetSettings(ctx, settings) } + +func buildDoTSettings(settings settings.DNS, + filter *mapfilter.Filter, logger Logger) ( + dotSettings dot.ServerSettings, err error) { + var middlewares []dot.Middleware + + if *settings.DoT.Caching { + lruCache, err := lru.New(lru.Settings{}) + if err != nil { + return dot.ServerSettings{}, fmt.Errorf("creating LRU cache: %w", err) + } + cacheMiddleware, err := cachemiddleware.New(cachemiddleware.Settings{ + Cache: lruCache, + }) + if err != nil { + return dot.ServerSettings{}, fmt.Errorf("creating cache middleware: %w", err) + } + middlewares = append(middlewares, cacheMiddleware) + } + + filterMiddleware, err := filtermiddleware.New(filtermiddleware.Settings{ + Filter: filter, + }) + if err != nil { + return dot.ServerSettings{}, fmt.Errorf("creating filter middleware: %w", err) + } + middlewares = append(middlewares, filterMiddleware) + + providersData := provider.NewProviders() + providers := make([]provider.Provider, len(settings.DoT.Providers)) + for i := range settings.DoT.Providers { + var err error + providers[i], err = providersData.Get(settings.DoT.Providers[i]) + if err != nil { + panic(err) // this should already had been checked + } + } + + ipVersion := "ipv4" + if *settings.DoT.IPv6 { + ipVersion = "ipv6" + } + return dot.ServerSettings{ + Resolver: dot.ResolverSettings{ + UpstreamResolvers: providers, + IPVersion: ipVersion, + Warner: logger, + }, + Middlewares: middlewares, + Logger: logger, + }, nil +} diff --git a/internal/dns/setup.go b/internal/dns/setup.go index 0443e08b0..510511632 100644 --- a/internal/dns/setup.go +++ b/internal/dns/setup.go @@ -4,59 +4,55 @@ import ( "context" "errors" "fmt" - "net" - "github.com/qdm12/dns/pkg/check" - "github.com/qdm12/dns/pkg/nameserver" + "github.com/qdm12/dns/v2/pkg/check" + "github.com/qdm12/dns/v2/pkg/dot" + "github.com/qdm12/dns/v2/pkg/nameserver" ) -var errUpdateFiles = errors.New("cannot update files") +var errUpdateBlockLists = errors.New("cannot update filter block lists") -// Returning cancel == nil signals we want to re-run setupUnbound -// Returning err == errUpdateFiles signals we should not fall back -// on the plaintext DNS as DOT is still up and running. -func (l *Loop) setupUnbound(ctx context.Context) ( - cancel context.CancelFunc, waitError chan error, closeStreams func(), err error) { +func (l *Loop) setupServer(ctx context.Context) (runError <-chan error, err error) { err = l.updateFiles(ctx) if err != nil { - return nil, nil, nil, - fmt.Errorf("%w: %s", errUpdateFiles, err) + return nil, fmt.Errorf("%w: %w", errUpdateBlockLists, err) } settings := l.GetSettings() - unboundCtx, cancel := context.WithCancel(context.Background()) - stdoutLines, stderrLines, waitError, err := l.conf.Start(unboundCtx, - *settings.DoT.Unbound.VerbosityDetailsLevel) + dotSettings, err := buildDoTSettings(settings, l.filter, l.logger) if err != nil { - cancel() - return nil, nil, nil, err + return nil, fmt.Errorf("building DoT settings: %w", err) } - linesCollectionCtx, linesCollectionCancel := context.WithCancel(context.Background()) - lineCollectionDone := make(chan struct{}) - go l.collectLines(linesCollectionCtx, lineCollectionDone, - stdoutLines, stderrLines) - closeStreams = func() { - linesCollectionCancel() - <-lineCollectionDone + server, err := dot.NewServer(dotSettings) + if err != nil { + return nil, fmt.Errorf("creating DoT server: %w", err) } - // use Unbound - nameserver.UseDNSInternally(settings.ServerAddress.AsSlice()) - err = nameserver.UseDNSSystemWide(l.resolvConf, settings.ServerAddress.AsSlice(), - *settings.KeepNameserver) + runError, err = server.Start() + if err != nil { + return nil, fmt.Errorf("starting server: %w", err) + } + l.server = server + + // use internal DNS server + nameserver.UseDNSInternally(nameserver.SettingsInternalDNS{ + IP: settings.ServerAddress, + }) + err = nameserver.UseDNSSystemWide(nameserver.SettingsSystemDNS{ + IP: settings.ServerAddress, + ResolvPath: l.resolvConf, + }) if err != nil { l.logger.Error(err.Error()) } - if err := check.WaitForDNS(ctx, net.DefaultResolver); err != nil { - cancel() - <-waitError - close(waitError) - closeStreams() - return nil, nil, nil, err + err = check.WaitForDNS(ctx, check.Settings{}) + if err != nil { + l.stopServer() + return nil, err } - return cancel, waitError, closeStreams, nil + return runError, nil } diff --git a/internal/dns/ticker.go b/internal/dns/ticker.go index 7076092e5..f926bc493 100644 --- a/internal/dns/ticker.go +++ b/internal/dns/ticker.go @@ -34,7 +34,7 @@ func (l *Loop) RunRestartTicker(ctx context.Context, done chan<- struct{}) { if err := l.updateFiles(ctx); err != nil { l.statusManager.SetStatus(constants.Crashed) l.logger.Error(err.Error()) - l.logger.Warn("skipping Unbound restart due to failed files update") + l.logger.Warn("skipping DNS server restart due to failed files update") continue } } diff --git a/internal/dns/update.go b/internal/dns/update.go index 6701dd025..9526d53be 100644 --- a/internal/dns/update.go +++ b/internal/dns/update.go @@ -1,35 +1,46 @@ package dns -import "context" +import ( + "context" + "fmt" + + "github.com/qdm12/dns/v2/pkg/blockbuilder" + "github.com/qdm12/dns/v2/pkg/middlewares/filter/update" +) func (l *Loop) updateFiles(ctx context.Context) (err error) { - l.logger.Info("downloading DNS over TLS cryptographic files") - if err := l.conf.SetupFiles(ctx); err != nil { - return err - } settings := l.GetSettings() - unboundSettings, err := settings.DoT.Unbound.ToUnboundFormat() + l.logger.Info("downloading hostnames and IP block lists") + blacklistSettings := settings.DoT.Blacklist.ToBlockBuilderSettings(l.client) + + blockBuilder, err := blockbuilder.New(blacklistSettings) if err != nil { - return err + return fmt.Errorf("creating block builder: %w", err) + } + + result := blockBuilder.BuildAll(ctx) + for _, resultErr := range result.Errors { + if err != nil { + err = fmt.Errorf("%w, %w", err, resultErr) + continue + } + err = resultErr } - l.logger.Info("downloading hostnames and IP block lists") - blacklistSettings, err := settings.DoT.Blacklist.ToBlacklistFormat() if err != nil { return err } - blockedHostnames, blockedIPs, blockedIPPrefixes, errs := - l.blockBuilder.All(ctx, blacklistSettings) - for _, err := range errs { - l.logger.Warn(err.Error()) + updateSettings := update.Settings{ + IPs: result.BlockedIPs, + IPPrefixes: result.BlockedIPPrefixes, + } + updateSettings.BlockHostnames(result.BlockedHostnames) + err = l.filter.Update(updateSettings) + if err != nil { + return fmt.Errorf("updating filter: %w", err) } - // TODO change to BlockHostnames() when migrating to qdm12/dns v2 - unboundSettings.Blacklist.FqdnHostnames = blockedHostnames - unboundSettings.Blacklist.IPs = blockedIPs - unboundSettings.Blacklist.IPPrefixes = blockedIPPrefixes - - return l.conf.MakeUnboundConf(unboundSettings) + return nil } diff --git a/internal/server/handler.go b/internal/server/handler.go index 29ae2ca5b..874cd9954 100644 --- a/internal/server/handler.go +++ b/internal/server/handler.go @@ -12,7 +12,7 @@ func newHandler(ctx context.Context, logger infoWarner, logging bool, buildInfo models.BuildInformation, vpnLooper VPNLooper, pfGetter PortForwardedGetter, - unboundLooper DNSLoop, + dnsLooper DNSLoop, updaterLooper UpdaterLooper, publicIPLooper PublicIPLoop, storage Storage, @@ -22,11 +22,11 @@ func newHandler(ctx context.Context, logger infoWarner, logging bool, vpn := newVPNHandler(ctx, vpnLooper, storage, ipv6Supported, logger) openvpn := newOpenvpnHandler(ctx, vpnLooper, pfGetter, logger) - dns := newDNSHandler(ctx, unboundLooper, logger) + dns := newDNSHandler(ctx, dnsLooper, logger) updater := newUpdaterHandler(ctx, updaterLooper, logger) publicip := newPublicIPHandler(publicIPLooper, logger) - handler.v0 = newHandlerV0(ctx, logger, vpnLooper, unboundLooper, updaterLooper) + handler.v0 = newHandlerV0(ctx, logger, vpnLooper, dnsLooper, updaterLooper) handler.v1 = newHandlerV1(logger, buildInfo, vpn, openvpn, dns, updater, publicip) handlerWithLog := withLogMiddleware(handler, logger, logging) diff --git a/internal/server/handlerv0.go b/internal/server/handlerv0.go index 6f2c92ea2..7135bbb3d 100644 --- a/internal/server/handlerv0.go +++ b/internal/server/handlerv0.go @@ -42,7 +42,7 @@ func (h *handlerV0) ServeHTTP(w http.ResponseWriter, r *http.Request) { if _, err := w.Write([]byte("openvpn restarted, please consider using the /v1/ API in the future.")); err != nil { h.logger.Warn(err.Error()) } - case "/unbound/actions/restart": + case "/unbound/actions/restart": // TODO v4 change to /dns/ outcome, _ := h.dns.ApplyStatus(h.ctx, constants.Stopped) h.logger.Info("dns: " + outcome) outcome, _ = h.dns.ApplyStatus(h.ctx, constants.Running) diff --git a/internal/server/server.go b/internal/server/server.go index 9f31a9465..c940fec61 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -10,12 +10,12 @@ import ( func New(ctx context.Context, address string, logEnabled bool, logger Logger, buildInfo models.BuildInformation, openvpnLooper VPNLooper, - pfGetter PortForwardedGetter, unboundLooper DNSLoop, + pfGetter PortForwardedGetter, dnsLooper DNSLoop, updaterLooper UpdaterLooper, publicIPLooper PublicIPLoop, storage Storage, ipv6Supported bool) ( server *httpserver.Server, err error) { handler := newHandler(ctx, logger, logEnabled, buildInfo, - openvpnLooper, pfGetter, unboundLooper, updaterLooper, publicIPLooper, + openvpnLooper, pfGetter, dnsLooper, updaterLooper, publicIPLooper, storage, ipv6Supported) httpServerSettings := httpserver.Settings{ diff --git a/maintenance.md b/maintenance.md index 0c123abaa..6282b7383 100644 --- a/maintenance.md +++ b/maintenance.md @@ -1,8 +1,7 @@ # Maintenance -- Rename `UNBLOCK` to `DOT_UNBOUND_UNBLOCK` +- Rename `UNBLOCK` to `DNS_HOSTNAMES_UNBLOCKED` - Change `Run` methods to `Start`+`Stop`, returning channels rather than injecting them -- Use DNS v2 beta - Go 1.18 - gofumpt - Use netip