aboutsummaryrefslogtreecommitdiff
path: root/src/pf_route_freebsd.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/pf_route_freebsd.erl')
-rw-r--r--src/pf_route_freebsd.erl179
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"]).