Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ builds:
# internal/buildtags.ReleaseTags, which a test enforces.
# Regenerate with: go run ./internal/buildtags/printtags
flags:
- -tags=ts_omit_ace,ts_omit_acme,ts_omit_advertiseexitnode,ts_omit_advertiseroutes,ts_omit_appconnectors,ts_omit_aws,ts_omit_bird,ts_omit_cachenetmap,ts_omit_captiveportal,ts_omit_capture,ts_omit_cliconndiag,ts_omit_clientmetrics,ts_omit_clientupdate,ts_omit_cloud,ts_omit_colorable,ts_omit_completion,ts_omit_completion_scripts,ts_omit_conn25,ts_omit_connreject,ts_omit_debug,ts_omit_debugeventbus,ts_omit_debugportmapper,ts_omit_desktop_sessions,ts_omit_dns,ts_omit_dnsresolvecache,ts_omit_doctor,ts_omit_drive,ts_omit_favorites,ts_omit_flashappliance,ts_omit_health,ts_omit_hujsonconf,ts_omit_identityfederation,ts_omit_ipnbus,ts_omit_iptables,ts_omit_kube,ts_omit_linkspeed,ts_omit_linuxdnsfight,ts_omit_listenrawdisco,ts_omit_logtail,ts_omit_netlog,ts_omit_networkmanager,ts_omit_oauthkey,ts_omit_osrouter,ts_omit_outboundproxy,ts_omit_peerapiclient,ts_omit_peerapiserver,ts_omit_portlist,ts_omit_portmapper,ts_omit_posture,ts_omit_qrcodes,ts_omit_relayserver,ts_omit_remoteconfig,ts_omit_resolved,ts_omit_routecheck,ts_omit_runtimemetrics,ts_omit_sdnotify,ts_omit_serve,ts_omit_serviceclientprefs,ts_omit_synology,ts_omit_syslog,ts_omit_syspolicy,ts_omit_systray,ts_omit_taildrop,ts_omit_tailnetlock,ts_omit_tap,ts_omit_tpm,ts_omit_tundevstats,ts_omit_unixsocketidentity,ts_omit_useexitnode,ts_omit_useproxy,ts_omit_usermetrics,ts_omit_useroutes,ts_omit_wakeonlan,ts_omit_webbrowser,ts_omit_webclient
- -tags=ts_omit_ace,ts_omit_acme,ts_omit_advertiseexitnode,ts_omit_advertiseroutes,ts_omit_appconnectors,ts_omit_aws,ts_omit_bird,ts_omit_cachenetmap,ts_omit_captiveportal,ts_omit_capture,ts_omit_cliconndiag,ts_omit_clientmetrics,ts_omit_clientupdate,ts_omit_cloud,ts_omit_colorable,ts_omit_completion,ts_omit_completion_scripts,ts_omit_conn25,ts_omit_connreject,ts_omit_debug,ts_omit_debugeventbus,ts_omit_debugportmapper,ts_omit_desktop_sessions,ts_omit_dns,ts_omit_dnsresolvecache,ts_omit_doctor,ts_omit_drive,ts_omit_exitnodehealth,ts_omit_favorites,ts_omit_flashappliance,ts_omit_health,ts_omit_hujsonconf,ts_omit_identityfederation,ts_omit_ipnbus,ts_omit_iptables,ts_omit_kube,ts_omit_linkspeed,ts_omit_linuxdnsfight,ts_omit_listenrawdisco,ts_omit_logtail,ts_omit_netlog,ts_omit_networkmanager,ts_omit_oauthkey,ts_omit_osrouter,ts_omit_outboundproxy,ts_omit_peerapiclient,ts_omit_peerapiserver,ts_omit_portlist,ts_omit_portmapper,ts_omit_posture,ts_omit_qrcodes,ts_omit_relayserver,ts_omit_remoteconfig,ts_omit_resolved,ts_omit_routecheck,ts_omit_runtimemetrics,ts_omit_sdnotify,ts_omit_serve,ts_omit_serviceclientprefs,ts_omit_synology,ts_omit_syslog,ts_omit_syspolicy,ts_omit_systray,ts_omit_taildrop,ts_omit_tailnetlock,ts_omit_tap,ts_omit_tpm,ts_omit_tundevstats,ts_omit_unixsocketidentity,ts_omit_useexitnode,ts_omit_useproxy,ts_omit_usermetrics,ts_omit_useroutes,ts_omit_wakeonlan,ts_omit_webbrowser,ts_omit_webclient
goos:
- linux
- windows
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

## Unreleased

