diff --git a/README.md b/README.md index ea64161..81a18aa 100644 --- a/README.md +++ b/README.md @@ -6,19 +6,22 @@ This part of code was extracted from [@socksy_bot](https://t.me/socksy_bot). Features -------- -* Promoted channels! See `mtproto_proxy_app.src` `tag` option. +* Promoted channels. See `tag` option. * "secure" randomized-packet-size protocol (34-symbol secrets starting with 'dd') to prevent detection by DPI -* Fake-TLS protocol (base64 secrets) - another protocol to prevent DPI detection -* Secure-only mode (only allow connections with 'dd' or fake-tls-base64-secrets). +* Fake-TLS protocol ('ee'/base64 secrets) - another protocol to prevent DPI detection +* Secure-only mode (only allow connections with 'dd' or fake-TLS). See `allowed_protocols` option. +* Connection limit policies - limit number of connections by IP / tls-domain / port; IP / tls-domain + blacklists / whitelists * Multiple ports with unique secret and promo tag for each port * Very high performance - can handle tens of thousands connections! Scales to all CPU cores. 1Gbps, 90k connections on 4-core/8Gb RAM cloud server. * Supports multiplexing (Many connections Client -> Proxy are wrapped to small amount of - connections Proxy -> Telegram Server) + connections Proxy -> Telegram Server) - lower pings and better OS network utilization * Protection from [replay attacks](https://habr.com/ru/post/452144/) used to detect proxies in some countries * Automatic telegram configuration reload (no need for restarts once per day) +* IPv6 for client connections * Most of the configuration options can be updated without service restart * Small codebase compared to official one, code is covered by automated tests * A lots of metrics could be exported (optional) @@ -27,20 +30,20 @@ How to install - one-line interactive installer ----------------------------------------------- This command will run [interactive script](https://gist.github.com/seriyps/dc00ad91bfd8a2058f30845cd0daed83) -that will install and configure proxy for your Ubuntu 18.04 server. +that will install and configure proxy for your Ubuntu / Debian / CentOS server. It will ask if you want to change default port/secret/ad-tag/protocols: ```bash curl -L -o mtp_install.sh https://git.io/fj5ru && bash mtp_install.sh ``` -You can also just provide port/secret/ad-tag/protocols as command line arguments: +You can also just provide port/secret/ad-tag/protocols/tls-domain as command line arguments: ```bash -curl -L -o mtp_install.sh https://git.io/fj5ru && bash mtp_install.sh -p 443 -s d0d6e111bada5511fcce9584deadbeef -t dcbe8f1493fa4cd9ab300891c0b5b326 -a dd -a tls +curl -L -o mtp_install.sh https://git.io/fj5ru && bash mtp_install.sh -p 443 -s d0d6e111bada5511fcce9584deadbeef -t dcbe8f1493fa4cd9ab300891c0b5b326 -a dd -a tls -d s3.amazonaws.com ``` -It does the same as described in [How to start OS-install - detailed](#how-to-start-os-install---detailed) but +It does the same as described in [How to start OS-install - detailed](#how-to-start-os-install---detailed), but generates config-file for you automatically. How to start - docker @@ -108,10 +111,24 @@ How to start OS-install - detailed -------------------------------------- -### Install deps (ubuntu 18.04) +### Install deps + +Ubuntu 18.xx / Ubuntu 19.xx / Debian 10: ```bash -sudo apt install erlang-nox erlang-dev build-essential +sudo apt install erlang-nox erlang-dev make sed diffutils tar +``` + +CentOS 7 + +```bash +# Enable "epel" and "Erlang solutions" repositories +sudo yum install wget \ + https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm \ + https://packages.erlang-solutions.com/erlang-solutions-1.0-1.noarch.rpm +# Install Erlang +sudo yum install erlang-compiler erlang-erts erlang-kernel erlang-stdlib erlang-syntax_tools \ + erlang-crypto erlang-inets erlang-sasl erlang-ssl ``` You need Erlang version 20 or higher! If your version is older, please, check @@ -273,12 +290,12 @@ You should disable all protocols other than `mtp_secure` by providing `allowed_p <..> ``` -### Only allow fake-TLS connections with base64-secrets +### Only allow fake-TLS connections with ee/base64-secrets Another censorship circumvention technique. MTPRoto proxy protocol pretends to be HTTPS web traffic (technically speaking, TLSv1.3 + HTTP/2). It's possible to only allow connections with this protocol by changing `allowed_protocols` to -be list with only `mtp_fake_tls`. You may also want to check `tls_allowed_domains` option. +be list with only `mtp_fake_tls`. ```erlang {mtproto_proxy, @@ -289,6 +306,85 @@ be list with only `mtp_fake_tls`. You may also want to check `tls_allowed_domain <..> ``` +### Connection limit policies + +Proxy supports flexible connection limit rules. It's possible to limit number of connections from +single IP or to single fake-TLS domain or to single port name; or any combination of them. +It also supports whitelists and blacklists: you can allow or forbid to connect from some IP or IP subnet +or with some TLS domains. + +Policy is set as value of `policy` config key and the value is the list of policy structures. +If list is empty, no limits will be checked. + +Following policies are supported: + +* `{max_connections, KEYS, NUMBER}` - EXPERIMENTAL! if there are more than NUMBER connections with + KEYS to the proxy, new connections with those KEYS will be rejected +* `{in_table, KEY, TABLE_NAME}` - only allow connections if KEY is present in TABLE_NAME (whitelist) +* `{not_in_table, KEY, TABLE_NAME}` - only allow connections if KEY is *not* present in TABLE_NAME (blacklist) + +Where: + +- `KEY` is one of: + - `port_name` - proxy port name + - `client_ipv4` - client's IPv4 address; ignored on IPv6 ports! + - `client_ipv6` - client's IPv6 address; ignored on IPv4 ports! + - `{client_ipv4_subnet, MASK}` - client's IPv4 subnet; mask is from 8 to 32 + - `{client_ipv6_subnet, MASK}` - client's IPv6 subnet; mask is from 32 to 128 + - `tls_domain` - domain name from fake-TLS secret; ignored if connection with non-fake-TLS protocol +- `KEYS` is a list of one or more `KEY`, eg, `[port, tls_domain]` +- `TABLE_NAME` is free-form text name of special internal database table, eg, `my_table`. + Tables will be created automatically when proxy is started; data in tables is not preserved when proxy + is restarted! + You can add or remove new values from table dynamically at any moment with commands like: + - `/opt/mtp_proxy/bin/mtp_proxy eval 'mtp_policy_table:add(my_table, tls_domain, "google.com")'` to add + - `/opt/mtp_proxy/bin/mtp_proxy eval 'mtp_policy_table:del(my_table, tls_domain, "google.com")'` to remove + +Some policy recipes / examples below + +#### Limit max connections to proxy port from single IP + +Here we allow maximum 100 concurrent connections from single IP to proxy port: + +```erlang +{mtproto_proxy, + [ + {policy, + [{max_connections, [port_name, client_ipv4], 100}]}, + {ports, + <..> +``` + +#### Limit number of connections with single fake-TLS domain; only allow certain domains + +We basically can assign each customer unique fake-TLS domain, give them unique TLS secret +and allow only 10 connections with this fake-TLS secret, so, they will not shere their credentials with +others: + +```erlang +{mtproto_proxy + [ + {policy, + [{max_connections, [port_name, tls_domain], 15}, + {in_table, tls_domain, customer_domains}]}, + {ports, + <..> +``` + +After that we can create unique fake-TLS secret for each customer using code like this: + +```erlang +/opt/mtp_proxy/bin/mtp_proxy eval ' +ProxySecret = mtp_handler:unhex(maps:get(secret, hd(application:get_env(mtproto_proxy, ports, [])))), +NumRecords = mtp_policy_table:table_size(customer_domains), +Rand = crypto:rand_bytes(2), +SubDomain = mtp_handler:hex(<>), +Domain = <>, +mtp_policy_table:add(customer_domains, tls_domain, Domain), +Secret = mtp_handler:hex(<<16#ee, ProxySecret/binary, Domain/binary>>), +io:format("Secret: ~s;\nDomain: ~s\n", [Secret, Domain]).' +``` + ### IPv6 Currently proxy only supports client connections via IPv6, but can only connect to Telegram servers @@ -333,6 +429,7 @@ If your server have low amount of RAM, try to set this may make proxy slower, it can start to consume bit more CPU, will be vulnerable to replay attacks, but will use less RAM. +You should also avoid `max_connections` policy because it uses RAM to track connections. If your server have lots of RAM, you can make it faster (users will get higher uppload/download speed), it will use less CPU and will be better protected from replay attacks, but will use more RAM: diff --git a/src/mtp_fake_tls.erl b/src/mtp_fake_tls.erl index 6cbfd69..66064d8 100644 --- a/src/mtp_fake_tls.erl +++ b/src/mtp_fake_tls.erl @@ -11,7 +11,8 @@ -behaviour(mtp_codec). --export([format_secret/2]). +-export([format_secret_base64/2, + format_secret_hex/2]). -export([from_client_hello/2, new/0, try_decode_packet/2, @@ -79,11 +80,16 @@ %% @doc format TLS secret --spec format_secret(binary(), binary()) -> binary(). -format_secret(Secret, Domain) when byte_size(Secret) == 16 -> +format_secret_hex(Secret, Domain) when byte_size(Secret) == 16 -> + mtp_handler:hex(<<16#ee, Secret/binary, Domain/binary>>); +format_secret_hex(HexSecret, Domain) when byte_size(HexSecret) == 32 -> + format_secret_hex(mtp_handler:unhex(HexSecret), Domain). + +-spec format_secret_base64(binary(), binary()) -> binary(). +format_secret_base64(Secret, Domain) when byte_size(Secret) == 16 -> base64url(<<16#ee, Secret/binary, Domain/binary>>); -format_secret(HexSecret, Domain) when byte_size(HexSecret) == 32 -> - format_secret(mtp_handler:unhex(HexSecret), Domain). +format_secret_base64(HexSecret, Domain) when byte_size(HexSecret) == 32 -> + format_secret_base64(mtp_handler:unhex(HexSecret), Domain). base64url(Bin) -> %% see https://hex.pm/packages/base64url diff --git a/src/mtp_handler.erl b/src/mtp_handler.erl index 5e5ce71..dc418fa 100644 --- a/src/mtp_handler.erl +++ b/src/mtp_handler.erl @@ -50,6 +50,7 @@ ad_tag :: binary(), addr :: mtp_config:netloc_v4v6(), % IP/Port of remote side + policy_state :: any(), started_at :: pos_integer(), timer_state = init :: init | hibernate | stop, timer :: gen_timeout:tout(), @@ -212,7 +213,14 @@ handle_info(Other, S) -> ?log(warning, "Unexpected msg ~p", [Other]), {noreply, S}. -terminate(_Reason, #state{started_at = Started, listener = Listener} = S) -> +terminate(_Reason, #state{started_at = Started, listener = Listener, + addr = {Ip, _}, policy_state = MaybeSni} = S) -> + try mtp_policy:dec( + application:get_env(?APP, policy, []), + Listener, Ip, MaybeSni) + catch T:R -> + ?log(warning, "Failed to decrement policy: ~p:~p", [T, R]) + end, maybe_close_down(S), mtp_metric:count_inc([?APP, in_connection_closed, total], 1, #{labels => [Listener]}), Lifetime = erlang:system_time(millisecond) - Started, @@ -295,16 +303,17 @@ parse_upstream_data(<> = AllData, assert_protocol(mtp_fake_tls), <> = AllData, {ok, Response, Meta, TlsCodec} = mtp_fake_tls:from_client_hello(Data, Secret), - check_tls_access(Listener, Ip, Meta), + check_tls_policy(Listener, Ip, Meta), Codec1 = mtp_codec:replace(tls, true, TlsCodec, Codec0), Codec = mtp_codec:push_back(tls, Tail, Codec1), ok = up_send_raw(Response, S), - {ok, S#state{codec = Codec, stage = init}}; + {ok, S#state{codec = Codec, stage = init, + policy_state = maps:get(sni_domain, Meta, undefined)}}; parse_upstream_data(<> = Data, #state{stage = init} = S) -> parse_upstream_data(Data, S#state{stage = tls_hello}); parse_upstream_data(<>, #state{stage = init, secret = Secret, listener = Listener, codec = Codec0, - ad_tag = Tag, addr = Addr} = S) -> + ad_tag = Tag, addr = {Ip, _} = Addr} = S) -> case mtp_obfuscated:from_header(Header, Secret) of {ok, DcId, PacketLayerMod, CryptoCodecSt} -> maybe_check_replay(Header), @@ -314,6 +323,7 @@ parse_upstream_data(<>, mtp_secure_fake_tls; {false, _} -> assert_protocol(PacketLayerMod), + check_policy(Listener, Ip, undefined), PacketLayerMod end, mtp_metric:count_inc([?APP, protocol_ok, total], @@ -356,20 +366,19 @@ maybe_check_replay(Packet) -> ok end. -check_tls_access(_Listener, _Ip, #{sni_domain := Domain}) -> +check_tls_policy(Listener, Ip, #{sni_domain := TlsDomain}) -> %% TODO validate timestamp! - %% TODO some more scalable solution - case application:get_env(?APP, tls_allowed_domains, any) of - any -> - %% No limits - true; - AllowedDomains -> - lists:member(Domain, AllowedDomains) - orelse error({protocol_error, tls_sni_domain_not_allowed, Domain}) - end; -check_tls_access(_, Ip, Meta) -> + check_policy(Listener, Ip, TlsDomain); +check_tls_policy(_, Ip, Meta) -> error({protocol_error, tls_no_sni, {Ip, Meta}}). +check_policy(Listener, Ip, Domain) -> + Rules = application:get_env(?APP, policy, []), + case mtp_policy:check(Rules, Listener, Ip, Domain) of + [] -> ok; + [Rule | _] -> + error({protocol_error, policy_error, {Rule, Listener, Ip, Domain}}) + end. up_send(Packet, #state{stage = tunnel, codec = UpCodec} = S) -> %% ?log(debug, ">Up: ~p", [Packet]), diff --git a/src/mtp_policy.erl b/src/mtp_policy.erl new file mode 100644 index 0000000..2889cf7 --- /dev/null +++ b/src/mtp_policy.erl @@ -0,0 +1,132 @@ +%%% @author Sergey +%%% @copyright (C) 2019, Sergey +%%% @doc +%%% Evaluator for "policy" config +%%% @end +%%% Created : 20 Aug 2019 by Sergey + +-module(mtp_policy). +-export([check/4]). +-export([dec/4]). +-export([convert/2]). + +-export_type([rule/0, + key/0, + db_val/0]). + +-record(vars, + {listener :: atom(), + client_ip :: inet:ip_address(), + ip_family :: inet | inet6, + tls_domain :: undefined | binary()}). + +-type key() :: + port_name | + tls_domain | + client_ipv4 | + client_ipv6 | + {client_ipv4_subnet, 1..32} | + {client_ipv6_subnet, 8..128}. + +-type rule() :: + {max_connections, [key()], pos_integer()} | + {in_table, key(), mtp_policy_table:sub_tab()} | + {not_in_table, key(), mtp_policy_table:sub_tab()}. + +-type db_val() :: binary() | integer() | atom(). + +-include_lib("hut/include/hut.hrl"). + +-spec check([rule()], any(), inet:ip_address(), binary() | undefined) -> [rule()]. +check(Rules, ListenerName, ClientIp, TlsDomain) -> + Vars = vars(ListenerName, ClientIp,TlsDomain), + lists:dropwhile( + fun(Rule) -> + try check(Rule, Vars) + catch throw:not_applicable -> + true + end + end, Rules). + +dec(Rules, ListenerName, ClientIp,TlsDomain) -> + %% FIXME: this is not idempotent if `check/4` returned `false`! + Vars = vars(ListenerName, ClientIp,TlsDomain), + lists:foreach( + fun({max_connections, Keys, _Max}) -> + try + Key = [val(K, Vars) || K <- Keys], + mtp_policy_counter:increment(Key) + catch throw:not_applicable -> + ok + end; + (_) -> + ok + end, Rules). + +vars(ListenerName, ClientIp, TlsDomain) -> + IpFamily = case tuple_size(ClientIp) of + 4 -> inet; + 8 -> inet6 + end, + #vars{listener = ListenerName, + client_ip = ClientIp, + ip_family = IpFamily, + tls_domain = TlsDomain}. + +check({max_connections, Keys, Max}, Vars) -> + Key = [val(K, Vars) || K <- Keys], + case mtp_policy_counter:increment(Key) of + N when N > Max -> + false; + _ -> + true + end; +check({in_table, Key, Tab}, Vars) -> + Val = val(Key, Vars), + mtp_policy_table:exists(Tab, Val); +check({not_in_table, Key, Tab}, Vars) -> + Val = val(Key, Vars), + not mtp_policy_table:exists(Tab, Val). + + +val(port_name = T, #vars{listener = Listener}) -> + convert(T, Listener); +val(tls_domain = T, #vars{tls_domain = Domain}) when is_binary(Domain) -> + convert(T, Domain); +val(client_ipv4 = T, #vars{ip_family = inet, client_ip = Ip}) -> + convert(T, Ip); +val(client_ipv6 = T, #vars{ip_family = inet6, client_ip = Ip}) -> + convert(T, Ip); +val({client_ipv4_subnet, Mask} = T, #vars{ip_family = inet, client_ip = Ip}) when Mask > 0, + Mask =< 32 -> + convert(T, Ip); +val({client_ipv6_subnet, Mask} = T, #vars{ip_family = inet6, client_ip = Ip}) when Mask > 8, + Mask =< 128 -> + convert(T, Ip); +val(Policy, Vars) when is_atom(Policy); + is_tuple(Policy) -> + ?log(debug, "Policy ~p not applicable ~p", [Policy, Vars]), + throw(not_applicable). + + +-spec convert(key(), any()) -> db_val(). +convert(port_name, PortName) -> + PortName; +convert(tls_domain, Domain) when is_binary(Domain) -> + Domain; +convert(tls_domain, DomainStr) when is_list(DomainStr) -> + convert(tls_domain, list_to_binary(DomainStr)); +convert(client_ipv4, Ip) -> + <> = mtp_rpc:inet_pton(Ip), + I; +convert(client_ipv6, Ip) -> + <> = mtp_rpc:inet_pton(Ip), + I; +convert({client_ipv4_subnet, Mask}, Ip) -> + <> = mtp_rpc:inet_pton(Ip), + I; +convert({client_ipv6_subnet, Mask}, Ip) -> + <> = mtp_rpc:inet_pton(Ip), + I. + + diff --git a/src/mtp_policy_counter.erl b/src/mtp_policy_counter.erl new file mode 100644 index 0000000..a4636b8 --- /dev/null +++ b/src/mtp_policy_counter.erl @@ -0,0 +1,80 @@ +%%%------------------------------------------------------------------- +%%% @author Sergey +%%% @copyright (C) 2019, Sergey +%%% @doc +%%% Storage for `max_connections` policy. +%%% It's quite simple wrapper for public ETS counter. +%%% @end +%%% Created : 20 Aug 2019 by Sergey +%%%------------------------------------------------------------------- +-module(mtp_policy_counter). + +-behaviour(gen_server). + +%% API +-export([start_link/0]). +-export([increment/1, + decrement/1, + flush/0]). + +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, + terminate/2, code_change/3]). +-type key() :: [mtp_policy:db_val()]. + +-define(TAB, ?MODULE). + +-record(state, {tab :: ets:tid()}). + +%%%=================================================================== +%%% API +%%%=================================================================== +-spec increment(key()) -> integer(). +increment(Key) -> + ets:update_counter(?TAB, Key, 1, {Key, 0}). + +-spec decrement(key()) -> integer(). +decrement(Key) -> + try ets:update_counter(?TAB, Key, 1) of + New when New =< 0 -> + ets:delete(?TAB, Key), + 0; + New -> New + catch error:badarg -> + %% already removed + 0 + end. + +%% @doc Clean all counters +flush() -> + gen_server:call(?MODULE, flush). + +start_link() -> + gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). + +%%%=================================================================== +%%% gen_server callbacks +%%%=================================================================== +init([]) -> + Tab = ets:new(?TAB, [named_table, {write_concurrency, true}, public]), + {ok, #state{tab = Tab}}. + +handle_call(flush, _From, #state{tab = Tab} = State) -> + true = ets:delete_all_objects(Tab), + {reply, ok, State}. + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== diff --git a/src/mtp_policy_table.erl b/src/mtp_policy_table.erl new file mode 100644 index 0000000..f58efd8 --- /dev/null +++ b/src/mtp_policy_table.erl @@ -0,0 +1,94 @@ +%%%------------------------------------------------------------------- +%%% @author Sergey +%%% @copyright (C) 2019, Sergey +%%% @doc +%%% Storage for `in_table` and `not_in_table` policies. Implements 2-level nested set. +%%% It's quite simple wrapper for protected ETS set. +%%% @end +%%% Created : 20 Aug 2019 by Sergey +%%%------------------------------------------------------------------- +-module(mtp_policy_table). + +-behaviour(gen_server). + +%% API +-export([start_link/0]). +-export([add/3, + del/3, + exists/2, + table_size/1, + flush/0]). + +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, + terminate/2, code_change/3]). +-type sub_tab() :: atom(). +-type value() :: mtp_policy:db_val(). + +-include_lib("stdlib/include/ms_transform.hrl"). +-define(TAB, ?MODULE). + +-record(state, {tab :: ets:tid()}). + +%%%=================================================================== +%%% API +%%%=================================================================== +-spec add(sub_tab(), mtp_policy:key(), value()) -> ok. +add(Subtable, Type, Value) -> + gen_server:call(?MODULE, {add, Subtable, mtp_policy:convert(Type, Value)}). + +-spec del(sub_tab(), mtp_policy:key(), value()) -> ok. +del(Subtable, Type, Value) -> + gen_server:call(?MODULE, {del, Subtable, mtp_policy:convert(Type, Value)}). + +-spec exists(sub_tab(), value()) -> boolean(). +exists(Subtable, Value) -> + case ets:lookup(?TAB, {Subtable, Value}) of + [] -> false; + [_] -> true + end. + +-spec table_size(sub_tab()) -> non_neg_integer(). +table_size(SubTable) -> + MS = ets:fun2ms(fun({{Tab, _}, _}) when Tab =:= SubTable -> true end), + ets:select_count(?TAB, MS). + +%% @doc Clean all counters +flush() -> + gen_server:call(?MODULE, flush). + +start_link() -> + gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). + +%%%=================================================================== +%%% gen_server callbacks +%%%=================================================================== +init([]) -> + Tab = ets:new(?TAB, [named_table, {read_concurrency, true}, protected]), + {ok, #state{tab = Tab}}. + +handle_call({add, SubTab, Data}, _From, #state{tab = Tab} = State) -> + true = ets:insert(Tab, {{SubTab, Data}, erlang:system_time(millisecond)}), + {reply, ok, State}; +handle_call({del, SubTab, Data}, _From, #state{tab = Tab} = State) -> + true = ets:delete(Tab, {SubTab, Data}), + {reply, ok, State}; +handle_call(flush, _From, #state{tab = Tab} = State) -> + true = ets:delete_all_objects(Tab), + {reply, ok, State}. + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== diff --git a/src/mtproto_proxy.app.src b/src/mtproto_proxy.app.src index 1b2f1fc..a80a588 100644 --- a/src/mtproto_proxy.app.src +++ b/src/mtproto_proxy.app.src @@ -58,11 +58,13 @@ %% protocols will be immediately disallowed. {allowed_protocols, [mtp_fake_tls, mtp_secure, mtp_abridged, mtp_intermediate]}, - %% Which domains to allow in TLS SNI - %% XXX: this option is experimental and will be removed later! - %% Can be set to `any' to allow any domains. - %% {tls_allowed_domains, any}, - {tls_allowed_domains, [<<"en.wikipedia.org">>, <<"s3.amazonaws.com">>]}, + %% Connection policies. + %% See README.md for documentation + %% {policy, + %% [{in_table, tls_domain, allowed_domains}, + %% {not_in_table, [client_ipv4], banned_ips}, + %% {max_connections, [port_name, tls_domain], 15} + %% ]}, {init_dc_connections, 2}, {clients_per_dc_connection, 300}, diff --git a/src/mtproto_proxy_app.erl b/src/mtproto_proxy_app.erl index c56dbd9..325aa4b 100644 --- a/src/mtproto_proxy_app.erl +++ b/src/mtproto_proxy_app.erl @@ -172,13 +172,8 @@ build_urls(Host, Port, Secret, Protocols) -> end, Protocols)), lists:map( fun(mtp_fake_tls) -> - %% Print just for 1st domain as example - Domain = case application:get_env(?APP, tls_allowed_domains) of - {ok, [Domain0 | _]} -> Domain0; - _ -> - <<"en.wikipedia.org">> - end, - ProtoSecret = mtp_fake_tls:format_secret(Secret, Domain), + Domain = <<"s3.amazonaws.com">>, + ProtoSecret = mtp_fake_tls:format_secret_hex(Secret, Domain), MkUrl(ProtoSecret); (mtp_secure) -> ProtoSecret = ["dd", Secret], diff --git a/src/mtproto_proxy_sup.erl b/src/mtproto_proxy_sup.erl index a0559c5..5baedfe 100644 --- a/src/mtproto_proxy_sup.erl +++ b/src/mtproto_proxy_sup.erl @@ -54,6 +54,10 @@ init([]) -> #{id => mtp_config, start => {mtp_config, start_link, []}}, #{id => mtp_session_storage, - start => {mtp_session_storage, start_link, []}} + start => {mtp_session_storage, start_link, []}}, + #{id => mtp_policy_table, + start => {mtp_policy_table, start_link, []}}, + #{id => mtp_policy_counter, + start => {mtp_policy_counter, start_link, []}} ], {ok, {SupFlags, Childs}}.