From 67851c64af0c83cdbf7351ac0b3ad12bf66e5be3 Mon Sep 17 00:00:00 2001 From: Eugene K Date: Thu, 11 Apr 2024 08:25:44 -0400 Subject: [PATCH] wire up vpn backend --- cmd/zrok/reserve.go | 10 +++- cmd/zrok/sharePrivate.go | 28 +++++++++- cmd/zrok/shareReserved.go | 23 ++++++++ endpoints/vpn/backend.go | 112 ++++++++++++++++++++++++++++++++++++++ endpoints/vpn/vpn.go | 9 +++ go.mod | 11 ++++ go.sum | 23 ++++++++ 7 files changed, 212 insertions(+), 4 deletions(-) create mode 100644 endpoints/vpn/backend.go create mode 100644 endpoints/vpn/vpn.go diff --git a/cmd/zrok/reserve.go b/cmd/zrok/reserve.go index 53341779..ab797059 100644 --- a/cmd/zrok/reserve.go +++ b/cmd/zrok/reserve.go @@ -40,7 +40,7 @@ func newReserveCommand() *reserveCommand { command := &reserveCommand{cmd: cmd} cmd.Flags().StringVarP(&command.uniqueName, "unique-name", "n", "", "A unique name for the reserved share (defaults to generated identifier)") cmd.Flags().StringArrayVar(&command.frontendSelection, "frontends", []string{"public"}, "Selected frontends to use for the share") - cmd.Flags().StringVarP(&command.backendMode, "backend-mode", "b", "proxy", "The backend mode (public|private: proxy, web, caddy, drive) (private: tcpTunnel, udpTunnel, socks)") + cmd.Flags().StringVarP(&command.backendMode, "backend-mode", "b", "proxy", "The backend mode (public|private: proxy, web, caddy, drive) (private: tcpTunnel, udpTunnel, socks, vpn)") cmd.Flags().BoolVarP(&command.jsonOutput, "json-output", "j", false, "Emit JSON describing the created reserved share") cmd.Flags().StringArrayVar(&command.basicAuth, "basic-auth", []string{}, "Basic authentication users (,...)") cmd.Flags().StringVar(&command.oauthProvider, "oauth-provider", "", "Enable OAuth provider [google, github]") @@ -56,7 +56,7 @@ func newReserveCommand() *reserveCommand { func (cmd *reserveCommand) run(_ *cobra.Command, args []string) { shareMode := sdk.ShareMode(args[0]) - privateOnlyModes := []string{"tcpTunnel", "udpTunnel", "socks"} + privateOnlyModes := []string{"tcpTunnel", "udpTunnel", "socks", "vpn"} if shareMode != sdk.PublicShareMode && shareMode != sdk.PrivateShareMode { tui.Error("invalid sharing mode; expecting 'public' or 'private'", nil) } else if shareMode == sdk.PublicShareMode && slices.Contains(privateOnlyModes, cmd.backendMode) { @@ -114,8 +114,12 @@ func (cmd *reserveCommand) run(_ *cobra.Command, args []string) { tui.Error("the 'socks' backend mode does not expect ", nil) } + case "vpn": + target = "vpn" + default: - tui.Error(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web, tcpTunnel, udpTunnel, caddy, drive, socks}", cmd.backendMode), nil) + tui.Error(fmt.Sprintf("invalid backend mode '%v'; "+ + "expected {proxy, web, tcpTunnel, udpTunnel, caddy, drive, socks, vpn}", cmd.backendMode), nil) } env, err := environment.LoadRoot() diff --git a/cmd/zrok/sharePrivate.go b/cmd/zrok/sharePrivate.go index cdc4c7fc..f327de81 100644 --- a/cmd/zrok/sharePrivate.go +++ b/cmd/zrok/sharePrivate.go @@ -9,6 +9,7 @@ import ( "github.com/openziti/zrok/endpoints/socks" "github.com/openziti/zrok/endpoints/tcpTunnel" "github.com/openziti/zrok/endpoints/udpTunnel" + "github.com/openziti/zrok/endpoints/vpn" "github.com/openziti/zrok/environment" "github.com/openziti/zrok/environment/env_core" "github.com/openziti/zrok/sdk/golang/sdk" @@ -42,7 +43,7 @@ func newSharePrivateCommand() *sharePrivateCommand { } command := &sharePrivateCommand{cmd: cmd} cmd.Flags().StringArrayVar(&command.basicAuth, "basic-auth", []string{}, "Basic authentication users (,...") - cmd.Flags().StringVarP(&command.backendMode, "backend-mode", "b", "proxy", "The backend mode {proxy, web, tcpTunnel, udpTunnel, caddy, drive, socks}") + cmd.Flags().StringVarP(&command.backendMode, "backend-mode", "b", "proxy", "The backend mode {proxy, web, tcpTunnel, udpTunnel, caddy, drive, socks, vpn}") cmd.Flags().BoolVar(&command.headless, "headless", false, "Disable TUI and run headless") cmd.Flags().BoolVar(&command.insecure, "insecure", false, "Enable insecure TLS certificate validation for ") cmd.Flags().BoolVar(&command.closed, "closed", false, "Enable closed permission mode (see --access-grant)") @@ -105,6 +106,9 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) { } target = "socks" + case "vpn": + target = "vpn" + default: tui.Error(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web, tcpTunnel, udpTunnel, caddy, drive}", cmd.backendMode), nil) } @@ -318,6 +322,28 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) { } }() + case "vpn": + cfg := &vpn.BackendConfig{ + IdentityPath: zif, + EndpointAddress: target, + ShrToken: shr.Token, + RequestsChan: requests, + } + + be, err := vpn.NewBackend(cfg) + if err != nil { + if !panicInstead { + tui.Error("error creating VPN backend", err) + } + panic(err) + } + + go func() { + if err := be.Run(); err != nil { + logrus.Errorf("error running VPN backend: %v", err) + } + }() + default: tui.Error("invalid backend mode", nil) } diff --git a/cmd/zrok/shareReserved.go b/cmd/zrok/shareReserved.go index 8275f198..294f203a 100644 --- a/cmd/zrok/shareReserved.go +++ b/cmd/zrok/shareReserved.go @@ -10,6 +10,7 @@ import ( "github.com/openziti/zrok/endpoints/socks" "github.com/openziti/zrok/endpoints/tcpTunnel" "github.com/openziti/zrok/endpoints/udpTunnel" + "github.com/openziti/zrok/endpoints/vpn" "github.com/openziti/zrok/environment" "github.com/openziti/zrok/rest_client_zrok/metadata" "github.com/openziti/zrok/rest_client_zrok/share" @@ -282,6 +283,28 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) { } }() + case "vpn": + cfg := &vpn.BackendConfig{ + IdentityPath: zif, + EndpointAddress: target, + ShrToken: shrToken, + RequestsChan: requests, + } + + be, err := vpn.NewBackend(cfg) + if err != nil { + if !panicInstead { + tui.Error("error creating VPN backend", err) + } + panic(err) + } + + go func() { + if err := be.Run(); err != nil { + logrus.Errorf("error running VPN backend: %v", err) + } + }() + default: tui.Error("invalid backend mode", nil) } diff --git a/endpoints/vpn/backend.go b/endpoints/vpn/backend.go new file mode 100644 index 00000000..aeebd0eb --- /dev/null +++ b/endpoints/vpn/backend.go @@ -0,0 +1,112 @@ +package vpn + +import ( + "encoding/json" + "fmt" + _ "github.com/net-byte/vtun/tun" + "github.com/openziti/sdk-golang/ziti" + "github.com/openziti/sdk-golang/ziti/edge" + "github.com/openziti/zrok/endpoints" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "github.com/songgao/water/waterutil" + "net" + "time" +) + +type BackendConfig struct { + IdentityPath string + EndpointAddress string + ShrToken string + RequestsChan chan *endpoints.Request +} + +type Backend struct { + cfg *BackendConfig + listener edge.Listener + + cidr net.IPAddr +} + +func NewBackend(cfg *BackendConfig) (*Backend, error) { + + options := ziti.ListenOptions{ + ConnectTimeout: 5 * time.Minute, + WaitForNEstablishedListeners: 1, + } + zcfg, err := ziti.NewConfigFromFile(cfg.IdentityPath) + if err != nil { + return nil, errors.Wrap(err, "error loading config") + } + zctx, err := ziti.NewContext(zcfg) + if err != nil { + return nil, errors.Wrap(err, "error loading ziti context") + } + listener, err := zctx.ListenWithOptions(cfg.ShrToken, &options) + if err != nil { + return nil, errors.Wrap(err, "error listening") + } + b := &Backend{ + cfg: cfg, + listener: listener, + } + return b, nil +} + +func (b *Backend) Run() error { + logrus.Info("started") + defer logrus.Info("exited") + + for { + if conn, err := b.listener.Accept(); err == nil { + go b.handle(conn) + } else { + return err + } + } +} + +type ipProto waterutil.IPProtocol + +func (p ipProto) String() string { + switch p { + case waterutil.TCP: + return "tcp" + case waterutil.UDP: + return "udp" + case waterutil.ICMP: + return "icmp" + default: + return fmt.Sprintf("proto[%d]", p) + } +} + +func (b *Backend) handle(conn net.Conn) { + defer func(conn net.Conn) { + _ = conn.Close() + }(conn) + + cfg := &ClientConfig{ + Greeting: "Welcome to zrok VPN", + } + j, err := json.Marshal(&cfg) + if err != nil { + return + } + conn.Write(j) + + buf := make([]byte, 16*1024) + for { + read, err := conn.Read(buf) + if err != nil { + logrus.Error("read error", err) + return + } + pkt := buf[:read] + logrus.Infof("read packet %d bytes %v %v:%v -> %v:%v", read, + ipProto(waterutil.IPv4Protocol(pkt)), + waterutil.IPv4Source(pkt), waterutil.IPv4SourcePort(pkt), + waterutil.IPv4Destination(pkt), waterutil.IPv4DestinationPort(pkt)) + + } +} diff --git a/endpoints/vpn/vpn.go b/endpoints/vpn/vpn.go new file mode 100644 index 00000000..e555d3bb --- /dev/null +++ b/endpoints/vpn/vpn.go @@ -0,0 +1,9 @@ +package vpn + +type ClientConfig struct { + Greeting string + IP string + CIDR string + ServerIP string + Routes []string +} diff --git a/go.mod b/go.mod index 4bbd7b04..13c9c29b 100644 --- a/go.mod +++ b/go.mod @@ -30,6 +30,7 @@ require ( github.com/michaelquigley/cf v0.0.13 github.com/michaelquigley/pfxlog v0.6.10 github.com/muesli/reflow v0.3.0 + github.com/net-byte/vtun v1.7.0 github.com/nxadm/tail v1.4.8 github.com/openziti/channel/v2 v2.0.121 github.com/openziti/edge-api v0.26.12 @@ -42,6 +43,7 @@ require ( github.com/rubenv/sql-migrate v1.6.0 github.com/shirou/gopsutil/v3 v3.24.1 github.com/sirupsen/logrus v1.9.3 + github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 github.com/spf13/cobra v1.8.0 github.com/stretchr/testify v1.9.0 github.com/wneessen/go-mail v0.2.7 @@ -107,6 +109,9 @@ require ( github.com/go-resty/resty/v2 v2.11.0 // indirect github.com/go-sql-driver/mysql v1.7.1 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/gobwas/httphead v0.1.0 // indirect + github.com/gobwas/pool v0.2.1 // indirect + github.com/gobwas/ws v1.1.0 // indirect github.com/golang/glog v1.1.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.4 // indirect @@ -123,6 +128,7 @@ require ( github.com/imdario/mergo v0.3.13 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect + github.com/inhies/go-bytesize v0.0.0-20210819104631-275770b98743 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect github.com/jackc/pgconn v1.14.0 // indirect github.com/jackc/pgio v1.0.0 // indirect @@ -159,6 +165,8 @@ require ( github.com/muesli/cancelreader v0.2.2 // indirect github.com/muesli/termenv v0.13.0 // indirect github.com/muhlemmer/gu v0.3.1 // indirect + github.com/net-byte/go-gateway v0.0.2 // indirect + github.com/net-byte/water v0.0.7 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/onsi/ginkgo/v2 v2.9.5 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect @@ -230,6 +238,9 @@ require ( golang.org/x/term v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/tools v0.13.0 // indirect + golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect + golang.zx2c4.com/wireguard v0.0.0-20220703234212-c31a7b1ab478 // indirect + golang.zx2c4.com/wireguard/windows v0.5.3 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect diff --git a/go.sum b/go.sum index c0a39e55..e37bc2e7 100644 --- a/go.sum +++ b/go.sum @@ -301,6 +301,12 @@ github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEe github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= +github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= +github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= +github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA= +github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= @@ -481,6 +487,8 @@ github.com/influxdata/influxdb-client-go/v2 v2.11.0/go.mod h1:YteV91FiQxRdccyJ2c github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7wlPfJLvMCdtV4zPulc4uCPrlywQOmbFOhgQNU= github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= +github.com/inhies/go-bytesize v0.0.0-20210819104631-275770b98743 h1:X3Xxno5Ji8idrNiUoFc7QyXpqhSYlDRYQmc7mlpMBzU= +github.com/inhies/go-bytesize v0.0.0-20210819104631-275770b98743/go.mod h1:KrtyD5PFj++GKkFS/7/RRrfnRhAMGQwy75GLCHWrCNs= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= @@ -704,6 +712,12 @@ github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzE github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/net-byte/go-gateway v0.0.2 h1:xNB7CqWh7js6PB/xOochjyJlDHl6sZthhPSoJdxwoLY= +github.com/net-byte/go-gateway v0.0.2/go.mod h1:+NvPbRjN64RUYvm6xtRBUswoAXKAe44Y/PfWtWMgwwY= +github.com/net-byte/vtun v1.7.0 h1:mt8sUKbFPbl5pc0EXeRFl5zCKXr3QCaSYZp7raGd5y0= +github.com/net-byte/vtun v1.7.0/go.mod h1:SVFWdwuyvV7BRyeyiaay7HfWor6se5894IkNsNTTo54= +github.com/net-byte/water v0.0.7 h1:wJUVq8x1AdfzZ5G8Qv61YRX+d22wx0ZgWNG0ihLqglo= +github.com/net-byte/water v0.0.7/go.mod h1:tRTm034ul8JBKkYFGN/WrnUM4cctr9laq5IpwvaVqUE= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= @@ -885,6 +899,8 @@ github.com/smallstep/truststore v0.12.1/go.mod h1:M4mebeNy28KusGX3lJxpLARIktLcyq github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 h1:TG/diQgUe0pntT/2D9tmUCz4VNwm9MfrtPr0SU2qSX8= +github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E= github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= @@ -1254,6 +1270,7 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1386,6 +1403,12 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 h1:Ug9qvr1myri/zFN6xL17LSCBGFDnphBBhzmILHsM5TY= +golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= +golang.zx2c4.com/wireguard v0.0.0-20220703234212-c31a7b1ab478 h1:vDy//hdR+GnROE3OdYbQKt9rdtNdHkDtONvpRwmls/0= +golang.zx2c4.com/wireguard v0.0.0-20220703234212-c31a7b1ab478/go.mod h1:bVQfyl2sCM/QIIGHpWbFGfHPuDvqnCNkT6MQLTCjO/U= +golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE= +golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI= 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=