fix message
This commit is contained in:
parent
8bdc5868c3
commit
388096a29a
@ -28,7 +28,7 @@
|
||||
-ifndef('SDL_REGISTER_SUPER_PB_H').
|
||||
-define('SDL_REGISTER_SUPER_PB_H', true).
|
||||
-record(sdl_register_super,
|
||||
{version = 0 :: non_neg_integer() | undefined, % = 1, optional, 32 bits
|
||||
{pkt_id = 0 :: non_neg_integer() | undefined, % = 1, optional, 32 bits
|
||||
client_id = <<>> :: unicode:chardata() | undefined, % = 2, optional
|
||||
network_id = 0 :: non_neg_integer() | undefined, % = 3, optional, 32 bits
|
||||
mac = <<>> :: iodata() | undefined, % = 4, optional
|
||||
@ -43,36 +43,49 @@
|
||||
-ifndef('SDL_REGISTER_SUPER_ACK_PB_H').
|
||||
-define('SDL_REGISTER_SUPER_ACK_PB_H', true).
|
||||
-record(sdl_register_super_ack,
|
||||
{aes_key = <<>> :: iodata() | undefined, % = 1, optional
|
||||
session_token = <<>> :: iodata() | undefined % = 2, optional
|
||||
{pkt_id = 0 :: non_neg_integer() | undefined, % = 1, optional, 32 bits
|
||||
aes_key = <<>> :: iodata() | undefined, % = 2, optional
|
||||
session_token = <<>> :: iodata() | undefined % = 3, optional
|
||||
}).
|
||||
-endif.
|
||||
|
||||
-ifndef('SDL_REGISTER_SUPER_NAK_PB_H').
|
||||
-define('SDL_REGISTER_SUPER_NAK_PB_H', true).
|
||||
-record(sdl_register_super_nak,
|
||||
{error_code = 0 :: non_neg_integer() | undefined, % = 1, optional, 32 bits
|
||||
error_message = <<>> :: unicode:chardata() | undefined % = 2, optional
|
||||
{pkt_id = 0 :: non_neg_integer() | undefined, % = 1, optional, 32 bits
|
||||
error_code = 0 :: non_neg_integer() | undefined, % = 2, optional, 32 bits
|
||||
error_message = <<>> :: unicode:chardata() | undefined % = 3, optional
|
||||
}).
|
||||
-endif.
|
||||
|
||||
-ifndef('SDL_QUERY_INFO_PB_H').
|
||||
-define('SDL_QUERY_INFO_PB_H', true).
|
||||
-record(sdl_query_info,
|
||||
{network_id = 0 :: non_neg_integer() | undefined, % = 1, optional, 32 bits
|
||||
src_mac = <<>> :: iodata() | undefined, % = 2, optional
|
||||
dst_mac = <<>> :: iodata() | undefined, % = 3, optional
|
||||
session_token = <<>> :: iodata() | undefined % = 4, optional
|
||||
{pkt_id = 0 :: non_neg_integer() | undefined, % = 1, optional, 32 bits
|
||||
network_id = 0 :: non_neg_integer() | undefined, % = 2, optional, 32 bits
|
||||
src_mac = <<>> :: iodata() | undefined, % = 3, optional
|
||||
dst_mac = <<>> :: iodata() | undefined, % = 4, optional
|
||||
session_token = <<>> :: iodata() | undefined % = 5, optional
|
||||
}).
|
||||
-endif.
|
||||
|
||||
-ifndef('SDL_PEER_INFO_PB_H').
|
||||
-define('SDL_PEER_INFO_PB_H', true).
|
||||
-record(sdl_peer_info,
|
||||
{network_id = 0 :: non_neg_integer() | undefined, % = 1, optional, 32 bits
|
||||
dst_mac = <<>> :: iodata() | undefined, % = 2, optional
|
||||
v4_info = undefined :: sdlan_pb:sdl_v4_info() | undefined, % = 3, optional
|
||||
v6_info :: sdlan_pb:sdl_v6_info() | undefined % = 4, optional
|
||||
{pkt_id = 0 :: non_neg_integer() | undefined, % = 1, optional, 32 bits
|
||||
network_id = 0 :: non_neg_integer() | undefined, % = 2, optional, 32 bits
|
||||
dst_mac = <<>> :: iodata() | undefined, % = 3, optional
|
||||
v4_info = undefined :: sdlan_pb:sdl_v4_info() | undefined, % = 4, optional
|
||||
v6_info :: sdlan_pb:sdl_v6_info() | undefined % = 5, optional
|
||||
}).
|
||||
-endif.
|
||||
|
||||
-ifndef('SDL_EMPTY_PEER_INFO_PB_H').
|
||||
-define('SDL_EMPTY_PEER_INFO_PB_H', true).
|
||||
-record(sdl_empty_peer_info,
|
||||
{pkt_id = 0 :: non_neg_integer() | undefined, % = 1, optional, 32 bits
|
||||
network_id = 0 :: non_neg_integer() | undefined, % = 2, optional, 32 bits
|
||||
dst_mac = <<>> :: iodata() | undefined % = 3, optional
|
||||
}).
|
||||
-endif.
|
||||
|
||||
@ -133,6 +146,15 @@
|
||||
}).
|
||||
-endif.
|
||||
|
||||
-ifndef('SDL_STUN_REPLY_PB_H').
|
||||
-define('SDL_STUN_REPLY_PB_H', true).
|
||||
-record(sdl_stun_reply,
|
||||
{network_id = 0 :: non_neg_integer() | undefined, % = 1, optional, 32 bits
|
||||
code = 0 :: non_neg_integer() | undefined, % = 2, optional, 32 bits
|
||||
message = <<>> :: unicode:chardata() | undefined % = 3, optional
|
||||
}).
|
||||
-endif.
|
||||
|
||||
-ifndef('SDL_DATA_PB_H').
|
||||
-define('SDL_DATA_PB_H', true).
|
||||
-record(sdl_data,
|
||||
|
||||
@ -8,19 +8,12 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(sdlan_cipher).
|
||||
-author("anlicheng").
|
||||
-include_lib("public_key/include/public_key.hrl").
|
||||
|
||||
%% API
|
||||
-export([rsa_encrypt/2, rsa_pem_decode/1]).
|
||||
-export([rsa_encrypt/2, rsa_pem_decode/1, rsa_decrypt/2]).
|
||||
-export([aes_encrypt/3, aes_decrypt/3]).
|
||||
-export([test/0]).
|
||||
|
||||
test() ->
|
||||
Key = <<"abcdabcdabcdabcd">>,
|
||||
X = aes_encrypt(Key, Key, <<"hello world">>),
|
||||
logger:debug("x is: ~p, raw: ~p", [X, aes_decrypt(Key, Key, X)]),
|
||||
|
||||
|
||||
ok.
|
||||
-export([rsa_generate_key/0]).
|
||||
|
||||
-spec rsa_pem_decode(PubKey :: binary()) -> public_key:rsa_public_key().
|
||||
rsa_pem_decode(PubKey) when is_binary(PubKey) ->
|
||||
@ -32,6 +25,23 @@ rsa_pem_decode(PubKey) when is_binary(PubKey) ->
|
||||
rsa_encrypt(BinData, PublicKey) when is_binary(BinData) ->
|
||||
public_key:encrypt_public(BinData, PublicKey, [{rsa_padding, rsa_pkcs1_padding}]).
|
||||
|
||||
-spec rsa_decrypt(EncData :: binary(), PrivateKey :: public_key:rsa_private_key()) -> binary().
|
||||
rsa_decrypt(EncData, PrivateKey) when is_binary(EncData) ->
|
||||
public_key:decrypt_private(EncData, PrivateKey, [{rsa_padding, rsa_pkcs1_padding}]).
|
||||
|
||||
rsa_generate_key() ->
|
||||
PrivateKey = public_key:generate_key({rsa, 2048, 65537}),
|
||||
PublicKey = #'RSAPublicKey'{
|
||||
modulus = PrivateKey#'RSAPrivateKey'.modulus,
|
||||
publicExponent = PrivateKey#'RSAPrivateKey'.publicExponent
|
||||
},
|
||||
|
||||
PemBin = public_key:pem_encode([
|
||||
public_key:pem_entry_encode('RSAPublicKey', PublicKey)
|
||||
]),
|
||||
PK = binary_to_list(PemBin),
|
||||
{PK, PrivateKey}.
|
||||
|
||||
%% 基于aes的加密算法
|
||||
-spec aes_encrypt(binary(), binary(), binary()) -> binary().
|
||||
aes_encrypt(Key, IVec, PlainText) when is_binary(Key), is_binary(IVec), is_binary(PlainText) ->
|
||||
@ -40,4 +50,5 @@ aes_encrypt(Key, IVec, PlainText) when is_binary(Key), is_binary(IVec), is_binar
|
||||
%% 基于aes的解密算法
|
||||
-spec aes_decrypt(binary(), binary(), binary()) -> binary().
|
||||
aes_decrypt(Key, IVec, CipherText) when is_binary(Key), is_binary(IVec), is_binary(CipherText) ->
|
||||
crypto:crypto_one_time(aes_128_ofb, Key, IVec, CipherText, [{encrypt, false}, {padding, pkcs_padding}]).
|
||||
crypto:crypto_one_time(aes_128_ofb, Key, IVec, CipherText, [{encrypt, false}, {padding, pkcs_padding}]).
|
||||
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
|
||||
%% API
|
||||
-export([start_link/2]).
|
||||
-export([get_name/1, get_pid/1, lookup_pid/1, attach/6, peer_info/5, unregister/3, debug_info/1, get_network_id/1, arp_query/2]).
|
||||
-export([get_name/1, get_pid/1, lookup_pid/1, attach/6, peer_info/4, unregister/3, debug_info/1, get_network_id/1, arp_query/2]).
|
||||
-export([forward/5, stun_request/4, disable_client/2, dropout_client/2]).
|
||||
-export([test_event/1]).
|
||||
|
||||
@ -107,9 +107,9 @@ arp_query(Pid, TargetIp) when is_pid(Pid), is_integer(TargetIp) ->
|
||||
unregister(Pid, ClientId, Mac) when is_pid(Pid), is_binary(ClientId), is_binary(Mac) ->
|
||||
gen_server:cast(Pid, {unregister, ClientId, Mac}).
|
||||
|
||||
-spec peer_info(Pid :: pid(), Sock :: inet:socket(), Peer :: {inet:ip4_address(), integer()}, PacketId :: integer(), Query :: #sdl_query_info{}) -> no_return().
|
||||
peer_info(Pid, Sock, ClientPeer, PacketId, Query) when is_pid(Pid) ->
|
||||
gen_server:cast(Pid, {peer_info, Sock, ClientPeer, PacketId, Query}).
|
||||
-spec peer_info(Pid :: pid(), Sock :: inet:socket(), Peer :: {inet:ip4_address(), integer()}, Query :: #sdl_query_info{}) -> no_return().
|
||||
peer_info(Pid, Sock, ClientPeer, Query) when is_pid(Pid) ->
|
||||
gen_server:cast(Pid, {peer_info, Sock, ClientPeer, Query}).
|
||||
|
||||
-spec forward(pid(), Sock :: any(), SrcMac :: binary(), DstMac :: binary(), Packet :: binary()) -> no_return().
|
||||
forward(Pid, Sock, SrcMac, DstMac, Packet) when is_pid(Pid), is_binary(SrcMac), is_binary(DstMac), is_binary(Packet) ->
|
||||
@ -253,13 +253,17 @@ handle_call(debug_info, _From, State = #state{network_id = NetworkId, ipaddr = I
|
||||
|
||||
%% 网络存在的nat_peer信息
|
||||
%% TODO SrcMac不存在的时候需要重新校验
|
||||
handle_cast({peer_info, Sock, {ClientIp, ClientPort}, PacketId, #sdl_query_info{src_mac = SrcMac, dst_mac = DstMac}}, State = #state{endpoints = Endpoints}) ->
|
||||
handle_cast({peer_info, Sock, {ClientIp, ClientPort}, #sdl_query_info{pkt_id = PktId, src_mac = SrcMac, dst_mac = DstMac}},
|
||||
State = #state{network_id = NetworkId, endpoints = Endpoints}) ->
|
||||
|
||||
case maps:find(DstMac, Endpoints) of
|
||||
{ok, #endpoint{hole = #hole{peer = DstNatPeer = {{Ip0, Ip1, Ip2, Ip3}, DstNatPort}, nat_type = DstNatType}, v6_info = DstV6Info}} ->
|
||||
%% 让目标服务器发送sendRegister事件(2024-06-25 新增,提高打洞的成功率)
|
||||
maybe_preload_hole(DstNatPeer, maps:get(SrcMac, Endpoints, undefined)),
|
||||
|
||||
PeerInfo = sdlan_pb:encode_msg(#sdl_peer_info{
|
||||
pkt_id = PktId,
|
||||
network_id = NetworkId,
|
||||
dst_mac = DstMac,
|
||||
v4_info = #sdl_v4_info {
|
||||
port = DstNatPort,
|
||||
@ -268,10 +272,15 @@ handle_cast({peer_info, Sock, {ClientIp, ClientPort}, PacketId, #sdl_query_info{
|
||||
},
|
||||
v6_info = DstV6Info
|
||||
}),
|
||||
PeerPacket = <<?PACKET_PEER_INFO, PacketId:32, PeerInfo/binary>>,
|
||||
PeerPacket = <<?PACKET_PEER_INFO, PeerInfo/binary>>,
|
||||
gen_udp:send(Sock, ClientIp, ClientPort, PeerPacket);
|
||||
_ ->
|
||||
EmptyPeerPacket = <<?PACKET_PEER_INFO, PacketId:32>>,
|
||||
EmptyPeerInfo = sdlan_pb:encode_msg(#sdl_empty_peer_info{
|
||||
pkt_id = PktId,
|
||||
network_id = NetworkId,
|
||||
dst_mac = DstMac
|
||||
}),
|
||||
EmptyPeerPacket = <<?PACKET_PEER_INFO, EmptyPeerInfo/binary>>,
|
||||
gen_udp:send(Sock, ClientIp, ClientPort, EmptyPeerPacket)
|
||||
end,
|
||||
{noreply, State};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -27,22 +27,13 @@
|
||||
%% API
|
||||
-export([start_link/4, do_register/4]).
|
||||
|
||||
-spec start_link(Sock :: inet:socket(), Ip :: inet:ip4_address(), Port :: integer(), Packet :: binary()) -> {ok, pid()}.
|
||||
-spec start_link(Sock :: inet:socket(), Ip :: inet:ip4_address(), Port :: integer(), Packet :: #sdl_register_super{}) -> {ok, pid()}.
|
||||
start_link(Sock, Ip, Port, Packet) ->
|
||||
{ok, erlang:spawn_link(?MODULE, do_register, [Sock, Ip, Port, Packet])}.
|
||||
|
||||
do_register(Sock, SrcIp, SrcPort, <<PacketId:32, Body/binary>>) ->
|
||||
#sdl_register_super{
|
||||
version = _Version,
|
||||
client_id = ClientId,
|
||||
network_id = NetworkId,
|
||||
mac = Mac,
|
||||
ip = Ip,
|
||||
mask_len = MaskLen,
|
||||
hostname = HostName,
|
||||
pub_key = PubKey,
|
||||
access_token = AccessToken
|
||||
} = sdlan_pb:decode_msg(Body, sdl_register_super),
|
||||
do_register(Sock, SrcIp, SrcPort, #sdl_register_super{
|
||||
pkt_id = PktId, client_id = ClientId, network_id = NetworkId, mac = Mac, ip = Ip, mask_len = MaskLen,
|
||||
hostname = HostName, pub_key = PubKey, access_token = AccessToken}) ->
|
||||
|
||||
%% 参数检查
|
||||
logger:debug("[sdlan_channel] client_id: ~p, ip: ~p, mac: ~p, host_name: ~p, access_token: ~p, network_id: ~p",
|
||||
@ -73,12 +64,13 @@ do_register(Sock, SrcIp, SrcPort, <<PacketId:32, Body/binary>>) ->
|
||||
EncodedAesKey = rsa_encode(AesKey, RsaPubKey),
|
||||
|
||||
RegisterSuperAck = sdlan_pb:encode_msg(#sdl_register_super_ack {
|
||||
pkt_id = PktId,
|
||||
aes_key = EncodedAesKey,
|
||||
session_token = SessionToken
|
||||
}),
|
||||
|
||||
%% 发送确认信息
|
||||
Reply = <<?PACKET_REGISTER_SUPER_ACK, PacketId:32, RegisterSuperAck/binary>>,
|
||||
Reply = <<?PACKET_REGISTER_SUPER_ACK, RegisterSuperAck/binary>>,
|
||||
gen_udp:send(Sock, SrcIp, SrcPort, Reply),
|
||||
|
||||
%% 设置节点的在线状态
|
||||
@ -86,34 +78,35 @@ do_register(Sock, SrcIp, SrcPort, <<PacketId:32, Body/binary>>) ->
|
||||
logger:debug("[sdlan_channel] client_id: ~p, set none online result is: ~p", [ClientId, Result]);
|
||||
{error, no_ip} ->
|
||||
logger:warning("[sdlan_channel] client_id: ~p, register get error: no_ip", [ClientId]),
|
||||
gen_udp:send(Sock, SrcIp, SrcPort, register_nak_reply(PacketId, ?NAK_NO_IP, <<"No Ip address">>));
|
||||
gen_udp:send(Sock, SrcIp, SrcPort, register_nak_reply(PktId, ?NAK_NO_IP, <<"No Ip address">>));
|
||||
{error, host_name_used} ->
|
||||
logger:warning("[sdlan_channel] client_id: ~p, register get error: host_name_used", [ClientId]),
|
||||
gen_udp:send(Sock, SrcIp, SrcPort, register_nak_reply(PacketId, ?NAK_HOSTNAME_USED, <<"Host Name Used">>));
|
||||
gen_udp:send(Sock, SrcIp, SrcPort, register_nak_reply(PktId, ?NAK_HOSTNAME_USED, <<"Host Name Used">>));
|
||||
{error, client_disabled} ->
|
||||
logger:warning("[sdlan_channel] client_id: ~p, register get error: client_disabled", [ClientId]),
|
||||
gen_udp:send(Sock, SrcIp, SrcPort, register_nak_reply(PacketId, ?NAK_NODE_DISABLE, <<"Client Connection Disable">>))
|
||||
gen_udp:send(Sock, SrcIp, SrcPort, register_nak_reply(PktId, ?NAK_NODE_DISABLE, <<"Client Connection Disable">>))
|
||||
end;
|
||||
undefined ->
|
||||
logger:warning("[sdlan_channel] client_id: ~p, register get error: network not found", [ClientId]),
|
||||
gen_udp:send(Sock, SrcIp, SrcPort, register_nak_reply(PacketId, ?NAK_INTERNAL_FAULT, <<"Internal Error">>))
|
||||
gen_udp:send(Sock, SrcIp, SrcPort, register_nak_reply(PktId, ?NAK_INTERNAL_FAULT, <<"Internal Error">>))
|
||||
end;
|
||||
{ok, #{<<"error">> := #{<<"code">> := Code, <<"message">> := Message}}} ->
|
||||
logger:warning("[sdlan_channel] network_id: ~p, client_id: ~p, register get error: ~ts, error_code: ~p", [NetworkId, ClientId, Message, Code]),
|
||||
gen_udp:send(Sock, SrcIp, SrcPort, register_nak_reply(PacketId, Code, Message));
|
||||
gen_udp:send(Sock, SrcIp, SrcPort, register_nak_reply(PktId, Code, Message));
|
||||
{error, Reason} ->
|
||||
logger:warning("[sdlan_channel] network_id: ~p, client_id: ~p, register get error: ~p", [NetworkId, ClientId, Reason]),
|
||||
gen_udp:send(Sock, SrcIp, SrcPort, register_nak_reply(PacketId, ?NAK_NETWORK_FAULT, <<"Network Error">>))
|
||||
gen_udp:send(Sock, SrcIp, SrcPort, register_nak_reply(PktId, ?NAK_NETWORK_FAULT, <<"Network Error">>))
|
||||
end,
|
||||
exit(normal).
|
||||
|
||||
-spec register_nak_reply(PacketId :: integer(), ErrorCode :: integer(), ErrorMsg :: binary()) -> binary().
|
||||
register_nak_reply(PacketId, ErrorCode, ErrorMsg) when is_integer(PacketId), is_integer(ErrorCode), is_binary(ErrorMsg) ->
|
||||
RegisterNakReply = sdlan_pb:encode_msg(#sdl_register_super_nak {
|
||||
pkt_id = PacketId,
|
||||
error_code = ErrorCode,
|
||||
error_message = ErrorMsg
|
||||
}),
|
||||
<<?PACKET_REGISTER_SUPER_NAK, PacketId:32, RegisterNakReply/binary>>.
|
||||
<<?PACKET_REGISTER_SUPER_NAK, RegisterNakReply/binary>>.
|
||||
|
||||
-spec rsa_encode(PlainText :: binary(), RsaPubKey :: public_key:rsa_public_key()) -> binary().
|
||||
rsa_encode(PlainText, RsaPubKey) when is_binary(PlainText) ->
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(sdlan_register_worker_sup).
|
||||
-author("anlicheng").
|
||||
-include("sdlan_pb.hrl").
|
||||
|
||||
-behaviour(supervisor).
|
||||
|
||||
@ -59,7 +60,7 @@ init([]) ->
|
||||
%%% Internal functions
|
||||
%%%===================================================================
|
||||
|
||||
-spec start_worker(Sock :: inet:socket(), Ip :: inet:ip4_address(), Port :: integer(), Packet :: binary()) -> supervisor:startchild_ret().
|
||||
-spec start_worker(Sock :: inet:socket(), Ip :: inet:ip4_address(), Port :: integer(), Packet :: #sdl_register_super{}) -> supervisor:startchild_ret().
|
||||
start_worker(Sock, Ip, Port, Packet) ->
|
||||
%% Start a temporary worker under the supervisor
|
||||
supervisor:start_child(?SERVER, [Sock, Ip, Port, Packet]).
|
||||
@ -117,16 +117,20 @@ code_change(_OldVsn, State = #state{}, _Extra) ->
|
||||
-spec handle_packet(Sock :: inet:socket(), Ip :: inet:ip4_address(), Port :: integer(), Packet :: binary()) -> no_return().
|
||||
%% 带上token或者网络id来注册
|
||||
handle_packet(Sock, Ip, Port, <<?PACKET_REGISTER_SUPER, Body/binary>>) ->
|
||||
sdlan_register_worker_sup:start_worker(Sock, Ip, Port, Body);
|
||||
maybe
|
||||
Register = catch sdlan_pb:decode_msg(Body, sdl_register_super),
|
||||
#sdl_register_super{} ?= Register,
|
||||
sdlan_register_worker_sup:start_worker(Sock, Ip, Port, Register)
|
||||
end;
|
||||
|
||||
%% 查询信息
|
||||
handle_packet(Sock, ClientIp, ClientPort, <<?PACKET_QUERY_INFO, PacketId:32, Body/binary>>) ->
|
||||
handle_packet(Sock, ClientIp, ClientPort, <<?PACKET_QUERY_INFO, Body/binary>>) ->
|
||||
maybe
|
||||
Query = catch sdlan_pb:decode_msg(Body, sdl_query_info),
|
||||
#sdl_query_info{network_id = NetworkId} ?= Query,
|
||||
|
||||
{ok, NetworkPid} ?= sdlan_network:lookup_pid(NetworkId),
|
||||
sdlan_network:peer_info(NetworkPid, Sock, {ClientIp, ClientPort}, PacketId, Query)
|
||||
sdlan_network:peer_info(NetworkPid, Sock, {ClientIp, ClientPort}, Query)
|
||||
end;
|
||||
|
||||
%% 处理心跳逻辑
|
||||
|
||||
@ -9,12 +9,14 @@
|
||||
-module(stun_client).
|
||||
-author("anlicheng").
|
||||
-include("sdlan_pb.hrl").
|
||||
-include("sdlan.hrl").
|
||||
|
||||
-behaviour(gen_server).
|
||||
|
||||
%% API
|
||||
-export([start_link/0]).
|
||||
-export([register/1, debug_info/1]).
|
||||
-export([test/0]).
|
||||
|
||||
%% gen_server callbacks
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
|
||||
@ -25,19 +27,25 @@
|
||||
-define(STUN_REGISTER, 3).
|
||||
%% 响应
|
||||
-define(STUN_REGISTER_ACK, 4).
|
||||
|
||||
-define(STUN_DATA, 5).
|
||||
|
||||
-define(SUPER_HOST, "127.0.0.1").
|
||||
-define(SUPER_PORT, 1265).
|
||||
|
||||
-record(state, {
|
||||
socket,
|
||||
tun_socket,
|
||||
client_id :: binary(),
|
||||
mac :: binary(),
|
||||
network_id,
|
||||
net_addr,
|
||||
ip,
|
||||
mask_len,
|
||||
aes_key,
|
||||
cookie = 1,
|
||||
|
||||
session_token :: binary(),
|
||||
|
||||
private_key,
|
||||
|
||||
sessions = #{}
|
||||
}).
|
||||
|
||||
@ -45,6 +53,11 @@
|
||||
%%% API
|
||||
%%%===================================================================
|
||||
|
||||
test() ->
|
||||
{ok, Pid} = start_link(),
|
||||
register(Pid),
|
||||
ok.
|
||||
|
||||
register(Pid) when is_pid(Pid) ->
|
||||
gen_server:call(Pid, register).
|
||||
|
||||
@ -67,11 +80,8 @@ start_link() ->
|
||||
{ok, State :: #state{}} | {ok, State :: #state{}, timeout() | hibernate} |
|
||||
{stop, Reason :: term()} | ignore).
|
||||
init([]) ->
|
||||
{ok, Socket} = gen_tcp:connect("localhost", 18083, [binary, {packet, 2}, {active, true}]),
|
||||
inet_tcp:controlling_process(Socket, self()),
|
||||
{ok, TunSocket} = gen_udp:open(12345, [binary, {active, true}]),
|
||||
|
||||
{ok, #state{socket = Socket, tun_socket = TunSocket, client_id = <<"22222222222222222222222222222222">>}}.
|
||||
{ok, TunSocket} = gen_udp:open(0, [binary, {active, true}]),
|
||||
{ok, #state{tun_socket = TunSocket, network_id = 8, mac = <<11, 12, 13, 14, 15, 16>>, ip = x, mask_len = 24, client_id = <<"22222222222222222222222222222222">>}}.
|
||||
|
||||
%% @private
|
||||
%% @doc Handling call messages
|
||||
@ -86,35 +96,26 @@ init([]) ->
|
||||
handle_call(debug_info, _From, State) ->
|
||||
{reply, {ok, State}, State};
|
||||
|
||||
handle_call(register, _From, State = #state{socket = Socket, client_id = ClientId}) ->
|
||||
Req = #{
|
||||
<<"version">> => 1,
|
||||
<<"client_id">> => ClientId,
|
||||
<<"dev_addr">> => #{
|
||||
<<"net_addr">> => 0,
|
||||
<<"net_bit_len">> => 0
|
||||
},
|
||||
<<"token">> => <<"1234567890">>
|
||||
},
|
||||
handle_call(register, _From, State = #state{tun_socket = Socket, network_id = NId, client_id = ClientId, ip = Ip, mac = Mac, mask_len = MaskLen}) ->
|
||||
{PublicKeyBin, PrivateKey} = sdlan_cipher:rsa_generate_key(),
|
||||
|
||||
Register = #sdl_register_super {
|
||||
version = 0,
|
||||
pkt_id = 1,
|
||||
client_id = ClientId,
|
||||
network_id = 8,
|
||||
mac = <<11, 12, 13, 14, 15, 16>>,
|
||||
ip = 0,
|
||||
mask_len = 0,
|
||||
network_id = NId,
|
||||
mac = Mac,
|
||||
ip = Ip,
|
||||
mask_len = MaskLen,
|
||||
hostname = <<"mysql1">>,
|
||||
pub_key = <<>>,
|
||||
pub_key = PublicKeyBin,
|
||||
access_token = <<"access_token1234">>
|
||||
},
|
||||
|
||||
logger:debug("register is: ~p", [Register]),
|
||||
|
||||
Packet = jiffy:encode(Req, [force_utf8]),
|
||||
ok = gen_tcp:send(Socket, <<1:32, 101, Packet/binary>>),
|
||||
Pkt = sdlan_pb:encode_msg(Register),
|
||||
ok = gen_udp:send(Socket, ?SUPER_HOST, ?SUPER_PORT, <<?PACKET_REGISTER_SUPER, Pkt/binary>>),
|
||||
|
||||
{reply, ok, State}.
|
||||
{reply, ok, State#state{private_key = PrivateKey}}.
|
||||
|
||||
%% @private
|
||||
%% @doc Handling cast messages
|
||||
@ -131,56 +132,33 @@ handle_cast(_Request, State = #state{}) ->
|
||||
{noreply, NewState :: #state{}} |
|
||||
{noreply, NewState :: #state{}, timeout() | hibernate} |
|
||||
{stop, Reason :: term(), NewState :: #state{}}).
|
||||
handle_info({tcp, Socket, <<1:32, 5, Data/binary>>}, State = #state{socket = Socket, tun_socket = TunSocket, client_id = ClientId, cookie = Cookie}) ->
|
||||
Response = jiffy:decode(Data, [return_maps]),
|
||||
#{
|
||||
<<"dev_addr">> := #{
|
||||
<<"network_id">> := NetworkId,
|
||||
<<"net_addr">> := NetAddr,
|
||||
<<"net_bit_len">> := NetBitLen
|
||||
},
|
||||
<<"aes_key">> := AesKey,
|
||||
<<"lifetime">> := Lifetime
|
||||
} = Response,
|
||||
handle_info({udp, _Socket, _ServerIp, _ServerPort, <<?PACKET_REGISTER_SUPER_ACK, Data/binary>>}, State = #state{private_key = PrivateKey}) ->
|
||||
SuperAck = #sdl_register_super_ack{session_token = SessionToken, aes_key = EncAesKey} = sdlan_pb:decode_msg(Data, sdl_register_super_ack),
|
||||
|
||||
logger:debug("[stun_client] get a register super response: ~p, alloc ip addr: ~p", [Response, sdlan_ipaddr:int_to_ipv4(NetAddr)]),
|
||||
AesKey = sdlan_cipher:rsa_decrypt(EncAesKey, PrivateKey),
|
||||
logger:debug("[stun_client] get a register super ack: ~p, aes_key: ~p", [SuperAck, AesKey]),
|
||||
|
||||
%% 开始注册自己的tun信息
|
||||
gen_udp:send(TunSocket, "localhost", 1265, <<1, Cookie:32, ClientId/binary, NetworkId:32, NetAddr:32>>),
|
||||
erlang:start_timer(5000, self(), stun_request_ticker),
|
||||
|
||||
{noreply, State#state{network_id = NetworkId, net_addr = NetAddr, mask_len = NetBitLen, aes_key = AesKey, cookie = Cookie + 1}};
|
||||
{noreply, State#state{session_token = SessionToken}};
|
||||
|
||||
handle_info({udp, _, _, _, <<2, Cookie:32, Family, Port:16, Ip0, Ip1, Ip2, Ip3>>}, State = #state{}) ->
|
||||
logger:debug("[stun_client] tun register ack, cookie: ~p, ack: ~p", [Cookie, {Family, Port, {Ip0, Ip1, Ip2, Ip3}}]),
|
||||
{noreply, State};
|
||||
handle_info({udp, _Socket, _ServerIp, _ServerPort, <<?PACKET_REGISTER_SUPER_NAK, Data/binary>>}, State) ->
|
||||
SuperNak = #sdl_register_super_nak{} = sdlan_pb:decode_msg(Data, sdl_register_super_nak),
|
||||
logger:debug("[stun_client] get a register super nak: ~p", [SuperNak]),
|
||||
{noreply, State#state{}};
|
||||
|
||||
handle_info({udp, _, Ip, Port, <<?STUN_REGISTER:8, NetworkId:32, SrcIp:32, DstIp:32>>}, State = #state{tun_socket = TunSocket, sessions = Sessions}) ->
|
||||
Packet = <<?STUN_REGISTER_ACK, NetworkId:32, DstIp:32, SrcIp:32>>,
|
||||
logger:debug("[stun_client] will send stun reply: ~p, peer: ~p", [Packet, {Ip, Port}]),
|
||||
ok = gen_udp:send(TunSocket, Ip, Port, Packet),
|
||||
handle_info({timeout, _, stun_request_ticker}, State = #state{tun_socket = TunSocket, client_id = ClientId, mac = Mac, ip = Ip, session_token = SessionToken}) ->
|
||||
Packet = sdlan_pb:encode_msg(#sdl_stun_request{
|
||||
client_id = ClientId,
|
||||
network_id = 8,
|
||||
mac = Mac,
|
||||
ip = Ip,
|
||||
nat_type = 0,
|
||||
session_token = SessionToken
|
||||
}),
|
||||
gen_udp:send(TunSocket, ?SUPER_HOST, ?SUPER_PORT, <<?PACKET_STUN_REQUEST, Packet/binary>>),
|
||||
erlang:start_timer(5000, self(), stun_request_ticker),
|
||||
|
||||
NSessions = maps:put(SrcIp, {Ip, Port}, Sessions),
|
||||
{noreply, State#state{sessions = NSessions}};
|
||||
|
||||
handle_info({udp, _, Ip, Port, <<?STUN_REGISTER_ACK, NetworkId:32, SrcIp:32, DstIp:32>>}, State = #state{sessions = Sessions}) ->
|
||||
logger:debug("[stun_client] stun_data: network_id: ~p, src: ~p, dst: ~p, register_ack!!!", [NetworkId, SrcIp, DstIp]),
|
||||
NSessions = maps:put(SrcIp, {Ip, Port}, Sessions),
|
||||
{noreply, State#state{sessions = NSessions}};
|
||||
|
||||
handle_info({udp, _, _Ip0, _Port0, <<?STUN_DATA, NetworkId:32, SrcIp:32, DstIp:32, TTL:8, Data/binary>>}, State = #state{tun_socket = TunSocket, sessions = Sessions}) ->
|
||||
logger:debug("[stun_client] stun_data: network_id: ~p, src: ~p, dst: ~p, data!!!", [NetworkId, SrcIp, DstIp]),
|
||||
case maps:is_key(SrcIp, Sessions) of
|
||||
true ->
|
||||
{Ip, Port} = maps:get(SrcIp, Sessions),
|
||||
ok = gen_udp:send(TunSocket, Ip, Port, <<?STUN_DATA, NetworkId:32, DstIp:32, SrcIp:32, 255, Data/binary>>),
|
||||
logger:debug("[stun_client] stun_data: network_id: ~p, src: ~p, dst: ~p, reply data!!!", [NetworkId, SrcIp, DstIp]);
|
||||
false ->
|
||||
logger:debug("[stun_client] stun_data: network_id: ~p, src: ~p, dst: ~p, no session", [NetworkId, SrcIp, DstIp])
|
||||
end,
|
||||
{noreply, State};
|
||||
|
||||
handle_info(Info, State = #state{}) ->
|
||||
logger:debug("[stun_client] get info: ~p", [Info]),
|
||||
{noreply, State}.
|
||||
|
||||
%% @private
|
||||
|
||||
@ -19,7 +19,7 @@ message SDLV6Info {
|
||||
// 只是验证凭证是否合法 (access_token)
|
||||
// 这里修改成了扁平的结构, 否则有些字段不好找放的位置
|
||||
message SDLRegisterSuper {
|
||||
uint32 version = 1;
|
||||
uint32 pkt_id = 1;
|
||||
string client_id = 2;
|
||||
uint32 network_id = 3;
|
||||
bytes mac = 4;
|
||||
@ -32,29 +32,39 @@ message SDLRegisterSuper {
|
||||
|
||||
// 这里修改成了udp的方式,后续需要验证: session_token
|
||||
message SDLRegisterSuperAck {
|
||||
bytes aes_key = 1;
|
||||
bytes session_token = 2;
|
||||
uint32 pkt_id = 1;
|
||||
bytes aes_key = 2;
|
||||
bytes session_token = 3;
|
||||
}
|
||||
|
||||
// 注册失败时候的消息体
|
||||
message SDLRegisterSuperNak {
|
||||
uint32 error_code = 1;
|
||||
string error_message = 2;
|
||||
uint32 pkt_id = 1;
|
||||
uint32 error_code = 2;
|
||||
string error_message = 3;
|
||||
}
|
||||
|
||||
// 网络地址查询
|
||||
message SDLQueryInfo {
|
||||
uint32 network_id = 1;
|
||||
bytes src_mac = 2;
|
||||
bytes dst_mac = 3;
|
||||
bytes session_token = 4;
|
||||
uint32 pkt_id = 1;
|
||||
uint32 network_id = 2;
|
||||
bytes src_mac = 3;
|
||||
bytes dst_mac = 4;
|
||||
bytes session_token = 5;
|
||||
}
|
||||
|
||||
message SDLPeerInfo {
|
||||
uint32 network_id = 1;
|
||||
bytes dst_mac = 2;
|
||||
SDLV4Info v4_info = 3;
|
||||
optional SDLV6Info v6_info = 4;
|
||||
uint32 pkt_id = 1;
|
||||
uint32 network_id = 2;
|
||||
bytes dst_mac = 3;
|
||||
SDLV4Info v4_info = 4;
|
||||
optional SDLV6Info v6_info = 5;
|
||||
}
|
||||
|
||||
message SDLEmptyPeerInfo {
|
||||
uint32 pkt_id = 1;
|
||||
uint32 network_id = 2;
|
||||
bytes dst_mac = 3;
|
||||
}
|
||||
|
||||
// 事件定义, 下面的事件是服务器主动推送的,不需要响应
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user