dhcp-log.pl 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. #!/usr/bin/perl
  2. #
  3. # Copyright (C) Roman Dmitiriev, rnd@rajven.ru
  4. #
  5. use FindBin '$Bin';
  6. use lib "$Bin/";
  7. use Data::Dumper;
  8. use Rstat::config;
  9. use Rstat::main;
  10. use Rstat::mysql;
  11. use Rstat::net_utils;
  12. use strict;
  13. use warnings;
  14. use Getopt::Long;
  15. use Proc::Daemon;
  16. use Cwd;
  17. use Net::Netmask;
  18. use File::Spec::Functions;
  19. use File::Copy qw(move);
  20. use Text::Iconv;
  21. my $pf = '/var/run/dhcp-log.pid';
  22. my $log='/var/lib/dhcpd/dhcpd.log';
  23. my $daemon = Proc::Daemon->new(
  24. pid_file => $pf,
  25. work_dir => $HOME_DIR
  26. );
  27. # are you running? Returns 0 if not.
  28. my $pid = $daemon->Status($pf);
  29. my $daemonize = 1;
  30. GetOptions(
  31. 'daemon!' => \$daemonize,
  32. "help" => \&usage,
  33. "reload" => \&reload,
  34. "restart" => \&restart,
  35. "start" => \&run,
  36. "status" => \&status,
  37. "stop" => \&stop
  38. ) or &usage;
  39. exit(0);
  40. sub stop {
  41. if ($pid) {
  42. print "Stopping pid $pid...";
  43. if ($daemon->Kill_Daemon($pf)) {
  44. print "Successfully stopped.\n";
  45. } else {
  46. print "Could not find $pid. Was it running?\n";
  47. }
  48. } else {
  49. print "Not running, nothing to stop.\n";
  50. }
  51. }
  52. sub status {
  53. if ($pid) {
  54. print "Running with pid $pid.\n";
  55. } else {
  56. print "Not running.\n";
  57. }
  58. }
  59. sub run {
  60. if (!$pid) {
  61. print "Starting...";
  62. if ($daemonize) {
  63. # when Init happens, everything under it runs in the child process.
  64. # this is important when dealing with file handles, due to the fact
  65. # Proc::Daemon shuts down all open file handles when Init happens.
  66. # Keep this in mind when laying out your program, particularly if
  67. # you use filehandles.
  68. $daemon->Init;
  69. }
  70. setpriority(0,0,19);
  71. my $converter = Text::Iconv->new("cp866", "utf8");
  72. while (1) {
  73. eval {
  74. # Create new database handle. If we can't connect, die()
  75. system('touch "'.$log.'"');
  76. my $hdb = DBI->connect("dbi:mysql:database=$DBNAME;host=$DBHOST","$DBUSER","$DBPASS");
  77. if ( !defined $hdb ) { die "Cannot connect to mySQL server: $DBI::errstr\n"; }
  78. open(DHCP, "tail -n 0 -F $log |") || die "$log not found!";
  79. while (my $logline = <DHCP>) {
  80. next unless defined $logline;
  81. chomp($logline);
  82. log_info("GET CLIENT REQUEST: $logline");
  83. my ($type,$ip,$mac,$hostname) = split (/\;/, $logline);
  84. next if (!$type);
  85. next if ($type!~/(old|add|del)/i);
  86. if (time()-$last_refresh_config>=60) { init_option($hdb); }
  87. my $client_hostname='UNDEFINED';
  88. if ($hostname and $hostname!~/undef/i) { $client_hostname=$hostname; }
  89. my $auth_network = $office_networks->match_string($ip);
  90. if (!$auth_network) {
  91. log_error("Unknown network in dhcp request! IP: $ip");
  92. next;
  93. }
  94. my $utf_client_hostname = $converter->convert($client_hostname);
  95. $mac=mac_splitted(isc_mac_simplify($mac));
  96. log_debug(uc($type).">>");
  97. log_debug("MAC: ".$mac);
  98. log_debug("IP: ".$ip);
  99. log_debug("HOSTNAME: ".$client_hostname);
  100. log_debug("UTF8 HOSTNAME: ".$utf_client_hostname);
  101. log_debug("END GET");
  102. my $ip_aton=StrToIp($ip);
  103. $mac=mac_splitted($mac);
  104. if ($type eq 'add') {
  105. log_info("Check for new auth...");
  106. resurrection_auth($hdb,$ip,$mac,$type);
  107. }
  108. my $auth_record = get_custom_record($hdb,'SELECT * FROM User_auth WHERE ip="'.$ip.'" and mac="'.$mac.'" and deleted=0 ORDER BY last_found DESC');
  109. my $auth_id = $auth_record->{id};
  110. my $ad_zone = get_option($hdb,33);
  111. my $ad_dns = get_option($hdb,3);
  112. $update_hostname_from_dhcp = get_option($hdb,46) || 0;
  113. my $subnets_dhcp = get_subnets_ref($hdb);
  114. my $enable_ad_dns_update = ($ad_zone and $ad_dns and $update_hostname_from_dhcp);
  115. log_debug("Subnet: $auth_network");
  116. log_debug("DNS update flags - zone: $ad_zone dns: $ad_dns config: $update_hostname_from_dhcp subnet: $subnets_dhcp->{$auth_network}->{dhcp_update_hostname}");
  117. my $maybe_update_dns=(($type=~/add/i or $type=~/old/i) and $utf_client_hostname and $utf_client_hostname !~/UNDEFINED/i and $enable_ad_dns_update and $subnets_dhcp->{$auth_network}->{dhcp_update_hostname});
  118. if ($maybe_update_dns) {
  119. log_debug("DNS update enabled.");
  120. #update dns block
  121. my $fqdn_static;
  122. if ($auth_record->{dns_name}) {
  123. $fqdn_static=lc($auth_record->{dns_name});
  124. if ($fqdn_static!~/$ad_zone$/i) {
  125. $fqdn_static=~s/\.$//;
  126. $fqdn_static=lc($fqdn_static.'.'.$ad_zone);
  127. }
  128. }
  129. my $fqdn=lc(trim($utf_client_hostname));
  130. if ($fqdn!~/$ad_zone$/i) {
  131. $fqdn=~s/\.$//;
  132. $fqdn=lc($fqdn.'.'.$ad_zone);
  133. }
  134. db_log_debug($hdb,"FOUND Auth_id: $auth_id dns_name: $fqdn_static dhcp_hostname: $fqdn");
  135. #check exists static dns name
  136. my $static_exists = 0;
  137. my $dynamic_exists = 0;
  138. my $static_ok = 0;
  139. my $dynamic_ok = 0;
  140. my $static_ref;
  141. my $dynamic_ref;
  142. if ($fqdn_static ne '') {
  143. my @dns_record=ResolveNames($fqdn_static);
  144. $static_exists = (scalar @dns_record>0);
  145. if ($static_exists) {
  146. $static_ref = join(' ',@dns_record);
  147. foreach my $dns_a (@dns_record) {
  148. if ($dns_a=~/^$ip$/) { $static_ok = $dns_a; }
  149. }
  150. }
  151. } else { $static_ok = 1; }
  152. if ($fqdn ne '') {
  153. my @dns_record=ResolveNames($fqdn);
  154. $dynamic_exists = (scalar @dns_record>0);
  155. if ($dynamic_exists) {
  156. $dynamic_ref = join(' ',@dns_record);
  157. foreach my $dns_a (@dns_record) {
  158. if ($dns_a=~/^$ip$/) { $dynamic_ok = $dns_a; }
  159. }
  160. }
  161. }
  162. if ($fqdn_static ne '') {
  163. if (!$static_ok) {
  164. db_log_info($hdb,"Static record mismatch! Expected $fqdn_static => $ip, recivied: $static_ref");
  165. if (!$static_exists) {
  166. db_log_info($hdb,"Static dns hostname defined but not found. Create it ($fqdn_static => $ip)!");
  167. update_ad_hostname($fqdn_static,$ip,$ad_zone,$ad_dns);
  168. }
  169. } else { db_log_debug($hdb,"Static record for $fqdn_static [$static_ok] correct."); }
  170. }
  171. if ($fqdn ne '' and $dynamic_ok ne '') { db_log_debug($hdb,"Dynamic record for $fqdn [$dynamic_ok] correct. No changes required."); }
  172. if ($fqdn ne '' and !$dynamic_ok) {
  173. #log only to file!!!
  174. log_error($hdb,"Dynamic record mismatch! Expected: $fqdn => $ip, recivied: $dynamic_ref. Checking the status.");
  175. #check exists hostname
  176. my $another_hostname_exists = 0;
  177. my $hostname_filter = ' LOWER(dns_name)="'.lc($utf_client_hostname).'"';
  178. if ($fqdn_static ne '' and $fqdn !~/$fqdn_static/) { $hostname_filter = $hostname_filter . ' or LOWER(dns_name)="'.lc($auth_record->{dns_name}).'"'; }
  179. #check exists another records with some static hostname
  180. my $name_record = get_custom_record($hdb,'SELECT * FROM User_auth WHERE id<>'.$auth_id.' and deleted=0 and ('.$hostname_filter.') ORDER BY last_found DESC');
  181. if ($name_record->{id}) { $another_hostname_exists = 1; }
  182. if (!$another_hostname_exists) {
  183. if ($fqdn_static and $fqdn_static ne '') {
  184. if ($fqdn_static!~/$fqdn/) {
  185. db_log_info($hdb,"Hostname from dhcp request $fqdn differs from static dns hostanme $fqdn_static. Ignore dynamic binding!");
  186. # update_ad_hostname($fqdn,$ip,$ad_zone,$ad_dns);
  187. }
  188. } else {
  189. db_log_info($hdb,"Static dns hostname not defined. Create dns record by dhcp request. $fqdn => $ip");
  190. update_ad_hostname($fqdn,$ip,$ad_zone,$ad_dns);
  191. }
  192. } else {
  193. db_log_error($hdb,"Found another record with some hostname id: $name_record->{id} ip: $name_record->{ip} hostname: $name_record->{dns_hostname}. Skip update.");
  194. }
  195. }
  196. #end update dns block
  197. } else {
  198. db_log_debug($hdb,"FOUND Auth_id: $auth_id");
  199. }
  200. if ($type=~/add/i and $utf_client_hostname and $utf_client_hostname !~/UNDEFINED/i) {
  201. my $auth_rec;
  202. $auth_rec->{dhcp_hostname} = $utf_client_hostname;
  203. update_record($hdb,'User_auth',$auth_rec,"id=$auth_id");
  204. }
  205. if ($hotspot_networks->match_string($ip) and $ignore_hotspot_dhcp_log) { next; }
  206. if ($ignore_update_dhcp_event and $type=~/old/i) { next; }
  207. if ($type=~/(old|del)/i) {
  208. my $auth_rec;
  209. $auth_rec->{dhcp_action}=$type;
  210. $auth_rec->{dhcp_time}=GetNowTime();
  211. update_record($hdb,'User_auth',$auth_rec,"id=$auth_id");
  212. }
  213. my $dhcp_log;
  214. $dhcp_log->{auth_id} = $auth_id;
  215. $dhcp_log->{ip} = $ip;
  216. $dhcp_log->{ip_int} = $ip_aton;
  217. $dhcp_log->{mac} = $mac;
  218. $dhcp_log->{action} = $type;
  219. insert_record($hdb,'dhcp_log',$dhcp_log);
  220. }
  221. close DHCP;
  222. };
  223. if ($@) { log_error("Exception found: $@"); }
  224. }
  225. } else {
  226. print "Already Running with pid $pid\n";
  227. }
  228. }
  229. sub usage {
  230. print "usage: dhcp-log.pl (start|stop|status|restart)\n";
  231. exit(0);
  232. }
  233. sub reload {
  234. print "reload process not implemented.\n";
  235. }
  236. sub restart {
  237. stop;
  238. run;
  239. }