diff --git a/CHANGELOG.md b/CHANGELOG.md index 6412150d..6e6a537a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,8 @@ NOTE: Add new changes BELOW THIS COMMENT. ### Changed +- `$dnsrewrite` rules containing IPv4-mapped IPv6 addresses are now working + consistently with legacy DNS rewrites and match the `AAAA` requests. - For non-A and non-AAAA requests, which has been filtered, the NODATA response is returned if the blocking mode isn't set to `Null IP`. In previous versions it returned NXDOMAIN response in such cases. @@ -67,6 +69,8 @@ In this release, the schema version has changed from 24 to 25. ### Fixed +- Legacy DNS rewrites containing IPv4-mapped IPv6 addresses are now matching the + `AAAA` requests, not `A` ([#6050]). - File log configuration, such as `max_size`, being ignored ([#6093]). - Panic on using a single-slash filtering rule. - Panic on shutting down while DNS requests are in process of filtering @@ -76,6 +80,7 @@ In this release, the schema version has changed from 24 to 25. [#3701]: https://github.com/AdguardTeam/AdGuardHome/issues/3701 [#5948]: https://github.com/AdguardTeam/AdGuardHome/issues/5948 [#6020]: https://github.com/AdguardTeam/AdGuardHome/issues/6020 +[#6050]: https://github.com/AdguardTeam/AdGuardHome/issues/6050 [#6053]: https://github.com/AdguardTeam/AdGuardHome/issues/6053 [#6093]: https://github.com/AdguardTeam/AdGuardHome/issues/6093 [#6122]: https://github.com/AdguardTeam/AdGuardHome/issues/6122 diff --git a/go.mod b/go.mod index d4ba483c..014d8845 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.20 require ( github.com/AdguardTeam/dnsproxy v0.54.0 github.com/AdguardTeam/golibs v0.15.0 - github.com/AdguardTeam/urlfilter v0.16.2 + github.com/AdguardTeam/urlfilter v0.17.0 github.com/NYTimes/gziphandler v1.1.1 github.com/ameshkov/dnscrypt/v2 v2.2.7 github.com/bluele/gcache v0.0.2 @@ -32,7 +32,7 @@ require ( github.com/ti-mo/netfilter v0.5.0 go.etcd.io/bbolt v1.3.7 golang.org/x/crypto v0.12.0 - golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb + golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 golang.org/x/net v0.14.0 golang.org/x/sys v0.11.0 gopkg.in/natefinch/lumberjack.v2 v2.2.1 @@ -61,5 +61,5 @@ require ( golang.org/x/mod v0.12.0 // indirect golang.org/x/sync v0.3.0 // indirect golang.org/x/text v0.12.0 // indirect - golang.org/x/tools v0.12.0 // indirect + golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 // indirect ) diff --git a/go.sum b/go.sum index 682064eb..bf1c6e7f 100644 --- a/go.sum +++ b/go.sum @@ -1,16 +1,11 @@ github.com/AdguardTeam/dnsproxy v0.54.0 h1:OgSitM/EKrMMOi+guWZNwaU1cqRqJKWgR3l3fPWWayI= github.com/AdguardTeam/dnsproxy v0.54.0/go.mod h1:tG/treaQekcKnugYoKOfm8vt3JGi6CliWta0MkQr15U= -github.com/AdguardTeam/golibs v0.4.0/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4= -github.com/AdguardTeam/golibs v0.10.4/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw= github.com/AdguardTeam/golibs v0.15.0 h1:yOv/fdVkJIOWKr0NlUXAE9RA0DK9GKiBbiGzq47vY7o= github.com/AdguardTeam/golibs v0.15.0/go.mod h1:66ZLs8P7nk/3IfKroQ1rqtieLk+5eXYXMBKXlVL7KeI= -github.com/AdguardTeam/gomitmproxy v0.2.0/go.mod h1:Qdv0Mktnzer5zpdpi5rAwixNJzW2FN91LjKJCkVbYGU= -github.com/AdguardTeam/urlfilter v0.16.2 h1:k9m9dUYVJ3sTswYa2/ukVNjicfGcz0oqFDO13hPmfHE= -github.com/AdguardTeam/urlfilter v0.16.2/go.mod h1:46YZDOV1+qtdRDuhZKVPSSp7JWWes0KayqHrKAFBdEI= +github.com/AdguardTeam/urlfilter v0.17.0 h1:tUzhtR9wMx704GIP3cibsDQJrixlMHfwoQbYJfPdFow= +github.com/AdguardTeam/urlfilter v0.17.0/go.mod h1:bbuZjPUzm/Ip+nz5qPPbwIP+9rZyQbQad8Lt/0fCulU= github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= -github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= -github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY= github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA= github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 h1:52m0LGchQBBVqJRyYYufQuIbVqRawmubW3OFGqK1ekw= @@ -23,7 +18,6 @@ github.com/beefsack/go-rate v0.0.0-20220214233405-116f4ca011a0 h1:0b2vaepXIfMsG+ github.com/beefsack/go-rate v0.0.0-20220214233405-116f4ca011a0/go.mod h1:6YNgTHLutezwnBvyneBbwvB8C82y3dcoOj5EQJIdGXA= github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw= github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 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= @@ -34,8 +28,7 @@ github.com/dimfeld/httptreemux/v5 v5.5.0/go.mod h1:QeEylH57C0v3VO0tkKraVz9oD3Uu9 github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY= -github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ping/ping v1.1.0 h1:3MCGhVX4fyEUuhsfwPrsEdQw6xspHkv5zHsiSoDFZYw= github.com/go-ping/ping v1.1.0/go.mod h1:xIFjORFzTxqIV/tDVGO4eDy/bLuSyawEeojSm3GfRGk= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= @@ -67,10 +60,8 @@ github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86 h1:elKwZS1OcdQ0 github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86/go.mod h1:aFAMtuldEgx/4q7iSGazk22+IcgvtiC+HIimFO9XlS8= github.com/kardianos/service v1.2.2 h1:ZvePhAHfvo0A7Mftk/tEzqEZ7Q4lgnR8sGz4xu1YX60= github.com/kardianos/service v1.2.2/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118 h1:2oDp6OOhLxQ9JBoUuysVz9UZ9uI6oLUbvAZu0x8o+vE= github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118/go.mod h1:ZFUnHIVchZ9lJoWoEGUg8Q3M4U8aNNWA3CVSUTkW4og= github.com/mdlayher/netlink v0.0.0-20190313131330-258ea9dff42c/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= @@ -84,11 +75,9 @@ github.com/mdlayher/raw v0.1.0/go.mod h1:yXnxvs6c0XoF/aK52/H5PjsVHmWBCFfZUfoh/Y5 github.com/mdlayher/socket v0.2.1/go.mod h1:QLlNPkFR88mRUNQIzRBMfXxwKal8H7u1h3bL1CV+f0E= 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.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc= @@ -102,40 +91,38 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.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/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= github.com/quic-go/qtls-go1-20 v0.3.2 h1:rRgN3WfnKbyik4dBV8A6girlJVxGand/d+jVKbQq5GI= github.com/quic-go/qtls-go1-20 v0.3.2/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= github.com/quic-go/quic-go v0.37.4 h1:ke8B73yMCWGq9MfrCCAw0Uzdm7GaViC3i39dsIdDlH4= github.com/quic-go/quic-go v0.37.4/go.mod h1:YsbH1r4mSHPJcLF4k4zruUkLBqctEMBDR6VPvcYjIsU= -github.com/shirou/gopsutil/v3 v3.21.8 h1:nKct+uP0TV8DjjNiHanKf8SAuub+GNsbrOtM9Nl9biA= -github.com/shirou/gopsutil/v3 v3.21.8/go.mod h1:YWp/H8Qs5fVmf17v7JNZzA0mPJ+mS2e9JdiUF9LlKzQ= +github.com/shirou/gopsutil/v3 v3.23.7 h1:C+fHO8hfIppoJ1WdsVm1RoI0RwXoNdfTK7yWXV0wVj4= +github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/ti-mo/netfilter v0.2.0/go.mod h1:8GbBGsY/8fxtyIdfwy29JiluNcPK4K7wIT+x42ipqUU= github.com/ti-mo/netfilter v0.5.0 h1:MZmsUw5bFRecOb0AeyjOPxTHg4UxYzyEs0Ek/6Lxoy8= github.com/ti-mo/netfilter v0.5.0/go.mod h1:nt+8B9hx/QpqHr7Hazq+2qMCCA8u2OTkyc/7+U9ARz8= -github.com/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev3vTo= -github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs= -github.com/tklauser/numcpus v0.3.0 h1:ILuRUQBtssgnxw0XXIjKUC56fgnOrFoQQ/4+DeU2biQ= -github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8= +github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM= +github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms= github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63 h1:YcojQL98T/OO+rybuzn2+5KrD5dBwXIvYBvQ2cD3Avg= github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= -golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb h1:mIKbk8weKhSeLH2GmUTrvx8CjkyJmnU1wFmg59CUjFA= -golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ= +golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -146,10 +133,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210929193557-e81a3d93ecf6/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -160,16 +145,11 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190322080309-f49334f85ddc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210909193231-528a39cd75f3/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -179,18 +159,15 @@ golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss= -golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= +golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E= +golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= 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= @@ -198,12 +175,9 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/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= diff --git a/internal/aghtest/aghtest.go b/internal/aghtest/aghtest.go index 955d6b33..3297795a 100644 --- a/internal/aghtest/aghtest.go +++ b/internal/aghtest/aghtest.go @@ -4,7 +4,7 @@ package aghtest import ( "crypto/sha256" "io" - "net" + "net/netip" "testing" "github.com/AdguardTeam/golibs/log" @@ -46,8 +46,8 @@ func ReplaceLogLevel(t testing.TB, l log.Level) { } // HostToIPs is a helper that generates one IPv4 and one IPv6 address from host. -func HostToIPs(host string) (ipv4, ipv6 net.IP) { +func HostToIPs(host string) (ipv4, ipv6 netip.Addr) { hash := sha256.Sum256([]byte(host)) - return net.IP(hash[:4]), net.IP(hash[4:20]) + return netip.AddrFrom4([4]byte(hash[:4])), netip.AddrFrom16([16]byte(hash[4:20])) } diff --git a/internal/dnsforward/access.go b/internal/dnsforward/access.go index c367d05b..d29afbde 100644 --- a/internal/dnsforward/access.go +++ b/internal/dnsforward/access.go @@ -131,7 +131,6 @@ func (a *accessManager) isBlockedClientID(id string) (ok bool) { func (a *accessManager) isBlockedHost(host string, qt rules.RRType) (ok bool) { _, ok = a.blockedHostsEng.MatchRequest(&urlfilter.DNSRequest{ Hostname: host, - ClientIP: "0.0.0.0", DNSType: qt, }) diff --git a/internal/dnsforward/config.go b/internal/dnsforward/config.go index 89695cc5..a59b8a8e 100644 --- a/internal/dnsforward/config.go +++ b/internal/dnsforward/config.go @@ -55,7 +55,7 @@ type FilteringConfig struct { // Callbacks for other modules // FilterHandler is an optional additional filtering callback. - FilterHandler func(clientAddr net.IP, clientID string, settings *filtering.Settings) `yaml:"-"` + FilterHandler func(cliAddr netip.Addr, clientID string, settings *filtering.Settings) `yaml:"-"` // GetCustomUpstreamByClient is a callback that returns upstreams // configuration based on the client IP address or ClientID. It returns @@ -71,11 +71,11 @@ type FilteringConfig struct { BlockingMode BlockingMode `yaml:"blocking_mode"` // BlockingIPv4 is the IP address to be returned for a blocked A request. - BlockingIPv4 net.IP `yaml:"blocking_ipv4"` + BlockingIPv4 netip.Addr `yaml:"blocking_ipv4"` // BlockingIPv6 is the IP address to be returned for a blocked AAAA // request. - BlockingIPv6 net.IP `yaml:"blocking_ipv6"` + BlockingIPv6 netip.Addr `yaml:"blocking_ipv6"` // BlockedResponseTTL is the time-to-live value for blocked responses. If // 0, then default value is used (3600). diff --git a/internal/dnsforward/dnsforward.go b/internal/dnsforward/dnsforward.go index c1ee6686..c1ff6751 100644 --- a/internal/dnsforward/dnsforward.go +++ b/internal/dnsforward/dnsforward.go @@ -645,7 +645,7 @@ func (s *Server) setupAddrProc() { } // validateBlockingMode returns an error if the blocking mode data aren't valid. -func validateBlockingMode(mode BlockingMode, blockingIPv4, blockingIPv6 net.IP) (err error) { +func validateBlockingMode(mode BlockingMode, blockingIPv4, blockingIPv6 netip.Addr) (err error) { switch mode { case BlockingModeDefault, @@ -654,10 +654,10 @@ func validateBlockingMode(mode BlockingMode, blockingIPv4, blockingIPv6 net.IP) BlockingModeNullIP: return nil case BlockingModeCustomIP: - if blockingIPv4 == nil { - return fmt.Errorf("blocking_ipv4 must be set when blocking_mode is custom_ip") - } else if blockingIPv6 == nil { - return fmt.Errorf("blocking_ipv6 must be set when blocking_mode is custom_ip") + if !blockingIPv4.Is4() { + return fmt.Errorf("blocking_ipv4 must be valid ipv4 on custom_ip blocking_mode") + } else if !blockingIPv6.Is6() { + return fmt.Errorf("blocking_ipv6 must be valid ipv6 on custom_ip blocking_mode") } return nil diff --git a/internal/dnsforward/dnsforward_test.go b/internal/dnsforward/dnsforward_test.go index acc8a6d1..fda64807 100644 --- a/internal/dnsforward/dnsforward_test.go +++ b/internal/dnsforward/dnsforward_test.go @@ -243,17 +243,17 @@ func newResp(rcode int, req *dns.Msg, ans []dns.RR) (resp *dns.Msg) { } func assertGoogleAResponse(t *testing.T, reply *dns.Msg) { - assertResponse(t, reply, net.IP{8, 8, 8, 8}) + assertResponse(t, reply, netip.AddrFrom4([4]byte{8, 8, 8, 8})) } -func assertResponse(t *testing.T, reply *dns.Msg, ip net.IP) { +func assertResponse(t *testing.T, reply *dns.Msg, ip netip.Addr) { t.Helper() require.Lenf(t, reply.Answer, 1, "dns server returned reply with wrong number of answers - %d", len(reply.Answer)) a, ok := reply.Answer[0].(*dns.A) require.Truef(t, ok, "dns server returned wrong answer type instead of A: %v", reply.Answer[0]) - assert.Truef(t, a.A.Equal(ip), "dns server returned wrong answer instead of %s: %s", ip, a.A) + assert.Equal(t, net.IP(ip.AsSlice()), a.A) } // sendTestMessagesAsync sends messages in parallel to check for race issues. @@ -473,7 +473,7 @@ func TestSafeSearch(t *testing.T) { OnLookupIP: func(_ context.Context, _, host string) (ips []net.IP, err error) { ip4, ip6 := aghtest.HostToIPs(host) - return []net.IP{ip4, ip6}, nil + return []net.IP{ip4.AsSlice(), ip6.AsSlice()}, nil }, } @@ -514,12 +514,12 @@ func TestSafeSearch(t *testing.T) { addr := s.dnsProxy.Addr(proxy.ProtoUDP).String() client := &dns.Client{} - yandexIP := net.IP{213, 180, 193, 56} + yandexIP := netip.AddrFrom4([4]byte{213, 180, 193, 56}) googleIP, _ := aghtest.HostToIPs("forcesafesearch.google.com") testCases := []struct { host string - want net.IP + want netip.Addr }{{ host: "yandex.com.", want: yandexIP, @@ -776,7 +776,7 @@ func TestClientRulesForCNAMEMatching(t *testing.T) { TCPListenAddrs: []*net.TCPAddr{{}}, FilteringConfig: FilteringConfig{ ProtectionEnabled: true, - FilterHandler: func(_ net.IP, _ string, settings *filtering.Settings) { + FilterHandler: func(_ netip.Addr, _ string, settings *filtering.Settings) { settings.FilteringEnabled = false }, EDNSClientSubnet: &EDNSClientSubnet{ @@ -876,7 +876,8 @@ func TestBlockedCustomIP(t *testing.T) { FilteringConfig: FilteringConfig{ ProtectionEnabled: true, BlockingMode: BlockingModeCustomIP, - BlockingIPv4: nil, + BlockingIPv4: netip.Addr{}, + BlockingIPv6: netip.Addr{}, UpstreamDNS: []string{"8.8.8.8:53", "8.8.4.4:53"}, EDNSClientSubnet: &EDNSClientSubnet{ Enabled: false, @@ -888,8 +889,8 @@ func TestBlockedCustomIP(t *testing.T) { err = s.Prepare(conf) assert.Error(t, err) - conf.BlockingIPv4 = net.IP{0, 0, 0, 1} - conf.BlockingIPv6 = net.ParseIP("::1") + conf.BlockingIPv4 = netip.AddrFrom4([4]byte{0, 0, 0, 1}) + conf.BlockingIPv6 = netip.MustParseAddr("::1") err = s.Prepare(conf) require.NoError(t, err) @@ -991,9 +992,7 @@ func TestBlockedBySafeBrowsing(t *testing.T) { require.NoErrorf(t, err, "couldn't talk to server %s: %s", addr, err) require.Lenf(t, reply.Answer, 1, "dns server %s returned reply with wrong number of answers - %d", addr, len(reply.Answer)) - a, ok := reply.Answer[0].(*dns.A) - require.Truef(t, ok, "dns server %s returned wrong answer type instead of A: %v", addr, reply.Answer[0]) - assert.Equal(t, ans4, a.A, "dns server %s returned wrong answer: %v", addr, a.A) + assertResponse(t, reply, ans4) } func TestRewrite(t *testing.T) { diff --git a/internal/dnsforward/dnsrewrite.go b/internal/dnsforward/dnsrewrite.go index 47eab12b..8b9a0fb1 100644 --- a/internal/dnsforward/dnsrewrite.go +++ b/internal/dnsforward/dnsrewrite.go @@ -2,7 +2,7 @@ package dnsforward import ( "fmt" - "net" + "net/netip" "github.com/AdguardTeam/AdGuardHome/internal/filtering" "github.com/AdguardTeam/dnsproxy/proxy" @@ -44,13 +44,13 @@ func (s *Server) ansFromDNSRewriteIP( rr rules.RRType, req *dns.Msg, ) (ans dns.RR, err error) { - ip, ok := v.(net.IP) + ip, ok := v.(netip.Addr) if !ok { - return nil, fmt.Errorf("value for rr type %s has type %T, not net.IP", dns.Type(rr), v) + return nil, fmt.Errorf("value for rr type %s has type %T, not netip.Addr", dns.Type(rr), v) } if rr == dns.TypeA { - return s.genAnswerA(req, ip.To4()), nil + return s.genAnswerA(req, ip), nil } return s.genAnswerAAAA(req, ip), nil @@ -160,13 +160,13 @@ func (s *Server) filterDNSRewrite( return errors.Error("no dns rewrite rule responses") } - rr := req.Question[0].Qtype - values := dnsrr.Response[rr] + qtype := req.Question[0].Qtype + values := dnsrr.Response[qtype] for i, v := range values { var ans dns.RR - ans, err = s.filterDNSRewriteResponse(req, rr, v) + ans, err = s.filterDNSRewriteResponse(req, qtype, v) if err != nil { - return fmt.Errorf("dns rewrite response for %d[%d]: %w", rr, i, err) + return fmt.Errorf("dns rewrite response for %s[%d]: %w", dns.Type(qtype), i, err) } resp.Answer = append(resp.Answer, ans) diff --git a/internal/dnsforward/dnsrewrite_test.go b/internal/dnsforward/dnsrewrite_test.go index 422759a3..5d591c2c 100644 --- a/internal/dnsforward/dnsrewrite_test.go +++ b/internal/dnsforward/dnsrewrite_test.go @@ -6,6 +6,7 @@ import ( "github.com/AdguardTeam/AdGuardHome/internal/filtering" "github.com/AdguardTeam/dnsproxy/proxy" + "github.com/AdguardTeam/golibs/netutil" "github.com/AdguardTeam/urlfilter/rules" "github.com/miekg/dns" "github.com/stretchr/testify/assert" @@ -15,8 +16,7 @@ import ( func TestServer_FilterDNSRewrite(t *testing.T) { // Helper data. const domain = "example.com" - ip4 := net.IP{127, 0, 0, 1} - ip6 := net.IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1} + ip4, ip6 := netutil.IPv4Localhost(), netutil.IPv6Localhost() mxVal := &rules.DNSMX{ Exchange: "mail.example.com", Preference: 32, @@ -89,7 +89,7 @@ func TestServer_FilterDNSRewrite(t *testing.T) { assert.Equal(t, dns.RcodeSuccess, d.Res.Rcode) require.Len(t, d.Res.Answer, 1) - assert.Equal(t, ip4, d.Res.Answer[0].(*dns.A).A) + assert.Equal(t, net.IP(ip4.AsSlice()), d.Res.Answer[0].(*dns.A).A) }) t.Run("noerror_aaaa", func(t *testing.T) { @@ -103,7 +103,7 @@ func TestServer_FilterDNSRewrite(t *testing.T) { assert.Equal(t, dns.RcodeSuccess, d.Res.Rcode) require.Len(t, d.Res.Answer, 1) - assert.Equal(t, ip6, d.Res.Answer[0].(*dns.AAAA).AAAA) + assert.Equal(t, net.IP(ip6.AsSlice()), d.Res.Answer[0].(*dns.AAAA).AAAA) }) t.Run("noerror_ptr", func(t *testing.T) { diff --git a/internal/dnsforward/filter.go b/internal/dnsforward/filter.go index 022b51c0..6f551e59 100644 --- a/internal/dnsforward/filter.go +++ b/internal/dnsforward/filter.go @@ -59,8 +59,8 @@ func (s *Server) clientRequestFilteringSettings(dctx *dnsContext) (setts *filter setts = s.dnsFilter.Settings() setts.ProtectionEnabled = dctx.protectionEnabled if s.conf.FilterHandler != nil { - ip, _ := netutil.IPAndPortFromAddr(dctx.proxyCtx.Addr) - s.conf.FilterHandler(ip, dctx.clientID, setts) + addrPort := netutil.NetAddrToAddrPort(dctx.proxyCtx.Addr) + s.conf.FilterHandler(addrPort.Addr(), dctx.clientID, setts) } return setts @@ -125,7 +125,7 @@ func (s *Server) filterRewritten( for _, ip := range res.IPList { switch qt { case dns.TypeA: - a := s.genAnswerA(req, ip.To4()) + a := s.genAnswerA(req, ip) a.Hdr.Name = dns.Fqdn(name) resp.Answer = append(resp.Answer, a) case dns.TypeAAAA: diff --git a/internal/dnsforward/http.go b/internal/dnsforward/http.go index 24695b9f..184e5e7c 100644 --- a/internal/dnsforward/http.go +++ b/internal/dnsforward/http.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" "io" - "net" "net/http" "net/netip" "strings" @@ -83,10 +82,10 @@ type jsonDNSConfig struct { LocalPTRUpstreams *[]string `json:"local_ptr_upstreams"` // BlockingIPv4 is custom IPv4 address for blocked A requests. - BlockingIPv4 net.IP `json:"blocking_ipv4"` + BlockingIPv4 netip.Addr `json:"blocking_ipv4"` // BlockingIPv6 is custom IPv6 address for blocked AAAA requests. - BlockingIPv6 net.IP `json:"blocking_ipv6"` + BlockingIPv6 netip.Addr `json:"blocking_ipv6"` // DisabledUntil is a timestamp until when the protection is disabled. DisabledUntil *time.Time `json:"protection_disabled_until"` @@ -297,8 +296,8 @@ func (s *Server) setConfig(dc *jsonDNSConfig) (shouldRestart bool) { if dc.BlockingMode != nil { s.conf.BlockingMode = *dc.BlockingMode if *dc.BlockingMode == BlockingModeCustomIP { - s.conf.BlockingIPv4 = dc.BlockingIPv4.To4() - s.conf.BlockingIPv6 = dc.BlockingIPv6.To16() + s.conf.BlockingIPv4 = dc.BlockingIPv4 + s.conf.BlockingIPv6 = dc.BlockingIPv6 } } diff --git a/internal/dnsforward/http_test.go b/internal/dnsforward/http_test.go index 434bad5d..9746e4ed 100644 --- a/internal/dnsforward/http_test.go +++ b/internal/dnsforward/http_test.go @@ -177,7 +177,7 @@ func TestDNSForwardHTTP_handleSetConfig(t *testing.T) { wantSet: "", }, { name: "blocking_mode_bad", - wantSet: "blocking_ipv4 must be set when blocking_mode is custom_ip", + wantSet: "blocking_ipv4 must be valid ipv4 on custom_ip blocking_mode", }, { name: "ratelimit", wantSet: "", diff --git a/internal/dnsforward/msg.go b/internal/dnsforward/msg.go index 4cb5671a..6d917fbe 100644 --- a/internal/dnsforward/msg.go +++ b/internal/dnsforward/msg.go @@ -1,7 +1,7 @@ package dnsforward import ( - "net" + "net/netip" "time" "github.com/AdguardTeam/AdGuardHome/internal/filtering" @@ -9,6 +9,7 @@ import ( "github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/urlfilter/rules" "github.com/miekg/dns" + "golang.org/x/exp/slices" ) // makeResponse creates a DNS response by req and sets necessary flags. It also @@ -26,24 +27,13 @@ func (s *Server) makeResponse(req *dns.Msg) (resp *dns.Msg) { return resp } -// containsIP returns true if the IP is already in the list. -func containsIP(ips []net.IP, ip net.IP) bool { - for _, a := range ips { - if a.Equal(ip) { - return true - } - } - - return false -} - // ipsFromRules extracts unique non-IP addresses from the filtering result // rules. -func ipsFromRules(resRules []*filtering.ResultRule) (ips []net.IP) { +func ipsFromRules(resRules []*filtering.ResultRule) (ips []netip.Addr) { for _, r := range resRules { // len(resRules) and len(ips) are actually small enough for O(n^2) to do // not raise performance questions. - if ip := r.IP; ip != nil && !containsIP(ips, ip) { + if ip := r.IP; ip != (netip.Addr{}) && !slices.Contains(ips, ip) { ips = append(ips, ip) } } @@ -84,7 +74,7 @@ func (s *Server) genDNSFilterMessage( // genForBlockingMode generates a filtered response to req based on the server's // blocking mode. -func (s *Server) genForBlockingMode(req *dns.Msg, ips []net.IP) (resp *dns.Msg) { +func (s *Server) genForBlockingMode(req *dns.Msg, ips []netip.Addr) (resp *dns.Msg) { qt := req.Question[0].Qtype switch m := s.conf.BlockingMode; m { case BlockingModeCustomIP: @@ -126,13 +116,13 @@ func (s *Server) genServerFailure(request *dns.Msg) *dns.Msg { return &resp } -func (s *Server) genARecord(request *dns.Msg, ip net.IP) *dns.Msg { +func (s *Server) genARecord(request *dns.Msg, ip netip.Addr) *dns.Msg { resp := s.makeResponse(request) resp.Answer = append(resp.Answer, s.genAnswerA(request, ip)) return resp } -func (s *Server) genAAAARecord(request *dns.Msg, ip net.IP) *dns.Msg { +func (s *Server) genAAAARecord(request *dns.Msg, ip netip.Addr) *dns.Msg { resp := s.makeResponse(request) resp.Answer = append(resp.Answer, s.genAnswerAAAA(request, ip)) return resp @@ -147,17 +137,17 @@ func (s *Server) hdr(req *dns.Msg, rrType rules.RRType) (h dns.RR_Header) { } } -func (s *Server) genAnswerA(req *dns.Msg, ip net.IP) (ans *dns.A) { +func (s *Server) genAnswerA(req *dns.Msg, ip netip.Addr) (ans *dns.A) { return &dns.A{ Hdr: s.hdr(req, dns.TypeA), - A: ip, + A: ip.AsSlice(), } } -func (s *Server) genAnswerAAAA(req *dns.Msg, ip net.IP) (ans *dns.AAAA) { +func (s *Server) genAnswerAAAA(req *dns.Msg, ip netip.Addr) (ans *dns.AAAA) { return &dns.AAAA{ Hdr: s.hdr(req, dns.TypeAAAA), - AAAA: ip, + AAAA: ip.AsSlice(), } } @@ -204,22 +194,24 @@ func (s *Server) genAnswerTXT(req *dns.Msg, strs []string) (ans *dns.TXT) { // addresses and an appropriate resource record type. If any of the IPs cannot // be converted to the correct protocol, genResponseWithIPs returns an empty // response. -func (s *Server) genResponseWithIPs(req *dns.Msg, ips []net.IP) (resp *dns.Msg) { +func (s *Server) genResponseWithIPs(req *dns.Msg, ips []netip.Addr) (resp *dns.Msg) { var ans []dns.RR switch req.Question[0].Qtype { case dns.TypeA: for _, ip := range ips { - if ip4 := ip.To4(); ip4 == nil { + if ip.Is4() { + ans = append(ans, s.genAnswerA(req, ip)) + } else { ans = nil break } - - ans = append(ans, s.genAnswerA(req, ip)) } case dns.TypeAAAA: for _, ip := range ips { - ans = append(ans, s.genAnswerAAAA(req, ip.To16())) + if ip.Is6() { + ans = append(ans, s.genAnswerAAAA(req, ip)) + } } default: // Go on and return an empty response. @@ -240,9 +232,9 @@ func (s *Server) makeResponseNullIP(req *dns.Msg) (resp *dns.Msg) { // converted into an empty slice instead of the zero IPv4. switch req.Question[0].Qtype { case dns.TypeA: - resp = s.genResponseWithIPs(req, []net.IP{{0, 0, 0, 0}}) + resp = s.genResponseWithIPs(req, []netip.Addr{netip.IPv4Unspecified()}) case dns.TypeAAAA: - resp = s.genResponseWithIPs(req, []net.IP{net.IPv6zero}) + resp = s.genResponseWithIPs(req, []netip.Addr{netip.IPv6Unspecified()}) default: resp = s.makeResponse(req) } @@ -251,9 +243,9 @@ func (s *Server) makeResponseNullIP(req *dns.Msg) (resp *dns.Msg) { } func (s *Server) genBlockedHost(request *dns.Msg, newAddr string, d *proxy.DNSContext) *dns.Msg { - ip := net.ParseIP(newAddr) - if ip != nil { - return s.genResponseWithIPs(request, []net.IP{ip}) + ip, err := netip.ParseAddr(newAddr) + if err == nil { + return s.genResponseWithIPs(request, []netip.Addr{ip}) } // look up the hostname, TODO: cache @@ -275,7 +267,7 @@ func (s *Server) genBlockedHost(request *dns.Msg, newAddr string, d *proxy.DNSCo return s.genServerFailure(request) } - err := prx.Resolve(newContext) + err = prx.Resolve(newContext) if err != nil { log.Printf("couldn't look up replacement host %q: %s", newAddr, err) diff --git a/internal/filtering/dnsrewrite_test.go b/internal/filtering/dnsrewrite_test.go index 884c40ad..ee88cb09 100644 --- a/internal/filtering/dnsrewrite_test.go +++ b/internal/filtering/dnsrewrite_test.go @@ -10,6 +10,7 @@ import ( "github.com/AdguardTeam/AdGuardHome/internal/aghnet" "github.com/AdguardTeam/AdGuardHome/internal/aghtest" + "github.com/AdguardTeam/golibs/netutil" "github.com/AdguardTeam/golibs/testutil" "github.com/AdguardTeam/urlfilter/rules" "github.com/miekg/dns" @@ -22,13 +23,13 @@ func TestDNSFilter_CheckHostRules_dnsrewrite(t *testing.T) { |cname^$dnsrewrite=new-cname |a-record^$dnsrewrite=127.0.0.1 - |aaaa-record^$dnsrewrite=::1 |txt-record^$dnsrewrite=NOERROR;TXT;hello-world - |refused^$dnsrewrite=REFUSED +|mapped^$dnsrewrite=NOERROR;AAAA;::ffff:127.0.0.1 + |a-records^$dnsrewrite=127.0.0.1 |a-records^$dnsrewrite=127.0.0.2 @@ -61,10 +62,11 @@ func TestDNSFilter_CheckHostRules_dnsrewrite(t *testing.T) { FilteringEnabled: true, } - ipv4p1 := net.IPv4(127, 0, 0, 1) - ipv4p2 := net.IPv4(127, 0, 0, 2) - ipv6p1 := net.IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1} - ipv6p2 := net.IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2} + ipv4p1 := netutil.IPv4Localhost() + ipv4p2 := ipv4p1.Next() + ipv6p1 := netutil.IPv6Localhost() + ipv6p2 := ipv6p1.Next() + mapped := netip.AddrFrom16(ipv4p1.As16()) testCasesA := []struct { name string @@ -111,6 +113,11 @@ func TestDNSFilter_CheckHostRules_dnsrewrite(t *testing.T) { want: []any{ipv4p1}, rcode: dns.RcodeSuccess, dtyp: dns.TypeA, + }, { + name: "mapped", + want: []any{mapped}, + rcode: dns.RcodeSuccess, + dtyp: dns.TypeAAAA, }} for _, tc := range testCasesA { diff --git a/internal/filtering/filtering.go b/internal/filtering/filtering.go index eb630f0e..0c49eefd 100644 --- a/internal/filtering/filtering.go +++ b/internal/filtering/filtering.go @@ -54,7 +54,7 @@ type ServiceEntry struct { // Settings are custom filtering settings for a client. type Settings struct { ClientName string - ClientIP net.IP + ClientIP netip.Addr ClientTags []string ServicesRules []ServiceEntry @@ -404,7 +404,7 @@ type ResultRule struct { Text string `json:",omitempty"` // IP is the host IP. It is nil unless the rule uses the // /etc/hosts syntax or the reason is FilteredSafeSearch. - IP net.IP `json:",omitempty"` + IP netip.Addr `json:",omitempty"` // FilterListID is the ID of the rule's filter list. FilterListID int64 `json:",omitempty"` } @@ -430,7 +430,7 @@ type Result struct { // IPList is the lookup rewrite result. It is empty unless Reason is set to // Rewritten. - IPList []net.IP `json:",omitempty"` + IPList []netip.Addr `json:",omitempty"` // Rules are applied rules. If Rules are not empty, each rule is not nil. Rules []*ResultRule `json:",omitempty"` @@ -787,22 +787,27 @@ func (d *DNSFilter) matchHostProcessDNSResult( return makeResult([]rules.Rule{dnsres.NetworkRule}, reason) } - if qtype == dns.TypeA && dnsres.HostRulesV4 != nil { - res = makeResult(hostRulesToRules(dnsres.HostRulesV4), FilteredBlockList) - for i, hr := range dnsres.HostRulesV4 { - res.Rules[i].IP = hr.IP.To4() + switch qtype { + case dns.TypeA: + if dnsres.HostRulesV4 != nil { + res = makeResult(hostRulesToRules(dnsres.HostRulesV4), FilteredBlockList) + for i, hr := range dnsres.HostRulesV4 { + res.Rules[i].IP = hr.IP + } + + return res } + case dns.TypeAAAA: + if dnsres.HostRulesV6 != nil { + res = makeResult(hostRulesToRules(dnsres.HostRulesV6), FilteredBlockList) + for i, hr := range dnsres.HostRulesV6 { + res.Rules[i].IP = hr.IP + } - return res - } - - if qtype == dns.TypeAAAA && dnsres.HostRulesV6 != nil { - res = makeResult(hostRulesToRules(dnsres.HostRulesV6), FilteredBlockList) - for i, hr := range dnsres.HostRulesV6 { - res.Rules[i].IP = hr.IP.To16() + return res } - - return res + default: + // Go on. } return hostResultForOtherQType(dnsres) @@ -837,7 +842,7 @@ func (d *DNSFilter) matchHost( Hostname: host, SortedClientTags: setts.ClientTags, // TODO(e.burkov): Wait for urlfilter update to pass net.IP. - ClientIP: setts.ClientIP.String(), + ClientIP: setts.ClientIP, ClientName: setts.ClientName, DNSType: rrtype, } diff --git a/internal/filtering/filtering_test.go b/internal/filtering/filtering_test.go index 9159f7be..83018ab3 100644 --- a/internal/filtering/filtering_test.go +++ b/internal/filtering/filtering_test.go @@ -3,12 +3,13 @@ package filtering import ( "bytes" "fmt" - "net" + "net/netip" "testing" "github.com/AdguardTeam/AdGuardHome/internal/aghtest" "github.com/AdguardTeam/AdGuardHome/internal/filtering/hashprefix" "github.com/AdguardTeam/golibs/log" + "github.com/AdguardTeam/golibs/netutil" "github.com/AdguardTeam/golibs/testutil" "github.com/AdguardTeam/urlfilter/rules" "github.com/miekg/dns" @@ -149,8 +150,8 @@ func TestDNSFilter_CheckHost_hostRules(t *testing.T) { require.Len(t, res.Rules, 2) - assert.Equal(t, res.Rules[0].IP, net.IP{0, 0, 0, 1}) - assert.Equal(t, res.Rules[1].IP, net.IP{0, 0, 0, 2}) + assert.Equal(t, res.Rules[0].IP, netip.AddrFrom4([4]byte{0, 0, 0, 1})) + assert.Equal(t, res.Rules[1].IP, netip.AddrFrom4([4]byte{0, 0, 0, 2})) // One IPv6 address. res, err = d.CheckHost("host2", dns.TypeAAAA, setts) @@ -160,7 +161,7 @@ func TestDNSFilter_CheckHost_hostRules(t *testing.T) { require.Len(t, res.Rules, 1) - assert.Equal(t, res.Rules[0].IP, net.IPv6loopback) + assert.Equal(t, res.Rules[0].IP, netutil.IPv6Localhost()) } // Safe Browsing. diff --git a/internal/filtering/http.go b/internal/filtering/http.go index 8d3f202f..43191ca6 100644 --- a/internal/filtering/http.go +++ b/internal/filtering/http.go @@ -3,8 +3,8 @@ package filtering import ( "encoding/json" "fmt" - "net" "net/http" + "net/netip" "net/url" "os" "path/filepath" @@ -404,8 +404,8 @@ type checkHostResp struct { SvcName string `json:"service_name"` // for Rewrite: - CanonName string `json:"cname"` // CNAME value - IPList []net.IP `json:"ip_addrs"` // list of IP addresses + CanonName string `json:"cname"` // CNAME value + IPList []netip.Addr `json:"ip_addrs"` // list of IP addresses // FilterID is the ID of the rule's filter list. // diff --git a/internal/filtering/rewrite/storage_test.go b/internal/filtering/rewrite/storage_test.go index 4db06a4e..502c20b9 100644 --- a/internal/filtering/rewrite/storage_test.go +++ b/internal/filtering/rewrite/storage_test.go @@ -1,9 +1,10 @@ package rewrite import ( - "net" + "net/netip" "testing" + "github.com/AdguardTeam/golibs/netutil" "github.com/AdguardTeam/urlfilter" "github.com/AdguardTeam/urlfilter/rules" "github.com/miekg/dns" @@ -45,33 +46,43 @@ func TestDefaultStorage_CRUD(t *testing.T) { } func TestDefaultStorage_MatchRequest(t *testing.T) { + var ( + addr1v4 = netip.AddrFrom4([4]byte{1, 2, 3, 4}) + addr2v4 = netip.AddrFrom4([4]byte{1, 2, 3, 5}) + addr3v4 = netip.AddrFrom4([4]byte{1, 2, 3, 6}) + addr4v4 = netip.AddrFrom4([4]byte{1, 2, 3, 7}) + + addr1v6 = netip.MustParseAddr("1:2:3::4") + addr2v6 = netip.MustParseAddr("1234::5678") + ) + items := []*Item{{ // This one and below are about CNAME, A and AAAA. Domain: "somecname", Answer: "somehost.com", }, { Domain: "somehost.com", - Answer: "0.0.0.0", + Answer: netip.IPv4Unspecified().String(), }, { Domain: "host.com", - Answer: "1.2.3.4", + Answer: addr1v4.String(), }, { Domain: "host.com", - Answer: "1.2.3.5", + Answer: addr2v4.String(), }, { Domain: "host.com", - Answer: "1:2:3::4", + Answer: addr1v6.String(), }, { Domain: "www.host.com", Answer: "host.com", }, { // This one is a wildcard. Domain: "*.host.com", - Answer: "1.2.3.5", + Answer: addr2v4.String(), }, { // This one and below are about wildcard overriding. Domain: "a.host.com", - Answer: "1.2.3.4", + Answer: addr1v4.String(), }, { // This one is about CNAME and wildcard interacting. Domain: "*.host2.com", @@ -89,13 +100,13 @@ func TestDefaultStorage_MatchRequest(t *testing.T) { Answer: "x.host.com", }, { Domain: "*.hostboth.com", - Answer: "1.2.3.6", + Answer: addr3v4.String(), }, { Domain: "*.hostboth.com", - Answer: "1234::5678", + Answer: addr2v6.String(), }, { Domain: "BIGHOST.COM", - Answer: "1.2.3.7", + Answer: addr4v4.String(), }, { Domain: "*.issue4016.com", Answer: "sub.issue4016.com", @@ -123,12 +134,12 @@ func TestDefaultStorage_MatchRequest(t *testing.T) { name: "rewritten_a", host: "www.host.com", wantDNSRewrites: []*rules.DNSRewrite{{ - Value: net.IP{1, 2, 3, 4}.To16(), + Value: addr1v4, NewCNAME: "", RCode: dns.RcodeSuccess, RRType: dns.TypeA, }, { - Value: net.IP{1, 2, 3, 5}.To16(), + Value: addr2v4, NewCNAME: "", RCode: dns.RcodeSuccess, RRType: dns.TypeA, @@ -138,7 +149,7 @@ func TestDefaultStorage_MatchRequest(t *testing.T) { name: "rewritten_aaaa", host: "www.host.com", wantDNSRewrites: []*rules.DNSRewrite{{ - Value: net.ParseIP("1:2:3::4"), + Value: addr1v6, NewCNAME: "", RCode: dns.RcodeSuccess, RRType: dns.TypeAAAA, @@ -148,7 +159,7 @@ func TestDefaultStorage_MatchRequest(t *testing.T) { name: "wildcard_match", host: "abc.host.com", wantDNSRewrites: []*rules.DNSRewrite{{ - Value: net.IP{1, 2, 3, 5}.To16(), + Value: addr2v4, NewCNAME: "", RCode: dns.RcodeSuccess, RRType: dns.TypeA, @@ -169,12 +180,12 @@ func TestDefaultStorage_MatchRequest(t *testing.T) { name: "wildcard_cname_interaction", host: "www.host2.com", wantDNSRewrites: []*rules.DNSRewrite{{ - Value: net.IP{1, 2, 3, 4}.To16(), + Value: addr1v4, NewCNAME: "", RCode: dns.RcodeSuccess, RRType: dns.TypeA, }, { - Value: net.IP{1, 2, 3, 5}.To16(), + Value: addr2v4, NewCNAME: "", RCode: dns.RcodeSuccess, RRType: dns.TypeA, @@ -184,7 +195,7 @@ func TestDefaultStorage_MatchRequest(t *testing.T) { name: "two_cnames", host: "b.host.com", wantDNSRewrites: []*rules.DNSRewrite{{ - Value: net.IP{0, 0, 0, 0}.To16(), + Value: netip.IPv4Unspecified(), NewCNAME: "", RCode: dns.RcodeSuccess, RRType: dns.TypeA, @@ -194,7 +205,7 @@ func TestDefaultStorage_MatchRequest(t *testing.T) { name: "two_cnames_and_wildcard", host: "b.host3.com", wantDNSRewrites: []*rules.DNSRewrite{{ - Value: net.IP{1, 2, 3, 5}.To16(), + Value: addr2v4, NewCNAME: "", RCode: dns.RcodeSuccess, RRType: dns.TypeA, @@ -204,7 +215,7 @@ func TestDefaultStorage_MatchRequest(t *testing.T) { name: "issue3343", host: "www.hostboth.com", wantDNSRewrites: []*rules.DNSRewrite{{ - Value: net.ParseIP("1234::5678"), + Value: addr2v6, NewCNAME: "", RCode: dns.RcodeSuccess, RRType: dns.TypeAAAA, @@ -214,7 +225,7 @@ func TestDefaultStorage_MatchRequest(t *testing.T) { name: "issue3351", host: "bighost.com", wantDNSRewrites: []*rules.DNSRewrite{{ - Value: net.IP{1, 2, 3, 7}.To16(), + Value: addr4v4, NewCNAME: "", RCode: dns.RcodeSuccess, RRType: dns.TypeA, @@ -255,16 +266,22 @@ func TestDefaultStorage_MatchRequest(t *testing.T) { } func TestDefaultStorage_MatchRequest_Levels(t *testing.T) { + var ( + addr1 = netip.AddrFrom4([4]byte{1, 1, 1, 1}) + addr2 = netip.AddrFrom4([4]byte{2, 2, 2, 2}) + addr3 = netip.AddrFrom4([4]byte{3, 3, 3, 3}) + ) + // Exact host, wildcard L2, wildcard L3. items := []*Item{{ Domain: "host.com", - Answer: "1.1.1.1", + Answer: addr1.String(), }, { Domain: "*.host.com", - Answer: "2.2.2.2", + Answer: addr2.String(), }, { Domain: "*.sub.host.com", - Answer: "3.3.3.3", + Answer: addr3.String(), }} s, err := NewDefaultStorage(-1, items) @@ -279,7 +296,7 @@ func TestDefaultStorage_MatchRequest_Levels(t *testing.T) { name: "exact_match", host: "host.com", wantDNSRewrites: []*rules.DNSRewrite{{ - Value: net.IP{1, 1, 1, 1}.To16(), + Value: addr1, NewCNAME: "", RCode: dns.RcodeSuccess, RRType: dns.TypeA, @@ -289,7 +306,7 @@ func TestDefaultStorage_MatchRequest_Levels(t *testing.T) { name: "l2_match", host: "sub.host.com", wantDNSRewrites: []*rules.DNSRewrite{{ - Value: net.IP{2, 2, 2, 2}.To16(), + Value: addr2, NewCNAME: "", RCode: dns.RcodeSuccess, RRType: dns.TypeA, @@ -300,7 +317,7 @@ func TestDefaultStorage_MatchRequest_Levels(t *testing.T) { // name: "l3_match", // host: "my.sub.host.com", // wantDNSRewrites: []*rules.DNSRewrite{{ - // Value: net.IP{3, 3, 3, 3}.To16(), + // Value: addr3, // NewCNAME: "", // RCode: dns.RcodeSuccess, // RRType: dns.TypeA, @@ -321,10 +338,12 @@ func TestDefaultStorage_MatchRequest_Levels(t *testing.T) { } func TestDefaultStorage_MatchRequest_ExceptionCNAME(t *testing.T) { + addr := netip.AddrFrom4([4]byte{2, 2, 2, 2}) + // Wildcard and exception for a sub-domain. items := []*Item{{ Domain: "*.host.com", - Answer: "2.2.2.2", + Answer: addr.String(), }, { Domain: "sub.host.com", Answer: "sub.host.com", @@ -345,7 +364,7 @@ func TestDefaultStorage_MatchRequest_ExceptionCNAME(t *testing.T) { name: "match_subdomain", host: "my.host.com", wantDNSRewrites: []*rules.DNSRewrite{{ - Value: net.IP{2, 2, 2, 2}.To16(), + Value: addr, NewCNAME: "", RCode: dns.RcodeSuccess, RRType: dns.TypeA, @@ -377,16 +396,18 @@ func TestDefaultStorage_MatchRequest_ExceptionCNAME(t *testing.T) { } func TestDefaultStorage_MatchRequest_ExceptionIP(t *testing.T) { + addr := netip.AddrFrom4([4]byte{1, 2, 3, 4}) + // Exception for AAAA record. items := []*Item{{ Domain: "host.com", - Answer: "1.2.3.4", + Answer: addr.String(), }, { Domain: "host.com", Answer: "AAAA", }, { Domain: "host2.com", - Answer: "::1", + Answer: netutil.IPv6Localhost().String(), }, { Domain: "host2.com", Answer: "A", @@ -407,7 +428,7 @@ func TestDefaultStorage_MatchRequest_ExceptionIP(t *testing.T) { name: "match_A", host: "host.com", wantDNSRewrites: []*rules.DNSRewrite{{ - Value: net.IP{1, 2, 3, 4}.To16(), + Value: addr, NewCNAME: "", RCode: dns.RcodeSuccess, RRType: dns.TypeA, @@ -427,7 +448,7 @@ func TestDefaultStorage_MatchRequest_ExceptionIP(t *testing.T) { name: "match_AAAA_host2.com", host: "host2.com", wantDNSRewrites: []*rules.DNSRewrite{{ - Value: net.ParseIP("::1"), + Value: netutil.IPv6Localhost(), NewCNAME: "", RCode: dns.RcodeSuccess, RRType: dns.TypeAAAA, diff --git a/internal/filtering/rewrites.go b/internal/filtering/rewrites.go index 3d0dd64f..a716ecbf 100644 --- a/internal/filtering/rewrites.go +++ b/internal/filtering/rewrites.go @@ -2,7 +2,7 @@ package filtering import ( "fmt" - "net" + "net/netip" "strings" "github.com/AdguardTeam/golibs/errors" @@ -27,22 +27,12 @@ type LegacyRewrite struct { // IP is the IP address that should be used in the response if Type is // dns.TypeA or dns.TypeAAAA. - IP net.IP `yaml:"-"` + IP netip.Addr `yaml:"-"` // Type is the DNS record type: A, AAAA, or CNAME. Type uint16 `yaml:"-"` } -// clone returns a deep clone of rw. -func (rw *LegacyRewrite) clone() (cloneRW *LegacyRewrite) { - return &LegacyRewrite{ - Domain: rw.Domain, - Answer: rw.Answer, - IP: slices.Clone(rw.IP), - Type: rw.Type, - } -} - // equal returns true if the rw is equal to the other. func (rw *LegacyRewrite) equal(other *LegacyRewrite) (ok bool) { return rw.Domain == other.Domain && rw.Answer == other.Answer @@ -62,11 +52,11 @@ func (rw *LegacyRewrite) matchesQType(qt uint16) (ok bool) { // If the types match or the entry is set to allow only the other type, // include them. - return rw.Type == qt || rw.IP == nil + return rw.Type == qt || rw.IP == netip.Addr{} } -// normalize makes sure that the a new or decoded entry is normalized with -// regards to domain name case, IP length, and so on. +// normalize makes sure that the new or decoded entry is normalized with regards +// to domain name case, IP length, and so on. // // If rw is nil, it returns an errors. func (rw *LegacyRewrite) normalize() (err error) { @@ -81,12 +71,12 @@ func (rw *LegacyRewrite) normalize() (err error) { switch rw.Answer { case "AAAA": - rw.IP = nil + rw.IP = netip.Addr{} rw.Type = dns.TypeAAAA return nil case "A": - rw.IP = nil + rw.IP = netip.Addr{} rw.Type = dns.TypeA return nil @@ -94,19 +84,18 @@ func (rw *LegacyRewrite) normalize() (err error) { // Go on. } - ip := net.ParseIP(rw.Answer) - if ip == nil { + ip, err := netip.ParseAddr(rw.Answer) + if err != nil { + log.Debug("normalizing legacy rewrite: %s", err) rw.Type = dns.TypeCNAME return nil } - ip4 := ip.To4() - if ip4 != nil { - rw.IP = ip4 + rw.IP = ip + if ip.Is4() { rw.Type = dns.TypeA } else { - rw.IP = ip rw.Type = dns.TypeAAAA } @@ -207,7 +196,7 @@ func findRewrites( func setRewriteResult(res *Result, host string, rewrites []*LegacyRewrite, qtype uint16) { for _, rw := range rewrites { if rw.Type == qtype && (qtype == dns.TypeA || qtype == dns.TypeAAAA) { - if rw.IP == nil { + if rw.IP == (netip.Addr{}) { // "A"/"AAAA" exception: allow getting from upstream. res.Reason = NotFilteredNotFound @@ -225,7 +214,12 @@ func setRewriteResult(res *Result, host string, rewrites []*LegacyRewrite, qtype func cloneRewrites(entries []*LegacyRewrite) (clone []*LegacyRewrite) { clone = make([]*LegacyRewrite, len(entries)) for i, rw := range entries { - clone[i] = rw.clone() + clone[i] = &LegacyRewrite{ + Domain: rw.Domain, + Answer: rw.Answer, + IP: rw.IP, + Type: rw.Type, + } } return clone diff --git a/internal/filtering/rewrites_test.go b/internal/filtering/rewrites_test.go index 17caa167..2b201b62 100644 --- a/internal/filtering/rewrites_test.go +++ b/internal/filtering/rewrites_test.go @@ -2,6 +2,7 @@ package filtering import ( "net" + "net/netip" "testing" "github.com/miekg/dns" @@ -15,33 +16,43 @@ func TestRewrites(t *testing.T) { d, _ := newForTest(t, nil, nil) t.Cleanup(d.Close) + var ( + addr1v4 = netip.AddrFrom4([4]byte{1, 2, 3, 4}) + addr2v4 = netip.AddrFrom4([4]byte{1, 2, 3, 5}) + addr3v4 = netip.AddrFrom4([4]byte{1, 2, 3, 6}) + addr4v4 = netip.AddrFrom4([4]byte{1, 2, 3, 7}) + + addr1v6 = netip.MustParseAddr("1:2:3::4") + addr2v6 = netip.MustParseAddr("1234::5678") + ) + d.Rewrites = []*LegacyRewrite{{ // This one and below are about CNAME, A and AAAA. Domain: "somecname", Answer: "somehost.com", }, { Domain: "somehost.com", - Answer: "0.0.0.0", + Answer: netip.IPv4Unspecified().String(), }, { Domain: "host.com", - Answer: "1.2.3.4", + Answer: addr1v4.String(), }, { Domain: "host.com", - Answer: "1.2.3.5", + Answer: addr2v4.String(), }, { Domain: "host.com", - Answer: "1:2:3::4", + Answer: addr1v6.String(), }, { Domain: "www.host.com", Answer: "host.com", }, { // This one is a wildcard. Domain: "*.host.com", - Answer: "1.2.3.5", + Answer: addr2v4.String(), }, { // This one and below are about wildcard overriding. Domain: "a.host.com", - Answer: "1.2.3.4", + Answer: addr1v4.String(), }, { // This one is about CNAME and wildcard interacting. Domain: "*.host2.com", @@ -59,13 +70,13 @@ func TestRewrites(t *testing.T) { Answer: "x.host.com", }, { Domain: "*.hostboth.com", - Answer: "1.2.3.6", + Answer: addr3v4.String(), }, { Domain: "*.hostboth.com", - Answer: "1234::5678", + Answer: addr2v6.String(), }, { Domain: "BIGHOST.COM", - Answer: "1.2.3.7", + Answer: addr4v4.String(), }, { Domain: "*.issue4016.com", Answer: "sub.issue4016.com", @@ -77,7 +88,7 @@ func TestRewrites(t *testing.T) { name string host string wantCName string - wantIPs []net.IP + wantIPs []netip.Addr wantReason Reason dtyp uint16 }{{ @@ -91,63 +102,63 @@ func TestRewrites(t *testing.T) { name: "rewritten_a", host: "www.host.com", wantCName: "host.com", - wantIPs: []net.IP{{1, 2, 3, 4}, {1, 2, 3, 5}}, + wantIPs: []netip.Addr{addr1v4, addr2v4}, wantReason: Rewritten, dtyp: dns.TypeA, }, { name: "rewritten_aaaa", host: "www.host.com", wantCName: "host.com", - wantIPs: []net.IP{net.ParseIP("1:2:3::4")}, + wantIPs: []netip.Addr{addr1v6}, wantReason: Rewritten, dtyp: dns.TypeAAAA, }, { name: "wildcard_match", host: "abc.host.com", wantCName: "", - wantIPs: []net.IP{{1, 2, 3, 5}}, + wantIPs: []netip.Addr{addr2v4}, wantReason: Rewritten, dtyp: dns.TypeA, }, { name: "wildcard_override", host: "a.host.com", wantCName: "", - wantIPs: []net.IP{{1, 2, 3, 4}}, + wantIPs: []netip.Addr{addr1v4}, wantReason: Rewritten, dtyp: dns.TypeA, }, { name: "wildcard_cname_interaction", host: "www.host2.com", wantCName: "host.com", - wantIPs: []net.IP{{1, 2, 3, 4}, {1, 2, 3, 5}}, + wantIPs: []netip.Addr{addr1v4, addr2v4}, wantReason: Rewritten, dtyp: dns.TypeA, }, { name: "two_cnames", host: "b.host.com", wantCName: "somehost.com", - wantIPs: []net.IP{{0, 0, 0, 0}}, + wantIPs: []netip.Addr{netip.IPv4Unspecified()}, wantReason: Rewritten, dtyp: dns.TypeA, }, { name: "two_cnames_and_wildcard", host: "b.host3.com", wantCName: "x.host.com", - wantIPs: []net.IP{{1, 2, 3, 5}}, + wantIPs: []netip.Addr{addr2v4}, wantReason: Rewritten, dtyp: dns.TypeA, }, { name: "issue3343", host: "www.hostboth.com", wantCName: "", - wantIPs: []net.IP{net.ParseIP("1234::5678")}, + wantIPs: []netip.Addr{addr2v6}, wantReason: Rewritten, dtyp: dns.TypeAAAA, }, { name: "issue3351", host: "bighost.com", wantCName: "", - wantIPs: []net.IP{{1, 2, 3, 7}}, + wantIPs: []netip.Addr{addr4v4}, wantReason: Rewritten, dtyp: dns.TypeA, }, { @@ -254,25 +265,25 @@ func TestRewritesExceptionCNAME(t *testing.T) { testCases := []struct { name string host string - want net.IP + want netip.Addr }{{ name: "match_subdomain", host: "my.host.com", - want: net.IP{2, 2, 2, 2}, + want: netip.AddrFrom4([4]byte{2, 2, 2, 2}), }, { name: "exception_cname", host: "sub.host.com", - want: nil, + want: netip.Addr{}, }, { name: "exception_wildcard", host: "my.sub.host.com", - want: nil, + want: netip.Addr{}, }} for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { r := d.processRewrites(tc.host, dns.TypeA) - if tc.want == nil { + if tc.want == (netip.Addr{}) { assert.Equal(t, NotFilteredNotFound, r.Reason, "got %s", r.Reason) return @@ -280,7 +291,7 @@ func TestRewritesExceptionCNAME(t *testing.T) { assert.Equal(t, Rewritten, r.Reason) require.Len(t, r.IPList, 1) - assert.True(t, tc.want.Equal(r.IPList[0])) + assert.Equal(t, tc.want, r.IPList[0]) }) } } @@ -314,58 +325,58 @@ func TestRewritesExceptionIP(t *testing.T) { require.NoError(t, d.prepareRewrites()) testCases := []struct { - name string - host string - want []net.IP - dtyp uint16 + name string + host string + want []netip.Addr + dtyp uint16 + wantReason Reason }{{ - name: "match_A", - host: "host.com", - want: []net.IP{{1, 2, 3, 4}}, - dtyp: dns.TypeA, + name: "match_A", + host: "host.com", + want: []netip.Addr{netip.AddrFrom4([4]byte{1, 2, 3, 4})}, + dtyp: dns.TypeA, + wantReason: Rewritten, }, { - name: "exception_AAAA_host.com", - host: "host.com", - want: nil, - dtyp: dns.TypeAAAA, + name: "exception_AAAA_host.com", + host: "host.com", + want: nil, + dtyp: dns.TypeAAAA, + wantReason: NotFilteredNotFound, }, { - name: "exception_A_host2.com", - host: "host2.com", - want: nil, - dtyp: dns.TypeA, + name: "exception_A_host2.com", + host: "host2.com", + want: nil, + dtyp: dns.TypeA, + wantReason: NotFilteredNotFound, }, { - name: "match_AAAA_host2.com", - host: "host2.com", - want: []net.IP{net.ParseIP("::1")}, - dtyp: dns.TypeAAAA, + name: "match_AAAA_host2.com", + host: "host2.com", + want: []netip.Addr{netip.MustParseAddr("::1")}, + dtyp: dns.TypeAAAA, + wantReason: Rewritten, }, { - name: "exception_A_host3.com", - host: "host3.com", - want: nil, - dtyp: dns.TypeA, + name: "exception_A_host3.com", + host: "host3.com", + want: nil, + dtyp: dns.TypeA, + wantReason: NotFilteredNotFound, }, { - name: "match_AAAA_host3.com", - host: "host3.com", - want: []net.IP{}, - dtyp: dns.TypeAAAA, + name: "match_AAAA_host3.com", + host: "host3.com", + want: nil, + dtyp: dns.TypeAAAA, + wantReason: Rewritten, }} for _, tc := range testCases { - t.Run(tc.name+"_"+tc.host, func(t *testing.T) { + t.Run(tc.name, func(t *testing.T) { + if tc.name != "match_AAAA_host3.com" { + t.SkipNow() + } + r := d.processRewrites(tc.host, tc.dtyp) - if tc.want == nil { - assert.Equal(t, NotFilteredNotFound, r.Reason) - - return - } - - assert.Equalf(t, Rewritten, r.Reason, "got %s", r.Reason) - - require.Len(t, r.IPList, len(tc.want)) - - for _, ip := range tc.want { - assert.True(t, ip.Equal(r.IPList[0])) - } + assert.Equal(t, tc.want, r.IPList) + assert.Equal(t, tc.wantReason, r.Reason) }) } } diff --git a/internal/filtering/safesearch/safesearch.go b/internal/filtering/safesearch/safesearch.go index 9d5b5121..f2d2b70c 100644 --- a/internal/filtering/safesearch/safesearch.go +++ b/internal/filtering/safesearch/safesearch.go @@ -8,6 +8,7 @@ import ( "encoding/gob" "fmt" "net" + "net/netip" "strings" "sync" "time" @@ -239,10 +240,9 @@ func (ss *Default) newResult( } if rewrite.RRType == qtype { - v := rewrite.Value - ip, ok := v.(net.IP) - if !ok || ip == nil { - return nil, fmt.Errorf("expected ip rewrite value, got %T(%[1]v)", v) + ip, ok := rewrite.Value.(netip.Addr) + if !ok || ip == (netip.Addr{}) { + return nil, fmt.Errorf("expected ip rewrite value, got %T(%[1]v)", rewrite.Value) } res.Rules[0].IP = ip @@ -267,12 +267,13 @@ func (ss *Default) newResult( for _, ip := range ips { // TODO(a.garipov): Remove this filtering once the resolver we use // actually learns about network. - ip = fitToProto(ip, qtype) - if ip == nil { + addr := fitToProto(ip, qtype) + if addr == (netip.Addr{}) { continue } - res.Rules[0].IP = ip + // TODO(e.burkov): Rules[0]? + res.Rules[0].IP = addr } return res, nil @@ -293,17 +294,16 @@ func qtypeToProto(qtype rules.RRType) (proto string) { // fitToProto returns a non-nil IP address if ip is the correct protocol version // for qtype. qtype is expected to be either [dns.TypeA] or [dns.TypeAAAA]. -func fitToProto(ip net.IP, qtype rules.RRType) (res net.IP) { - ip4 := ip.To4() - if qtype == dns.TypeA { - return ip4 +func fitToProto(ip net.IP, qtype rules.RRType) (res netip.Addr) { + if ip4 := ip.To4(); qtype == dns.TypeA { + if ip4 != nil { + return netip.AddrFrom4([4]byte(ip4)) + } + } else if ip = ip.To16(); ip != nil && qtype == dns.TypeAAAA { + return netip.AddrFrom16([16]byte(ip)) } - if ip4 == nil { - return ip - } - - return nil + return netip.Addr{} } // setCacheResult stores data in cache for host. qtype is expected to be either diff --git a/internal/filtering/safesearch/safesearch_internal_test.go b/internal/filtering/safesearch/safesearch_internal_test.go index 909265ee..ae4e380d 100644 --- a/internal/filtering/safesearch/safesearch_internal_test.go +++ b/internal/filtering/safesearch/safesearch_internal_test.go @@ -3,6 +3,7 @@ package safesearch import ( "context" "net" + "net/netip" "testing" "time" @@ -33,7 +34,7 @@ var defaultSafeSearchConf = filtering.SafeSearchConfig{ YouTube: true, } -var yandexIP = net.IPv4(213, 180, 193, 56) +var yandexIP = netip.AddrFrom4([4]byte{213, 180, 193, 56}) func newForTest(t testing.TB, ssConf filtering.SafeSearchConfig) (ss *Default) { ss, err := NewDefault(ssConf, "", testCacheSize, testCacheTTL) @@ -93,7 +94,7 @@ func TestSafeSearchCacheGoogle(t *testing.T) { OnLookupIP: func(_ context.Context, _, host string) (ips []net.IP, err error) { ip4, ip6 := aghtest.HostToIPs(host) - return []net.IP{ip4, ip6}, nil + return []net.IP{ip4.AsSlice(), ip6.AsSlice()}, nil }, } @@ -109,14 +110,14 @@ func TestSafeSearchCacheGoogle(t *testing.T) { require.NoError(t, err) require.Len(t, res.Rules, 1) - assert.True(t, res.Rules[0].IP.Equal(wantIP)) + assert.Equal(t, wantIP, res.Rules[0].IP) // Check cache. cachedValue, isFound := ss.getCachedResult(domain, testQType) require.True(t, isFound) require.Len(t, cachedValue.Rules, 1) - assert.True(t, cachedValue.Rules[0].IP.Equal(wantIP)) + assert.Equal(t, wantIP, cachedValue.Rules[0].IP) } const googleHost = "www.google.com" diff --git a/internal/filtering/safesearch/safesearch_test.go b/internal/filtering/safesearch/safesearch_test.go index c62dd6e4..16b720d1 100644 --- a/internal/filtering/safesearch/safesearch_test.go +++ b/internal/filtering/safesearch/safesearch_test.go @@ -3,6 +3,7 @@ package safesearch_test import ( "context" "net" + "net/netip" "testing" "time" @@ -43,7 +44,7 @@ var testConf = filtering.SafeSearchConfig{ // yandexIP is the expected IP address of Yandex safe search results. Keep in // sync with the rules data. -var yandexIP = net.IPv4(213, 180, 193, 56) +var yandexIP = netip.AddrFrom4([4]byte{213, 180, 193, 56}) func TestDefault_CheckHost_yandex(t *testing.T) { conf := testConf @@ -87,7 +88,7 @@ func TestDefault_CheckHost_yandexAAAA(t *testing.T) { // once the TODO in [safesearch.Default.newResult] is resolved. require.Len(t, res.Rules, 1) - assert.Nil(t, res.Rules[0].IP) + assert.Empty(t, res.Rules[0].IP) assert.EqualValues(t, filtering.SafeSearchListID, res.Rules[0].FilterListID) } @@ -96,7 +97,7 @@ func TestDefault_CheckHost_google(t *testing.T) { OnLookupIP: func(_ context.Context, _, host string) (ips []net.IP, err error) { ip4, ip6 := aghtest.HostToIPs(host) - return []net.IP{ip4, ip6}, nil + return []net.IP{ip4.AsSlice(), ip6.AsSlice()}, nil }, } @@ -178,7 +179,7 @@ func TestDefault_CheckHost_duckduckgoAAAA(t *testing.T) { // once the TODO in [safesearch.Default.newResult] is resolved. require.Len(t, res.Rules, 1) - assert.Nil(t, res.Rules[0].IP) + assert.Empty(t, res.Rules[0].IP) assert.EqualValues(t, filtering.SafeSearchListID, res.Rules[0].FilterListID) } diff --git a/internal/home/dns.go b/internal/home/dns.go index cb6a5142..df307cc1 100644 --- a/internal/home/dns.go +++ b/internal/home/dns.go @@ -378,7 +378,7 @@ func getDNSEncryption() (de dnsEncryption) { // applyAdditionalFiltering adds additional client information and settings if // the client has them. -func applyAdditionalFiltering(clientIP net.IP, clientID string, setts *filtering.Settings) { +func applyAdditionalFiltering(clientIP netip.Addr, clientID string, setts *filtering.Settings) { // pref is a prefix for logging messages around the scope. const pref = "applying filters" @@ -386,7 +386,7 @@ func applyAdditionalFiltering(clientIP net.IP, clientID string, setts *filtering log.Debug("%s: looking for client with ip %s and clientid %q", pref, clientIP, clientID) - if clientIP == nil { + if !clientIP.IsValid() { return } diff --git a/internal/home/dns_internal_test.go b/internal/home/dns_internal_test.go index 8ba988f2..22fa06fe 100644 --- a/internal/home/dns_internal_test.go +++ b/internal/home/dns_internal_test.go @@ -1,7 +1,7 @@ package home import ( - "net" + "net/netip" "testing" "github.com/AdguardTeam/AdGuardHome/internal/filtering" @@ -10,6 +10,8 @@ import ( "github.com/stretchr/testify/require" ) +var testIPv4 = netip.AddrFrom4([4]byte{1, 2, 3, 4}) + func TestApplyAdditionalFiltering(t *testing.T) { var err error @@ -78,7 +80,7 @@ func TestApplyAdditionalFiltering(t *testing.T) { t.Run(tc.name, func(t *testing.T) { setts := &filtering.Settings{} - applyAdditionalFiltering(net.IP{1, 2, 3, 4}, tc.id, setts) + applyAdditionalFiltering(testIPv4, tc.id, setts) tc.FilteringEnabled(t, setts.FilteringEnabled) tc.SafeSearchEnabled(t, setts.SafeSearchEnabled) tc.SafeBrowsingEnabled(t, setts.SafeBrowsingEnabled) @@ -169,7 +171,7 @@ func TestApplyAdditionalFiltering_blockedServices(t *testing.T) { t.Run(tc.name, func(t *testing.T) { setts := &filtering.Settings{} - applyAdditionalFiltering(net.IP{1, 2, 3, 4}, tc.id, setts) + applyAdditionalFiltering(testIPv4, tc.id, setts) require.Len(t, setts.ServicesRules, tc.wantLen) }) } diff --git a/internal/querylog/decode.go b/internal/querylog/decode.go index af9a7ca4..f1ff5ad1 100644 --- a/internal/querylog/decode.go +++ b/internal/querylog/decode.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "net" + "net/netip" "strings" "time" @@ -183,7 +184,11 @@ func decodeResultRuleKey(key string, i int, dec *json.Decoder, ent *logEntry) { case "IP": ent.Result.Rules, vToken = decodeVTokenAndAddRule(key, i, dec, ent.Result.Rules) if ipStr, ok := vToken.(string); ok { - ent.Result.Rules[i].IP = net.ParseIP(ipStr) + if ip, err := netip.ParseAddr(ipStr); err == nil { + ent.Result.Rules[i].IP = ip + } else { + log.Debug("querylog: decoding ipStr value: %s", err) + } } case "Text": ent.Result.Rules, vToken = decodeVTokenAndAddRule(key, i, dec, ent.Result.Rules) @@ -362,8 +367,9 @@ func decodeResultIPList(dec *json.Decoder, ent *logEntry) { return case string: - ip := net.ParseIP(v) - if ip != nil { + var ip netip.Addr + ip, err = netip.ParseAddr(v) + if err == nil { ent.Result.IPList = append(ent.Result.IPList, ip) } default: @@ -462,7 +468,7 @@ func translateResult(ent *logEntry) { resp := res.DNSRewriteResult.Response for _, ip := range res.IPList { qType := dns.TypeAAAA - if ip.To4() != nil { + if ip.Is4() { qType = dns.TypeA } diff --git a/internal/querylog/decode_test.go b/internal/querylog/decode_test.go index 3e4e4f0d..4fc1d244 100644 --- a/internal/querylog/decode_test.go +++ b/internal/querylog/decode_test.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/base64" "net" + "net/netip" "strings" "testing" "time" @@ -11,6 +12,7 @@ import ( "github.com/AdguardTeam/AdGuardHome/internal/aghtest" "github.com/AdguardTeam/AdGuardHome/internal/filtering" "github.com/AdguardTeam/golibs/log" + "github.com/AdguardTeam/golibs/netutil" "github.com/AdguardTeam/urlfilter/rules" "github.com/miekg/dns" "github.com/stretchr/testify/assert" @@ -71,15 +73,15 @@ func TestDecodeLogEntry(t *testing.T) { }, CanonName: "example.com", ServiceName: "example.org", - IPList: []net.IP{net.IPv4(127, 0, 0, 2)}, + IPList: []netip.Addr{netip.AddrFrom4([4]byte{127, 0, 0, 2})}, Rules: []*filtering.ResultRule{{ FilterListID: 42, Text: "||an.yandex.ru", - IP: net.IPv4(127, 0, 0, 2), + IP: netip.AddrFrom4([4]byte{127, 0, 0, 2}), }, { FilterListID: 43, Text: "||an2.yandex.ru", - IP: net.IPv4(127, 0, 0, 3), + IP: netip.AddrFrom4([4]byte{127, 0, 0, 3}), }}, Reason: filtering.FilteredBlockList, IsFiltered: true, @@ -192,8 +194,10 @@ func TestDecodeLogEntry(t *testing.T) { func TestDecodeLogEntry_backwardCompatability(t *testing.T) { var ( - a1, a2 = net.IP{127, 0, 0, 1}.To16(), net.IP{127, 0, 0, 2}.To16() - aaaa1, aaaa2 = net.ParseIP("::1"), net.ParseIP("::2") + a1 = netutil.IPv4Localhost() + a2 = a1.Next() + aaaa1 = netutil.IPv6Localhost() + aaaa2 = aaaa1.Next() ) testCases := []struct { @@ -230,7 +234,7 @@ func TestDecodeLogEntry_backwardCompatability(t *testing.T) { entry: `{"Result":{"IPList":["127.0.0.1","127.0.0.2","::1","::2"],"Reason":9}}`, want: &logEntry{ Result: filtering.Result{ - IPList: []net.IP{ + IPList: []netip.Addr{ a1, a2, aaaa1,