Add option to disable connections by some protocols

Mostly useful to forbid connections without 'dd' secret
parent 9b11341f
...@@ -9,9 +9,11 @@ Features ...@@ -9,9 +9,11 @@ Features
* Promoted channels! See `mtproto_proxy_app.src` `tag` option. * Promoted channels! See `mtproto_proxy_app.src` `tag` option.
* "secure" randomized-packet-size protocol (34-symbol secrets starting with 'dd') * "secure" randomized-packet-size protocol (34-symbol secrets starting with 'dd')
to prevent detection by DPI to prevent detection by DPI
* Secure-only mode (only allow connections with 'dd'-secrets). See `allowed_protocols` option.
* Multiple ports with unique secret and promo tag for each port * Multiple ports with unique secret and promo tag for each port
* Automatic configuration reload (no need for restarts once per day) * Automatic configuration reload (no need for restarts once per day)
* Very high performance - can handle tens of thousands connections! * Most of the configuration options might be updated without service restart
* Very high performance - can handle tens of thousands connections! Scales to all CPU cores.
* Small codebase compared to oficial one * Small codebase compared to oficial one
* A lots of metrics could be exported (optional) * A lots of metrics could be exported (optional)
...@@ -118,10 +120,13 @@ and then re-install proxy by ...@@ -118,10 +120,13 @@ and then re-install proxy by
``` ```
sudo make uninstall && make && sudo make install sudo make uninstall && make && sudo make install
``` ```
There are other ways as well. It's even possible to update configuration options
without service restart / without downtime, but it's a bit trickier.
### Change default port / secret / ad tag ### Change default port / secret / ad tag
To change default settings, change `mtproto_proxy` section as: To change default settings, change `mtproto_proxy` section of `prod-sys.config` as:
``` ```
{mtproto_proxy, {mtproto_proxy,
%% see src/mtproto_proxy.app.src for examples. %% see src/mtproto_proxy.app.src for examples.
...@@ -171,6 +176,21 @@ To do so, just add more configs to `ports` section, separated by comma, eg: ...@@ -171,6 +176,21 @@ To do so, just add more configs to `ports` section, separated by comma, eg:
Each section should have unique `name`! Each section should have unique `name`!
### Only allow connections with 'dd'-secrets
It might be useful in Iran, where proxies are detected by DPI.
You should disable all protocols other than `mtp_secure` by providing `allowed_protocols` option:
```
{mtproto_proxy,
[
{allowed_protocols, [mtp_secure]},
{ports,
[#{name => mtp_handler_1,
<..>
```
Helpers Helpers
------- -------
......
...@@ -226,9 +226,9 @@ handle_upstream_data(<<Header:64/binary, Rest/binary>>, #state{stage = init, sta ...@@ -226,9 +226,9 @@ handle_upstream_data(<<Header:64/binary, Rest/binary>>, #state{stage = init, sta
S#state{up_codec = UpCodec, S#state{up_codec = UpCodec,
up_acc = Rest, up_acc = Rest,
stage_state = undefined}); stage_state = undefined});
{error, unknown_protocol} = Err -> {error, Reason} = Err ->
metric:count_inc([?APP, protocol_error, total], metric:count_inc([?APP, protocol_error, total],
1, #{labels => [unknown]}), 1, #{labels => [Reason]}),
Err Err
end; end;
handle_upstream_data(Bin, #state{stage = init, stage_state = <<>>} = S) -> handle_upstream_data(Bin, #state{stage = init, stage_state = <<>>} = S) ->
......
...@@ -60,25 +60,25 @@ init_down_encrypt(<<_:8/binary, Key:32/binary, IV:16/binary, _/binary>>) -> ...@@ -60,25 +60,25 @@ init_down_encrypt(<<_:8/binary, Key:32/binary, IV:16/binary, _/binary>>) ->
%% @doc creates new obfuscated stream (MTProto proxy format) %% @doc creates new obfuscated stream (MTProto proxy format)
-spec from_header(binary(), binary()) -> {ok, integer(), mtp_layer:codec(), codec()}. -spec from_header(binary(), binary()) -> {ok, integer(), mtp_layer:codec(), codec()}
| {error, unknown_protocol | disabled_protocol}.
from_header(Header, Secret) when byte_size(Header) == 64 -> from_header(Header, Secret) when byte_size(Header) == 64 ->
{EncKey, EncIV} = init_up_encrypt(Header, Secret), {EncKey, EncIV} = init_up_encrypt(Header, Secret),
{DecKey, DecIV} = init_up_decrypt(Header, Secret), {DecKey, DecIV} = init_up_decrypt(Header, Secret),
St = new(EncKey, EncIV, DecKey, DecIV), St = new(EncKey, EncIV, DecKey, DecIV),
{<<_:56/binary, Bin1:8/binary, _/binary>>, St1} = decrypt(Header, St), {<<_:56/binary, Bin1:8/binary, _/binary>>, St1} = decrypt(Header, St),
case Bin1 of case get_protocol(Bin1) of
<<16#ef, 16#ef, 16#ef, 16#ef, _/binary>> -> {error, unknown_protocol} = Err ->
DcId = get_dc(Bin1), Err;
{ok, DcId, mtp_abridged, St1}; Protocol ->
<<16#ee, 16#ee, 16#ee, 16#ee, _/binary>> -> {ok, AllowedProtocols} = application:get_env(?APP, allowed_protocols),
DcId = get_dc(Bin1), case lists:member(Protocol, AllowedProtocols) of
{ok, DcId, mtp_intermediate, St1}; true ->
<<16#dd, 16#dd, 16#dd, 16#dd, _/binary>> -> DcId = get_dc(Bin1),
DcId = get_dc(Bin1), {ok, DcId, Protocol, St1};
{ok, DcId, mtp_secure, St1}; false ->
_ -> {error, disabled_protocol}
metric:count_inc([?APP, protocol_error, total], 1, #{labels => [unknown]}), end
{error, unknown_protocol}
end. end.
init_up_encrypt(Bin, Secret) -> init_up_encrypt(Bin, Secret) ->
...@@ -94,6 +94,15 @@ init_up_decrypt(Bin, Secret) -> ...@@ -94,6 +94,15 @@ init_up_decrypt(Bin, Secret) ->
KeyHash = crypto:hash('sha256', <<Key/binary, Secret/binary>>), KeyHash = crypto:hash('sha256', <<Key/binary, Secret/binary>>),
{KeyHash, IV}. {KeyHash, IV}.
get_protocol(<<16#ef, 16#ef, 16#ef, 16#ef, _/binary>>) ->
mtp_abridged;
get_protocol(<<16#ee, 16#ee, 16#ee, 16#ee, _/binary>>) ->
mtp_intermediate;
get_protocol(<<16#dd, 16#dd, 16#dd, 16#dd, _/binary>>) ->
mtp_secure;
get_protocol(_) ->
{error, unknown_protocol}.
get_dc(<<_:4/binary, DcId:16/signed-little-integer, _/binary>>) -> get_dc(<<_:4/binary, DcId:16/signed-little-integer, _/binary>>) ->
DcId. DcId.
......
...@@ -44,7 +44,13 @@ ...@@ -44,7 +44,13 @@
%% tag is what you get from @MTProxybot %% tag is what you get from @MTProxybot
tag => <<"dcbe8f1493fa4cd9ab300891c0b5b326">>}]}, tag => <<"dcbe8f1493fa4cd9ab300891c0b5b326">>}]},
{num_acceptors, 60}, {num_acceptors, 60},
{max_connections, 40960} {max_connections, 40960},
%% It's possible to forbid connection from telegram client to proxy
%% with some of the protocols. Might be useful to set this to
%% only `{allowed_protocols, [mtp_secure]}` if you want to only allow
%% connections to this proxy with "dd"-secrets. Connections by other
%% protocols will be immediately closed.
{allowed_protocols, [mtp_abridged, mtp_intermediate, mtp_secure]}
]}, ]},
{modules, []}, {modules, []},
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment