-module(pf_route_macos_SUITE).
-compile(export_all).
-compile(nowarn_export_all).
-include_lib("pf_route/src/pf_route.hrl").
-include_lib("pf_route/src/pf_route_macos.hrl").
-include_lib("stdlib/include/assert.hrl").
suite() ->
[{timetrap, 10000}].
all() ->
[{group, pf_route_parser}, {group, netstat_parser}].
groups() ->
[{pf_route_parser, [parallel], pf_route_parser_tests()}, {netstat_parser, [parallel], netstat_parser_tests()}].
init_per_group(_Group, Config) ->
Config.
end_per_group(_, _) ->
ok.
%% Netstat
netstat_parser_tests() ->
[netstat_list].
netstat_list(_) ->
{skip, todo}.
%% Packet
pf_route_parser_tests() ->
[pckt_rt_add, pckt_rt_add_error, pckt_rt_add_expire, pckt_rt_delete, pckt_rt_delete_2, pckt_rt_get, pckt_rt_get_default, pckt_rt_ifinfo, pckt_rt_deladdr].
%% Result of `route add 192.168.3.0/24 8.8.8.8`.
pckt_rt_add(_) ->
ct:comment("RT_ADD"),
Binary = <<5,1,0,0,0,0,67,8,0,0,7,0,0,0,21,130,0,0,1,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,2,0,0,
192,168,3,0,0,0,0,0,0,0,0,0,16,2,0,0,8,8,8,8,0,0,0,0,0,0,0,0,7,2
,0,0,255,255,255,0>>,
{ok, Rt} = pf_route_macos:parse_pf_route_packet(Binary),
#macos_rt{} = Rt,
?assertEqual(add, Rt#macos_rt.type),
?assertEqual([up, gateway, done, static], Rt#macos_rt.flags),
?assertEqual([destination, gateway, netmask], Rt#macos_rt.addrs),
?assertEqual(33301, Rt#macos_rt.pid),
?assertEqual(1, Rt#macos_rt.seq),
?assertEqual(0, Rt#macos_rt.errno),
?assertEqual(0, Rt#macos_rt.expire),
?assertEqual({0, 0, 0}, Rt#macos_rt.filler),
?assertEqual(#pf_route_inet4{address = {192, 168, 3, 0}}, Rt#macos_rt.destination),
?assertEqual(#pf_route_inet4{address = {8, 8, 8, 8}}, Rt#macos_rt.gateway),
?assertEqual(#pf_route_inet4{address = {255, 255, 255, 0}}, Rt#macos_rt.netmask),
?assertEqual(undefined, Rt#macos_rt.ifp),
?assertEqual(0, Rt#macos_rt.ifp_index),
?assertEqual(undefined, Rt#macos_rt.ifa),
?assertEqual(undefined, Rt#macos_rt.author),
?assertEqual(undefined, Rt#macos_rt.brd).
pckt_rt_add_error(_) ->
ct:comment("RT_ADD with error (already existing)"),
Binary = <<5,1,0,0,0,0,3,8,0,0,7,0,0,0,99,228,0,0,1,0,0,0,17,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,2,0,
0,192,168,3,0,0,0,0,0,0,0,0,0,16,2,0,0,8,8,8,8,0,0,0,0,0,0,0,0,
7,2,0,0,255,255,255,0>>,
{ok, Rt} = pf_route_macos:parse_pf_route_packet(Binary),
#macos_rt{} = Rt,
?assertEqual(17, Rt#macos_rt.errno).
pckt_rt_add_expire(_) ->
ct:comment("RT_ADD with expiry"),
Binary = <<5,1,0,0,0,0,67,8,0,0,7,0,0,0,22,231,0,0,1,0,0,0,0,0,0,0,0,0,0,0,
4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,152,122,97,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
16,2,0,0,192,168,4,0,0,0,0,0,0,0,0,0,16,2,0,0,8,8,8,8,0,0,0,0,0,
0,0,0,7,2,0,0,255,255,255,0>>,
{ok, Rt} = pf_route_macos:parse_pf_route_packet(Binary),
#macos_rt{} = Rt,
?assertEqual(1635424292, Rt#macos_rt.expire),
?assertEqual([expire], Rt#macos_rt.metrics_init).
pckt_rt_delete(_) ->
ct:comment("RT_DELETE"),
Binary = <<5,2,15,0,0,0,4,0,32,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,30,0,0,
0,0,0,0,254,128,0,15,0,0,0,0,144,241,224,255,254,211,173,11,0,0,
0,0,20,18,15,0,6,0,6,0,146,241,224,211,173,11,0,0,0,0,0,0>>,
{ok, Rt} = pf_route_macos:parse_pf_route_packet(Binary),
#macos_rt{} = Rt,
?assertEqual(delete, Rt#macos_rt.type).
pckt_rt_delete_2(_) ->
ct:comment("RT_DELETE with ifp/ifa"),
%% RTM_DELETE: Delete Route: len 164, pid: 80, seq 166, errno 0, ifscope 12, flags:<HOST,DONE,WASCLONED,BROADCAST,IFSCOPE,CONDEMNED>
%% locks: inits:
%% sockaddrs: <DST,GATEWAY,IFP,IFA>
%% 172.20.10.15 ff.ff.ff.ff.ff.ff en0:a0.78.17.af.bb.68 172.20.10.13
Binary = <<5,2,12,0,0,0,68,0,66,3,51,0,0,0,80,0,0,0,166,0,0,0,0,0,0,0,8,0,
0,0,0,0,0,0,0,0,0,0,220,5,0,0,0,0,0,0,70,51,121,97,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,16,2,0,0,172,20,10,15,0,0,0,0,0,0,0,0,20,18,12,0,6,0,6,0,
255,255,255,255,255,255,0,0,0,0,0,0,20,18,12,0,6,3,6,0,101,110,
48,160,120,23,175,187,104,0,0,0,16,2,0,0,172,20,10,13,0,0,0,0,0,
0,0,0>>,
{ok, Rt} = pf_route_macos:parse_pf_route_packet(Binary),
#macos_rt{} = Rt,
?assertEqual([host, done, wascloned, broadcast, ifscope, condemned], Rt#macos_rt.flags),
?assertEqual(12, Rt#macos_rt.ifp_index),
?assertEqual(#pf_route_inet4{address = {172,20,10,15}}, Rt#macos_rt.destination),
?assertEqual({macos_link, 12, 6, <<>>, [255, 255, 255, 255, 255, 255], <<>>}, Rt#macos_rt.gateway),
?assertEqual({macos_link, 12, 6, <<"en0">>, [160, 120, 23, 175, 187, 104], <<>>}, Rt#macos_rt.ifp),
?assertEqual(#pf_route_inet4{address = {172,20,10,13}}, Rt#macos_rt.ifa).
pckt_rt_get(_) ->
ct:comment("RT_GET for a subnet"),
%RTM_GET: Report Metrics: len 168, pid: 69344, seq 1, errno 0, flags:<UP,GATEWAY,DONE,STATIC,PRCLONING>
% locks: inits:
% sockaddrs: <DST,GATEWAY,NETMASK,IFP,IFA>
% 192.168.3.0 dns.google (255) ffff ffff ff en0:a0.78.17.af.bb.68 172.20.10.13
Binary = <<5,4,12,0,0,0,67,8,1,0,55,0,0,0,224,14,1,0,1,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,220,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,
2,0,0,192,168,3,0,0,0,0,0,0,0,0,0,16,2,0,0,8,8,8,8,0,0,0,0,0,0,
0,0,7,255,255,255,255,255,255,0,20,18,12,0,6,3,6,0,101,110,48,
160,120,23,175,187,104,0,0,0,16,2,0,0,172,20,10,13,0,0,0,0,0,0,
0,0>>,
{ok, Rt} = pf_route_macos:parse_pf_route_packet(Binary),
#macos_rt{} = Rt,
?assertEqual(#pf_route_inet4{address = {192, 168, 3, 0}}, Rt#macos_rt.destination),
?assertEqual(#pf_route_inet4{address = {8, 8, 8, 8}}, Rt#macos_rt.gateway),
?assertEqual(#pf_route_inet4{address = {255, 255, 255, 0}}, Rt#macos_rt.netmask).
pckt_rt_get_default(_) ->
ct:comment("RT_GET default"),
%% RTM_GET: Report Metrics: len 164, pid: 56835, seq 1, errno 0, flags:<UP,GATEWAY,DONE,STATIC,PRCLONING,GLOBAL>
%% locks: inits:
%% sockaddrs: <DST,GATEWAY,NETMASK,IFP,IFA>
%% default 172.20.10.1 default en0:a0.78.17.af.bb.68 172.20.10.13
Binary = <<5,4,12,0,0,0,67,8,1,64,55,0,0,0,3,222,0,0,1,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,220,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,2,0,0,172,20,10,1,12,0,0,0,0,0,
0,0,0,0,0,0,20,18,12,0,6,3,6,0,101,110,48,160,120,23,175,187,
104,0,0,0,16,2,0,0,172,20,10,13,0,0,0,0,0,0,0,0>>,
{ok, Rt} = pf_route_macos:parse_pf_route_packet(Binary),
#macos_rt{} = Rt,
?assertEqual(get, Rt#macos_rt.type),
?assertEqual([up, gateway, done, static, prcloning, global], Rt#macos_rt.flags),
?assertEqual([destination, gateway, netmask, ifp, ifa], Rt#macos_rt.addrs),
?assertEqual(1500, Rt#macos_rt.mtu),
?assertEqual(#pf_route_inet4{address = {0, 0, 0, 0}}, Rt#macos_rt.destination),
?assertEqual(#pf_route_inet4{address = {172, 20, 10, 1}}, Rt#macos_rt.gateway),
?assertEqual(#pf_route_inet4{address = {0, 0, 0, 0}}, Rt#macos_rt.netmask),
?assertEqual({macos_link, 12, 6, <<"en0">>, [160, 120, 23, 175, 187, 104], <<>>}, Rt#macos_rt.ifp),
?assertEqual(12, Rt#macos_rt.ifp_index),
?assertEqual(#pf_route_inet4{address = {172, 20, 10, 13}}, Rt#macos_rt.ifa).
pckt_rt_ifinfo(_) ->
ct:comment("RT_IFINFO (new interface)"),
%% RTM_IFINFO: iface status change: len 112, if# 22, flags:<BROADCAST,b6,RUNNING,SIMPLEX,MULTICAST>
Binary = <<5,14,0,0,0,0,35,136,0,0,22,0,0,0,6,0,0,6,14,0,0,0,220,5,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,43,121,97,
0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0>>,
{ok, If} = pf_route_macos:parse_pf_route_packet(Binary),
#macos_if{} = If,
?assertEqual([up, broadcast, notrailers, simplex, multicast], If#macos_if.flags),
?assertEqual([], If#macos_if.addrs),
?assertEqual(22, If#macos_if.index),
{skip, If}.
pckt_rt_deladdr(_) ->
ct:comment("RT_DELADDR"),
Binary = <<5,13,52,0,0,0,0,1,0,0,15,0,0,0,0,0,0,0,28,30,0,0,0,0,0,0,255,
255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,20,18,15,0,
6,4,6,0,108,108,119,48,146,241,224,211,173,11,0,0,28,30,0,0,0,0,
0,0,254,128,0,15,0,0,0,0,144,241,224,255,254,211,173,11,0,0,0,0>>,
{ok, Ifa} = pf_route_macos:parse_pf_route_packet(Binary),
#macos_ifa{} = Ifa,
?assertEqual(deleted, Ifa#macos_ifa.type),
?assertEqual([promisc], Ifa#macos_ifa.flags),
?assertEqual([netmask, ifp, ifa], Ifa#macos_ifa.addrs),
?assertEqual(15, Ifa#macos_ifa.index),
?assertEqual(0, Ifa#macos_ifa.metric),
?assertEqual(#pf_route_inet6{address = {65535,65535,65535,65535,0,0,0,0},flow = 0, scope = 0}, Ifa#macos_ifa.netmask),
?assertEqual(#macos_link{index = 15, type = 6, name = <<"llw0">>, address = [146, 241, 224, 211, 173, 11], selector = <<>>}, Ifa#macos_ifa.ifp),
?assertEqual(#pf_route_inet6{address = {33022,3840,0,0,61840,65504,54270,2989},flow = 0, scope = 0}, Ifa#macos_ifa.ifa).