support arp request
This commit is contained in:
parent
b009a324bd
commit
92a5998868
@ -60,6 +60,10 @@
|
|||||||
%% 欢迎消息
|
%% 欢迎消息
|
||||||
-define(PACKET_WELCOME, 16#4F).
|
-define(PACKET_WELCOME, 16#4F).
|
||||||
|
|
||||||
|
%% ARP查询
|
||||||
|
-define(PACKET_ARP_REQUEST, 16#50).
|
||||||
|
-define(PACKET_ARP_RESPONSE, 16#51).
|
||||||
|
|
||||||
%% 数据转发
|
%% 数据转发
|
||||||
-define(PACKET_STUN_DATA, 16#FF).
|
-define(PACKET_STUN_DATA, 16#FF).
|
||||||
|
|
||||||
|
|||||||
@ -159,7 +159,7 @@ handle_event(internal, {frame, <<?PACKET_REGISTER_SUPER, Body/binary>>}, initial
|
|||||||
true = not (sdlan_util:is_multicast_mac(Mac) orelse sdlan_util:is_broadcast_mac(Mac)),
|
true = not (sdlan_util:is_multicast_mac(Mac) orelse sdlan_util:is_broadcast_mac(Mac)),
|
||||||
|
|
||||||
MacBinStr = sdlan_util:format_mac(Mac),
|
MacBinStr = sdlan_util:format_mac(Mac),
|
||||||
IpAddr = sdlan_ipaddr:int_to_ipv4(Ip),
|
IpAddr = sdlan_util:int_to_ipv4(Ip),
|
||||||
Params = #{
|
Params = #{
|
||||||
<<"network_id">> => NetworkId,
|
<<"network_id">> => NetworkId,
|
||||||
<<"client_id">> => ClientId,
|
<<"client_id">> => ClientId,
|
||||||
@ -251,6 +251,28 @@ handle_event(internal, {frame, <<?PACKET_QUERY_INFO, Body/binary>>}, registered,
|
|||||||
keep_state_and_data
|
keep_state_and_data
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
%% arp查询
|
||||||
|
handle_event(internal, {frame, <<?PACKET_ARP_REQUEST, Body/binary>>}, registered, #state{stream = Stream, network_id = NetworkId, network_pid = NetworkPid, mac = SrcMac}) when is_pid(NetworkPid) ->
|
||||||
|
#sdl_arp_request{pkt_id = PktId, target_ip = TargetIp} = sdlan_pb:decode_msg(Body, sdl_arp_request),
|
||||||
|
case sdlan_network:arp_request(NetworkPid, TargetIp) of
|
||||||
|
error ->
|
||||||
|
logger:debug("[sdlan_channel] network: ~p, arp_request target_ip: ~p, mac not found", [NetworkId, TargetIp]),
|
||||||
|
EmptyResponse = sdlan_pb:encode_msg(#sdl_empty{
|
||||||
|
pkt_id = PktId
|
||||||
|
}),
|
||||||
|
quic_send(Stream, <<?PACKET_ARP_RESPONSE, EmptyResponse/binary>>),
|
||||||
|
keep_state_and_data;
|
||||||
|
{ok, Mac} ->
|
||||||
|
logger:debug("[sdlan_channel] network: ~p, arp_request target_ip: ~p, mac: ~p", [NetworkId, sdlan_util:int_to_ipv4(TargetIp), sdlan_util:format_mac(Mac)]),
|
||||||
|
PeerInfo = sdlan_pb:encode_msg(#sdl_arp_response{
|
||||||
|
pkt_id = PktId,
|
||||||
|
target_ip = TargetIp,
|
||||||
|
target_mac = Mac
|
||||||
|
}),
|
||||||
|
quic_send(Stream, <<?PACKET_PEER_INFO, PeerInfo/binary>>),
|
||||||
|
keep_state_and_data
|
||||||
|
end;
|
||||||
|
|
||||||
handle_event(internal, {frame, <<?PACKET_POLICY_REQUEST, Body/binary>>}, registered, #state{stream = Stream, network_pid = NetworkPid}) when is_pid(NetworkPid) ->
|
handle_event(internal, {frame, <<?PACKET_POLICY_REQUEST, Body/binary>>}, registered, #state{stream = Stream, network_pid = NetworkPid}) when is_pid(NetworkPid) ->
|
||||||
maybe
|
maybe
|
||||||
PolicyRequest = catch sdlan_pb:decode_msg(Body, sdl_policy_request),
|
PolicyRequest = catch sdlan_pb:decode_msg(Body, sdl_policy_request),
|
||||||
|
|||||||
@ -1,55 +0,0 @@
|
|||||||
%%%-------------------------------------------------------------------
|
|
||||||
%%% @author anlicheng
|
|
||||||
%%% @copyright (C) 2024, <COMPANY>
|
|
||||||
%%% @doc
|
|
||||||
%%%
|
|
||||||
%%% @end
|
|
||||||
%%% Created : 27. 3月 2024 17:43
|
|
||||||
%%%-------------------------------------------------------------------
|
|
||||||
-module(sdlan_ipaddr).
|
|
||||||
-author("anlicheng").
|
|
||||||
|
|
||||||
%% API
|
|
||||||
-export([ipv4_to_int/1, int_to_ipv4/1, ips/2, format_ip/1]).
|
|
||||||
-export([ipv6_bytes_to_binary/1]).
|
|
||||||
|
|
||||||
format_ip(Ip) when is_integer(Ip) ->
|
|
||||||
int_to_ipv4(Ip);
|
|
||||||
format_ip(Ip) ->
|
|
||||||
Ip.
|
|
||||||
|
|
||||||
-spec ipv4_to_int(Ip :: integer() | binary() | inet:ip4_address()) -> integer().
|
|
||||||
ipv4_to_int(Ip) when is_integer(Ip) ->
|
|
||||||
Ip;
|
|
||||||
ipv4_to_int({Ip0, Ip1, Ip2, Ip3}) ->
|
|
||||||
<<Ip:32>> = <<Ip0, Ip1, Ip2, Ip3>>,
|
|
||||||
Ip;
|
|
||||||
ipv4_to_int(Ip) when is_binary(Ip) ->
|
|
||||||
Parts0 = binary:split(Ip, <<".">>, [global]),
|
|
||||||
Parts = lists:map(fun binary_to_integer/1, Parts0),
|
|
||||||
<<IpInt:32>> = iolist_to_binary(Parts),
|
|
||||||
IpInt.
|
|
||||||
|
|
||||||
-spec int_to_ipv4(Ip :: integer()) -> binary().
|
|
||||||
int_to_ipv4(Ip) when is_integer(Ip) ->
|
|
||||||
<<Ip0, Ip1, Ip2, Ip3>> = <<Ip:32>>,
|
|
||||||
<<(integer_to_binary(Ip0))/binary, $., (integer_to_binary(Ip1))/binary, $., (integer_to_binary(Ip2))/binary, $., (integer_to_binary(Ip3))/binary>>.
|
|
||||||
|
|
||||||
-spec ips(NetAddr :: binary(), MaskLen :: integer()) -> [Ip :: integer()].
|
|
||||||
ips(NetAddr, MaskLen) when is_binary(NetAddr), is_integer(MaskLen) ->
|
|
||||||
Mask = 16#FFFFFFFF bsr MaskLen,
|
|
||||||
Net0 = ipv4_to_int(NetAddr),
|
|
||||||
%% 防止网络地址给得不对,比如: "192.168.1.101",
|
|
||||||
L = 32 - MaskLen,
|
|
||||||
Net = (Net0 bsr L) bsl L,
|
|
||||||
lists:map(fun(V) -> Net + V end, lists:seq(1, Mask - 1)).
|
|
||||||
|
|
||||||
-spec ipv6_bytes_to_binary(Bytes :: binary()) -> Bin :: binary().
|
|
||||||
ipv6_bytes_to_binary(<<A:16, B:16, C:16, D:16, E:16, F:16, G:16, H:16>>) ->
|
|
||||||
Segments = [integer_to_list(X, 16) || X <- [A, B, C, D, E, F, G, H]],
|
|
||||||
% 填充每个段以确保是4位
|
|
||||||
Padded = [string:pad(S, 4, leading, $0) || S <- Segments],
|
|
||||||
% 合并成IPv6地址格式,这里没有处理最简化形式的缩写
|
|
||||||
iolist_to_binary(lists:flatten(string:join(Padded, ":")));
|
|
||||||
ipv6_bytes_to_binary(_) ->
|
|
||||||
<<"">>.
|
|
||||||
@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
%% API
|
%% API
|
||||||
-export([start_link/2]).
|
-export([start_link/2]).
|
||||||
-export([get_name/1, get_pid/1, lookup_pid/1, peer_info/3, unregister/3, debug_info/1, get_network_id/1, attach/6]).
|
-export([get_name/1, get_pid/1, lookup_pid/1, peer_info/3, unregister/3, debug_info/1, get_network_id/1, attach/6, arp_request/2]).
|
||||||
-export([forward/5, update_hole/7, disable_client/2, get_channel/2]).
|
-export([forward/5, update_hole/7, disable_client/2, get_channel/2]).
|
||||||
-export([test_event/1]).
|
-export([test_event/1]).
|
||||||
|
|
||||||
@ -109,6 +109,10 @@ unregister(Pid, ClientId, Mac) when is_pid(Pid), is_binary(ClientId), is_binary(
|
|||||||
peer_info(Pid, SrcMac, DstMac) when is_pid(Pid), is_binary(SrcMac), is_binary(DstMac) ->
|
peer_info(Pid, SrcMac, DstMac) when is_pid(Pid), is_binary(SrcMac), is_binary(DstMac) ->
|
||||||
gen_server:call(Pid, {peer_info, SrcMac, DstMac}).
|
gen_server:call(Pid, {peer_info, SrcMac, DstMac}).
|
||||||
|
|
||||||
|
-spec arp_request(Pid :: pid(), TargetIp :: integer()) -> error | {ok, Mac :: binary()}.
|
||||||
|
arp_request(Pid, TargetIp) when is_pid(Pid), is_integer(TargetIp) ->
|
||||||
|
gen_server:call(Pid, {arp_request, TargetIp}).
|
||||||
|
|
||||||
-spec forward(pid(), Sock :: any(), SrcMac :: binary(), DstMac :: binary(), Packet :: binary()) -> no_return().
|
-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) ->
|
forward(Pid, Sock, SrcMac, DstMac, Packet) when is_pid(Pid), is_binary(SrcMac), is_binary(DstMac), is_binary(Packet) ->
|
||||||
gen_server:cast(Pid, {forward, Sock, SrcMac, DstMac, Packet}).
|
gen_server:cast(Pid, {forward, Sock, SrcMac, DstMac, Packet}).
|
||||||
@ -183,7 +187,7 @@ handle_call({attach, ChannelPid, ClientId, Mac, Ip, Hostname}, _From,
|
|||||||
State = #state{network_id = NetworkId, domain = Domain, endpoints = Endpoints, aes_key = AesKey}) ->
|
State = #state{network_id = NetworkId, domain = Domain, endpoints = Endpoints, aes_key = AesKey}) ->
|
||||||
%% 分配ip地址的时候,以mac地址为唯一基准
|
%% 分配ip地址的时候,以mac地址为唯一基准
|
||||||
logger:debug("[sdlan_network] alloc_ip, network_id: ~p, client_id: ~p, mac: ~p, ip_addr: ~p",
|
logger:debug("[sdlan_network] alloc_ip, network_id: ~p, client_id: ~p, mac: ~p, ip_addr: ~p",
|
||||||
[NetworkId, ClientId, sdlan_util:format_mac(Mac), sdlan_ipaddr:int_to_ipv4(Ip)]),
|
[NetworkId, ClientId, sdlan_util:format_mac(Mac), sdlan_util:int_to_ipv4(Ip)]),
|
||||||
%% 添加域名->ip的映射关系
|
%% 添加域名->ip的映射关系
|
||||||
sdlan_hostname_regedit:insert(Hostname, Domain, Ip),
|
sdlan_hostname_regedit:insert(Hostname, Domain, Ip),
|
||||||
|
|
||||||
@ -246,7 +250,7 @@ handle_call({peer_info, SrcMac, DstMac}, _From, State = #state{endpoints = Endpo
|
|||||||
{ok, #endpoint{hole = #hole{peer = {SrcNatIp, SrcNatPort}, nat_type = SrcNatType}, v6_info = SrcV6Info}} ?= maps:find(SrcMac, Endpoints),
|
{ok, #endpoint{hole = #hole{peer = {SrcNatIp, SrcNatPort}, nat_type = SrcNatType}, v6_info = SrcV6Info}} ?= maps:find(SrcMac, Endpoints),
|
||||||
RegisterEvent = sdlan_pb:encode_msg(#sdl_send_register_event {
|
RegisterEvent = sdlan_pb:encode_msg(#sdl_send_register_event {
|
||||||
dst_mac = SrcMac,
|
dst_mac = SrcMac,
|
||||||
nat_ip = sdlan_ipaddr:ipv4_to_int(SrcNatIp),
|
nat_ip = sdlan_util:ipv4_to_int(SrcNatIp),
|
||||||
nat_type = SrcNatType,
|
nat_type = SrcNatType,
|
||||||
nat_port = SrcNatPort,
|
nat_port = SrcNatPort,
|
||||||
v6_info = SrcV6Info
|
v6_info = SrcV6Info
|
||||||
@ -258,6 +262,15 @@ handle_call({peer_info, SrcMac, DstMac}, _From, State = #state{endpoints = Endpo
|
|||||||
{reply, error, State}
|
{reply, error, State}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
%% arp查询
|
||||||
|
handle_call({arp_request, TargetIp}, _From, State = #state{endpoints = Endpoints}) ->
|
||||||
|
case search_endpoint(fun(_, #endpoint{ip = Ip0}) -> Ip0 =:= TargetIp end, Endpoints) of
|
||||||
|
error ->
|
||||||
|
{reply, error, State};
|
||||||
|
{ok, Mac, _} ->
|
||||||
|
{reply, {ok, Mac}, State}
|
||||||
|
end;
|
||||||
|
|
||||||
handle_call(debug_info, _From, State = #state{network_id = NetworkId, ipaddr = IpAddr, mask_len = MaskLen, owner_id = OwnerId, endpoints = Endpoints}) ->
|
handle_call(debug_info, _From, State = #state{network_id = NetworkId, ipaddr = IpAddr, mask_len = MaskLen, owner_id = OwnerId, endpoints = Endpoints}) ->
|
||||||
Reply = #{
|
Reply = #{
|
||||||
<<"network_id">> => NetworkId,
|
<<"network_id">> => NetworkId,
|
||||||
@ -467,7 +480,7 @@ format_endpoint({Mac, #endpoint{client_id = ClientId, ip = Ip, hole = #hole{peer
|
|||||||
#{
|
#{
|
||||||
client_id => ClientId,
|
client_id => ClientId,
|
||||||
mac => sdlan_util:format_mac(Mac),
|
mac => sdlan_util:format_mac(Mac),
|
||||||
ip => sdlan_ipaddr:int_to_ipv4(Ip),
|
ip => sdlan_util:int_to_ipv4(Ip),
|
||||||
hole_map => HoleMap,
|
hole_map => HoleMap,
|
||||||
v6_info => V6InfoMap
|
v6_info => V6InfoMap
|
||||||
}.
|
}.
|
||||||
|
|||||||
@ -13,6 +13,8 @@
|
|||||||
-export([rand_byte/1, md5/1, format_mac/1, assert_call/2]).
|
-export([rand_byte/1, md5/1, format_mac/1, assert_call/2]).
|
||||||
-export([json_data/1, json_error/2]).
|
-export([json_data/1, json_error/2]).
|
||||||
-export([is_broadcast_mac/1, is_multicast_mac/1]).
|
-export([is_broadcast_mac/1, is_multicast_mac/1]).
|
||||||
|
-export([ipv4_to_int/1, int_to_ipv4/1, ips/2, format_ip/1]).
|
||||||
|
-export([ipv6_bytes_to_binary/1]).
|
||||||
|
|
||||||
-spec format_mac(Mac :: binary()) -> binary().
|
-spec format_mac(Mac :: binary()) -> binary().
|
||||||
format_mac(Mac) when is_binary(Mac) ->
|
format_mac(Mac) when is_binary(Mac) ->
|
||||||
@ -71,4 +73,46 @@ is_broadcast_mac(Mac) when is_binary(Mac) ->
|
|||||||
|
|
||||||
-spec is_multicast_mac(Mac :: binary()) -> boolean().
|
-spec is_multicast_mac(Mac :: binary()) -> boolean().
|
||||||
is_multicast_mac(Mac) when is_binary(Mac) ->
|
is_multicast_mac(Mac) when is_binary(Mac) ->
|
||||||
binary:part(Mac, 0, 3) =:= <<16#01,16#00,16#5E>>.
|
binary:part(Mac, 0, 3) =:= <<16#01,16#00,16#5E>>.
|
||||||
|
|
||||||
|
|
||||||
|
format_ip(Ip) when is_integer(Ip) ->
|
||||||
|
int_to_ipv4(Ip);
|
||||||
|
format_ip(Ip) ->
|
||||||
|
Ip.
|
||||||
|
|
||||||
|
-spec ipv4_to_int(Ip :: integer() | binary() | inet:ip4_address()) -> integer().
|
||||||
|
ipv4_to_int(Ip) when is_integer(Ip) ->
|
||||||
|
Ip;
|
||||||
|
ipv4_to_int({Ip0, Ip1, Ip2, Ip3}) ->
|
||||||
|
<<Ip:32>> = <<Ip0, Ip1, Ip2, Ip3>>,
|
||||||
|
Ip;
|
||||||
|
ipv4_to_int(Ip) when is_binary(Ip) ->
|
||||||
|
Parts0 = binary:split(Ip, <<".">>, [global]),
|
||||||
|
Parts = lists:map(fun binary_to_integer/1, Parts0),
|
||||||
|
<<IpInt:32>> = iolist_to_binary(Parts),
|
||||||
|
IpInt.
|
||||||
|
|
||||||
|
-spec int_to_ipv4(Ip :: integer()) -> binary().
|
||||||
|
int_to_ipv4(Ip) when is_integer(Ip) ->
|
||||||
|
<<Ip0, Ip1, Ip2, Ip3>> = <<Ip:32>>,
|
||||||
|
<<(integer_to_binary(Ip0))/binary, $., (integer_to_binary(Ip1))/binary, $., (integer_to_binary(Ip2))/binary, $., (integer_to_binary(Ip3))/binary>>.
|
||||||
|
|
||||||
|
-spec ips(NetAddr :: binary(), MaskLen :: integer()) -> [Ip :: integer()].
|
||||||
|
ips(NetAddr, MaskLen) when is_binary(NetAddr), is_integer(MaskLen) ->
|
||||||
|
Mask = 16#FFFFFFFF bsr MaskLen,
|
||||||
|
Net0 = ipv4_to_int(NetAddr),
|
||||||
|
%% 防止网络地址给得不对,比如: "192.168.1.101",
|
||||||
|
L = 32 - MaskLen,
|
||||||
|
Net = (Net0 bsr L) bsl L,
|
||||||
|
lists:map(fun(V) -> Net + V end, lists:seq(1, Mask - 1)).
|
||||||
|
|
||||||
|
-spec ipv6_bytes_to_binary(Bytes :: binary()) -> Bin :: binary().
|
||||||
|
ipv6_bytes_to_binary(<<A:16, B:16, C:16, D:16, E:16, F:16, G:16, H:16>>) ->
|
||||||
|
Segments = [integer_to_list(X, 16) || X <- [A, B, C, D, E, F, G, H]],
|
||||||
|
% 填充每个段以确保是4位
|
||||||
|
Padded = [string:pad(S, 4, leading, $0) || S <- Segments],
|
||||||
|
% 合并成IPv6地址格式,这里没有处理最简化形式的缩写
|
||||||
|
iolist_to_binary(lists:flatten(string:join(Padded, ":")));
|
||||||
|
ipv6_bytes_to_binary(_) ->
|
||||||
|
<<"">>.
|
||||||
Loading…
x
Reference in New Issue
Block a user