diff --git a/go.mod b/go.mod index bf367187d488c..e7ccaab4f85ef 100644 --- a/go.mod +++ b/go.mod @@ -36,7 +36,7 @@ replace github.com/tcnksm/go-httpstat => github.com/coder/go-httpstat v0.0.0-202 // There are a few minor changes we make to Tailscale that we're slowly upstreaming. Compare here: // https://github.com/tailscale/tailscale/compare/main...coder:tailscale:main -replace tailscale.com => github.com/coder/tailscale v1.1.1-0.20250611020837-f14d20d23d8c +replace tailscale.com => github.com/coder/tailscale v1.1.1-0.20250724015444-494197765996 // This is replaced to include // 1. a fix for a data race: c.f. https://github.com/tailscale/wireguard-go/pull/25 diff --git a/go.sum b/go.sum index ff5c603c3db18..de1bbc535d3c5 100644 --- a/go.sum +++ b/go.sum @@ -926,8 +926,8 @@ github.com/coder/serpent v0.10.0 h1:ofVk9FJXSek+SmL3yVE3GoArP83M+1tX+H7S4t8BSuM= github.com/coder/serpent v0.10.0/go.mod h1:cZFW6/fP+kE9nd/oRkEHJpG6sXCtQ+AX7WMMEHv0Y3Q= github.com/coder/ssh v0.0.0-20231128192721-70855dedb788 h1:YoUSJ19E8AtuUFVYBpXuOD6a/zVP3rcxezNsoDseTUw= github.com/coder/ssh v0.0.0-20231128192721-70855dedb788/go.mod h1:aGQbuCLyhRLMzZF067xc84Lh7JDs1FKwCmF1Crl9dxQ= -github.com/coder/tailscale v1.1.1-0.20250611020837-f14d20d23d8c h1:d/qBIi3Ez7KkopRgNtfdvTMqvqBg47d36qVfkd3C5EQ= -github.com/coder/tailscale v1.1.1-0.20250611020837-f14d20d23d8c/go.mod h1:l7ml5uu7lFh5hY28lGYM4b/oFSmuPHYX6uk4RAu23Lc= +github.com/coder/tailscale v1.1.1-0.20250724015444-494197765996 h1:9x+ouDw9BKW1tdGzuQOWGMT2XkWLs+QQjeCrxYuU1lo= +github.com/coder/tailscale v1.1.1-0.20250724015444-494197765996/go.mod h1:l7ml5uu7lFh5hY28lGYM4b/oFSmuPHYX6uk4RAu23Lc= github.com/coder/terraform-config-inspect v0.0.0-20250107175719-6d06d90c630e h1:JNLPDi2P73laR1oAclY6jWzAbucf70ASAvf5mh2cME0= github.com/coder/terraform-config-inspect v0.0.0-20250107175719-6d06d90c630e/go.mod h1:Gz/z9Hbn+4KSp8A2FBtNszfLSdT2Tn/uAKGuVqqWmDI= github.com/coder/terraform-provider-coder/v2 v2.7.1-0.20250623193313-e890833351e2 h1:vtGzECz5CyzuxMODexWdIRxhYLqyTcHafuJpH60PYhM= diff --git a/tailnet/conn.go b/tailnet/conn.go index c3ebd246c539f..e23e0ae04b0d5 100644 --- a/tailnet/conn.go +++ b/tailnet/conn.go @@ -65,7 +65,9 @@ const EnvMagicsockDebugLogging = "CODER_MAGICSOCK_DEBUG_LOGGING" func init() { // Globally disable network namespacing. All networking happens in - // userspace. + // userspace unless the connection is configured to use a TUN. + // NOTE: this exists in init() so it affects all connections (incl. DERP) + // made by tailscale packages by default. netns.SetEnabled(false) // Tailscale, by default, "trims" the set of peers down to ones that we are // "actively" communicating with in an effort to save memory. Since @@ -100,6 +102,18 @@ type Options struct { BlockEndpoints bool Logger slog.Logger ListenPort uint16 + // UseSoftNetIsolation enables our homemade soft isolation feature in the + // netns package. This option will only be considered if TUNDev is set. + // + // The Coder soft isolation mode is a workaround to allow Coder Connect to + // connect to Coder servers behind corporate VPNs, and relaxes some of the + // loop protections that come with Tailscale. + // + // When soft isolation is disabled, the netns package will function as + // normal and route all traffic through the default interface (and block all + // traffic to other VPN interfaces) on macOS and Windows. + UseSoftNetIsolation bool + // CaptureHook is a callback that captures Disco packets and packets sent // into the tailnet tunnel. CaptureHook capture.Callback @@ -154,7 +168,11 @@ func NewConn(options *Options) (conn *Conn, err error) { return nil, xerrors.New("At least one IP range must be provided") } - netns.SetEnabled(options.TUNDev != nil) + useNetNS := options.TUNDev != nil + useSoftIsolation := useNetNS && options.UseSoftNetIsolation + options.Logger.Debug(context.Background(), "network isolation configuration", slog.F("use_netns", useNetNS), slog.F("use_soft_isolation", useSoftIsolation)) + netns.SetEnabled(useNetNS) + netns.SetCoderSoftIsolation(useSoftIsolation) var telemetryStore *TelemetryStore if options.TelemetrySink != nil { diff --git a/vpn/client.go b/vpn/client.go index 0411b209c24a8..8d2115ec2839a 100644 --- a/vpn/client.go +++ b/vpn/client.go @@ -69,13 +69,14 @@ func NewClient() Client { } type Options struct { - Headers http.Header - Logger slog.Logger - DNSConfigurator dns.OSConfigurator - Router router.Router - TUNDevice tun.Device - WireguardMonitor *netmon.Monitor - UpdateHandler tailnet.UpdatesHandler + Headers http.Header + Logger slog.Logger + UseSoftNetIsolation bool + DNSConfigurator dns.OSConfigurator + Router router.Router + TUNDevice tun.Device + WireguardMonitor *netmon.Monitor + UpdateHandler tailnet.UpdatesHandler } type derpMapRewriter struct { @@ -163,6 +164,7 @@ func (*client) NewConn(initCtx context.Context, serverURL *url.URL, token string DERPForceWebSockets: connInfo.DERPForceWebSockets, Logger: options.Logger, BlockEndpoints: connInfo.DisableDirectConnections, + UseSoftNetIsolation: options.UseSoftNetIsolation, DNSConfigurator: options.DNSConfigurator, Router: options.Router, TUNDev: options.TUNDevice, diff --git a/vpn/speaker_internal_test.go b/vpn/speaker_internal_test.go index 433868851a5bc..5ec5de4a3bf59 100644 --- a/vpn/speaker_internal_test.go +++ b/vpn/speaker_internal_test.go @@ -23,7 +23,7 @@ func TestMain(m *testing.M) { goleak.VerifyTestMain(m, testutil.GoleakOptions...) } -const expectedHandshake = "codervpn tunnel 1.2\n" +const expectedHandshake = "codervpn tunnel 1.3\n" // TestSpeaker_RawPeer tests the speaker with a peer that we simulate by directly making reads and // writes to the other end of the pipe. There should be at least one test that does this, rather diff --git a/vpn/tunnel.go b/vpn/tunnel.go index e4624ac1822b0..e0203b624522b 100644 --- a/vpn/tunnel.go +++ b/vpn/tunnel.go @@ -271,13 +271,14 @@ func (t *Tunnel) start(req *StartRequest) error { svrURL, apiToken, &Options{ - Headers: header, - Logger: t.clientLogger, - DNSConfigurator: networkingStack.DNSConfigurator, - Router: networkingStack.Router, - TUNDevice: networkingStack.TUNDevice, - WireguardMonitor: networkingStack.WireguardMonitor, - UpdateHandler: t, + Headers: header, + Logger: t.clientLogger, + UseSoftNetIsolation: req.GetTunnelUseSoftNetIsolation(), + DNSConfigurator: networkingStack.DNSConfigurator, + Router: networkingStack.Router, + TUNDevice: networkingStack.TUNDevice, + WireguardMonitor: networkingStack.WireguardMonitor, + UpdateHandler: t, }, ) if err != nil { diff --git a/vpn/tunnel_internal_test.go b/vpn/tunnel_internal_test.go index c21fd20251282..b93b679de332c 100644 --- a/vpn/tunnel_internal_test.go +++ b/vpn/tunnel_internal_test.go @@ -2,8 +2,10 @@ package vpn import ( "context" + "encoding/json" "maps" "net" + "net/http" "net/netip" "net/url" "slices" @@ -22,6 +24,7 @@ import ( "github.com/coder/quartz" maputil "github.com/coder/coder/v2/coderd/util/maps" + "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/tailnet" "github.com/coder/coder/v2/tailnet/proto" "github.com/coder/coder/v2/testutil" @@ -29,25 +32,43 @@ import ( func newFakeClient(ctx context.Context, t *testing.T) *fakeClient { return &fakeClient{ - t: t, - ctx: ctx, - ch: make(chan *fakeConn, 1), + t: t, + ctx: ctx, + connCh: make(chan *fakeConn, 1), + } +} + +func newFakeClientWithOptsCh(ctx context.Context, t *testing.T) *fakeClient { + return &fakeClient{ + t: t, + ctx: ctx, + connCh: make(chan *fakeConn, 1), + optsCh: make(chan *Options, 1), } } type fakeClient struct { - t *testing.T - ctx context.Context - ch chan *fakeConn + t *testing.T + ctx context.Context + connCh chan *fakeConn + optsCh chan *Options // options will be written to this channel if it's not nil } var _ Client = (*fakeClient)(nil) -func (f *fakeClient) NewConn(context.Context, *url.URL, string, *Options) (Conn, error) { +func (f *fakeClient) NewConn(_ context.Context, _ *url.URL, _ string, opts *Options) (Conn, error) { + if f.optsCh != nil { + select { + case <-f.ctx.Done(): + return nil, f.ctx.Err() + case f.optsCh <- opts: + } + } + select { case <-f.ctx.Done(): return nil, f.ctx.Err() - case conn := <-f.ch: + case conn := <-f.connCh: return conn, nil } } @@ -134,7 +155,7 @@ func TestTunnel_StartStop(t *testing.T) { t.Parallel() ctx := testutil.Context(t, testutil.WaitShort) - client := newFakeClient(ctx, t) + client := newFakeClientWithOptsCh(ctx, t) conn := newFakeConn(tailnet.WorkspaceUpdate{}, time.Time{}) _, mgr := setupTunnel(t, ctx, client, quartz.NewMock(t)) @@ -142,29 +163,45 @@ func TestTunnel_StartStop(t *testing.T) { errCh := make(chan error, 1) var resp *TunnelMessage // When: we start the tunnel + telemetry := codersdk.CoderDesktopTelemetry{ + DeviceID: "device001", + DeviceOS: "macOS", + CoderDesktopVersion: "0.24.8", + } + telemetryJSON, err := json.Marshal(telemetry) + require.NoError(t, err) go func() { r, err := mgr.unaryRPC(ctx, &ManagerMessage{ Msg: &ManagerMessage_Start{ Start: &StartRequest{ TunnelFileDescriptor: 2, - CoderUrl: "https://coder.example.com", - ApiToken: "fakeToken", + // Use default value for TunnelUseSoftNetIsolation + CoderUrl: "https://coder.example.com", + ApiToken: "fakeToken", Headers: []*StartRequest_Header{ {Name: "X-Test-Header", Value: "test"}, }, - DeviceOs: "macOS", - DeviceId: "device001", - CoderDesktopVersion: "0.24.8", + DeviceOs: telemetry.DeviceOS, + DeviceId: telemetry.DeviceID, + CoderDesktopVersion: telemetry.CoderDesktopVersion, }, }, }) resp = r errCh <- err }() - // Then: `NewConn` is called, - testutil.RequireSend(ctx, t, client.ch, conn) + + // Then: `NewConn` is called + opts := testutil.RequireReceive(ctx, t, client.optsCh) + require.Equal(t, http.Header{ + "X-Test-Header": {"test"}, + codersdk.CoderDesktopTelemetryHeader: {string(telemetryJSON)}, + }, opts.Headers) + require.False(t, opts.UseSoftNetIsolation) // the default is false + testutil.RequireSend(ctx, t, client.connCh, conn) + // And: a response is received - err := testutil.TryReceive(ctx, t, errCh) + err = testutil.TryReceive(ctx, t, errCh) require.NoError(t, err) _, ok := resp.Msg.(*TunnelMessage_Start) require.True(t, ok) @@ -197,7 +234,7 @@ func TestTunnel_PeerUpdate(t *testing.T) { wsID1 := uuid.UUID{1} wsID2 := uuid.UUID{2} - client := newFakeClient(ctx, t) + client := newFakeClientWithOptsCh(ctx, t) conn := newFakeConn(tailnet.WorkspaceUpdate{ UpsertedWorkspaces: []*tailnet.Workspace{ { @@ -211,22 +248,28 @@ func TestTunnel_PeerUpdate(t *testing.T) { tun, mgr := setupTunnel(t, ctx, client, quartz.NewMock(t)) + // When: we start the tunnel errCh := make(chan error, 1) var resp *TunnelMessage go func() { r, err := mgr.unaryRPC(ctx, &ManagerMessage{ Msg: &ManagerMessage_Start{ Start: &StartRequest{ - TunnelFileDescriptor: 2, - CoderUrl: "https://coder.example.com", - ApiToken: "fakeToken", + TunnelFileDescriptor: 2, + TunnelUseSoftNetIsolation: true, + CoderUrl: "https://coder.example.com", + ApiToken: "fakeToken", }, }, }) resp = r errCh <- err }() - testutil.RequireSend(ctx, t, client.ch, conn) + + // Then: `NewConn` is called + opts := testutil.RequireReceive(ctx, t, client.optsCh) + require.True(t, opts.UseSoftNetIsolation) + testutil.RequireSend(ctx, t, client.connCh, conn) err := testutil.TryReceive(ctx, t, errCh) require.NoError(t, err) _, ok := resp.Msg.(*TunnelMessage_Start) @@ -291,7 +334,7 @@ func TestTunnel_NetworkSettings(t *testing.T) { resp = r errCh <- err }() - testutil.RequireSend(ctx, t, client.ch, conn) + testutil.RequireSend(ctx, t, client.connCh, conn) err := testutil.TryReceive(ctx, t, errCh) require.NoError(t, err) _, ok := resp.Msg.(*TunnelMessage_Start) @@ -432,7 +475,7 @@ func TestTunnel_sendAgentUpdate(t *testing.T) { resp = r errCh <- err }() - testutil.RequireSend(ctx, t, client.ch, conn) + testutil.RequireSend(ctx, t, client.connCh, conn) err := testutil.TryReceive(ctx, t, errCh) require.NoError(t, err) _, ok := resp.Msg.(*TunnelMessage_Start) @@ -603,7 +646,7 @@ func TestTunnel_sendAgentUpdateReconnect(t *testing.T) { resp = r errCh <- err }() - testutil.RequireSend(ctx, t, client.ch, conn) + testutil.RequireSend(ctx, t, client.connCh, conn) err := testutil.TryReceive(ctx, t, errCh) require.NoError(t, err) _, ok := resp.Msg.(*TunnelMessage_Start) @@ -703,7 +746,7 @@ func TestTunnel_sendAgentUpdateWorkspaceReconnect(t *testing.T) { resp = r errCh <- err }() - testutil.RequireSend(ctx, t, client.ch, conn) + testutil.RequireSend(ctx, t, client.connCh, conn) err := testutil.TryReceive(ctx, t, errCh) require.NoError(t, err) _, ok := resp.Msg.(*TunnelMessage_Start) @@ -806,7 +849,7 @@ func TestTunnel_slowPing(t *testing.T) { resp = r errCh <- err }() - testutil.RequireSend(ctx, t, client.ch, conn) + testutil.RequireSend(ctx, t, client.connCh, conn) err := testutil.TryReceive(ctx, t, errCh) require.NoError(t, err) _, ok := resp.Msg.(*TunnelMessage_Start) @@ -895,7 +938,7 @@ func TestTunnel_stopMidPing(t *testing.T) { resp = r errCh <- err }() - testutil.RequireSend(ctx, t, client.ch, conn) + testutil.RequireSend(ctx, t, client.connCh, conn) err := testutil.TryReceive(ctx, t, errCh) require.NoError(t, err) _, ok := resp.Msg.(*TunnelMessage_Start) diff --git a/vpn/version.go b/vpn/version.go index 2bf815e903e29..b7bf1448a2c2e 100644 --- a/vpn/version.go +++ b/vpn/version.go @@ -23,7 +23,9 @@ var CurrentSupportedVersions = RPCVersionList{ // - preferred_derp: The server that DERP relayed connections are // using, if they're not using P2P. // - preferred_derp_latency: The latency to the preferred DERP - {Major: 1, Minor: 2}, + // 1.3 adds: + // - tunnel_use_soft_net_isolation to the StartRequest + {Major: 1, Minor: 3}, }, } diff --git a/vpn/vpn.pb.go b/vpn/vpn.pb.go index fbf5ce303fa35..8e08a453acdc3 100644 --- a/vpn/vpn.pb.go +++ b/vpn/vpn.pb.go @@ -1375,10 +1375,11 @@ type StartRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - TunnelFileDescriptor int32 `protobuf:"varint,1,opt,name=tunnel_file_descriptor,json=tunnelFileDescriptor,proto3" json:"tunnel_file_descriptor,omitempty"` - CoderUrl string `protobuf:"bytes,2,opt,name=coder_url,json=coderUrl,proto3" json:"coder_url,omitempty"` - ApiToken string `protobuf:"bytes,3,opt,name=api_token,json=apiToken,proto3" json:"api_token,omitempty"` - Headers []*StartRequest_Header `protobuf:"bytes,4,rep,name=headers,proto3" json:"headers,omitempty"` + TunnelFileDescriptor int32 `protobuf:"varint,1,opt,name=tunnel_file_descriptor,json=tunnelFileDescriptor,proto3" json:"tunnel_file_descriptor,omitempty"` + TunnelUseSoftNetIsolation bool `protobuf:"varint,8,opt,name=tunnel_use_soft_net_isolation,json=tunnelUseSoftNetIsolation,proto3" json:"tunnel_use_soft_net_isolation,omitempty"` + CoderUrl string `protobuf:"bytes,2,opt,name=coder_url,json=coderUrl,proto3" json:"coder_url,omitempty"` + ApiToken string `protobuf:"bytes,3,opt,name=api_token,json=apiToken,proto3" json:"api_token,omitempty"` + Headers []*StartRequest_Header `protobuf:"bytes,4,rep,name=headers,proto3" json:"headers,omitempty"` // Device ID from Coder Desktop DeviceId string `protobuf:"bytes,5,opt,name=device_id,json=deviceId,proto3" json:"device_id,omitempty"` // Device OS from Coder Desktop @@ -1426,6 +1427,13 @@ func (x *StartRequest) GetTunnelFileDescriptor() int32 { return 0 } +func (x *StartRequest) GetTunnelUseSoftNetIsolation() bool { + if x != nil { + return x.TunnelUseSoftNetIsolation + } + return false +} + func (x *StartRequest) GetCoderUrl() string { if x != nil { return x.CoderUrl @@ -2554,82 +2562,86 @@ var file_vpn_vpn_proto_rawDesc = []byte{ 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x22, 0xd4, 0x02, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x67, 0x65, 0x22, 0x96, 0x03, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x34, 0x0a, 0x16, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x14, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x46, 0x69, 0x6c, 0x65, 0x44, - 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6f, 0x64, - 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6f, - 0x64, 0x65, 0x72, 0x55, 0x72, 0x6c, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x70, 0x69, 0x5f, 0x74, 0x6f, - 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x70, 0x69, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x12, 0x32, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x04, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x76, 0x70, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x07, - 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, - 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, - 0x63, 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6f, - 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4f, - 0x73, 0x12, 0x32, 0x0a, 0x15, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x5f, 0x64, 0x65, 0x73, 0x6b, 0x74, - 0x6f, 0x70, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x13, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x44, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x56, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0x32, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, - 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x4e, 0x0a, 0x0d, 0x53, 0x74, 0x61, - 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72, - 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x7a, 0x0a, 0x1d, 0x53, 0x74, 0x61, - 0x72, 0x74, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, - 0x61, 0x64, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x62, 0x79, - 0x74, 0x65, 0x73, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x0c, 0x62, 0x79, 0x74, 0x65, 0x73, 0x57, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x12, - 0x24, 0x0a, 0x0b, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x04, 0x48, 0x00, 0x52, 0x0a, 0x62, 0x79, 0x74, 0x65, 0x73, 0x54, 0x6f, 0x74, - 0x61, 0x6c, 0x88, 0x01, 0x01, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, - 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x22, 0xaa, 0x01, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x72, 0x74, 0x50, - 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2d, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x67, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x76, 0x70, 0x6e, 0x2e, 0x53, 0x74, 0x61, - 0x72, 0x74, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x61, 0x67, 0x65, 0x52, - 0x05, 0x73, 0x74, 0x61, 0x67, 0x65, 0x12, 0x54, 0x0a, 0x11, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, - 0x61, 0x64, 0x5f, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x22, 0x2e, 0x76, 0x70, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x50, 0x72, 0x6f, - 0x67, 0x72, 0x65, 0x73, 0x73, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x50, 0x72, 0x6f, - 0x67, 0x72, 0x65, 0x73, 0x73, 0x48, 0x00, 0x52, 0x10, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, - 0x64, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x88, 0x01, 0x01, 0x42, 0x14, 0x0a, 0x12, - 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, - 0x73, 0x73, 0x22, 0x0d, 0x0a, 0x0b, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x22, 0x4d, 0x0a, 0x0c, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x65, - 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x22, 0x0f, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x22, 0xe4, 0x01, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x33, 0x0a, 0x09, - 0x6c, 0x69, 0x66, 0x65, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x15, 0x2e, 0x76, 0x70, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x4c, 0x69, 0x66, - 0x65, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x52, 0x09, 0x6c, 0x69, 0x66, 0x65, 0x63, 0x79, 0x63, 0x6c, - 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x30, 0x0a, 0x0b, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x75, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x70, - 0x6e, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x0a, 0x70, 0x65, - 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x22, 0x4e, 0x0a, 0x09, 0x4c, 0x69, 0x66, 0x65, - 0x63, 0x79, 0x63, 0x6c, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, - 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x54, 0x41, 0x52, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x01, - 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x54, 0x41, 0x52, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0c, 0x0a, - 0x08, 0x53, 0x54, 0x4f, 0x50, 0x50, 0x49, 0x4e, 0x47, 0x10, 0x03, 0x12, 0x0b, 0x0a, 0x07, 0x53, - 0x54, 0x4f, 0x50, 0x50, 0x45, 0x44, 0x10, 0x04, 0x2a, 0x47, 0x0a, 0x12, 0x53, 0x74, 0x61, 0x72, - 0x74, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x61, 0x67, 0x65, 0x12, 0x10, - 0x0a, 0x0c, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x69, 0x6e, 0x67, 0x10, 0x00, - 0x12, 0x0f, 0x0a, 0x0b, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x10, - 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x69, 0x6e, 0x67, 0x10, - 0x02, 0x42, 0x39, 0x5a, 0x1d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x76, 0x32, 0x2f, 0x76, - 0x70, 0x6e, 0xaa, 0x02, 0x17, 0x43, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x44, 0x65, 0x73, 0x6b, 0x74, - 0x6f, 0x70, 0x2e, 0x56, 0x70, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x40, 0x0a, 0x1d, 0x74, 0x75, 0x6e, + 0x6e, 0x65, 0x6c, 0x5f, 0x75, 0x73, 0x65, 0x5f, 0x73, 0x6f, 0x66, 0x74, 0x5f, 0x6e, 0x65, 0x74, + 0x5f, 0x69, 0x73, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x19, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x55, 0x73, 0x65, 0x53, 0x6f, 0x66, 0x74, 0x4e, + 0x65, 0x74, 0x49, 0x73, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x63, + 0x6f, 0x64, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x63, 0x6f, 0x64, 0x65, 0x72, 0x55, 0x72, 0x6c, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x70, 0x69, 0x5f, + 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x70, 0x69, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x32, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, + 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x76, 0x70, 0x6e, 0x2e, 0x53, 0x74, 0x61, + 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x5f, 0x6f, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x4f, 0x73, 0x12, 0x32, 0x0a, 0x15, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x5f, 0x64, 0x65, 0x73, + 0x6b, 0x74, 0x6f, 0x70, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x13, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x44, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0x32, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x4e, 0x0a, 0x0d, 0x53, + 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, + 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x7a, 0x0a, 0x1d, 0x53, + 0x74, 0x61, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x44, 0x6f, 0x77, 0x6e, + 0x6c, 0x6f, 0x61, 0x64, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x23, 0x0a, 0x0d, + 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x0c, 0x62, 0x79, 0x74, 0x65, 0x73, 0x57, 0x72, 0x69, 0x74, 0x74, 0x65, + 0x6e, 0x12, 0x24, 0x0a, 0x0b, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x74, 0x6f, 0x74, 0x61, 0x6c, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x48, 0x00, 0x52, 0x0a, 0x62, 0x79, 0x74, 0x65, 0x73, 0x54, + 0x6f, 0x74, 0x61, 0x6c, 0x88, 0x01, 0x01, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x62, 0x79, 0x74, 0x65, + 0x73, 0x5f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x22, 0xaa, 0x01, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x72, + 0x74, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2d, 0x0a, 0x05, 0x73, 0x74, 0x61, + 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x76, 0x70, 0x6e, 0x2e, 0x53, + 0x74, 0x61, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x61, 0x67, + 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x67, 0x65, 0x12, 0x54, 0x0a, 0x11, 0x64, 0x6f, 0x77, 0x6e, + 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x76, 0x70, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x50, + 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x50, + 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x48, 0x00, 0x52, 0x10, 0x64, 0x6f, 0x77, 0x6e, 0x6c, + 0x6f, 0x61, 0x64, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x88, 0x01, 0x01, 0x42, 0x14, + 0x0a, 0x12, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x70, 0x72, 0x6f, 0x67, + 0x72, 0x65, 0x73, 0x73, 0x22, 0x0d, 0x0a, 0x0b, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x22, 0x4d, 0x0a, 0x0c, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x23, 0x0a, + 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x22, 0x0f, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x22, 0xe4, 0x01, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x33, + 0x0a, 0x09, 0x6c, 0x69, 0x66, 0x65, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x15, 0x2e, 0x76, 0x70, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x4c, + 0x69, 0x66, 0x65, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x52, 0x09, 0x6c, 0x69, 0x66, 0x65, 0x63, 0x79, + 0x63, 0x6c, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, + 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x30, 0x0a, 0x0b, 0x70, 0x65, 0x65, 0x72, + 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, + 0x76, 0x70, 0x6e, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x0a, + 0x70, 0x65, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x22, 0x4e, 0x0a, 0x09, 0x4c, 0x69, + 0x66, 0x65, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, + 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x54, 0x41, 0x52, 0x54, 0x49, 0x4e, 0x47, + 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x54, 0x41, 0x52, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, + 0x0c, 0x0a, 0x08, 0x53, 0x54, 0x4f, 0x50, 0x50, 0x49, 0x4e, 0x47, 0x10, 0x03, 0x12, 0x0b, 0x0a, + 0x07, 0x53, 0x54, 0x4f, 0x50, 0x50, 0x45, 0x44, 0x10, 0x04, 0x2a, 0x47, 0x0a, 0x12, 0x53, 0x74, + 0x61, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x61, 0x67, 0x65, + 0x12, 0x10, 0x0a, 0x0c, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x69, 0x6e, 0x67, + 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x6e, + 0x67, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x69, 0x6e, + 0x67, 0x10, 0x02, 0x42, 0x39, 0x5a, 0x1d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x76, 0x32, + 0x2f, 0x76, 0x70, 0x6e, 0xaa, 0x02, 0x17, 0x43, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x44, 0x65, 0x73, + 0x6b, 0x74, 0x6f, 0x70, 0x2e, 0x56, 0x70, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/vpn/vpn.proto b/vpn/vpn.proto index 357a2b91b12fb..61c9978cdcad6 100644 --- a/vpn/vpn.proto +++ b/vpn/vpn.proto @@ -214,6 +214,7 @@ message NetworkSettingsResponse { // StartResponse. message StartRequest { int32 tunnel_file_descriptor = 1; + bool tunnel_use_soft_net_isolation = 8; string coder_url = 2; string api_token = 3; // Additional HTTP headers added to all requests pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy