From 5a2cae508160b482510ba8999d6354a001b85fce Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Fri, 19 Nov 2021 09:16:11 +0000 Subject: [PATCH 01/19] Add new Tailscale version to integration tests --- integration_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration_test.go b/integration_test.go index a9125a0a..c2679918 100644 --- a/integration_test.go +++ b/integration_test.go @@ -28,7 +28,7 @@ import ( "tailscale.com/ipn/ipnstate" ) -var tailscaleVersions = []string{"1.16.2", "1.14.3", "1.12.3"} +var tailscaleVersions = []string{"1.18.0", "1.16.2", "1.14.3", "1.12.3"} type TestNamespace struct { count int From 349264830b6689edd7d2f008cdc03c32ed4a55e0 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Tue, 23 Nov 2021 11:27:44 +0000 Subject: [PATCH 02/19] Use .1 --- integration_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration_test.go b/integration_test.go index c2679918..d6aedf19 100644 --- a/integration_test.go +++ b/integration_test.go @@ -28,7 +28,7 @@ import ( "tailscale.com/ipn/ipnstate" ) -var tailscaleVersions = []string{"1.18.0", "1.16.2", "1.14.3", "1.12.3"} +var tailscaleVersions = []string{"1.18.1", "1.16.2", "1.14.3", "1.12.3"} type TestNamespace struct { count int From 50b47adaa3fa0db6878be66154dd82fa1aee6c9d Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Fri, 26 Nov 2021 23:27:09 +0000 Subject: [PATCH 03/19] Upgrade tailscale to 1.18 --- go.mod | 9 +++---- go.sum | 85 ++++++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 63 insertions(+), 31 deletions(-) diff --git a/go.mod b/go.mod index 65a8582e..e036effc 100644 --- a/go.mod +++ b/go.mod @@ -44,12 +44,11 @@ require ( github.com/ugorji/go v1.2.6 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/zsais/go-gin-prometheus v0.1.0 - go4.org/mem v0.0.0-20210711025021-927187094b94 // indirect - golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 - golang.org/x/net v0.0.0-20211104170005-ce137452f963 // indirect + go4.org/mem v0.0.0-20210711025021-927187094b94 + golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c - golang.org/x/sys v0.0.0-20211103235746-7861aae1554b // indirect + golang.org/x/sys v0.0.0-20211124211545-fe61309f8881 // indirect google.golang.org/genproto v0.0.0-20211104193956-4c6863e31247 google.golang.org/grpc v1.42.0 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 @@ -62,5 +61,5 @@ require ( gorm.io/driver/sqlite v1.1.5 gorm.io/gorm v1.21.15 inet.af/netaddr v0.0.0-20211027220019-c74959edd3b6 - tailscale.com v1.14.6 + tailscale.com v1.18.1 ) diff --git a/go.sum b/go.sum index a34ef217..8d4b4587 100644 --- a/go.sum +++ b/go.sum @@ -79,6 +79,7 @@ github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMx github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= +github.com/akutz/memconn v0.1.0/go.mod h1:Jo8rI7m0NieZyLI5e2CDlRdRqRRB4S7Xp77ukDjH+Fw= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -106,6 +107,16 @@ github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQ github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.38.52/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/aws/aws-sdk-go-v2 v1.9.2/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= +github.com/aws/aws-sdk-go-v2/config v1.8.3/go.mod h1:4AEiLtAb8kLs7vgw2ZV3p2VZ1+hBavOc84hqxVNpCyw= +github.com/aws/aws-sdk-go-v2/credentials v1.4.3/go.mod h1:FNNC6nQZQUuyhq5aE5c7ata8o9e4ECGmS4lAXC7o1mQ= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.6.0/go.mod h1:gqlclDEZp4aqJOancXK6TN24aKhT0W0Ae9MHk3wzTMM= +github.com/aws/aws-sdk-go-v2/internal/ini v1.2.4/go.mod h1:ZcBrrI3zBKlhGFNYWvju0I3TR93I7YIgAfy82Fh4lcQ= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.3.2/go.mod h1:72HRZDLMtmVQiLG2tLfQcaWLCssELvGl+Zf2WVxMmR8= +github.com/aws/aws-sdk-go-v2/service/ssm v1.12.0/go.mod h1:m3cb1hedrft0oYmueH0CkBgRdiwczuKRXPr0tilSpz4= +github.com/aws/aws-sdk-go-v2/service/sso v1.4.2/go.mod h1:NBvT9R1MEF+Ud6ApJKM0G+IkPchKS7p7c2YPKwHmBOk= +github.com/aws/aws-sdk-go-v2/service/sts v1.7.2/go.mod h1:8EzeIqfWt2wWT4rJVu3f21TfrhJ8AEMzVybRNSb/b4g= +github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -173,8 +184,9 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= +github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= github.com/daixiang0/gci v0.2.4/go.mod h1:+AV8KmHTGxxwp/pY84TLQfFKp2vuKXXJVzF3kD/hfR4= github.com/daixiang0/gci v0.2.7/go.mod h1:+4dZ7TISfSmqfAGv59ePaHfNzgGtIkHAhhdKggP1JAc= @@ -232,7 +244,7 @@ github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= -github.com/frankban/quicktest v1.13.0/go.mod h1:qLE0fzW0VuyUAJgPU19zByoIr0HtCHN/r/VLSOOIySU= +github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -240,11 +252,12 @@ github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gin-gonic/gin v1.7.4 h1:QmUZXrvJ9qZ3GfWvQ+2wnW/1ePrTEJqPKMYEU3lD/DM= github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= github.com/github/fakeca v0.1.0/go.mod h1:+bormgoGMMuamOscx7N91aOuUST7wdaJ2rNjeohylyo= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/gliderlabs/ssh v0.3.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/gliderlabs/ssh v0.3.3/go.mod h1:ZSS+CUoKHDrqVakTfTWUlKSr9MtMFkC4UvtQKD7O914= github.com/go-critic/go-critic v0.5.2/go.mod h1:cc0+HvdE3lFpqLecgqMaJcvWWH77sLdBp+wLGPM1Yyo= github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= @@ -260,9 +273,8 @@ github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vb github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-multierror/multierror v1.0.2/go.mod h1:U7SZR/D9jHgt2nkSj8XcbCWdmVM2igraCHQ3HC1HiKY= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= -github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.2.6-0.20210915003542-8b1f7f90f6b1/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= @@ -271,6 +283,7 @@ github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-playground/validator/v10 v10.9.0 h1:NgTtmN58D0m8+UuxtYmGztBJB7VnPgjj221I1QHci2A= github.com/go-playground/validator/v10 v10.9.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= @@ -291,7 +304,11 @@ github.com/go-toolsmith/typep v1.0.0/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2 github.com/go-toolsmith/typep v1.0.2/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU= github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.5/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= @@ -340,7 +357,6 @@ github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx 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/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4= github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6/go.mod h1:DbHgvLiFKX1Sh2T1w8Q/h4NAI8MHIpzCdnBUDTXU3I0= @@ -377,7 +393,6 @@ github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4r github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= -github.com/google/goexpect v0.0.0-20210430020637-ab937bf7fd6f/go.mod h1:n1ej5+FqyEytMt/mugVDZLIiqTMO+vsrgY+kM6ohzN0= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/goterm v0.0.0-20190703233501-fc88cf888a3f/go.mod h1:nOFQdrUlIlx6M6ODdSpBj1NVA+VgLC6kmw60mkw34H4= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= @@ -401,6 +416,7 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3 github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gookit/color v1.3.1/go.mod h1:R3ogXq2B9rTbXoSHJ1HyUVAZ3poOJHpd9nQmyGZsfvQ= @@ -417,6 +433,7 @@ github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= @@ -600,10 +617,10 @@ github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= 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/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.0/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= @@ -704,7 +721,7 @@ github.com/mdlayher/socket v0.0.0-20210307095302-262dc9984e00/go.mod h1:GAFlyu4/ github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.42/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= +github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -795,8 +812,8 @@ github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrap github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= -github.com/peterbourgon/ff/v2 v2.0.0/go.mod h1:xjwr+t+SjWm4L46fcj/D+Ap+6ME7+HqFzaP22pP5Ggk= github.com/peterbourgon/ff/v3 v3.0.0/go.mod h1:UILIFjRH5a/ar8TjXYLTkIvSvekZqPm5Eb/qbGk6CT0= +github.com/peterbourgon/ff/v3 v3.1.0/go.mod h1:XNJLY8EIl6MjMVjBS4F0+G0LYoAqs0DTa4rmHHukKDE= github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw= github.com/philip-bui/grpc-zerolog v1.0.1 h1:EMacvLRUd2O1K0eWod27ZP5CY1iTNkhBDLSN+Q4JEvA= github.com/philip-bui/grpc-zerolog v1.0.1/go.mod h1:qXbiq/2X4ZUMMshsqlWyTHOcw7ns+GZmlqZZN05ZHcQ= @@ -811,7 +828,7 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pkg/profile v1.5.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= -github.com/pkg/sftp v1.13.0/go.mod h1:41g+FIPlQUTDCveupEmEA65IoiQFrtgCeDopC4ajGIM= +github.com/pkg/sftp v1.13.4/go.mod h1:LzqnAvaD5TWeNBsZpfKxSYn1MbjWwOsCIAFFJbpIsK8= 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/polyfloyd/go-errorlint v0.0.0-20201006195004-351e25ade6e3/go.mod h1:wi9BfjxjF/bwiZ701TzmfKu6UKC357IOAtNr0Td0Lvw= @@ -907,6 +924,7 @@ github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic github.com/sirupsen/logrus v1.8.0/go.mod h1:4GuYW9TZmE769R5STWrRakJc4UqQ3+QQ95fyz7ENv1A= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= @@ -966,10 +984,12 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69 github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tailscale/certstore v0.0.0-20210528134328-066c94b793d3/go.mod h1:2P+hpOwd53e7JMX/L4f3VXkv1G+33ES6IWZSrkIeWNs= github.com/tailscale/depaware v0.0.0-20201214215404-77d1e9757027/go.mod h1:p9lPsd+cx33L3H9nNoecRRxPssFKUwwI50I3pZ0yT+8= +github.com/tailscale/goexpect v0.0.0-20210902213824-6e8c725cea41/go.mod h1:/roCdA6gg6lQyw/Oz6gIIGu3ggJKYhF+WC/AQReE5XQ= github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05/go.mod h1:PdCqy9JzfWMJf1H5UJW2ip33/d4YkoKN0r67yKH1mG8= github.com/tailscale/hujson v0.0.0-20200924210142-dde312d0d6a2/go.mod h1:STqf+YV0ADdzk4ejtXFsGqDpATP9JoL0OB+hiFQbkdE= github.com/tailscale/hujson v0.0.0-20210923003652-c3758b31534b h1:bvys7zUACfrQZBUAinXREfu9jUgq6KcNQcQnUkzl3yc= github.com/tailscale/hujson v0.0.0-20210923003652-c3758b31534b/go.mod h1:iTDXJsA6A2wNNjurgic2rk+is6uzU4U2NLm4T+edr6M= +github.com/tailscale/netlink v1.1.1-0.20211101221916-cabfb018fe85/go.mod h1:NzVQi3Mleb+qzq8VmcWpSkcSYxXIg0DkI6XDzpVkhJ0= github.com/tcnksm/go-httpstat v0.2.0/go.mod h1:s3JVJFtQxtBEBC9dwcdTTXS9xFnM3SXAZwPG41aurT8= github.com/tcnksm/go-latest v0.0.0-20170313132115-e3007ae9052e h1:IWllFTiDjjLIf2oeKxpIUmtiDV5sn71VgeQgg6vcE7k= github.com/tcnksm/go-latest v0.0.0-20170313132115-e3007ae9052e/go.mod h1:d7u6HkTYKSv5m6MCKkOQlHwaShTMl3HjqSGW3XtVhXM= @@ -995,6 +1015,7 @@ github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLY github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ= github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw= github.com/ulikunitz/xz v0.5.7/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ultraware/funlen v0.0.3/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= @@ -1005,7 +1026,9 @@ github.com/valyala/fasthttp v1.16.0/go.mod h1:YOKImeEosDdBPnxc0gy7INqi3m1zK6A+xl github.com/valyala/quicktemplate v1.6.3/go.mod h1:fwPzK2fHuYEODzJ9pkw0ipCPNHZ2tD5KW4lOuSdPKzY= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netlink v1.1.1-0.20211101163509-b10eb8fe5cf6/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -1093,14 +1116,16 @@ golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 h1:/pEO3GD/ABYAjuakUS6xSEmmlyVS4kxBNkeA9tLJiTI= +golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1194,10 +1219,12 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v 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-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211104170005-ce137452f963 h1:8gJUadZl+kWvZBqG/LautX0X6qe5qTC2VI/3V3NBRAY= -golang.org/x/net v0.0.0-20211104170005-ce137452f963/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211101193420-4a448f8816b3/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211111083644-e5c967477495/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1271,6 +1298,7 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1284,6 +1312,7 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1313,6 +1342,7 @@ golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/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-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1322,9 +1352,11 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211103235746-7861aae1554b h1:1VkfZQv42XQlA/jchYumAnv1UPo6RgF9rJFkTgZIxO4= +golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881 h1:TyHqChC80pFkXWraUUf6RuB5IqFdQieMLwwCJokV2pc= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1339,7 +1371,6 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7-0.20210524175448-3115f89c4b99/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1448,8 +1479,10 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.zx2c4.com/wireguard v0.0.0-20210624150102-15b24b6179e0/go.mod h1:laHzsbfMhGSobUmruXWAyMKKHSqvIcrqZJMyHD+/3O8= -golang.zx2c4.com/wireguard/windows v0.3.16/go.mod h1:f80rkFY2CKQklps1GHE15k/M4Tq78aofbr1iQM5MTVY= +golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= +golang.zx2c4.com/wireguard v0.0.0-20210905140043-2ef39d47540c/go.mod h1:laHzsbfMhGSobUmruXWAyMKKHSqvIcrqZJMyHD+/3O8= +golang.zx2c4.com/wireguard v0.0.0-20211116201604-de7c702ace45/go.mod h1:evxZIqfCetExY5piKXGAxJYwvXWkps9zTCkWpkoGFxw= +golang.zx2c4.com/wireguard/windows v0.4.10/go.mod h1:v7w/8FC48tTBm1IzScDVPEEb0/GjLta+T0ybpP9UWRg= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -1649,13 +1682,12 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.6/go.mod h1:pyyisuGw24ruLjrr1ddx39WE0y9OooInRzEYLhQB2YY= -honnef.co/go/tools v0.1.4/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= +honnef.co/go/tools v0.2.1/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY= howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= inet.af/netaddr v0.0.0-20210515010201-ad03edc7c841/go.mod h1:z0nx+Dh+7N7CC8V5ayHtHGpZpxLQZZxkIaaz6HN65Ls= -inet.af/netaddr v0.0.0-20210721214506-ce7a8ad02cc1/go.mod h1:z0nx+Dh+7N7CC8V5ayHtHGpZpxLQZZxkIaaz6HN65Ls= inet.af/netaddr v0.0.0-20211027220019-c74959edd3b6 h1:acCzuUSQ79tGsM/O50VRFySfMm19IoMKL+sZztZkCxw= inet.af/netaddr v0.0.0-20211027220019-c74959edd3b6/go.mod h1:y3MGhcFMlh0KZPMuXXow8mpjxxAk3yoDNsp4cQz54i8= -inet.af/netstack v0.0.0-20210622165351-29b14ebc044e/go.mod h1:fG3G1dekmK8oDX3iVzt8c0zICLMLSN8SjdxbXVt0WjU= +inet.af/netstack v0.0.0-20211101182044-1c1bcf452982/go.mod h1:fG3G1dekmK8oDX3iVzt8c0zICLMLSN8SjdxbXVt0WjU= inet.af/peercred v0.0.0-20210318190834-4259e17bb763/go.mod h1:FjawnflS/udxX+SvpsMgZfdqx2aykOlkISeAsADi5IU= inet.af/wf v0.0.0-20210516214145-a5343001b756/go.mod h1:ViGMZRA6+RA318D7GCncrjv5gHUrPYrNDejjU12tikA= mvdan.cc/gofumpt v0.0.0-20200802201014-ab5a8192947d/go.mod h1:bzrjFmaD6+xqohD3KYP0H2FEuxknnBmyyOxdhLdaIws= @@ -1663,11 +1695,12 @@ mvdan.cc/gofumpt v0.0.0-20201129102820-5c11c50e9475/go.mod h1:E4LOcu9JQEtnYXtB1Y mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= mvdan.cc/unparam v0.0.0-20200501210554-b37ab49443f7/go.mod h1:HGC5lll35J70Y5v7vCGb9oLhHoScFwkHDJm/05RdSTc= +nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= software.sslmate.com/src/go-pkcs12 v0.0.0-20180114231543-2291e8f0f237/go.mod h1:/xvNRWUqm0+/ZMiF4EX00vrSCMsE4/NHb+Pt3freEeQ= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= -tailscale.com v1.14.6 h1:xhpDI3hks1lz80Tq7gxybdM0vt8NSuWEFpQeBqBZJhw= -tailscale.com v1.14.6/go.mod h1:3F94TfP5nSn9M40v7jEQB+QI3m/4trasLDF3Dcljs8o= +tailscale.com v1.18.1 h1:3hkMsdpREdz2w0O3YcmOgJkl95ChTT4Dje7wq8prD/E= +tailscale.com v1.18.1/go.mod h1:XzG4o2vtYFkVvmJWPaTGSaOzqlKSRx2WU+aJbrxaVE0= From c63c259d319fe3b03535cf4989e9c9039ec87134 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Fri, 26 Nov 2021 23:28:06 +0000 Subject: [PATCH 04/19] Switch wgkey for types/key We dont seem to need the wireguard key anymore, we generate a key on startup based on the new library and the users fetch it from /key. Clean up app.go and update docs --- app.go | 21 ++++++--------------- config-example.yaml | 3 --- docs/Configuration.md | 6 ------ docs/DNS.md | 1 - k8s/postgres/deployment.yaml | 2 -- k8s/sqlite/statefulset.yaml | 2 -- 6 files changed, 6 insertions(+), 29 deletions(-) diff --git a/app.go b/app.go index 0d3332dd..874bedf2 100644 --- a/app.go +++ b/app.go @@ -43,7 +43,7 @@ import ( "inet.af/netaddr" "tailscale.com/tailcfg" "tailscale.com/types/dnstype" - "tailscale.com/types/wgkey" + "tailscale.com/types/key" ) const ( @@ -66,7 +66,6 @@ const ( type Config struct { ServerURL string Addr string - PrivateKeyPath string EphemeralNodeInactivityTimeout time.Duration IPPrefix netaddr.IPPrefix BaseDomain string @@ -129,8 +128,8 @@ type Headscale struct { dbString string dbType string dbDebug bool - publicKey *wgkey.Key - privateKey *wgkey.Private + publicKey *key.MachinePublic + privateKey *key.MachinePrivate DERPMap *tailcfg.DERPMap @@ -148,15 +147,7 @@ type Headscale struct { // NewHeadscale returns the Headscale app. func NewHeadscale(cfg Config) (*Headscale, error) { - content, err := os.ReadFile(cfg.PrivateKeyPath) - if err != nil { - return nil, err - } - - privKey, err := wgkey.ParsePrivate(string(content)) - if err != nil { - return nil, err - } + privKey := key.NewMachine() pubKey := privKey.Public() var dbString string @@ -185,13 +176,13 @@ func NewHeadscale(cfg Config) (*Headscale, error) { cfg: cfg, dbType: cfg.DBtype, dbString: dbString, - privateKey: privKey, + privateKey: &privKey, publicKey: &pubKey, aclRules: tailcfg.FilterAllowAll, // default allowall requestedExpiryCache: requestedExpiryCache, } - err = app.initDB() + err := app.initDB() if err != nil { return nil, err } diff --git a/config-example.yaml b/config-example.yaml index 60369306..dc4bd579 100644 --- a/config-example.yaml +++ b/config-example.yaml @@ -6,9 +6,6 @@ server_url: http://127.0.0.1:8080 # Address to listen to / bind to on the server listen_addr: 0.0.0.0:8080 -# Path to WireGuard private key file -private_key_path: private.key - derp: # List of externally available DERP maps encoded in JSON urls: diff --git a/docs/Configuration.md b/docs/Configuration.md index fa766428..f5e8c3f4 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -21,12 +21,6 @@ log_level: debug `log_level` can be used to set the Log level for Headscale, it defaults to `debug`, and the available levels are: `trace`, `debug`, `info`, `warn` and `error`. -```yaml -private_key_path: private.key -``` - -`private_key_path` is the path to the Wireguard private key. If the path is relative, it will be interpreted as relative to the directory the configuration file was read from. - ```yaml derp_map_path: derp.yaml ``` diff --git a/docs/DNS.md b/docs/DNS.md index e51feaf6..53106526 100644 --- a/docs/DNS.md +++ b/docs/DNS.md @@ -15,7 +15,6 @@ The setup is done via the `config.yaml` file, under the `dns_config` key. ```yaml server_url: http://127.0.0.1:8001 listen_addr: 0.0.0.0:8001 -private_key_path: private.key dns_config: nameservers: - 1.1.1.1 diff --git a/k8s/postgres/deployment.yaml b/k8s/postgres/deployment.yaml index 661d87ed..75e64446 100644 --- a/k8s/postgres/deployment.yaml +++ b/k8s/postgres/deployment.yaml @@ -25,8 +25,6 @@ spec: configMapKeyRef: name: headscale-config key: listen_addr - - name: PRIVATE_KEY_PATH - value: /vol/secret/private-key - name: DERP_MAP_PATH value: /vol/config/derp.yaml - name: EPHEMERAL_NODE_INACTIVITY_TIMEOUT diff --git a/k8s/sqlite/statefulset.yaml b/k8s/sqlite/statefulset.yaml index 71077dad..050bf766 100644 --- a/k8s/sqlite/statefulset.yaml +++ b/k8s/sqlite/statefulset.yaml @@ -26,8 +26,6 @@ spec: configMapKeyRef: name: headscale-config key: listen_addr - - name: PRIVATE_KEY_PATH - value: /vol/secret/private-key - name: DERP_MAP_PATH value: /vol/config/derp.yaml - name: EPHEMERAL_NODE_INACTIVITY_TIMEOUT From 07418140a2b5bebafc20a87f5a87c9f2b619b427 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Fri, 26 Nov 2021 23:29:41 +0000 Subject: [PATCH 05/19] Remove config loading of private key path --- cmd/headscale/cli/utils.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/cmd/headscale/cli/utils.go b/cmd/headscale/cli/utils.go index 98b53619..d47a5ca9 100644 --- a/cmd/headscale/cli/utils.go +++ b/cmd/headscale/cli/utils.go @@ -222,11 +222,10 @@ func getHeadscaleConfig() headscale.Config { derpConfig := GetDERPConfig() return headscale.Config{ - ServerURL: viper.GetString("server_url"), - Addr: viper.GetString("listen_addr"), - PrivateKeyPath: absPath(viper.GetString("private_key_path")), - IPPrefix: netaddr.MustParseIPPrefix(viper.GetString("ip_prefix")), - BaseDomain: baseDomain, + ServerURL: viper.GetString("server_url"), + Addr: viper.GetString("listen_addr"), + IPPrefix: netaddr.MustParseIPPrefix(viper.GetString("ip_prefix")), + BaseDomain: baseDomain, DERP: derpConfig, From cfd53bc4aafaeed912330db7c2698ada135afa4e Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Fri, 26 Nov 2021 23:30:42 +0000 Subject: [PATCH 06/19] Factor wgkey to types/key This commit converts all the uses of wgkey to the new key interfaces. It now has specific machine, node and discovery keys and we now should use them correctly. Please note the new logic which strips a key prefix (in utils.go) that is now standard inside tailscale. In theory we could put it in the database, but to preserve backwards compatibility and not spend a lot of resources on accounting for both, we just strip them. --- api.go | 92 +++++++++++++-------------- cmd/headscale/cli/nodes.go | 7 +-- machine.go | 66 ++++++++++++-------- oidc.go | 16 ++++- oidc_test.go | 6 +- poll.go | 17 ++--- utils.go | 123 +++++++++++++++++++++---------------- 7 files changed, 184 insertions(+), 143 deletions(-) diff --git a/api.go b/api.go index 1a51fdfe..84b79a58 100644 --- a/api.go +++ b/api.go @@ -13,9 +13,10 @@ import ( "github.com/gin-gonic/gin" "github.com/klauspost/compress/zstd" "github.com/rs/zerolog/log" + "go4.org/mem" "gorm.io/gorm" "tailscale.com/tailcfg" - "tailscale.com/types/wgkey" + "tailscale.com/types/key" ) const ( @@ -34,7 +35,7 @@ func (h *Headscale) KeyHandler(ctx *gin.Context) { ctx.Data( http.StatusOK, "text/plain; charset=utf-8", - []byte(h.publicKey.HexString()), + []byte(MachinePublicKeyStripPrefix(*h.publicKey)), ) } @@ -73,10 +74,10 @@ func (h *Headscale) RegisterWebAPI(ctx *gin.Context) { func (h *Headscale) RegistrationHandler(ctx *gin.Context) { body, _ := io.ReadAll(ctx.Request.Body) machineKeyStr := ctx.Param("id") - machineKey, err := wgkey.ParseHex(machineKeyStr) + machineKey, err := key.ParseMachinePublicUntyped(mem.S(machineKeyStr)) if err != nil { log.Error(). - Str("handler", "Registration"). + Caller(). Err(err). Msg("Cannot parse machine key") machineRegistrations.WithLabelValues("unknown", "web", "error", "unknown").Inc() @@ -88,7 +89,7 @@ func (h *Headscale) RegistrationHandler(ctx *gin.Context) { err = decode(body, &req, &machineKey, h.privateKey) if err != nil { log.Error(). - Str("handler", "Registration"). + Caller(). Err(err). Msg("Cannot decode message") machineRegistrations.WithLabelValues("unknown", "web", "error", "unknown").Inc() @@ -98,17 +99,17 @@ func (h *Headscale) RegistrationHandler(ctx *gin.Context) { } now := time.Now().UTC() - machine, err := h.GetMachineByMachineKey(machineKey.HexString()) + machine, err := h.GetMachineByMachineKey(machineKey) if errors.Is(err, gorm.ErrRecordNotFound) { log.Info().Str("machine", req.Hostinfo.Hostname).Msg("New machine") newMachine := Machine{ Expiry: &time.Time{}, - MachineKey: machineKey.HexString(), + MachineKey: MachinePublicKeyStripPrefix(machineKey), Name: req.Hostinfo.Hostname, } if err := h.db.Create(&newMachine).Error; err != nil { log.Error(). - Str("handler", "Registration"). + Caller(). Err(err). Msg("Could not create row") machineRegistrations.WithLabelValues("unknown", "web", "error", machine.Namespace.Name). @@ -125,7 +126,7 @@ func (h *Headscale) RegistrationHandler(ctx *gin.Context) { // - Trying to log out (sending a expiry in the past) // - A valid, registered machine, looking for the node map // - Expired machine wanting to reauthenticate - if machine.NodeKey == wgkey.Key(req.NodeKey).HexString() { + if machine.NodeKey == req.NodeKey.String() { // The client sends an Expiry in the past if the client is requesting to expire the key (aka logout) // https://github.com/tailscale/tailscale/blob/main/tailcfg/tailcfg.go#L648 if !req.Expiry.IsZero() && req.Expiry.UTC().Before(now) { @@ -144,7 +145,7 @@ func (h *Headscale) RegistrationHandler(ctx *gin.Context) { } // The NodeKey we have matches OldNodeKey, which means this is a refresh after a key expiration - if machine.NodeKey == wgkey.Key(req.OldNodeKey).HexString() && + if machine.NodeKey == req.OldNodeKey.String() && !machine.isExpired() { h.handleMachineRefreshKey(ctx, machineKey, req, *machine) @@ -168,7 +169,7 @@ func (h *Headscale) RegistrationHandler(ctx *gin.Context) { } func (h *Headscale) getMapResponse( - machineKey wgkey.Key, + machineKey key.MachinePublic, req tailcfg.MapRequest, machine *Machine, ) ([]byte, error) { @@ -179,6 +180,7 @@ func (h *Headscale) getMapResponse( node, err := machine.toNode(h.cfg.BaseDomain, h.cfg.DNSConfig, true) if err != nil { log.Error(). + Caller(). Str("func", "getMapResponse"). Err(err). Msg("Cannot convert to node") @@ -189,6 +191,7 @@ func (h *Headscale) getMapResponse( peers, err := h.getValidPeers(machine) if err != nil { log.Error(). + Caller(). Str("func", "getMapResponse"). Err(err). Msg("Cannot fetch peers") @@ -201,6 +204,7 @@ func (h *Headscale) getMapResponse( nodePeers, err := peers.toNodes(h.cfg.BaseDomain, h.cfg.DNSConfig, true) if err != nil { log.Error(). + Caller(). Str("func", "getMapResponse"). Err(err). Msg("Failed to convert peers to Tailscale nodes") @@ -238,10 +242,7 @@ func (h *Headscale) getMapResponse( encoder, _ := zstd.NewWriter(nil) srcCompressed := encoder.EncodeAll(src, nil) - respBody, err = encodeMsg(srcCompressed, &machineKey, h.privateKey) - if err != nil { - return nil, err - } + respBody = h.privateKey.SealTo(machineKey, srcCompressed) } else { respBody, err = encode(resp, &machineKey, h.privateKey) if err != nil { @@ -257,7 +258,7 @@ func (h *Headscale) getMapResponse( } func (h *Headscale) getMapKeepAliveResponse( - machineKey wgkey.Key, + machineKey key.MachinePublic, mapRequest tailcfg.MapRequest, ) ([]byte, error) { mapResponse := tailcfg.MapResponse{ @@ -269,10 +270,7 @@ func (h *Headscale) getMapKeepAliveResponse( src, _ := json.Marshal(mapResponse) encoder, _ := zstd.NewWriter(nil) srcCompressed := encoder.EncodeAll(src, nil) - respBody, err = encodeMsg(srcCompressed, &machineKey, h.privateKey) - if err != nil { - return nil, err - } + respBody = h.privateKey.SealTo(machineKey, srcCompressed) } else { respBody, err = encode(mapResponse, &machineKey, h.privateKey) if err != nil { @@ -288,13 +286,12 @@ func (h *Headscale) getMapKeepAliveResponse( func (h *Headscale) handleMachineLogOut( ctx *gin.Context, - machineKey wgkey.Key, + machineKey key.MachinePublic, machine Machine, ) { resp := tailcfg.RegisterResponse{} log.Info(). - Str("handler", "Registration"). Str("machine", machine.Name). Msg("Client requested logout") @@ -306,7 +303,7 @@ func (h *Headscale) handleMachineLogOut( respBody, err := encode(resp, &machineKey, h.privateKey) if err != nil { log.Error(). - Str("handler", "Registration"). + Caller(). Err(err). Msg("Cannot encode message") ctx.String(http.StatusInternalServerError, "") @@ -318,14 +315,13 @@ func (h *Headscale) handleMachineLogOut( func (h *Headscale) handleMachineValidRegistration( ctx *gin.Context, - machineKey wgkey.Key, + machineKey key.MachinePublic, machine Machine, ) { resp := tailcfg.RegisterResponse{} // The machine registration is valid, respond with redirect to /map log.Debug(). - Str("handler", "Registration"). Str("machine", machine.Name). Msg("Client is registered and we have the current NodeKey. All clear to /map") @@ -337,7 +333,7 @@ func (h *Headscale) handleMachineValidRegistration( respBody, err := encode(resp, &machineKey, h.privateKey) if err != nil { log.Error(). - Str("handler", "Registration"). + Caller(). Err(err). Msg("Cannot encode message") machineRegistrations.WithLabelValues("update", "web", "error", machine.Namespace.Name). @@ -353,7 +349,7 @@ func (h *Headscale) handleMachineValidRegistration( func (h *Headscale) handleMachineExpired( ctx *gin.Context, - machineKey wgkey.Key, + machineKey key.MachinePublic, registerRequest tailcfg.RegisterRequest, machine Machine, ) { @@ -361,7 +357,6 @@ func (h *Headscale) handleMachineExpired( // The client has registered before, but has expired log.Debug(). - Str("handler", "Registration"). Str("machine", machine.Name). Msg("Machine registration has expired. Sending a authurl to register") @@ -373,16 +368,16 @@ func (h *Headscale) handleMachineExpired( if h.cfg.OIDC.Issuer != "" { resp.AuthURL = fmt.Sprintf("%s/oidc/register/%s", - strings.TrimSuffix(h.cfg.ServerURL, "/"), machineKey.HexString()) + strings.TrimSuffix(h.cfg.ServerURL, "/"), machineKey.String()) } else { resp.AuthURL = fmt.Sprintf("%s/register?key=%s", - strings.TrimSuffix(h.cfg.ServerURL, "/"), machineKey.HexString()) + strings.TrimSuffix(h.cfg.ServerURL, "/"), machineKey.String()) } respBody, err := encode(resp, &machineKey, h.privateKey) if err != nil { log.Error(). - Str("handler", "Registration"). + Caller(). Err(err). Msg("Cannot encode message") machineRegistrations.WithLabelValues("reauth", "web", "error", machine.Namespace.Name). @@ -398,17 +393,16 @@ func (h *Headscale) handleMachineExpired( func (h *Headscale) handleMachineRefreshKey( ctx *gin.Context, - machineKey wgkey.Key, + machineKey key.MachinePublic, registerRequest tailcfg.RegisterRequest, machine Machine, ) { resp := tailcfg.RegisterResponse{} log.Debug(). - Str("handler", "Registration"). Str("machine", machine.Name). Msg("We have the OldNodeKey in the database. This is a key refresh") - machine.NodeKey = wgkey.Key(registerRequest.NodeKey).HexString() + machine.NodeKey = NodePublicKeyStripPrefix(registerRequest.NodeKey) h.db.Save(&machine) resp.AuthURL = "" @@ -416,7 +410,7 @@ func (h *Headscale) handleMachineRefreshKey( respBody, err := encode(resp, &machineKey, h.privateKey) if err != nil { log.Error(). - Str("handler", "Registration"). + Caller(). Err(err). Msg("Cannot encode message") ctx.String(http.StatusInternalServerError, "Extremely sad!") @@ -428,7 +422,7 @@ func (h *Headscale) handleMachineRefreshKey( func (h *Headscale) handleMachineRegistrationNew( ctx *gin.Context, - machineKey wgkey.Key, + machineKey key.MachinePublic, registerRequest tailcfg.RegisterRequest, machine Machine, ) { @@ -436,18 +430,17 @@ func (h *Headscale) handleMachineRegistrationNew( // The machine registration is new, redirect the client to the registration URL log.Debug(). - Str("handler", "Registration"). Str("machine", machine.Name). Msg("The node is sending us a new NodeKey, sending auth url") if h.cfg.OIDC.Issuer != "" { resp.AuthURL = fmt.Sprintf( "%s/oidc/register/%s", strings.TrimSuffix(h.cfg.ServerURL, "/"), - machineKey.HexString(), + machineKey.String(), ) } else { resp.AuthURL = fmt.Sprintf("%s/register?key=%s", - strings.TrimSuffix(h.cfg.ServerURL, "/"), machineKey.HexString()) + strings.TrimSuffix(h.cfg.ServerURL, "/"), MachinePublicKeyStripPrefix(machineKey)) } if !registerRequest.Expiry.IsZero() { @@ -457,19 +450,21 @@ func (h *Headscale) handleMachineRegistrationNew( Time("expiry", registerRequest.Expiry). Msg("Non-zero expiry time requested, adding to cache") h.requestedExpiryCache.Set( - machineKey.HexString(), + machineKey.String(), registerRequest.Expiry, requestedExpiryCacheExpiration, ) } - machine.NodeKey = wgkey.Key(registerRequest.NodeKey).HexString() // save the NodeKey + machine.NodeKey = NodePublicKeyStripPrefix(registerRequest.NodeKey) + + // save the NodeKey h.db.Save(&machine) respBody, err := encode(resp, &machineKey, h.privateKey) if err != nil { log.Error(). - Str("handler", "Registration"). + Caller(). Err(err). Msg("Cannot encode message") ctx.String(http.StatusInternalServerError, "") @@ -481,7 +476,7 @@ func (h *Headscale) handleMachineRegistrationNew( func (h *Headscale) handleAuthKey( ctx *gin.Context, - machineKey wgkey.Key, + machineKey key.MachinePublic, registerRequest tailcfg.RegisterRequest, machine Machine, ) { @@ -493,6 +488,7 @@ func (h *Headscale) handleAuthKey( pak, err := h.checkKeyValidity(registerRequest.Auth.AuthKey) if err != nil { log.Error(). + Caller(). Str("func", "handleAuthKey"). Str("machine", machine.Name). Err(err). @@ -501,6 +497,7 @@ func (h *Headscale) handleAuthKey( respBody, err := encode(resp, &machineKey, h.privateKey) if err != nil { log.Error(). + Caller(). Str("func", "handleAuthKey"). Str("machine", machine.Name). Err(err). @@ -513,6 +510,7 @@ func (h *Headscale) handleAuthKey( } ctx.Data(http.StatusUnauthorized, "application/json; charset=utf-8", respBody) log.Error(). + Caller(). Str("func", "handleAuthKey"). Str("machine", machine.Name). Msg("Failed authentication via AuthKey") @@ -537,6 +535,7 @@ func (h *Headscale) handleAuthKey( ip, err := h.getAvailableIP() if err != nil { log.Error(). + Caller(). Str("func", "handleAuthKey"). Str("machine", machine.Name). Msg("Failed to find an available IP") @@ -555,9 +554,9 @@ func (h *Headscale) handleAuthKey( machine.AuthKeyID = uint(pak.ID) machine.IPAddress = ip.String() machine.NamespaceID = pak.NamespaceID - machine.NodeKey = wgkey.Key(registerRequest.NodeKey). - HexString() - // we update it just in case + + machine.NodeKey = NodePublicKeyStripPrefix(registerRequest.NodeKey) + // we update it just in case machine.Registered = true machine.RegisterMethod = RegisterMethodAuthKey h.db.Save(&machine) @@ -571,6 +570,7 @@ func (h *Headscale) handleAuthKey( respBody, err := encode(resp, &machineKey, h.privateKey) if err != nil { log.Error(). + Caller(). Str("func", "handleAuthKey"). Str("machine", machine.Name). Err(err). diff --git a/cmd/headscale/cli/nodes.go b/cmd/headscale/cli/nodes.go index f5117d95..2c7fa9b5 100644 --- a/cmd/headscale/cli/nodes.go +++ b/cmd/headscale/cli/nodes.go @@ -11,9 +11,9 @@ import ( v1 "github.com/juanfont/headscale/gen/go/headscale/v1" "github.com/pterm/pterm" "github.com/spf13/cobra" + "go4.org/mem" "google.golang.org/grpc/status" - "tailscale.com/tailcfg" - "tailscale.com/types/wgkey" + "tailscale.com/types/key" ) func init() { @@ -486,11 +486,10 @@ func nodesToPtables( expiry = machine.Expiry.AsTime() } - nKey, err := wgkey.ParseHex(machine.NodeKey) + nodeKey, err := key.ParseNodePublicUntyped(mem.S(machine.NodeKey)) if err != nil { return nil, err } - nodeKey := tailcfg.NodeKey(nKey) var online string if lastSeen.After( diff --git a/machine.go b/machine.go index 306b3a47..26c59c65 100644 --- a/machine.go +++ b/machine.go @@ -12,12 +12,12 @@ import ( "github.com/fatih/set" v1 "github.com/juanfont/headscale/gen/go/headscale/v1" "github.com/rs/zerolog/log" + "go4.org/mem" "google.golang.org/protobuf/types/known/timestamppb" "gorm.io/datatypes" - "gorm.io/gorm" "inet.af/netaddr" "tailscale.com/tailcfg" - "tailscale.com/types/wgkey" + "tailscale.com/types/key" ) const ( @@ -260,9 +260,11 @@ func (h *Headscale) GetMachineByID(id uint64) (*Machine, error) { } // GetMachineByMachineKey finds a Machine by ID and returns the Machine struct. -func (h *Headscale) GetMachineByMachineKey(machineKey string) (*Machine, error) { +func (h *Headscale) GetMachineByMachineKey( + machineKey key.MachinePublic, +) (*Machine, error) { m := Machine{} - if result := h.db.Preload("Namespace").First(&m, "machine_key = ?", machineKey); result.Error != nil { + if result := h.db.Preload("Namespace").First(&m, "machine_key = ?", MachinePublicKeyStripPrefix(machineKey)); result.Error != nil { return nil, result.Error } @@ -437,25 +439,31 @@ func (machine Machine) toNode( dnsConfig *tailcfg.DNSConfig, includeRoutes bool, ) (*tailcfg.Node, error) { - nodeKey, err := wgkey.ParseHex(machine.NodeKey) + nodeKey, err := key.ParseNodePublicUntyped(mem.S(machine.NodeKey)) if err != nil { - return nil, err + log.Trace(). + Caller(). + Str("node_key", machine.NodeKey). + Msgf("Failed to parse node public key from hex") + + return nil, fmt.Errorf("failed to parse node public key: %w", err) } - machineKey, err := wgkey.ParseHex(machine.MachineKey) + machineKey, err := key.ParseMachinePublicUntyped(mem.S(machine.MachineKey)) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to parse machine public key: %w", err) } - var discoKey tailcfg.DiscoKey + var discoKey key.DiscoPublic if machine.DiscoKey != "" { - dKey, err := wgkey.ParseHex(machine.DiscoKey) + dKey := key.DiscoPublic{} + err := dKey.UnmarshalText([]byte(discoPublicHexPrefix + machine.DiscoKey)) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to parse disco public key: %w", err) } - discoKey = tailcfg.DiscoKey(dKey) + discoKey = key.DiscoPublic(dKey) } else { - discoKey = tailcfg.DiscoKey{} + discoKey = key.DiscoPublic{} } addrs := []netaddr.IPPrefix{} @@ -555,9 +563,9 @@ func (machine Machine) toNode( ), // in headscale, unlike tailcontrol server, IDs are permanent Name: hostname, User: tailcfg.UserID(machine.NamespaceID), - Key: tailcfg.NodeKey(nodeKey), + Key: nodeKey, KeyExpiry: keyExpiry, - Machine: tailcfg.MachineKey(machineKey), + Machine: machineKey, DiscoKey: discoKey, Addresses: addrs, AllowedIPs: allowedIPs, @@ -618,31 +626,35 @@ func (machine *Machine) toProto() *v1.Machine { // RegisterMachine is executed from the CLI to register a new Machine using its MachineKey. func (h *Headscale) RegisterMachine( - key string, + machineKeyStr string, namespaceName string, ) (*Machine, error) { namespace, err := h.GetNamespace(namespaceName) if err != nil { return nil, err } - machineKey, err := wgkey.ParseHex(key) + + machineKey, err := key.ParseMachinePublicUntyped(mem.S(machineKeyStr)) if err != nil { return nil, err } - machine := Machine{} - if result := h.db.First(&machine, "machine_key = ?", machineKey.HexString()); errors.Is( - result.Error, - gorm.ErrRecordNotFound, - ) { - return nil, errMachineNotFound + log.Trace(). + Caller(). + Str("machine_key_str", machineKeyStr). + Str("machine_key", machineKey.String()). + Msg("Registering machine") + + machine, err := h.GetMachineByMachineKey(machineKey) + if err != nil { + return nil, err } // TODO(kradalby): Currently, if it fails to find a requested expiry, non will be set // This means that if a user is to slow with register a machine, it will possibly not // have the correct expiry. requestedTime := time.Time{} - if requestedTimeIf, found := h.requestedExpiryCache.Get(machineKey.HexString()); found { + if requestedTimeIf, found := h.requestedExpiryCache.Get(machineKey.String()); found { log.Trace(). Caller(). Str("machine", machine.Name). @@ -658,9 +670,9 @@ func (h *Headscale) RegisterMachine( Str("machine", machine.Name). Msg("machine already registered, reauthenticating") - h.RefreshMachine(&machine, requestedTime) + h.RefreshMachine(machine, requestedTime) - return &machine, nil + return machine, nil } log.Trace(). @@ -709,7 +721,7 @@ func (h *Headscale) RegisterMachine( Str("ip", ip.String()). Msg("Machine registered with the database") - return &machine, nil + return machine, nil } func (machine *Machine) GetAdvertisedRoutes() ([]netaddr.IPPrefix, error) { diff --git a/oidc.go b/oidc.go index 9b0a3087..02666d89 100644 --- a/oidc.go +++ b/oidc.go @@ -15,8 +15,10 @@ import ( "github.com/gin-gonic/gin" "github.com/patrickmn/go-cache" "github.com/rs/zerolog/log" + "go4.org/mem" "golang.org/x/oauth2" "gorm.io/gorm" + "tailscale.com/types/key" ) const ( @@ -187,7 +189,17 @@ func (h *Headscale) OIDCCallback(ctx *gin.Context) { return } - machineKey, machineKeyOK := machineKeyIf.(string) + + machineKeyStr, machineKeyOK := machineKeyIf.(string) + + machineKey, err := key.ParseMachinePublicUntyped(mem.S(machineKeyStr)) + if err != nil { + log.Error(). + Msg("could not parse machine public key") + ctx.String(http.StatusBadRequest, "could not parse public key") + + return + } if !machineKeyOK { log.Error().Msg("could not get machine key from cache") @@ -201,7 +213,7 @@ func (h *Headscale) OIDCCallback(ctx *gin.Context) { // TODO(kradalby): Currently, if it fails to find a requested expiry, non will be set requestedTime := time.Time{} - if requestedTimeIf, found := h.requestedExpiryCache.Get(machineKey); found { + if requestedTimeIf, found := h.requestedExpiryCache.Get(machineKey.String()); found { if reqTime, ok := requestedTimeIf.(time.Time); ok { requestedTime = reqTime } diff --git a/oidc_test.go b/oidc_test.go index 21a4357d..db581b99 100644 --- a/oidc_test.go +++ b/oidc_test.go @@ -9,7 +9,7 @@ import ( "golang.org/x/oauth2" "gorm.io/gorm" "tailscale.com/tailcfg" - "tailscale.com/types/wgkey" + "tailscale.com/types/key" ) func TestHeadscale_getNamespaceFromEmail(t *testing.T) { @@ -19,8 +19,8 @@ func TestHeadscale_getNamespaceFromEmail(t *testing.T) { dbString string dbType string dbDebug bool - publicKey *wgkey.Key - privateKey *wgkey.Private + publicKey *key.MachinePublic + privateKey *key.MachinePrivate aclPolicy *ACLPolicy aclRules []tailcfg.FilterRule lastStateChange sync.Map diff --git a/poll.go b/poll.go index 9cf14e7a..b993fa7b 100644 --- a/poll.go +++ b/poll.go @@ -9,10 +9,11 @@ import ( "github.com/gin-gonic/gin" "github.com/rs/zerolog/log" + "go4.org/mem" "gorm.io/datatypes" "gorm.io/gorm" "tailscale.com/tailcfg" - "tailscale.com/types/wgkey" + "tailscale.com/types/key" ) const ( @@ -36,7 +37,7 @@ func (h *Headscale) PollNetMapHandler(ctx *gin.Context) { Msg("PollNetMapHandler called") body, _ := io.ReadAll(ctx.Request.Body) mKeyStr := ctx.Param("id") - mKey, err := wgkey.ParseHex(mKeyStr) + mKey, err := key.ParseMachinePublicUntyped(mem.S(mKeyStr)) if err != nil { log.Error(). Str("handler", "PollNetMap"). @@ -58,19 +59,19 @@ func (h *Headscale) PollNetMapHandler(ctx *gin.Context) { return } - machine, err := h.GetMachineByMachineKey(mKey.HexString()) + machine, err := h.GetMachineByMachineKey(mKey) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { log.Warn(). Str("handler", "PollNetMap"). - Msgf("Ignoring request, cannot find machine with key %s", mKey.HexString()) + Msgf("Ignoring request, cannot find machine with key %s", mKey.String()) ctx.String(http.StatusUnauthorized, "") return } log.Error(). Str("handler", "PollNetMap"). - Msgf("Failed to fetch machine from the database with Machine key: %s", mKey.HexString()) + Msgf("Failed to fetch machine from the database with Machine key: %s", mKey.String()) ctx.String(http.StatusInternalServerError, "") } log.Trace(). @@ -82,7 +83,7 @@ func (h *Headscale) PollNetMapHandler(ctx *gin.Context) { hostinfo, _ := json.Marshal(req.Hostinfo) machine.Name = req.Hostinfo.Hostname machine.HostInfo = datatypes.JSON(hostinfo) - machine.DiscoKey = wgkey.Key(req.DiscoKey).HexString() + machine.DiscoKey = DiscoPublicKeyStripPrefix(req.DiscoKey) now := time.Now().UTC() // From Tailscale client: @@ -225,7 +226,7 @@ func (h *Headscale) PollNetMapStream( ctx *gin.Context, machine *Machine, mapRequest tailcfg.MapRequest, - machineKey wgkey.Key, + machineKey key.MachinePublic, pollDataChan chan []byte, keepAliveChan chan []byte, updateChan chan struct{}, @@ -491,7 +492,7 @@ func (h *Headscale) scheduledPollWorker( cancelChan <-chan struct{}, updateChan chan<- struct{}, keepAliveChan chan<- []byte, - machineKey wgkey.Key, + machineKey key.MachinePublic, mapRequest tailcfg.MapRequest, machine *Machine, ) { diff --git a/utils.go b/utils.go index 9f7849e2..d0fa1b5e 100644 --- a/utils.go +++ b/utils.go @@ -7,50 +7,95 @@ package headscale import ( "context" - "crypto/rand" "encoding/json" "fmt" - "io" "net" "strings" - "golang.org/x/crypto/nacl/box" + "github.com/rs/zerolog/log" "inet.af/netaddr" "tailscale.com/tailcfg" - "tailscale.com/types/wgkey" + "tailscale.com/types/key" ) const ( errCannotDecryptReponse = Error("cannot decrypt response") errResponseMissingNonce = Error("response missing nonce") errCouldNotAllocateIP = Error("could not find any suitable IP") + + // These constants are copied from the upstream tailscale.com/types/key + // library, because they are not exported. + // https://github.com/tailscale/tailscale/tree/main/types/key + + // nodePrivateHexPrefix is the prefix used to identify a + // hex-encoded node private key. + // + // This prefix name is a little unfortunate, in that it comes from + // WireGuard's own key types, and we've used it for both key types + // we persist to disk (machine and node keys). But we're stuck + // with it for now, barring another round of tricky migration. + nodePrivateHexPrefix = "privkey:" + + // nodePublicHexPrefix is the prefix used to identify a + // hex-encoded node public key. + // + // This prefix is used in the control protocol, so cannot be + // changed. + nodePublicHexPrefix = "nodekey:" + + // machinePrivateHexPrefix is the prefix used to identify a + // hex-encoded machine private key. + // + // This prefix name is a little unfortunate, in that it comes from + // WireGuard's own key types. Unfortunately we're stuck with it for + // machine keys, because we serialize them to disk with this prefix. + machinePrivateHexPrefix = "privkey:" + + // machinePublicHexPrefix is the prefix used to identify a + // hex-encoded machine public key. + // + // This prefix is used in the control protocol, so cannot be + // changed. + machinePublicHexPrefix = "mkey:" + + // discoPublicHexPrefix is the prefix used to identify a + // hex-encoded disco public key. + // + // This prefix is used in the control protocol, so cannot be + // changed. + discoPublicHexPrefix = "discokey:" ) +func MachinePublicKeyStripPrefix(machineKey key.MachinePublic) string { + return strings.TrimPrefix(machineKey.String(), machinePublicHexPrefix) +} + +func NodePublicKeyStripPrefix(nodeKey key.NodePublic) string { + return strings.TrimPrefix(nodeKey.String(), nodePublicHexPrefix) +} + +func DiscoPublicKeyStripPrefix(discoKey key.DiscoPublic) string { + return strings.TrimPrefix(discoKey.String(), discoPublicHexPrefix) +} + // Error is used to compare errors as per https://dave.cheney.net/2016/04/07/constant-errors type Error string func (e Error) Error() string { return string(e) } func decode( - msg []byte, - v interface{}, - pubKey *wgkey.Key, - privKey *wgkey.Private, -) error { - return decodeMsg(msg, v, pubKey, privKey) -} - -func decodeMsg( msg []byte, output interface{}, - pubKey *wgkey.Key, - privKey *wgkey.Private, + pubKey *key.MachinePublic, + privKey *key.MachinePrivate, ) error { - decrypted, err := decryptMsg(msg, pubKey, privKey) - if err != nil { - return err + log.Trace().Int("length", len(msg)).Msg("Trying to decrypt") + + decrypted, ok := privKey.OpenFrom(*pubKey, msg) + if !ok { + return errCannotDecryptReponse } - // fmt.Println(string(decrypted)) + if err := json.Unmarshal(decrypted, output); err != nil { return err } @@ -58,45 +103,17 @@ func decodeMsg( return nil } -func decryptMsg(msg []byte, pubKey *wgkey.Key, privKey *wgkey.Private) ([]byte, error) { - var nonce [24]byte - if len(msg) < len(nonce)+1 { - return nil, errResponseMissingNonce - } - copy(nonce[:], msg) - msg = msg[len(nonce):] - - pub, pri := (*[32]byte)(pubKey), (*[32]byte)(privKey) - decrypted, ok := box.Open(nil, msg, &nonce, pub, pri) - if !ok { - return nil, errCannotDecryptReponse - } - - return decrypted, nil -} - -func encode(v interface{}, pubKey *wgkey.Key, privKey *wgkey.Private) ([]byte, error) { +func encode( + v interface{}, + pubKey *key.MachinePublic, + privKey *key.MachinePrivate, +) ([]byte, error) { b, err := json.Marshal(v) if err != nil { return nil, err } - return encodeMsg(b, pubKey, privKey) -} - -func encodeMsg( - payload []byte, - pubKey *wgkey.Key, - privKey *wgkey.Private, -) ([]byte, error) { - var nonce [24]byte - if _, err := io.ReadFull(rand.Reader, nonce[:]); err != nil { - panic(err) - } - pub, pri := (*[32]byte)(pubKey), (*[32]byte)(privKey) - msg := box.Seal(nonce[:], payload, &nonce, pub, pri) - - return msg, nil + return privKey.SealTo(*pubKey, b), nil } func (h *Headscale) getAvailableIP() (*netaddr.IP, error) { From 0012c7617067e6b02b6d55ad9a264f7c786f7c69 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Fri, 26 Nov 2021 23:34:11 +0000 Subject: [PATCH 07/19] Make it easier to run cli integration tests --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index 060d3b9c..6b4c02ff 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,9 @@ test: test_integration: go test -tags integration -timeout 30m ./... +test_integration_cli: + go test -tags integration -v integration_cli_test.go integration_common_test.go + coverprofile_func: go tool cover -func=coverage.out From c38f00fab85d3e77d99f3796683d4c5913ef2931 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Fri, 26 Nov 2021 23:50:42 +0000 Subject: [PATCH 08/19] Unmarshal keys in the non-deprecated way --- api.go | 5 +++-- cmd/headscale/cli/nodes.go | 4 ++-- integration_cli_test.go | 3 +++ machine.go | 14 +++++++------- oidc.go | 4 ++-- poll.go | 19 ++++++++++--------- utils.go | 18 ------------------ 7 files changed, 27 insertions(+), 40 deletions(-) diff --git a/api.go b/api.go index 84b79a58..ff738712 100644 --- a/api.go +++ b/api.go @@ -13,7 +13,6 @@ import ( "github.com/gin-gonic/gin" "github.com/klauspost/compress/zstd" "github.com/rs/zerolog/log" - "go4.org/mem" "gorm.io/gorm" "tailscale.com/tailcfg" "tailscale.com/types/key" @@ -74,7 +73,9 @@ func (h *Headscale) RegisterWebAPI(ctx *gin.Context) { func (h *Headscale) RegistrationHandler(ctx *gin.Context) { body, _ := io.ReadAll(ctx.Request.Body) machineKeyStr := ctx.Param("id") - machineKey, err := key.ParseMachinePublicUntyped(mem.S(machineKeyStr)) + + var machineKey key.MachinePublic + err := machineKey.UnmarshalText([]byte(machineKeyStr)) if err != nil { log.Error(). Caller(). diff --git a/cmd/headscale/cli/nodes.go b/cmd/headscale/cli/nodes.go index 2c7fa9b5..5adc7f59 100644 --- a/cmd/headscale/cli/nodes.go +++ b/cmd/headscale/cli/nodes.go @@ -11,7 +11,6 @@ import ( v1 "github.com/juanfont/headscale/gen/go/headscale/v1" "github.com/pterm/pterm" "github.com/spf13/cobra" - "go4.org/mem" "google.golang.org/grpc/status" "tailscale.com/types/key" ) @@ -486,7 +485,8 @@ func nodesToPtables( expiry = machine.Expiry.AsTime() } - nodeKey, err := key.ParseNodePublicUntyped(mem.S(machine.NodeKey)) + var nodeKey key.NodePublic + err := nodeKey.UnmarshalText([]byte(machine.NodeKey)) if err != nil { return nil, err } diff --git a/integration_cli_test.go b/integration_cli_test.go index ee940542..eb553220 100644 --- a/integration_cli_test.go +++ b/integration_cli_test.go @@ -720,6 +720,7 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() { []string{}, ) assert.Nil(s.T(), err) + fmt.Println("Error: ", err) var listOnlySharedMachineNamespace []v1.Machine err = json.Unmarshal( @@ -728,6 +729,8 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() { ) assert.Nil(s.T(), err) + fmt.Println("List: ", listOnlySharedMachineNamespaceResult) + fmt.Println("List2: ", listOnlySharedMachineNamespace) assert.Len(s.T(), listOnlySharedMachineNamespace, 2) assert.Equal(s.T(), uint64(6), listOnlySharedMachineNamespace[0].Id) diff --git a/machine.go b/machine.go index 26c59c65..03caa5a2 100644 --- a/machine.go +++ b/machine.go @@ -12,7 +12,6 @@ import ( "github.com/fatih/set" v1 "github.com/juanfont/headscale/gen/go/headscale/v1" "github.com/rs/zerolog/log" - "go4.org/mem" "google.golang.org/protobuf/types/known/timestamppb" "gorm.io/datatypes" "inet.af/netaddr" @@ -439,7 +438,8 @@ func (machine Machine) toNode( dnsConfig *tailcfg.DNSConfig, includeRoutes bool, ) (*tailcfg.Node, error) { - nodeKey, err := key.ParseNodePublicUntyped(mem.S(machine.NodeKey)) + var nodeKey key.NodePublic + err := nodeKey.UnmarshalText([]byte(machine.NodeKey)) if err != nil { log.Trace(). Caller(). @@ -449,19 +449,18 @@ func (machine Machine) toNode( return nil, fmt.Errorf("failed to parse node public key: %w", err) } - machineKey, err := key.ParseMachinePublicUntyped(mem.S(machine.MachineKey)) + var machineKey key.MachinePublic + err = machineKey.UnmarshalText([]byte(machine.MachineKey)) if err != nil { return nil, fmt.Errorf("failed to parse machine public key: %w", err) } var discoKey key.DiscoPublic if machine.DiscoKey != "" { - dKey := key.DiscoPublic{} - err := dKey.UnmarshalText([]byte(discoPublicHexPrefix + machine.DiscoKey)) + err := discoKey.UnmarshalText([]byte(discoPublicHexPrefix + machine.DiscoKey)) if err != nil { return nil, fmt.Errorf("failed to parse disco public key: %w", err) } - discoKey = key.DiscoPublic(dKey) } else { discoKey = key.DiscoPublic{} } @@ -634,7 +633,8 @@ func (h *Headscale) RegisterMachine( return nil, err } - machineKey, err := key.ParseMachinePublicUntyped(mem.S(machineKeyStr)) + var machineKey key.MachinePublic + err = machineKey.UnmarshalText([]byte(machineKeyStr)) if err != nil { return nil, err } diff --git a/oidc.go b/oidc.go index 02666d89..48ad7187 100644 --- a/oidc.go +++ b/oidc.go @@ -15,7 +15,6 @@ import ( "github.com/gin-gonic/gin" "github.com/patrickmn/go-cache" "github.com/rs/zerolog/log" - "go4.org/mem" "golang.org/x/oauth2" "gorm.io/gorm" "tailscale.com/types/key" @@ -192,7 +191,8 @@ func (h *Headscale) OIDCCallback(ctx *gin.Context) { machineKeyStr, machineKeyOK := machineKeyIf.(string) - machineKey, err := key.ParseMachinePublicUntyped(mem.S(machineKeyStr)) + var machineKey key.MachinePublic + err = machineKey.UnmarshalText([]byte(machineKeyStr)) if err != nil { log.Error(). Msg("could not parse machine public key") diff --git a/poll.go b/poll.go index b993fa7b..70bacc6f 100644 --- a/poll.go +++ b/poll.go @@ -9,7 +9,6 @@ import ( "github.com/gin-gonic/gin" "github.com/rs/zerolog/log" - "go4.org/mem" "gorm.io/datatypes" "gorm.io/gorm" "tailscale.com/tailcfg" @@ -36,8 +35,10 @@ func (h *Headscale) PollNetMapHandler(ctx *gin.Context) { Str("id", ctx.Param("id")). Msg("PollNetMapHandler called") body, _ := io.ReadAll(ctx.Request.Body) - mKeyStr := ctx.Param("id") - mKey, err := key.ParseMachinePublicUntyped(mem.S(mKeyStr)) + machineKeyStr := ctx.Param("id") + + var machineKey key.MachinePublic + err := machineKey.UnmarshalText([]byte(machineKeyStr)) if err != nil { log.Error(). Str("handler", "PollNetMap"). @@ -48,7 +49,7 @@ func (h *Headscale) PollNetMapHandler(ctx *gin.Context) { return } req := tailcfg.MapRequest{} - err = decode(body, &req, &mKey, h.privateKey) + err = decode(body, &req, &machineKey, h.privateKey) if err != nil { log.Error(). Str("handler", "PollNetMap"). @@ -59,19 +60,19 @@ func (h *Headscale) PollNetMapHandler(ctx *gin.Context) { return } - machine, err := h.GetMachineByMachineKey(mKey) + machine, err := h.GetMachineByMachineKey(machineKey) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { log.Warn(). Str("handler", "PollNetMap"). - Msgf("Ignoring request, cannot find machine with key %s", mKey.String()) + Msgf("Ignoring request, cannot find machine with key %s", machineKey.String()) ctx.String(http.StatusUnauthorized, "") return } log.Error(). Str("handler", "PollNetMap"). - Msgf("Failed to fetch machine from the database with Machine key: %s", mKey.String()) + Msgf("Failed to fetch machine from the database with Machine key: %s", machineKey.String()) ctx.String(http.StatusInternalServerError, "") } log.Trace(). @@ -101,7 +102,7 @@ func (h *Headscale) PollNetMapHandler(ctx *gin.Context) { } h.db.Save(&machine) - data, err := h.getMapResponse(mKey, req, machine) + data, err := h.getMapResponse(machineKey, req, machine) if err != nil { log.Error(). Str("handler", "PollNetMap"). @@ -206,7 +207,7 @@ func (h *Headscale) PollNetMapHandler(ctx *gin.Context) { ctx, machine, req, - mKey, + machineKey, pollDataChan, keepAliveChan, updateChan, diff --git a/utils.go b/utils.go index d0fa1b5e..fa9f028d 100644 --- a/utils.go +++ b/utils.go @@ -20,22 +20,12 @@ import ( const ( errCannotDecryptReponse = Error("cannot decrypt response") - errResponseMissingNonce = Error("response missing nonce") errCouldNotAllocateIP = Error("could not find any suitable IP") // These constants are copied from the upstream tailscale.com/types/key // library, because they are not exported. // https://github.com/tailscale/tailscale/tree/main/types/key - // nodePrivateHexPrefix is the prefix used to identify a - // hex-encoded node private key. - // - // This prefix name is a little unfortunate, in that it comes from - // WireGuard's own key types, and we've used it for both key types - // we persist to disk (machine and node keys). But we're stuck - // with it for now, barring another round of tricky migration. - nodePrivateHexPrefix = "privkey:" - // nodePublicHexPrefix is the prefix used to identify a // hex-encoded node public key. // @@ -43,14 +33,6 @@ const ( // changed. nodePublicHexPrefix = "nodekey:" - // machinePrivateHexPrefix is the prefix used to identify a - // hex-encoded machine private key. - // - // This prefix name is a little unfortunate, in that it comes from - // WireGuard's own key types. Unfortunately we're stuck with it for - // machine keys, because we serialize them to disk with this prefix. - machinePrivateHexPrefix = "privkey:" - // machinePublicHexPrefix is the prefix used to identify a // hex-encoded machine public key. // From 59aeaa8476aa6043f830dc2e2bd8bbff3693a799 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Sat, 27 Nov 2021 20:25:12 +0000 Subject: [PATCH 09/19] Ensure we always have the key prefix when needed --- api.go | 2 +- cmd/headscale/cli/nodes.go | 4 +++- machine.go | 12 ++++++++---- oidc.go | 2 +- poll.go | 2 +- utils.go | 24 ++++++++++++++++++++++++ 6 files changed, 38 insertions(+), 8 deletions(-) diff --git a/api.go b/api.go index ff738712..aadc604e 100644 --- a/api.go +++ b/api.go @@ -75,7 +75,7 @@ func (h *Headscale) RegistrationHandler(ctx *gin.Context) { machineKeyStr := ctx.Param("id") var machineKey key.MachinePublic - err := machineKey.UnmarshalText([]byte(machineKeyStr)) + err := machineKey.UnmarshalText([]byte(MachinePublicKeyEnsurePrefix(machineKeyStr))) if err != nil { log.Error(). Caller(). diff --git a/cmd/headscale/cli/nodes.go b/cmd/headscale/cli/nodes.go index 5adc7f59..26ead6dc 100644 --- a/cmd/headscale/cli/nodes.go +++ b/cmd/headscale/cli/nodes.go @@ -486,7 +486,9 @@ func nodesToPtables( } var nodeKey key.NodePublic - err := nodeKey.UnmarshalText([]byte(machine.NodeKey)) + err := nodeKey.UnmarshalText( + []byte(headscale.NodePublicKeyEnsurePrefix(machine.NodeKey)), + ) if err != nil { return nil, err } diff --git a/machine.go b/machine.go index 03caa5a2..d58c9c5c 100644 --- a/machine.go +++ b/machine.go @@ -439,7 +439,7 @@ func (machine Machine) toNode( includeRoutes bool, ) (*tailcfg.Node, error) { var nodeKey key.NodePublic - err := nodeKey.UnmarshalText([]byte(machine.NodeKey)) + err := nodeKey.UnmarshalText([]byte(NodePublicKeyEnsurePrefix(machine.NodeKey))) if err != nil { log.Trace(). Caller(). @@ -450,14 +450,18 @@ func (machine Machine) toNode( } var machineKey key.MachinePublic - err = machineKey.UnmarshalText([]byte(machine.MachineKey)) + err = machineKey.UnmarshalText( + []byte(MachinePublicKeyEnsurePrefix(machine.MachineKey)), + ) if err != nil { return nil, fmt.Errorf("failed to parse machine public key: %w", err) } var discoKey key.DiscoPublic if machine.DiscoKey != "" { - err := discoKey.UnmarshalText([]byte(discoPublicHexPrefix + machine.DiscoKey)) + err := discoKey.UnmarshalText( + []byte(DiscoPublicKeyEnsurePrefix(machine.DiscoKey)), + ) if err != nil { return nil, fmt.Errorf("failed to parse disco public key: %w", err) } @@ -634,7 +638,7 @@ func (h *Headscale) RegisterMachine( } var machineKey key.MachinePublic - err = machineKey.UnmarshalText([]byte(machineKeyStr)) + err = machineKey.UnmarshalText([]byte(MachinePublicKeyEnsurePrefix(machineKeyStr))) if err != nil { return nil, err } diff --git a/oidc.go b/oidc.go index 48ad7187..d481e028 100644 --- a/oidc.go +++ b/oidc.go @@ -192,7 +192,7 @@ func (h *Headscale) OIDCCallback(ctx *gin.Context) { machineKeyStr, machineKeyOK := machineKeyIf.(string) var machineKey key.MachinePublic - err = machineKey.UnmarshalText([]byte(machineKeyStr)) + err = machineKey.UnmarshalText([]byte(MachinePublicKeyEnsurePrefix(machineKeyStr))) if err != nil { log.Error(). Msg("could not parse machine public key") diff --git a/poll.go b/poll.go index 70bacc6f..1d2db944 100644 --- a/poll.go +++ b/poll.go @@ -38,7 +38,7 @@ func (h *Headscale) PollNetMapHandler(ctx *gin.Context) { machineKeyStr := ctx.Param("id") var machineKey key.MachinePublic - err := machineKey.UnmarshalText([]byte(machineKeyStr)) + err := machineKey.UnmarshalText([]byte(MachinePublicKeyEnsurePrefix(machineKeyStr))) if err != nil { log.Error(). Str("handler", "PollNetMap"). diff --git a/utils.go b/utils.go index fa9f028d..c9971390 100644 --- a/utils.go +++ b/utils.go @@ -60,6 +60,30 @@ func DiscoPublicKeyStripPrefix(discoKey key.DiscoPublic) string { return strings.TrimPrefix(discoKey.String(), discoPublicHexPrefix) } +func MachinePublicKeyEnsurePrefix(machineKey string) string { + if !strings.HasPrefix(machineKey, machinePublicHexPrefix) { + return machinePublicHexPrefix + machineKey + } + + return machineKey +} + +func NodePublicKeyEnsurePrefix(nodeKey string) string { + if !strings.HasPrefix(nodeKey, nodePublicHexPrefix) { + return nodePublicHexPrefix + nodeKey + } + + return nodeKey +} + +func DiscoPublicKeyEnsurePrefix(discoKey string) string { + if !strings.HasPrefix(discoKey, discoPublicHexPrefix) { + return discoPublicHexPrefix + discoKey + } + + return discoKey +} + // Error is used to compare errors as per https://dave.cheney.net/2016/04/07/constant-errors type Error string From d96b681c8380f13c5b1a9ace86daf02ab536bf36 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Sat, 27 Nov 2021 20:25:37 +0000 Subject: [PATCH 10/19] Fix node cli integration test --- integration_cli_test.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/integration_cli_test.go b/integration_cli_test.go index eb553220..81a19334 100644 --- a/integration_cli_test.go +++ b/integration_cli_test.go @@ -639,7 +639,7 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() { "--name", fmt.Sprintf("shared-machine-%d", index+1), "--namespace", - namespace.Name, + sharedNamespace.Name, "--key", machineKey, "--output", @@ -720,7 +720,6 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() { []string{}, ) assert.Nil(s.T(), err) - fmt.Println("Error: ", err) var listOnlySharedMachineNamespace []v1.Machine err = json.Unmarshal( @@ -729,8 +728,6 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() { ) assert.Nil(s.T(), err) - fmt.Println("List: ", listOnlySharedMachineNamespaceResult) - fmt.Println("List2: ", listOnlySharedMachineNamespace) assert.Len(s.T(), listOnlySharedMachineNamespace, 2) assert.Equal(s.T(), uint64(6), listOnlySharedMachineNamespace[0].Id) From 2ae882d8019329fce724409242dd5ea99d0c1e5f Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Sat, 27 Nov 2021 20:31:33 +0000 Subject: [PATCH 11/19] Update go version --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index e036effc..982c2989 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/juanfont/headscale -go 1.16 +go 1.17 require ( github.com/AlecAivazis/survey/v2 v2.3.2 From 6295b0bd843ac8676e3bf6cf2e9f8860f34f17c0 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Sat, 27 Nov 2021 20:34:46 +0000 Subject: [PATCH 12/19] Go mod tidy --- go.mod | 115 ++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 94 insertions(+), 21 deletions(-) diff --git a/go.mod b/go.mod index 982c2989..2d9e8c61 100644 --- a/go.mod +++ b/go.mod @@ -4,35 +4,19 @@ go 1.17 require ( github.com/AlecAivazis/survey/v2 v2.3.2 - github.com/Microsoft/go-winio v0.5.0 // indirect - github.com/cenkalti/backoff/v4 v4.1.1 // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect - github.com/containerd/continuity v0.1.0 // indirect github.com/coreos/go-oidc/v3 v3.1.0 - github.com/docker/cli v20.10.8+incompatible // indirect - github.com/docker/docker v20.10.8+incompatible // indirect github.com/efekarakus/termcolor v1.0.1 github.com/fatih/set v0.2.1 github.com/gin-gonic/gin v1.7.4 - github.com/go-playground/validator/v10 v10.9.0 // indirect github.com/gofrs/uuid v4.1.0+incompatible - github.com/google/go-github v17.0.0+incompatible // indirect - github.com/google/go-querystring v1.1.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 github.com/grpc-ecosystem/grpc-gateway/v2 v2.6.0 github.com/infobloxopen/protoc-gen-gorm v1.0.1 - github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.13.6 - github.com/lib/pq v1.10.3 // indirect - github.com/mattn/go-isatty v0.0.14 // indirect - github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect - github.com/opencontainers/runc v1.0.2 // indirect github.com/ory/dockertest/v3 v3.7.0 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/philip-bui/grpc-zerolog v1.0.1 github.com/prometheus/client_golang v1.11.0 - github.com/prometheus/common v0.32.1 // indirect - github.com/prometheus/procfs v0.7.3 // indirect github.com/pterm/pterm v0.12.30 github.com/rs/zerolog v1.26.0 github.com/soheilhy/cmux v0.1.5 @@ -41,20 +25,15 @@ require ( github.com/stretchr/testify v1.7.0 github.com/tailscale/hujson v0.0.0-20210923003652-c3758b31534b github.com/tcnksm/go-latest v0.0.0-20170313132115-e3007ae9052e - github.com/ugorji/go v1.2.6 // indirect - github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/zsais/go-gin-prometheus v0.1.0 - go4.org/mem v0.0.0-20210711025021-927187094b94 golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c - golang.org/x/sys v0.0.0-20211124211545-fe61309f8881 // indirect google.golang.org/genproto v0.0.0-20211104193956-4c6863e31247 google.golang.org/grpc v1.42.0 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 google.golang.org/protobuf v1.27.1 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c - gopkg.in/square/go-jose.v2 v2.6.0 // indirect gopkg.in/yaml.v2 v2.4.0 gorm.io/datatypes v1.0.2 gorm.io/driver/postgres v1.1.1 @@ -63,3 +42,97 @@ require ( inet.af/netaddr v0.0.0-20211027220019-c74959edd3b6 tailscale.com v1.18.1 ) + +require ( + github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/Microsoft/go-winio v0.5.0 // indirect + github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect + github.com/atomicgo/cursor v0.0.1 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cenkalti/backoff/v4 v4.1.1 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/containerd/continuity v0.1.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/docker/cli v20.10.8+incompatible // indirect + github.com/docker/docker v20.10.8+incompatible // indirect + github.com/docker/go-connections v0.4.0 // indirect + github.com/docker/go-units v0.4.0 // indirect + github.com/fsnotify/fsnotify v1.4.9 // indirect + github.com/ghodss/yaml v1.0.0 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-playground/locales v0.14.0 // indirect + github.com/go-playground/universal-translator v0.18.0 // indirect + github.com/go-playground/validator/v10 v10.9.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/glog v1.0.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/google/go-github v17.0.0+incompatible // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect + github.com/gookit/color v1.4.2 // indirect + github.com/hashicorp/go-version v1.2.0 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/imdario/mergo v0.3.12 // indirect + github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/jackc/chunkreader/v2 v2.0.1 // indirect + github.com/jackc/pgconn v1.10.0 // indirect + github.com/jackc/pgio v1.0.0 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgproto3/v2 v2.1.1 // indirect + github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect + github.com/jackc/pgtype v1.8.1 // indirect + github.com/jackc/pgx/v4 v4.13.0 // indirect + github.com/jinzhu/gorm v1.9.16 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.2 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect + github.com/kr/pretty v0.3.0 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/leodido/go-urn v1.2.1 // indirect + github.com/lib/pq v1.10.3 // indirect + github.com/magiconair/properties v1.8.5 // indirect + github.com/mattn/go-colorable v0.1.8 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect + github.com/mattn/go-runewidth v0.0.13 // indirect + github.com/mattn/go-sqlite3 v1.14.8 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect + github.com/mitchellh/mapstructure v1.4.1 // indirect + github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.0.1 // indirect + github.com/opencontainers/runc v1.0.2 // indirect + github.com/pelletier/go-toml v1.9.3 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_model v0.2.0 // indirect + github.com/prometheus/common v0.32.1 // indirect + github.com/prometheus/procfs v0.7.3 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + github.com/rogpeppe/go-internal v1.8.0 // indirect + github.com/sirupsen/logrus v1.8.1 // indirect + github.com/spf13/afero v1.6.0 // indirect + github.com/spf13/cast v1.3.1 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/subosito/gotenv v1.2.0 // indirect + github.com/ugorji/go/codec v1.2.6 // indirect + github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect + github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect + github.com/xeipuuv/gojsonschema v1.2.0 // indirect + github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect + go4.org/intern v0.0.0-20211027215823-ae77deb06f29 // indirect + go4.org/mem v0.0.0-20210711025021-927187094b94 // indirect + go4.org/unsafe/assume-no-moving-gc v0.0.0-20211027215541-db492cf91b37 // indirect + golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect + golang.org/x/sys v0.0.0-20211124211545-fe61309f8881 // indirect + golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect + golang.org/x/text v0.3.7 // indirect + google.golang.org/appengine v1.6.7 // indirect + gopkg.in/ini.v1 v1.62.0 // indirect + gopkg.in/square/go-jose.v2 v2.6.0 // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect +) From e9d5214d1cc608ee52f2e68f8028ce6a08edd3f1 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Sat, 27 Nov 2021 21:04:19 +0000 Subject: [PATCH 13/19] Disable tests which is broken due to split version --- integration_test.go | 84 ++++++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/integration_test.go b/integration_test.go index d6aedf19..7840adc3 100644 --- a/integration_test.go +++ b/integration_test.go @@ -393,46 +393,50 @@ func (s *IntegrationTestSuite) TestGetIpAddresses() { } } -func (s *IntegrationTestSuite) TestStatus() { - for _, scales := range s.namespaces { - ips, err := getIPs(scales.tailscales) - assert.Nil(s.T(), err) - - for hostname, tailscale := range scales.tailscales { - s.T().Run(hostname, func(t *testing.T) { - command := []string{"tailscale", "status", "--json"} - - fmt.Printf("Getting status for %s\n", hostname) - result, err := ExecuteCommand( - &tailscale, - command, - []string{}, - ) - assert.Nil(t, err) - - var status ipnstate.Status - err = json.Unmarshal([]byte(result), &status) - assert.Nil(s.T(), err) - - // TODO(kradalby): Replace this check with peer length of SAME namespace - // Check if we have as many nodes in status - // as we have IPs/tailscales - // lines := strings.Split(result, "\n") - // assert.Equal(t, len(ips), len(lines)-1) - // assert.Equal(t, len(scales.tailscales), len(lines)-1) - - peerIps := getIPsfromIPNstate(status) - - // Check that all hosts is present in all hosts status - for ipHostname, ip := range ips { - if hostname != ipHostname { - assert.Contains(t, peerIps, ip) - } - } - }) - } - } -} +// TODO(kradalby): fix this test +// We need some way to impot ipnstate.Status from multiple go packages. +// Currently it will only work with 1.18.x since that is the last +// version we have in go.mod +// func (s *IntegrationTestSuite) TestStatus() { +// for _, scales := range s.namespaces { +// ips, err := getIPs(scales.tailscales) +// assert.Nil(s.T(), err) +// +// for hostname, tailscale := range scales.tailscales { +// s.T().Run(hostname, func(t *testing.T) { +// command := []string{"tailscale", "status", "--json"} +// +// fmt.Printf("Getting status for %s\n", hostname) +// result, err := ExecuteCommand( +// &tailscale, +// command, +// []string{}, +// ) +// assert.Nil(t, err) +// +// var status ipnstate.Status +// err = json.Unmarshal([]byte(result), &status) +// assert.Nil(s.T(), err) +// +// // TODO(kradalby): Replace this check with peer length of SAME namespace +// // Check if we have as many nodes in status +// // as we have IPs/tailscales +// // lines := strings.Split(result, "\n") +// // assert.Equal(t, len(ips), len(lines)-1) +// // assert.Equal(t, len(scales.tailscales), len(lines)-1) +// +// peerIps := getIPsfromIPNstate(status) +// +// // Check that all hosts is present in all hosts status +// for ipHostname, ip := range ips { +// if hostname != ipHostname { +// assert.Contains(t, peerIps, ip) +// } +// } +// }) +// } +// } +// } func getIPsfromIPNstate(status ipnstate.Status) []netaddr.IP { ips := make([]netaddr.IP, 0) From ff8c961dbbd8fe01cdacbd9da60d039b9fb4b83f Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Sun, 28 Nov 2021 08:23:45 +0000 Subject: [PATCH 14/19] Make sure comparison of nodekey is on the same format --- api.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api.go b/api.go index aadc604e..076594dc 100644 --- a/api.go +++ b/api.go @@ -127,7 +127,7 @@ func (h *Headscale) RegistrationHandler(ctx *gin.Context) { // - Trying to log out (sending a expiry in the past) // - A valid, registered machine, looking for the node map // - Expired machine wanting to reauthenticate - if machine.NodeKey == req.NodeKey.String() { + if machine.NodeKey == NodePublicKeyStripPrefix(req.NodeKey) { // The client sends an Expiry in the past if the client is requesting to expire the key (aka logout) // https://github.com/tailscale/tailscale/blob/main/tailcfg/tailcfg.go#L648 if !req.Expiry.IsZero() && req.Expiry.UTC().Before(now) { @@ -146,7 +146,7 @@ func (h *Headscale) RegistrationHandler(ctx *gin.Context) { } // The NodeKey we have matches OldNodeKey, which means this is a refresh after a key expiration - if machine.NodeKey == req.OldNodeKey.String() && + if machine.NodeKey == NodePublicKeyStripPrefix(req.OldNodeKey) && !machine.isExpired() { h.handleMachineRefreshKey(ctx, machineKey, req, *machine) From 32006f3a20c791d677c55528d9a3adf2d892c237 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Sun, 28 Nov 2021 08:26:36 +0000 Subject: [PATCH 15/19] Use go 1.17 --- .github/workflows/test-integration.yml | 2 +- .github/workflows/test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-integration.yml b/.github/workflows/test-integration.yml index e939df22..abf46d32 100644 --- a/.github/workflows/test-integration.yml +++ b/.github/workflows/test-integration.yml @@ -17,7 +17,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v2 with: - go-version: "1.16.3" + go-version: "1.17.3" - name: Run Integration tests run: go test -tags integration -timeout 30m diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3d254fa6..4540482c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,7 +17,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v2 with: - go-version: "1.16.3" # The Go version to download (if necessary) and use. + go-version: "1.17.3" # The Go version to download (if necessary) and use. # Install all the dependencies - name: Install dependencies From 34f4109fbd6b5c5da322eb31ac1dbe1b5d9d74e7 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Sun, 28 Nov 2021 09:17:18 +0000 Subject: [PATCH 16/19] Add back privatekey, but automatically generate it if it does not exist --- api.go | 2 +- app.go | 67 +++++++++++++++++++++++++++++++------- cmd/headscale/cli/utils.go | 9 ++--- utils.go | 11 +++++++ 4 files changed, 73 insertions(+), 16 deletions(-) diff --git a/api.go b/api.go index 076594dc..96e22bd5 100644 --- a/api.go +++ b/api.go @@ -34,7 +34,7 @@ func (h *Headscale) KeyHandler(ctx *gin.Context) { ctx.Data( http.StatusOK, "text/plain; charset=utf-8", - []byte(MachinePublicKeyStripPrefix(*h.publicKey)), + []byte(MachinePublicKeyStripPrefix(h.privateKey.Public())), ) } diff --git a/app.go b/app.go index 640803b6..db788908 100644 --- a/app.go +++ b/app.go @@ -47,11 +47,12 @@ import ( ) const ( - AuthPrefix = "Bearer " - Postgres = "postgres" - Sqlite = "sqlite3" - updateInterval = 5000 - HTTPReadTimeout = 30 * time.Second + AuthPrefix = "Bearer " + Postgres = "postgres" + Sqlite = "sqlite3" + updateInterval = 5000 + HTTPReadTimeout = 30 * time.Second + privateKeyFileMode = 0o600 requestedExpiryCacheExpiration = time.Minute * 5 requestedExpiryCacheCleanupInterval = time.Minute * 10 @@ -68,6 +69,7 @@ type Config struct { Addr string EphemeralNodeInactivityTimeout time.Duration IPPrefix netaddr.IPPrefix + PrivateKeyPath string BaseDomain string DERP DERPConfig @@ -128,7 +130,6 @@ type Headscale struct { dbString string dbType string dbDebug bool - publicKey *key.MachinePublic privateKey *key.MachinePrivate DERPMap *tailcfg.DERPMap @@ -147,8 +148,10 @@ type Headscale struct { // NewHeadscale returns the Headscale app. func NewHeadscale(cfg Config) (*Headscale, error) { - privKey := key.NewMachine() - pubKey := privKey.Public() + privKey, err := readOrCreatePrivateKey(cfg.PrivateKeyPath) + if err != nil { + return nil, fmt.Errorf("failed to read or create private key: %w", err) + } var dbString string switch cfg.DBtype { @@ -176,13 +179,12 @@ func NewHeadscale(cfg Config) (*Headscale, error) { cfg: cfg, dbType: cfg.DBtype, dbString: dbString, - privateKey: &privKey, - publicKey: &pubKey, + privateKey: privKey, aclRules: tailcfg.FilterAllowAll, // default allowall requestedExpiryCache: requestedExpiryCache, } - err := app.initDB() + err = app.initDB() if err != nil { return nil, err } @@ -694,3 +696,46 @@ func stdoutHandler(ctx *gin.Context) { Bytes("body", body). Msg("Request did not match") } + +func readOrCreatePrivateKey(path string) (*key.MachinePrivate, error) { + privateKey, err := os.ReadFile(path) + if errors.Is(err, os.ErrNotExist) { + log.Info().Str("path", path).Msg("No private key file at path, creating...") + + machineKey := key.NewMachine() + + machineKeyStr, err := machineKey.MarshalText() + if err != nil { + return nil, fmt.Errorf( + "failed to convert private key to string for saving: %w", + err, + ) + } + err = os.WriteFile(path, machineKeyStr, privateKeyFileMode) + if err != nil { + return nil, fmt.Errorf( + "failed to save private key to disk: %w", + err, + ) + } + + return &machineKey, nil + } else if err != nil { + return nil, fmt.Errorf("failed to read private key file: %w", err) + } + + privateKeyEnsurePrefix := PrivateKeyEnsurePrefix(string(privateKey)) + + var machineKey key.MachinePrivate + if err = machineKey.UnmarshalText([]byte(privateKeyEnsurePrefix)); err != nil { + log.Info(). + Str("path", path). + Msg("This might be due to a legacy (headscale pre-0.12) private key. " + + "If the key is in WireGuard format, delete the key and restart headscale. " + + "A new key will automatically be generated. All Tailscale clients will have to be restarted") + + return nil, fmt.Errorf("failed to parse private key: %w", err) + } + + return &machineKey, nil +} diff --git a/cmd/headscale/cli/utils.go b/cmd/headscale/cli/utils.go index d47a5ca9..a4856642 100644 --- a/cmd/headscale/cli/utils.go +++ b/cmd/headscale/cli/utils.go @@ -222,10 +222,11 @@ func getHeadscaleConfig() headscale.Config { derpConfig := GetDERPConfig() return headscale.Config{ - ServerURL: viper.GetString("server_url"), - Addr: viper.GetString("listen_addr"), - IPPrefix: netaddr.MustParseIPPrefix(viper.GetString("ip_prefix")), - BaseDomain: baseDomain, + ServerURL: viper.GetString("server_url"), + Addr: viper.GetString("listen_addr"), + IPPrefix: netaddr.MustParseIPPrefix(viper.GetString("ip_prefix")), + PrivateKeyPath: absPath(viper.GetString("private_key_path")), + BaseDomain: baseDomain, DERP: derpConfig, diff --git a/utils.go b/utils.go index c9971390..7011e63d 100644 --- a/utils.go +++ b/utils.go @@ -46,6 +46,9 @@ const ( // This prefix is used in the control protocol, so cannot be // changed. discoPublicHexPrefix = "discokey:" + + // privateKey prefix. + privateHexPrefix = "privkey:" ) func MachinePublicKeyStripPrefix(machineKey key.MachinePublic) string { @@ -84,6 +87,14 @@ func DiscoPublicKeyEnsurePrefix(discoKey string) string { return discoKey } +func PrivateKeyEnsurePrefix(privateKey string) string { + if !strings.HasPrefix(privateKey, privateHexPrefix) { + return privateHexPrefix + privateKey + } + + return privateKey +} + // Error is used to compare errors as per https://dave.cheney.net/2016/04/07/constant-errors type Error string From e167be6d64ee90400b33cddb669c6e2dbb878155 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Sun, 28 Nov 2021 09:18:24 +0000 Subject: [PATCH 17/19] Remove generate private key step from docs --- docs/Running.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/Running.md b/docs/Running.md index ac9d2282..8aa5850e 100644 --- a/docs/Running.md +++ b/docs/Running.md @@ -39,11 +39,9 @@ touch config/db.sqlite ``` -4. Create a WireGuard private key, headscale configuration, and a DERP map file. Refer to [tailscale sample](https://raw.githubusercontent.com/tailscale/tailscale/main/net/dnsfallback/dns-fallback-servers.json) for more guidance. +4. Create a headscale configuration, and a DERP map file. Refer to [tailscale sample](https://raw.githubusercontent.com/tailscale/tailscale/main/net/dnsfallback/dns-fallback-servers.json) for more guidance. ```shell - wg genkey > config/private.key - cp config.yaml.[sqlite|postgres].example config/config.yaml cp derp-example.yaml config/derp.yaml From 5b8587037d1207e048b1e4150efbf013499b1732 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Sun, 28 Nov 2021 09:25:27 +0000 Subject: [PATCH 18/19] Remove non-existing field from oidc test --- oidc_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/oidc_test.go b/oidc_test.go index db581b99..d50027a9 100644 --- a/oidc_test.go +++ b/oidc_test.go @@ -19,7 +19,6 @@ func TestHeadscale_getNamespaceFromEmail(t *testing.T) { dbString string dbType string dbDebug bool - publicKey *key.MachinePublic privateKey *key.MachinePrivate aclPolicy *ACLPolicy aclRules []tailcfg.FilterRule @@ -153,7 +152,6 @@ func TestHeadscale_getNamespaceFromEmail(t *testing.T) { dbString: test.fields.dbString, dbType: test.fields.dbType, dbDebug: test.fields.dbDebug, - publicKey: test.fields.publicKey, privateKey: test.fields.privateKey, aclPolicy: test.fields.aclPolicy, aclRules: test.fields.aclRules, From 8e9a94613c0094e308bdcc086e96b15f12a4fda6 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Sun, 28 Nov 2021 11:00:22 +0000 Subject: [PATCH 19/19] Remove outdate integration test private key --- integration_test/etc/private.key | 1 - 1 file changed, 1 deletion(-) delete mode 100644 integration_test/etc/private.key diff --git a/integration_test/etc/private.key b/integration_test/etc/private.key deleted file mode 100644 index b3a3ae6d..00000000 --- a/integration_test/etc/private.key +++ /dev/null @@ -1 +0,0 @@ -SEmQwCu+tGywQWEUsf93TpTRUvlB7WhnCdHgWrSXjEA=