- New experimental `tailcat serve --hybrid` flag (and `Server.Hybrid`
in the Go API) uses wireguard-go's hybrid post-quantum (ML-KEM-768)
WireGuard handshake, whose post-quantum protection doesn't depend on
the tailcat address staying secret. Hybrid addresses say so, so
clients use the hybrid handshake too, and carry a shorter 128-bit
pre-shared key, so they're shorter. Older clients reject hybrid
addresses. ([#133](https://github.com/tailscale/tailcat/issues/133))
- **Breaking Go API change:** `Server.AllowedClients` and
`Server.AddAllowedClient` are replaced by the `Server.AllowClient`
hook, a `func(key.NodePublic) bool` asked about each client as it
Expand Down
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,16 @@ compatibility with tailcat clients v0.5.0 and earlier, `--psk=false` on `serve`
or `genkey` produces shorter addresses, but removes post-quantum protection and
protection from public DERP operators that observe the peers' public keys.

The pre-shared key's post-quantum protection only lasts while the address
stays secret. The experimental `tailcat serve --hybrid` flag instead uses
a hybrid post-quantum (ML-KEM-768) WireGuard handshake, which protects
recorded traffic even when the address is public, such as in a DNS TXT
record. A hybrid address still contains a pre-shared key by default, to
keep out DERP operators, but a shorter 128-bit one, so the address is
shorter too.
Clients need a tailcat version with hybrid support; older clients reject
hybrid addresses.

```sh
$ tailcat genkey --key=default --region=nyc
# prints the tailcat address; key saved to ~/.config/tailcat/keys/default.private.json
Expand Down Expand Up @@ -706,8 +716,10 @@ followed by base64-encoded [CBOR](https://cbor.io/) containing:
- A separate path-discovery public key (Curve25519, 32 bytes)
- By default, an independent WireGuard pre-shared key (256 random bits),
which prevents a DERP operator that observes the peers' public keys from
joining the tunnel and provides post-quantum protection against recorded
traffic
joining the tunnel and, while the address stays secret, provides
post-quantum protection against recorded traffic
- With `serve --hybrid` (experimental), a flag saying to use the hybrid
post-quantum WireGuard handshake, and only 128 bits of pre-shared key
- DERP info. Either:
1. a small integer referencing one of the default [Tailscale-run tailcat servers](https://tailcat.dev/derpmap.json), or
2. full DERP server metadata, to either use a custom DERP server, or to avoid the client needing a potential round-trip to fetch the latest DERP map (the `tailcat serve --full-address` flag and the `tailcat resolve` subcommand produce this form)
Expand Down
2 changes: 1 addition & 1 deletion build-tags.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
ts_omit_ace,ts_omit_acme,ts_omit_advertiseexitnode,ts_omit_advertiseroutes,ts_omit_appconnectors,ts_omit_aws,ts_omit_bird,ts_omit_cachenetmap,ts_omit_captiveportal,ts_omit_capture,ts_omit_cliconndiag,ts_omit_clientmetrics,ts_omit_clientupdate,ts_omit_cloud,ts_omit_colorable,ts_omit_completion,ts_omit_completion_scripts,ts_omit_conn25,ts_omit_connreject,ts_omit_debug,ts_omit_debugeventbus,ts_omit_debugportmapper,ts_omit_desktop_sessions,ts_omit_dns,ts_omit_dnsresolvecache,ts_omit_doctor,ts_omit_drive,ts_omit_favorites,ts_omit_flashappliance,ts_omit_health,ts_omit_hujsonconf,ts_omit_identityfederation,ts_omit_ipnbus,ts_omit_iptables,ts_omit_kube,ts_omit_linkspeed,ts_omit_linuxdnsfight,ts_omit_listenrawdisco,ts_omit_logtail,ts_omit_netlog,ts_omit_networkmanager,ts_omit_oauthkey,ts_omit_osrouter,ts_omit_outboundproxy,ts_omit_peerapiclient,ts_omit_peerapiserver,ts_omit_portlist,ts_omit_portmapper,ts_omit_posture,ts_omit_qrcodes,ts_omit_relayserver,ts_omit_remoteconfig,ts_omit_resolved,ts_omit_routecheck,ts_omit_runtimemetrics,ts_omit_sdnotify,ts_omit_serve,ts_omit_serviceclientprefs,ts_omit_synology,ts_omit_syslog,ts_omit_syspolicy,ts_omit_systray,ts_omit_taildrop,ts_omit_tailnetlock,ts_omit_tap,ts_omit_tpm,ts_omit_tundevstats,ts_omit_unixsocketidentity,ts_omit_useexitnode,ts_omit_useproxy,ts_omit_usermetrics,ts_omit_useroutes,ts_omit_wakeonlan,ts_omit_webbrowser,ts_omit_webclient
ts_omit_ace,ts_omit_acme,ts_omit_advertiseexitnode,ts_omit_advertiseroutes,ts_omit_appconnectors,ts_omit_aws,ts_omit_bird,ts_omit_cachenetmap,ts_omit_captiveportal,ts_omit_capture,ts_omit_cliconndiag,ts_omit_clientmetrics,ts_omit_clientupdate,ts_omit_cloud,ts_omit_colorable,ts_omit_completion,ts_omit_completion_scripts,ts_omit_conn25,ts_omit_connreject,ts_omit_debug,ts_omit_debugeventbus,ts_omit_debugportmapper,ts_omit_desktop_sessions,ts_omit_dns,ts_omit_dnsresolvecache,ts_omit_doctor,ts_omit_drive,ts_omit_exitnodehealth,ts_omit_favorites,ts_omit_flashappliance,ts_omit_health,ts_omit_hujsonconf,ts_omit_identityfederation,ts_omit_ipnbus,ts_omit_iptables,ts_omit_kube,ts_omit_linkspeed,ts_omit_linuxdnsfight,ts_omit_listenrawdisco,ts_omit_logtail,ts_omit_netlog,ts_omit_networkmanager,ts_omit_oauthkey,ts_omit_osrouter,ts_omit_outboundproxy,ts_omit_peerapiclient,ts_omit_peerapiserver,ts_omit_portlist,ts_omit_portmapper,ts_omit_posture,ts_omit_qrcodes,ts_omit_relayserver,ts_omit_remoteconfig,ts_omit_resolved,ts_omit_routecheck,ts_omit_runtimemetrics,ts_omit_sdnotify,ts_omit_serve,ts_omit_serviceclientprefs,ts_omit_synology,ts_omit_syslog,ts_omit_syspolicy,ts_omit_systray,ts_omit_taildrop,ts_omit_tailnetlock,ts_omit_tap,ts_omit_tpm,ts_omit_tundevstats,ts_omit_unixsocketidentity,ts_omit_useexitnode,ts_omit_useproxy,ts_omit_usermetrics,ts_omit_useroutes,ts_omit_wakeonlan,ts_omit_webbrowser,ts_omit_webclient
4 changes: 2 additions & 2 deletions cmd/tailcat/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func TestHelpListsCommandTree(t *testing.T) {
// Server-only flags live on the serve subcommand, not the root.
// (The long help prose may still mention them; only reject them
// as rendered flag entries.)
for _, notWant := range []string{"\n --allow", "\n --full-address", "\n --psk", "\n --ssh-authorized-keys"} {
for _, notWant := range []string{"\n --allow", "\n --full-address", "\n --psk", "\n --hybrid", "\n --ssh-authorized-keys"} {
if strings.Contains(help, notWant) {
t.Errorf("root help lists server-only flag %q", strings.TrimSpace(notWant))
}
Expand All @@ -99,7 +99,7 @@ func TestServeHelpListsServerFlags(t *testing.T) {
t.Fatal("no serve subcommand")
}
help := ffhelp.Command(serve).String()
for _, want := range []string{"--allow", "--full-address", "--key", "--psk", "--ssh-authorized-keys"} {
for _, want := range []string{"--allow", "--full-address", "--hybrid", "--key", "--psk", "--ssh-authorized-keys"} {
if !strings.Contains(help, want) {
t.Errorf("serve help is missing %q", want)
}
Expand Down
31 changes: 31 additions & 0 deletions cmd/tailcat/serve_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,37 @@ func TestServeWithoutPSK(t *testing.T) {
}
}

func TestServeHybrid(t *testing.T) {
for _, psk := range []bool{true, false} {
t.Run(fmt.Sprintf("psk=%v", psk), func(t *testing.T) {
t.Parallel()
e := newTestEnv(t)
port := startEchoListener(t)
_, addr, serverStderr := e.startServer("serve", "--hybrid", fmt.Sprintf("--psk=%v", psk), strconv.Itoa(int(port)))

ci, err := tailcat.ParseAddr(tailcat.Addr(addr))
if err != nil {
t.Fatal(err)
}
if !ci.Hybrid {
t.Fatal("serve --hybrid produced a non-hybrid address")
}
if got := !ci.PresharedKey.IsZero(); got != psk {
t.Fatalf("address has PSK = %v; want %v", got, psk)
}

const payload = "echo over a hybrid handshake"
got, err := runClient(t, e.cmd("--key=new", "--derpmap-url="+e.derpMapURL, addr, strconv.Itoa(int(port))), serverStderr, payload)
if err != nil {
t.Fatalf("client to hybrid server: %v", err)
}
if got != payload {
t.Errorf("server echoed %q; want %q", got, payload)
}
})
}
}

func TestServeRemembersSavedKeyWithoutPSK(t *testing.T) {
t.Parallel()
e := newTestEnv(t)
Expand Down
8 changes: 7 additions & 1 deletion cmd/tailcat/tailcat.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ var (
flagFiles *string
flagSSHAuthorizedKeys *string
flagPSK *bool
flagHybrid *bool
flagVerbose *bool
flagFullAddress *bool
flagJSON *bool
Expand Down Expand Up @@ -105,6 +106,7 @@ func newRootCommand() *ff.Command {
flagFiles = serveFS.StringLong("files", "", "directory to serve to SFTP clients (scp, sftp) with the 'files' service, with an optional :ro (read-only, the default), :rw (read-write), :wo (flat write-only drop box), or :wo+ (recursive write-only drop box) suffix. If empty, the current directory is served read-only. Giving --files implies the 'files' service.")
flagSSHAuthorizedKeys = serveFS.StringLong("ssh-authorized-keys", "", "comma-separated SSH public key sources for the 'ssh' service: authorized_keys file paths, literal OpenSSH public key lines, or names like 'alice@github' (fetched from https://github.com/alice.keys). All sources are loaded and validated at startup.")
flagPSK = serveFS.BoolLongDefault("psk", true, "include a WireGuard pre-shared key in the tailcat address (recommended). Set false only for shorter addresses and compatibility with tailcat clients v0.5.0 and earlier; this weakens security.")
flagHybrid = serveFS.BoolLong("hybrid", "EXPERIMENTAL: use the hybrid post-quantum (ML-KEM-768) WireGuard handshake, which doesn't depend on the tailcat address staying secret for its post-quantum protection. The address is shorter, with a 128-bit pre-shared key, but only works with clients that support the hybrid handshake; older clients reject it.")

recvFS := ff.NewFlagSet("recv").SetParent(serveFS)
flagRecvAcceptDirs := recvFS.BoolLong("accept-dirs", "accept directory trees (tailcat cp -r), keeping requested file names when available. The trade-off: senders can then make and stat directories and learn whether some names already exist in the drop box. The default flat mode reveals nothing about existing files, but accepts only single files, each saved under a server-chosen unique name.")
Expand Down Expand Up @@ -1362,6 +1364,9 @@ func server(logf logger.Logf, serveSpec string, execArgs []string) {
ci.PresharedKey = tailcat.PresharedKey{}
}
psk := ci.PresharedKey
if *flagHybrid {
psk = psk.ForHybrid()
}
if reg == nil {
// A key created with custom DERP hostnames (genkey --region=<host>)
// has pre-populated regions with no DERP map ID to reference, so its
Expand Down Expand Up @@ -1393,9 +1398,10 @@ func server(logf logger.Logf, serveSpec string, execArgs []string) {
}
ci.ServerPublic = tailcat.NodePublic{NodePublic: priv.Public()}
ci.ServerDiscoPublic = tailcat.DiscoPublicForNode(priv)
ci.Hybrid = *flagHybrid
connStr := ci.Addr()

s := &tailcat.Server{Key: priv, PresharedKey: psk, DisablePresharedKey: !usePSK, Logf: logf, Region: reg}
s := &tailcat.Server{Key: priv, PresharedKey: psk, DisablePresharedKey: !usePSK, Hybrid: *flagHybrid, Logf: logf, Region: reg}
sshServices := services.Contains("ssh") || services.Contains("no-auth-ssh") || services.Contains("files")
if sshServices && !tailcat.SupportsSSHServer() {
log.Fatalf("Tailscale SSH server not supported on %v", runtime.GOOS)
Expand Down
2 changes: 1 addition & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,4 @@
};
});
}
# nix-direnv cache busting line: sha256-E3vBmBO4K4REDf62ztSLzvko9kKGeLz5efCv2HGi/3M=
# nix-direnv cache busting line: sha256-QIVRQZ1SsWoRAzmY8oTCelk2EINTqkrUEcnyq2BEUms=
4 changes: 2 additions & 2 deletions flakehashes.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"vendor": {
"goModSum": "sha256-XQZn3hG/2N0/tWNeQlOeMjln9p6g/lewLpplCd+/n8A=",
"sri": "sha256-E3vBmBO4K4REDf62ztSLzvko9kKGeLz5efCv2HGi/3M="
"goModSum": "sha256-z79SW4OXVGw7okhwQm6cZh94gg4rzrNei2QAzc5YqN0=",
"sri": "sha256-QIVRQZ1SsWoRAzmY8oTCelk2EINTqkrUEcnyq2BEUms="
}
}
52 changes: 27 additions & 25 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/tailscale/tailcat

go 1.27.1
go 1.27.3

require (
github.com/chromedp/cdproto v0.0.0-20260714215040-dc233986426f
Expand All @@ -11,18 +11,18 @@ require (
github.com/klauspost/compress v1.20.0
github.com/peterbourgon/ff/v4 v4.0.0-beta.1
github.com/pkg/sftp v1.13.11
github.com/tailscale/gliderssh v0.3.4-0.20260716005906-1a0f895faf28
github.com/tailscale/wireguard-go v0.0.0-20260924224943-0a83b87f7908
github.com/tailscale/gliderssh v0.3.4-0.20261026144310-31f7cf365d3a
github.com/tailscale/wireguard-go v0.0.0-20261102205419-b884e294b6d8
github.com/toqueteos/webbrowser v1.2.1
github.com/u-root/u-root v0.16.0
go4.org/mem v0.0.0-20240501181205-ae6ca9944745
go4.org/netipx v0.0.0-20260823151212-3075585bcbeb
golang.org/x/crypto v0.57.0
golang.org/x/crypto v0.58.0
golang.org/x/exp v0.0.0-20260908205506-85c1c2202aba
golang.org/x/net v0.59.0
golang.org/x/sys v0.48.0
golang.org/x/net v0.62.0
golang.org/x/sys v0.49.0
gvisor.dev/gvisor v0.0.0-20260915211658-a6f909f08a72
tailscale.com v1.103.0-pre.0.20260929142145-a0e471a35b8f
tailscale.com v1.105.0-pre.0.20261103181955-911d8f84a054
)

require (
Expand All @@ -32,22 +32,24 @@ require (
github.com/akutz/memconn v0.1.0 // indirect
github.com/alexbrainman/sspi v0.0.0-20250919150558-7d374ff0d59e // indirect
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
github.com/aws/aws-sdk-go-v2 v1.46.0 // indirect
github.com/aws/aws-sdk-go-v2/config v1.33.3 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.20.3 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.19.2 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.5.2 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.8.2 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.5.2 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.19 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.14.2 // indirect
github.com/aws/aws-sdk-go-v2/service/signin v1.9.0 // indirect
github.com/aws/aws-sdk-go-v2 v1.47.3 // indirect
github.com/aws/aws-sdk-go-v2/config v1.33.9 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.20.9 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.20.3 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.5.6 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.8.6 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.5.6 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.21 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.14.6 // indirect
github.com/aws/aws-sdk-go-v2/service/signin v1.10.4 // indirect
github.com/aws/aws-sdk-go-v2/service/ssm v1.77.0 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.37.0 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.42.0 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.49.0 // indirect
github.com/aws/smithy-go v1.28.1 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.38.4 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.43.4 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.51.4 // indirect
github.com/aws/smithy-go v1.28.5 // indirect
github.com/axiomhq/hyperloglog v0.2.6 // indirect
github.com/benbjohnson/immutable v0.4.3 // indirect
github.com/bradfitz/reco v0.0.0-20260929154613-b883fbd17e3f // indirect
github.com/chromedp/sysutil v1.1.0 // indirect
github.com/coder/websocket v1.8.15 // indirect
github.com/coreos/go-iptables v0.8.0 // indirect
Expand Down Expand Up @@ -100,11 +102,11 @@ require (
github.com/x448/float16 v0.8.4 // indirect
golang.org/x/exp/typeparams v0.0.0-20260811152304-ee035b5b010f // indirect
golang.org/x/mod v0.41.0 // indirect
golang.org/x/sync v0.23.0 // indirect
golang.org/x/term v0.46.0 // indirect
golang.org/x/text v0.42.0 // indirect
golang.org/x/sync v0.24.0 // indirect
golang.org/x/term v0.47.0 // indirect
golang.org/x/text v0.43.0 // indirect
golang.org/x/time v0.16.0 // indirect
golang.org/x/tools v0.50.0 // indirect
golang.org/x/tools v0.51.0 // indirect
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
golang.zx2c4.com/wireguard/windows v1.0.1 // indirect
honnef.co/go/tools v0.8.1 // indirect
Expand Down
Loading
Loading