增加网络基础包的解析

This commit is contained in:
anlicheng 2026-01-14 17:37:14 +08:00
parent 8d94244689
commit d7db914e88
2 changed files with 241 additions and 0 deletions

View File

@ -0,0 +1,153 @@
%%%-------------------------------------------------------------------
%%% @doc ARP packet parser / builder (Ethernet + IPv4)
%%%-------------------------------------------------------------------
-module(arp_packet).
-export([parse/1, marshal/1, is_broadcast_mac/1, arp_request/3, arp_response/3]).
-define(ARP_REQUEST, 1).
-define(ARP_RESPONSE, 2).
-define(ETHERNET, 16#0001).
-define(IPV4, 16#0800).
-define(BROADCAST_MAC, <<255,255,255,255,255,255>>).
-record(arp_packet, {
hardware_type,
protocol_type,
hardware_size,
protocol_size,
opcode,
sender_mac,
sender_ip,
target_mac,
target_ip
}).
%%--------------------------------------------------------------------
%% Parsing
%%--------------------------------------------------------------------
-spec parse(binary()) ->
{ok, #arp_packet{}} | {error, invalid_length | invalid_opcode}.
parse(Bin) when is_binary(Bin) ->
case Bin of
<<
HType:16/big,
PType:16/big,
HLen:8,
PLen:8,
Op:16/big,
SMac:6/binary,
SIP:32/big,
TMac:6/binary,
TIP:32/big,
_/binary
>> ->
case decode_opcode(Op) of
{ok, Opcode} ->
{ok, #arp_packet{
hardware_type = HType,
protocol_type = PType,
hardware_size = HLen,
protocol_size = PLen,
opcode = Opcode,
sender_mac = SMac,
sender_ip = SIP,
target_mac = TMac,
target_ip = TIP
}};
error ->
{error, invalid_opcode}
end;
_ ->
{error, invalid_length}
end.
%%--------------------------------------------------------------------
%% Marshal
%%--------------------------------------------------------------------
-spec marshal(#arp_packet{}) -> binary().
marshal(#arp_packet{
hardware_type = HType,
protocol_type = PType,
hardware_size = HLen,
protocol_size = PLen,
opcode = Opcode,
sender_mac = SMac,
sender_ip = SIP,
target_mac = TMac,
target_ip = TIP
}) ->
Op = encode_opcode(Opcode),
<<
HType:16/big,
PType:16/big,
HLen:8,
PLen:8,
Op:16/big,
SMac/binary,
SIP:32/big,
TMac/binary,
TIP:32/big
>>.
%%--------------------------------------------------------------------
%% Opcode helpers
%%--------------------------------------------------------------------
decode_opcode(?ARP_REQUEST) -> {ok, request};
decode_opcode(?ARP_RESPONSE) -> {ok, response};
decode_opcode(_) -> error.
encode_opcode(request) -> ?ARP_REQUEST;
encode_opcode(response) -> ?ARP_RESPONSE.
%%--------------------------------------------------------------------
%% Utils
%%--------------------------------------------------------------------
-spec is_broadcast_mac(binary()) -> boolean().
is_broadcast_mac(?BROADCAST_MAC) -> true;
is_broadcast_mac(_) -> false.
%%--------------------------------------------------------------------
%% Builders ( Swift )
%%--------------------------------------------------------------------
-spec arp_request(integer(), binary(), integer()) -> #arp_packet{}.
arp_request(SenderIP, SenderMAC, TargetIP) ->
#arp_packet{
hardware_type = ?ETHERNET,
protocol_type = ?IPV4,
hardware_size = 6,
protocol_size = 4,
opcode = request,
sender_mac = SenderMAC,
sender_ip = SenderIP,
target_mac = <<0,0,0,0,0,0>>,
target_ip = TargetIP
}.
-spec arp_response(#arp_packet{}, binary(), integer()) -> #arp_packet{}.
arp_response(#arp_packet{
hardware_type = HType,
protocol_type = PType,
hardware_size = HLen,
protocol_size = PLen,
sender_mac = ReqMac,
sender_ip = ReqIP
}, Mac, IP) ->
#arp_packet{
hardware_type = HType,
protocol_type = PType,
hardware_size = HLen,
protocol_size = PLen,
opcode = response,
sender_mac = Mac,
sender_ip = IP,
target_mac = ReqMac,
target_ip = ReqIP
}.

View File

@ -0,0 +1,88 @@
%%%-------------------------------------------------------------------
%%% @doc Ethernet II layer packet parser
%%%-------------------------------------------------------------------
-module(layer_packet).
-export([parse/1, marshal/1, is_broadcast_mac/1, is_multicast_mac/1]).
-define(ETH_ARP, 16#0806).
-define(ETH_IPV4, 16#0800).
-define(ETH_IPV6, 16#86DD).
-define(ETH_VLAN, 16#8100).
-record(layer_packet, {
dst_mac,
src_mac,
type,
payload
}).
%%--------------------------------------------------------------------
%% API
%%--------------------------------------------------------------------
-spec parse(binary()) -> {ok, #layer_packet{}} | {error, invalid_length | invalid_type}.
parse(Bin) when is_binary(Bin) ->
case Bin of
<<Dst:6/binary, Src:6/binary, Type:16, Payload/binary>> ->
case decode_type(Type) of
{ok, T} ->
{ok, #layer_packet{
dst_mac = Dst,
src_mac = Src,
type = T,
payload = Payload
}};
error ->
{error, invalid_type}
end;
_ ->
{error, invalid_length}
end.
%%--------------------------------------------------------------------
-spec marshal(#layer_packet{}) -> binary().
marshal(#layer_packet{dst_mac = Dst, src_mac = Src, type = Type, payload = Payload}) ->
TypeBin = encode_type(Type),
<<Dst/binary, Src/binary, TypeBin:16, Payload/binary>>.
%%--------------------------------------------------------------------
%% EtherType mapping
%%--------------------------------------------------------------------
decode_type(?ETH_ARP) ->
{ok, arp};
decode_type(?ETH_IPV4) ->
{ok, ipv4};
decode_type(?ETH_IPV6) ->
{ok, ipv6};
decode_type(?ETH_VLAN) ->
{ok, tagged_frame};
decode_type(_) ->
error.
encode_type(arp) ->
?ETH_ARP;
encode_type(ipv4) ->
?ETH_IPV4;
encode_type(ipv6) ->
?ETH_IPV6;
encode_type(tagged_frame) ->
?ETH_VLAN.
%%--------------------------------------------------------------------
%% MAC helpers ( Swift MacAddress)
%%--------------------------------------------------------------------
-spec is_broadcast_mac(binary()) -> boolean().
is_broadcast_mac(<<255,255,255,255,255,255>>) ->
true;
is_broadcast_mac(_) ->
false.
-spec is_multicast_mac(binary()) -> boolean().
is_multicast_mac(<<1,0,94,_/binary>>) ->
true;
is_multicast_mac(_) ->
false.