Skip to content
Permalink
Browse files

ioc2rpz is a place where threat intelligence meets DNS

  • Loading branch information...
Homas committed Jul 24, 2019
1 parent 9926b18 commit 79ea1fa3fa2424e795d13045a255a622640924a6
Showing with 55 additions and 16 deletions.
  1. +4 −1 ChangeLog.md
  2. +1 −1 include/ioc2rpz.hrl
  3. +2 −2 src/ioc2rpz.erl
  4. +48 −12 src/ioc2rpz_rest.erl
@@ -1,5 +1,8 @@
# ioc2rpz change log
[CB] - Changed Behaviour
## 2019-07-21 v1.0.0.1
- RPZ statistics collected: # rules and # indicators

## 2019-07-21 v1.0.0.0
- Released v1.0.0.0

@@ -11,7 +14,7 @@

## 2019-06-13 v0.9.4.0
- Fixed bugs:
- #10
- #10 "redirect_domain add zone name"
- live zones, wrong records count in the hot cache
- Rule generation code was optimized
- Configuration can be split by multiple files using "include"
@@ -46,7 +46,7 @@
%%%%%%
%%%%%% Do not modify any settings below the line
%%%%%%
-define(ioc2rpz_ver, "1.0.0.0-2019072101").
-define(ioc2rpz_ver, "1.0.0.1-2019072201").

