fetch_new_arp.pl 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. #!/usr/bin/perl
  2. #
  3. # Copyright (C) Roman Dmitiriev, rnd@rajven.ru
  4. #
  5. use FindBin '$Bin';
  6. use lib "$Bin/";
  7. use strict;
  8. use DBI;
  9. use Time::Local;
  10. use Net::Patricia;
  11. use Data::Dumper;
  12. use Date::Parse;
  13. use Socket;
  14. use Rstat::config;
  15. use Rstat::main;
  16. use Rstat::net_utils;
  17. use Rstat::snmp;
  18. use Rstat::mysql;
  19. use NetAddr::IP;
  20. setpriority(0,0,19);
  21. my %mac_history;
  22. my ($sec,$min,$hour,$day,$month,$year,$zone) = localtime(time());
  23. $month += 1;
  24. $year += 1900;
  25. my $now_str=sprintf "%04d-%02d-%02d %02d:%02d:%02d",$year,$month,$day,$hour,$min,$sec;
  26. my $now_day=sprintf "%04d-%02d-%02d",$year,$month,$day;
  27. if (!$arp_discovery) {
  28. db_log_verbose($dbh,'Arp discovery disabled by config');
  29. } else {
  30. db_log_verbose($dbh,'Arp discovery started.');
  31. if ($ARGV[0]) {
  32. db_log_verbose($dbh,'Active check started!');
  33. my $subnets=get_subnets_ref($dbh);
  34. foreach my $net (keys %$subnets) {
  35. next if (!$net);
  36. next if (!$subnets->{$net}{discovery});
  37. my $run_cmd="$fping -g $subnets->{$net}{subnet} -B1.0 -c 1 >/dev/null 2>&1";
  38. db_log_debug($dbh,"Checked network $subnets->{$net}{subnet}") if ($debug);
  39. do_exec($run_cmd);
  40. }
  41. }
  42. my $router_list = $dbh->prepare( "SELECT ip,snmp_version,community FROM devices where deleted=0 and is_router=1 and discovery=1 and snmp_version>0 ORDER by ip" );
  43. if ( !defined $router_list ) { die "Cannot prepare statement: $DBI::errstr\n"; }
  44. $router_list->execute;
  45. my $router_ref = $router_list->fetchall_arrayref();
  46. $router_list->finish();
  47. #get userid list
  48. my $user_auth_list = $dbh->prepare( "SELECT id,ip,mac,comments FROM User_auth where deleted=0 ORDER by ip" );
  49. if ( !defined $user_auth_list ) { die "Cannot prepare statement: $DBI::errstr\n"; }
  50. $user_auth_list->execute;
  51. my $authlist_ref = $user_auth_list->fetchall_arrayref();
  52. $user_auth_list->finish();
  53. my $users = new Net::Patricia;
  54. my %ip_list;
  55. foreach my $row (@$authlist_ref) {
  56. $users->add_string($row->[1],$row->[0]);
  57. $ip_list{$row->[0]}->{id}=$row->[0];
  58. $ip_list{$row->[0]}->{ip}=$row->[1];
  59. $ip_list{$row->[0]}->{mac}=mac_splitted($row->[2]) || '';
  60. }
  61. foreach my $router (@$router_ref) {
  62. my $router_ip=$router->[0];
  63. my $snmp_version=$router->[1];
  64. my $community=$router->[2];
  65. #print "Analyze $router_ip $snmp_version $community\n";
  66. my $arp_table=get_arp_table($router_ip,$community,$snmp_version);
  67. next if (!$arp_table);
  68. foreach my $ip (keys %$arp_table) {
  69. next if (!$arp_table->{$ip});
  70. my $mac=trim($arp_table->{$ip});
  71. $mac=mac_splitted($mac);
  72. next if (!$mac);
  73. next if ($mac=~/ff:ff:ff:ff:ff:ff/i);
  74. next if ($mac!~/(\S{2}):(\S{2}):(\S{2}):(\S{2}):(\S{2}):(\S{2})/);
  75. my $simple_mac=mac_simplify($mac);
  76. $ip=trim($ip);
  77. my $ip_aton=StrToIp($ip);
  78. $mac_history{$simple_mac}{changed}=0;
  79. $mac_history{$simple_mac}{ip}=$ip;
  80. $mac_history{$simple_mac}{auth_id}=0;
  81. next if (!$office_networks->match_string($ip));
  82. db_log_debug($dbh,"Analyze ip: $ip mac: $mac") if ($debug);
  83. my $auth_id = $users->match_string($ip);
  84. resurrection_auth($dbh,$ip,$mac,'arp');
  85. my $cur_auth_id=get_id_record($dbh,'User_auth',"ip='$ip' and mac='$mac' and deleted=0 order by last_found DESC");
  86. $mac_history{$simple_mac}{auth_id}=$cur_auth_id;
  87. if ($auth_id ne $cur_auth_id) {
  88. $mac_history{$simple_mac}{changed}=1;
  89. }
  90. }
  91. }
  92. db_log_verbose($dbh,'Arp discovery stopped.');
  93. }
  94. #MAC Discavery
  95. if (!$mac_discovery) {
  96. db_log_verbose($dbh,'Mac discovery disabled by config');
  97. } else {
  98. sleep(1);
  99. db_log_verbose($dbh,'Mac discovery started.');
  100. my %connections=();
  101. my $connections_list=do_sql($dbh,"Select id,auth_id,port_id from connections order by auth_id");
  102. foreach my $connection (@$connections_list) {
  103. next if (!$connection);
  104. my ($conn_id,$conn_auth_id,$conn_port_id)=@$connection;
  105. $connections{$conn_auth_id}{port}=$conn_port_id;
  106. $connections{$conn_auth_id}{id}=$conn_id;
  107. }
  108. my $auth_filter='';
  109. if ($arp_discovery) { $auth_filter=" and last_found >='".$now_day."' "; }
  110. my $auth_sql="Select id,mac from User_auth where mac is not null and deleted=0 $auth_filter order by id asc";
  111. my $auth_list=do_sql($dbh,$auth_sql);
  112. my %auth_table;
  113. foreach my $auth (@$auth_list) {
  114. next if (!$auth);
  115. my ($auth_id,$auth_mac)=@$auth;
  116. $auth_mac=mac_simplify($auth_mac);
  117. $auth_table{oper_table}{$auth_mac}=$auth_id;
  118. }
  119. $auth_sql="Select id,mac from User_auth where mac is not null and deleted=0 order by id asc";
  120. my $auth_full_list=do_sql($dbh,$auth_sql);
  121. foreach my $auth (@$auth_full_list) {
  122. next if (!$auth);
  123. my ($auth_id,$auth_mac)=@$auth;
  124. $auth_mac=mac_simplify($auth_mac);
  125. $auth_table{full_table}{$auth_mac}=$auth_id;
  126. }
  127. my $unknown_list=do_sql($dbh,"Select id,mac,port_id,device_id from Unknown_mac where mac !='' order by mac");
  128. my %unknown_table;
  129. foreach my $unknown (@$unknown_list) {
  130. next if (!$unknown);
  131. my ($unknown_id,$unknown_mac,$unknown_port_id,$unknown_device_id)=@$unknown;
  132. $unknown_mac=mac_simplify($unknown_mac);
  133. $unknown_table{$unknown_mac}{unknown_id}=$unknown_id;
  134. $unknown_table{$unknown_mac}{port_id}=$unknown_port_id;
  135. $unknown_table{$unknown_mac}{device_id}=$unknown_device_id;
  136. }
  137. my $device_ref = do_sql($dbh,"SELECT ip,snmp_version,community,fdb_snmp_index,device_name,id from devices WHERE deleted=0 and discovery=1 and snmp_version>0" );
  138. foreach my $device (@$device_ref) {
  139. my %port_snmp_index=();
  140. my %port_index=();
  141. my %mac_port_count=();
  142. my %mac_address_table=();
  143. my %port_links=();
  144. my ($dev_ip,$dev_snmp_ver,$dev_community,$dev_fdb_index,$dev_name,$dev_id)=@$device;
  145. next if (!$dev_id);
  146. #print "$dev_ip,$dev_snmp_ver,$dev_community,$dev_fdb_index,$dev_name,$dev_id\n" if ($debug);
  147. my $fdb=get_fdb_table($dev_ip,$dev_community,$dev_snmp_ver);
  148. next if (!$fdb);
  149. my $device_ports = do_sql($dbh,"Select port,snmp_index,target_port_id,id,skip,vlan from device_ports where device_id=$dev_id");
  150. foreach my $port (@$device_ports) {
  151. my ($port,$snmp_index,$target_port_id,$port_id,$skip_port,$vlan)=@$port;
  152. my $port_index=$port;
  153. if (!$vlan) { $vlan=1; }
  154. if ($dev_fdb_index) {
  155. if (!$snmp_index) { next; }
  156. $port_index=$snmp_index;
  157. }
  158. my $current_vlan = get_vlan_at_port($dev_ip,$dev_community,$dev_snmp_ver,$port_index);
  159. if (!$current_vlan or $current_vlan=~/noSuchInstance/i or !is_integer($current_vlan)) { $current_vlan=1; }
  160. if ($current_vlan != $vlan) {
  161. my $dev_ports;
  162. $dev_ports->{vlan}=$current_vlan;
  163. update_record($dbh,'device_ports',$dev_ports,"device_id=$dev_id and port=$port");
  164. db_log_verbose($dbh,"Vlan changed at device $dev_name [$port] old: $vlan current: $current_vlan");
  165. }
  166. next if ($skip_port);
  167. $port_snmp_index{$snmp_index}=$port;
  168. $port_index{$port}=$port_id;
  169. $port_links{$port}=$target_port_id;
  170. $mac_port_count{$port}=0;
  171. }
  172. foreach my $mac (keys %$fdb) {
  173. my $port = $fdb->{$mac};
  174. next if (!$port);
  175. if ($dev_fdb_index) {
  176. if (!exists $port_snmp_index{$port}) { next; }
  177. $port=$port_snmp_index{$port};
  178. }
  179. if (!exists $port_index{$port}) { next; }
  180. $mac_port_count{$port}++;
  181. $mac_address_table{$mac}=$port;
  182. }
  183. foreach my $port (keys %mac_port_count) {
  184. if (!$port) { next; }
  185. if (!exists $port_index{$port}) { next; }
  186. #skip uplink|downlink
  187. if ($port_links{$port}>0) { next; }
  188. my $dev_ports;
  189. $dev_ports->{last_mac_count}=$mac_port_count{$port};
  190. update_record($dbh,'device_ports',$dev_ports,"device_id=$dev_id and port=$port");
  191. }
  192. foreach my $mac (keys %mac_address_table) {
  193. my $port = $mac_address_table{$mac};
  194. if (!$port) { next; }
  195. if (!exists $port_index{$port}) { next; }
  196. #skip uplink|downlink
  197. if ($port_links{$port}>0) { next; }
  198. my $simple_mac=mac_simplify($mac);
  199. $mac_history{$simple_mac}{port_id}=$port_index{$port};
  200. $mac_history{$simple_mac}{dev_id}=$dev_id;
  201. if (!$mac_history{$simple_mac}{changed}) { $mac_history{$simple_mac}{changed}=0; }
  202. my $port_id=$port_index{$port};
  203. if (exists $auth_table{full_table}{$mac} or exists $auth_table{oper_table}{$mac}) {
  204. my $auth_id;
  205. if (exists $auth_table{oper_table}{$mac}) { $auth_id=$auth_table{oper_table}{$mac}; } else {
  206. $auth_id=$auth_table{full_table}{$mac};
  207. if ($debug) {
  208. db_log_debug($dbh,"Mac not found in oper ARP-table. Use old values auth_id: $auth_id [$mac] at device $dev_name [$port]");
  209. }
  210. }
  211. if (exists $connections{$auth_id}) {
  212. if ($port_id == $connections{$auth_id}{port}) {
  213. if (exists $auth_table{oper_table}{$mac}) {
  214. my $auth_rec;
  215. $auth_rec->{last_found}=$now_str;
  216. update_record($dbh,'User_auth',$auth_rec,"id=".$auth_id);
  217. }
  218. next;
  219. }
  220. $connections{$auth_id}{port}=$port_id;
  221. $mac_history{$simple_mac}{changed}=1;
  222. $mac_history{$simple_mac}{auth_id}=$auth_id;
  223. db_log_info($dbh,"Found auth_id: $auth_id [$mac] at device $dev_name [$port]. Update connection");
  224. my $auth_rec;
  225. $auth_rec->{last_found}=$now_str;
  226. update_record($dbh,'User_auth',$auth_rec,"id=".$auth_id);
  227. my $conn_rec;
  228. $conn_rec->{port_id}=$port_id;
  229. $conn_rec->{device_id}=$dev_id;
  230. update_record($dbh,'connections',$conn_rec,"auth_id=$auth_id");
  231. } else {
  232. $mac_history{$simple_mac}{changed}=1;
  233. $mac_history{$simple_mac}{auth_id}=$auth_id;
  234. $connections{$auth_id}{port}=$port_id;
  235. db_log_info($dbh,"Found auth_id: $auth_id [$mac] at device $dev_name [$port]. Create connection.");
  236. my $auth_rec;
  237. $auth_rec->{last_found}=$now_str;
  238. update_record($dbh,'User_auth',$auth_rec,"id=".$auth_id);
  239. my $conn_rec;
  240. $conn_rec->{port_id}=$port_id;
  241. $conn_rec->{device_id}=$dev_id;
  242. $conn_rec->{auth_id}=$auth_id;
  243. insert_record($dbh,'connections',$conn_rec);
  244. }
  245. } else {
  246. if (exists $unknown_table{$simple_mac}{unknown_id}) {
  247. next if ($unknown_table{$simple_mac}{port_id} == $port_id and $unknown_table{$simple_mac}{device_id} == $dev_id);
  248. $mac_history{$simple_mac}{changed}=1;
  249. $mac_history{$simple_mac}{auth_id}=0;
  250. $mac=mac_splitted($mac);
  251. db_log_debug($dbh,"Unknown mac $mac moved to $dev_name [$port]") if ($debug);
  252. my $unknown_rec;
  253. $unknown_rec->{port_id}=$port_id;
  254. $unknown_rec->{device_id}=$dev_id;
  255. update_record($dbh,'Unknown_mac',$unknown_rec,"id=$unknown_table{$simple_mac}{unknown_id}");
  256. } else {
  257. $mac=mac_splitted($mac);
  258. $mac_history{$simple_mac}{changed}=1;
  259. $mac_history{$simple_mac}{auth_id}=0;
  260. db_log_debug($dbh,"Unknown mac $mac found at $dev_name [$port]") if ($debug);
  261. my $unknown_rec;
  262. $unknown_rec->{port_id}=$port_id;
  263. $unknown_rec->{device_id}=$dev_id;
  264. $unknown_rec->{mac}=$simple_mac;
  265. insert_record($dbh,'Unknown_mac',$unknown_rec);
  266. }
  267. }
  268. }
  269. }
  270. db_log_verbose($dbh,'Mac discovery stopped.');
  271. }
  272. foreach my $mac (keys %mac_history) {
  273. next if (!$mac);
  274. next if (!$mac_history{$mac}->{changed});
  275. my $h_dev_id='';
  276. $h_dev_id=$mac_history{$mac}->{dev_id} if ($mac_history{$mac}->{dev_id});
  277. my $h_port_id='';
  278. $h_port_id=$mac_history{$mac}->{port_id} if ($mac_history{$mac}->{port_id});
  279. my $h_ip='';
  280. $h_ip=$mac_history{$mac}->{ip} if ($mac_history{$mac}->{ip});
  281. my $h_auth_id=$mac_history{$mac}->{auth_id} if ($mac_history{$mac}->{auth_id});
  282. if (!$h_auth_id) { $h_auth_id=0; }
  283. next if (!$h_dev_id);
  284. my $history_rec;
  285. $history_rec->{device_id}=$h_dev_id;
  286. $history_rec->{port_id}=$h_port_id;
  287. $history_rec->{mac}=$mac;
  288. $history_rec->{ip}=$h_ip;
  289. $history_rec->{auth_id}=$h_auth_id;
  290. insert_record($dbh,'mac_history',$history_rec);
  291. }
  292. $dbh->disconnect;
  293. exit 0;