support arp request
This commit is contained in:
parent
b009a324bd
commit
92a5998868
@ -60,6 +60,10 @@
|
||||
%% 欢迎消息
|
||||
-define(PACKET_WELCOME, 16#4F).
|
||||
|
||||
%% ARP查询
|
||||
-define(PACKET_ARP_REQUEST, 16#50).
|
||||
-define(PACKET_ARP_RESPONSE, 16#51).
|
||||
|
||||
%% 数据转发
|
||||
-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)),
|
||||
|
||||
MacBinStr = sdlan_util:format_mac(Mac),
|
||||
IpAddr = sdlan_ipaddr:int_to_ipv4(Ip),
|
||||
IpAddr = sdlan_util:int_to_ipv4(Ip),
|
||||
Params = #{
|
||||
<<"network_id">> => NetworkId,
|
||||
<<"client_id">> => ClientId,
|
||||
@ -251,6 +251,28 @@ handle_event(internal, {frame, <<?PACKET_QUERY_INFO, Body/binary>>}, registered,
|
||||
keep_state_and_data
|
||||
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) ->
|
||||
maybe
|
||||
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
|
||||
-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([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) ->
|
||||
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().
|
||||
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}).
|
||||
@ -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}) ->
|
||||
%% 分配ip地址的时候,以mac地址为唯一基准
|
||||
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的映射关系
|
||||
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),
|
||||
RegisterEvent = sdlan_pb:encode_msg(#sdl_send_register_event {
|
||||
dst_mac = SrcMac,
|
||||
nat_ip = sdlan_ipaddr:ipv4_to_int(SrcNatIp),
|
||||
nat_ip = sdlan_util:ipv4_to_int(SrcNatIp),
|
||||
nat_type = SrcNatType,
|
||||
nat_port = SrcNatPort,
|
||||
v6_info = SrcV6Info
|
||||
@ -258,6 +262,15 @@ handle_call({peer_info, SrcMac, DstMac}, _From, State = #state{endpoints = Endpo
|
||||
{reply, error, State}
|
||||
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}) ->
|
||||
Reply = #{
|
||||
<<"network_id">> => NetworkId,
|
||||
@ -467,7 +480,7 @@ format_endpoint({Mac, #endpoint{client_id = ClientId, ip = Ip, hole = #hole{peer
|
||||
#{
|
||||
client_id => ClientId,
|
||||
mac => sdlan_util:format_mac(Mac),
|
||||
ip => sdlan_ipaddr:int_to_ipv4(Ip),
|
||||
ip => sdlan_util:int_to_ipv4(Ip),
|
||||
hole_map => HoleMap,
|
||||
v6_info => V6InfoMap
|
||||
}.
|
||||
|
||||
@ -13,6 +13,8 @@
|
||||
-export([rand_byte/1, md5/1, format_mac/1, assert_call/2]).
|
||||
-export([json_data/1, json_error/2]).
|
||||
-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().
|
||||
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().
|
||||
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