diff options
Diffstat (limited to 'src/pf_route_freebsd.erl')
-rw-r--r-- | src/pf_route_freebsd.erl | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/src/pf_route_freebsd.erl b/src/pf_route_freebsd.erl new file mode 100644 index 0000000..871211c --- /dev/null +++ b/src/pf_route_freebsd.erl @@ -0,0 +1,179 @@ +-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(<<?RTM_VERSION:?U_CHAR, ?RTM_ADD:?U_CHAR, Binary/binary>>) -> parse_rt_msghdr(Binary, add); +parse_pf_route_packet(<<?RTM_VERSION:?U_CHAR, ?RTM_DELETE:?U_CHAR, Binary/binary>>) -> parse_rt_msghdr(Binary, delete); +parse_pf_route_packet(<<?RTM_VERSION:?U_CHAR, ?RTM_CHANGE:?U_CHAR, Binary/binary>>) -> parse_rt_msghdr(Binary, change); +parse_pf_route_packet(<<?RTM_VERSION:?U_CHAR, ?RTM_GET:?U_CHAR, Binary/binary>>) -> parse_rt_msghdr(Binary, get); +parse_pf_route_packet(<<?RTM_VERSION:?U_CHAR, ?RTM_LOSING:?U_CHAR, Binary/binary>>) -> parse_rt_msghdr(Binary, losing); +parse_pf_route_packet(<<?RTM_VERSION:?U_CHAR, ?RTM_REDIRECT:?U_CHAR, Binary/binary>>) -> parse_rt_msghdr(Binary, redirect); +parse_pf_route_packet(<<?RTM_VERSION:?U_CHAR, ?RTM_MISS:?U_CHAR, Binary/binary>>) -> parse_rt_msghdr(Binary, miss); +parse_pf_route_packet(<<?RTM_VERSION:?U_CHAR, ?RTM_LOCK:?U_CHAR, Binary/binary>>) -> parse_rt_msghdr(Binary, lock); +parse_pf_route_packet(<<?RTM_VERSION:?U_CHAR, ?RTM_RESOLVE:?U_CHAR, Binary/binary>>) -> parse_rt_msghdr(Binary, resolve); +%%parse_pf_route_packet(<<?RTM_VERSION:?U_CHAR, ?RTM_NEWADDR:?U_CHAR, Binary/binary>>) -> parse_ifa_msghdr(Binary, newaddr); +%%parse_pf_route_packet(<<?RTM_VERSION:?U_CHAR, ?RTM_DELADDR:?U_CHAR, Binary/binary>>) -> parse_ifa_msghdr(Binary, deladdr); +parse_pf_route_packet(<<?RTM_VERSION:?U_CHAR, ?RTM_IFINFO:?U_CHAR, Binary/binary>>) -> parse_if_msghdr(Binary, ifinfo); +%%parse_pf_route_packet(<<?RTM_VERSION:?U_CHAR, ?RTM_NEWMADDR:?U_CHAR, Binary/binary>>) -> parse_ifma_msghdr(Binary, newmaddr); +%%parse_pf_route_packet(<<?RTM_VERSION:?U_CHAR, ?RTM_DELMADDR:?U_CHAR, Binary/binary>>) -> parse_if_mamsghdr(Binary, delmaddr); +%%parse_pf_route_packet(<<?RTM_VERSION:?U_CHAR, ?RTM_IFANNOUNCE:?U_CHAR, Binary/binary>>) -> parse_ifannounce_msghdr(Binary, ifannounce); +%%parse_pf_route_packet(<<?RTM_VERSION:?U_CHAR, ?RTM_IEEE80211:?U_CHAR, Binary/binary>>) -> 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(<<Len:?U_CHAR, Family:?U_CHAR, Content/binary>>, [Type | Rest], Rt) -> + <<BinaryAddr:(Len - 2)/binary, Binary/binary>> = 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(<<Index:?U_SHORT, Type:?U_CHAR, NameLen:?U_CHAR, AddrLen:?U_CHAR, SelLen:?U_CHAR, Data/binary>>, ?AF_LINK) -> + <<Name:NameLen/binary, Address:AddrLen/binary, Selector:SelLen/binary, _Rest/binary>> = 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"]). |