Add option to disable crc32 check in mtp_full to save CPU

parent 90ad1dd0
...@@ -415,6 +415,8 @@ mtp_policy_table:add(customer_domains, tls_domain, "my-client1.example.com").' ...@@ -415,6 +415,8 @@ mtp_policy_table:add(customer_domains, tls_domain, "my-client1.example.com").'
``` ```
And then use http://seriyps.ru/mtpgen.html to generate unique link for them. And then use http://seriyps.ru/mtpgen.html to generate unique link for them.
Be aware that domains table will be reset if proxy is restarted! Make sure you re-add them
when proxy restarts (eg, via [systemd hook script](https://unix.stackexchange.com/q/326181/70382)).
### IPv6 ### IPv6
...@@ -478,6 +480,12 @@ it will use less CPU and will be better protected from replay attacks, but will ...@@ -478,6 +480,12 @@ it will use less CPU and will be better protected from replay attacks, but will
max_age_minutes => 1440}}, max_age_minutes => 1440}},
``` ```
One more option to decrease CPU usage is to disable CRC32 checksum check:
```erlang
{mtp_full_check_crc32, false},
```
Also, for highload setups it's recommended to increase sysctl parameters: Also, for highload setups it's recommended to increase sysctl parameters:
``` ```
......
...@@ -495,10 +495,11 @@ down_handshake1(S) -> ...@@ -495,10 +495,11 @@ down_handshake1(S) ->
Schema = 1, %AES Schema = 1, %AES
Msg = mtp_rpc:encode_nonce({nonce, KeySelector, Schema, CryptoTs, Nonce}), Msg = mtp_rpc:encode_nonce({nonce, KeySelector, Schema, CryptoTs, Nonce}),
Deadline = erlang:send_after(?HANDSHAKE_TIMEOUT, self(), handshake_timeout), Deadline = erlang:send_after(?HANDSHAKE_TIMEOUT, self(), handshake_timeout),
CheckCRC = application:get_env(?APP, mtp_full_check_crc32, true),
S1 = S#state{stage = handshake_1, S1 = S#state{stage = handshake_1,
%% Use fake encryption codec %% Use fake encryption codec
codec = mtp_codec:new(mtp_noop_codec, mtp_noop_codec:new(), codec = mtp_codec:new(mtp_noop_codec, mtp_noop_codec:new(),
mtp_full, mtp_full:new(-2, -2), mtp_full, mtp_full:new(-2, -2, CheckCRC),
false, undefined, ?MAX_CODEC_BUFFERS), false, undefined, ?MAX_CODEC_BUFFERS),
stage_state = {Deadline, KeySelector, Nonce, CryptoTs, Key}}, stage_state = {Deadline, KeySelector, Nonce, CryptoTs, Key}},
down_send(Msg, S1). down_send(Msg, S1).
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
-module(mtp_full). -module(mtp_full).
-behaviour(mtp_codec). -behaviour(mtp_codec).
-export([new/0, new/2, -export([new/0, new/3,
try_decode_packet/2, try_decode_packet/2,
encode_packet/2]). encode_packet/2]).
-export_type([codec/0]). -export_type([codec/0]).
...@@ -20,7 +20,9 @@ ...@@ -20,7 +20,9 @@
-record(full_st, -record(full_st,
{enc_seq_no :: integer(), {enc_seq_no :: integer(),
dec_seq_no :: integer()}). dec_seq_no :: integer(),
check_crc = true :: boolean()}).
-define(MIN_MSG_LEN, 12). -define(MIN_MSG_LEN, 12).
-define(MAX_MSG_LEN, 16777216). %2^24 - 16mb -define(MAX_MSG_LEN, 16777216). %2^24 - 16mb
...@@ -32,17 +34,18 @@ ...@@ -32,17 +34,18 @@
new() -> new() ->
new(0, 0). new(0, 0, true).
new(EncSeqNo, DecSeqNo) -> new(EncSeqNo, DecSeqNo, CheckCRC) ->
#full_st{enc_seq_no = EncSeqNo, #full_st{enc_seq_no = EncSeqNo,
dec_seq_no = DecSeqNo}. dec_seq_no = DecSeqNo,
check_crc = CheckCRC}.
try_decode_packet(<<4:32/little, Tail/binary>>, S) -> try_decode_packet(<<4:32/little, Tail/binary>>, S) ->
%% Skip padding %% Skip padding
try_decode_packet(Tail, S); try_decode_packet(Tail, S);
try_decode_packet(<<Len:32/little, PktSeqNo:32/signed-little, Tail/binary>>, try_decode_packet(<<Len:32/little, PktSeqNo:32/signed-little, Tail/binary>>,
#full_st{dec_seq_no = SeqNo} = S) -> #full_st{dec_seq_no = SeqNo, check_crc = CheckCRC} = S) ->
((Len rem byte_size(?PAD)) == 0) ((Len rem byte_size(?PAD)) == 0)
orelse error({wrong_alignement, Len}), orelse error({wrong_alignement, Len}),
((?MIN_MSG_LEN =< Len) and (Len =< ?MAX_MSG_LEN)) ((?MIN_MSG_LEN =< Len) and (Len =< ?MAX_MSG_LEN))
...@@ -52,9 +55,14 @@ try_decode_packet(<<Len:32/little, PktSeqNo:32/signed-little, Tail/binary>>, ...@@ -52,9 +55,14 @@ try_decode_packet(<<Len:32/little, PktSeqNo:32/signed-little, Tail/binary>>,
BodyLen = Len - 4 - 4 - 4, BodyLen = Len - 4 - 4 - 4,
case Tail of case Tail of
<<Body:BodyLen/binary, CRC:32/little, Rest/binary>> -> <<Body:BodyLen/binary, CRC:32/little, Rest/binary>> ->
PacketCrc = erlang:crc32([<<Len:32/little, PktSeqNo:32/little>> | Body]), case CheckCRC of
(CRC == PacketCrc) true ->
orelse error({wrong_checksum, CRC, PacketCrc}), PacketCrc = erlang:crc32([<<Len:32/little, PktSeqNo:32/little>> | Body]),
(CRC == PacketCrc)
orelse error({wrong_checksum, CRC, PacketCrc});
false ->
ok
end,
%% TODO: predict padding size from padding_size(Len) %% TODO: predict padding size from padding_size(Len)
{ok, Body, trim_padding(Rest), S#full_st{dec_seq_no = SeqNo + 1}}; {ok, Body, trim_padding(Rest), S#full_st{dec_seq_no = SeqNo + 1}};
_ -> _ ->
......
...@@ -130,6 +130,10 @@ ...@@ -130,6 +130,10 @@
%% {upstream_socket_buffer_size, 51200}, %50kb %% {upstream_socket_buffer_size, 51200}, %50kb
%% {downstream_socket_buffer_size, 512000}, %500kb %% {downstream_socket_buffer_size, 512000}, %500kb
%% Whether we should check CRC32 sum of packets encoded with mtp_full
%% codec. Setting this to `false' decreases CPU usage. Default: true
%% {mtp_full_check_crc32, true},
%% Where to fetch telegram proxy configuration %% Where to fetch telegram proxy configuration
%% Mostly used to testing %% Mostly used to testing
%% {proxy_secret_url, "https://core.telegram.org/getProxySecret"}, %% {proxy_secret_url, "https://core.telegram.org/getProxySecret"},
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
intermediate/1, bench_intermediate/2, intermediate/1, bench_intermediate/2,
secure/1, bench_secure/2, secure/1, bench_secure/2,
full/1, bench_full/2, full/1, bench_full/2,
full_nocheck/1, bench_full_nocheck/2,
aes_cbc/1, bench_aes_cbc/2, aes_cbc/1, bench_aes_cbc/2,
obfuscated/1, bench_obfuscated/2, obfuscated/1, bench_obfuscated/2,
fold_dd_codec/1, bench_fold_dd_codec/2, fold_dd_codec/1, bench_fold_dd_codec/2,
...@@ -86,6 +87,17 @@ decode_all_full(Stream0, Codec0) -> ...@@ -86,6 +87,17 @@ decode_all_full(Stream0, Codec0) ->
end. end.
%% @doc bench mtp_full with disabled CRC32 verification check
full_nocheck(init) ->
mtp_full:new(0, 0, false);
full_nocheck({input, Codec}) ->
Packets = mk_front_packets(),
encode_all(Packets, mtp_full, Codec).
bench_full_nocheck(Stream, Codec) ->
decode_all_full(Stream, Codec).
%% @doc bench aes_cbc decryption %% @doc bench aes_cbc decryption
aes_cbc(init) -> aes_cbc(init) ->
Key = binary:copy(<<0>>, 32), Key = binary:copy(<<0>>, 32),
......
...@@ -74,7 +74,7 @@ ranch_init({Ref, Transport, Opts}) -> ...@@ -74,7 +74,7 @@ ranch_init({Ref, Transport, Opts}) ->
init({Socket, Transport, Opts}) -> init({Socket, Transport, Opts}) ->
Codec = mtp_codec:new(mtp_noop_codec, mtp_noop_codec:new(), Codec = mtp_codec:new(mtp_noop_codec, mtp_noop_codec:new(),
mtp_full, mtp_full:new(-2, -2)), mtp_full, mtp_full:new(-2, -2, true)),
State = #hs_state{sock = Socket, State = #hs_state{sock = Socket,
transport = Transport, transport = Transport,
secret = maps:get(secret, Opts), secret = maps:get(secret, Opts),
......
...@@ -145,7 +145,7 @@ fullcbc_stream(Key, Iv, Stream) -> ...@@ -145,7 +145,7 @@ fullcbc_stream(Key, Iv, Stream) ->
mk_fullcbc_codec(EncKey, EncIv, DecKey, DecIv) -> mk_fullcbc_codec(EncKey, EncIv, DecKey, DecIv) ->
Crypto = mtp_aes_cbc:new(EncKey, EncIv, DecKey, DecIv, 16), Crypto = mtp_aes_cbc:new(EncKey, EncIv, DecKey, DecIv, 16),
Packet = mtp_full:new(1, 1), Packet = mtp_full:new(1, 1, true),
mtp_codec:new(mtp_aes_cbc, Crypto, mtp_codec:new(mtp_aes_cbc, Crypto,
mtp_full, Packet). mtp_full, Packet).
......
...@@ -9,10 +9,11 @@ prop_codec(doc) -> ...@@ -9,10 +9,11 @@ prop_codec(doc) ->
"Tests that any 4-byte aligned binary can be encoded and decoded back". "Tests that any 4-byte aligned binary can be encoded and decoded back".
prop_codec() -> prop_codec() ->
?FORALL(Bin, mtp_prop_gen:packet_4b(), codec(Bin)). ?FORALL({CheckCRC, Bin}, {proper_types:boolean(), mtp_prop_gen:packet_4b()},
codec(Bin, CheckCRC)).
codec(Bin) -> codec(Bin, CheckCRC) ->
Codec = mtp_full:new(), Codec = mtp_full:new(0, 0, CheckCRC),
{Data, Codec1} = mtp_full:encode_packet(Bin, Codec), {Data, Codec1} = mtp_full:encode_packet(Bin, Codec),
{ok, Decoded, <<>>, _} = mtp_full:try_decode_packet(iolist_to_binary(Data), Codec1), {ok, Decoded, <<>>, _} = mtp_full:try_decode_packet(iolist_to_binary(Data), Codec1),
Decoded == Bin. Decoded == Bin.
......
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