-define(ZNameZip,16#c00c:16). %Zone name/original fqdn from a request is always at byte 10 in the response
-define(ZNameZipN,16#c00c). % Offset in bytes - Zone name/original fqdn from a request is always at byte 10 in the response
@@ -660,7 +660,7 @@ send_zone(<<"true">>,Socket,{Questions,DNSId,OptB,OptE,RH,Rest,Zone,?T_IXFR,NSSe
T_ZIP_L=init_T_ZIP_L(Zone),
%В момент переключения на добавления - SOARECCL обнуляем, таким образом отслеживаем, что мы добавили новую SOA
{ok, NRules, NIOCs}=send_packets(Socket,IOCexp ++ IOCnew, [], 0, 0, true, [DNSId, <<1:1, OptB:7, 1:1, OptE:3, ?NOERROR:4, 1:16>>], Questions, SOAREC,SOARECCL,Zone,MP,PktHLen,T_ZIP_L,TSIG,0,ixfr,0,false,Proto),
ioc2rpz_fun:logMessage("Zone ~p, # of rules ~p, # of IOCs ~p ~n", [Zone#rpz.zone_str, NRules, NIOCs]),
ioc2rpz_fun:logMessage("Zone ~p, ~p rules, ~p IOCs ~n", [Zone#rpz.zone_str, NRules, NIOCs]),
ets:delete(T_ZIP_L),
ok;

@@ -698,7 +698,7 @@ send_zone_live(Socket,Op,Zone,PktH,Questions, SOAREC,NSRec,TSIG,Proto) ->
ioc2rpz_db:delete_old_db_record(Zone),
T_ZIP_L=init_T_ZIP_L(Zone),
{ok, NRules, NIOCs}=send_packets(Socket,IOC, [], 0, 0, true, PktH, Questions, SOAREC,NSRec,Zone,MP,PktHLen,T_ZIP_L,TSIG,0,Op,0,true,Proto),
ioc2rpz_fun:logMessage("Live zone ~p, # of rules ~p, # of IOCs ~p ~n", [Zone#rpz.zone_str, NRules, NIOCs]),
ioc2rpz_fun:logMessage("Live zone ~p, ~p rules, ~p IOCs ~n", [Zone#rpz.zone_str, NRules, NIOCs]),
ets:delete(T_ZIP_L),
{ok,MD5, NRules, NIOCs}
end.
@@ -131,32 +131,29 @@ srv_mgmt(Req, State, Format) when State#state.op == terminate -> %Shutdown serve
srv_mgmt(Req, State, Format) when State#state.op == stats_serv -> % Statistics -- TODO
#{peer := {IP, Port}} = Req,
ioc2rpz_fun:logMessageCEF(ioc2rpz_fun:msg_CEF(230),[ioc2rpz:ip_to_str(IP), Port, cowboy_req:path(Req), ""]),
Srv_rules = lists:sum(([ X#rpz.rule_count || [X] <- ets:match(cfg_table,{[rpz,'_'],'_','$2'}), X#rpz.rule_count /= undefined])),
RPZ_stat = [ {X#rpz.zone_str,X#rpz.rule_count} || [X] <- ets:match(cfg_table,{[rpz,'_'],'_','$2'}), X#rpz.rule_count /= undefined],
Sources_stat = [ {X#source.name,X#source.ioc_count} || [X] <- ets:match(cfg_table,{[source,'_'],'$2'}), X#source.ioc_count /= undefined],
% io_lib:format("[~s]",[list_tuples_to_json([],Array)])
Body=case Format of
txt -> io_lib:format("Srv total RPZ rules: ~p\nRPZ:\n ~p\nSources:\n ~p\n",[Srv_rules,RPZ_stat,Sources_stat]);
json -> io_lib:format("{\"srv_total_rules\":~p,\"rpz\":~s,\"sources\":~s}\n",[Srv_rules,list_tuples_to_json(RPZ_stat),list_tuples_to_json(Sources_stat)])
txt -> io_lib:format("Srv:\n ~s\nRPZ:\n ~p\nSources:\n ~p\n",[gen_srv_stats(txt),gen_rpz_stats(),gen_source_stats()]);
json -> io_lib:format("{\"srv\":~s,\"rpz\":~s,\"sources\":~s}\n",[gen_srv_stats(json),list_tuples_to_json(gen_rpz_stats()),list_tuples_to_json(gen_source_stats())])
end,
{Body, Req, State};


srv_mgmt(Req, State, Format) when State#state.op == stats_rpz -> % Statistics -- TODO
#{peer := {IP, Port}} = Req,
ioc2rpz_fun:logMessageCEF(ioc2rpz_fun:msg_CEF(230),[ioc2rpz:ip_to_str(IP), Port, cowboy_req:path(Req), ""]),
RPZ_stat = [ {X#rpz.zone_str,X#rpz.rule_count} || [X] <- ets:match(cfg_table,{[rpz,'_'],'_','$2'}), X#rpz.rule_count /= undefined],
Body=case Format of
txt -> io_lib:format("RPZ:\n ~p\n",[RPZ_stat]);
json -> io_lib:format("{\"rpz\":~s}\n",[list_tuples_to_json(RPZ_stat)])
txt -> io_lib:format("RPZ:\n ~p\n",[gen_rpz_stats()]);
json -> io_lib:format("{\"rpz\":~s}\n",[list_tuples_to_json(gen_rpz_stats())])
end,
{Body, Req, State};

srv_mgmt(Req, State, Format) when State#state.op == stats_source -> % Statistics -- TODO
#{peer := {IP, Port}} = Req,
ioc2rpz_fun:logMessageCEF(ioc2rpz_fun:msg_CEF(230),[ioc2rpz:ip_to_str(IP), Port, cowboy_req:path(Req), ""]),
Sources_stat = [ {X#source.name,X#source.ioc_count} || [X] <- ets:match(cfg_table,{[source,'_'],'$2'}), X#source.ioc_count /= undefined],
Body=case Format of
txt -> io_lib:format("Sources:\n ~p\n",[Sources_stat]);
json -> io_lib:format("{\"sources\":~s}\n",[list_tuples_to_json(Sources_stat)])
txt -> io_lib:format("Sources:\n ~p\n",[gen_source_stats()]);
json -> io_lib:format("{\"sources\":~s}\n",[list_tuples_to_json(gen_source_stats())])
end,
{Body, Req, State};

@@ -197,6 +194,26 @@ srv_mgmt(Req, State, Format) when State#state.op == catch_all -> % Catch all uns
rest_terminate(Req, State) ->
ok.

gen_rpz_stats() ->
[ [{"name",X#rpz.zone_str},{"rule_count",X#rpz.rule_count},{"ioc_count",X#rpz.ioc_count},{"serial",X#rpz.serial},{"serial_ixfr",X#rpz.serial_ixfr},{"update_time",X#rpz.update_time},{"ixfr_update_time",X#rpz.ixfr_update_time},{"ixfr_nz_update_time",X#rpz.ixfr_nz_update_time}] || [X] <- ets:match(cfg_table,{[rpz,'_'],'_','$2'}), X#rpz.rule_count /= undefined].

gen_source_stats() ->
[ [{"name",X#source.name},{"ioc_count",X#source.ioc_count}] || [X] <- ets:match(cfg_table,{[source,'_'],'$2'}), X#source.ioc_count /= undefined].

gen_srv_stats(Format) ->
Srv_rules = lists:sum(([ X#rpz.rule_count || [X] <- ets:match(cfg_table,{[rpz,'_'],'_','$2'}), X#rpz.rule_count /= undefined])),
Node=node(),
WS = erlang:system_info(wordsize),
MemHC = binary_to_list(ioc2rpz_fun:conv_to_Mb(ioc2rpz_db:db_table_info(rpz_hotcache_table,memory) * WS)),
MemAXFR = binary_to_list(ioc2rpz_fun:conv_to_Mb(ioc2rpz_db:db_table_info(rpz_axfr_table,memory) * WS)),
MemIXFR = binary_to_list(ioc2rpz_fun:conv_to_Mb(ioc2rpz_db:db_table_info(rpz_ixfr_table,memory) * WS)),
gen_srv_stats(Format,[Node,Srv_rules,MemHC,MemAXFR,MemIXFR]).

gen_srv_stats(txt, [Node,Srv_rules,MemHC,MemAXFR,MemIXFR]) ->
io_lib:format("node_name ~p\n srv_total_rules ~b\n hot_cache_mem ~s\n axfr_table_mem ~s\n ixfr_table_mem ~s\n",[Node,Srv_rules,MemHC,MemAXFR,MemIXFR]);
gen_srv_stats(json, [Node,Srv_rules,MemHC,MemAXFR,MemIXFR]) ->
io_lib:format("{\"node_name\":\"~p\",\"srv_total_rules\":~b,\"hot_cache_mem\":\"~s\",\"axfr_table_mem\":\"~s\",\"ixfr_table_mem\":\"~s\"}",[Node,Srv_rules,MemHC,MemAXFR,MemIXFR]).

list_tuples_to_json(Array) ->
io_lib:format("[~s]",[list_tuples_to_json([],Array)]).

@@ -213,8 +230,27 @@ tuple_to_json({Name,Value}) when is_integer(Value)->
io_lib:format("{\"~s\":~b}",[Name,Value]);

tuple_to_json({Name,Value}) ->
io_lib:format("{\"~s\":\"~b\"}",[Name,Value]).
io_lib:format("{\"~s\":\"~s\"}",[Name,Value]);

tuple_to_json(REST) ->
Res=mtuple_to_json([],REST),
io_lib:format("{~s}",[Res]).

mtuple_to_json([],[{Name,Value}|REST]) when is_integer(Value)->
mtuple_to_json(io_lib:format("\"~s\":~b",[Name,Value]),REST);

mtuple_to_json([],[{Name,Value}|REST]) ->
mtuple_to_json(io_lib:format("\"~s\":\"~s\"",[Name,Value]),REST);

mtuple_to_json(Val,[{Name,Value}|REST]) when is_integer(Value)->
mtuple_to_json(Val++io_lib:format(",\"~s\":~b",[Name,Value]),REST);

mtuple_to_json(Val,[{Name,Value}|REST]) ->
mtuple_to_json(Val++io_lib:format(",\"~s\":\"~s\"",[Name,Value]),REST);

mtuple_to_json(Val,[]) ->
Val.

ioc2jsonarr(IOCs) ->
%ioc2rpz_fun:logMessage("~p\n\n",[IOCs]),
ioc2jsonarr([],IOCs).

0 comments on commit 79ea1fa

Please sign in to comment.
You can’t perform that action at this time.