From 6a701e098fe0e182aa0b6e43c037740756f4e4bf Mon Sep 17 00:00:00 2001 From: zhongwencool Date: Sun, 30 Jan 2022 14:09:26 +0800 Subject: [PATCH 1/8] feat(shell): add restricted shell and user_default --- apps/emqx/etc/emqx_cloud/vm.args | 5 + apps/emqx/etc/emqx_edge/vm.args | 5 + apps/emqx/src/emqx_listeners.erl | 2 + apps/emqx_dashboard/src/emqx_dashboard.erl | 12 +-- .../src/emqx_restricted_shell.erl | 93 +++++++++++++++++++ apps/emqx_machine/src/user_default.erl | 29 ++++++ 6 files changed, 140 insertions(+), 6 deletions(-) create mode 100644 apps/emqx_machine/src/emqx_restricted_shell.erl create mode 100644 apps/emqx_machine/src/user_default.erl diff --git a/apps/emqx/etc/emqx_cloud/vm.args b/apps/emqx/etc/emqx_cloud/vm.args index 0ee4b1e15..8111eed38 100644 --- a/apps/emqx/etc/emqx_cloud/vm.args +++ b/apps/emqx/etc/emqx_cloud/vm.args @@ -36,6 +36,11 @@ ## Can be one of: inet_tcp, inet6_tcp, inet_tls #-proto_dist inet_tcp +## The shell is started in a restricted mode. +## In this mode, the shell evaluates a function call only if allowed. +## Prevent user from accidentally calling a function from the prompt that could harm a running system. +-stdlib restricted_shell emqx_restricted_shell + ## Specify SSL Options in the file if using SSL for Erlang Distribution. ## Used only when -proto_dist set to inet_tls #-ssl_dist_optfile {{ platform_etc_dir }}/ssl_dist.conf diff --git a/apps/emqx/etc/emqx_edge/vm.args b/apps/emqx/etc/emqx_edge/vm.args index 70ce81f9f..743068538 100644 --- a/apps/emqx/etc/emqx_edge/vm.args +++ b/apps/emqx/etc/emqx_edge/vm.args @@ -35,6 +35,11 @@ ## Can be one of: inet_tcp, inet6_tcp, inet_tls #-proto_dist inet_tcp +## The shell is started in a restricted mode. +## In this mode, the shell evaluates a function call only if allowed. +## Prevent user from accidentally calling a function from the prompt that could harm a running system. +-stdlib restricted_shell emqx_restricted_shell + ## Specify SSL Options in the file if using SSL for Erlang Distribution. ## Used only when -proto_dist set to inet_tls #-ssl_dist_optfile {{ platform_etc_dir }}/ssl_dist.conf diff --git a/apps/emqx/src/emqx_listeners.erl b/apps/emqx/src/emqx_listeners.erl index 163e3eb39..c8aaadb70 100644 --- a/apps/emqx/src/emqx_listeners.erl +++ b/apps/emqx/src/emqx_listeners.erl @@ -48,6 +48,8 @@ -export([post_config_update/5]). +-export([format_addr/1]). + -define(CONF_KEY_PATH, [listeners]). -define(TYPES_STRING, ["tcp","ssl","ws","wss","quic"]). diff --git a/apps/emqx_dashboard/src/emqx_dashboard.erl b/apps/emqx_dashboard/src/emqx_dashboard.erl index 1777dbd86..5e512e201 100644 --- a/apps/emqx_dashboard/src/emqx_dashboard.erl +++ b/apps/emqx_dashboard/src/emqx_dashboard.erl @@ -62,11 +62,11 @@ start_listeners() -> middlewares => [cowboy_router, ?EMQX_MIDDLE, cowboy_handler] }, Res = - lists:foldl(fun({Name, Protocol, Port, RanchOptions}, Acc) -> + lists:foldl(fun({Name, Protocol, Bind, RanchOptions}, Acc) -> Minirest = BaseMinirest#{protocol => Protocol}, case minirest:start(Name, RanchOptions, Minirest) of {ok, _} -> - ?ULOG("Start listener ~ts on ~p successfully.~n", [Name, Port]), + ?ULOG("Listener ~ts on ~ts started.~n", [Name, emqx_listeners:format_addr(Bind)]), Acc; {error, _Reason} -> %% Don't record the reason because minirest already does(too much logs noise). @@ -82,7 +82,7 @@ stop_listeners() -> [begin case minirest:stop(Name) of ok -> - ?ULOG("Stop listener ~ts on ~p successfully.~n", [Name, Port]); + ?ULOG("Listener ~ts on ~ts stopped.~n", [Name, emqx_listeners:format_addr(Port)]); {error, not_found} -> ?SLOG(warning, #{msg => "stop_listener_failed", name => Name, port => Port}) end @@ -101,17 +101,17 @@ apps() -> listeners() -> [begin Protocol = maps:get(protocol, ListenerOption0, http), - {ListenerOption, Port} = ip_port(ListenerOption0), + {ListenerOption, Bind} = ip_port(ListenerOption0), Name = listener_name(Protocol, ListenerOption), RanchOptions = ranch_opts(maps:without([protocol], ListenerOption)), - {Name, Protocol, Port, RanchOptions} + {Name, Protocol, Bind, RanchOptions} end || ListenerOption0 <- emqx_conf:get([dashboard, listeners], [])]. ip_port(Opts) -> ip_port(maps:take(bind, Opts), Opts). ip_port(error, Opts) -> {Opts#{port => 18083}, 18083}; ip_port({Port, Opts}, _) when is_integer(Port) -> {Opts#{port => Port}, Port}; -ip_port({{IP, Port}, Opts}, _) -> {Opts#{port => Port, ip => IP}, Port}. +ip_port({{IP, Port}, Opts}, _) -> {Opts#{port => Port, ip => IP}, {IP, Port}}. ranch_opts(RanchOptions) -> diff --git a/apps/emqx_machine/src/emqx_restricted_shell.erl b/apps/emqx_machine/src/emqx_restricted_shell.erl new file mode 100644 index 000000000..f0bcf3424 --- /dev/null +++ b/apps/emqx_machine/src/emqx_restricted_shell.erl @@ -0,0 +1,93 @@ +%%-------------------------------------------------------------------- +%% Copyright (c) 2021-2022 EMQ Technologies Co., Ltd. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%%-------------------------------------------------------------------- + +-module(emqx_restricted_shell). + +-export([local_allowed/3, non_local_allowed/3]). +-export([lock/0, unlock/0, is_locked/0]). + +-include_lib("emqx/include/logger.hrl"). + +-define(APP, 'emqx_machine'). +-define(IS_LOCKED, 'restricted.is_locked'). +-define(MAX_HEAP_SIZE, 1024 * 1024 * 1). +-define(MAX_ARGS_SIZE, 1024 * 10). + +-define(RED_BG, "\e[48;2;184;0;0m"). +-define(RESET, "\e[0m"). + +-define(LOCAL_NOT_ALLOWED, [halt, q]). +-define(NON_LOCAL_NOT_ALLOWED, [{erlang, halt}, {c, q}, {init, stop}, {init, restart}, {init, reboot}]). + +is_locked() -> + {ok, false} =/= application:get_env(?APP, ?IS_LOCKED). + +lock() -> application:set_env(?APP, ?IS_LOCKED, true). +unlock() -> application:set_env(?APP, ?IS_LOCKED, false). + +local_allowed(MF, Args, State) -> + IsAllowed = is_allowed(MF, ?LOCAL_NOT_ALLOWED), + log(IsAllowed, MF, Args), + {IsAllowed, State}. + +non_local_allowed(MF, Args, State) -> + IsAllowed = is_allowed(MF, ?NON_LOCAL_NOT_ALLOWED), + log(IsAllowed, MF, Args), + {IsAllowed, State}. + +is_allowed(MF, NotAllowed) -> + case lists:member(MF, NotAllowed) of + true -> not is_locked(); + false -> true + end. + +limit_warning(MF, Args) -> + max_heap_size_warning(MF, Args), + max_args_warning(MF, Args). + +max_args_warning(MF, Args) -> + ArgsSize = erts_debug:flat_size(Args), + case ArgsSize < ?MAX_ARGS_SIZE of + true -> ok; + false -> + warning("[WARNING] current_args_size:~w, max_args_size:~w", [ArgsSize, ?MAX_ARGS_SIZE]), + ?SLOG(warning, #{msg => "execute_function_in_shell_max_args_size", + function => MF, + args => Args, + args_size => ArgsSize, + max_heap_size => ?MAX_ARGS_SIZE}) + end. + +max_heap_size_warning(MF, Args) -> + {heap_size, HeapSize} = erlang:process_info(self(), heap_size), + case HeapSize < ?MAX_HEAP_SIZE of + true -> ok; + false -> + warning("[WARNING] current_heap_size:~w, max_heap_size_warning:~w", [HeapSize, ?MAX_HEAP_SIZE]), + ?SLOG(warning, #{msg => "shell_process_exceed_max_heap_size", + current_heap_size => HeapSize, + function => MF, + args => Args, + max_heap_size => ?MAX_HEAP_SIZE}) + end. + +log(true, MF, Args) -> limit_warning(MF, Args); +log(false, MF, Args) -> + warning("DANGEROUS FUNCTION: DO NOT ALLOWED IN SHELL!!!!!", []), + ?SLOG(error, #{msg => "execute_function_in_shell_not_allowed", function => MF, args => Args}). + +warning(Format, Args) -> + io:format(?RED_BG ++ Format ++ ?RESET ++ "~n", Args). diff --git a/apps/emqx_machine/src/user_default.erl b/apps/emqx_machine/src/user_default.erl new file mode 100644 index 000000000..0071db837 --- /dev/null +++ b/apps/emqx_machine/src/user_default.erl @@ -0,0 +1,29 @@ +%%-------------------------------------------------------------------- +%% Copyright (c) 2021-2022 EMQ Technologies Co., Ltd. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%%-------------------------------------------------------------------- +-module(user_default). + +-include_lib("emqx/include/emqx.hrl"). +-include_lib("emqx/include/logger.hrl"). +-include_lib("emqx/include/emqx_mqtt.hrl"). +-include_lib("emqx_conf/include/emqx_conf.hrl"). +-include_lib("emqx_dashboard/include/emqx_dashboard.hrl"). +-include_lib("emqx_slow_subs/include/emqx_slow_subs.hrl"). + +%% API +-export([lock/0, unlock/0]). + +lock() -> emqx_restricted_shell:lock(). +unlock() -> emqx_restricted_shell:unlock(). From 3efa5838303865ceee47b5e7cb3189bff7c73e4a Mon Sep 17 00:00:00 2001 From: zhongwencool Date: Sun, 30 Jan 2022 14:57:14 +0800 Subject: [PATCH 2/8] feat(shell): add emqx version to prompt. --- apps/emqx_machine/src/emqx_machine_app.erl | 1 + apps/emqx_machine/src/emqx_restricted_shell.erl | 12 ++++++++++++ apps/emqx_machine/src/user_default.erl | 1 - 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/apps/emqx_machine/src/emqx_machine_app.erl b/apps/emqx_machine/src/emqx_machine_app.erl index 9e96ea234..bae1cecdf 100644 --- a/apps/emqx_machine/src/emqx_machine_app.erl +++ b/apps/emqx_machine/src/emqx_machine_app.erl @@ -24,6 +24,7 @@ start(_Type, _Args) -> ok = emqx_machine:start(), + emqx_restricted_shell:set_prompt_func(), emqx_machine_sup:start_link(). stop(_State) -> diff --git a/apps/emqx_machine/src/emqx_restricted_shell.erl b/apps/emqx_machine/src/emqx_restricted_shell.erl index f0bcf3424..f45f880a7 100644 --- a/apps/emqx_machine/src/emqx_restricted_shell.erl +++ b/apps/emqx_machine/src/emqx_restricted_shell.erl @@ -17,6 +17,7 @@ -module(emqx_restricted_shell). -export([local_allowed/3, non_local_allowed/3]). +-export([set_prompt_func/0, prompt_func/1]). -export([lock/0, unlock/0, is_locked/0]). -include_lib("emqx/include/logger.hrl"). @@ -38,6 +39,17 @@ is_locked() -> lock() -> application:set_env(?APP, ?IS_LOCKED, true). unlock() -> application:set_env(?APP, ?IS_LOCKED, false). +set_prompt_func() -> + shell:prompt_func({?MODULE, prompt_func}). + +prompt_func(PropList) -> + Line = proplists:get_value(history, PropList, 1), + Version = emqx_release:version(), + case is_alive() of + true -> io_lib:format(<<"~ts(~s)~w> ">>, [Version, node(), Line]); + false -> io_lib:format(<<"~ts ~w> ">>, [Version, Line]) + end. + local_allowed(MF, Args, State) -> IsAllowed = is_allowed(MF, ?LOCAL_NOT_ALLOWED), log(IsAllowed, MF, Args), diff --git a/apps/emqx_machine/src/user_default.erl b/apps/emqx_machine/src/user_default.erl index 0071db837..86ed5adb6 100644 --- a/apps/emqx_machine/src/user_default.erl +++ b/apps/emqx_machine/src/user_default.erl @@ -20,7 +20,6 @@ -include_lib("emqx/include/emqx_mqtt.hrl"). -include_lib("emqx_conf/include/emqx_conf.hrl"). -include_lib("emqx_dashboard/include/emqx_dashboard.hrl"). --include_lib("emqx_slow_subs/include/emqx_slow_subs.hrl"). %% API -export([lock/0, unlock/0]). From b189d594c323d30845459316895369408aeb734a Mon Sep 17 00:00:00 2001 From: zhongwencool Date: Sun, 30 Jan 2022 15:35:48 +0800 Subject: [PATCH 3/8] chore: fix dialyzer warning. --- apps/emqx_machine/src/emqx_machine_app.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/emqx_machine/src/emqx_machine_app.erl b/apps/emqx_machine/src/emqx_machine_app.erl index bae1cecdf..ae837db2c 100644 --- a/apps/emqx_machine/src/emqx_machine_app.erl +++ b/apps/emqx_machine/src/emqx_machine_app.erl @@ -24,7 +24,7 @@ start(_Type, _Args) -> ok = emqx_machine:start(), - emqx_restricted_shell:set_prompt_func(), + _ = emqx_restricted_shell:set_prompt_func(), emqx_machine_sup:start_link(). stop(_State) -> From f24c05b1bdc31d540afe417fddf3dbac61ccc68e Mon Sep 17 00:00:00 2001 From: zhongwencool Date: Mon, 7 Feb 2022 10:31:00 +0800 Subject: [PATCH 4/8] chore(shell): make restricted_shell prompt more friendly. --- .../src/emqx_restricted_shell.erl | 39 +++++++++++-------- apps/emqx_machine/src/user_default.erl | 3 ++ 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/apps/emqx_machine/src/emqx_restricted_shell.erl b/apps/emqx_machine/src/emqx_restricted_shell.erl index f45f880a7..d855b7aff 100644 --- a/apps/emqx_machine/src/emqx_restricted_shell.erl +++ b/apps/emqx_machine/src/emqx_restricted_shell.erl @@ -30,8 +30,8 @@ -define(RED_BG, "\e[48;2;184;0;0m"). -define(RESET, "\e[0m"). --define(LOCAL_NOT_ALLOWED, [halt, q]). --define(NON_LOCAL_NOT_ALLOWED, [{erlang, halt}, {c, q}, {init, stop}, {init, restart}, {init, reboot}]). +-define(LOCAL_PROHIBITED, [halt, q]). +-define(REMOTE_PROHIBITED, [{erlang, halt}, {c, q}, {init, stop}, {init, restart}, {init, reboot}]). is_locked() -> {ok, false} =/= application:get_env(?APP, ?IS_LOCKED). @@ -51,21 +51,25 @@ prompt_func(PropList) -> end. local_allowed(MF, Args, State) -> - IsAllowed = is_allowed(MF, ?LOCAL_NOT_ALLOWED), - log(IsAllowed, MF, Args), - {IsAllowed, State}. + Allowed = check_allowed(MF, ?LOCAL_PROHIBITED), + log(Allowed, MF, Args), + {is_allowed(Allowed), State}. non_local_allowed(MF, Args, State) -> - IsAllowed = is_allowed(MF, ?NON_LOCAL_NOT_ALLOWED), - log(IsAllowed, MF, Args), - {IsAllowed, State}. + Allow = check_allowed(MF, ?REMOTE_PROHIBITED), + log(Allow, MF, Args), + {is_allowed(Allow), State}. -is_allowed(MF, NotAllowed) -> - case lists:member(MF, NotAllowed) of - true -> not is_locked(); - false -> true +check_allowed(MF, NotAllowed) -> + case {lists:member(MF, NotAllowed), is_locked()} of + {true, false} -> exempted; + {true, true} -> prohibited; + {false, _} -> ignore end. +is_allowed(prohibited) -> false; +is_allowed(_) -> true. + limit_warning(MF, Args) -> max_heap_size_warning(MF, Args), max_args_warning(MF, Args). @@ -96,10 +100,13 @@ max_heap_size_warning(MF, Args) -> max_heap_size => ?MAX_HEAP_SIZE}) end. -log(true, MF, Args) -> limit_warning(MF, Args); -log(false, MF, Args) -> - warning("DANGEROUS FUNCTION: DO NOT ALLOWED IN SHELL!!!!!", []), - ?SLOG(error, #{msg => "execute_function_in_shell_not_allowed", function => MF, args => Args}). +log(prohibited, MF, Args) -> + warning("DANGEROUS FUNCTION: FORBIDDEN IN SHELL!!!!!", []), + ?SLOG(error, #{msg => "execute_function_in_shell_prohibited", function => MF, args => Args}); +log(exempted, MF, Args) -> + limit_warning(MF, Args), + ?SLOG(error, #{msg => "execute_dangerous_function_in_shell_exempted", function => MF, args => Args}); +log(ignore, MF, Args) -> limit_warning(MF, Args). warning(Format, Args) -> io:format(?RED_BG ++ Format ++ ?RESET ++ "~n", Args). diff --git a/apps/emqx_machine/src/user_default.erl b/apps/emqx_machine/src/user_default.erl index 86ed5adb6..91899be61 100644 --- a/apps/emqx_machine/src/user_default.erl +++ b/apps/emqx_machine/src/user_default.erl @@ -15,11 +15,14 @@ %%-------------------------------------------------------------------- -module(user_default). +%% INCLUDE BEGIN +%% Import all the record definitions from the header file into the erlang shell. -include_lib("emqx/include/emqx.hrl"). -include_lib("emqx/include/logger.hrl"). -include_lib("emqx/include/emqx_mqtt.hrl"). -include_lib("emqx_conf/include/emqx_conf.hrl"). -include_lib("emqx_dashboard/include/emqx_dashboard.hrl"). +%% INCLUDE END %% API -export([lock/0, unlock/0]). From b50ceac9bbf203074133514338bbd9ddfde640bd Mon Sep 17 00:00:00 2001 From: zhongwencool Date: Tue, 8 Feb 2022 10:28:10 +0800 Subject: [PATCH 5/8] chore(listener): change the listener binding format 0.0.0.0:port to :port. --- apps/emqx/src/emqx_listeners.erl | 2 +- apps/emqx_dashboard/src/emqx_dashboard.erl | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/emqx/src/emqx_listeners.erl b/apps/emqx/src/emqx_listeners.erl index c8aaadb70..c72baa743 100644 --- a/apps/emqx/src/emqx_listeners.erl +++ b/apps/emqx/src/emqx_listeners.erl @@ -365,7 +365,7 @@ merge_default(Options) -> end. format_addr(Port) when is_integer(Port) -> - io_lib:format("0.0.0.0:~w", [Port]); + io_lib:format(":~w", [Port]); format_addr({Addr, Port}) when is_list(Addr) -> io_lib:format("~ts:~w", [Addr, Port]); format_addr({Addr, Port}) when is_tuple(Addr) -> diff --git a/apps/emqx_dashboard/src/emqx_dashboard.erl b/apps/emqx_dashboard/src/emqx_dashboard.erl index 5e512e201..168eb2457 100644 --- a/apps/emqx_dashboard/src/emqx_dashboard.erl +++ b/apps/emqx_dashboard/src/emqx_dashboard.erl @@ -66,7 +66,7 @@ start_listeners() -> Minirest = BaseMinirest#{protocol => Protocol}, case minirest:start(Name, RanchOptions, Minirest) of {ok, _} -> - ?ULOG("Listener ~ts on ~ts started.~n", [Name, emqx_listeners:format_addr(Bind)]), + ?ULOG("Start listener ~ts on ~p successfully.~n", [Name, emqx_listeners:format_addr(Bind)]), Acc; {error, _Reason} -> %% Don't record the reason because minirest already does(too much logs noise). @@ -82,7 +82,7 @@ stop_listeners() -> [begin case minirest:stop(Name) of ok -> - ?ULOG("Listener ~ts on ~ts stopped.~n", [Name, emqx_listeners:format_addr(Port)]); + ?ULOG("Stop listener ~ts on ~p successfully.~n", [Name, emqx_listeners:format_addr(Port)]); {error, not_found} -> ?SLOG(warning, #{msg => "stop_listener_failed", name => Name, port => Port}) end From 00fe86639245a95d88324f749c4e4d6fa1bc0f15 Mon Sep 17 00:00:00 2001 From: zhongwencool Date: Tue, 8 Feb 2022 10:49:11 +0800 Subject: [PATCH 6/8] chore(test): add restricted_shell CT test. --- .../test/emqx_restricted_shell_SUITE.erl | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 apps/emqx_machine/test/emqx_restricted_shell_SUITE.erl diff --git a/apps/emqx_machine/test/emqx_restricted_shell_SUITE.erl b/apps/emqx_machine/test/emqx_restricted_shell_SUITE.erl new file mode 100644 index 000000000..4ae0e66a2 --- /dev/null +++ b/apps/emqx_machine/test/emqx_restricted_shell_SUITE.erl @@ -0,0 +1,72 @@ +%%-------------------------------------------------------------------- +%% Copyright (c) 2020-2022 EMQ Technologies Co., Ltd. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%%-------------------------------------------------------------------- + +-module(emqx_restricted_shell_SUITE). + +-compile(export_all). +-compile(nowarn_export_all). + +-include_lib("emqx/include/emqx.hrl"). +-include_lib("eunit/include/eunit.hrl"). +-include_lib("common_test/include/ct.hrl"). + +all() -> emqx_common_test_helpers:all(?MODULE). + +init_per_suite(Config) -> + emqx_common_test_helpers:start_apps([]), + Config. + +end_per_suite(_Config) -> + emqx_common_test_helpers:stop_apps([]). + +t_local_allowed(_Config) -> + LocalProhibited = [halt, q], + State = undefined, + lists:foreach(fun(LocalFunc) -> + ?assertEqual({false, State}, emqx_restricted_shell:local_allowed(LocalFunc, [], State)) + end, LocalProhibited), + LocalAllowed = [ls, pwd], + lists:foreach(fun(LocalFunc) -> + ?assertEqual({true, State},emqx_restricted_shell:local_allowed(LocalFunc, [], State)) + end, LocalAllowed), + ok. + +t_non_local_allowed(_Config) -> + RemoteProhibited = [{erlang, halt}, {c, q}, {init, stop}, {init, restart}, {init, reboot}], + State = undefined, + lists:foreach(fun(RemoteFunc) -> + ?assertEqual({false, State}, emqx_restricted_shell:non_local_allowed(RemoteFunc, [], State)) + end, RemoteProhibited), + RemoteAllowed = [{erlang, date}, {erlang, system_time}], + lists:foreach(fun(RemoteFunc) -> + ?assertEqual({true, State}, emqx_restricted_shell:local_allowed(RemoteFunc, [], State)) + end, RemoteAllowed), + ok. + +t_lock(_Config) -> + State = undefined, + emqx_restricted_shell:lock(), + ?assertEqual({false, State}, emqx_restricted_shell:local_allowed(q, [], State)), + ?assertEqual({true, State}, emqx_restricted_shell:local_allowed(ls, [], State)), + ?assertEqual({false, State}, emqx_restricted_shell:non_local_allowed({init, stop}, [], State)), + ?assertEqual({true, State}, emqx_restricted_shell:non_local_allowed({inet, getifaddrs}, [], State)), + emqx_restricted_shell:unlock(), + ?assertEqual({true, State}, emqx_restricted_shell:local_allowed(q, [], State)), + ?assertEqual({true, State}, emqx_restricted_shell:local_allowed(ls, [], State)), + ?assertEqual({true, State}, emqx_restricted_shell:non_local_allowed({init, stop}, [], State)), + ?assertEqual({true, State}, emqx_restricted_shell:non_local_allowed({inet, getifaddrs}, [], State)), + emqx_restricted_shell:lock(), + ok. From 5f2618912fcbf7440eb05f4da69000d9d4f3030e Mon Sep 17 00:00:00 2001 From: zhongwencool Date: Tue, 8 Feb 2022 11:03:54 +0800 Subject: [PATCH 7/8] chore(format): format port by ts --- apps/emqx_dashboard/src/emqx_dashboard.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/emqx_dashboard/src/emqx_dashboard.erl b/apps/emqx_dashboard/src/emqx_dashboard.erl index 168eb2457..37629c16e 100644 --- a/apps/emqx_dashboard/src/emqx_dashboard.erl +++ b/apps/emqx_dashboard/src/emqx_dashboard.erl @@ -66,7 +66,7 @@ start_listeners() -> Minirest = BaseMinirest#{protocol => Protocol}, case minirest:start(Name, RanchOptions, Minirest) of {ok, _} -> - ?ULOG("Start listener ~ts on ~p successfully.~n", [Name, emqx_listeners:format_addr(Bind)]), + ?ULOG("Start listener ~ts on ~ts successfully.~n", [Name, emqx_listeners:format_addr(Bind)]), Acc; {error, _Reason} -> %% Don't record the reason because minirest already does(too much logs noise). @@ -82,7 +82,7 @@ stop_listeners() -> [begin case minirest:stop(Name) of ok -> - ?ULOG("Stop listener ~ts on ~p successfully.~n", [Name, emqx_listeners:format_addr(Port)]); + ?ULOG("Stop listener ~ts on ~ts successfully.~n", [Name, emqx_listeners:format_addr(Port)]); {error, not_found} -> ?SLOG(warning, #{msg => "stop_listener_failed", name => Name, port => Port}) end From f3fa302d8403ab97b8e3bb20efd80163c9e94c31 Mon Sep 17 00:00:00 2001 From: zhongwencool Date: Tue, 8 Feb 2022 15:25:22 +0800 Subject: [PATCH 8/8] chore: print only the port number when bound on all interfaces. --- apps/emqx/src/emqx_listeners.erl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/emqx/src/emqx_listeners.erl b/apps/emqx/src/emqx_listeners.erl index c72baa743..a249447d3 100644 --- a/apps/emqx/src/emqx_listeners.erl +++ b/apps/emqx/src/emqx_listeners.erl @@ -366,6 +366,11 @@ merge_default(Options) -> format_addr(Port) when is_integer(Port) -> io_lib:format(":~w", [Port]); +%% Print only the port number when bound on all interfaces +format_addr({{0, 0, 0, 0}, Port}) -> + format_addr(Port); +format_addr({{0, 0, 0, 0, 0, 0, 0, 0}, Port}) -> + format_addr(Port); format_addr({Addr, Port}) when is_list(Addr) -> io_lib:format("~ts:~w", [Addr, Port]); format_addr({Addr, Port}) when is_tuple(Addr) ->