-module(pf_route_freebsd). -include("pf_route.hrl"). -include("pf_route_freebsd.hrl"). -export([default_table/0, current_table/0, tables/0]). -export([list/1]). -export([monitor/1]). -export([parse_pf_route_packet/1]). default_table() -> 1. current_table() -> case os:cmd("sysctl net.my_fibnum") of [$n, $e, $t, $., $m, $y, $_, $f, $i, $n, $b, $u, $m, $:, $\s | Rest] -> {ok, list_to_integer(string:trim(Rest))}; _ -> error end. tables() -> case os:cmd("sysctl net.fibs") of [$n, $e, $t, $., $f, $i, $b, $s, $:, $\s | Rest] -> Count = list_to_integer(string:trim(Rest)), {ok, lists:seq(1, Count)}; _ -> error end. list(Table) -> case lists:member(fib:tables(), Table) of true -> do_list(Table); _ -> {error, {no_table, Table}} end. monitor(Table) -> Self = self(), OpenFun = fun (_Socket) -> {todo_set_table, Table} end, PcktFun = fun (Binary) -> Packet = parse_pf_route_packet(Binary), Self ! {pf_route_monitor, Packet} end, spawn_link(fun () -> pf_route_pf_route_socket:open(?PF_ROUTE, ?SOCK_RAW, ?AF_UNSPEC, OpenFun, PcktFun) end). parse_pf_route_packet(<>) -> parse_rt_msghdr(Binary, add); parse_pf_route_packet(<>) -> parse_rt_msghdr(Binary, delete); parse_pf_route_packet(<>) -> parse_rt_msghdr(Binary, change); parse_pf_route_packet(<>) -> parse_rt_msghdr(Binary, get); parse_pf_route_packet(<>) -> parse_rt_msghdr(Binary, losing); parse_pf_route_packet(<>) -> parse_rt_msghdr(Binary, redirect); parse_pf_route_packet(<>) -> parse_rt_msghdr(Binary, miss); parse_pf_route_packet(<>) -> parse_rt_msghdr(Binary, lock); parse_pf_route_packet(<>) -> parse_rt_msghdr(Binary, resolve); %%parse_pf_route_packet(<>) -> parse_ifa_msghdr(Binary, newaddr); %%parse_pf_route_packet(<>) -> parse_ifa_msghdr(Binary, deladdr); parse_pf_route_packet(<>) -> parse_if_msghdr(Binary, ifinfo); %%parse_pf_route_packet(<>) -> parse_ifma_msghdr(Binary, newmaddr); %%parse_pf_route_packet(<>) -> parse_if_mamsghdr(Binary, delmaddr); %%parse_pf_route_packet(<>) -> parse_ifannounce_msghdr(Binary, ifannounce); %%parse_pf_route_packet(<>) -> parse_ifannounce_msghdr(Binary, ieee80211). parse_pf_route_packet(Binary) -> {error, {invalid_packet, Binary}}. parse_rt_msghdr(<<% struct rt_msghdr (len, ver and type removed) IfpIndex:?U_SHORT, _Spare1:?U_SHORT, Flags:?INT, Addrs:?INT, Pid:?PID_T, Seq:?INT, Errno:?INT, FMask:?INT, % bitmask used in RTM_CHANGE Inits:?U_LONG, % rt_metrics Locks:?U_LONG, Mtu:?U_LONG, Hopcount:?U_LONG, Expire:?U_LONG, Recv:?U_LONG, Send:?U_LONG, Ssthresh:?U_LONG, Rtt:?U_LONG, Rttvar:?U_LONG, Pksent:?U_LONG, Weight:?U_LONG, Nhidx:?U_LONG, Filler1:?U_LONG, Filler2:?U_LONG, % List of addrs BinaryAddrs/binary >>, Type) -> Rt = #freebsd_rt{type = Type, ifp_index = IfpIndex, flags = Flags, addrs = Addrs, pid = Pid, seq = Seq, errno = Errno, fmask = FMask, metrics_init = Inits, metrics_lock = Locks, mtu = Mtu, hopcount = Hopcount, expire = Expire, recvpipe = Recv, sendpipe = Send, ssthresh = Ssthresh, rtt = Rtt, rttvar = Rttvar, pksent = Pksent, weight = Weight, nhidx = Nhidx, filler = {Filler1, Filler2}}, parse_rt(Rt, BinaryAddrs). parse_rt(Rt0, BinaryAddrs) -> Rt1 = Rt0#freebsd_rt{flags = pf_route_util:read_bitmask(?RTF, Rt0#freebsd_rt.flags), addrs = pf_route_util:read_bitmask(?RTA, Rt0#freebsd_rt.addrs), metrics_init = pf_route_util:read_bitmask(?RTV, Rt0#freebsd_rt.metrics_init), metrics_lock = pf_route_util:read_bitmask(?RTV, Rt0#freebsd_rt.metrics_lock)}, logger:warning("pf_route_freebsd:monitor Rt = ~p~nBinary: ~p", [Rt1, BinaryAddrs]), Rt = get_addrs(BinaryAddrs, Rt1#freebsd_rt.addrs, Rt1), logger:warning("pf_route_freebsd:monitor Rt = ~p", [Rt]), Rt. get_addrs(<>, [Type | Rest], Rt) -> <> = Content, get_addrs(Binary, Rest, set_rt_addr(Type, process_address(BinaryAddr, Family), Rt)); get_addrs(_, [], Rt) -> Rt. set_rt_addr(destination, Value, Rt) -> Rt#freebsd_rt{destination = Value}; set_rt_addr(gateway, Value, Rt) -> Rt#freebsd_rt{gateway = Value}; set_rt_addr(netmask, Value, Rt) -> Rt#freebsd_rt{netmask = Value}; set_rt_addr(ifp, Value, Rt) -> Rt#freebsd_rt{ifp = Value}; set_rt_addr(ifa, Value, Rt) -> Rt#freebsd_rt{ifa = Value}; set_rt_addr(author, Value, Rt) -> Rt#freebsd_rt{author = Value}; set_rt_addr(brd, Value, Rt) -> Rt#freebsd_rt{brd = Value}. process_address(<<_Port:?U_SHORT, A, B, C, D, _Zero:64/little-unsigned-integer>>, ?AF_INET) -> {A, B, C, D}; process_address(<>, ?AF_LINK) -> <> = Data, Link = #freebsd_link{index = Index, type = Type, name = Name, address = binary_to_list(Address), selector = Selector}, Link; process_address(Data, Family) -> logger:error("freebsd:process_address: no clause for family ~p = ~p", [Family, Data]), {sockaddr, Family, Data}. parse_if_msghdr(<<% if_msghdr Addrs:?INT, Flags:?INT, Index:?U_SHORT, _Spare1:?U_SHORT, % if_data Type:?UINT8, Physical:?UINT8, AddrLen:?UINT8, HdrLen:?UINT8, Linkstate:?UINT8, Vhid:?UINT8, DataLen:?UINT16, Mtu:?UINT32, Metric:?UINT32, Baudrate:?UINT64, IPackets:?UINT64, IErrors:?UINT64, OPackets:?UINT64, OErrors:?UINT64, Collisions:?UINT64, IBytes:?UINT64, OBytes:?UINT64, IMcasts:?UINT64, OMcasts:?UINT64, IQdrops:?UINT64, OQdrops:?UINT64, Noproto:?UINT64, Hwassist:?UINT64, Data/binary>>, ifinfo) -> If = #freebsd_if{addrs = pf_route_util:read_bitmask(?RTA, Addrs), flags = pf_route_util:read_bitmask(?IFF, Flags), index = Index, type = Type, physical = Physical, addrlen = AddrLen,hdrlen = HdrLen, linkstate = maps:get(Linkstate, ?LINK_STATE), vhid = Vhid,datalen = DataLen,mtu = Mtu,metric = Metric, baudrate = Baudrate, ipackets = IPackets,ierrors = IErrors,opackets = OPackets,oerrors = OErrors,collisions = Collisions, ibytes = IBytes,obytes = OBytes,imcasts = IMcasts,omcasts = OMcasts,iqdrops = IQdrops, oqdrops = OQdrops,noproto = Noproto,hwassist = Hwassist}, logger:warning("pf_route_freebsd: freebsd_if: ~p~nBinary: ~p", [If, Data]), If. do_list(Table) -> os:cmd(["setfib ", Table, " netstat -rn"]).