mirror of
https://github.com/tailscale/tailscale.git
synced 2026-07-14 17:43:03 -04:00
The client/local package doc said its API is not necessarily stable, but that caveat was easy to miss and only a few cert methods said anything explicit either way. People have been surprised by IPN bus changes between releases. Add explicit "API maturity" notes, matching the existing wording on the cert methods, marking stable: BugReport, BugReportWithOpts, CertDomains, CheckUpdate, CurrentDERPMap, DialTCP, UserDial, DisconnectControl, GetPrefs, EditPrefs, Status, StatusWithoutPeers, SetUseExitNode, SwitchProfile, UserProfile, and the WhoIs* methods. Mark unstable: ipn.Notify, WatchIPNBus, DoLocalRequest, the Debug*, Drive*, Check*, EventBus*, and Stream* methods, SetComponentDebugLogging, TailDaemonLogs, ShutdownTailscaled, GetDNSOSConfig, GetEffectivePolicy, GetServeConfig, and GetAppConnectorRouteInfo. Also note on tailcfg.DERPMap that the type is subject to minor changes over time though its general shape is stable, document that ipn.Prefs.CorpDNS is the internal name for "tailscale set --accept-dns", and add a package doc paragraph to client/local saying that methods without an explicit API maturity note should be assumed unstable. Updates #20406 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com> Change-Id: I9333c58ae312e392c61d7de77987282e84ce2aeb
88 lines
2.5 KiB
Go
88 lines
2.5 KiB
Go
// Copyright (c) Tailscale Inc & contributors
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
//go:build !ts_omit_debugportmapper
|
|
|
|
package local
|
|
|
|
import (
|
|
"cmp"
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/netip"
|
|
"net/url"
|
|
"strconv"
|
|
"time"
|
|
|
|
"tailscale.com/client/tailscale/apitype"
|
|
)
|
|
|
|
// DebugPortmapOpts contains options for the [Client.DebugPortmap] command.
|
|
type DebugPortmapOpts struct {
|
|
// Duration is how long the mapping should be created for. It defaults
|
|
// to 5 seconds if not set.
|
|
Duration time.Duration
|
|
|
|
// Type is the kind of portmap to debug. The empty string instructs the
|
|
// portmap client to perform all known types. Other valid options are
|
|
// "pmp", "pcp", and "upnp".
|
|
Type string
|
|
|
|
// GatewayAddr specifies the gateway address used during portmapping.
|
|
// If set, SelfAddr must also be set. If unset, it will be
|
|
// autodetected.
|
|
GatewayAddr netip.Addr
|
|
|
|
// SelfAddr specifies the gateway address used during portmapping. If
|
|
// set, GatewayAddr must also be set. If unset, it will be
|
|
// autodetected.
|
|
SelfAddr netip.Addr
|
|
|
|
// LogHTTP instructs the debug-portmap endpoint to print all HTTP
|
|
// requests and responses made to the logs.
|
|
LogHTTP bool
|
|
}
|
|
|
|
// DebugPortmap invokes the debug-portmap endpoint, and returns an
|
|
// io.ReadCloser that can be used to read the logs that are printed during this
|
|
// process.
|
|
//
|
|
// opts can be nil; if so, default values will be used.
|
|
//
|
|
// API maturity: this method is not considered a stable API and is
|
|
// subject to change between releases.
|
|
func (lc *Client) DebugPortmap(ctx context.Context, opts *DebugPortmapOpts) (io.ReadCloser, error) {
|
|
vals := make(url.Values)
|
|
if opts == nil {
|
|
opts = &DebugPortmapOpts{}
|
|
}
|
|
|
|
vals.Set("duration", cmp.Or(opts.Duration, 5*time.Second).String())
|
|
vals.Set("type", opts.Type)
|
|
vals.Set("log_http", strconv.FormatBool(opts.LogHTTP))
|
|
|
|
if opts.GatewayAddr.IsValid() != opts.SelfAddr.IsValid() {
|
|
return nil, fmt.Errorf("both GatewayAddr and SelfAddr must be provided if one is")
|
|
} else if opts.GatewayAddr.IsValid() {
|
|
vals.Set("gateway_and_self", fmt.Sprintf("%s/%s", opts.GatewayAddr, opts.SelfAddr))
|
|
}
|
|
|
|
req, err := http.NewRequestWithContext(ctx, "GET", "http://"+apitype.LocalAPIHost+"/localapi/v0/debug-portmap?"+vals.Encode(), nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
res, err := lc.doLocalRequestNiceError(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if res.StatusCode != 200 {
|
|
body, _ := io.ReadAll(res.Body)
|
|
res.Body.Close()
|
|
return nil, fmt.Errorf("HTTP %s: %s", res.Status, body)
|
|
}
|
|
|
|
return res.Body, nil
|
|
}
|