ipn/localapi: add localapi debug endpoints for packet filter/matches

For debugging #6423. This is easier than TS_DEBUG_MAP, as this means I
can pipe things into jq, etc.

Updates #6423

Change-Id: Ib3e7496b2eb3f47d4bed42e9b8045a441424b23c
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
pull/6892/head
Brad Fitzpatrick 2 years ago committed by Brad Fitzpatrick
parent b2b8e62476
commit eafbf8886d

@ -16,6 +16,7 @@ import (
"tailscale.com/types/logger" "tailscale.com/types/logger"
"tailscale.com/types/netmap" "tailscale.com/types/netmap"
"tailscale.com/types/opt" "tailscale.com/types/opt"
"tailscale.com/types/views"
"tailscale.com/wgengine/filter" "tailscale.com/wgengine/filter"
) )
@ -40,6 +41,7 @@ type mapSession struct {
lastDNSConfig *tailcfg.DNSConfig lastDNSConfig *tailcfg.DNSConfig
lastDERPMap *tailcfg.DERPMap lastDERPMap *tailcfg.DERPMap
lastUserProfile map[tailcfg.UserID]tailcfg.UserProfile lastUserProfile map[tailcfg.UserID]tailcfg.UserProfile
lastPacketFilterRules views.Slice[tailcfg.FilterRule]
lastParsedPacketFilter []filter.Match lastParsedPacketFilter []filter.Match
lastSSHPolicy *tailcfg.SSHPolicy lastSSHPolicy *tailcfg.SSHPolicy
collectServices bool collectServices bool
@ -96,6 +98,7 @@ func (ms *mapSession) netmapForResponse(resp *tailcfg.MapResponse) *netmap.Netwo
if pf := resp.PacketFilter; pf != nil { if pf := resp.PacketFilter; pf != nil {
var err error var err error
ms.lastPacketFilterRules = views.SliceOf(pf)
ms.lastParsedPacketFilter, err = filter.MatchesFromFilterRules(pf) ms.lastParsedPacketFilter, err = filter.MatchesFromFilterRules(pf)
if err != nil { if err != nil {
ms.logf("parsePacketFilter: %v", err) ms.logf("parsePacketFilter: %v", err)
@ -147,21 +150,22 @@ func (ms *mapSession) netmapForResponse(resp *tailcfg.MapResponse) *netmap.Netwo
} }
nm := &netmap.NetworkMap{ nm := &netmap.NetworkMap{
NodeKey: ms.privateNodeKey.Public(), NodeKey: ms.privateNodeKey.Public(),
PrivateKey: ms.privateNodeKey, PrivateKey: ms.privateNodeKey,
MachineKey: ms.machinePubKey, MachineKey: ms.machinePubKey,
Peers: resp.Peers, Peers: resp.Peers,
UserProfiles: make(map[tailcfg.UserID]tailcfg.UserProfile), UserProfiles: make(map[tailcfg.UserID]tailcfg.UserProfile),
Domain: ms.lastDomain, Domain: ms.lastDomain,
DomainAuditLogID: ms.lastDomainAuditLogID, DomainAuditLogID: ms.lastDomainAuditLogID,
DNS: *ms.lastDNSConfig, DNS: *ms.lastDNSConfig,
PacketFilter: ms.lastParsedPacketFilter, PacketFilter: ms.lastParsedPacketFilter,
SSHPolicy: ms.lastSSHPolicy, PacketFilterRules: ms.lastPacketFilterRules,
CollectServices: ms.collectServices, SSHPolicy: ms.lastSSHPolicy,
DERPMap: ms.lastDERPMap, CollectServices: ms.collectServices,
Debug: debug, DERPMap: ms.lastDERPMap,
ControlHealth: ms.lastHealth, Debug: debug,
TKAEnabled: ms.lastTKAInfo != nil && !ms.lastTKAInfo.Disabled, ControlHealth: ms.lastHealth,
TKAEnabled: ms.lastTKAInfo != nil && !ms.lastTKAInfo.Disabled,
} }
ms.netMapBuilding = nm ms.netMapBuilding = nm

@ -61,39 +61,41 @@ var handler = map[string]localAPIHandler{
// The other /localapi/v0/NAME handlers are exact matches and contain only NAME // The other /localapi/v0/NAME handlers are exact matches and contain only NAME
// without a trailing slash: // without a trailing slash:
"bugreport": (*Handler).serveBugReport, "bugreport": (*Handler).serveBugReport,
"check-ip-forwarding": (*Handler).serveCheckIPForwarding, "check-ip-forwarding": (*Handler).serveCheckIPForwarding,
"check-prefs": (*Handler).serveCheckPrefs, "check-prefs": (*Handler).serveCheckPrefs,
"component-debug-logging": (*Handler).serveComponentDebugLogging, "component-debug-logging": (*Handler).serveComponentDebugLogging,
"debug": (*Handler).serveDebug, "debug": (*Handler).serveDebug,
"debug-derp-region": (*Handler).serveDebugDERPRegion, "debug-derp-region": (*Handler).serveDebugDERPRegion,
"derpmap": (*Handler).serveDERPMap, "debug-packet-filter-matches": (*Handler).serveDebugPacketFilterMatches,
"dev-set-state-store": (*Handler).serveDevSetStateStore, "debug-packet-filter-rules": (*Handler).serveDebugPacketFilterRules,
"dial": (*Handler).serveDial, "derpmap": (*Handler).serveDERPMap,
"file-targets": (*Handler).serveFileTargets, "dev-set-state-store": (*Handler).serveDevSetStateStore,
"goroutines": (*Handler).serveGoroutines, "dial": (*Handler).serveDial,
"id-token": (*Handler).serveIDToken, "file-targets": (*Handler).serveFileTargets,
"login-interactive": (*Handler).serveLoginInteractive, "goroutines": (*Handler).serveGoroutines,
"logout": (*Handler).serveLogout, "id-token": (*Handler).serveIDToken,
"metrics": (*Handler).serveMetrics, "login-interactive": (*Handler).serveLoginInteractive,
"ping": (*Handler).servePing, "logout": (*Handler).serveLogout,
"prefs": (*Handler).servePrefs, "metrics": (*Handler).serveMetrics,
"pprof": (*Handler).servePprof, "ping": (*Handler).servePing,
"serve-config": (*Handler).serveServeConfig, "prefs": (*Handler).servePrefs,
"set-dns": (*Handler).serveSetDNS, "pprof": (*Handler).servePprof,
"set-expiry-sooner": (*Handler).serveSetExpirySooner, "serve-config": (*Handler).serveServeConfig,
"start": (*Handler).serveStart, "set-dns": (*Handler).serveSetDNS,
"status": (*Handler).serveStatus, "set-expiry-sooner": (*Handler).serveSetExpirySooner,
"tka/init": (*Handler).serveTKAInit, "start": (*Handler).serveStart,
"tka/log": (*Handler).serveTKALog, "status": (*Handler).serveStatus,
"tka/modify": (*Handler).serveTKAModify, "tka/init": (*Handler).serveTKAInit,
"tka/sign": (*Handler).serveTKASign, "tka/log": (*Handler).serveTKALog,
"tka/status": (*Handler).serveTKAStatus, "tka/modify": (*Handler).serveTKAModify,
"tka/disable": (*Handler).serveTKADisable, "tka/sign": (*Handler).serveTKASign,
"tka/force-local-disable": (*Handler).serveTKALocalDisable, "tka/status": (*Handler).serveTKAStatus,
"upload-client-metrics": (*Handler).serveUploadClientMetrics, "tka/disable": (*Handler).serveTKADisable,
"watch-ipn-bus": (*Handler).serveWatchIPNBus, "tka/force-local-disable": (*Handler).serveTKALocalDisable,
"whois": (*Handler).serveWhoIs, "upload-client-metrics": (*Handler).serveUploadClientMetrics,
"watch-ipn-bus": (*Handler).serveWatchIPNBus,
"whois": (*Handler).serveWhoIs,
} }
func randHex(n int) string { func randHex(n int) string {
@ -506,6 +508,40 @@ func (h *Handler) serveDevSetStateStore(w http.ResponseWriter, r *http.Request)
io.WriteString(w, "done\n") io.WriteString(w, "done\n")
} }
func (h *Handler) serveDebugPacketFilterRules(w http.ResponseWriter, r *http.Request) {
if !h.PermitWrite {
http.Error(w, "debug access denied", http.StatusForbidden)
return
}
nm := h.b.NetMap()
if nm == nil {
http.Error(w, "no netmap", http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "application/json")
enc := json.NewEncoder(w)
enc.SetIndent("", "\t")
enc.Encode(nm.PacketFilterRules)
}
func (h *Handler) serveDebugPacketFilterMatches(w http.ResponseWriter, r *http.Request) {
if !h.PermitWrite {
http.Error(w, "debug access denied", http.StatusForbidden)
return
}
nm := h.b.NetMap()
if nm == nil {
http.Error(w, "no netmap", http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "application/json")
enc := json.NewEncoder(w)
enc.SetIndent("", "\t")
enc.Encode(nm.PacketFilter)
}
func (h *Handler) serveComponentDebugLogging(w http.ResponseWriter, r *http.Request) { func (h *Handler) serveComponentDebugLogging(w http.ResponseWriter, r *http.Request) {
if !h.PermitWrite { if !h.PermitWrite {
http.Error(w, "debug access denied", http.StatusForbidden) http.Error(w, "debug access denied", http.StatusForbidden)

@ -16,6 +16,7 @@ import (
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
"tailscale.com/tka" "tailscale.com/tka"
"tailscale.com/types/key" "tailscale.com/types/key"
"tailscale.com/types/views"
"tailscale.com/wgengine/filter" "tailscale.com/wgengine/filter"
) )
@ -38,9 +39,10 @@ type NetworkMap struct {
Peers []*tailcfg.Node // sorted by Node.ID Peers []*tailcfg.Node // sorted by Node.ID
DNS tailcfg.DNSConfig DNS tailcfg.DNSConfig
// TODO(maisem) : replace with View. // TODO(maisem) : replace with View.
Hostinfo tailcfg.Hostinfo Hostinfo tailcfg.Hostinfo
PacketFilter []filter.Match PacketFilter []filter.Match
SSHPolicy *tailcfg.SSHPolicy // or nil, if not enabled/allowed PacketFilterRules views.Slice[tailcfg.FilterRule]
SSHPolicy *tailcfg.SSHPolicy // or nil, if not enabled/allowed
// CollectServices reports whether this node's Tailnet has // CollectServices reports whether this node's Tailnet has
// requested that info about services be included in HostInfo. // requested that info about services be included in HostInfo.

Loading…
Cancel
Save