garbage.pl 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. #!/usr/bin/perl
  2. #
  3. # Copyright (C) Roman Dmitiriev, rnd@rajven.ru
  4. #
  5. use utf8;
  6. use open ":encoding(utf8)";
  7. use Encode;
  8. no warnings 'utf8';
  9. use English;
  10. use base;
  11. use FindBin '$Bin';
  12. use lib "/opt/Eye/scripts";
  13. use strict;
  14. use DBI;
  15. use Date::Parse;
  16. use eyelib::config;
  17. use eyelib::database;
  18. use eyelib::common;
  19. use eyelib::net_utils;
  20. use eyelib::main;
  21. use DateTime;
  22. use Fcntl qw(:flock);
  23. open(SELF,"<",$0) or die "Cannot open $0 - $!";
  24. flock(SELF, LOCK_EX|LOCK_NB) or exit 1;
  25. my @db_tables =(
  26. 'connections',
  27. 'device_l3_interfaces',
  28. 'device_ports',
  29. 'User_list',
  30. 'User_auth',
  31. 'Unknown_mac',
  32. 'User_stats',
  33. 'User_stats_full',
  34. 'dhcp_log',
  35. 'worklog',
  36. 'remote_syslog',
  37. 'Traffic_detail',
  38. );
  39. my $debug_history = 3;
  40. my $optimize = 0;
  41. if ($ARGV[0] =~/optimize/i) { $optimize = 1; }
  42. log_info($dbh,'Garbage started.');
  43. sub is_dhcp_pool {
  44. my $pools = shift;
  45. my $ip_int = shift;
  46. foreach my $subnet (keys %{$pools}) {
  47. #print "net: $subnet ip: $ip_int pool: $pools->{$subnet}->{first_ip} .. $pools->{$subnet}->{last_ip}\n";
  48. if ($ip_int <= $pools->{$subnet}->{last_ip} and $ip_int>= $pools->{$subnet}->{first_ip}) { return $subnet; }
  49. }
  50. return 0;
  51. }
  52. #unblock users
  53. my ($sec,$min,$hour,$day,$month,$year,$zone) = localtime(time());
  54. my $history_sql;
  55. my $history_rf;
  56. my %nets;
  57. my %dhcp_conf;
  58. foreach my $net (@office_network_list) {
  59. my $scope_name=$net;
  60. $scope_name =~s/\/\d+$//g;
  61. $nets{$scope_name}= new Net::Patricia;
  62. $nets{$scope_name}->add_string($net);
  63. }
  64. my $now = DateTime->now(time_zone=>'local');
  65. $now->set(day=>1);
  66. my $month_start=$dbh->quote($now->ymd("-")." 00:00:00");
  67. my $month_dur = DateTime::Duration->new( months => 1 );
  68. my $next_month = $now + $month_dur;
  69. $next_month->set(day=>1);
  70. my $month_stop = $dbh->quote($next_month->ymd("-")." 00:00:00");
  71. my $dhcp_networks = new Net::Patricia;
  72. my @subnets=get_records_sql($dbh,'SELECT * FROM subnets WHERE office=1 AND dhcp=1 AND vpn=0 ORDER BY ip_int_start');
  73. foreach my $subnet (@subnets) {
  74. $dhcp_networks->add_string($subnet->{subnet});
  75. my $subnet_name = $subnet->{subnet};
  76. $subnet_name=~s/\/\d+$//g;
  77. $dhcp_conf{$subnet_name}->{first_ip}=$subnet->{dhcp_start};
  78. $dhcp_conf{$subnet_name}->{last_ip}=$subnet->{dhcp_stop};
  79. }
  80. if ($day==1) {
  81. log_info($dbh,'Monthly amnesty started');
  82. db_log_info($dbh,"Amnistuyemo all blocked user by traffic for a month");
  83. do_sql($dbh,"Update User_list set blocked=0");
  84. do_sql($dbh,"Update User_auth set blocked=0, changed=1 WHERE blocked=1 and deleted=0");
  85. log_info($dbh,'Monthly amnesty stopped');
  86. } else {
  87. #month stat
  88. log_info($dbh,'Daily statistics started');
  89. my $month_sql="SELECT User_list.id, User_list.login, SUM( traf_all ) AS traf_sum, User_list.month_quota as uquota
  90. FROM ( SELECT User_stats.auth_id, SUM( byte_in + byte_out ) AS traf_all FROM User_stats
  91. WHERE User_stats.`timestamp`>=$month_start AND User_stats.`timestamp`< $month_stop
  92. GROUP BY User_stats.auth_id ) AS V, User_auth, User_list
  93. WHERE V.auth_id = User_auth.id AND User_auth.user_id = User_list.id and User_list.blocked=1 GROUP BY login";
  94. my @month_stats = get_records_sql($dbh,$month_sql);
  95. foreach my $row (@month_stats) {
  96. my $m_quota=$row->{uquota}*$KB*$KB;
  97. next if ($m_quota < $row->{traf_sum});
  98. unblock_user($dbh,$row->{id});
  99. }
  100. log_info($dbh,'Daily statistics stopped');
  101. }
  102. log_info($dbh,'Clean dhcp leases for dynamic hosts with overdue lease time');
  103. #clean temporary dhcp leases & connections only for dhcp pool ip
  104. my $users_sql = "SELECT * FROM User_auth WHERE deleted=0 AND (`ou_id`=".$default_user_ou_id." OR `ou_id`=".$default_hotspot_ou_id.")";
  105. my @users_auth = get_records_sql($dbh,$users_sql);
  106. foreach my $row (@users_auth) {
  107. next if (!is_dhcp_pool(\%dhcp_conf,$row->{ip_int}));
  108. my $last_dhcp_time = GetUnixTimeByStr($row->{dhcp_time});
  109. if ($dhcp_networks->match_string($row->{ip})) {
  110. my $clean_dhcp_time = $last_dhcp_time + 60*$dhcp_networks->match_string($row->{ip});
  111. if (time() - $clean_dhcp_time>0) {
  112. db_log_verbose($dbh,"Clean overdue dhcp leases for ip: $row->{ip} id: $row->{id} last dhcp: $row->{dhcp_time} clean time: ".GetTimeStrByUnixTime($clean_dhcp_time)." now: ".GetNowTime());
  113. delete_user_auth($dbh,$row->{id});
  114. my $u_count=get_count_records($dbh,'User_auth','deleted=0 and user_id='.$row->{user_id});
  115. if (!$u_count) {
  116. delete_user($dbh,$row->{'user_id'});
  117. db_log_info($dbh,"Remove dynamic user id: $row->{'user_id'} by dhcp lease timeout");
  118. }
  119. }
  120. }
  121. }
  122. $now = DateTime->now(time_zone=>'local');
  123. #clean dhcp log
  124. if ($history_dhcp) {
  125. my $day_dur = DateTime::Duration->new( days => $history_dhcp );
  126. my $clean_date = $now - $day_dur;
  127. my $clean_str = $dbh->quote($clean_date->ymd("-")." 00:00:00");
  128. log_info($dbh,'Clearing outdated records dhcp log');
  129. do_sql($dbh,"DELETE FROM dhcp_log WHERE `timestamp` < $clean_str" );
  130. log_verbose($dbh,"Clean dhcp leases for all older that ".$clean_str);
  131. }
  132. ##### clean old connections ########
  133. if ($connections_history) {
  134. log_info($dbh,'Clearing outdated connection records');
  135. my $day_dur = DateTime::Duration->new( days => $connections_history );
  136. my $clean_date = $now - $day_dur;
  137. my $clean_str = $dbh->quote($clean_date->ymd("-")." 00:00:00");
  138. $users_sql = "SELECT id FROM User_auth WHERE `last_found` < $clean_str and last_found>0";
  139. log_debug($dbh,$users_sql) if ($debug);
  140. @users_auth=get_records_sql($dbh,$users_sql);
  141. foreach my $row (@users_auth) {
  142. log_debug($dbh,"Clear old connection for user_auth ".$row->{id});
  143. do_sql($dbh,"DELETE FROM connections WHERE auth_id='".$row->{id}."'");
  144. }
  145. }
  146. ##### clean dup connections ########
  147. log_info($dbh,'Clearing duplicated connection records');
  148. my $conn_sql = "SELECT id,port_id,auth_id FROM connections order by port_id";
  149. my @conn_ref = get_records_sql($dbh,$conn_sql);
  150. my $old_port_id=0;
  151. my $old_auth_id=0;
  152. foreach my $row (@conn_ref) {
  153. my $c_id = $row->{id};
  154. my $c_port_id = $row->{port_id};
  155. my $c_auth_id = $row->{auth_id};
  156. if (!$c_port_id) { $c_port_id=0; }
  157. if (!$c_auth_id) { $c_auth_id=0; }
  158. if ($old_port_id ==0 or $old_auth_id==0) { $old_port_id=$c_port_id; $old_auth_id=$c_auth_id; next; }
  159. if ($old_port_id >0 and $old_port_id != $c_port_id) { $old_port_id=$c_port_id; $old_auth_id=$c_auth_id; next; }
  160. if ($old_auth_id >0 and $old_auth_id != $c_auth_id) { $old_port_id=$c_port_id; $old_auth_id=$c_auth_id; next; }
  161. do_sql($dbh,"DELETE FROM connections WHERE id='".$c_id."'");
  162. log_info($dbh,"Remove dup connection $c_id: $c_port_id $c_auth_id");
  163. }
  164. ##### clean empty user account and corresponded devices for dynamic users and hotspot ################
  165. log_info($dbh,'Clearing empty user account and corresponded devices for dynamic users and hotspot');
  166. my $u_sql = "SELECT * FROM User_list as U WHERE (U.ou_id=".$default_hotspot_ou_id." OR U.ou_id=".$default_user_ou_id.") AND (SELECT COUNT(*) FROM User_auth WHERE User_auth.deleted=0 AND User_auth.user_id = U.id)=0";
  167. my @u_ref = get_records_sql($dbh,$u_sql);
  168. foreach my $row (@u_ref) {
  169. db_log_info($dbh,"Remove empty dynamic user with id: $row->{id} login: $row->{login}");
  170. delete_user($dbh,$row->{id});
  171. }
  172. ##### clean empty user account and corresponded devices ################
  173. if ($config_ref{clean_empty_user}) {
  174. log_info($dbh,'Clearing empty user account and corresponded devices');
  175. # my $u_sql = "SELECT * FROM User_list as U WHERE (SELECT COUNT(*) FROM User_auth WHERE User_auth.deleted=0 AND User_auth.user_id = U.id)=0 AND (SELECT COUNT(*) FROM auth_rules WHERE auth_rules.user_id = U.id)=0";
  176. # my $u_sql = "SELECT * FROM User_list as U WHERE (SELECT COUNT(*) FROM User_auth WHERE User_auth.deleted=0 AND User_auth.user_id = U.id)=0";
  177. my $u_sql = "SELECT * FROM User_list as U WHERE U.permanent=0 AND (SELECT COUNT(*) FROM User_auth WHERE User_auth.deleted=0 AND User_auth.user_id = U.id)=0 AND (SELECT COUNT(*) FROM auth_rules WHERE auth_rules.user_id = U.id)=0;";
  178. my @u_ref = get_records_sql($dbh,$u_sql);
  179. foreach my $row (@u_ref) {
  180. db_log_info($dbh,"Remove empty user with id: $row->{id} login: $row->{login}");
  181. delete_user($dbh,$row->{id});
  182. }
  183. }
  184. ##### Remove unreferensed auth rules
  185. do_sql($dbh, "DELETE FROM `auth_rules` WHERE user_id NOT IN (SELECT id FROM User_list)");
  186. ##### unknown mac clean ############
  187. log_info($dbh,'Clearing unknown mac if it found in current User_auth table');
  188. $users_sql = "SELECT mac FROM User_auth WHERE deleted=0";
  189. @users_auth = get_records_sql($dbh,$users_sql);
  190. foreach my $row (@users_auth) {
  191. next if (!$row->{mac});
  192. do_sql($dbh,"DELETE FROM Unknown_mac WHERE mac='".mac_simplify($row->{mac})."'");
  193. }
  194. ##### traffic detail ######
  195. if ($history) {
  196. my $day_dur = DateTime::Duration->new( days => $history );
  197. my $clean_date = $now - $day_dur;
  198. my $clean_str = $dbh->quote($clean_date->ymd("-")." 00:00:00");
  199. log_info($dbh,"Clean traffic detail older that ".$clean_str);
  200. #clean old traffic detail
  201. do_sql($dbh,"DELETE FROM Traffic_detail WHERE `timestamp` < $clean_str" );
  202. }
  203. ##### log ######
  204. if ($history_log_day) {
  205. my $day_dur = DateTime::Duration->new( days => $history_log_day );
  206. my $clean_date = $now - $day_dur;
  207. my $clean_str = $dbh->quote($clean_date->ymd("-")." 00:00:00");
  208. log_info($dbh,"Clean VERBOSE worklog older that ".$clean_str);
  209. do_sql($dbh,"DELETE FROM worklog WHERE level>$L_INFO AND `timestamp` < $clean_str" );
  210. }
  211. #clean debug logs older than $debug_history days
  212. if ($debug_history) {
  213. my $day_dur = DateTime::Duration->new( days => 3 );
  214. my $clean_date = $now - $day_dur;
  215. my $clean_str = $dbh->quote($clean_date->ymd("-")." 00:00:00");
  216. log_info($dbh,"Clean debug worklog older that ".$clean_str);
  217. do_sql($dbh,"DELETE FROM worklog WHERE level>=$L_DEBUG AND `timestamp` < $clean_str" );
  218. }
  219. ##### remote syslog ######
  220. if ($history_syslog_day) {
  221. my $day_dur = DateTime::Duration->new( days => $history_syslog_day );
  222. my $clean_date = $now - $day_dur;
  223. my $clean_str = $dbh->quote($clean_date->ymd("-")." 00:00:00");
  224. log_info($dbh,"Clean syslog older that ".$clean_str);
  225. do_sql($dbh,"DELETE FROM remote_syslog WHERE `date` < $clean_str" );
  226. }
  227. ##### Traffic stats ######
  228. if ($history_trafstat_day) {
  229. my $day_dur = DateTime::Duration->new( days => $history_trafstat_day );
  230. my $clean_date = $now - $day_dur;
  231. my $clean_str = $dbh->quote($clean_date->ymd("-")." 00:00:00");
  232. log_info($dbh,"Clean traffic statistics older that ".$clean_str);
  233. do_sql($dbh,"DELETE FROM User_stats WHERE `timestamp` < $clean_str" );
  234. }
  235. ##### Traffic stats full ######
  236. my $iptraf_history = $config_ref{traffic_ipstat_history};
  237. if ($iptraf_history) {
  238. my $day_dur = DateTime::Duration->new( days => $iptraf_history );
  239. my $clean_date = $now - $day_dur;
  240. my $clean_str = $dbh->quote($clean_date->ymd("-")." 00:00:00");
  241. log_info($dbh,"Clean traffic full statistics older that ".$clean_str);
  242. do_sql($dbh,"DELETE FROM User_stats_full WHERE `timestamp` < $clean_str" );
  243. }
  244. #### clean unknown user ip
  245. do_sql($dbh,"DELETE FROM User_auth WHERE (mac is NULL or mac='') and deleted=1");
  246. #### save location changes
  247. my %connections;
  248. my @connections_list=get_records_sql($dbh,"SELECT * FROM connections ORDER BY auth_id");
  249. foreach my $connection (@connections_list) {
  250. next if (!$connection);
  251. $connections{$connection->{auth_id}}=$connection;
  252. }
  253. my $auth_sql="SELECT * FROM User_auth WHERE mac IS NOT NULL AND mac !='' AND deleted=0 ORDER BY last_found DESC";
  254. my %auth_table;
  255. my @auth_full_list=get_records_sql($dbh,$auth_sql);
  256. foreach my $auth (@auth_full_list) {
  257. next if (!$auth);
  258. my $auth_mac=mac_simplify($auth->{mac});
  259. next if (exists $auth_table{$auth_mac});
  260. next if (!exists $connections{$auth->{id}});
  261. $auth_table{$auth_mac}=1;
  262. my $h_sql = "SELECT * FROM mac_history WHERE mac='".$auth_mac."' ORDER BY `timestamp` DESC";
  263. my $history = get_record_sql($dbh,$h_sql);
  264. if (!$history) {
  265. #add record to history
  266. my $cur_conn = $connections{$auth->{id}};
  267. my $new;
  268. $new->{device_id}=$cur_conn->{device_id};
  269. $new->{port_id}=$cur_conn->{port_id};
  270. $new->{auth_id}=$auth->{id};
  271. $new->{ip}=$auth->{ip};
  272. $new->{mac}=$auth_mac;
  273. $new->{timestamp}=$auth->{last_found};
  274. db_log_info($dbh,"Auth id: $auth->{id} $auth_mac found at location device_id: $new->{device_id} port_id: $new->{port_id}");
  275. insert_record($dbh,"mac_history",$new);
  276. next;
  277. }
  278. my $cur_conn = $connections{$auth->{id}};
  279. #check record history
  280. if ($history->{device_id} != $cur_conn->{device_id} or $history->{port_id} != $cur_conn->{port_id}) {
  281. #add new record
  282. my $new;
  283. $new->{device_id}=$cur_conn->{device_id};
  284. $new->{port_id}=$cur_conn->{port_id};
  285. $new->{auth_id}=$auth->{id};
  286. $new->{ip}=$auth->{ip};
  287. $new->{mac}=$auth_mac;
  288. $new->{timestamp}=$auth->{last_found};
  289. db_log_info($dbh,"Auth id: $auth->{id} $auth_mac moved to another location device_id: $new->{device_id} port_id: $new->{port_id}");
  290. insert_record($dbh,"mac_history",$new);
  291. }
  292. }
  293. if ( $optimize ) {
  294. log_info($dbh,'Start optimize tables');
  295. foreach my $table (@db_tables) {
  296. my $opt_sql = "optimize table ".$table;
  297. my $opt_rf=$dbh->prepare($opt_sql) or die "Unable to prepare $opt_sql:" . $dbh->errstr;
  298. my $opt_result = $opt_rf->execute();
  299. #CREATE TABLE `".$table.".new` LIKE $table;
  300. #INSERT INTO `".$table.".new` SELECT * FROM $table;
  301. #RENAME TABLE $table TO `".$table.".backup`;
  302. #RENAME TABLE `".$table.".new` TO $table;
  303. #DROP TABLE `".$table.".backup`;";
  304. }
  305. log_info($dbh,'Optimize ended.');
  306. }
  307. log_info($dbh,'Garbage stopped.');
  308. $dbh->disconnect;
  309. exit 0;