mirror of
https://github.com/cunnie/sslip.io.git
synced 2025-10-05 07:36:54 +08:00
Disable DNS-backed key-value store
I'm disabling the key-value store because no one was using it. There are other reasons, too: - The removal of the `etcd` library dropped the executable size by over half from 17MB to 7MB - I didn't want users who've deployed it internally to be "surprised" by unexpected key-value features - Key-value-over-DNS has a seamy side to it: "data exfiltration". I know there are legitimate uses for it, but I've come to believe that a Key-value-over-HTTP solution is preferable because it's not only more legitimate but also because it eliminates the DNS caching problem.
This commit is contained in:
@@ -60,18 +60,7 @@ dig @$DNS_SERVER_IP txt ip.sslip.io +short | tr -d '"'
|
|||||||
echo 127.0.0.1
|
echo 127.0.0.1
|
||||||
dig @$DNS_SERVER_IP txt version.status.sslip.io +short | grep $VERSION
|
dig @$DNS_SERVER_IP txt version.status.sslip.io +short | grep $VERSION
|
||||||
echo "\"$VERSION\""
|
echo "\"$VERSION\""
|
||||||
dig @$DNS_SERVER_IP my-key.k-v.io txt +short # returns nothing
|
|
||||||
echo " ===" # separator because the results are too similar
|
echo " ===" # separator because the results are too similar
|
||||||
dig @$DNS_SERVER_IP put.MyValue.my-key.k-v.io txt +short
|
|
||||||
echo "\"MyValue\""
|
|
||||||
echo " ===" # separator because the results are too similar
|
|
||||||
dig @$DNS_SERVER_IP MY-KEY.k-v.io txt +short
|
|
||||||
echo "\"MyValue\""
|
|
||||||
echo " ===" # separator because the results are too similar
|
|
||||||
dig @$DNS_SERVER_IP delete.my-key.k-v.io txt +short
|
|
||||||
echo
|
|
||||||
echo " ===" # separator because the results are too similar
|
|
||||||
dig @$DNS_SERVER_IP my-key.k-v.io txt +short # returns nothing
|
|
||||||
dig @$DNS_SERVER_IP 1.0.0.127.in-addr.arpa ptr +short
|
dig @$DNS_SERVER_IP 1.0.0.127.in-addr.arpa ptr +short
|
||||||
echo "127-0-0-1.sslip.io."
|
echo "127-0-0-1.sslip.io."
|
||||||
dig @$DNS_SERVER_IP metrics.status.sslip.io txt +short | grep '"Queries: '
|
dig @$DNS_SERVER_IP metrics.status.sslip.io txt +short | grep '"Queries: '
|
||||||
|
@@ -36,6 +36,8 @@
|
|||||||
<main role="main" class="container">
|
<main role="main" class="container">
|
||||||
<div class="starter-template">
|
<div class="starter-template">
|
||||||
<h1>k-v.io</h1>
|
<h1>k-v.io</h1>
|
||||||
|
<p>k-v.io is under construction. I've dismantled the DNS-backed key-value store—no one was using it. Stay
|
||||||
|
tuned.</p><!--
|
||||||
<p>A DNS-based Key-Value Store. <a href="https://ci.nono.io/teams/main/pipelines/sslip.io"><img alt="badge" src=
|
<p>A DNS-based Key-Value Store. <a href="https://ci.nono.io/teams/main/pipelines/sslip.io"><img alt="badge" src=
|
||||||
"https://ci.nono.io/api/v1/teams/main/pipelines/sslip.io/badge"></a></p>
|
"https://ci.nono.io/api/v1/teams/main/pipelines/sslip.io/badge"></a></p>
|
||||||
<h2>Quick Start</h2>
|
<h2>Quick Start</h2>
|
||||||
@@ -115,6 +117,8 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
-->
|
||||||
|
</div>
|
||||||
</main><!-- /.container -->
|
</main><!-- /.container -->
|
||||||
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity=
|
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity=
|
||||||
"sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
|
"sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
|
||||||
|
@@ -21,14 +21,6 @@
|
|||||||
"TXTSslipIoSPF"
|
"TXTSslipIoSPF"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"k-v.io.": {
|
|
||||||
"A": [
|
|
||||||
"104.155.144.4"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"_acme-challenge.k-v.io.": {
|
|
||||||
"TXT": []
|
|
||||||
},
|
|
||||||
"ns.sslip.io.": {
|
"ns.sslip.io.": {
|
||||||
"A": [
|
"A": [
|
||||||
"52.0.56.137",
|
"52.0.56.137",
|
||||||
|
@@ -1,33 +1,22 @@
|
|||||||
module xip
|
module xip
|
||||||
|
|
||||||
go 1.19
|
go 1.20
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/onsi/ginkgo/v2 v2.8.4
|
github.com/onsi/ginkgo/v2 v2.8.4
|
||||||
github.com/onsi/gomega v1.27.2
|
github.com/onsi/gomega v1.27.2
|
||||||
go.etcd.io/etcd/client/v3 v3.5.7
|
|
||||||
golang.org/x/net v0.7.0
|
golang.org/x/net v0.7.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/coreos/go-semver v0.3.1 // indirect
|
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
|
||||||
github.com/go-logr/logr v1.2.3 // indirect
|
github.com/go-logr/logr v1.2.3 // indirect
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
|
||||||
github.com/golang/protobuf v1.5.2 // indirect
|
|
||||||
github.com/google/go-cmp v0.5.9 // indirect
|
github.com/google/go-cmp v0.5.9 // indirect
|
||||||
github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10 // indirect
|
github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10 // indirect
|
||||||
go.etcd.io/etcd/api/v3 v3.5.7 // indirect
|
github.com/stretchr/testify v1.8.0 // indirect
|
||||||
go.etcd.io/etcd/client/pkg/v3 v3.5.7 // indirect
|
|
||||||
go.uber.org/atomic v1.10.0 // indirect
|
|
||||||
go.uber.org/multierr v1.9.0 // indirect
|
|
||||||
go.uber.org/zap v1.24.0 // indirect
|
|
||||||
golang.org/x/sys v0.5.0 // indirect
|
golang.org/x/sys v0.5.0 // indirect
|
||||||
golang.org/x/text v0.7.0 // indirect
|
golang.org/x/text v0.7.0 // indirect
|
||||||
golang.org/x/tools v0.6.0 // indirect
|
golang.org/x/tools v0.6.0 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20230227214838-9b19f0bdc514 // indirect
|
|
||||||
google.golang.org/grpc v1.53.0 // indirect
|
|
||||||
google.golang.org/protobuf v1.28.1 // indirect
|
google.golang.org/protobuf v1.28.1 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
@@ -1,8 +1,3 @@
|
|||||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
|
||||||
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
|
|
||||||
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
|
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@@ -10,87 +5,40 @@ github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
|||||||
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
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/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10 h1:CqYfpuYIjnlNxM3msdyPRKabhXZWbKjf3Q8BWROFBso=
|
github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10 h1:CqYfpuYIjnlNxM3msdyPRKabhXZWbKjf3Q8BWROFBso=
|
||||||
github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk=
|
github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk=
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
|
||||||
github.com/onsi/ginkgo/v2 v2.8.4 h1:gf5mIQ8cLFieruNLAdgijHF1PYfLphKm2dxxcUtcqK0=
|
github.com/onsi/ginkgo/v2 v2.8.4 h1:gf5mIQ8cLFieruNLAdgijHF1PYfLphKm2dxxcUtcqK0=
|
||||||
github.com/onsi/ginkgo/v2 v2.8.4/go.mod h1:427dEDQZkDKsBvCjc2A/ZPefhKxsTTrsQegMlayL730=
|
github.com/onsi/ginkgo/v2 v2.8.4/go.mod h1:427dEDQZkDKsBvCjc2A/ZPefhKxsTTrsQegMlayL730=
|
||||||
github.com/onsi/gomega v1.27.2 h1:SKU0CXeKE/WVgIV1T61kSa3+IRE8Ekrv9rdXDwwTqnY=
|
github.com/onsi/gomega v1.27.2 h1:SKU0CXeKE/WVgIV1T61kSa3+IRE8Ekrv9rdXDwwTqnY=
|
||||||
github.com/onsi/gomega v1.27.2/go.mod h1:5mR3phAHpkAVIDkHEUBY6HGVsU+cpcEscrGPB4oPlZI=
|
github.com/onsi/gomega v1.27.2/go.mod h1:5mR3phAHpkAVIDkHEUBY6HGVsU+cpcEscrGPB4oPlZI=
|
||||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
|
||||||
go.etcd.io/etcd/api/v3 v3.5.7 h1:sbcmosSVesNrWOJ58ZQFitHMdncusIifYcrBfwrlJSY=
|
|
||||||
go.etcd.io/etcd/api/v3 v3.5.7/go.mod h1:9qew1gCdDDLu+VwmeG+iFpL+QlpHTo7iubavdVDgCAA=
|
|
||||||
go.etcd.io/etcd/client/pkg/v3 v3.5.7 h1:y3kf5Gbp4e4q7egZdn5T7W9TSHUvkClN6u+Rq9mEOmg=
|
|
||||||
go.etcd.io/etcd/client/pkg/v3 v3.5.7/go.mod h1:o0Abi1MK86iad3YrWhgUsbGx1pmTS+hrORWc2CamuhY=
|
|
||||||
go.etcd.io/etcd/client/v3 v3.5.7 h1:u/OhpiuCgYY8awOHlhIhmGIGpxfBU/GZBUP3m/3/Iz4=
|
|
||||||
go.etcd.io/etcd/client/v3 v3.5.7/go.mod h1:sOWmj9DZUMyAngS7QQwCyAXXAL6WhgTOPLNS/NabQgw=
|
|
||||||
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
|
|
||||||
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
|
||||||
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
|
|
||||||
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
|
|
||||||
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
|
|
||||||
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
|
|
||||||
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
|
|
||||||
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.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
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-20200226121028-0de0cce0169b/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.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/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-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
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-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
|
||||||
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
|
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
|
||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
google.golang.org/genproto v0.0.0-20230227214838-9b19f0bdc514 h1:rtNKfB++wz5mtDY2t5C8TXlU5y52ojSu7tZo0z7u8eQ=
|
|
||||||
google.golang.org/genproto v0.0.0-20230227214838-9b19f0bdc514/go.mod h1:TvhZT5f700eVlTNwND1xoEZQeWTB2RY/65kplwl/bFA=
|
|
||||||
google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc=
|
|
||||||
google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
|
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
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.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v2 v2.2.2/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 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
@@ -123,30 +123,6 @@ var _ = Describe("IntegrationMetrics", func() {
|
|||||||
actualMetrics = digAndGetMetrics("@localhost version.status.sslip.io txt +short -p "+strconv.Itoa(port), port)
|
actualMetrics = digAndGetMetrics("@localhost version.status.sslip.io txt +short -p "+strconv.Itoa(port), port)
|
||||||
Expect(expectedMetrics.MostlyEquals(actualMetrics)).To(BeTrue())
|
Expect(expectedMetrics.MostlyEquals(actualMetrics)).To(BeTrue())
|
||||||
|
|
||||||
// TXT put.value.key.k-v.io updates .Queries, .AnsweredQueries, .AnsweredTXTPutKvQueries
|
|
||||||
expectedMetrics.Queries++
|
|
||||||
expectedMetrics.AnsweredQueries++
|
|
||||||
expectedMetrics.AnsweredTXTPutKvQueries++
|
|
||||||
expectedMetrics = bumpExpectedToAccountForMetricsQuery(expectedMetrics)
|
|
||||||
actualMetrics = digAndGetMetrics("@localhost put.value.key.k-v.io txt +short -p "+strconv.Itoa(port), port)
|
|
||||||
Expect(expectedMetrics.MostlyEquals(actualMetrics)).To(BeTrue())
|
|
||||||
|
|
||||||
// TXT key.k-v.io updates .Queries, .AnsweredQueries, .AnsweredTXTGetKvQueries
|
|
||||||
expectedMetrics.Queries++
|
|
||||||
expectedMetrics.AnsweredQueries++
|
|
||||||
expectedMetrics.AnsweredTXTGetKvQueries++
|
|
||||||
expectedMetrics = bumpExpectedToAccountForMetricsQuery(expectedMetrics)
|
|
||||||
actualMetrics = digAndGetMetrics("@localhost key.k-v.io txt +short -p "+strconv.Itoa(port), port)
|
|
||||||
Expect(expectedMetrics.MostlyEquals(actualMetrics)).To(BeTrue())
|
|
||||||
|
|
||||||
// TXT delete.key.k-v.io updates .Queries, .AnsweredTXTDelKvQueries
|
|
||||||
// It doesn't count as an "answered" query because it returns no record
|
|
||||||
expectedMetrics.Queries++
|
|
||||||
expectedMetrics.AnsweredTXTDelKvQueries++
|
|
||||||
expectedMetrics = bumpExpectedToAccountForMetricsQuery(expectedMetrics)
|
|
||||||
actualMetrics = digAndGetMetrics("@localhost delete.key.k-v.io txt +short -p "+strconv.Itoa(port), port)
|
|
||||||
Expect(expectedMetrics.MostlyEquals(actualMetrics)).To(BeTrue())
|
|
||||||
|
|
||||||
// PTR version.sslip.io updates .Queries, .AnsweredQueries, .AnsweredPTRQueriesIPv4
|
// PTR version.sslip.io updates .Queries, .AnsweredQueries, .AnsweredPTRQueriesIPv4
|
||||||
expectedMetrics.Queries++
|
expectedMetrics.Queries++
|
||||||
expectedMetrics.AnsweredQueries++
|
expectedMetrics.AnsweredQueries++
|
||||||
@@ -203,7 +179,6 @@ func getMetrics(port int) (m xip.Metrics) {
|
|||||||
var junk string
|
var junk string
|
||||||
_, err = fmt.Sscanf(string(stdout),
|
_, err = fmt.Sscanf(string(stdout),
|
||||||
"\"Uptime: %d\"\n"+
|
"\"Uptime: %d\"\n"+
|
||||||
"\"KV Store: %s\n"+ // %s "swallows" the double-quote at the end
|
|
||||||
"\"Blocklist: %s %s %s\n"+
|
"\"Blocklist: %s %s %s\n"+
|
||||||
"\"Queries: %d (%s\n"+ // %s "swallows" the `/s"` at the end
|
"\"Queries: %d (%s\n"+ // %s "swallows" the `/s"` at the end
|
||||||
"\"Answered Queries: %d (%s\n"+ // %s "swallows" the `/s"` at the end
|
"\"Answered Queries: %d (%s\n"+ // %s "swallows" the `/s"` at the end
|
||||||
@@ -211,12 +186,10 @@ func getMetrics(port int) (m xip.Metrics) {
|
|||||||
"\"AAAA: %d\"\n"+
|
"\"AAAA: %d\"\n"+
|
||||||
"\"TXT Source: %d\"\n"+
|
"\"TXT Source: %d\"\n"+
|
||||||
"\"TXT Version: %d\"\n"+
|
"\"TXT Version: %d\"\n"+
|
||||||
"\"TXT KV GET/PUT/DEL: %d/%d/%d\"\n"+
|
|
||||||
"\"PTR IPv4/IPv6: %d/%d\"\n"+
|
"\"PTR IPv4/IPv6: %d/%d\"\n"+
|
||||||
"\"NS DNS-01: %d\"\n"+
|
"\"NS DNS-01: %d\"\n"+
|
||||||
"\"Blocked: %d\"\n",
|
"\"Blocked: %d\"\n",
|
||||||
&uptime,
|
&uptime,
|
||||||
&junk,
|
|
||||||
&junk, &junk, &junk,
|
&junk, &junk, &junk,
|
||||||
&m.Queries, &junk,
|
&m.Queries, &junk,
|
||||||
&m.AnsweredQueries, &junk,
|
&m.AnsweredQueries, &junk,
|
||||||
@@ -224,7 +197,6 @@ func getMetrics(port int) (m xip.Metrics) {
|
|||||||
&m.AnsweredAAAAQueries,
|
&m.AnsweredAAAAQueries,
|
||||||
&m.AnsweredTXTSrcIPQueries,
|
&m.AnsweredTXTSrcIPQueries,
|
||||||
&m.AnsweredTXTVersionQueries,
|
&m.AnsweredTXTVersionQueries,
|
||||||
&m.AnsweredTXTGetKvQueries, &m.AnsweredTXTPutKvQueries, &m.AnsweredTXTDelKvQueries,
|
|
||||||
&m.AnsweredPTRQueriesIPv4, &m.AnsweredPTRQueriesIPv6,
|
&m.AnsweredPTRQueriesIPv4, &m.AnsweredPTRQueriesIPv6,
|
||||||
&m.AnsweredNSDNS01ChallengeQueries,
|
&m.AnsweredNSDNS01ChallengeQueries,
|
||||||
&m.AnsweredBlockedQueries,
|
&m.AnsweredBlockedQueries,
|
||||||
|
@@ -58,10 +58,6 @@ var _ = Describe("sslip.io-dns-server", func() {
|
|||||||
Eventually(string(digSession.Out.Contents())).Should(MatchRegexp(digResults))
|
Eventually(string(digSession.Out.Contents())).Should(MatchRegexp(digResults))
|
||||||
Eventually(string(serverSession.Err.Contents())).Should(MatchRegexp(serverLogMessage))
|
Eventually(string(serverSession.Err.Contents())).Should(MatchRegexp(serverLogMessage))
|
||||||
},
|
},
|
||||||
Entry("A (customized) for k-v.io",
|
|
||||||
"@localhost k-v.io +short",
|
|
||||||
`\A104.155.144.4\n\z`,
|
|
||||||
`TypeA k-v.io. \? 104.155.144.4\n`),
|
|
||||||
Entry("A (customized) for sslip.io",
|
Entry("A (customized) for sslip.io",
|
||||||
"@localhost sslip.io +short",
|
"@localhost sslip.io +short",
|
||||||
`\A78.46.204.247\n\z`,
|
`\A78.46.204.247\n\z`,
|
||||||
@@ -131,26 +127,6 @@ var _ = Describe("sslip.io-dns-server", func() {
|
|||||||
"@127.0.0.1 example.com txt +short",
|
"@127.0.0.1 example.com txt +short",
|
||||||
`\A\z`,
|
`\A\z`,
|
||||||
`TypeTXT example.com. \? nil, SOA example.com. briancunnie.gmail.com. 2022112600 900 900 1800 180\n`),
|
`TypeTXT example.com. \? nil, SOA example.com. briancunnie.gmail.com. 2022112600 900 900 1800 180\n`),
|
||||||
Entry(`getting a non-existent value: TXT for non-existent.k-v.io"`,
|
|
||||||
"@127.0.0.1 non-existent.k-v.io txt +short",
|
|
||||||
`\A\z`,
|
|
||||||
`TypeTXT non-existent.k-v.io. \? nil, SOA non-existent.k-v.io. briancunnie.gmail.com. 2022112600 900 900 1800 180\n`),
|
|
||||||
Entry(`putting a value: TXT for put.MyValue.MY-KEY.k-v.io"`,
|
|
||||||
"@127.0.0.1 put.MyValue.MY-KEY.k-v.io txt +short",
|
|
||||||
`"MyValue"`,
|
|
||||||
`TypeTXT put.MyValue.MY-KEY.k-v.io. \? \["MyValue"\]`),
|
|
||||||
Entry(`deleting a value: TXT for delete.my-key.k-v.io"`,
|
|
||||||
"@127.0.0.1 delete.my-key.k-v.io txt +short",
|
|
||||||
`\A\z`,
|
|
||||||
`TypeTXT delete.my-key.k-v.io. \? nil, SOA delete.my-key.k-v.io. briancunnie.gmail.com. 2022112600 900 900 1800 180\n`),
|
|
||||||
Entry(`setting a TXT for _acme-challenge.k-v.io appears to work (spoiler: it doesn't)'"`,
|
|
||||||
"@127.0.0.1 put.sneaky-boy._acme-challenge.k-v.io txt +short",
|
|
||||||
`sneaky-boy`,
|
|
||||||
`TypeTXT put.sneaky-boy._acme-challenge.k-v.io. \? \["sneaky-boy"\]`),
|
|
||||||
Entry(`get a TXT for _acme-challenge.k-v.io is blocked to foil Let's Encrypt ACME DNS-01 challenge"`,
|
|
||||||
"@127.0.0.1 _acme-challenge.k-v.io txt +short",
|
|
||||||
`Please don't try to procure a k-v.io cert via DNS-01 challenge`,
|
|
||||||
`TypeTXT _acme-challenge.k-v.io. \? \["Please don't try to procure a k-v.io cert via DNS-01 challenge"\]`),
|
|
||||||
Entry(`get a PTR for 1.0.168.192.in-addr.arpa returns 192-168-0-1.sslip.io`,
|
Entry(`get a PTR for 1.0.168.192.in-addr.arpa returns 192-168-0-1.sslip.io`,
|
||||||
"@127.0.0.1 1.0.168.192.in-addr.arpa ptr +short",
|
"@127.0.0.1 1.0.168.192.in-addr.arpa ptr +short",
|
||||||
`\A192-168-0-1.sslip.io.\n\z`,
|
`\A192-168-0-1.sslip.io.\n\z`,
|
||||||
@@ -267,79 +243,6 @@ var _ = Describe("sslip.io-dns-server", func() {
|
|||||||
Eventually(string(serverSession.Err.Contents())).Should(MatchRegexp(`TypeTXT sslip.io. \? \["protonmail-verification=ce0ca3f5010aa7a2cf8bcc693778338ffde73e26"\], \["v=spf1 include:_spf.protonmail.ch mx ~all"\]\n`))
|
Eventually(string(serverSession.Err.Contents())).Should(MatchRegexp(`TypeTXT sslip.io. \? \["protonmail-verification=ce0ca3f5010aa7a2cf8bcc693778338ffde73e26"\], \["v=spf1 include:_spf.protonmail.ch mx ~all"\]\n`))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
When(`a TXT record for a host under the "k-v.io" domain is queried`, func() {
|
|
||||||
It(`the PUT has a three-minute TTL`, func() {
|
|
||||||
digArgs = "@localhost put.a.a.k-v.io txt -p " + strconv.Itoa(port)
|
|
||||||
digCmd = exec.Command("dig", strings.Split(digArgs, " ")...)
|
|
||||||
digSession, err = Start(digCmd, GinkgoWriter, GinkgoWriter)
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
Eventually(digSession, 1).Should(Exit(0))
|
|
||||||
Eventually(string(digSession.Out.Contents())).Should(MatchRegexp(`put.a.a.k-v.io. 180 IN TXT "a"`))
|
|
||||||
Eventually(string(serverSession.Err.Contents())).Should(MatchRegexp(`TypeTXT put.a.a.k-v.io. \? \["a"\]`))
|
|
||||||
})
|
|
||||||
It(`the GET has a three-minute TTL`, func() {
|
|
||||||
// create (PUT) the key
|
|
||||||
digArgs = "@localhost put.a.b.k-v.io txt -p " + strconv.Itoa(port)
|
|
||||||
digCmd = exec.Command("dig", strings.Split(digArgs, " ")...)
|
|
||||||
digSession, err = Start(digCmd, GinkgoWriter, GinkgoWriter)
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
Eventually(digSession, 1).Should(Exit(0))
|
|
||||||
// retrieve (GET) the key
|
|
||||||
digArgs = "@localhost b.k-v.io txt -p " + strconv.Itoa(port)
|
|
||||||
digCmd = exec.Command("dig", strings.Split(digArgs, " ")...)
|
|
||||||
digSession, err = Start(digCmd, GinkgoWriter, GinkgoWriter)
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
Eventually(digSession, 1).Should(Exit(0))
|
|
||||||
Eventually(string(digSession.Out.Contents()), 3).Should(MatchRegexp(`b.k-v.io. 180 IN TXT "a"`))
|
|
||||||
Eventually(string(serverSession.Err.Contents())).Should(MatchRegexp(`TypeTXT b.k-v.io. \? \["a"\]`))
|
|
||||||
})
|
|
||||||
It(`the DELETE returns no records so that value cached in downstream DNS servers expires more quickly`, func() {
|
|
||||||
// create (PUT) the key
|
|
||||||
digArgs = "@localhost put.a.c.k-v.io txt -p " + strconv.Itoa(port)
|
|
||||||
digCmd = exec.Command("dig", strings.Split(digArgs, " ")...)
|
|
||||||
digSession, err = Start(digCmd, GinkgoWriter, GinkgoWriter)
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
Eventually(digSession, 1).Should(Exit(0))
|
|
||||||
// DELETE the key
|
|
||||||
digArgs = "@localhost delete.c.k-v.io txt -p " + strconv.Itoa(port)
|
|
||||||
digCmd = exec.Command("dig", strings.Split(digArgs, " ")...)
|
|
||||||
digSession, err = Start(digCmd, GinkgoWriter, GinkgoWriter)
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
Eventually(digSession, 1).Should(Exit(0))
|
|
||||||
Eventually(string(serverSession.Err.Contents())).Should(MatchRegexp(`TypeTXT delete.c.k-v.io. \? nil, SOA delete.c.k-v.io. briancunnie.gmail.com. 2022112600 900 900 1800 180`))
|
|
||||||
})
|
|
||||||
It(`the DELETE on a non-existent key behaves the same as the DELETE on an existing key`, func() {
|
|
||||||
// DELETE the key (make sure it's gone)
|
|
||||||
digArgs = "@localhost delete.d.k-v.io txt -p " + strconv.Itoa(port)
|
|
||||||
digCmd = exec.Command("dig", strings.Split(digArgs, " ")...)
|
|
||||||
digSession, err = Start(digCmd, GinkgoWriter, GinkgoWriter)
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
Eventually(digSession, 1).Should(Exit(0))
|
|
||||||
// DELETE again to test the non-existent behavior
|
|
||||||
digArgs = "@localhost delete.d.k-v.io txt -p " + strconv.Itoa(port)
|
|
||||||
digCmd = exec.Command("dig", strings.Split(digArgs, " ")...)
|
|
||||||
digSession, err = Start(digCmd, GinkgoWriter, GinkgoWriter)
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
Eventually(digSession, 1).Should(Exit(0))
|
|
||||||
Eventually(string(serverSession.Err.Contents())).Should(MatchRegexp(`TypeTXT delete.d.k-v.io. \? nil, SOA delete.d.k-v.io. briancunnie.gmail.com. 2022112600 900 900 1800 180`))
|
|
||||||
})
|
|
||||||
It(`setting a TXT for _acme-challenge.subdomain-key.k-v.io doesn't expose DNS-01 vulnerability`, func() {
|
|
||||||
// set (PUT) the key
|
|
||||||
digArgs = "@localhost put.baffled-boy._acme-challenge.subdomain-key.k-v.io txt +short -p " + strconv.Itoa(port)
|
|
||||||
digCmd = exec.Command("dig", strings.Split(digArgs, " ")...)
|
|
||||||
digSession, err = Start(digCmd, GinkgoWriter, GinkgoWriter)
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
Eventually(digSession, 1).Should(Exit(0))
|
|
||||||
// GET the key
|
|
||||||
digArgs = "@localhost get.subdomain-key.k-v.io txt +short -p " + strconv.Itoa(port)
|
|
||||||
digCmd = exec.Command("dig", strings.Split(digArgs, " ")...)
|
|
||||||
digSession, err = Start(digCmd, GinkgoWriter, GinkgoWriter)
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
Eventually(digSession, 1).Should(Exit(0))
|
|
||||||
Eventually(string(digSession.Out.Contents()), 3).Should(MatchRegexp(`"baffled-boy._acme-challenge"`))
|
|
||||||
Eventually(string(serverSession.Err.Contents())).Should(MatchRegexp(`TypeTXT get.subdomain-key.k-v.io. \? \["baffled-boy._acme-challenge"\]`))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
When(`a record for an "_acme-challenge" domain is queried`, func() {
|
When(`a record for an "_acme-challenge" domain is queried`, func() {
|
||||||
When(`it's an NS record`, func() {
|
When(`it's an NS record`, func() {
|
||||||
It(`returns the NS record of the query with the "_acme-challenge." stripped`, func() {
|
It(`returns the NS record of the query with the "_acme-challenge." stripped`, func() {
|
||||||
|
@@ -15,13 +15,11 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
var etcdEndpoint = flag.String("etcdHost", "localhost:2379", "etcd client endpoint; falls back to builtin key-value store if unable to connect")
|
|
||||||
var blocklistURL = flag.String("blocklistURL", "https://raw.githubusercontent.com/cunnie/sslip.io/main/etc/blocklist.txt", `URL containing a list of "forbidden" names/CIDRs`)
|
var blocklistURL = flag.String("blocklistURL", "https://raw.githubusercontent.com/cunnie/sslip.io/main/etc/blocklist.txt", `URL containing a list of "forbidden" names/CIDRs`)
|
||||||
var nameservers = flag.String("nameservers", "ns-aws.sslip.io.,ns-azure.sslip.io.,ns-gce.sslip.io.", "comma-separated list of nameservers")
|
var nameservers = flag.String("nameservers", "ns-aws.sslip.io.,ns-azure.sslip.io.,ns-gce.sslip.io.", "comma-separated list of nameservers")
|
||||||
var addresses = flag.String("addresses",
|
var addresses = flag.String("addresses",
|
||||||
"sslip.io=78.46.204.247,"+
|
"sslip.io=78.46.204.247,"+
|
||||||
"sslip.io=2a01:4f8:c17:b8f::2,"+
|
"sslip.io=2a01:4f8:c17:b8f::2,"+
|
||||||
"k-v.io=104.155.144.4,"+
|
|
||||||
"ns.sslip.io=52.0.56.137,"+
|
"ns.sslip.io=52.0.56.137,"+
|
||||||
"ns.sslip.io=52.187.42.158,"+
|
"ns.sslip.io=52.187.42.158,"+
|
||||||
"ns.sslip.io=104.155.144.4,"+
|
"ns.sslip.io=104.155.144.4,"+
|
||||||
@@ -34,10 +32,10 @@ func main() {
|
|||||||
var quiet = flag.Bool("quiet", false, "suppresses logging of each DNS response")
|
var quiet = flag.Bool("quiet", false, "suppresses logging of each DNS response")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
log.Printf("%s version %s starting", os.Args[0], xip.VersionSemantic)
|
log.Printf("%s version %s starting", os.Args[0], xip.VersionSemantic)
|
||||||
log.Printf("etcd endpoint: %s, blocklist URL: %s, name servers: %s, bind port: %d, quiet: %t",
|
log.Printf("blocklist URL: %s, name servers: %s, bind port: %d, quiet: %t",
|
||||||
*etcdEndpoint, *blocklistURL, *nameservers, *bindPort, *quiet)
|
*blocklistURL, *nameservers, *bindPort, *quiet)
|
||||||
|
|
||||||
x, logmessages := xip.NewXip(*etcdEndpoint, *blocklistURL, strings.Split(*nameservers, ","), strings.Split(*addresses, ","))
|
x, logmessages := xip.NewXip(*blocklistURL, strings.Split(*nameservers, ","), strings.Split(*addresses, ","))
|
||||||
for _, logmessage := range logmessages {
|
for _, logmessage := range logmessages {
|
||||||
log.Println(logmessage)
|
log.Println(logmessage)
|
||||||
}
|
}
|
||||||
|
@@ -5,7 +5,6 @@ package xip
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"context"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@@ -14,29 +13,18 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
clientv3 "go.etcd.io/etcd/client/v3"
|
|
||||||
"golang.org/x/net/dns/dnsmessage"
|
"golang.org/x/net/dns/dnsmessage"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 -generate
|
//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 -generate
|
||||||
|
|
||||||
//counterfeiter:generate . V3client
|
|
||||||
type V3client interface {
|
|
||||||
Get(context.Context, string, ...clientv3.OpOption) (*clientv3.GetResponse, error)
|
|
||||||
Put(context.Context, string, string, ...clientv3.OpOption) (*clientv3.PutResponse, error)
|
|
||||||
Delete(context.Context, string, ...clientv3.OpOption) (*clientv3.DeleteResponse, error)
|
|
||||||
Close() error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Xip is meant to be a singleton that holds global state for the DNS server
|
// Xip is meant to be a singleton that holds global state for the DNS server
|
||||||
type Xip struct {
|
type Xip struct {
|
||||||
Etcd V3client // etcd client for `k-v.io`
|
|
||||||
DnsAmplificationAttackDelay chan struct{} // for throttling metrics.status.sslip.io
|
DnsAmplificationAttackDelay chan struct{} // for throttling metrics.status.sslip.io
|
||||||
Metrics Metrics // DNS server metrics
|
Metrics Metrics // DNS server metrics
|
||||||
BlocklistStrings []string // list of blacklisted strings that shouldn't appear in public hostnames
|
BlocklistStrings []string // list of blacklisted strings that shouldn't appear in public hostnames
|
||||||
@@ -54,9 +42,6 @@ type Metrics struct {
|
|||||||
AnsweredAAAAQueries int
|
AnsweredAAAAQueries int
|
||||||
AnsweredTXTSrcIPQueries int
|
AnsweredTXTSrcIPQueries int
|
||||||
AnsweredTXTVersionQueries int
|
AnsweredTXTVersionQueries int
|
||||||
AnsweredTXTGetKvQueries int
|
|
||||||
AnsweredTXTPutKvQueries int
|
|
||||||
AnsweredTXTDelKvQueries int
|
|
||||||
AnsweredNSDNS01ChallengeQueries int
|
AnsweredNSDNS01ChallengeQueries int
|
||||||
AnsweredBlockedQueries int
|
AnsweredBlockedQueries int
|
||||||
AnsweredPTRQueriesIPv4 int
|
AnsweredPTRQueriesIPv4 int
|
||||||
@@ -88,12 +73,6 @@ type DomainCustomization struct {
|
|||||||
// DNS hostnames are technically case-insensitive
|
// DNS hostnames are technically case-insensitive
|
||||||
type DomainCustomizations map[string]DomainCustomization
|
type DomainCustomizations map[string]DomainCustomization
|
||||||
|
|
||||||
// KvCustomizations is a lookup table for custom TXT records
|
|
||||||
// e.g. KvCustomizations["my-key"] = []dnsmessage.TXTResource{ TXT: { "my-value" } }
|
|
||||||
// The key should NOT include ".k-v.io."
|
|
||||||
// It's used when there's no etcd server running
|
|
||||||
type KvCustomizations map[string][]dnsmessage.TXTResource
|
|
||||||
|
|
||||||
// There's nothing like global variables to make my heart pound with joy.
|
// There's nothing like global variables to make my heart pound with joy.
|
||||||
// Some of these are global because they are, in essence, constants which
|
// Some of these are global because they are, in essence, constants which
|
||||||
// I don't want to waste time recreating with every function call.
|
// I don't want to waste time recreating with every function call.
|
||||||
@@ -105,7 +84,6 @@ var (
|
|||||||
ipv4ReverseRE = regexp.MustCompile(`^(.*)\.in-addr\.arpa\.$`)
|
ipv4ReverseRE = regexp.MustCompile(`^(.*)\.in-addr\.arpa\.$`)
|
||||||
ipv6ReverseRE = regexp.MustCompile(`^(([[:xdigit:]]\.){32})ip6\.arpa\.`)
|
ipv6ReverseRE = regexp.MustCompile(`^(([[:xdigit:]]\.){32})ip6\.arpa\.`)
|
||||||
dns01ChallengeRE = regexp.MustCompile(`(?i)_acme-challenge\.`) // (?i) → non-capturing case insensitive
|
dns01ChallengeRE = regexp.MustCompile(`(?i)_acme-challenge\.`) // (?i) → non-capturing case insensitive
|
||||||
kvRE = regexp.MustCompile(`\.k-v\.io\.$`)
|
|
||||||
|
|
||||||
mbox, _ = dnsmessage.NewName("briancunnie.gmail.com.")
|
mbox, _ = dnsmessage.NewName("briancunnie.gmail.com.")
|
||||||
mx1, _ = dnsmessage.NewName("mail.protonmail.ch.")
|
mx1, _ = dnsmessage.NewName("mail.protonmail.ch.")
|
||||||
@@ -120,15 +98,6 @@ var (
|
|||||||
|
|
||||||
MetricsBufferSize = 200 // big enough to run our tests, and small enough to prevent DNS amplification attacks
|
MetricsBufferSize = 200 // big enough to run our tests, and small enough to prevent DNS amplification attacks
|
||||||
|
|
||||||
// etcdContextTimeout — the duration (context) that we wait for etcd to get back to us
|
|
||||||
// - etcd queries on the nameserver take as long as 482 milliseconds on the "slow" server, 247 on the "fast"
|
|
||||||
// - round-trip time from my house in San Francisco to ns-azure in Singapore is 190 milliseconds
|
|
||||||
// - time between queries with `dig` on my macOS Monterey is 5000 milliseconds, three queries before giving up
|
|
||||||
// - quadruple the headroom for queries 4 x 482 = 1928, should still leave enough room to get answer back
|
|
||||||
// within the 5000 milliseconds
|
|
||||||
etcdContextTimeout = 1928 * time.Millisecond
|
|
||||||
|
|
||||||
TxtKvCustomizations = KvCustomizations{}
|
|
||||||
Customizations = DomainCustomizations{
|
Customizations = DomainCustomizations{
|
||||||
"sslip.io.": {
|
"sslip.io.": {
|
||||||
MX: []dnsmessage.MXResource{
|
MX: []dnsmessage.MXResource{
|
||||||
@@ -143,12 +112,6 @@ var (
|
|||||||
},
|
},
|
||||||
TXT: TXTSslipIoSPF,
|
TXT: TXTSslipIoSPF,
|
||||||
},
|
},
|
||||||
// don't let people procure *.k-v.io TLS certs via ACME DNS-01 challenge
|
|
||||||
"_acme-challenge.k-v.io.": {
|
|
||||||
TXT: func(_ *Xip, _ net.IP) ([]dnsmessage.TXTResource, error) {
|
|
||||||
return []dnsmessage.TXTResource{{TXT: []string{"Please don't try to procure a k-v.io cert via DNS-01 challenge"}}}, nil
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// nameserver addresses; we get queries for those every once in a while
|
// nameserver addresses; we get queries for those every once in a while
|
||||||
// CNAMEs for sslip.io for DKIM signing
|
// CNAMEs for sslip.io for DKIM signing
|
||||||
"protonmail._domainkey.sslip.io.": {
|
"protonmail._domainkey.sslip.io.": {
|
||||||
@@ -201,19 +164,8 @@ type Response struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewXip follows convention for constructors: https://go.dev/doc/effective_go#allocation_new
|
// NewXip follows convention for constructors: https://go.dev/doc/effective_go#allocation_new
|
||||||
func NewXip(etcdEndpoint, blocklistURL string, nameservers []string, addresses []string) (x *Xip, logmessages []string) {
|
func NewXip(blocklistURL string, nameservers []string, addresses []string) (x *Xip, logmessages []string) {
|
||||||
var err error
|
|
||||||
x = &Xip{Metrics: Metrics{Start: time.Now()}}
|
x = &Xip{Metrics: Metrics{Start: time.Now()}}
|
||||||
// connect to `etcd`; if there's an error, set etcdCli to `nil` and that to
|
|
||||||
// determine whether to use a local key-value store instead
|
|
||||||
x.Etcd, err = clientv3New(etcdEndpoint)
|
|
||||||
if err != nil {
|
|
||||||
logmessages = append(logmessages, fmt.Sprintf("failed to connect to etcd at %s, using local key-value store instead: %s", etcdEndpoint, err.Error()))
|
|
||||||
} else {
|
|
||||||
logmessages = append(logmessages, fmt.Sprintf("Successfully connected to etcd at %s", etcdEndpoint))
|
|
||||||
}
|
|
||||||
// don't `defer etcdCli.Close()`: "The Client has internal state (watchers and leases), so
|
|
||||||
// Clients should be reused instead of created as needed"
|
|
||||||
|
|
||||||
// Download the blocklist
|
// Download the blocklist
|
||||||
logmessages = append(logmessages, x.downloadBlockList(blocklistURL))
|
logmessages = append(logmessages, x.downloadBlockList(blocklistURL))
|
||||||
@@ -819,7 +771,7 @@ func (x *Xip) NSResources(fqdnString string) []dnsmessage.NSResource {
|
|||||||
return x.NameServers
|
return x.NameServers
|
||||||
}
|
}
|
||||||
|
|
||||||
// TXTResources returns TXT records from Customizations or KvCustomizations
|
// TXTResources returns TXT records from Customizations
|
||||||
func (x *Xip) TXTResources(fqdn string, ip net.IP) ([]dnsmessage.TXTResource, error) {
|
func (x *Xip) TXTResources(fqdn string, ip net.IP) ([]dnsmessage.TXTResource, error) {
|
||||||
if domain, ok := Customizations[strings.ToLower(fqdn)]; ok {
|
if domain, ok := Customizations[strings.ToLower(fqdn)]; ok {
|
||||||
// Customizations[strings.ToLower(fqdn)] returns a _function_,
|
// Customizations[strings.ToLower(fqdn)] returns a _function_,
|
||||||
@@ -828,9 +780,6 @@ func (x *Xip) TXTResources(fqdn string, ip net.IP) ([]dnsmessage.TXTResource, er
|
|||||||
return domain.TXT(x, ip)
|
return domain.TXT(x, ip)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if kvRE.MatchString(fqdn) {
|
|
||||||
return x.kvTXTResources(fqdn)
|
|
||||||
}
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -938,11 +887,6 @@ func TXTMetrics(x *Xip, _ net.IP) (txtResources []dnsmessage.TXTResource, err er
|
|||||||
var metrics []string
|
var metrics []string
|
||||||
uptime := time.Since(x.Metrics.Start)
|
uptime := time.Since(x.Metrics.Start)
|
||||||
metrics = append(metrics, fmt.Sprintf("Uptime: %.0f", uptime.Seconds()))
|
metrics = append(metrics, fmt.Sprintf("Uptime: %.0f", uptime.Seconds()))
|
||||||
keyValueStore := "etcd"
|
|
||||||
if x.isEtcdNil() {
|
|
||||||
keyValueStore = "builtin"
|
|
||||||
}
|
|
||||||
metrics = append(metrics, "KV Store: "+keyValueStore)
|
|
||||||
metrics = append(metrics, fmt.Sprintf("Blocklist: %s %d,%d",
|
metrics = append(metrics, fmt.Sprintf("Blocklist: %s %d,%d",
|
||||||
x.BlocklistUpdated.Format("2006-01-02 15:04:05-07"),
|
x.BlocklistUpdated.Format("2006-01-02 15:04:05-07"),
|
||||||
len(x.BlocklistStrings),
|
len(x.BlocklistStrings),
|
||||||
@@ -953,7 +897,6 @@ func TXTMetrics(x *Xip, _ net.IP) (txtResources []dnsmessage.TXTResource, err er
|
|||||||
metrics = append(metrics, fmt.Sprintf("AAAA: %d", x.Metrics.AnsweredAAAAQueries))
|
metrics = append(metrics, fmt.Sprintf("AAAA: %d", x.Metrics.AnsweredAAAAQueries))
|
||||||
metrics = append(metrics, fmt.Sprintf("TXT Source: %d", x.Metrics.AnsweredTXTSrcIPQueries))
|
metrics = append(metrics, fmt.Sprintf("TXT Source: %d", x.Metrics.AnsweredTXTSrcIPQueries))
|
||||||
metrics = append(metrics, fmt.Sprintf("TXT Version: %d", x.Metrics.AnsweredTXTVersionQueries))
|
metrics = append(metrics, fmt.Sprintf("TXT Version: %d", x.Metrics.AnsweredTXTVersionQueries))
|
||||||
metrics = append(metrics, fmt.Sprintf("TXT KV GET/PUT/DEL: %d/%d/%d", x.Metrics.AnsweredTXTGetKvQueries, x.Metrics.AnsweredTXTPutKvQueries, x.Metrics.AnsweredTXTDelKvQueries))
|
|
||||||
metrics = append(metrics, fmt.Sprintf("PTR IPv4/IPv6: %d/%d", x.Metrics.AnsweredPTRQueriesIPv4, x.Metrics.AnsweredPTRQueriesIPv6))
|
metrics = append(metrics, fmt.Sprintf("PTR IPv4/IPv6: %d/%d", x.Metrics.AnsweredPTRQueriesIPv4, x.Metrics.AnsweredPTRQueriesIPv6))
|
||||||
metrics = append(metrics, fmt.Sprintf("NS DNS-01: %d", x.Metrics.AnsweredNSDNS01ChallengeQueries))
|
metrics = append(metrics, fmt.Sprintf("NS DNS-01: %d", x.Metrics.AnsweredNSDNS01ChallengeQueries))
|
||||||
metrics = append(metrics, fmt.Sprintf("Blocked: %d", x.Metrics.AnsweredBlockedQueries))
|
metrics = append(metrics, fmt.Sprintf("Blocked: %d", x.Metrics.AnsweredBlockedQueries))
|
||||||
@@ -963,106 +906,6 @@ func TXTMetrics(x *Xip, _ net.IP) (txtResources []dnsmessage.TXTResource, err er
|
|||||||
return txtResources, nil
|
return txtResources, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// when TXT for "k-v.io" is queried, return the key-value pair
|
|
||||||
func (x *Xip) kvTXTResources(fqdn string) ([]dnsmessage.TXTResource, error) {
|
|
||||||
// "labels" => official RFC 1035 term
|
|
||||||
// k-v.io. => ["k-v", "io"] are labels
|
|
||||||
var (
|
|
||||||
verb string // i.e. "get", "put", "delete"
|
|
||||||
key string // e.g. "my-key" as in "my-key.k-v.io"
|
|
||||||
value string // e.g. "my-value" as in "put.my-value.my-key.k-v.io"
|
|
||||||
)
|
|
||||||
labels := strings.Split(fqdn, ".")
|
|
||||||
labels = labels[:len(labels)-3] // strip ".k-v.io"
|
|
||||||
// key is always present, always first subdomain of "k-v.io"
|
|
||||||
key = strings.ToLower(labels[len(labels)-1])
|
|
||||||
switch {
|
|
||||||
case len(labels) == 1:
|
|
||||||
verb = "get" // default action if only key, not verb, is not present
|
|
||||||
case len(labels) == 2:
|
|
||||||
verb = strings.ToLower(labels[0]) // verb, if present, is leftmost, "put.value.key.k-v.io"
|
|
||||||
case len(labels) > 2:
|
|
||||||
verb = strings.ToLower(labels[0])
|
|
||||||
// concatenate multiple labels to create value, especially useful for version numbers
|
|
||||||
value = strings.Join(labels[1:len(labels)-1], ".") // e.g. "put.94.0.2.firefox-version.k-v.io"
|
|
||||||
}
|
|
||||||
// prepare to query etcd:
|
|
||||||
switch verb {
|
|
||||||
case "get":
|
|
||||||
return x.getKv(key)
|
|
||||||
case "put":
|
|
||||||
if len(labels) == 2 {
|
|
||||||
return []dnsmessage.TXTResource{{[]string{"422: missing a value: put.value.key.k-v.io"}}}, nil
|
|
||||||
}
|
|
||||||
return x.putKv(key, value)
|
|
||||||
case "delete":
|
|
||||||
return x.deleteKv(key)
|
|
||||||
}
|
|
||||||
return []dnsmessage.TXTResource{{[]string{"422: valid verbs are get, put, delete"}}}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Xip) getKv(key string) ([]dnsmessage.TXTResource, error) {
|
|
||||||
if x.isEtcdNil() {
|
|
||||||
if txtRecord, ok := TxtKvCustomizations[key]; ok {
|
|
||||||
x.Metrics.AnsweredTXTGetKvQueries++
|
|
||||||
return txtRecord, nil
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), etcdContextTimeout)
|
|
||||||
defer cancel()
|
|
||||||
resp, err := x.Etcd.Get(ctx, key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf(`couldn't GET "%s": %w`, key, err)
|
|
||||||
}
|
|
||||||
if len(resp.Kvs) > 0 {
|
|
||||||
x.Metrics.AnsweredTXTGetKvQueries++
|
|
||||||
return []dnsmessage.TXTResource{{[]string{string(resp.Kvs[0].Value)}}}, nil
|
|
||||||
}
|
|
||||||
return []dnsmessage.TXTResource{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Xip) putKv(key, value string) ([]dnsmessage.TXTResource, error) {
|
|
||||||
if len(value) > 63 { // too-long TXT records can be used in DNS amplification attacks; Truncate!
|
|
||||||
value = value[:63]
|
|
||||||
}
|
|
||||||
if x.isEtcdNil() {
|
|
||||||
TxtKvCustomizations[key] = []dnsmessage.TXTResource{
|
|
||||||
{
|
|
||||||
[]string{value},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
x.Metrics.AnsweredTXTPutKvQueries++
|
|
||||||
return TxtKvCustomizations[key], nil
|
|
||||||
}
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), etcdContextTimeout)
|
|
||||||
defer cancel()
|
|
||||||
_, err := x.Etcd.Put(ctx, key, value)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("couldn't PUT (%s: %s): %w", key, value, err)
|
|
||||||
}
|
|
||||||
x.Metrics.AnsweredTXTPutKvQueries++
|
|
||||||
return []dnsmessage.TXTResource{{[]string{value}}}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Xip) deleteKv(key string) ([]dnsmessage.TXTResource, error) {
|
|
||||||
if x.isEtcdNil() {
|
|
||||||
if _, ok := TxtKvCustomizations[key]; ok {
|
|
||||||
x.Metrics.AnsweredTXTDelKvQueries++
|
|
||||||
delete(TxtKvCustomizations, key)
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), etcdContextTimeout)
|
|
||||||
defer cancel()
|
|
||||||
_, err := x.Etcd.Delete(ctx, key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("couldn't DELETE (key %s): %w", key, err)
|
|
||||||
}
|
|
||||||
x.Metrics.AnsweredTXTDelKvQueries++
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// soaLogMessage returns an easy-to-read string for logging SOA Answers/Authorities
|
// soaLogMessage returns an easy-to-read string for logging SOA Answers/Authorities
|
||||||
func soaLogMessage(soaResource dnsmessage.SOAResource) string {
|
func soaLogMessage(soaResource dnsmessage.SOAResource) string {
|
||||||
return soaResource.NS.String() + " " +
|
return soaResource.NS.String() + " " +
|
||||||
@@ -1082,9 +925,6 @@ func (a Metrics) MostlyEquals(b Metrics) bool {
|
|||||||
a.AnsweredAAAAQueries == b.AnsweredAAAAQueries &&
|
a.AnsweredAAAAQueries == b.AnsweredAAAAQueries &&
|
||||||
a.AnsweredTXTSrcIPQueries == b.AnsweredTXTSrcIPQueries &&
|
a.AnsweredTXTSrcIPQueries == b.AnsweredTXTSrcIPQueries &&
|
||||||
a.AnsweredTXTVersionQueries == b.AnsweredTXTVersionQueries &&
|
a.AnsweredTXTVersionQueries == b.AnsweredTXTVersionQueries &&
|
||||||
a.AnsweredTXTGetKvQueries == b.AnsweredTXTGetKvQueries &&
|
|
||||||
a.AnsweredTXTPutKvQueries == b.AnsweredTXTPutKvQueries &&
|
|
||||||
a.AnsweredTXTDelKvQueries == b.AnsweredTXTDelKvQueries &&
|
|
||||||
a.AnsweredPTRQueriesIPv4 == b.AnsweredPTRQueriesIPv4 &&
|
a.AnsweredPTRQueriesIPv4 == b.AnsweredPTRQueriesIPv4 &&
|
||||||
a.AnsweredPTRQueriesIPv6 == b.AnsweredPTRQueriesIPv6 &&
|
a.AnsweredPTRQueriesIPv6 == b.AnsweredPTRQueriesIPv6 &&
|
||||||
a.AnsweredNSDNS01ChallengeQueries == b.AnsweredNSDNS01ChallengeQueries &&
|
a.AnsweredNSDNS01ChallengeQueries == b.AnsweredNSDNS01ChallengeQueries &&
|
||||||
@@ -1161,15 +1001,6 @@ func ReadBlocklist(blocklist io.Reader) (stringBlocklists []string, cidrBlocklis
|
|||||||
return stringBlocklists, cidrBlocklists, nil
|
return stringBlocklists, cidrBlocklists, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Xip) isEtcdNil() bool {
|
|
||||||
// comparing interfaces to nil are tricky: interfaces contain both a type
|
|
||||||
// and a value, and although the value is nil the type isn't, so we need the following
|
|
||||||
if x.Etcd == nil || reflect.ValueOf(x.Etcd).IsNil() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Xip) blocklist(hostname string) bool {
|
func (x *Xip) blocklist(hostname string) bool {
|
||||||
aResources := NameToA(hostname)
|
aResources := NameToA(hostname)
|
||||||
aaaaResources := NameToAAAA(hostname)
|
aaaaResources := NameToAAAA(hostname)
|
||||||
@@ -1322,25 +1153,3 @@ func (x *Xip) nameToAAAAwithBlocklist(q dnsmessage.Question, response Response,
|
|||||||
}
|
}
|
||||||
return response, logMessage + strings.Join(logMessages, ", "), nil
|
return response, logMessage + strings.Join(logMessages, ", "), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// clientv3New attempts to connect to local etcd and retrieve a key to make
|
|
||||||
// sure the connection works. If for any reason it fails it returns nil +
|
|
||||||
// error
|
|
||||||
func clientv3New(etcdEndpoint string) (*clientv3.Client, error) {
|
|
||||||
etcdEndpoints := []string{etcdEndpoint}
|
|
||||||
etcdCli, err := clientv3.New(clientv3.Config{
|
|
||||||
Endpoints: etcdEndpoints,
|
|
||||||
DialTimeout: 250 * time.Millisecond,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Let's do a query to determine if etcd is really, truly there
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), etcdContextTimeout)
|
|
||||||
defer cancel()
|
|
||||||
_, err = etcdCli.Get(ctx, "some-silly-key, doesn't matter if it exists")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return etcdCli, nil
|
|
||||||
}
|
|
||||||
|
@@ -5,12 +5,10 @@ import (
|
|||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
"xip/xip"
|
"xip/xip"
|
||||||
|
|
||||||
. "github.com/onsi/ginkgo/v2"
|
. "github.com/onsi/ginkgo/v2"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
clientv3 "go.etcd.io/etcd/client/v3"
|
|
||||||
"golang.org/x/net/dns/dnsmessage"
|
"golang.org/x/net/dns/dnsmessage"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -81,7 +79,7 @@ var _ = Describe("Xip", func() {
|
|||||||
|
|
||||||
Describe("NSResources()", func() {
|
Describe("NSResources()", func() {
|
||||||
When("we use the default nameservers", func() {
|
When("we use the default nameservers", func() {
|
||||||
var x, _ = xip.NewXip("localhost:2379", "file:///", []string{"ns-aws.sslip.io.", "ns-azure.sslip.io.", "ns-gce.sslip.io."}, []string{})
|
var x, _ = xip.NewXip("file:///", []string{"ns-aws.sslip.io.", "ns-azure.sslip.io.", "ns-gce.sslip.io."}, []string{})
|
||||||
It("returns the name servers", func() {
|
It("returns the name servers", func() {
|
||||||
randomDomain := random8ByteString() + ".com."
|
randomDomain := random8ByteString() + ".com."
|
||||||
ns := x.NSResources(randomDomain)
|
ns := x.NSResources(randomDomain)
|
||||||
@@ -113,7 +111,7 @@ var _ = Describe("Xip", func() {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
When("we override the default nameservers", func() {
|
When("we override the default nameservers", func() {
|
||||||
var x, _ = xip.NewXip("localhost:2379", "file:///", []string{"mickey", "minn.ie.", "goo.fy"}, []string{})
|
var x, _ = xip.NewXip("file:///", []string{"mickey", "minn.ie.", "goo.fy"}, []string{})
|
||||||
It("returns the configured servers", func() {
|
It("returns the configured servers", func() {
|
||||||
randomDomain := random8ByteString() + ".com."
|
randomDomain := random8ByteString() + ".com."
|
||||||
ns := x.NSResources(randomDomain)
|
ns := x.NSResources(randomDomain)
|
||||||
@@ -178,69 +176,6 @@ var _ = Describe("Xip", func() {
|
|||||||
Expect(len(txts)).To(Equal(0))
|
Expect(len(txts)).To(Equal(0))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
When(`the domain "k-v.io is queried"`, Ordered, func() {
|
|
||||||
txtTests := func() {
|
|
||||||
DescribeTable(`the domain "k-v.io" is queried for TXT records`,
|
|
||||||
func(fqdn string, txts []string) {
|
|
||||||
txtResources, err := x.TXTResources(fqdn, nil)
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
Expect(len(txtResources)).To(Equal(len(txts)))
|
|
||||||
for i, txtResource := range txtResources {
|
|
||||||
Expect(len(txtResource.TXT)).To(Equal(1)) // each TXT record has 1 & only 1 string
|
|
||||||
Expect(txtResource.TXT[0]).To(Equal(txts[i]))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// simple tests: get, put, delete with single label value
|
|
||||||
Entry("no arguments → empty array", "k-v.io.", []string{}),
|
|
||||||
Entry("putting a value → that value", "PUT.MyValue.my-key.k-v.io.", []string{"MyValue"}),
|
|
||||||
Entry("getting that value → that value", "my-key.k-v.io.", []string{"MyValue"}),
|
|
||||||
Entry("getting that value with an UPPERCASE key → that value", "MY-KEY.k-v.io.", []string{"MyValue"}),
|
|
||||||
Entry("explicitly getting that value → that value", "GeT.my-key.k-v.io.", []string{"MyValue"}),
|
|
||||||
Entry("deleting that value → empty array", "DelETe.my-key.k-v.io.", []string{}),
|
|
||||||
Entry("getting that deleted value → empty array", "my-key.k-v.io.", []string{}),
|
|
||||||
// errors
|
|
||||||
Entry("getting a non-existent key → empty array", "nonexistent.k-v.io.", []string{}),
|
|
||||||
Entry("putting but skipping the value → error txt", "put.my-key.k-v.io.", []string{"422: missing a value: put.value.key.k-v.io"}),
|
|
||||||
Entry("deleting a non-existent key → silently succeeds", "delete.non-existent.k-v.io.", []string{}),
|
|
||||||
Entry("using a garbage verb → error txt", "post.my-key.k-v.io.", []string{"422: valid verbs are get, put, delete"}),
|
|
||||||
// others
|
|
||||||
Entry("putting a multi-label value", "put.96.0.4664.55.chrome-version.k-v.io.", []string{"96.0.4664.55"}),
|
|
||||||
Entry("putting a super-long multi-label value to use in a DNS amplification attack gets truncated to 63 characters",
|
|
||||||
"put"+
|
|
||||||
".IReturnedAndSawUnderTheSunThatTheRaceIsNotToTheSwiftNotThe"+
|
|
||||||
".BattleToTheStrongNeitherYetBreadToTheWiseNorYetRichesToMenOf"+
|
|
||||||
".amplify.k-v.io.",
|
|
||||||
[]string{"IReturnedAndSawUnderTheSunThatTheRaceIsNotToTheSwiftNotThe.Batt"},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
|
||||||
When("there's no etcd, just local, in-memory key-value", func() {
|
|
||||||
txtTests()
|
|
||||||
})
|
|
||||||
etcdURI := "localhost:2379"
|
|
||||||
// make sure there's an etcd listening before we run our tests
|
|
||||||
conn, err := net.DialTimeout("tcp", etcdURI, 250*time.Millisecond)
|
|
||||||
if err == nil {
|
|
||||||
err = conn.Close()
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
When(`etcd is backing the kv store`, func() {
|
|
||||||
BeforeEach(func() {
|
|
||||||
etcdCli, err := clientv3.New(clientv3.Config{
|
|
||||||
Endpoints: []string{etcdURI},
|
|
||||||
DialTimeout: 250 * time.Millisecond,
|
|
||||||
})
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
x.Etcd = etcdCli
|
|
||||||
})
|
|
||||||
AfterEach(func() {
|
|
||||||
err = x.Etcd.Close()
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
})
|
|
||||||
txtTests()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("NameToA()", func() {
|
Describe("NameToA()", func() {
|
||||||
|
Reference in New Issue
Block a user