From 780c56e119f63cd9dcd622c2bcaf12a3ca309eca Mon Sep 17 00:00:00 2001 From: Mihai Parparita Date: Thu, 23 Feb 2023 11:48:03 -0800 Subject: [PATCH] ipn/ipnlocal: add delegated interface information to /interfaces PeerAPI handler Exposes the delegated interface data added by #7248 in the debug endpoint. I would have found it useful when working on that PR, and it may be handy in the future as well. Also makes the interfaces table slightly easier to parse by adding borders to it. To make then nicer-looking, the CSP was relaxed to allow inline styles. Signed-off-by: Mihai Parparita --- ipn/ipnlocal/peerapi.go | 17 ++++++++++++++--- net/interfaces/interfaces.go | 12 ++++++++++++ net/interfaces/interfaces_darwin.go | 16 ++++++++++++++++ 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/ipn/ipnlocal/peerapi.go b/ipn/ipnlocal/peerapi.go index e0f78ec85..1a85775ff 100644 --- a/ipn/ipnlocal/peerapi.go +++ b/ipn/ipnlocal/peerapi.go @@ -670,7 +670,7 @@ func (h *peerAPIHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } if peerAPIRequestShouldGetSecurityHeaders(r) { - w.Header().Set("Content-Security-Policy", `default-src 'none'; frame-ancestors 'none'; script-src 'none'; script-src-elem 'none'; script-src-attr 'none'`) + w.Header().Set("Content-Security-Policy", `default-src 'none'; frame-ancestors 'none'; script-src 'none'; script-src-elem 'none'; script-src-attr 'none'; style-src 'unsafe-inline'`) w.Header().Set("X-Frame-Options", "DENY") w.Header().Set("X-Content-Type-Options", "nosniff") } @@ -799,15 +799,21 @@ func (h *peerAPIHandler) handleServeInterfaces(w http.ResponseWriter, r *http.Re fmt.Fprintf(w, "

Could not get the default route: %s

\n", html.EscapeString(err.Error())) } + if hasCGNATInterface, err := interfaces.HasCGNATInterface(); hasCGNATInterface { + fmt.Fprintln(w, "

There is another interface using the CGNAT range.

") + } else if err != nil { + fmt.Fprintf(w, "

Could not check for CGNAT interfaces: %s

\n", html.EscapeString(err.Error())) + } + i, err := interfaces.GetList() if err != nil { fmt.Fprintf(w, "Could not get interfaces: %s\n", html.EscapeString(err.Error())) return } - fmt.Fprintln(w, "") + fmt.Fprintln(w, "
") fmt.Fprint(w, "") - for _, v := range []any{"Index", "Name", "MTU", "Flags", "Addrs"} { + for _, v := range []any{"Index", "Name", "MTU", "Flags", "Addrs", "Extra"} { fmt.Fprintf(w, " ", v) } fmt.Fprint(w, "\n") @@ -816,6 +822,11 @@ func (h *peerAPIHandler) handleServeInterfaces(w http.ResponseWriter, r *http.Re for _, v := range []any{iface.Index, iface.Name, iface.MTU, iface.Flags, ipps} { fmt.Fprintf(w, " ", html.EscapeString(fmt.Sprintf("%v", v))) } + if extras, err := interfaces.InterfaceDebugExtras(iface.Index); err == nil && extras != "" { + fmt.Fprintf(w, " ", html.EscapeString(extras)) + } else if err != nil { + fmt.Fprintf(w, " ", html.EscapeString(err.Error())) + } fmt.Fprint(w, "\n") }) fmt.Fprintln(w, "
%v
%s%s%s
") diff --git a/net/interfaces/interfaces.go b/net/interfaces/interfaces.go index c9d92dfcb..d5a76c511 100644 --- a/net/interfaces/interfaces.go +++ b/net/interfaces/interfaces.go @@ -756,3 +756,15 @@ func HasCGNATInterface() (bool, error) { } return hasCGNATInterface, nil } + +var interfaceDebugExtras func(ifIndex int) (string, error) + +// InterfaceDebugExtras returns extra debugging information about an interface +// if any (an empty string will be returned if there are no additional details). +// Formatting is platform-dependent and should not be parsed. +func InterfaceDebugExtras(ifIndex int) (string, error) { + if interfaceDebugExtras != nil { + return interfaceDebugExtras(ifIndex) + } + return "", nil +} diff --git a/net/interfaces/interfaces_darwin.go b/net/interfaces/interfaces_darwin.go index d16f1a5e7..6c68844fe 100644 --- a/net/interfaces/interfaces_darwin.go +++ b/net/interfaces/interfaces_darwin.go @@ -4,6 +4,7 @@ package interfaces import ( + "fmt" "net" "strings" "sync" @@ -29,6 +30,10 @@ var ifNames struct { m map[int]string // ifindex => name } +func init() { + interfaceDebugExtras = interfaceDebugExtrasDarwin +} + // getDelegatedInterface returns the interface index of the underlying interface // for the given interface index. 0 is returned if the interface does not // delegate. @@ -93,3 +98,14 @@ func getDelegatedInterface(ifIndex int) (int, error) { } return int(ifr.ifr_delegated), nil } + +func interfaceDebugExtrasDarwin(ifIndex int) (string, error) { + delegated, err := getDelegatedInterface(ifIndex) + if err != nil { + return "", err + } + if delegated == 0 { + return "", nil + } + return fmt.Sprintf("delegated=%d", delegated), nil +}