diff --git a/client/server/mdm.go b/client/server/mdm.go index da0deb4f2..1ac010cea 100644 --- a/client/server/mdm.go +++ b/client/server/mdm.go @@ -207,6 +207,50 @@ func mdmManagedFieldConflicts(msg *proto.SetConfigRequest, policy *mdm.Policy) [ return conflicts } +// setConfigRequestHasConfigOverrides reports whether the SetConfigRequest +// carries ANY field that would actually mutate the persisted config. The +// CLI builds the request unconditionally on every `netbird up` (see +// setupSetConfigReq in cmd/up.go), so a plain `netbird up` results in a +// SetConfig call with every field at its zero value; the gate must skip +// such no-op invocations or it would always fire even when the user did +// not pass any --flag. +func setConfigRequestHasConfigOverrides(msg *proto.SetConfigRequest) bool { + if msg == nil { + return false + } + return msg.ManagementUrl != "" || + msg.AdminURL != "" || + msg.OptionalPreSharedKey != nil || + len(msg.CustomDNSAddress) > 0 || + len(msg.NatExternalIPs) > 0 || msg.CleanNATExternalIPs || + len(msg.ExtraIFaceBlacklist) > 0 || + len(msg.DnsLabels) > 0 || msg.CleanDNSLabels || + msg.DnsRouteInterval != nil || + msg.RosenpassEnabled != nil || + msg.RosenpassPermissive != nil || + msg.InterfaceName != nil || + msg.WireguardPort != nil || + msg.Mtu != nil || + msg.DisableAutoConnect != nil || + msg.ServerSSHAllowed != nil || + msg.NetworkMonitor != nil || + msg.DisableClientRoutes != nil || + msg.DisableServerRoutes != nil || + msg.DisableDns != nil || + msg.DisableFirewall != nil || + msg.BlockLanAccess != nil || + msg.DisableNotifications != nil || + msg.LazyConnectionEnabled != nil || + msg.BlockInbound != nil || + msg.DisableIpv6 != nil || + msg.EnableSSHRoot != nil || + msg.EnableSSHSFTP != nil || + msg.EnableSSHLocalPortForwarding != nil || + msg.EnableSSHRemotePortForwarding != nil || + msg.DisableSSHAuth != nil || + msg.SshJWTCacheTTL != nil +} + // loginRequestHasConfigOverrides reports whether the LoginRequest // carries ANY field that would mutate persisted daemon configuration // (as opposed to pure-auth fields like setupKey, hostname, hint, diff --git a/client/server/server.go b/client/server/server.go index a4a2e30d0..e27e0a467 100644 --- a/client/server/server.go +++ b/client/server/server.go @@ -322,8 +322,16 @@ func (s *Server) SetConfig(callerCtx context.Context, msg *proto.SetConfigReques s.mutex.Lock() defer s.mutex.Unlock() - if s.checkUpdateSettingsDisabled() { - return nil, gstatus.Errorf(codes.Unavailable, errUpdateSettingsDisabled) + // Skip the update-settings gate when the request carries no actual + // overrides: the CLI builds a SetConfigRequest unconditionally on + // every `netbird up` (setupSetConfigReq in cmd/up.go), so a plain + // `netbird up` would otherwise always trip the gate and surface a + // misleading "setConfig method is not available" warning, even when + // the user did not pass any config flag. + if setConfigRequestHasConfigOverrides(msg) { + if s.checkUpdateSettingsDisabled() { + return nil, gstatus.Errorf(codes.Unavailable, errUpdateSettingsDisabled) + } } // MDM gate: refuse the whole request if any of its fields is enforced