apiClient returns an HTTP client that can be used to make requests to the workspace agent's HTTP API server.
()
| 1378 | // apiClient returns an HTTP client that can be used to make |
| 1379 | // requests to the workspace agent's HTTP API server. |
| 1380 | func (c *agentConn) apiClient() *http.Client { |
| 1381 | agentAddr := netip.AddrPortFrom(c.agentAddress(), AgentHTTPAPIServerPort) |
| 1382 | return &http.Client{ |
| 1383 | // Redirects are blocked to prevent misuse. |
| 1384 | CheckRedirect: func(*http.Request, []*http.Request) error { |
| 1385 | return http.ErrUseLastResponse |
| 1386 | }, |
| 1387 | Transport: &http.Transport{ |
| 1388 | // Disable keep alives as we're usually only making a single |
| 1389 | // request, and this triggers goleak in tests |
| 1390 | DisableKeepAlives: true, |
| 1391 | DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { |
| 1392 | if network != "tcp" { |
| 1393 | return nil, xerrors.Errorf("network must be tcp") |
| 1394 | } |
| 1395 | |
| 1396 | host, port, err := net.SplitHostPort(addr) |
| 1397 | if err != nil { |
| 1398 | return nil, xerrors.Errorf("split host port %q: %w", addr, err) |
| 1399 | } |
| 1400 | |
| 1401 | // Verify that the port is TailnetStatisticsPort. |
| 1402 | if port != strconv.Itoa(AgentHTTPAPIServerPort) { |
| 1403 | return nil, xerrors.Errorf("request %q does not appear to be for http api", addr) |
| 1404 | } |
| 1405 | |
| 1406 | if reqAddr, err := netip.ParseAddr(host); err != nil || reqAddr != agentAddr.Addr() { |
| 1407 | c.opts.Logger.Warn(ctx, "blocked workspace agent API request to unintended host", |
| 1408 | slog.F("agent_id", c.opts.AgentID), |
| 1409 | slog.F("request_host", host), |
| 1410 | slog.F("intended_agent_addr", agentAddr.Addr()), |
| 1411 | ) |
| 1412 | return nil, xerrors.Errorf("request host %q does not match intended agent %q", host, agentAddr.Addr()) |
| 1413 | } |
| 1414 | |
| 1415 | if !c.AwaitReachable(ctx) { |
| 1416 | return nil, xerrors.Errorf("workspace agent not reachable in time: %v", ctx.Err()) |
| 1417 | } |
| 1418 | |
| 1419 | // Always dial the pinned agent address, never the request host. |
| 1420 | conn, err := c.Conn.DialContextTCP(ctx, agentAddr) |
| 1421 | if err != nil { |
| 1422 | return nil, xerrors.Errorf("dial http api: %w", err) |
| 1423 | } |
| 1424 | |
| 1425 | return conn, nil |
| 1426 | }, |
| 1427 | }, |
| 1428 | } |
| 1429 | } |
| 1430 | |
| 1431 | func (c *agentConn) GetPeerDiagnostics() tailnet.PeerDiagnostics { |
| 1432 | return c.Conn.GetPeerDiagnostics(c.opts.AgentID) |
no test coverage detected