mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-18 08:16:39 +00:00
[client] Add --disable-networks flag to block network selection (#5896)
This commit is contained in:
@@ -75,6 +75,7 @@ var (
|
|||||||
mtu uint16
|
mtu uint16
|
||||||
profilesDisabled bool
|
profilesDisabled bool
|
||||||
updateSettingsDisabled bool
|
updateSettingsDisabled bool
|
||||||
|
networksDisabled bool
|
||||||
|
|
||||||
rootCmd = &cobra.Command{
|
rootCmd = &cobra.Command{
|
||||||
Use: "netbird",
|
Use: "netbird",
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ func init() {
|
|||||||
serviceCmd.AddCommand(runCmd, startCmd, stopCmd, restartCmd, svcStatusCmd, installCmd, uninstallCmd, reconfigureCmd, resetParamsCmd)
|
serviceCmd.AddCommand(runCmd, startCmd, stopCmd, restartCmd, svcStatusCmd, installCmd, uninstallCmd, reconfigureCmd, resetParamsCmd)
|
||||||
serviceCmd.PersistentFlags().BoolVar(&profilesDisabled, "disable-profiles", false, "Disables profiles feature. If enabled, the client will not be able to change or edit any profile. To persist this setting, use: netbird service install --disable-profiles")
|
serviceCmd.PersistentFlags().BoolVar(&profilesDisabled, "disable-profiles", false, "Disables profiles feature. If enabled, the client will not be able to change or edit any profile. To persist this setting, use: netbird service install --disable-profiles")
|
||||||
serviceCmd.PersistentFlags().BoolVar(&updateSettingsDisabled, "disable-update-settings", false, "Disables update settings feature. If enabled, the client will not be able to change or edit any settings. To persist this setting, use: netbird service install --disable-update-settings")
|
serviceCmd.PersistentFlags().BoolVar(&updateSettingsDisabled, "disable-update-settings", false, "Disables update settings feature. If enabled, the client will not be able to change or edit any settings. To persist this setting, use: netbird service install --disable-update-settings")
|
||||||
|
serviceCmd.PersistentFlags().BoolVar(&networksDisabled, "disable-networks", false, "Disables network selection. If enabled, the client will not allow listing, selecting, or deselecting networks. To persist, use: netbird service install --disable-networks")
|
||||||
|
|
||||||
rootCmd.PersistentFlags().StringVarP(&serviceName, "service", "s", defaultServiceName, "Netbird system service name")
|
rootCmd.PersistentFlags().StringVarP(&serviceName, "service", "s", defaultServiceName, "Netbird system service name")
|
||||||
serviceEnvDesc := `Sets extra environment variables for the service. ` +
|
serviceEnvDesc := `Sets extra environment variables for the service. ` +
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ func (p *program) Start(svc service.Service) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
serverInstance := server.New(p.ctx, util.FindFirstLogPath(logFiles), configPath, profilesDisabled, updateSettingsDisabled)
|
serverInstance := server.New(p.ctx, util.FindFirstLogPath(logFiles), configPath, profilesDisabled, updateSettingsDisabled, networksDisabled)
|
||||||
if err := serverInstance.Start(); err != nil {
|
if err := serverInstance.Start(); err != nil {
|
||||||
log.Fatalf("failed to start daemon: %v", err)
|
log.Fatalf("failed to start daemon: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,6 +59,10 @@ func buildServiceArguments() []string {
|
|||||||
args = append(args, "--disable-update-settings")
|
args = append(args, "--disable-update-settings")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if networksDisabled {
|
||||||
|
args = append(args, "--disable-networks")
|
||||||
|
}
|
||||||
|
|
||||||
return args
|
return args
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ type serviceParams struct {
|
|||||||
LogFiles []string `json:"log_files,omitempty"`
|
LogFiles []string `json:"log_files,omitempty"`
|
||||||
DisableProfiles bool `json:"disable_profiles,omitempty"`
|
DisableProfiles bool `json:"disable_profiles,omitempty"`
|
||||||
DisableUpdateSettings bool `json:"disable_update_settings,omitempty"`
|
DisableUpdateSettings bool `json:"disable_update_settings,omitempty"`
|
||||||
|
DisableNetworks bool `json:"disable_networks,omitempty"`
|
||||||
ServiceEnvVars map[string]string `json:"service_env_vars,omitempty"`
|
ServiceEnvVars map[string]string `json:"service_env_vars,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,6 +79,7 @@ func currentServiceParams() *serviceParams {
|
|||||||
LogFiles: logFiles,
|
LogFiles: logFiles,
|
||||||
DisableProfiles: profilesDisabled,
|
DisableProfiles: profilesDisabled,
|
||||||
DisableUpdateSettings: updateSettingsDisabled,
|
DisableUpdateSettings: updateSettingsDisabled,
|
||||||
|
DisableNetworks: networksDisabled,
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(serviceEnvVars) > 0 {
|
if len(serviceEnvVars) > 0 {
|
||||||
@@ -142,6 +144,10 @@ func applyServiceParams(cmd *cobra.Command, params *serviceParams) {
|
|||||||
updateSettingsDisabled = params.DisableUpdateSettings
|
updateSettingsDisabled = params.DisableUpdateSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !serviceCmd.PersistentFlags().Changed("disable-networks") {
|
||||||
|
networksDisabled = params.DisableNetworks
|
||||||
|
}
|
||||||
|
|
||||||
applyServiceEnvParams(cmd, params)
|
applyServiceEnvParams(cmd, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -535,6 +535,7 @@ func fieldToGlobalVar(field string) string {
|
|||||||
"LogFiles": "logFiles",
|
"LogFiles": "logFiles",
|
||||||
"DisableProfiles": "profilesDisabled",
|
"DisableProfiles": "profilesDisabled",
|
||||||
"DisableUpdateSettings": "updateSettingsDisabled",
|
"DisableUpdateSettings": "updateSettingsDisabled",
|
||||||
|
"DisableNetworks": "networksDisabled",
|
||||||
"ServiceEnvVars": "serviceEnvVars",
|
"ServiceEnvVars": "serviceEnvVars",
|
||||||
}
|
}
|
||||||
if v, ok := m[field]; ok {
|
if v, ok := m[field]; ok {
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ func startClientDaemon(
|
|||||||
s := grpc.NewServer()
|
s := grpc.NewServer()
|
||||||
|
|
||||||
server := client.New(ctx,
|
server := client.New(ctx,
|
||||||
"", "", false, false)
|
"", "", false, false, false)
|
||||||
if err := server.Start(); err != nil {
|
if err := server.Start(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4979,6 +4979,7 @@ type GetFeaturesResponse struct {
|
|||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
DisableProfiles bool `protobuf:"varint,1,opt,name=disable_profiles,json=disableProfiles,proto3" json:"disable_profiles,omitempty"`
|
DisableProfiles bool `protobuf:"varint,1,opt,name=disable_profiles,json=disableProfiles,proto3" json:"disable_profiles,omitempty"`
|
||||||
DisableUpdateSettings bool `protobuf:"varint,2,opt,name=disable_update_settings,json=disableUpdateSettings,proto3" json:"disable_update_settings,omitempty"`
|
DisableUpdateSettings bool `protobuf:"varint,2,opt,name=disable_update_settings,json=disableUpdateSettings,proto3" json:"disable_update_settings,omitempty"`
|
||||||
|
DisableNetworks bool `protobuf:"varint,3,opt,name=disable_networks,json=disableNetworks,proto3" json:"disable_networks,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
}
|
}
|
||||||
@@ -5027,6 +5028,13 @@ func (x *GetFeaturesResponse) GetDisableUpdateSettings() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *GetFeaturesResponse) GetDisableNetworks() bool {
|
||||||
|
if x != nil {
|
||||||
|
return x.DisableNetworks
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
type TriggerUpdateRequest struct {
|
type TriggerUpdateRequest struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
@@ -6472,10 +6480,11 @@ const file_daemon_proto_rawDesc = "" +
|
|||||||
"\f_profileNameB\v\n" +
|
"\f_profileNameB\v\n" +
|
||||||
"\t_username\"\x10\n" +
|
"\t_username\"\x10\n" +
|
||||||
"\x0eLogoutResponse\"\x14\n" +
|
"\x0eLogoutResponse\"\x14\n" +
|
||||||
"\x12GetFeaturesRequest\"x\n" +
|
"\x12GetFeaturesRequest\"\xa3\x01\n" +
|
||||||
"\x13GetFeaturesResponse\x12)\n" +
|
"\x13GetFeaturesResponse\x12)\n" +
|
||||||
"\x10disable_profiles\x18\x01 \x01(\bR\x0fdisableProfiles\x126\n" +
|
"\x10disable_profiles\x18\x01 \x01(\bR\x0fdisableProfiles\x126\n" +
|
||||||
"\x17disable_update_settings\x18\x02 \x01(\bR\x15disableUpdateSettings\"\x16\n" +
|
"\x17disable_update_settings\x18\x02 \x01(\bR\x15disableUpdateSettings\x12)\n" +
|
||||||
|
"\x10disable_networks\x18\x03 \x01(\bR\x0fdisableNetworks\"\x16\n" +
|
||||||
"\x14TriggerUpdateRequest\"M\n" +
|
"\x14TriggerUpdateRequest\"M\n" +
|
||||||
"\x15TriggerUpdateResponse\x12\x18\n" +
|
"\x15TriggerUpdateResponse\x12\x18\n" +
|
||||||
"\asuccess\x18\x01 \x01(\bR\asuccess\x12\x1a\n" +
|
"\asuccess\x18\x01 \x01(\bR\asuccess\x12\x1a\n" +
|
||||||
|
|||||||
@@ -727,6 +727,7 @@ message GetFeaturesRequest{}
|
|||||||
message GetFeaturesResponse{
|
message GetFeaturesResponse{
|
||||||
bool disable_profiles = 1;
|
bool disable_profiles = 1;
|
||||||
bool disable_update_settings = 2;
|
bool disable_update_settings = 2;
|
||||||
|
bool disable_networks = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message TriggerUpdateRequest {}
|
message TriggerUpdateRequest {}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"golang.org/x/exp/maps"
|
"golang.org/x/exp/maps"
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
gstatus "google.golang.org/grpc/status"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/client/proto"
|
"github.com/netbirdio/netbird/client/proto"
|
||||||
"github.com/netbirdio/netbird/route"
|
"github.com/netbirdio/netbird/route"
|
||||||
@@ -27,6 +29,10 @@ func (s *Server) ListNetworks(context.Context, *proto.ListNetworksRequest) (*pro
|
|||||||
s.mutex.Lock()
|
s.mutex.Lock()
|
||||||
defer s.mutex.Unlock()
|
defer s.mutex.Unlock()
|
||||||
|
|
||||||
|
if s.networksDisabled {
|
||||||
|
return nil, gstatus.Errorf(codes.Unavailable, errNetworksDisabled)
|
||||||
|
}
|
||||||
|
|
||||||
if s.connectClient == nil {
|
if s.connectClient == nil {
|
||||||
return nil, fmt.Errorf("not connected")
|
return nil, fmt.Errorf("not connected")
|
||||||
}
|
}
|
||||||
@@ -118,6 +124,10 @@ func (s *Server) SelectNetworks(_ context.Context, req *proto.SelectNetworksRequ
|
|||||||
s.mutex.Lock()
|
s.mutex.Lock()
|
||||||
defer s.mutex.Unlock()
|
defer s.mutex.Unlock()
|
||||||
|
|
||||||
|
if s.networksDisabled {
|
||||||
|
return nil, gstatus.Errorf(codes.Unavailable, errNetworksDisabled)
|
||||||
|
}
|
||||||
|
|
||||||
if s.connectClient == nil {
|
if s.connectClient == nil {
|
||||||
return nil, fmt.Errorf("not connected")
|
return nil, fmt.Errorf("not connected")
|
||||||
}
|
}
|
||||||
@@ -164,6 +174,10 @@ func (s *Server) DeselectNetworks(_ context.Context, req *proto.SelectNetworksRe
|
|||||||
s.mutex.Lock()
|
s.mutex.Lock()
|
||||||
defer s.mutex.Unlock()
|
defer s.mutex.Unlock()
|
||||||
|
|
||||||
|
if s.networksDisabled {
|
||||||
|
return nil, gstatus.Errorf(codes.Unavailable, errNetworksDisabled)
|
||||||
|
}
|
||||||
|
|
||||||
if s.connectClient == nil {
|
if s.connectClient == nil {
|
||||||
return nil, fmt.Errorf("not connected")
|
return nil, fmt.Errorf("not connected")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ const (
|
|||||||
errRestoreResidualState = "failed to restore residual state: %v"
|
errRestoreResidualState = "failed to restore residual state: %v"
|
||||||
errProfilesDisabled = "profiles are disabled, you cannot use this feature without profiles enabled"
|
errProfilesDisabled = "profiles are disabled, you cannot use this feature without profiles enabled"
|
||||||
errUpdateSettingsDisabled = "update settings are disabled, you cannot use this feature without update settings enabled"
|
errUpdateSettingsDisabled = "update settings are disabled, you cannot use this feature without update settings enabled"
|
||||||
|
errNetworksDisabled = "network selection is disabled by the administrator"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrServiceNotUp = errors.New("service is not up")
|
var ErrServiceNotUp = errors.New("service is not up")
|
||||||
@@ -88,6 +89,7 @@ type Server struct {
|
|||||||
profileManager *profilemanager.ServiceManager
|
profileManager *profilemanager.ServiceManager
|
||||||
profilesDisabled bool
|
profilesDisabled bool
|
||||||
updateSettingsDisabled bool
|
updateSettingsDisabled bool
|
||||||
|
networksDisabled bool
|
||||||
|
|
||||||
sleepHandler *sleephandler.SleepHandler
|
sleepHandler *sleephandler.SleepHandler
|
||||||
|
|
||||||
@@ -104,7 +106,7 @@ type oauthAuthFlow struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// New server instance constructor.
|
// New server instance constructor.
|
||||||
func New(ctx context.Context, logFile string, configFile string, profilesDisabled bool, updateSettingsDisabled bool) *Server {
|
func New(ctx context.Context, logFile string, configFile string, profilesDisabled bool, updateSettingsDisabled bool, networksDisabled bool) *Server {
|
||||||
s := &Server{
|
s := &Server{
|
||||||
rootCtx: ctx,
|
rootCtx: ctx,
|
||||||
logFile: logFile,
|
logFile: logFile,
|
||||||
@@ -113,6 +115,7 @@ func New(ctx context.Context, logFile string, configFile string, profilesDisable
|
|||||||
profileManager: profilemanager.NewServiceManager(configFile),
|
profileManager: profilemanager.NewServiceManager(configFile),
|
||||||
profilesDisabled: profilesDisabled,
|
profilesDisabled: profilesDisabled,
|
||||||
updateSettingsDisabled: updateSettingsDisabled,
|
updateSettingsDisabled: updateSettingsDisabled,
|
||||||
|
networksDisabled: networksDisabled,
|
||||||
jwtCache: newJWTCache(),
|
jwtCache: newJWTCache(),
|
||||||
}
|
}
|
||||||
agent := &serverAgent{s}
|
agent := &serverAgent{s}
|
||||||
@@ -1628,6 +1631,7 @@ func (s *Server) GetFeatures(ctx context.Context, msg *proto.GetFeaturesRequest)
|
|||||||
features := &proto.GetFeaturesResponse{
|
features := &proto.GetFeaturesResponse{
|
||||||
DisableProfiles: s.checkProfilesDisabled(),
|
DisableProfiles: s.checkProfilesDisabled(),
|
||||||
DisableUpdateSettings: s.checkUpdateSettingsDisabled(),
|
DisableUpdateSettings: s.checkUpdateSettingsDisabled(),
|
||||||
|
DisableNetworks: s.networksDisabled,
|
||||||
}
|
}
|
||||||
|
|
||||||
return features, nil
|
return features, nil
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ func TestConnectWithRetryRuns(t *testing.T) {
|
|||||||
t.Fatalf("failed to set active profile state: %v", err)
|
t.Fatalf("failed to set active profile state: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
s := New(ctx, "debug", "", false, false)
|
s := New(ctx, "debug", "", false, false, false)
|
||||||
|
|
||||||
s.config = config
|
s.config = config
|
||||||
|
|
||||||
@@ -164,7 +164,7 @@ func TestServer_Up(t *testing.T) {
|
|||||||
t.Fatalf("failed to set active profile state: %v", err)
|
t.Fatalf("failed to set active profile state: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
s := New(ctx, "console", "", false, false)
|
s := New(ctx, "console", "", false, false, false)
|
||||||
err = s.Start()
|
err = s.Start()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@@ -234,7 +234,7 @@ func TestServer_SubcribeEvents(t *testing.T) {
|
|||||||
t.Fatalf("failed to set active profile state: %v", err)
|
t.Fatalf("failed to set active profile state: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
s := New(ctx, "console", "", false, false)
|
s := New(ctx, "console", "", false, false, false)
|
||||||
|
|
||||||
err = s.Start()
|
err = s.Start()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ func TestSetConfig_AllFieldsSaved(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
s := New(ctx, "console", "", false, false)
|
s := New(ctx, "console", "", false, false, false)
|
||||||
|
|
||||||
rosenpassEnabled := true
|
rosenpassEnabled := true
|
||||||
rosenpassPermissive := true
|
rosenpassPermissive := true
|
||||||
|
|||||||
@@ -314,6 +314,7 @@ type serviceClient struct {
|
|||||||
lastNotifiedVersion string
|
lastNotifiedVersion string
|
||||||
settingsEnabled bool
|
settingsEnabled bool
|
||||||
profilesEnabled bool
|
profilesEnabled bool
|
||||||
|
networksEnabled bool
|
||||||
showNetworks bool
|
showNetworks bool
|
||||||
wNetworks fyne.Window
|
wNetworks fyne.Window
|
||||||
wProfiles fyne.Window
|
wProfiles fyne.Window
|
||||||
@@ -368,6 +369,7 @@ func newServiceClient(args *newServiceClientArgs) *serviceClient {
|
|||||||
|
|
||||||
showAdvancedSettings: args.showSettings,
|
showAdvancedSettings: args.showSettings,
|
||||||
showNetworks: args.showNetworks,
|
showNetworks: args.showNetworks,
|
||||||
|
networksEnabled: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
s.eventHandler = newEventHandler(s)
|
s.eventHandler = newEventHandler(s)
|
||||||
@@ -920,8 +922,10 @@ func (s *serviceClient) updateStatus() error {
|
|||||||
s.mStatus.SetIcon(s.icConnectedDot)
|
s.mStatus.SetIcon(s.icConnectedDot)
|
||||||
s.mUp.Disable()
|
s.mUp.Disable()
|
||||||
s.mDown.Enable()
|
s.mDown.Enable()
|
||||||
s.mNetworks.Enable()
|
if s.networksEnabled {
|
||||||
s.mExitNode.Enable()
|
s.mNetworks.Enable()
|
||||||
|
s.mExitNode.Enable()
|
||||||
|
}
|
||||||
s.startExitNodeRefresh()
|
s.startExitNodeRefresh()
|
||||||
systrayIconState = true
|
systrayIconState = true
|
||||||
case status.Status == string(internal.StatusConnecting):
|
case status.Status == string(internal.StatusConnecting):
|
||||||
@@ -1093,14 +1097,14 @@ func (s *serviceClient) onTrayReady() {
|
|||||||
s.getSrvConfig()
|
s.getSrvConfig()
|
||||||
time.Sleep(100 * time.Millisecond) // To prevent race condition caused by systray not being fully initialized and ignoring setIcon
|
time.Sleep(100 * time.Millisecond) // To prevent race condition caused by systray not being fully initialized and ignoring setIcon
|
||||||
for {
|
for {
|
||||||
|
// Check features before status so menus respect disable flags before being enabled
|
||||||
|
s.checkAndUpdateFeatures()
|
||||||
|
|
||||||
err := s.updateStatus()
|
err := s.updateStatus()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error while updating status: %v", err)
|
log.Errorf("error while updating status: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check features periodically to handle daemon restarts
|
|
||||||
s.checkAndUpdateFeatures()
|
|
||||||
|
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -1299,6 +1303,16 @@ func (s *serviceClient) checkAndUpdateFeatures() {
|
|||||||
s.mProfile.setEnabled(profilesEnabled)
|
s.mProfile.setEnabled(profilesEnabled)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update networks and exit node menus based on current features
|
||||||
|
s.networksEnabled = features == nil || !features.DisableNetworks
|
||||||
|
if s.networksEnabled && s.connected {
|
||||||
|
s.mNetworks.Enable()
|
||||||
|
s.mExitNode.Enable()
|
||||||
|
} else {
|
||||||
|
s.mNetworks.Disable()
|
||||||
|
s.mExitNode.Disable()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// getFeatures from the daemon to determine which features are enabled/disabled.
|
// getFeatures from the daemon to determine which features are enabled/disabled.
|
||||||
|
|||||||
Reference in New Issue
Block a user