隔离出udp包的处理逻辑

This commit is contained in:
anlicheng 2026-01-23 14:55:15 +08:00
parent ce69bfd730
commit c1f196fa96

View File

@ -100,77 +100,11 @@ handle_cast({stun_relay, Ip, Port, Reply}, State = #state{socket = Sock}) ->
{noreply, NewState :: #state{}} |
{noreply, NewState :: #state{}, timeout() | hibernate} |
{stop, Reason :: term(), NewState :: #state{}}).
handle_info({udp, Sock, Ip, Port, <<?PACKET_STUN_REQUEST:8, Body/binary>>}, State = #state{socket = Sock}) ->
#sdl_stun_request{cookie = Cookie, client_id = ClientId, network_id = NetworkId, mac = Mac, nat_type = NatType, v6_info = V6Info} = sdlan_pb:decode_msg(Body, sdl_stun_request),
%% ip对应的nat的映射关系
case sdlan_network:get_pid(NetworkId) of
undefined ->
logger:debug("[sdlan_stun] stun_request network_id: ~p, client_id: ~p, not found", [NetworkId, ClientId]),
{noreply, State};
NetworkPid when is_pid(NetworkPid) ->
sdlan_network:update_hole(NetworkPid, ClientId, Mac, {Ip, Port}, NatType, V6Info),
StunReply = sdlan_pb:encode_msg(#sdl_stun_reply{
cookie = Cookie
}),
ok = gen_udp:send(Sock, Ip, Port, <<?PACKET_STUN_REPLY, StunReply/binary>>),
logger:debug("[sdlan_stun] stun_request network_id: ~p, client_id: ~p, hole: ~p", [NetworkId, ClientId, {Ip, Port}]),
{noreply, State}
end;
%% nat类型的探测机制,
%% assist的配置attr = 2
handle_info({udp, Sock, Ip, Port, <<?PACKET_STUN_PROBE:8, Body/binary>>}, State = #state{socket = Sock}) ->
#sdl_stun_probe{cookie = Cookie, attr = Attr} = sdlan_pb:decode_msg(Body, sdl_stun_probe),
logger:debug("[sdlan_stun] get stun_probe request, att: ~p", [Attr]),
ProbeReply = sdlan_pb:encode_msg(#sdl_stun_probe_reply {
cookie = Cookie,
port = Port,
ip = int_ip(Ip)
}),
Packet = <<?PACKET_STUN_PROBE_REPLY, ProbeReply/binary>>,
case Attr of
?STUN_ATTR_CHANGE_NONE ->
ok = gen_udp:send(Sock, Ip, Port, Packet);
?STUN_ATTR_CHANGE_PORT ->
sdlan_stun_port_assist:stun_relay(Ip, Port, Packet);
?STUN_ATTR_CHANGE_PEER ->
sdlan_stun_peer_assist:stun_relay(Ip, Port, Packet)
end,
handle_info({udp, Sock, Ip, Port, Packet}, State = #state{socket = Sock}) ->
catch handle_packet(Sock, Ip, Port, Packet),
{noreply, State};
%% , stun_reply的转发通过socket来转发
handle_info({udp, Sock, _, _, <<?PACKET_STUN_PROBE_RELAY:8, Ip0, Ip1, Ip2, Ip3, Port:16, Reply/binary>>}, State = #state{socket = Sock}) ->
logger:debug("[sdlan_stun] get stun_probe_replay request, reply: ~p", [Reply]),
gen_udp:send(Sock, {Ip0, Ip1, Ip2, Ip3}, Port, Reply),
{noreply, State};
handle_info({udp, _, _Ip, _Port, <<?PACKET_STUN_DATA, Body/binary>>}, State = #state{socket = Sock}) ->
Data = #sdl_data{network_id = NetworkId, src_mac = SrcMac, dst_mac = DstMac, ttl = TTL} = sdlan_pb:decode_msg(Body, sdl_data),
logger:debug("[sdlan_stun] stun data, src_mac: ~p, dst_mac: ~p", [sdlan_util:format_mac(SrcMac), sdlan_util:format_mac(DstMac)]),
maybe
{ok, NetworkPid} ?= sdlan_network:lookup_pid(NetworkId),
%% ttl需要减1
NData = sdlan_pb:encode_msg(Data#sdl_data{ttl = TTL - 1, is_p2p = false}),
sdlan_network:forward(NetworkPid, Sock, SrcMac, DstMac, <<?PACKET_STUN_DATA, NData/binary>>)
end,
{noreply, State};
handle_info({udp, _, Ip, Port, <<?PACKET_ARP_REQUEST, Body/binary>>}, State = #state{socket = Sock}) ->
#sdl_arp_request{network_id = NetworkId, target_ip = TargetIp} = sdlan_pb:decode_msg(Body, sdl_arp_request),
logger:debug("[sdlan_stun] stun sdl_arp_request, network_id: ~p, target_ip: ~p", [NetworkId, TargetIp]),
maybe
{ok, NetworkPid} ?= sdlan_network:lookup_pid(NetworkId),
{ok, TargetMac} ?= sdlan_network:arp_query(NetworkPid, TargetIp),
ArpResponse = sdlan_pb:encode_msg(#sdl_arp_response{network_id = NetworkId, target_ip = TargetIp, target_mac = TargetMac}),
ok ?= gen_udp:send(Sock, Ip, Port, ArpResponse)
end,
{noreply, State};
handle_info({udp_error , Sock, Reason}, State = #state{socket = Sock}) ->
{stop, Reason, State};
handle_info(Info, State) ->
logger:error("[sdlan_stun] get a unknown message: ~p, channel will closed", [Info]),
{noreply, State}.
@ -197,6 +131,70 @@ code_change(_OldVsn, State = #state{}, _Extra) ->
%%% Internal functions
%%%===================================================================
-spec handle_packet(Sock :: inet:socket(), Ip :: inet:ip4_address(), Port :: integer(), Packet :: binary()) -> no_return().
handle_packet(Sock, Ip, Port, <<?PACKET_STUN_REQUEST:8, Body/binary>>) ->
#sdl_stun_request{cookie = Cookie, client_id = ClientId, network_id = NetworkId, mac = Mac, nat_type = NatType, v6_info = V6Info} = sdlan_pb:decode_msg(Body, sdl_stun_request),
%% ip对应的nat的映射关系
case sdlan_network:get_pid(NetworkId) of
undefined ->
logger:debug("[sdlan_stun] stun_request network_id: ~p, client_id: ~p, not found", [NetworkId, ClientId]),
ok;
NetworkPid when is_pid(NetworkPid) ->
sdlan_network:update_hole(NetworkPid, ClientId, Mac, {Ip, Port}, NatType, V6Info),
StunReply = sdlan_pb:encode_msg(#sdl_stun_reply{
cookie = Cookie
}),
ok = gen_udp:send(Sock, Ip, Port, <<?PACKET_STUN_REPLY, StunReply/binary>>),
logger:debug("[sdlan_stun] stun_request network_id: ~p, client_id: ~p, hole: ~p", [NetworkId, ClientId, {Ip, Port}])
end;
%% nat类型的探测机制,
%% assist的配置attr = 2
handle_packet(Sock, Ip, Port, <<?PACKET_STUN_PROBE:8, Body/binary>>) ->
#sdl_stun_probe{cookie = Cookie, attr = Attr} = sdlan_pb:decode_msg(Body, sdl_stun_probe),
logger:debug("[sdlan_stun] get stun_probe request, att: ~p", [Attr]),
ProbeReply = sdlan_pb:encode_msg(#sdl_stun_probe_reply {
cookie = Cookie,
port = Port,
ip = int_ip(Ip)
}),
Packet = <<?PACKET_STUN_PROBE_REPLY, ProbeReply/binary>>,
case Attr of
?STUN_ATTR_CHANGE_NONE ->
ok = gen_udp:send(Sock, Ip, Port, Packet);
?STUN_ATTR_CHANGE_PORT ->
sdlan_stun_port_assist:stun_relay(Ip, Port, Packet);
?STUN_ATTR_CHANGE_PEER ->
sdlan_stun_peer_assist:stun_relay(Ip, Port, Packet)
end;
%% , stun_reply的转发通过socket来转发
handle_packet(Sock, _, _, <<?PACKET_STUN_PROBE_RELAY:8, Ip0, Ip1, Ip2, Ip3, Port:16, Reply/binary>>) ->
logger:debug("[sdlan_stun] get stun_probe_replay request, reply: ~p", [Reply]),
gen_udp:send(Sock, {Ip0, Ip1, Ip2, Ip3}, Port, Reply);
handle_packet(Sock, _Ip, _Port, <<?PACKET_STUN_DATA, Body/binary>>) ->
Data = #sdl_data{network_id = NetworkId, src_mac = SrcMac, dst_mac = DstMac, ttl = TTL} = sdlan_pb:decode_msg(Body, sdl_data),
logger:debug("[sdlan_stun] stun data, src_mac: ~p, dst_mac: ~p", [sdlan_util:format_mac(SrcMac), sdlan_util:format_mac(DstMac)]),
maybe
{ok, NetworkPid} ?= sdlan_network:lookup_pid(NetworkId),
%% ttl需要减1
NData = sdlan_pb:encode_msg(Data#sdl_data{ttl = TTL - 1, is_p2p = false}),
sdlan_network:forward(NetworkPid, Sock, SrcMac, DstMac, <<?PACKET_STUN_DATA, NData/binary>>)
end;
handle_packet(Sock, Ip, Port, <<?PACKET_ARP_REQUEST, Body/binary>>) ->
#sdl_arp_request{network_id = NetworkId, target_ip = TargetIp} = sdlan_pb:decode_msg(Body, sdl_arp_request),
logger:debug("[sdlan_stun] stun sdl_arp_request, network_id: ~p, target_ip: ~p", [NetworkId, TargetIp]),
maybe
{ok, NetworkPid} ?= sdlan_network:lookup_pid(NetworkId),
{ok, TargetMac} ?= sdlan_network:arp_query(NetworkPid, TargetIp),
ArpResponse = sdlan_pb:encode_msg(#sdl_arp_response{network_id = NetworkId, target_ip = TargetIp, target_mac = TargetMac}),
ok ?= gen_udp:send(Sock, Ip, Port, ArpResponse)
end.
-spec int_ip(tuple()) -> integer().
int_ip({Ip0, Ip1, Ip2, Ip3}) ->
<<Ip:32>> = <<Ip0, Ip1, Ip2, Ip3>>,