@@ -2,8 +2,10 @@ package vpn
22
33import (
44"context"
5+ "encoding/json"
56"maps"
67"net"
8+ "net/http"
79"net/netip"
810"net/url"
911"slices"
@@ -22,32 +24,51 @@ import (
2224"github.com/coder/quartz"
2325
2426maputil"github.com/coder/coder/v2/coderd/util/maps"
27+ "github.com/coder/coder/v2/codersdk"
2528"github.com/coder/coder/v2/tailnet"
2629"github.com/coder/coder/v2/tailnet/proto"
2730"github.com/coder/coder/v2/testutil"
2831)
2932
3033func newFakeClient (ctx context.Context ,t * testing.T )* fakeClient {
3134return & fakeClient {
32- t :t ,
33- ctx :ctx ,
34- ch :make (chan * fakeConn ,1 ),
35+ t :t ,
36+ ctx :ctx ,
37+ connCh :make (chan * fakeConn ,1 ),
38+ }
39+ }
40+
41+ func newFakeClientWithOptsCh (ctx context.Context ,t * testing.T )* fakeClient {
42+ return & fakeClient {
43+ t :t ,
44+ ctx :ctx ,
45+ connCh :make (chan * fakeConn ,1 ),
46+ optsCh :make (chan * Options ,1 ),
3547}
3648}
3749
3850type fakeClient struct {
39- t * testing.T
40- ctx context.Context
41- ch chan * fakeConn
51+ t * testing.T
52+ ctx context.Context
53+ connCh chan * fakeConn
54+ optsCh chan * Options // options will be written to this channel if it's not nil
4255}
4356
4457var _ Client = (* fakeClient )(nil )
4558
46- func (f * fakeClient )NewConn (context.Context ,* url.URL ,string ,* Options ) (Conn ,error ) {
59+ func (f * fakeClient )NewConn (_ context.Context ,_ * url.URL ,_ string ,opts * Options ) (Conn ,error ) {
60+ if f .optsCh != nil {
61+ select {
62+ case <- f .ctx .Done ():
63+ return nil ,f .ctx .Err ()
64+ case f .optsCh <- opts :
65+ }
66+ }
67+
4768select {
4869case <- f .ctx .Done ():
4970return nil ,f .ctx .Err ()
50- case conn := <- f .ch :
71+ case conn := <- f .connCh :
5172return conn ,nil
5273}
5374}
@@ -134,37 +155,53 @@ func TestTunnel_StartStop(t *testing.T) {
134155t .Parallel ()
135156
136157ctx := testutil .Context (t ,testutil .WaitShort )
137- client := newFakeClient (ctx ,t )
158+ client := newFakeClientWithOptsCh (ctx ,t )
138159conn := newFakeConn (tailnet.WorkspaceUpdate {}, time.Time {})
139160
140161_ ,mgr := setupTunnel (t ,ctx ,client ,quartz .NewMock (t ))
141162
142163errCh := make (chan error ,1 )
143164var resp * TunnelMessage
144165// When: we start the tunnel
166+ telemetry := codersdk.CoderDesktopTelemetry {
167+ DeviceID :"device001" ,
168+ DeviceOS :"macOS" ,
169+ CoderDesktopVersion :"0.24.8" ,
170+ }
171+ telemetryJSON ,err := json .Marshal (telemetry )
172+ require .NoError (t ,err )
145173go func () {
146174r ,err := mgr .unaryRPC (ctx ,& ManagerMessage {
147175Msg :& ManagerMessage_Start {
148176Start :& StartRequest {
149177TunnelFileDescriptor :2 ,
150- CoderUrl :"https://coder.example.com" ,
151- ApiToken :"fakeToken" ,
178+ // Use default value for TunnelUseSoftNetIsolation
179+ CoderUrl :"https://coder.example.com" ,
180+ ApiToken :"fakeToken" ,
152181Headers : []* StartRequest_Header {
153182{Name :"X-Test-Header" ,Value :"test" },
154183},
155- DeviceOs :"macOS" ,
156- DeviceId :"device001" ,
157- CoderDesktopVersion :"0.24.8" ,
184+ DeviceOs :telemetry . DeviceOS ,
185+ DeviceId :telemetry . DeviceID ,
186+ CoderDesktopVersion :telemetry . CoderDesktopVersion ,
158187},
159188},
160189})
161190resp = r
162191errCh <- err
163192}()
164- // Then: `NewConn` is called,
165- testutil .RequireSend (ctx ,t ,client .ch ,conn )
193+
194+ // Then: `NewConn` is called
195+ opts := testutil .RequireReceive (ctx ,t ,client .optsCh )
196+ require .Equal (t , http.Header {
197+ "X-Test-Header" : {"test" },
198+ codersdk .CoderDesktopTelemetryHeader : {string (telemetryJSON )},
199+ },opts .Headers )
200+ require .False (t ,opts .UseSoftNetIsolation )// the default is false
201+ testutil .RequireSend (ctx ,t ,client .connCh ,conn )
202+
166203// And: a response is received
167- err : =testutil .TryReceive (ctx ,t ,errCh )
204+ err = testutil .TryReceive (ctx ,t ,errCh )
168205require .NoError (t ,err )
169206_ ,ok := resp .Msg .(* TunnelMessage_Start )
170207require .True (t ,ok )
@@ -197,7 +234,7 @@ func TestTunnel_PeerUpdate(t *testing.T) {
197234wsID1 := uuid.UUID {1 }
198235wsID2 := uuid.UUID {2 }
199236
200- client := newFakeClient (ctx ,t )
237+ client := newFakeClientWithOptsCh (ctx ,t )
201238conn := newFakeConn (tailnet.WorkspaceUpdate {
202239UpsertedWorkspaces : []* tailnet.Workspace {
203240{
@@ -211,22 +248,28 @@ func TestTunnel_PeerUpdate(t *testing.T) {
211248
212249tun ,mgr := setupTunnel (t ,ctx ,client ,quartz .NewMock (t ))
213250
251+ // When: we start the tunnel
214252errCh := make (chan error ,1 )
215253var resp * TunnelMessage
216254go func () {
217255r ,err := mgr .unaryRPC (ctx ,& ManagerMessage {
218256Msg :& ManagerMessage_Start {
219257Start :& StartRequest {
220- TunnelFileDescriptor :2 ,
221- CoderUrl :"https://coder.example.com" ,
222- ApiToken :"fakeToken" ,
258+ TunnelFileDescriptor :2 ,
259+ TunnelUseSoftNetIsolation :true ,
260+ CoderUrl :"https://coder.example.com" ,
261+ ApiToken :"fakeToken" ,
223262},
224263},
225264})
226265resp = r
227266errCh <- err
228267}()
229- testutil .RequireSend (ctx ,t ,client .ch ,conn )
268+
269+ // Then: `NewConn` is called
270+ opts := testutil .RequireReceive (ctx ,t ,client .optsCh )
271+ require .True (t ,opts .UseSoftNetIsolation )
272+ testutil .RequireSend (ctx ,t ,client .connCh ,conn )
230273err := testutil .TryReceive (ctx ,t ,errCh )
231274require .NoError (t ,err )
232275_ ,ok := resp .Msg .(* TunnelMessage_Start )
@@ -291,7 +334,7 @@ func TestTunnel_NetworkSettings(t *testing.T) {
291334resp = r
292335errCh <- err
293336}()
294- testutil .RequireSend (ctx ,t ,client .ch ,conn )
337+ testutil .RequireSend (ctx ,t ,client .connCh ,conn )
295338err := testutil .TryReceive (ctx ,t ,errCh )
296339require .NoError (t ,err )
297340_ ,ok := resp .Msg .(* TunnelMessage_Start )
@@ -432,7 +475,7 @@ func TestTunnel_sendAgentUpdate(t *testing.T) {
432475resp = r
433476errCh <- err
434477}()
435- testutil .RequireSend (ctx ,t ,client .ch ,conn )
478+ testutil .RequireSend (ctx ,t ,client .connCh ,conn )
436479err := testutil .TryReceive (ctx ,t ,errCh )
437480require .NoError (t ,err )
438481_ ,ok := resp .Msg .(* TunnelMessage_Start )
@@ -603,7 +646,7 @@ func TestTunnel_sendAgentUpdateReconnect(t *testing.T) {
603646resp = r
604647errCh <- err
605648}()
606- testutil .RequireSend (ctx ,t ,client .ch ,conn )
649+ testutil .RequireSend (ctx ,t ,client .connCh ,conn )
607650err := testutil .TryReceive (ctx ,t ,errCh )
608651require .NoError (t ,err )
609652_ ,ok := resp .Msg .(* TunnelMessage_Start )
@@ -703,7 +746,7 @@ func TestTunnel_sendAgentUpdateWorkspaceReconnect(t *testing.T) {
703746resp = r
704747errCh <- err
705748}()
706- testutil .RequireSend (ctx ,t ,client .ch ,conn )
749+ testutil .RequireSend (ctx ,t ,client .connCh ,conn )
707750err := testutil .TryReceive (ctx ,t ,errCh )
708751require .NoError (t ,err )
709752_ ,ok := resp .Msg .(* TunnelMessage_Start )
@@ -806,7 +849,7 @@ func TestTunnel_slowPing(t *testing.T) {
806849resp = r
807850errCh <- err
808851}()
809- testutil .RequireSend (ctx ,t ,client .ch ,conn )
852+ testutil .RequireSend (ctx ,t ,client .connCh ,conn )
810853err := testutil .TryReceive (ctx ,t ,errCh )
811854require .NoError (t ,err )
812855_ ,ok := resp .Msg .(* TunnelMessage_Start )
@@ -895,7 +938,7 @@ func TestTunnel_stopMidPing(t *testing.T) {
895938resp = r
896939errCh <- err
897940}()
898- testutil .RequireSend (ctx ,t ,client .ch ,conn )
941+ testutil .RequireSend (ctx ,t ,client .connCh ,conn )
899942err := testutil .TryReceive (ctx ,t ,errCh )
900943require .NoError (t ,err )
901944_ ,ok := resp .Msg .(* TunnelMessage_Start )