diff --git a/cmd/mkmanifest/main.go b/cmd/mkmanifest/main.go
new file mode 100644
index 000000000..916774a00
--- /dev/null
+++ b/cmd/mkmanifest/main.go
@@ -0,0 +1,52 @@
+// Copyright (c) 2022 Tailscale Inc & AUTHORS All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The mkmanifest command is a simple helper utility to create a '.syso' file
+// that contains a Windows manifest file.
+package main
+
+import (
+ "log"
+ "os"
+
+ "github.com/tc-hib/winres"
+)
+
+func main() {
+ if len(os.Args) != 4 {
+ log.Fatalf("usage: %s arch manifest.xml output.syso", os.Args[0])
+ }
+
+ arch := winres.Arch(os.Args[1])
+ switch arch {
+ case winres.ArchAMD64, winres.ArchARM64, winres.ArchI386, winres.ArchARM:
+ default:
+ log.Fatalf("unsupported arch: %s", arch)
+ }
+
+ manifest, err := os.ReadFile(os.Args[2])
+ if err != nil {
+ log.Fatalf("error reading manifest file %q: %v", os.Args[2], err)
+ }
+
+ out := os.Args[3]
+
+ // Start by creating an empty resource set
+ rs := winres.ResourceSet{}
+
+ // Add resources
+ rs.Set(winres.RT_MANIFEST, winres.ID(1), 0, manifest)
+
+ // Compile to a COFF object file
+ f, err := os.Create(out)
+ if err != nil {
+ log.Fatalf("error creating output file %q: %v", out, err)
+ }
+ if err := rs.WriteObject(f, arch); err != nil {
+ log.Fatalf("error writing object: %v", err)
+ }
+ if err := f.Close(); err != nil {
+ log.Fatalf("error writing output file %q: %v", out, err)
+ }
+}
diff --git a/cmd/tailscale/generate.go b/cmd/tailscale/generate.go
new file mode 100644
index 000000000..e068c1390
--- /dev/null
+++ b/cmd/tailscale/generate.go
@@ -0,0 +1,10 @@
+// Copyright (c) 2022 Tailscale Inc & AUTHORS All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+//go:generate go run tailscale.com/cmd/mkmanifest amd64 windows-manifest.xml manifest_windows_amd64.syso
+//go:generate go run tailscale.com/cmd/mkmanifest 386 windows-manifest.xml manifest_windows_386.syso
+//go:generate go run tailscale.com/cmd/mkmanifest arm64 windows-manifest.xml manifest_windows_arm64.syso
+//go:generate go run tailscale.com/cmd/mkmanifest arm windows-manifest.xml manifest_windows_arm.syso
diff --git a/cmd/tailscale/manifest_windows_386.syso b/cmd/tailscale/manifest_windows_386.syso
new file mode 100644
index 000000000..ac4915862
Binary files /dev/null and b/cmd/tailscale/manifest_windows_386.syso differ
diff --git a/cmd/tailscale/manifest_windows_amd64.syso b/cmd/tailscale/manifest_windows_amd64.syso
new file mode 100644
index 000000000..3a22f2cdf
Binary files /dev/null and b/cmd/tailscale/manifest_windows_amd64.syso differ
diff --git a/cmd/tailscale/manifest_windows_arm.syso b/cmd/tailscale/manifest_windows_arm.syso
new file mode 100644
index 000000000..1a92ede02
Binary files /dev/null and b/cmd/tailscale/manifest_windows_arm.syso differ
diff --git a/cmd/tailscale/manifest_windows_arm64.syso b/cmd/tailscale/manifest_windows_arm64.syso
new file mode 100644
index 000000000..7998b6736
Binary files /dev/null and b/cmd/tailscale/manifest_windows_arm64.syso differ
diff --git a/cmd/tailscale/windows-manifest.xml b/cmd/tailscale/windows-manifest.xml
new file mode 100644
index 000000000..6c5f46058
--- /dev/null
+++ b/cmd/tailscale/windows-manifest.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cmd/tailscaled/generate.go b/cmd/tailscaled/generate.go
new file mode 100644
index 000000000..e068c1390
--- /dev/null
+++ b/cmd/tailscaled/generate.go
@@ -0,0 +1,10 @@
+// Copyright (c) 2022 Tailscale Inc & AUTHORS All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+//go:generate go run tailscale.com/cmd/mkmanifest amd64 windows-manifest.xml manifest_windows_amd64.syso
+//go:generate go run tailscale.com/cmd/mkmanifest 386 windows-manifest.xml manifest_windows_386.syso
+//go:generate go run tailscale.com/cmd/mkmanifest arm64 windows-manifest.xml manifest_windows_arm64.syso
+//go:generate go run tailscale.com/cmd/mkmanifest arm windows-manifest.xml manifest_windows_arm.syso
diff --git a/cmd/tailscaled/manifest_windows_386.syso b/cmd/tailscaled/manifest_windows_386.syso
new file mode 100644
index 000000000..ac4915862
Binary files /dev/null and b/cmd/tailscaled/manifest_windows_386.syso differ
diff --git a/cmd/tailscaled/manifest_windows_amd64.syso b/cmd/tailscaled/manifest_windows_amd64.syso
new file mode 100644
index 000000000..3a22f2cdf
Binary files /dev/null and b/cmd/tailscaled/manifest_windows_amd64.syso differ
diff --git a/cmd/tailscaled/manifest_windows_arm.syso b/cmd/tailscaled/manifest_windows_arm.syso
new file mode 100644
index 000000000..1a92ede02
Binary files /dev/null and b/cmd/tailscaled/manifest_windows_arm.syso differ
diff --git a/cmd/tailscaled/manifest_windows_arm64.syso b/cmd/tailscaled/manifest_windows_arm64.syso
new file mode 100644
index 000000000..7998b6736
Binary files /dev/null and b/cmd/tailscaled/manifest_windows_arm64.syso differ
diff --git a/cmd/tailscaled/windows-manifest.xml b/cmd/tailscaled/windows-manifest.xml
new file mode 100644
index 000000000..6c5f46058
--- /dev/null
+++ b/cmd/tailscaled/windows-manifest.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/go.mod b/go.mod
index 029652aa3..db9791393 100644
--- a/go.mod
+++ b/go.mod
@@ -53,6 +53,7 @@ require (
github.com/tailscale/hujson v0.0.0-20220630195928-54599719472f
github.com/tailscale/mkctr v0.0.0-20220601142259-c0b937af2e89
github.com/tailscale/netlink v1.1.1-0.20211101221916-cabfb018fe85
+ github.com/tc-hib/winres v0.1.6
github.com/tcnksm/go-httpstat v0.2.0
github.com/toqueteos/webbrowser v1.2.0
github.com/u-root/u-root v0.9.1-0.20221111022710-6e9699743f5d
@@ -213,6 +214,7 @@ require (
github.com/moricho/tparallel v0.2.1 // indirect
github.com/nakabonne/nestif v0.3.1 // indirect
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 // indirect
+ github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
github.com/nishanths/exhaustive v0.7.11 // indirect
github.com/nishanths/predeclared v0.2.1 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
@@ -270,6 +272,7 @@ require (
github.com/xanzy/ssh-agent v0.3.1 // indirect
github.com/yeya24/promlinter v0.1.0 // indirect
golang.org/x/exp/typeparams v0.0.0-20220328175248-053ad81199eb // indirect
+ golang.org/x/image v0.0.0-20201208152932-35266b937fa6 // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/text v0.4.0 // indirect
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect
diff --git a/go.sum b/go.sum
index a50720247..f812df4df 100644
--- a/go.sum
+++ b/go.sum
@@ -854,6 +854,8 @@ github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4N
github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 h1:4kuARK6Y6FxaNu/BnU2OAaLF86eTVhP2hjTB6iMvItA=
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8=
+github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
+github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nishanths/exhaustive v0.1.0/go.mod h1:S1j9110vxV1ECdCudXRkeMnFQ/DQk9ajLT0Uf2MYZQQ=
github.com/nishanths/exhaustive v0.2.3/go.mod h1:bhIX678Nx8inLM9PbpvK1yv6oGtoP8BfaIeMzgBNKvc=
@@ -1104,6 +1106,8 @@ github.com/tailscale/mkctr v0.0.0-20220601142259-c0b937af2e89 h1:7xU7AFQE83h0wz/
github.com/tailscale/mkctr v0.0.0-20220601142259-c0b937af2e89/go.mod h1:OGMqrTzDqmJkGumUTtOv44Rp3/4xS+QFbE8Rn0AGlaU=
github.com/tailscale/netlink v1.1.1-0.20211101221916-cabfb018fe85 h1:zrsUcqrG2uQSPhaUPjUQwozcRdDdSxxqhNgNZ3drZFk=
github.com/tailscale/netlink v1.1.1-0.20211101221916-cabfb018fe85/go.mod h1:NzVQi3Mleb+qzq8VmcWpSkcSYxXIg0DkI6XDzpVkhJ0=
+github.com/tc-hib/winres v0.1.6 h1:qgsYHze+BxQPEYilxIz/KCQGaClvI2+yLBAZs+3+0B8=
+github.com/tc-hib/winres v0.1.6/go.mod h1:pe6dOR40VOrGz8PkzreVKNvEKnlE8t4yR8A8naL+t7A=
github.com/tcnksm/go-httpstat v0.2.0 h1:rP7T5e5U2HfmOBmZzGgGZjBQ5/GluWUylujl0tJ04I0=
github.com/tcnksm/go-httpstat v0.2.0/go.mod h1:s3JVJFtQxtBEBC9dwcdTTXS9xFnM3SXAZwPG41aurT8=
github.com/tdakkota/asciicheck v0.0.0-20200416190851-d7f85be797a2/go.mod h1:yHp0ai0Z9gUljN3o0xMhYJnH/IcvkdTBOX2fmJ93JEM=
@@ -1280,6 +1284,8 @@ golang.org/x/exp/typeparams v0.0.0-20220328175248-053ad81199eb h1:fP6C8Xutcp5Ala
golang.org/x/exp/typeparams v0.0.0-20220328175248-053ad81199eb/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/image v0.0.0-20201208152932-35266b937fa6 h1:nfeHNc1nAqecKCy2FCy4HY+soOOe5sDLJ/gZLbx6GYI=
+golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=