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 +}