Packages

High-performance Telegram MTProto proxy server

Security advisory: This version has known vulnerabilities. View advisories

Current section

Files

Jump to
mtproto_proxy src mtp_intermediate.erl
Raw

src/mtp_intermediate.erl

%%% @author Sergey <me@seriyps.ru>
%%% @copyright (C) 2018, Sergey
%%% @doc
%%% MTProto intermediate protocol
%%% @end
%%% Created : 18 Jun 2018 by Sergey <me@seriyps.ru>
-module(mtp_intermediate).
-behaviour(mtp_codec).
-export([new/0,
new/1,
try_decode_packet/2,
encode_packet/2]).
-export_type([codec/0]).
-dialyzer(no_improper_lists).
-record(int_st,
{padding = false :: boolean(),
buffer = <<>> :: binary()}).
-define(MAX_PACKET_SIZE, 1 * 1024 * 1024). % 1mb
-define(APP, mtproto_proxy).
-define(MAX_SIZE, 16#80000000).
-opaque codec() :: #int_st{}.
new() ->
new(#{}).
new(Opts) ->
#int_st{padding = maps:get(padding, Opts, false)}.
-spec try_decode_packet(binary(), codec()) -> {ok, binary(), codec()}
| {incomplete, codec()}.
try_decode_packet(<<Len:32/unsigned-little, _/binary>> = Data,
#int_st{buffer = <<>>} = St) ->
Len1 = case Len < ?MAX_SIZE of
true -> Len;
false -> Len - ?MAX_SIZE
end,
(Len1 < ?MAX_PACKET_SIZE)
orelse
begin
error({protocol_error, intermediate_max_size, Len1})
end,
try_decode_packet_len(Len1, Data, St);
try_decode_packet(Bin, #int_st{buffer = Buf} = St) when byte_size(Buf) > 0 ->
try_decode_packet(<<Buf/binary, Bin/binary>>, St#int_st{buffer = <<>>});
try_decode_packet(Bin, #int_st{buffer = <<>>} = St) ->
{incomplete, St#int_st{buffer = Bin}}.
try_decode_packet_len(Len, Data, #int_st{padding = Pad} = St) ->
Padding = case Pad of
true -> Len rem 4;
false -> 0
end,
NopadLen = Len - Padding,
case Data of
<<_:4/binary, Packet:NopadLen/binary, _Padding:Padding/binary, Rest/binary>> ->
{ok, Packet, St#int_st{buffer = Rest}};
_ ->
{incomplete, St#int_st{buffer = Data}}
end.
-spec encode_packet(iodata(), codec()) -> {iodata(), codec()}.
encode_packet(Data, #int_st{padding = Pad} = St) ->
Size = iolist_size(Data),
Packet = case Pad of
false -> [<<Size:32/little>> | Data];
true ->
PadSize = rand:uniform(4) - 1,
Padding = crypto:strong_rand_bytes(PadSize), % 0 is ok
[<<(Size + PadSize):32/little>>, Data | Padding]
end,
{Packet, St}.