Skip to content

Commit 689855c

Browse files
committed
fix: rewrite url to agent ip in single tailnet
This restores previous behavior of being able to cache connections across agents in single tailnet.
1 parent 76e7328 commit 689855c

File tree

2 files changed

+36
-9
lines changed

2 files changed

+36
-9
lines changed

coderd/tailnet.go

+10-9
Original file line numberDiff line numberDiff line change
@@ -99,14 +99,7 @@ func NewServerTailnet(
9999
transport: tailnetTransport.Clone(),
100100
}
101101
tn.transport.DialContext = tn.dialContext
102-
103-
// Bugfix: for some reason all calls to tn.dialContext come from
104-
// "localhost", causing connections to be cached and requests to go to the
105-
// wrong workspaces. This disables keepalives for now until the root cause
106-
// can be found.
107-
tn.transport.MaxIdleConnsPerHost = -1
108-
tn.transport.DisableKeepAlives = true
109-
102+
tn.transport.MaxIdleConnsPerHost = 10
110103
tn.transport.MaxIdleConns = 0
111104
// We intentionally don't verify the certificate chain here.
112105
// The connection to the workspace is already established and most
@@ -308,7 +301,15 @@ type ServerTailnet struct {
308301
}
309302

310303
func (s *ServerTailnet) ReverseProxy(targetURL, dashboardURL *url.URL, agentID uuid.UUID) *httputil.ReverseProxy {
311-
proxy := httputil.NewSingleHostReverseProxy(targetURL)
304+
// Rewrite the targetURL's Host to point to the agent's IP. This is
305+
// necessary because due to TCP connection caching, each agent needs to be
306+
// addressed invidivually. Otherwise, all connections get dialed as
307+
// "localhost:port", causing connections to be shared across agents.
308+
tgt := *targetURL
309+
_, port, _ := net.SplitHostPort(tgt.Host)
310+
tgt.Host = net.JoinHostPort(tailnet.IPFromUUID(agentID).String(), port)
311+
312+
proxy := httputil.NewSingleHostReverseProxy(&tgt)
312313
proxy.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) {
313314
site.RenderStaticErrorPage(w, r, site.ErrorPageData{
314315
Status: http.StatusBadGateway,

coderd/tailnet_test.go

+26
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,32 @@ func TestServerTailnet_ReverseProxy(t *testing.T) {
7474
assert.Equal(t, http.StatusOK, res.StatusCode)
7575
})
7676

77+
t.Run("HostRewrite", func(t *testing.T) {
78+
t.Parallel()
79+
80+
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
81+
defer cancel()
82+
83+
agentID, _, serverTailnet := setupAgent(t, nil)
84+
85+
u, err := url.Parse(fmt.Sprintf("http://127.0.0.1:%d", codersdk.WorkspaceAgentHTTPAPIServerPort))
86+
require.NoError(t, err)
87+
88+
rp, release, err := serverTailnet.ReverseProxy(u, u, agentID)
89+
require.NoError(t, err)
90+
defer release()
91+
92+
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
93+
require.NoError(t, err)
94+
95+
// Ensure the reverse proxy director rewrites the url host to the agent's IP.
96+
rp.Director(req)
97+
assert.Equal(t,
98+
fmt.Sprintf("[%s]:%d", tailnet.IPFromUUID(agentID).String(), codersdk.WorkspaceAgentHTTPAPIServerPort),
99+
req.URL.Host,
100+
)
101+
})
102+
77103
t.Run("HTTPSProxy", func(t *testing.T) {
78104
t.Parallel()
79105

0 commit comments

Comments
 (0)